Skip to content

Commit

Permalink
Fix __init_subclass__ type check (#7723)
Browse files Browse the repository at this point in the history
  • Loading branch information
ilevkivskyi authored and msullivan committed Oct 16, 2019
1 parent 9751449 commit 97d25cf
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 5 deletions.
12 changes: 9 additions & 3 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1706,7 +1706,9 @@ def visit_class_def(self, defn: ClassDef) -> None:
with self.scope.push_class(defn.info):
self.accept(defn.defs)
self.binder = old_binder
self.check_init_subclass(defn)
if not (defn.info.typeddict_type or defn.info.tuple_type or defn.info.is_enum):
# If it is not a normal class (not a special form) check class keywords.
self.check_init_subclass(defn)
if not defn.has_incompatible_baseclass:
# Otherwise we've already found errors; more errors are not useful
self.check_multiple_inheritance(typ)
Expand Down Expand Up @@ -1751,6 +1753,11 @@ def check_init_subclass(self, defn: ClassDef) -> None:
Base.__init_subclass__(thing=5) is called at line 4. This is what we simulate here.
Child.__init_subclass__ is never called.
"""
if (defn.info.metaclass_type and
defn.info.metaclass_type.type.fullname() not in ('builtins.type', 'abc.ABCMeta')):
# We can't safely check situations when both __init_subclass__ and a custom
# metaclass are present.
return
# At runtime, only Base.__init_subclass__ will be called, so
# we skip the current class itself.
for base in defn.info.mro[1:]:
Expand All @@ -1775,10 +1782,9 @@ def check_init_subclass(self, defn: ClassDef) -> None:
self.expr_checker.accept(call_expr,
allow_none_return=True,
always_allow_any=True)
# We are only interested in the first Base having __init_subclass__
# We are only interested in the first Base having __init_subclass__,
# all other bases have already been checked.
break
return

def check_protocol_variance(self, defn: ClassDef) -> None:
"""Check that protocol definition is compatible with declared
Expand Down
11 changes: 9 additions & 2 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -6229,14 +6229,21 @@ class Child(Base, thing=5, default_name=""):
[builtins fixtures/object_with_init_subclass.pyi]

[case testInitSubclassWithMetaclassOK]
class Base(type):
class Base:
thing: int

def __init_subclass__(cls, thing: int):
cls.thing = thing

class Child(Base, metaclass=Base, thing=0):
class Child(Base, metaclass=type, thing=0):
pass
[builtins fixtures/object_with_init_subclass.pyi]

[case testInitSubclassWithCustomMetaclassOK]
class M(type): ...
class Child(metaclass=M, thing=0):
pass
[builtins fixtures/object_with_init_subclass.pyi]

[case testTooManyArgsForObject]
class A(thing=5):
Expand Down
1 change: 1 addition & 0 deletions test-data/unit/fixtures/dict.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ VT = TypeVar('VT')

class object:
def __init__(self) -> None: pass
def __init_subclass__(cls) -> None: pass
def __eq__(self, other: object) -> bool: pass

class type: pass
Expand Down

0 comments on commit 97d25cf

Please sign in to comment.