Skip to content

Commit 5a40f11

Browse files
committed
Fix __new__ and __init__ precedence
Fixes #5647 See also #5642
1 parent 1f200dd commit 5a40f11

File tree

3 files changed

+16
-11
lines changed

3 files changed

+16
-11
lines changed

mypy/checkmember.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,15 +1321,18 @@ def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> P
13211321
"""
13221322

13231323
# We take the type from whichever of __init__ and __new__ is first
1324-
# in the MRO, preferring __init__ if there is a tie.
1324+
# in the MRO, preferring __new__ if there is a tie.
13251325
init_method = info.get("__init__")
13261326
new_method = info.get("__new__")
13271327
if not init_method or not is_valid_constructor(init_method.node):
13281328
# Must be an invalid class definition.
13291329
return AnyType(TypeOfAny.from_error)
13301330
# There *should* always be a __new__ method except the test stubs
13311331
# lack it, so just copy init_method in that situation
1332-
new_method = new_method or init_method
1332+
if new_method is None:
1333+
new_method = named_type("builtins.object").type.get("__init__")
1334+
if not new_method:
1335+
return AnyType(TypeOfAny.from_error)
13331336
if not is_valid_constructor(new_method.node):
13341337
# Must be an invalid class definition.
13351338
return AnyType(TypeOfAny.from_error)
@@ -1363,12 +1366,13 @@ def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> P
13631366
fallback=named_type("builtins.function"),
13641367
)
13651368
return class_callable(sig, info, fallback, None, is_new=False)
1366-
1367-
# Otherwise prefer __init__ in a tie. It isn't clear that this
1368-
# is the right thing, but __new__ caused problems with
1369-
# typeshed (#5647).
1370-
method = init_method.node
1371-
is_new = False
1369+
if init_method.node.info.fullname == "builtins.dict":
1370+
# dict.__new__ in typeshed is pretty unhelpful
1371+
method = init_method.node
1372+
is_new = False
1373+
else:
1374+
method = new_method.node
1375+
is_new = True
13721376
# Construct callable type based on signature of __init__. Adjust
13731377
# return type and insert type arguments.
13741378
if isinstance(method, FuncBase):

test-data/unit/check-classes.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6324,7 +6324,7 @@ class A:
63246324
def __init__(self, x: int) -> None:
63256325
pass
63266326

6327-
reveal_type(A) # N: Revealed type is "def (x: builtins.int) -> __main__.A"
6327+
reveal_type(A) # N: Revealed type is "def (*args: Any) -> __main__.A"
63286328
[builtins fixtures/tuple.pyi]
63296329

63306330
[case testCyclicDecorator]
@@ -7883,7 +7883,7 @@ if object():
78837883
if object():
78847884
reveal_type(B()) # N: Revealed type is "Never"
78857885
if object():
7886-
reveal_type(C()) # N: Revealed type is "Never"
7886+
reveal_type(C()) # N: Revealed type is "__main__.C"
78877887
if object():
78887888
reveal_type(D()) # N: Revealed type is "Never"
78897889

@@ -7933,7 +7933,7 @@ if object():
79337933
reveal_type(B(1)) # N: Revealed type is "__main__.B"
79347934

79357935
if object():
7936-
reveal_type(C()) # N: Revealed type is "Never"
7936+
reveal_type(C()) # N: Revealed type is "__main__.C"
79377937
reveal_type(C(1)) # N: Revealed type is "__main__.C"
79387938

79397939
if object():

test-data/unit/fixtures/object_hashable.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
class object:
2+
def __init__(self) -> None: ...
23
def __hash__(self) -> int: ...
34

45
class type: ...

0 commit comments

Comments
 (0)