FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

bpo-33073: Adding as_integer_ratio to ints. by lisroach · Pull Request #8750 · python/cpython · GitHub

/ cpython Public

bpo-33073: Adding as_integer_ratio to ints. - #8750

Merged
rhettinger merged 18 commits into
python:masterfrom
lisroach:iss_33073
Sep 14, 2018
Merged

bpo-33073: Adding as_integer_ratio to ints.#8750
rhettinger merged 18 commits into
python:masterfrom
lisroach:iss_33073

Conversation

lisroach commented Aug 12, 2018
edited by bedevere-bot
Loading

Copy link
Copy Markdown
Contributor

Adding as_integer_ratio to ints to make them more interoperable with floats.

https://bugs.python.org/issue33073

Comment thread Objects/longobject.c Outdated
PyObject *result_pair = NULL;

denominator = PyLong_FromLong(1);
result_pair = PyTuple_Pack(2, self, denominator);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

If PyLong_FromLong returns NULL then PyTuple_Pack and Py_DECREF(denominator) will fail.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think the whole function can be replaced with return PyTuple_Pack(2, self, _PyLong_One).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@pablogsal But PyLong_FromLong always receive the 1. How could it fail?

pablogsal Aug 14, 2018
edited
Loading

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The contract of PyLong_FromLong says that it can return NULL on failure. Even if the current implementation (that uses the array of small ints) makes it improbable/impossible to fail, this can change in the future without changing the external API.

Comment thread Objects/longobject.c Outdated
Return a pair of integers, whose ratio is exactly equal to the original int
and with a positive denominator.

Raise OverflowError on infinities and a ValueError on NaNs.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

An int can never be any of these things - remove this line

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Yes. math.inf is float class

Comment thread Lib/test/test_long.py Outdated
def test_as_integer_ratio(self):
tests = [10, 0, -10, 1, 3]
for value in tests:
self.assertEqual((value).as_integer_ratio(), (value, 1))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

nit: no parens needed around value

Comment thread Doc/library/stdtypes.rst
Return a pair of integers whose ratio is exactly equal to the original integer
and with a positive denominator. The integer ratio of integers (whole numbers)
is always the integer as the numerator and 1 as the denominator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

A versionadded directive needs to be added. Also, the developer's guide states that reST files should use an indentation of 3 spaces.

