Skip to content

Commit

Permalink
Treat Any metaclass the same as Any base class (#13605)
Browse files Browse the repository at this point in the history
Closes #13599
  • Loading branch information
sobolevn authored Sep 8, 2022
1 parent c0372cc commit 520b83e
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 15 deletions.
17 changes: 11 additions & 6 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2076,12 +2076,17 @@ def get_declared_metaclass(
# Probably a name error - it is already handled elsewhere
return None, False
if isinstance(sym.node, Var) and isinstance(get_proper_type(sym.node.type), AnyType):
# 'Any' metaclass -- just ignore it.
#
# TODO: A better approach would be to record this information
# and assume that the type object supports arbitrary
# attributes, similar to an 'Any' base class.
return None, False
# Create a fake TypeInfo that fallbacks to `Any`, basically allowing
# all the attributes. Same thing as we do for `Any` base class.
any_info = self.make_empty_type_info(ClassDef(sym.node.name, Block([])))
any_info.fallback_to_any = True
any_info._fullname = sym.node.fullname
if self.options.disallow_subclassing_any:
self.fail(
f'Class cannot use "{any_info.fullname}" as a metaclass (has type "Any")',
metaclass_expr,
)
return Instance(any_info, []), False
if isinstance(sym.node, PlaceholderNode):
return None, True # defer later in the caller

Expand Down
39 changes: 30 additions & 9 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -4392,6 +4392,35 @@ def f(TB: Type[B]):
reveal_type(TB) # N: Revealed type is "Type[__main__.B]"
reveal_type(TB.x) # N: Revealed type is "builtins.int"

[case testMetaclassAsAny]
from typing import Any, ClassVar

MyAny: Any
class WithMeta(metaclass=MyAny):
x: ClassVar[int]

reveal_type(WithMeta.a) # N: Revealed type is "Any"
reveal_type(WithMeta.m) # N: Revealed type is "Any"
reveal_type(WithMeta.x) # N: Revealed type is "builtins.int"
reveal_type(WithMeta().x) # N: Revealed type is "builtins.int"
WithMeta().m # E: "WithMeta" has no attribute "m"
WithMeta().a # E: "WithMeta" has no attribute "a"

[case testMetaclassAsAnyWithAFlag]
# flags: --disallow-subclassing-any
from typing import Any, ClassVar

MyAny: Any
class WithMeta(metaclass=MyAny): # E: Class cannot use "__main__.MyAny" as a metaclass (has type "Any")
x: ClassVar[int]

reveal_type(WithMeta.a) # N: Revealed type is "Any"
reveal_type(WithMeta.m) # N: Revealed type is "Any"
reveal_type(WithMeta.x) # N: Revealed type is "builtins.int"
reveal_type(WithMeta().x) # N: Revealed type is "builtins.int"
WithMeta().m # E: "WithMeta" has no attribute "m"
WithMeta().a # E: "WithMeta" has no attribute "a"

[case testMetaclassIterable]
from typing import Iterable, Iterator

Expand Down Expand Up @@ -4476,15 +4505,7 @@ from missing import M
class A(metaclass=M):
y = 0
reveal_type(A.y) # N: Revealed type is "builtins.int"
A.x # E: "Type[A]" has no attribute "x"

[case testAnyMetaclass]
from typing import Any
M = None # type: Any
class A(metaclass=M):
y = 0
reveal_type(A.y) # N: Revealed type is "builtins.int"
A.x # E: "Type[A]" has no attribute "x"
reveal_type(A.x) # N: Revealed type is "Any"

[case testValidTypeAliasAsMetaclass]
from typing_extensions import TypeAlias
Expand Down

0 comments on commit 520b83e

Please sign in to comment.