Fix PytestPluginManager._is_in_confcutdir on Windows
On Windows two paths might be in different drives, so if a path is not one of the parents of the confcutdir, it does not necessarily mean it is inside the confcutdir either. Use `Path.is_relative_to` instead which directly answers that question for us. The previous implementation could cause pytest to inspect all the parent paths of a path from one drive if pytest was invoked from another drive. Moved the implementation to a function because it would be too convoluted to test the `PytestPluginManager._is_in_confcutdir` method directly.
This commit is contained in:
parent
5f241f388b
commit
f829a1ef06
|
@ -580,11 +580,9 @@ class PytestPluginManager(PluginManager):
|
||||||
def _is_in_confcutdir(self, path: Path) -> bool:
|
def _is_in_confcutdir(self, path: Path) -> bool:
|
||||||
"""Whether a path is within the confcutdir.
|
"""Whether a path is within the confcutdir.
|
||||||
|
|
||||||
When false, should not load conftest.
|
When false, should not load conftest or recurse into path for collection.
|
||||||
"""
|
"""
|
||||||
if self._confcutdir is None:
|
return path_within_confcutdir(path=path, confcutdir=self._confcutdir)
|
||||||
return True
|
|
||||||
return path not in self._confcutdir.parents
|
|
||||||
|
|
||||||
def _try_load_conftest(
|
def _try_load_conftest(
|
||||||
self, anchor: Path, importmode: Union[str, ImportMode], rootpath: Path
|
self, anchor: Path, importmode: Union[str, ImportMode], rootpath: Path
|
||||||
|
@ -609,9 +607,6 @@ class PytestPluginManager(PluginManager):
|
||||||
if directory in self._dirpath2confmods:
|
if directory in self._dirpath2confmods:
|
||||||
return
|
return
|
||||||
|
|
||||||
# XXX these days we may rather want to use config.rootpath
|
|
||||||
# and allow users to opt into looking into the rootdir parent
|
|
||||||
# directories instead of requiring to specify confcutdir.
|
|
||||||
clist = []
|
clist = []
|
||||||
for parent in reversed((directory, *directory.parents)):
|
for parent in reversed((directory, *directory.parents)):
|
||||||
if self._is_in_confcutdir(parent):
|
if self._is_in_confcutdir(parent):
|
||||||
|
@ -1908,3 +1903,10 @@ def apply_warning_filters(
|
||||||
|
|
||||||
for arg in cmdline_filters:
|
for arg in cmdline_filters:
|
||||||
warnings.filterwarnings(*parse_warning_filter(arg, escape=True))
|
warnings.filterwarnings(*parse_warning_filter(arg, escape=True))
|
||||||
|
|
||||||
|
|
||||||
|
def path_within_confcutdir(*, path: Path, confcutdir: Optional[Path]) -> bool:
|
||||||
|
# Extracted into a function for unit-testing.
|
||||||
|
if confcutdir is None:
|
||||||
|
return True
|
||||||
|
return path.is_relative_to(confcutdir)
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
# mypy: allow-untyped-defs
|
# mypy: allow-untyped-defs
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from _pytest.config import Config
|
from _pytest.config import Config
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
|
from _pytest.config import path_within_confcutdir
|
||||||
from _pytest.config import PytestPluginManager
|
from _pytest.config import PytestPluginManager
|
||||||
from _pytest.config.exceptions import UsageError
|
from _pytest.config.exceptions import UsageError
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
@ -404,7 +407,7 @@ class TestPytestPluginManager:
|
||||||
pytestpm.consider_conftest(mod, registration_name="unused")
|
pytestpm.consider_conftest(mod, registration_name="unused")
|
||||||
|
|
||||||
|
|
||||||
class TestPytestPluginManagerBootstrapming:
|
class TestPytestPluginManagerBootstrapping:
|
||||||
def test_preparse_args(self, pytestpm: PytestPluginManager) -> None:
|
def test_preparse_args(self, pytestpm: PytestPluginManager) -> None:
|
||||||
pytest.raises(
|
pytest.raises(
|
||||||
ImportError, lambda: pytestpm.consider_preparse(["xyz", "-p", "hello123"])
|
ImportError, lambda: pytestpm.consider_preparse(["xyz", "-p", "hello123"])
|
||||||
|
@ -464,3 +467,53 @@ class TestPytestPluginManagerBootstrapming:
|
||||||
assert pytestpm.has_plugin("abc")
|
assert pytestpm.has_plugin("abc")
|
||||||
assert not pytestpm.is_blocked("abc")
|
assert not pytestpm.is_blocked("abc")
|
||||||
assert not pytestpm.is_blocked("pytest_abc")
|
assert not pytestpm.is_blocked("pytest_abc")
|
||||||
|
|
||||||
|
|
||||||
|
skip_if_win = pytest.mark.skipif(
|
||||||
|
not sys.platform.startswith("win"), reason="Windows only"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"path, confcutdir, expected",
|
||||||
|
[
|
||||||
|
(Path("/projects/app/tests"), Path("/projects/app"), True),
|
||||||
|
(Path("/projects/app"), Path("/projects/app"), True),
|
||||||
|
(Path("/projects"), Path("/projects/app"), False),
|
||||||
|
(Path("/"), Path("/projects/app"), False),
|
||||||
|
pytest.param(
|
||||||
|
Path("e:/projects/app/tests"),
|
||||||
|
Path("e:/projects/app"),
|
||||||
|
True,
|
||||||
|
marks=skip_if_win,
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
Path("e:/projects/app"),
|
||||||
|
Path("e:/projects/app"),
|
||||||
|
True,
|
||||||
|
marks=skip_if_win,
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
Path("e:/"),
|
||||||
|
Path("e:/projects/app"),
|
||||||
|
False,
|
||||||
|
marks=skip_if_win,
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
Path("c:/testing"),
|
||||||
|
Path("e:/projects/app"),
|
||||||
|
False,
|
||||||
|
marks=skip_if_win,
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
Path("c:/projects/app"),
|
||||||
|
Path("e:/projects/app"),
|
||||||
|
False,
|
||||||
|
marks=skip_if_win,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_path_within_confcutdir(
|
||||||
|
path: Path, confcutdir: Optional[Path], expected: bool
|
||||||
|
) -> None:
|
||||||
|
assert path_within_confcutdir(path=path, confcutdir=confcutdir) == expected
|
||||||
|
|
Loading…
Reference in New Issue