Merge pull request #1030 from jeremy-hiatt/dont-rewrite-path-hooks

Avoid modifying path placeholders created by editable installs
This commit is contained in:
Ronny Pfannschmidt
2024-03-01 07:34:14 +01:00
committed by GitHub
3 changed files with 42 additions and 1 deletions

1
changelog/1028.bugfix Normal file
View File

@@ -0,0 +1 @@
Fix compatiblity issue between `looponfail` and editable installs.

View File

@@ -160,7 +160,8 @@ def init_worker_session(channel, args, option_dict):
newpaths = [] newpaths = []
for p in sys.path: for p in sys.path:
if p: if p:
if not os.path.isabs(p): # Ignore path placeholders created for editable installs
if not os.path.isabs(p) and not p.endswith(".__path_hook__"):
p = os.path.abspath(p) p = os.path.abspath(p)
newpaths.append(p) newpaths.append(p)
sys.path[:] = newpaths sys.path[:] = newpaths

View File

@@ -1,3 +1,5 @@
import pathlib
import tempfile
import unittest.mock import unittest.mock
from typing import List from typing import List
@@ -191,6 +193,43 @@ class TestRemoteControl:
control.loop_once() control.loop_once()
assert control.failures assert control.failures
def test_ignore_sys_path_hook_entry(
self, pytester: pytest.Pytester, monkeypatch: pytest.MonkeyPatch
) -> None:
# Modifying sys.path as seen by the worker process is a bit tricky,
# because any changes made in the current process do not carry over.
# However, we can leverage the `sitecustomize` behavior to run arbitrary
# code when the subprocess interpreter is starting up. We just need to
# install our module in the search path, which we can accomplish by
# adding a temporary directory to PYTHONPATH.
tmpdir = tempfile.TemporaryDirectory()
with open(pathlib.Path(tmpdir.name) / "sitecustomize.py", "w") as custom:
print(
textwrap.dedent(
"""
import sys
sys.path.append('dummy.__path_hook__')
"""
),
file=custom,
)
monkeypatch.setenv("PYTHONPATH", tmpdir.name, prepend=":")
item = pytester.getitem(
textwrap.dedent(
"""
def test_func():
import sys
assert "dummy.__path_hook__" in sys.path
"""
)
)
control = RemoteControl(item.config)
control.setup()
topdir, failures = control.runsession()[:2]
assert not failures
class TestLooponFailing: class TestLooponFailing:
def test_looponfail_from_fail_to_ok(self, pytester: pytest.Pytester) -> None: def test_looponfail_from_fail_to_ok(self, pytester: pytest.Pytester) -> None: