-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for __spec__ #14739
Add support for __spec__ #14739
Conversation
Fixes python#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
This comment has been minimized.
This comment has been minimized.
elif name == "__spec__": | ||
inst: Type | None = self.named_type_or_none("importlib.machinery.ModuleSpec") | ||
if inst is None: | ||
if self.final_iteration: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this may down slow down tests significantly, since every module top level will have to be processed many times? Maybe instead check options.use_builtins_fixtures
and fall back to builtins.object
immediately if it's true.
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] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider also adding a pythoneval test that uses full stubs.
@hauntsaninja @JukkaL Is there anything that I could help to conclude this PR? |
Yeah, that sounds good. And if you want to experiment before sprints, feel free to post a diff on this PR and I can commit and merge it :-) |
I'd like to, but I need some guidance on writing tests in mypy and internal mechanisms mentioned in the previous review. I'll try a look. |
Maybe the pythoneval test update could be: diff --git a/test-data/unit/pythoneval.test b/test-data/unit/pythoneval.test
index 0ed3540b6..9a43d9071 100644
--- a/test-data/unit/pythoneval.test
+++ b/test-data/unit/pythoneval.test
@@ -107,14 +107,20 @@ f
[case testModuleAttributes]
import math
import typing
+print(type(__spec__))
print(math.__name__)
+print(math.__spec__.name)
print(type(math.__dict__))
print(type(math.__doc__ or ''))
+print(type(math.__spec__))
print(math.__class__)
[out]
+<class 'NoneType'>
+math
math
<class 'dict'>
<class 'str'>
+<class '_frozen_importlib.ModuleSpec'>
<class 'module'>
[case testSpecialAttributes] |
Maybe the first review would intend the following changes..? diff --git a/mypy/semanal.py b/mypy/semanal.py
index 5bafe124b..1158d7f7b 100644
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -662,14 +662,14 @@ class SemanticAnalyzer(
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")
- assert inst is not None, "Cannot find builtins.object"
- else:
- self.defer()
- return
+ assert not self.final_iteration, "Cannot find builtins.object to add __spec__"
+ self.defer()
+ return
if file_node.name == "__main__":
# https://docs.python.org/3/reference/import.html#main-spec
inst = UnionType.make_union([inst, NoneType()]) |
Thank you, pushed with some minor changes (I think we still need the final_iteration code)! Btw, I'm in Room 320 :-) |
Thanks!!! 👍🏼 |
This comment has been minimized.
This comment has been minimized.
@hauntsaninja Here is another patch to add: diff --git a/test-data/unit/fine-grained-inspect.test b/test-data/unit/fine-grained-inspect.test
index f8ce35585..ed89f2f09 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]
==
-{"<pack.bar>": ["C", "__annotations__", "__doc__", "__file__", "__name__", "__package__", "bar", "x"], "ModuleType": ["__file__", "__getattr__"]}
+{"<pack.bar>": ["C", "__annotations__", "__doc__", "__file__", "__name__", "__package__", "__spec__", "bar", "x"], "ModuleType": ["__file__", "__getattr__"]}
[case testInspectModuleDef]
# inspect2: --show=definition --include-kind tmp/foo.py:2:1 |
It seems to be the expected result as now mypy recognizes the |
This comment has been minimized.
This comment has been minimized.
test-data/unit/pythoneval.test
Outdated
math | ||
math | ||
<class '_frozen_importlib_external.ExtensionFileLoader'> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks in Python 3.8... 😥
Diff from mypy_primer, showing the effect of this PR on open source code: pydantic (https://github.com/samuelcolvin/pydantic)
- pydantic/__init__.py:223: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:225: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:226: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:227: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:228: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:229: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:230: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:231: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:232: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:234: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:236: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:237: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:238: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:239: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:240: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:242: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:243: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:245: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:247: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:248: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:249: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:250: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:251: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:252: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:254: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:255: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:256: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:258: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:259: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:260: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:262: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:263: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:265: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:266: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:267: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:268: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:269: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:270: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:271: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:272: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:273: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:274: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:275: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:276: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:277: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:278: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:279: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:280: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:281: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:282: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:283: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:284: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:285: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:286: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:287: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:288: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:290: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:292: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:293: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:294: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:295: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:296: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:297: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:298: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:299: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:300: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:301: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:302: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:303: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:304: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:305: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:306: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:307: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:308: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:309: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:310: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:311: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:312: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:313: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:314: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:315: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:316: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:317: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:318: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:319: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:320: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:321: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:322: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:323: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:324: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:325: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:326: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:327: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:328: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:329: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:330: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:331: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:332: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:333: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:334: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:335: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:336: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:337: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:338: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:339: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:340: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:341: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:342: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:343: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:344: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:345: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:346: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:347: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:348: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:349: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:350: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:352: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:354: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:355: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:356: error: Name "__spec__" is not defined [name-defined]
- pydantic/__init__.py:358: error: Name "__spec__" is not defined [name-defined]
... (truncated 139 lines) ...
|
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__
caseCo-authored-by: Joongi Kim me@daybreaker.info