Skip to content

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

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

Merged
merged 7 commits into from
Sep 20, 2018

Conversation

msullivan
Copy link
Collaborator

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.

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.
Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

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

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()
Copy link
Member

Choose a reason for hiding this comment

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

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'

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

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.

Copy link
Member

@gvanrossum gvanrossum left a comment

Choose a reason for hiding this comment

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

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 msullivan merged commit 6e6d672 into master Sep 20, 2018
@msullivan msullivan deleted the new_over_init branch September 20, 2018 20:49
hauntsaninja added a commit to hauntsaninja/mypy that referenced this pull request Nov 3, 2024
hauntsaninja added a commit to hauntsaninja/mypy that referenced this pull request Nov 3, 2024
hauntsaninja added a commit to hauntsaninja/mypy that referenced this pull request Nov 3, 2024
hauntsaninja added a commit to hauntsaninja/mypy that referenced this pull request Dec 27, 2024
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

Successfully merging this pull request may close these issues.

Invalid signature for type object when both __init__ and __new__
2 participants