You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR fixes some points of #14033:
* Give metaclass errors to their own error code (I chose `metaclass`).
* Document shortcomings of and workarounds for mypy's metaclass
handling.
I didn't attempt to fix that mypy follows the logic for determining the
metaclass as documented whereas it should follow what the interpreter is
actually doing
(#14033 (comment)). I
think such a change is better kept as a separate PR, which is why I
don't want to close the issue with this PR.
Fixes: #14033
---------
Co-authored-by: hauntsaninja <[email protected]>
Copy file name to clipboardExpand all lines: test-data/unit/check-classes.test
+24-14Lines changed: 24 additions & 14 deletions
Original file line number
Diff line number
Diff line change
@@ -4757,8 +4757,8 @@ class C(B):
4757
4757
class X(type): pass
4758
4758
class Y(type): pass
4759
4759
class A(metaclass=X): pass
4760
-
class B(A, metaclass=Y): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
4761
-
4760
+
class B(A, metaclass=Y): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
4761
+
# N: "__main__.Y" (metaclass of "__main__.B") conflicts with "__main__.X" (metaclass of "__main__.A")
4762
4762
[case testMetaclassNoTypeReveal]
4763
4763
class M:
4764
4764
x = 0 # type: int
@@ -5737,8 +5737,8 @@ def f() -> type: return M
5737
5737
class C1(six.with_metaclass(M), object): pass # E: Unsupported dynamic base class "six.with_metaclass"
5738
5738
class C2(C1, six.with_metaclass(M)): pass # E: Unsupported dynamic base class "six.with_metaclass"
5739
5739
class C3(six.with_metaclass(A)): pass # E: Metaclasses not inheriting from "type" are not supported
5740
-
@six.add_metaclass(A) # E: Metaclasses not inheriting from "type" are not supported \
5741
-
# E: Argument 1 to "add_metaclass" has incompatible type "type[A]"; expected "type[type]"
5740
+
@six.add_metaclass(A) # E: Metaclasses not inheriting from "type" are not supported \
5741
+
# E: Argument 1 to "add_metaclass" has incompatible type "type[A]"; expected "type[type]"
5742
5742
5743
5743
class D3(A): pass
5744
5744
class C4(six.with_metaclass(M), metaclass=M): pass # E: Multiple metaclass definitions
class CQA(Q1): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
5758
-
class CQW(six.with_metaclass(M, Q1)): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
5757
+
class CQA(Q1): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
5758
+
# N: "__main__.M" (metaclass of "__main__.CQA") conflicts with "__main__.M1" (metaclass of "__main__.Q1")
5759
+
class CQW(six.with_metaclass(M, Q1)): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
5760
+
# N: "__main__.M" (metaclass of "__main__.CQW") conflicts with "__main__.M1" (metaclass of "__main__.Q1")
5759
5761
[builtins fixtures/tuple.pyi]
5760
5762
5761
5763
[case testSixMetaclassAny]
@@ -5873,7 +5875,8 @@ class C5(future.utils.with_metaclass(f())): pass # E: Dynamic metaclass not sup
5873
5875
5874
5876
class M1(type): pass
5875
5877
class Q1(metaclass=M1): pass
5876
-
class CQW(future.utils.with_metaclass(M, Q1)): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
5878
+
class CQW(future.utils.with_metaclass(M, Q1)): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
5879
+
# N: "__main__.M" (metaclass of "__main__.CQW") conflicts with "__main__.M1" (metaclass of "__main__.Q1")
5877
5880
[builtins fixtures/tuple.pyi]
5878
5881
5879
5882
[case testFutureMetaclassAny]
@@ -7342,17 +7345,22 @@ class ChildOfCorrectSubclass1(CorrectSubclass1): ...
7342
7345
class CorrectWithType1(C, A1): ...
7343
7346
class CorrectWithType2(B, C): ...
7344
7347
7345
-
class Conflict1(A1, B, E): ... # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
7346
-
class Conflict2(A, B): ... # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
7347
-
class Conflict3(B, A): ... # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
7348
+
class Conflict1(A1, B, E): ... # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
7349
+
# N: "__main__.MyMeta1" (metaclass of "__main__.A") conflicts with "__main__.MyMeta2" (metaclass of "__main__.B")
7350
+
class Conflict2(A, B): ... # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
7351
+
# N: "__main__.MyMeta1" (metaclass of "__main__.A") conflicts with "__main__.MyMeta2" (metaclass of "__main__.B")
7352
+
class Conflict3(B, A): ... # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
7353
+
# N: "__main__.MyMeta2" (metaclass of "__main__.B") conflicts with "__main__.MyMeta1" (metaclass of "__main__.A")
7348
7354
7349
7355
class ChildOfConflict1(Conflict3): ...
7350
7356
class ChildOfConflict2(Conflict3, metaclass=CorrectMeta): ...
7351
7357
7352
7358
class ConflictingMeta(MyMeta1, MyMeta3): ...
7353
-
class Conflict4(A1, B, E, metaclass=ConflictingMeta): ... # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
7359
+
class Conflict4(A1, B, E, metaclass=ConflictingMeta): ... # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
7360
+
# N: "__main__.ConflictingMeta" (metaclass of "__main__.Conflict4") conflicts with "__main__.MyMeta2" (metaclass of "__main__.B")
7354
7361
7355
-
class ChildOfCorrectButWrongMeta(CorrectSubclass1, metaclass=ConflictingMeta): # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
7362
+
class ChildOfCorrectButWrongMeta(CorrectSubclass1, metaclass=ConflictingMeta): # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
7363
+
# N: "__main__.ConflictingMeta" (metaclass of "__main__.ChildOfCorrectButWrongMeta") conflicts with "__main__.CorrectMeta" (metaclass of "__main__.CorrectSubclass1")
7356
7364
...
7357
7365
7358
7366
[case testMetaClassConflictIssue14033]
@@ -7367,8 +7375,10 @@ class B1(metaclass=M2): pass
7367
7375
7368
7376
class C1(metaclass=Mx): pass
7369
7377
7370
-
class TestABC(A2, B1, C1): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
7371
-
class TestBAC(B1, A2, C1): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
7378
+
class TestABC(A2, B1, C1): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
7379
+
# N: "__main__.M1" (metaclass of "__main__.A1") conflicts with "__main__.M2" (metaclass of "__main__.B1")
7380
+
class TestBAC(B1, A2, C1): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases \
7381
+
# N: "__main__.M2" (metaclass of "__main__.B1") conflicts with "__main__.M1" (metaclass of "__main__.A1")
Copy file name to clipboardExpand all lines: test-data/unit/check-errorcodes.test
+41Lines changed: 41 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1239,6 +1239,47 @@ def f(x: str) -> TypeIs[int]: # E: Narrowed type "int" is not a subtype of inpu
1239
1239
1240
1240
[builtins fixtures/tuple.pyi]
1241
1241
1242
+
[case testDynamicMetaclass]
1243
+
class A(metaclass=type(tuple)): pass # E: Dynamic metaclass not supported for "A" [metaclass]
1244
+
[builtins fixtures/tuple.pyi]
1245
+
1246
+
[case testMetaclassOfTypeAny]
1247
+
# mypy: disallow-subclassing-any=True
1248
+
from typing import Any
1249
+
foo: Any = ...
1250
+
class A(metaclass=foo): pass # E: Class cannot use "foo" as a metaclass (has type "Any") [metaclass]
1251
+
1252
+
[case testMetaclassOfWrongType]
1253
+
class Foo:
1254
+
bar = 1
1255
+
class A2(metaclass=Foo.bar): pass # E: Invalid metaclass "Foo.bar" [metaclass]
1256
+
1257
+
[case testMetaclassNotTypeSubclass]
1258
+
class M: pass
1259
+
class A(metaclass=M): pass # E: Metaclasses not inheriting from "type" are not supported [metaclass]
1260
+
1261
+
[case testMultipleMetaclasses]
1262
+
import six
1263
+
class M1(type): pass
1264
+
1265
+
@six.add_metaclass(M1)
1266
+
class A1(metaclass=M1): pass # E: Multiple metaclass definitions [metaclass]
1267
+
1268
+
class A2(six.with_metaclass(M1), metaclass=M1): pass # E: Multiple metaclass definitions [metaclass]
1269
+
1270
+
@six.add_metaclass(M1)
1271
+
class A3(six.with_metaclass(M1)): pass # E: Multiple metaclass definitions [metaclass]
1272
+
[builtins fixtures/tuple.pyi]
1273
+
1274
+
[case testInvalidMetaclassStructure]
1275
+
class X(type): pass
1276
+
class Y(type): pass
1277
+
class A(metaclass=X): pass
1278
+
class B(A, metaclass=Y): pass # E: Metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases [metaclass] \
1279
+
# N: "__main__.Y" (metaclass of "__main__.B") conflicts with "__main__.X" (metaclass of "__main__.A")
0 commit comments