|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
| 3 | +import importlib |
| 4 | +import os |
3 | 5 | import pkgutil |
4 | 6 | import sys |
5 | 7 | import token |
6 | 8 | import tokenize |
| 9 | +from importlib.machinery import FileFinder |
7 | 10 | from io import StringIO |
8 | 11 | from contextlib import contextmanager |
9 | 12 | from dataclasses import dataclass |
@@ -50,6 +53,7 @@ def __init__(self, namespace: Mapping[str, Any] | None = None) -> None: |
50 | 53 | self.namespace = namespace or {} |
51 | 54 | self._global_cache: list[pkgutil.ModuleInfo] = [] |
52 | 55 | self._curr_sys_path: list[str] = sys.path[:] |
| 56 | + self._stdlib_path = os.path.dirname(importlib.__path__[0]) |
53 | 57 |
|
54 | 58 | def get_completions(self, line: str) -> list[str] | None: |
55 | 59 | """Return the next possible import completions for 'line'.""" |
@@ -104,16 +108,27 @@ def _find_modules(self, path: str, prefix: str) -> list[str]: |
104 | 108 | return [] |
105 | 109 |
|
106 | 110 | modules: Iterable[pkgutil.ModuleInfo] = self.global_cache |
| 111 | + is_stdlib_import: bool | None = None |
107 | 112 | for segment in path.split('.'): |
108 | 113 | modules = [mod_info for mod_info in modules |
109 | 114 | if mod_info.ispkg and mod_info.name == segment] |
| 115 | + if is_stdlib_import is None: |
| 116 | + # Top-level import decide if we import from stdlib or not |
| 117 | + is_stdlib_import = all( |
| 118 | + self._is_stdlib_module(mod_info) for mod_info in modules |
| 119 | + ) |
110 | 120 | modules = self.iter_submodules(modules) |
111 | 121 |
|
112 | 122 | module_names = [module.name for module in modules] |
113 | | - module_names.extend(HARDCODED_SUBMODULES.get(path, ())) |
| 123 | + if is_stdlib_import: |
| 124 | + module_names.extend(HARDCODED_SUBMODULES.get(path, ())) |
114 | 125 | return [module_name for module_name in module_names |
115 | 126 | if self.is_suggestion_match(module_name, prefix)] |
116 | 127 |
|
| 128 | + def _is_stdlib_module(self, module_info: pkgutil.ModuleInfo) -> bool: |
| 129 | + return (isinstance(module_info.module_finder, FileFinder) |
| 130 | + and module_info.module_finder.path == self._stdlib_path) |
| 131 | + |
117 | 132 | def is_suggestion_match(self, module_name: str, prefix: str) -> bool: |
118 | 133 | if prefix: |
119 | 134 | return module_name.startswith(prefix) |
|
0 commit comments