Comment thread Objects/longobject.c Outdated
int_as_integer_ratio_impl(PyObject *self)
/*[clinic end generated code: output=e60803ae1cc8621a input=ce9c7768a1287fb9]*/
{
return PyTuple_Pack(2, self, _PyLong_One)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

There's a missing semicolon at the end of this line; I think that's why the continuous integration builds are failing.

Also, please change the indentation of this line to 4 spaces instead of 2 spaces, following PEP7. Thanks!

Copy link
Copy Markdown
Member

@lisroach Thanks for the update. I've pushed a commit that should fix the failing test_doctest.

mdickinson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

@lisroach If you're okay with my recent updates, I think this PR is ready to merge.

mdickinson added the type-feature A feature request or enhancement label Aug 25, 2018
Comment thread Objects/longobject.c Outdated
int_as_integer_ratio_impl(PyObject *self)
/*[clinic end generated code: output=e60803ae1cc8621a input=c1aea0aa6fb85c28]*/
{
return PyTuple_Pack(2, self, _PyLong_One);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

True.as_integer_ratio() will return (True, 1). It should return (1, 1).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Hmm; good point. There's a precedent here in the form of True.numerator, which returns 1.

Comment thread Objects/longobject.c
Return a pair of integers, whose ratio is exactly equal to the original int
and with a positive denominator.

>>> (10).as_integer_ratio()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Do we need so much examples in a docstring?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think it's useful to have at least one positive and one negative example, so that it's obvious at a glance that the behaviour for negatives is to give (for example) (-5, 1) rather than (5, -1). I could imagine users thinking that 0 was somehow a special case, too, so I like that we have the 0 example there.

Comment thread Lib/test/test_long.py Outdated
self.assertEqual(type(value >> shift), int)

def test_as_integer_ratio(self):
tests = [10, 0, -10, 1, 3]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Why so much similar cases are needed?

Add tests for booleans and other int subclasses. Check types of numerator and denominator.

Comment thread Doc/library/stdtypes.rst Outdated

Return a pair of integers whose ratio is exactly equal to the original
integer and with a positive denominator. The integer ratio of integers
(whole numbers) is always the integer as the numerator and 1 as the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

``1``

mdickinson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Changing my approval due to the issues Serhiy noted. @lisroach do you want to tackle the outstanding comments? I'm happy to pick this up if not.

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

Copy link
Copy Markdown
Contributor Author

I have made the requested changes; please review again.

I am not sure if I could do the boolean check better- somehow in one line? I'm open to advice!

Thanks for all the reviews @mdickinson and @serhiy-storchaka it's been really helpful!

Copy link
Copy Markdown
Contributor Author

@eric-wieser I believe Serhiy's thinking is correct, it should be (1, 1).
Subclasses of int inherit the same operations of int, and those operations create instances of int (as opposed to creating an instance of the subclass). For example, if we look at the unary plus of int:

>>> class Int(int):
...     pass
...
>>> x = Int(42)
>>> type(+x)
<class 'int'>
>>> type(+True)
<class 'int'>

Comment thread Lib/test/test_long.py Outdated
class Foo(enum.IntEnum):
X = 42
self.assertEqual(Foo.X.as_integer_ratio(), (42, 1))
assert(type(Foo.X.as_integer_ratio()[0] == int))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This should be: self.assertEqual(type(Foo.X.as_integer_ratio()[0], int). Unittest doesn't use assertion statements.

Comment thread Objects/longobject.c Outdated
return PyTuple_Pack(2, self, _PyLong_One);
else {
PyObject *temp = PyNumber_Positive(self);
Py_DECREF(temp);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The DECREF needs to occur after building the tuple; otherwise, the Python integer object can (and likely will) disappear before it gets used.

Comment thread Objects/longobject.c Outdated
if PyLong_CheckExact(self)
return PyTuple_Pack(2, self, _PyLong_One);
else {
PyObject *temp = PyNumber_Positive(self);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

We need another way to do this. The intent of this code is to construct a regular integer instance from an instance of an int subclass. The problem with PyNumber_Positive() is that the subclass can itself define pos() to return something other than an exact int. Elsewhere, we use _PyLong_Copy for this purpose.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Is there a reason why PyNumber_Index does not call _PyLong_Copy?

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

rhettinger dismissed mdickinson’s stale review September 14, 2018 05:34

Am checking to see the Serhiy's issues are resolved.

Copy link
Copy Markdown
Contributor

Reviving a comment hidden away above - should operator.index / PyNumber_Index / int->tp_as_number->nb_index call _PyLong_Copy too for consistency?

Comment thread Objects/longobject.c
{
if PyLong_CheckExact(self) {
return PyTuple_Pack(2, self, _PyLong_One);
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

else { should be on the next line per PEP 7.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Missing parens on the if too

Comment thread Objects/longobject.c
Comment thread Objects/longobject.c
rhettinger merged commit 5ac7043 into python:master Sep 14, 2018

eric-wieser commented Sep 14, 2018
edited
Loading

Copy link
Copy Markdown
Contributor

ISTM, the code is reasonable as-is.

Despite the missing null check and invalid C syntax that works only because of a macro?

Copy link
Copy Markdown
Contributor

Eric, I didn't see your comments prior to merging. See PR 9297 for the cleanup. The part that was fine as-is was using PyTuple_Pack() on two different code paths.

eric-wieser commented Sep 14, 2018
edited
Loading

Copy link
Copy Markdown
Contributor

Agreed, the two code paths thing was unimportant. #9297 seems to address all my comments, other than the question about nb_index, which is tangential anyway

Copy link
Copy Markdown
Contributor

Can you note your review on 9297 please.

Copy link
Copy Markdown
Contributor

If that's aimed at me, I don't know what you're asking me to do.

serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This PR was merged too soon. There are several issues with it. See also comments by @sir-sigurd and @eric-wieser.

Comment thread Lib/test/test_long.py
self.assertEqual(False.as_integer_ratio(), (0, 1))
assert(type(True.as_integer_ratio()[0]) == int)
assert(type(False.as_integer_ratio()[0]) == int)
self.assertEqual(type(True.as_integer_ratio()[0]), int)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Test also the denumerator type.

Comment thread Objects/longobject.c
if PyLong_CheckExact(self) {
return PyTuple_Pack(2, self, _PyLong_One);
} else {
PyObject *numerator = _PyLong_Copy(self);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Use the same same code as for for the numerator getter.

Test the result for NULL.

Comment thread Doc/whatsnew/3.8.rst
was lifted.
(Contributed by Serhiy Storchaka in :issue:`32489`.)

* The ``int`` type now has a new ``as_integer_ratio`` method compatible

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Add links:

:class:`int`
:meth:`~int.as_integer_ratio`
:meth:`float.as_integer_ratio`

Copy link
Copy Markdown
Member

Reviving a comment hidden away above - should operator.index / PyNumber_Index / int->tp_as_number->nb_index call _PyLong_Copy too for consistency?

This is a different issue. And I think that it should not.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type-feature A feature request or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.


Back | FazBrowse Home | New Git URL