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

Fix type object signature when both __new__ and __init__ present #5642

Merged
merged 7 commits into from Sep 20, 2018

Conversation

Projects
None yet
2 participants
@msullivan
Collaborator

msullivan commented Sep 19, 2018

Currently mypy will prefer __init__ to __new__ for determining
the signature of a type object if there exists any __init__
other than object's.
Instead, prefer the closest definition in the MRO, so that
subclass __new__ can override parent __init__.

Fixes #1435.

Fix type object signature when both __new__ and __init__ present
Currently mypy will prefer __init__ to __new__ for determining
the signature of a type object if there exists any __init__
other than object's.
Instead, prefer the closest definition in the MRO, so that
subclass __new__ can override parent __init__.

Fixes #1435.
@gvanrossum

Note that only the first example fails in CPython -- the others are OK.

The rule CPython uses is this (for a class C with superclass B, where B is not object):

  • If both C.__new__ and C.__init__ refer to their versions in object, the signature is def () -> C.
  • If exactly one of C.__new__ and C.__object__ refers to its object version, the other determines the signature.
  • If both override their corresponding object versions, they must match -- even if they don't come from the same class (say, if one comes from C and the other from B).
def __new__(cls) -> 'B':
...
B()

This comment has been minimized.

@gvanrossum

gvanrossum Sep 19, 2018

Member

But at runtime in CPython this is an error:

$ Traceback (most recent call last):
  File "_.py", line 9, in <module>
    b = B()
TypeError: __init__() missing 1 required positional argument: 'x'

This comment has been minimized.

@msullivan

msullivan Sep 19, 2018

Collaborator

Oh, hm:
The original bug example had the __new__ call return an int, which works because __init__ isn't called if it isn't a subclass.

@gvanrossum

Let's merge this and open a new issue for the remaining nits:

  • should prefer __new__ over __init__
  • should check __new__ against __init__ (using the full rules I specified)

msullivan added some commits Sep 19, 2018

@msullivan msullivan merged commit 6e6d672 into master Sep 20, 2018

2 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

@msullivan msullivan deleted the new_over_init branch Sep 20, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment