Skip to content

Commit 02d86b8

Browse files
Hugohong258sebastinas
authored andcommitted
Support absolute paths in import completion skip list
1 parent 4a21ac0 commit 02d86b8

3 files changed

Lines changed: 55 additions & 5 deletions

File tree

‎bpython/importcompletion.py‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,24 @@ def complete(self, cursor_offset: int, line: str) -> set[str] | None:
162162
else:
163163
return None
164164

165+
def _is_skipped(self, path: Path) -> bool:
166+
for pattern in self.skiplist:
167+
if Path(pattern).is_absolute():
168+
if any(
169+
fnmatch.fnmatch(str(parent), pattern)
170+
for parent in (path, *path.parents)
171+
):
172+
return True
173+
elif fnmatch.fnmatch(path.name, pattern):
174+
return True
175+
return False
176+
165177
def find_modules(self, path: Path) -> Generator[str | None, None, None]:
166178
"""Find all modules (and packages) for a given directory."""
167179
if not path.is_dir():
168180
# Perhaps a zip file
169181
return
170-
if any(fnmatch.fnmatch(path.name, entry) for entry in self.skiplist):
182+
if self._is_skipped(path):
171183
# Path is on skiplist
172184
return
173185

@@ -177,9 +189,7 @@ def find_modules(self, path: Path) -> Generator[str | None, None, None]:
177189
if p.name.startswith(".") or p.name == "__pycache__":
178190
# Impossible to import from names starting with . and we can skip __pycache__
179191
continue
180-
elif any(
181-
fnmatch.fnmatch(p.name, entry) for entry in self.skiplist
182-
):
192+
elif self._is_skipped(p):
183193
# Path is on skiplist
184194
continue
185195
elif not any(p.name.endswith(suffix) for suffix in SUFFIXES):

‎bpython/test/test_importcompletion.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,40 @@ def test_simple_symbolic_link_loop(self):
192192
self.assertFalse(filepaths)
193193

194194

195+
class TestSkiplist(unittest.TestCase):
196+
def test_absolute_paths(self):
197+
with tempfile.TemporaryDirectory() as directory:
198+
root = Path(directory).resolve()
199+
for name in ("first", "second"):
200+
(root / name).mkdir()
201+
(root / name / "__init__.py").touch()
202+
(root / name / "inside.py").touch()
203+
204+
cases = (
205+
([root], str(root), set()),
206+
([root], str(root / "first"), {"second", "second.inside"}),
207+
([root / "first"], str(root), set()),
208+
)
209+
for paths, skip, expected in cases:
210+
with self.subTest(paths=paths, skip=skip):
211+
gatherer = ModuleGatherer(paths, [skip])
212+
while gatherer.find_coroutine():
213+
pass
214+
self.assertEqual(gatherer.modules, expected)
215+
216+
def test_relative_name_pattern_remains_supported(self):
217+
with tempfile.TemporaryDirectory() as directory:
218+
root = Path(directory).resolve()
219+
for name in ("first", "second"):
220+
(root / name).mkdir()
221+
(root / name / "__init__.py").touch()
222+
(root / name / "inside.py").touch()
223+
gatherer = ModuleGatherer([root], ["f*"])
224+
while gatherer.find_coroutine():
225+
pass
226+
self.assertEqual(gatherer.modules, {"second", "second.inside"})
227+
228+
195229
class TestBugReports(unittest.TestCase):
196230
def test_issue_847(self):
197231
with tempfile.TemporaryDirectory() as import_test_folder:

‎doc/sphinx/source/configuration-options.rst‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,13 @@ Whether to use Unicode characters to draw boxes (default: True).
186186

187187
import_completion_skiplist
188188
^^^^^^^^^^^^^^^^^^^^^^^^^^
189-
A `:`-seperated list of patterns to skip when processing modules for import completion.
189+
A ``:``-separated list of patterns to skip when processing modules for import
190+
completion. A name pattern such as ``node_modules`` or ``build*`` matches names
191+
at any level. On POSIX systems, an absolute path such as ``/home/user/projects``
192+
skips that directory and its descendants, including when a descendant is itself
193+
on the module search path. Paths are matched against resolved filesystem paths.
194+
The colon separator means that Windows drive-letter paths cannot be specified
195+
in this option.
190196

191197
.. versionadded:: 0.21
192198

0 commit comments

Comments
 (0)