diff --git a/mypy/nodes.py b/mypy/nodes.py index f520280dce2d..7680641e659f 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -106,7 +106,8 @@ def get_column(self) -> int: '__doc__': None, # depends on Python version, see semanal.py '__path__': None, # depends on if the module is a package '__file__': '__builtins__.str', - '__package__': '__builtins__.str' + '__package__': '__builtins__.str', + '__annotations__': None, # dict[str, Any] bounded in add_implicit_module_attrs() } diff --git a/mypy/semanal.py b/mypy/semanal.py index db255a7dedc8..60127961b60e 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -447,6 +447,13 @@ def add_implicit_module_attrs(self, file_node: MypyFile) -> None: node = sym.node assert isinstance(node, TypeInfo) typ = Instance(node, [self.str_type()]) + elif name == '__annotations__': + sym = self.lookup_qualified("__builtins__.dict", Context(), suppress_errors=True) + if not sym: + continue + node = sym.node + assert isinstance(node, TypeInfo) + typ = Instance(node, [self.str_type(), AnyType(TypeOfAny.special_form)]) else: assert t is not None, 'type should be specified for {}'.format(name) typ = UnboundType(t) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index b568017cfa5f..ccaf28022d4e 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -978,6 +978,7 @@ def verify_typealias( "__cached__", "__loader__", "__spec__", + "__annotations__", "__path__", # mypy adds __path__ to packages, but C packages don't have it "__getattr__", # resulting behaviour might be typed explicitly # TODO: remove the following from this list diff --git a/test-data/unit/check-basic.test b/test-data/unit/check-basic.test index 03dee485c848..238aab3944ff 100644 --- a/test-data/unit/check-basic.test +++ b/test-data/unit/check-basic.test @@ -236,32 +236,16 @@ from typing import Any def f() -> Any: yield -[case testModule__name__] +[case testModuleImplicitAttributes] import typing -x = __name__ # type: str -a = __name__ # type: A # E: Incompatible types in assignment (expression has type "str", variable has type "A") class A: pass +reveal_type(__name__) # N: Revealed type is "builtins.str" +reveal_type(__doc__) # N: Revealed type is "builtins.str" +reveal_type(__file__) # N: Revealed type is "builtins.str" +reveal_type(__package__) # N: Revealed type is "builtins.str" +reveal_type(__annotations__) # N: Revealed type is "builtins.dict[builtins.str, Any]" [builtins fixtures/primitives.pyi] -[case testModule__doc__] -import typing -x = __doc__ # type: str -a = __doc__ # type: A # E: Incompatible types in assignment (expression has type "str", variable has type "A") -class A: pass -[builtins fixtures/primitives.pyi] - -[case testModule__file__] -import typing -x = __file__ # type: str -a = __file__ # type: A # E: Incompatible types in assignment (expression has type "str", variable has type "A") -class A: pass -[builtins fixtures/primitives.pyi] - -[case test__package__] -import typing -x = __package__ # type: str -a = __file__ # type: int # E: Incompatible types in assignment (expression has type "str", variable has type "int") - -- Scoping and shadowing -- ---------------------