Skip to content

Commit f201120

Browse files
authored
Change order of search path to fix inconsistency between pylint and astroid. (#2589)
1 parent 8696918 commit f201120

File tree

4 files changed

+60
-1
lines changed

4 files changed

+60
-1
lines changed

ChangeLog

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ What's New in astroid 3.3.6?
2020
============================
2121
Release date: TBA
2222

23+
* Fix precedence of `path` arg in `modpath_from_file_with_callback` to be higher than `sys.path`
2324

2425

2526
What's New in astroid 3.3.5?

astroid/modutils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ def modpath_from_file_with_callback(
278278
filename = os.path.expanduser(_path_from_filename(filename))
279279
paths_to_check = sys.path.copy()
280280
if path:
281-
paths_to_check += path
281+
paths_to_check = path + paths_to_check
282282
for pathname in itertools.chain(
283283
paths_to_check, map(_cache_normalize_path, paths_to_check)
284284
):

astroid/util.py

+26
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
from __future__ import annotations
77

8+
import contextlib
9+
import sys
810
import warnings
11+
from collections.abc import Iterator, Sequence
912
from typing import TYPE_CHECKING, Any, Final, Literal
1013

1114
from astroid.exceptions import InferenceError
@@ -157,3 +160,26 @@ def safe_infer(
157160
return None # there is some kind of ambiguity
158161
except StopIteration:
159162
return value
163+
164+
165+
def _augment_sys_path(additional_paths: Sequence[str]) -> list[str]:
166+
original = list(sys.path)
167+
changes = []
168+
seen = set()
169+
for additional_path in additional_paths:
170+
if additional_path not in seen:
171+
changes.append(additional_path)
172+
seen.add(additional_path)
173+
174+
sys.path[:] = changes + sys.path
175+
return original
176+
177+
178+
@contextlib.contextmanager
179+
def augmented_sys_path(additional_paths: Sequence[str]) -> Iterator[None]:
180+
"""Augment 'sys.path' by adding entries from additional_paths."""
181+
original = _augment_sys_path(additional_paths)
182+
try:
183+
yield
184+
finally:
185+
sys.path[:] = original

tests/test_modutils.py

+32
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from astroid import modutils
2323
from astroid.const import PY310_PLUS
2424
from astroid.interpreter._import import spec
25+
from astroid.util import augmented_sys_path
2526

2627
from . import resources
2728

@@ -175,6 +176,37 @@ def test_import_symlink_with_source_outside_of_path(self) -> None:
175176
finally:
176177
os.remove(linked_file_name)
177178

179+
def test_modpath_from_file_path_order(self) -> None:
180+
"""Test for ordering of paths.
181+
The test does the following:
182+
1. Add a tmp directory to beginning of sys.path via augmented_sys_path
183+
2. Create a module file in sub directory of tmp directory
184+
3. If the sub directory is passed as additional directory, module name
185+
should be relative to the subdirectory since additional directory has
186+
higher precedence."""
187+
with tempfile.TemporaryDirectory() as tmp_dir:
188+
with augmented_sys_path([tmp_dir]):
189+
mod_name = "module"
190+
sub_dirname = "subdir"
191+
sub_dir = tmp_dir + "/" + sub_dirname
192+
os.mkdir(sub_dir)
193+
module_file = f"{sub_dir}/{mod_name}.py"
194+
195+
with open(module_file, "w+", encoding="utf-8"):
196+
pass
197+
198+
# Without additional directory, return relative to tmp_dir
199+
self.assertEqual(
200+
modutils.modpath_from_file(module_file), [sub_dirname, mod_name]
201+
)
202+
203+
# With sub directory as additional directory, return relative to
204+
# sub directory
205+
self.assertEqual(
206+
modutils.modpath_from_file(f"{sub_dir}/{mod_name}.py", [sub_dir]),
207+
[mod_name],
208+
)
209+
178210
def test_import_symlink_both_outside_of_path(self) -> None:
179211
with tempfile.NamedTemporaryFile() as tmpfile:
180212
linked_file_name = os.path.join(tempfile.gettempdir(), "symlinked_file.py")

0 commit comments

Comments
 (0)