-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
gh-69605: Check for already imported modules in PyREPL module completion #139461
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
Changes from 18 commits
6ed2776
48fd43f
7ac428e
6515e2f
7dbb906
ac3065a
75a33da
ce124b1
ee7047f
3f362cd
ed8ce73
19c49bb
16e44af
14f6175
bdd7bdf
78e4737
e3f1ddb
2644400
5fa70cf
d332e14
1a5327c
d48f243
e235e20
f6757fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,7 +107,23 @@ def _find_modules(self, path: str, prefix: str) -> list[str]: | |
| if path is None: | ||
| return [] | ||
|
|
||
| modules: Iterable[pkgutil.ModuleInfo] = self.global_cache | ||
| modules: Iterable[pkgutil.ModuleInfo] | ||
| imported_module = sys.modules.get(path.split('.')[0]) | ||
| if imported_module: | ||
| # Module already imported: only look in its location, | ||
| # even if a module with the same name would be higher in path | ||
| imported_path = (imported_module.__spec__ | ||
| and imported_module.__spec__.origin) | ||
| if not imported_path: | ||
| # Module imported but no spec/origin: propose no suggestions | ||
| return [] | ||
| if os.path.basename(imported_path) == "__init__.py": # package | ||
| imported_path = os.path.dirname(imported_path) | ||
| import_location = os.path.dirname(imported_path) | ||
| modules = list(pkgutil.iter_modules([import_location])) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if this is correct, it's going to find submodules but we actually want this to be the top-level modules
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe it's OK, because >>> import os, pkgutil, typing, concurrent
>>>
>>> typing.__spec__.origin # single-file module
'<venv>/lib/python3.14/typing.py'
>>> concurrent.__spec__.origin # package
'<venv>/lib/python3.14/concurrent/__init__.py'
>>>
>>> loc = os.path.dirname(typing.__spec__.origin) # or do it twice for concurrent
>>> [mod for mod in pkgutil.iter_modules([loc]) if mod.name in ("typing", "concurrent")]
[ModuleInfo(module_finder=FileFinder('<venv>/lib/python3.14'), name='concurrent', ispkg=True),
ModuleInfo(module_finder=FileFinder('<venv>/lib/python3.14'), name='typing', ispkg=False)]While refactoring this into a separate function I ended up rewriting the whole thing, it should be more explicit now (and it checks |
||
| else: | ||
| modules = self.global_cache | ||
|
|
||
| is_stdlib_import: bool | None = None | ||
| for segment in path.split('.'): | ||
| modules = [mod_info for mod_info in modules | ||
|
|
@@ -196,7 +212,6 @@ def global_cache(self) -> list[pkgutil.ModuleInfo]: | |
| """Global module cache""" | ||
| if not self._global_cache or self._curr_sys_path != sys.path: | ||
| self._curr_sys_path = sys.path[:] | ||
| # print('getting packages') | ||
| self._global_cache = list(pkgutil.iter_modules()) | ||
| return self._global_cache | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Fix edge-cases around already imported modules in the :term:`REPL` | ||
| auto-completion of imports. |
Uh oh!
There was an error while loading. Please reload this page.