Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test_new_no_args fails on PyPy2.7 #671

Closed
mgorny opened this issue Aug 22, 2019 · 8 comments
Closed

test_new_no_args fails on PyPy2.7 #671

mgorny opened this issue Aug 22, 2019 · 8 comments

Comments

@mgorny
Copy link

mgorny commented Aug 22, 2019

$ pypy --version
Python 2.7.13 (8cdda8b8cdb8ff29d9e620cccd6c5edd2f2a23ec, Apr 19 2019, 18:39:17)
[PyPy 7.1.1 with GCC 7.4.0]
$ cd python2 && pypy -m unittest discover
.....................................................................................................F...................................................................................................................................
======================================================================
FAIL: test_new_no_args (test_typing.GenericTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/typing/python2/test_typing.py", line 1825, in test_new_no_args
    A('foo')
AssertionError: TypeError not raised

----------------------------------------------------------------------
Ran 233 tests in 0.759s

FAILED (failures=1)

Same result with tox, after copying testenv:py27 to testenv:pypy.

@ilevkivskyi
Copy link
Member

Why do you think it is not a PyPy bug? In any case, PyPy is not officially supported by this backport. So unless you are willing to provide a reasonable fix/workaround, I am going to close this.

@mgorny
Copy link
Author

mgorny commented Aug 22, 2019

I don't know, I was hoping you'd be able to tell me. 3.6.4 worked fine.

@nickgaya
Copy link

Here is the relevant difference between CPython and PyPy.

In CPython:

>>> from typing import Generic, TypeVar
>>> T = TypeVar('T')
>>> class A(Generic[T]):
...     pass
... 
>>> A.__init__ is object.__init__
True

In PyPy:

>>>> from typing import Generic, TypeVar
>>>> T = TypeVar('T')
>>>> class A(Generic[T]):
....     pass
....     
>>>> A.__init__ is object.__init__
False

This means that in PyPy, typing._generic_new(A, 'foo') will call object.__new__(A) instead of object.__new__(A, 'foo') as in CPython, which would raise a TypeError.

Moreover, in both CPython and PyPy, object.__init__(object.__new__(A), 'foo') succeeds, even though ordinarily object.__init__() raises a TypeError if given extra arguments. This is actually the crux of the problem.

We can produce similar behavior in CPython like this:

class B(Generic[T]):
    def __init__(self, *args, **kwargs):
        return super(B, self).__init__(*args, **kwargs)

It looks like A and B should be equivalent, but in CPython, A('foo') raises a TypeError while B('foo') does not. In PyPy, A and B behave the the same, which is arguably more consistent.

So the central question is: Why doesn't object.__init__(object.__new__(A), 'foo') raise an exception?

@nickgaya
Copy link

nickgaya commented Oct 25, 2019

Related: #560, python/cpython#6758

@ilevkivskyi What was the reasoning behind adding the __init__ identity check in typing._generic_new()? And do you have some idea why object.__init__() doesn't throw a TypeError as described above? It seems to me that if object.__init__() behaved as expected, the extra check added in cpython#6758 should not be needed.

@nickgaya
Copy link

nickgaya commented Oct 25, 2019

Hm, I found the answer to my question here:

This is definitely a wart -- object.__init__ and object.__new__ each ignore extra arguments only when the other is overridden (and they themselves are not).

I'll ponder this a bit to see if there's a different solution that would work for both A and B.

@mgorny
Copy link
Author

mgorny commented Nov 21, 2019

Could you hint me a bit on how to handle this downstream? Is this a regression in the new version, or merely a thing that wasn't tested before? Is this something critical to functionality, or can I just ignore the test failure on PyPy for the time being?

@gvanrossum
Copy link
Member

It's not a regression in typing.py. I don't know what changed (the test or the typing.py module) but it looks like it's failing due to the absence of an expected exception, which doesn't sound like the end of the world. Maybe you can try deleting these two lines from the failing test:

        with self.assertRaises(TypeError):
            A('foo')

If it then passes, I wouldn't worry (and we might accept a PR that skips those two lines if PyPy is detected).

For more details just carefully read this issue from the top, it's all there.

@srittau
Copy link
Collaborator

srittau commented Nov 4, 2021

The typing backport has been removed from this repository, making this issue obsolete.

@srittau srittau closed this as completed Nov 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants