From e632feaecc11bc8f1e1f12c8842a2b55458e1ae6 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Thu, 17 Sep 2020 22:31:18 -0700 Subject: [PATCH 1/5] Add __path__ to package __init__ Resolves #1422 --- mypy/nodes.py | 11 +++++++---- mypy/semanal.py | 6 ++++++ test-data/unit/check-modules.test | 10 ++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/mypy/nodes.py b/mypy/nodes.py index dff1dd6c1072..5f23bc17727a 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -97,10 +97,13 @@ def get_column(self) -> int: inverse_node_kinds = {_kind: _name for _name, _kind in node_kinds.items()} # type: Final -implicit_module_attrs = {'__name__': '__builtins__.str', - '__doc__': None, # depends on Python version, see semanal.py - '__file__': '__builtins__.str', - '__package__': '__builtins__.str'} # type: Final +implicit_module_attrs = { + '__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' +} # type: Final # These aliases exist because built-in class objects are not subscriptable. diff --git a/mypy/semanal.py b/mypy/semanal.py index 2ea444bf4ab2..7826256a512a 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -400,6 +400,12 @@ 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 + typ = self.named_type("__builtins__.list", [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-modules.test b/test-data/unit/check-modules.test index 140a0c017bfd..e49ccf1f36c5 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -2825,3 +2825,13 @@ from mystery import a, b as b, c as d [out] 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/latest/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] From 0faa2b8c217dde74f18649e031cb4db3dcabfc8b Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Fri, 18 Sep 2020 10:39:42 -0700 Subject: [PATCH 2/5] Inline named_type This gives us better errors for fixtures stuff and helps with Python 2 --- mypy/semanal.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 7826256a512a..83f83a4808f5 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -405,7 +405,12 @@ def add_implicit_module_attrs(self, file_node: MypyFile) -> None: continue # Need to construct the type ourselves, to avoid issues with __builtins__.list # not being subscriptable or typing.List not getting bound - typ = self.named_type("__builtins__.list", [self.str_type()]) + 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) From 3e0cf94970c2fe89149b21998a696d4a9230f386 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Fri, 18 Sep 2020 10:40:23 -0700 Subject: [PATCH 3/5] lib-stub: add list to builtins --- test-data/unit/lib-stub/builtins.pyi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test-data/unit/lib-stub/builtins.pyi b/test-data/unit/lib-stub/builtins.pyi index 7ba4002ed4ac..059255e399b5 100644 --- a/test-data/unit/lib-stub/builtins.pyi +++ b/test-data/unit/lib-stub/builtins.pyi @@ -19,4 +19,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 From 68af7a6ffdb32e6cba4f313cc1e132b39b015fab Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Fri, 18 Sep 2020 10:53:36 -0700 Subject: [PATCH 4/5] some other test fixes --- test-data/unit/check-incomplete-fixture.test | 8 -------- test-data/unit/fine-grained-modules.test | 2 +- test-data/unit/fixtures/args.pyi | 4 +++- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/test-data/unit/check-incomplete-fixture.test b/test-data/unit/check-incomplete-fixture.test index 44683ae295cf..bada4d8a74f8 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/fine-grained-modules.test b/test-data/unit/fine-grained-modules.test index 6fb947eb511a..4b57e233334b 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 From 977d93c6f92388366a5bceb9fcaa2a561c536e26 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Thu, 15 Apr 2021 12:11:45 -0700 Subject: [PATCH 5/5] double quotes --- test-data/unit/check-modules.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index c93e2ead42a9..c92c2023ea4a 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -2828,7 +2828,7 @@ tmp/stub.pyi:1: note: See https://mypy.readthedocs.io/en/stable/running_mypy.htm [case testPackagePath] import p -reveal_type(p.__path__) # N: Revealed type is 'builtins.list[builtins.str]' +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]