diff --git a/mypy/nodes.py b/mypy/nodes.py index d4e7170cac98..ce0286db84f6 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -99,10 +99,11 @@ def get_column(self) -> int: implicit_module_attrs: Final = { - "__name__": "__builtins__.str", - "__doc__": None, # depends on Python version, see semanal.py - "__file__": "__builtins__.str", - "__package__": "__builtins__.str", + '__name__': '__builtins__.str', + '__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' } diff --git a/mypy/semanal.py b/mypy/semanal.py index 619011753371..49ec5c88f30f 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -427,6 +427,17 @@ def add_implicit_module_attrs(self, file_node: MypyFile) -> None: else: typ = UnionType([UnboundType('__builtins__.str'), UnboundType('__builtins__.unicode')]) + elif name == '__path__': + if not file_node.is_package_init_file(): + continue + # Need to construct the type ourselves, to avoid issues with __builtins__.list + # not being subscriptable or typing.List not getting bound + sym = self.lookup_qualified("__builtins__.list", Context()) + if not sym: + continue + node = sym.node + assert isinstance(node, TypeInfo) + typ = Instance(node, [self.str_type()]) else: assert t is not None, 'type should be specified for {}'.format(name) typ = UnboundType(t) diff --git a/test-data/unit/check-incomplete-fixture.test b/test-data/unit/check-incomplete-fixture.test index 8c5ec0899069..f06dad293184 100644 --- a/test-data/unit/check-incomplete-fixture.test +++ b/test-data/unit/check-incomplete-fixture.test @@ -12,14 +12,6 @@ import m m.x # E: "object" has no attribute "x" [file m.py] -[case testListMissingFromStubs] -from typing import List -def f(x: List[int]) -> None: pass -[out] -main:1: error: Module "typing" has no attribute "List" -main:1: note: Maybe your test fixture does not define "builtins.list"? -main:1: note: Consider adding [builtins fixtures/list.pyi] to your test description - [case testDictMissingFromStubs] from typing import Dict def f(x: Dict[int]) -> None: pass diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index ad7322a2573f..1a2504f3a611 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -2888,6 +2888,16 @@ from mystery import a, b as b, c as d tmp/stub.pyi:1: error: Cannot find implementation or library stub for module named "mystery" tmp/stub.pyi:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#missing-imports +[case testPackagePath] +import p +reveal_type(p.__path__) # N: Revealed type is "builtins.list[builtins.str]" +p.m.__path__ # E: "object" has no attribute "__path__" + +[file p/__init__.py] +from . import m as m +[file p/m.py] +[builtins fixtures/list.pyi] + [case testReExportAllInStub] from m1 import C from m1 import D # E: Module "m1" has no attribute "D" @@ -3121,4 +3131,4 @@ main:2: error: Cannot find implementation or library stub for module named "blea # flags: --ignore-missing-imports import bleach.xyz from bleach.abc import fgh -[file bleach/__init__.pyi] +[file bleach/__init__.pyi] \ No newline at end of file diff --git a/test-data/unit/fine-grained-modules.test b/test-data/unit/fine-grained-modules.test index 3ce38e280ef5..8d5b918dbbab 100644 --- a/test-data/unit/fine-grained-modules.test +++ b/test-data/unit/fine-grained-modules.test @@ -1437,7 +1437,7 @@ x = 1 [file b/foo.py] [file b/__init__.py.2] # Dummy change -[builtins fixtures/bool.pyi] +[builtins fixtures/primitives.pyi] [out] == diff --git a/test-data/unit/fixtures/args.pyi b/test-data/unit/fixtures/args.pyi index 0a38ceeece2e..2ee8736a154c 100644 --- a/test-data/unit/fixtures/args.pyi +++ b/test-data/unit/fixtures/args.pyi @@ -1,6 +1,6 @@ # Builtins stub used to support *args, **kwargs. -from typing import TypeVar, Generic, Iterable, Tuple, Dict, Any, overload, Mapping +from typing import TypeVar, Generic, Iterable, Sequence, Tuple, Dict, Any, overload, Mapping Tco = TypeVar('Tco', covariant=True) T = TypeVar('T') @@ -22,6 +22,8 @@ class tuple(Iterable[Tco], Generic[Tco]): pass class dict(Iterable[T], Mapping[T, S], Generic[T, S]): pass +class list(Generic[T], Sequence[T]): pass + class int: def __eq__(self, o: object) -> bool: pass class str: pass diff --git a/test-data/unit/lib-stub/builtins.pyi b/test-data/unit/lib-stub/builtins.pyi index 57fc4b8f0de2..8c4f504fb2e7 100644 --- a/test-data/unit/lib-stub/builtins.pyi +++ b/test-data/unit/lib-stub/builtins.pyi @@ -20,4 +20,8 @@ class bytes: pass class function: pass class ellipsis: pass +from typing import Generic, Sequence, TypeVar +_T = TypeVar('_T') +class list(Generic[_T], Sequence[_T]): pass + # Definition of None is implicit