Skip to content

Commit 137dd74

Browse files
committed
Fix __new__ and __init__ precedence
Fixes python#5647 See also python#5642
1 parent 6d13d0d commit 137dd74

File tree

3 files changed

+17
-12
lines changed

3 files changed

+17
-12
lines changed

mypy/checkmember.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,15 +1329,18 @@ def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> P
13291329
"""
13301330

13311331
# We take the type from whichever of __init__ and __new__ is first
1332-
# in the MRO, preferring __init__ if there is a tie.
1332+
# in the MRO, preferring __new__ if there is a tie.
13331333
init_method = info.get("__init__")
13341334
new_method = info.get("__new__")
13351335
if not init_method or not is_valid_constructor(init_method.node):
13361336
# Must be an invalid class definition.
13371337
return AnyType(TypeOfAny.from_error)
13381338
# There *should* always be a __new__ method except the test stubs
1339-
# lack it, so just copy init_method in that situation
1340-
new_method = new_method or init_method
1339+
# lack it, so just copy builtin's init in that situation
1340+
if new_method is None:
1341+
new_method = named_type("builtins.object").type.get("__init__")
1342+
if not new_method:
1343+
return AnyType(TypeOfAny.from_error)
13411344
if not is_valid_constructor(new_method.node):
13421345
# Must be an invalid class definition.
13431346
return AnyType(TypeOfAny.from_error)
@@ -1371,12 +1374,13 @@ def type_object_type(info: TypeInfo, named_type: Callable[[str], Instance]) -> P
13711374
fallback=named_type("builtins.function"),
13721375
)
13731376
return class_callable(sig, info, fallback, None, is_new=False)
1374-
1375-
# Otherwise prefer __init__ in a tie. It isn't clear that this
1376-
# is the right thing, but __new__ caused problems with
1377-
# typeshed (#5647).
1378-
method = init_method.node
1379-
is_new = False
1377+
if init_method.node.info.fullname == "builtins.dict":
1378+
# dict.__new__ in typeshed is pretty unhelpful
1379+
method = init_method.node
1380+
is_new = False
1381+
else:
1382+
method = new_method.node
1383+
is_new = True
13801384
# Construct callable type based on signature of __init__. Adjust
13811385
# return type and insert type arguments.
13821386
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)