From 830db42d5d72ef97be7ddbe5a505e8af0491f0e2 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 19 Feb 2023 17:01:39 -0800 Subject: [PATCH 1/5] Add support for __spec__ Fixes #4145 It was too annoying to get the fixtures to work out here, so I didn't. But you can see the tests will add the None for the non `__main__` case --- mypy/nodes.py | 1 + mypy/semanal.py | 14 ++++++++++++++ test-data/unit/check-basic.test | 8 ++++++++ 3 files changed, 23 insertions(+) diff --git a/mypy/nodes.py b/mypy/nodes.py index 4787930214f3..dc32a638ad4c 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -115,6 +115,7 @@ def set_line( "__file__": "__builtins__.str", "__package__": "__builtins__.str", "__annotations__": None, # dict[str, Any] bounded in add_implicit_module_attrs() + "__spec__": None, # importlib.machinery.ModuleSpec bounded in add_implicit_module_attrs() } diff --git a/mypy/semanal.py b/mypy/semanal.py index d2fd92499679..1d6411d5ed92 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -270,6 +270,7 @@ TypeVarLikeType, TypeVarType, UnboundType, + UnionType, UnpackType, get_proper_type, get_proper_types, @@ -644,6 +645,19 @@ def add_implicit_module_attrs(self, file_node: MypyFile) -> None: self.defer() return typ = inst + elif name == "__spec__": + inst: Type | None = self.named_type_or_none("importlib.machinery.ModuleSpec") + if inst is None: + if self.final_iteration: + inst = self.named_type_or_none("builtins.object") + assert inst is not None, "Cannot find builtins.object" + else: + self.defer() + return + if file_node.name == "__main__": + # https://docs.python.org/3/reference/import.html#main-spec + inst = UnionType.make_union([inst, NoneType()]) + typ = inst else: assert t is not None, f"type should be specified for {name}" typ = UnboundType(t) diff --git a/test-data/unit/check-basic.test b/test-data/unit/check-basic.test index c16b9e40122d..b81f9573b347 100644 --- a/test-data/unit/check-basic.test +++ b/test-data/unit/check-basic.test @@ -219,6 +219,14 @@ 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]" +# This will actually reveal Union[importlib.machinery.ModuleSpec, None] +reveal_type(__spec__) # N: Revealed type is "Union[builtins.object, None]" + +import module +reveal_type(module.__name__) # N: Revealed type is "builtins.str" +# This will actually reveal importlib.machinery.ModuleSpec +reveal_type(module.__spec__) # N: Revealed type is "builtins.object" +[file module.py] [builtins fixtures/primitives.pyi] From 50d08971f64e1d2ad10f1e14fdfb8056fd655bfa Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Mon, 20 May 2024 10:23:02 -0400 Subject: [PATCH 2/5] feedback --- mypy/semanal.py | 5 ++++- test-data/unit/pythoneval.test | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 1d6411d5ed92..a57fa92a25cb 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -646,7 +646,10 @@ def add_implicit_module_attrs(self, file_node: MypyFile) -> None: return typ = inst elif name == "__spec__": - inst: Type | None = self.named_type_or_none("importlib.machinery.ModuleSpec") + if self.options.use_builtins_fixtures: + inst = self.named_type_or_none("builtins.object") + else: + inst = self.named_type_or_none("importlib.machinery.ModuleSpec") if inst is None: if self.final_iteration: inst = self.named_type_or_none("builtins.object") diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index fbbaecbba241..788eedd75a13 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -107,14 +107,22 @@ f [case testModuleAttributes] import math import typing +print(type(__spec__)) print(math.__name__) +print(math.__spec__.name) +print(type(math.__spec__.loader)) print(type(math.__dict__)) print(type(math.__doc__ or '')) +print(type(math.__spec__)) print(math.__class__) [out] + math +math + + [case testSpecialAttributes] From 4705f0b9d5279bb34e78e988ab81d6c2b923a1b4 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Mon, 20 May 2024 10:38:30 -0400 Subject: [PATCH 3/5] fixup --- mypy/semanal.py | 1 + test-data/unit/pythoneval.test | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 7dcd3e7b11db..61c4eb737fb9 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -636,6 +636,7 @@ def add_implicit_module_attrs(self, file_node: MypyFile) -> None: str_type: Type | None = self.named_type_or_none("builtins.str") if str_type is None: str_type = UnboundType("builtins.str") + inst: Type | None for name, t in implicit_module_attrs.items(): if name == "__doc__": typ: Type = str_type diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 2a86250c657a..716a4eb4f6a3 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -113,7 +113,7 @@ print(math.__spec__.name) print(type(math.__spec__.loader)) print(type(math.__dict__)) print(type(math.__doc__ or '')) -print(type(math.__spec__)) +print(type(math.__spec__).__name__) print(math.__class__) [out] @@ -122,7 +122,7 @@ math - +ModuleSpec [case testSpecialAttributes] From 411c328ca47a501343ae2165d98ea988e761448d Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Mon, 20 May 2024 17:11:53 -0400 Subject: [PATCH 4/5] . --- test-data/unit/fine-grained-inspect.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/fine-grained-inspect.test b/test-data/unit/fine-grained-inspect.test index f8ce35585c10..ed89f2f099f9 100644 --- a/test-data/unit/fine-grained-inspect.test +++ b/test-data/unit/fine-grained-inspect.test @@ -236,7 +236,7 @@ class C: ... [builtins fixtures/module.pyi] [out] == -{"": ["C", "__annotations__", "__doc__", "__file__", "__name__", "__package__", "bar", "x"], "ModuleType": ["__file__", "__getattr__"]} +{"": ["C", "__annotations__", "__doc__", "__file__", "__name__", "__package__", "__spec__", "bar", "x"], "ModuleType": ["__file__", "__getattr__"]} [case testInspectModuleDef] # inspect2: --show=definition --include-kind tmp/foo.py:2:1 From d01b0cfd004bfc1fad819193f341533b852d2436 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Mon, 20 May 2024 18:22:12 -0400 Subject: [PATCH 5/5] . --- test-data/unit/pythoneval.test | 2 -- 1 file changed, 2 deletions(-) diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test index 716a4eb4f6a3..acb0ff88ad04 100644 --- a/test-data/unit/pythoneval.test +++ b/test-data/unit/pythoneval.test @@ -110,7 +110,6 @@ import typing print(type(__spec__)) print(math.__name__) print(math.__spec__.name) -print(type(math.__spec__.loader)) print(type(math.__dict__)) print(type(math.__doc__ or '')) print(type(math.__spec__).__name__) @@ -119,7 +118,6 @@ print(math.__class__) math math - ModuleSpec