pathlib: replace py.path.local.visit() with our own function
Part of reducing dependency on `py`. Also enables upcoming improvements. In cases where there are simpler alternatives (in tests), I used those. What's left are a couple of uses in `_pytest.main` and `_pytest.python` and they only have modest requirements, so all of the featureful code from py is not needed.
This commit is contained in:
parent
3a060b77e8
commit
c15bb5d3de
|
@ -32,6 +32,7 @@ from _pytest.config.argparsing import Parser
|
||||||
from _pytest.fixtures import FixtureManager
|
from _pytest.fixtures import FixtureManager
|
||||||
from _pytest.outcomes import exit
|
from _pytest.outcomes import exit
|
||||||
from _pytest.pathlib import Path
|
from _pytest.pathlib import Path
|
||||||
|
from _pytest.pathlib import visit
|
||||||
from _pytest.reports import CollectReport
|
from _pytest.reports import CollectReport
|
||||||
from _pytest.reports import TestReport
|
from _pytest.reports import TestReport
|
||||||
from _pytest.runner import collect_one_node
|
from _pytest.runner import collect_one_node
|
||||||
|
@ -617,9 +618,10 @@ class Session(nodes.FSCollector):
|
||||||
assert not names, "invalid arg {!r}".format((argpath, names))
|
assert not names, "invalid arg {!r}".format((argpath, names))
|
||||||
|
|
||||||
seen_dirs = set() # type: Set[py.path.local]
|
seen_dirs = set() # type: Set[py.path.local]
|
||||||
for path in argpath.visit(
|
for path in visit(argpath, self._recurse):
|
||||||
fil=self._visit_filter, rec=self._recurse, bf=True, sort=True
|
if not path.check(file=1):
|
||||||
):
|
continue
|
||||||
|
|
||||||
dirpath = path.dirpath()
|
dirpath = path.dirpath()
|
||||||
if dirpath not in seen_dirs:
|
if dirpath not in seen_dirs:
|
||||||
# Collect packages first.
|
# Collect packages first.
|
||||||
|
@ -668,11 +670,6 @@ class Session(nodes.FSCollector):
|
||||||
return
|
return
|
||||||
yield from m
|
yield from m
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _visit_filter(f: py.path.local) -> bool:
|
|
||||||
# TODO: Remove type: ignore once `py` is typed.
|
|
||||||
return f.check(file=1) # type: ignore
|
|
||||||
|
|
||||||
def _tryconvertpyarg(self, x: str) -> str:
|
def _tryconvertpyarg(self, x: str) -> str:
|
||||||
"""Convert a dotted module name to path."""
|
"""Convert a dotted module name to path."""
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -16,6 +16,7 @@ from os.path import isabs
|
||||||
from os.path import sep
|
from os.path import sep
|
||||||
from posixpath import sep as posix_sep
|
from posixpath import sep as posix_sep
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
|
from typing import Callable
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
@ -556,3 +557,17 @@ def resolve_package_path(path: Path) -> Optional[Path]:
|
||||||
break
|
break
|
||||||
result = parent
|
result = parent
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def visit(
|
||||||
|
path: py.path.local, recurse: Callable[[py.path.local], bool],
|
||||||
|
) -> Iterator[py.path.local]:
|
||||||
|
"""Walk path recursively, in breadth-first order.
|
||||||
|
|
||||||
|
Entries at each directory level are sorted.
|
||||||
|
"""
|
||||||
|
entries = sorted(path.listdir())
|
||||||
|
yield from entries
|
||||||
|
for entry in entries:
|
||||||
|
if entry.check(dir=1) and recurse(entry):
|
||||||
|
yield from visit(entry, recurse)
|
||||||
|
|
|
@ -65,6 +65,7 @@ from _pytest.outcomes import skip
|
||||||
from _pytest.pathlib import import_path
|
from _pytest.pathlib import import_path
|
||||||
from _pytest.pathlib import ImportPathMismatchError
|
from _pytest.pathlib import ImportPathMismatchError
|
||||||
from _pytest.pathlib import parts
|
from _pytest.pathlib import parts
|
||||||
|
from _pytest.pathlib import visit
|
||||||
from _pytest.reports import TerminalRepr
|
from _pytest.reports import TerminalRepr
|
||||||
from _pytest.warning_types import PytestCollectionWarning
|
from _pytest.warning_types import PytestCollectionWarning
|
||||||
from _pytest.warning_types import PytestUnhandledCoroutineWarning
|
from _pytest.warning_types import PytestUnhandledCoroutineWarning
|
||||||
|
@ -641,7 +642,7 @@ class Package(Module):
|
||||||
):
|
):
|
||||||
yield Module.from_parent(self, fspath=init_module)
|
yield Module.from_parent(self, fspath=init_module)
|
||||||
pkg_prefixes = set() # type: Set[py.path.local]
|
pkg_prefixes = set() # type: Set[py.path.local]
|
||||||
for path in this_path.visit(rec=self._recurse, bf=True, sort=True):
|
for path in visit(this_path, recurse=self._recurse):
|
||||||
# We will visit our own __init__.py file, in which case we skip it.
|
# We will visit our own __init__.py file, in which case we skip it.
|
||||||
is_file = path.isfile()
|
is_file = path.isfile()
|
||||||
if is_file:
|
if is_file:
|
||||||
|
|
|
@ -142,14 +142,14 @@ class TestFillFixtures:
|
||||||
p = testdir.copy_example()
|
p = testdir.copy_example()
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||||
result = testdir.runpytest(next(p.visit("test_*.py")))
|
result = testdir.runpytest(str(next(Path(str(p)).rglob("test_*.py"))))
|
||||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||||
|
|
||||||
def test_extend_fixture_conftest_conftest(self, testdir):
|
def test_extend_fixture_conftest_conftest(self, testdir):
|
||||||
p = testdir.copy_example()
|
p = testdir.copy_example()
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||||
result = testdir.runpytest(next(p.visit("test_*.py")))
|
result = testdir.runpytest(str(next(Path(str(p)).rglob("test_*.py"))))
|
||||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||||
|
|
||||||
def test_extend_fixture_conftest_plugin(self, testdir):
|
def test_extend_fixture_conftest_plugin(self, testdir):
|
||||||
|
|
|
@ -7,6 +7,7 @@ import pytest
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.main import _in_venv
|
from _pytest.main import _in_venv
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
from _pytest.pathlib import Path
|
||||||
from _pytest.pathlib import symlink_or_skip
|
from _pytest.pathlib import symlink_or_skip
|
||||||
from _pytest.pytester import Testdir
|
from _pytest.pytester import Testdir
|
||||||
|
|
||||||
|
@ -115,8 +116,8 @@ class TestCollectFS:
|
||||||
tmpdir.ensure(".whatever", "test_notfound.py")
|
tmpdir.ensure(".whatever", "test_notfound.py")
|
||||||
tmpdir.ensure(".bzr", "test_notfound.py")
|
tmpdir.ensure(".bzr", "test_notfound.py")
|
||||||
tmpdir.ensure("normal", "test_found.py")
|
tmpdir.ensure("normal", "test_found.py")
|
||||||
for x in tmpdir.visit("test_*.py"):
|
for x in Path(str(tmpdir)).rglob("test_*.py"):
|
||||||
x.write("def test_hello(): pass")
|
x.write_text("def test_hello(): pass", "utf-8")
|
||||||
|
|
||||||
result = testdir.runpytest("--collect-only")
|
result = testdir.runpytest("--collect-only")
|
||||||
s = result.stdout.str()
|
s = result.stdout.str()
|
||||||
|
|
|
@ -477,8 +477,9 @@ class TestConftestVisibility:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
print("created directory structure:")
|
print("created directory structure:")
|
||||||
for x in testdir.tmpdir.visit():
|
tmppath = Path(str(testdir.tmpdir))
|
||||||
print(" " + x.relto(testdir.tmpdir))
|
for x in tmppath.rglob(""):
|
||||||
|
print(" " + str(x.relative_to(tmppath)))
|
||||||
|
|
||||||
return {"runner": runner, "package": package, "swc": swc, "snc": snc}
|
return {"runner": runner, "package": package, "swc": swc, "snc": snc}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue