Skip to content

Commit bddc8bf

Browse files
authored
Now __new__ in a metaclass must return a subtype of type, refs #11398 (#11420)
Closes #11398 Now cases like ```python from typing import Type class MyMetaClass(type): def __new__(cls, name, bases, attrs) -> Type['MyClass']: pass class MyClass(metaclass=MyMetaClass): pass ``` will pass.
1 parent 0ec868f commit bddc8bf

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

mypy/checker.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,17 @@ def check___new___signature(self, fdef: FuncDef, typ: CallableType) -> None:
11091109
bound_type = bind_self(typ, self_type, is_classmethod=True)
11101110
# Check that __new__ (after binding cls) returns an instance
11111111
# type (or any).
1112-
if not isinstance(get_proper_type(bound_type.ret_type),
1112+
if isinstance(fdef.info, TypeInfo) and fdef.info.is_metaclass():
1113+
# This is a metaclass, so it must return a new unrelated type.
1114+
self.check_subtype(
1115+
bound_type.ret_type,
1116+
self.type_type(),
1117+
fdef,
1118+
message_registry.INVALID_NEW_TYPE,
1119+
'returns',
1120+
'but must return a subtype of'
1121+
)
1122+
elif not isinstance(get_proper_type(bound_type.ret_type),
11131123
(AnyType, Instance, TupleType)):
11141124
self.fail(
11151125
message_registry.NON_INSTANCE_NEW_TYPE.format(

test-data/unit/check-classes.test

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6419,6 +6419,37 @@ class B(A):
64196419

64206420
reveal_type(B()) # N: Revealed type is "__main__.B"
64216421

6422+
[case testNewReturnType10]
6423+
# https://github.com/python/mypy/issues/11398
6424+
from typing import Type
6425+
6426+
class MyMetaClass(type):
6427+
def __new__(cls, name, bases, attrs) -> Type['MyClass']:
6428+
pass
6429+
6430+
class MyClass(metaclass=MyMetaClass):
6431+
pass
6432+
6433+
[case testNewReturnType11]
6434+
# https://github.com/python/mypy/issues/11398
6435+
class MyMetaClass(type):
6436+
def __new__(cls, name, bases, attrs) -> type:
6437+
pass
6438+
6439+
class MyClass(metaclass=MyMetaClass):
6440+
pass
6441+
6442+
[case testNewReturnType12]
6443+
# https://github.com/python/mypy/issues/11398
6444+
from typing import Type
6445+
6446+
class MyMetaClass(type):
6447+
def __new__(cls, name, bases, attrs) -> int: # E: Incompatible return type for "__new__" (returns "int", but must return a subtype of "type")
6448+
pass
6449+
6450+
class MyClass(metaclass=MyMetaClass):
6451+
pass
6452+
64226453
[case testGenericOverride]
64236454
from typing import Generic, TypeVar, Any
64246455

0 commit comments

Comments
 (0)