Skip to content

Commit

Permalink
Now __new__ in a metaclass must return a subtype of type, refs py…
Browse files Browse the repository at this point in the history
…thon#11398 (python#11420)

Closes python#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.
  • Loading branch information
sobolevn authored and tushar-deepsource committed Jan 20, 2022
1 parent 245a86b commit 32b591c
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 1 deletion.
12 changes: 11 additions & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,17 @@ def check___new___signature(self, fdef: FuncDef, typ: CallableType) -> None:
bound_type = bind_self(typ, self_type, is_classmethod=True)
# Check that __new__ (after binding cls) returns an instance
# type (or any).
if not isinstance(get_proper_type(bound_type.ret_type),
if isinstance(fdef.info, TypeInfo) and fdef.info.is_metaclass():
# This is a metaclass, so it must return a new unrelated type.
self.check_subtype(
bound_type.ret_type,
self.type_type(),
fdef,
message_registry.INVALID_NEW_TYPE,
'returns',
'but must return a subtype of'
)
elif not isinstance(get_proper_type(bound_type.ret_type),
(AnyType, Instance, TupleType)):
self.fail(
message_registry.NON_INSTANCE_NEW_TYPE.format(
Expand Down
31 changes: 31 additions & 0 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -6419,6 +6419,37 @@ class B(A):

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

[case testNewReturnType10]
# https://github.com/python/mypy/issues/11398
from typing import Type

class MyMetaClass(type):
def __new__(cls, name, bases, attrs) -> Type['MyClass']:
pass

class MyClass(metaclass=MyMetaClass):
pass

[case testNewReturnType11]
# https://github.com/python/mypy/issues/11398
class MyMetaClass(type):
def __new__(cls, name, bases, attrs) -> type:
pass

class MyClass(metaclass=MyMetaClass):
pass

[case testNewReturnType12]
# https://github.com/python/mypy/issues/11398
from typing import Type

class MyMetaClass(type):
def __new__(cls, name, bases, attrs) -> int: # E: Incompatible return type for "__new__" (returns "int", but must return a subtype of "type")
pass

class MyClass(metaclass=MyMetaClass):
pass

[case testGenericOverride]
from typing import Generic, TypeVar, Any

Expand Down

0 comments on commit 32b591c

Please sign in to comment.