-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Fixed the issue of causes KeyError
when using the parameter --import-mode=importlib
in pytest>=8.2 . (#12592)
#12752
base: main
Are you sure you want to change the base?
Conversation
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.
Thanks @dongfangtianyu, but I'm not sure this approach is correct (although the introduced test seems to indicate it works).
Perhaps it would be helpful to submit a snippet upstream that uses PathFinder.find_spec
and causes it to raise KeyError
to obtain advice.
@@ -629,6 +629,15 @@ def _import_module_using_spec( | |||
|
|||
if spec_matches_module_path(spec, module_path): | |||
assert spec is not None | |||
|
|||
# Find spec and import this module. |
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.
Thanks @dongfangtianyu for the PR.
Based on this, I attempted to modify the execution process in _import_module_using_spec, moving the import of the parent module to after insert_missing_modules() to avoid a KeyError due to sys.modules not being ready.
But this change seems to be doing the opposite of what is recommended by https://docs.python.org/3/library/importlib.html#approximating-importlib-import-module: it is attempting to import the child module first, insert dummy/missing modules, and then import the parent module. The linked docs do the exact opposite.
Seems like inserting the dummy modules at this point might just be silencing the error with dummy modules instead of the correct modules.
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.
The original plan was to refactor this function by following the documentation example.
A shortcut was to use insert_missing_modules to simulate the keys in sys.modules, and unexpectedly, the tests passed.
I apologize for not tracking or analyzing the impact of this approach. I will confirm the implications as soon as possible.
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.
Confirmation: When loading test case files outside the cwd, the insert_missing_modules function will mock all levels of parent modules, which is not expected.
Thank you for your response @nicoddemus . I’m also unsure if this approach is suitable. The main purpose of this PR is to request a review and discussion from the maintainers. I’ve tried various fixes, but all have failed. During this process, I’ve often thought that this issue should be fixed upstream. Since I’m not yet familiar with the lower-level aspects of Python, I’ve been avoiding creating an issue in the Python repository. However, you’re right. I will prepare a sample code later and seek advice from upstream. |
…in the namespace package causes a KeyError.(pytest-dev#12592)
098e5a6
to
7108bb9
Compare
Hi @nicoddemus , can you please re-review the code? Judging from the results, the effect of this modification:
Welcome any further suggestions. |
Hi @dongfangtianyu just to let you know I've been busy, but I will review this ASAP. 👍 |
closes #12592
Reproduction Steps:
Create a namespace package in a non-root directory and include a test file.
Create a directory with the same name in that location.
Directory Structure:
Execution Results:
Through tracing, it was discovered that the error occurs during the second call to
pathlib._import_module_using_spec
.This is the entire call process when the exception occurs.
In simple terms, when executing
PathFinder.find_spec('a.b.c', ['/app/a/b/c'])
:Python assumes that we are trying to import a module named
c
(the tail module).At this point, there happens to be a directory
c
in/app/a/b/c
, which is then treated as a namespace.According to convention, its parent module
a.b
should already exist insys.modules
, and it is accessed directly using the item method.However, when pytest uses the
importlib
mode, it doesn't follow this convention, leading to aKeyError
.So, from the observable behavior, it seems to be an upstream issue.
However, from a deeper perspective, there might also be a problem with pytest's handling of parent module imports.
I noticed that
_import_module_using_spec
attempts to follow the convention of importing the parent module, but the error occurs precisely during this process:https://github.com/pytest-dev/pytest/blob/main/src/_pytest/pathlib.py#L634-L656
I searched for the usage of 'importlib', and the example provided in the Python documentation can import of any module or namespace package in this case:
https://docs.python.org/3/library/importlib.html#approximating-importlib-import-module.
Unlike
_import_module_using_spec
, the example function in the documentation first ensures that the necessary parent modules are present insys.modules
, and then imports the target module (or target namespace package).Based on this, I attempted to modify the execution process in
_import_module_using_spec
, moving the import of the parent module to afterinsert_missing_modules()
to avoid aKeyError
due tosys.modules
not being ready.From the test results, it works quite well, but I'm not sure if there are potential flaws or better solutions (in fact, I've tried and discarded many solutions).
Welcome any further suggestions.