From d787d5f192769000c9a7557f4966ede99079444c Mon Sep 17 00:00:00 2001 From: elazar Date: Tue, 7 Feb 2017 11:59:24 +0200 Subject: [PATCH 1/2] do not support classes not subclassing type --- mypy/nodes.py | 2 +- mypy/semanal.py | 3 +++ test-data/unit/check-classes.test | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/mypy/nodes.py b/mypy/nodes.py index 8d0d15af4c6a..6cf792d55290 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2022,7 +2022,7 @@ def calculate_metaclass_type(self) -> 'Optional[mypy.types.Instance]': return None def is_metaclass(self) -> bool: - return self.has_base('builtins.type') + return self.has_base('builtins.type') or self.fullname() == 'abc.ABCMeta' def _calculate_is_enum(self) -> bool: """ diff --git a/mypy/semanal.py b/mypy/semanal.py index 66553325ece2..63291418bc2b 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -911,6 +911,9 @@ def analyze_metaclass(self, defn: ClassDef) -> None: if not isinstance(sym.node, TypeInfo) or sym.node.tuple_type is not None: self.fail("Invalid metaclass '%s'" % defn.metaclass, defn) return + if not sym.node.is_metaclass(): + self.fail("Metaclasses not inheriting from 'type' are not supported", defn) + return inst = fill_typevars(sym.node) assert isinstance(inst, Instance) defn.info.declared_metaclass = inst diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index af69bf7c4c30..c543afef6478 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2770,9 +2770,9 @@ class B(A, metaclass=Y): pass # E: Inconsistent metaclass structure for 'B' class M: x = 0 # type: int -class A(metaclass=M): pass +class A(metaclass=M): pass # E: Metaclasses not inheriting from 'type' are not supported -reveal_type(A.x) # E: Revealed type is 'builtins.int' +A.x # E: "A" has no attribute "x" [case testMetaclassTypeReveal] from typing import Type @@ -2810,4 +2810,4 @@ from typing import Tuple class M(Tuple[int]): pass class C(metaclass=M): pass # E: Invalid metaclass 'M' -[builtins fixtures/tuple.pyi] \ No newline at end of file +[builtins fixtures/tuple.pyi] From e82286b0a8429562be38860864e30a928fdd71cb Mon Sep 17 00:00:00 2001 From: elazar Date: Tue, 7 Feb 2017 15:18:36 +0200 Subject: [PATCH 2/2] add test for indirect type subclass --- test-data/unit/check-classes.test | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index c543afef6478..dccc213cc914 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2785,6 +2785,14 @@ def f(TA: Type[A]): reveal_type(TA) # E: Revealed type is 'Type[__main__.A]' reveal_type(TA.x) # E: Revealed type is 'builtins.int' +[case testSubclassMetaclass] +class M1(type): + x = 0 +class M2(M1): pass +class C(metaclass=M2): + pass +reveal_type(C.x) # E: Revealed type is 'builtins.int' + [case testMetaclassIterable] from typing import Iterable, Iterator