Convert most of the collection code from py.path to pathlib
This commit is contained in:
		
							parent
							
								
									4faed28261
								
							
						
					
					
						commit
						ca4effc822
					
				| 
						 | 
					@ -3,3 +3,4 @@ The following changes have been made to internal pytest types/functions:
 | 
				
			||||||
- The ``path`` property of ``_pytest.code.Code`` returns ``Path`` instead of ``py.path.local``.
 | 
					- The ``path`` property of ``_pytest.code.Code`` returns ``Path`` instead of ``py.path.local``.
 | 
				
			||||||
- The ``path`` property of ``_pytest.code.TracebackEntry`` returns ``Path`` instead of ``py.path.local``.
 | 
					- The ``path`` property of ``_pytest.code.TracebackEntry`` returns ``Path`` instead of ``py.path.local``.
 | 
				
			||||||
- The ``_pytest.code.getfslineno()`` function returns ``Path`` instead of ``py.path.local``.
 | 
					- The ``_pytest.code.getfslineno()`` function returns ``Path`` instead of ``py.path.local``.
 | 
				
			||||||
 | 
					- The ``_pytest.python.path_matches_patterns()`` function takes ``Path`` instead of ``py.path.local``.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -348,7 +348,7 @@ class PytestPluginManager(PluginManager):
 | 
				
			||||||
        self._conftestpath2mod: Dict[Path, types.ModuleType] = {}
 | 
					        self._conftestpath2mod: Dict[Path, types.ModuleType] = {}
 | 
				
			||||||
        self._confcutdir: Optional[Path] = None
 | 
					        self._confcutdir: Optional[Path] = None
 | 
				
			||||||
        self._noconftest = False
 | 
					        self._noconftest = False
 | 
				
			||||||
        self._duplicatepaths: Set[py.path.local] = set()
 | 
					        self._duplicatepaths: Set[Path] = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # plugins that were explicitly skipped with pytest.skip
 | 
					        # plugins that were explicitly skipped with pytest.skip
 | 
				
			||||||
        # list of (module name, skip reason)
 | 
					        # list of (module name, skip reason)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,7 @@ from _pytest.fixtures import FixtureManager
 | 
				
			||||||
from _pytest.outcomes import exit
 | 
					from _pytest.outcomes import exit
 | 
				
			||||||
from _pytest.pathlib import absolutepath
 | 
					from _pytest.pathlib import absolutepath
 | 
				
			||||||
from _pytest.pathlib import bestrelpath
 | 
					from _pytest.pathlib import bestrelpath
 | 
				
			||||||
 | 
					from _pytest.pathlib import fnmatch_ex
 | 
				
			||||||
from _pytest.pathlib import visit
 | 
					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
 | 
				
			||||||
| 
						 | 
					@ -353,11 +354,14 @@ def pytest_runtestloop(session: "Session") -> bool:
 | 
				
			||||||
    return True
 | 
					    return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _in_venv(path: py.path.local) -> bool:
 | 
					def _in_venv(path: Path) -> bool:
 | 
				
			||||||
    """Attempt to detect if ``path`` is the root of a Virtual Environment by
 | 
					    """Attempt to detect if ``path`` is the root of a Virtual Environment by
 | 
				
			||||||
    checking for the existence of the appropriate activate script."""
 | 
					    checking for the existence of the appropriate activate script."""
 | 
				
			||||||
    bindir = path.join("Scripts" if sys.platform.startswith("win") else "bin")
 | 
					    bindir = path.joinpath("Scripts" if sys.platform.startswith("win") else "bin")
 | 
				
			||||||
    if not bindir.isdir():
 | 
					    try:
 | 
				
			||||||
 | 
					        if not bindir.is_dir():
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					    except OSError:
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
    activates = (
 | 
					    activates = (
 | 
				
			||||||
        "activate",
 | 
					        "activate",
 | 
				
			||||||
| 
						 | 
					@ -367,33 +371,32 @@ def _in_venv(path: py.path.local) -> bool:
 | 
				
			||||||
        "Activate.bat",
 | 
					        "Activate.bat",
 | 
				
			||||||
        "Activate.ps1",
 | 
					        "Activate.ps1",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    return any([fname.basename in activates for fname in bindir.listdir()])
 | 
					    return any(fname.name in activates for fname in bindir.iterdir())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def pytest_ignore_collect(path: py.path.local, config: Config) -> Optional[bool]:
 | 
					def pytest_ignore_collect(fspath: Path, config: Config) -> Optional[bool]:
 | 
				
			||||||
    path_ = Path(path)
 | 
					    ignore_paths = config._getconftest_pathlist("collect_ignore", path=fspath.parent)
 | 
				
			||||||
    ignore_paths = config._getconftest_pathlist("collect_ignore", path=path_.parent)
 | 
					 | 
				
			||||||
    ignore_paths = ignore_paths or []
 | 
					    ignore_paths = ignore_paths or []
 | 
				
			||||||
    excludeopt = config.getoption("ignore")
 | 
					    excludeopt = config.getoption("ignore")
 | 
				
			||||||
    if excludeopt:
 | 
					    if excludeopt:
 | 
				
			||||||
        ignore_paths.extend(absolutepath(x) for x in excludeopt)
 | 
					        ignore_paths.extend(absolutepath(x) for x in excludeopt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if path_ in ignore_paths:
 | 
					    if fspath in ignore_paths:
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ignore_globs = config._getconftest_pathlist(
 | 
					    ignore_globs = config._getconftest_pathlist(
 | 
				
			||||||
        "collect_ignore_glob", path=path_.parent
 | 
					        "collect_ignore_glob", path=fspath.parent
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    ignore_globs = ignore_globs or []
 | 
					    ignore_globs = ignore_globs or []
 | 
				
			||||||
    excludeglobopt = config.getoption("ignore_glob")
 | 
					    excludeglobopt = config.getoption("ignore_glob")
 | 
				
			||||||
    if excludeglobopt:
 | 
					    if excludeglobopt:
 | 
				
			||||||
        ignore_globs.extend(absolutepath(x) for x in excludeglobopt)
 | 
					        ignore_globs.extend(absolutepath(x) for x in excludeglobopt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if any(fnmatch.fnmatch(str(path), str(glob)) for glob in ignore_globs):
 | 
					    if any(fnmatch.fnmatch(str(fspath), str(glob)) for glob in ignore_globs):
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    allow_in_venv = config.getoption("collect_in_virtualenv")
 | 
					    allow_in_venv = config.getoption("collect_in_virtualenv")
 | 
				
			||||||
    if not allow_in_venv and _in_venv(path):
 | 
					    if not allow_in_venv and _in_venv(fspath):
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
    return None
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -538,21 +541,21 @@ class Session(nodes.FSCollector):
 | 
				
			||||||
        if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config):
 | 
					        if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config):
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
        norecursepatterns = self.config.getini("norecursedirs")
 | 
					        norecursepatterns = self.config.getini("norecursedirs")
 | 
				
			||||||
        if any(path.check(fnmatch=pat) for pat in norecursepatterns):
 | 
					        if any(fnmatch_ex(pat, fspath) for pat in norecursepatterns):
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _collectfile(
 | 
					    def _collectfile(
 | 
				
			||||||
        self, path: py.path.local, handle_dupes: bool = True
 | 
					        self, fspath: Path, handle_dupes: bool = True
 | 
				
			||||||
    ) -> Sequence[nodes.Collector]:
 | 
					    ) -> Sequence[nodes.Collector]:
 | 
				
			||||||
        fspath = Path(path)
 | 
					        path = py.path.local(fspath)
 | 
				
			||||||
        assert (
 | 
					        assert (
 | 
				
			||||||
            path.isfile()
 | 
					            fspath.is_file()
 | 
				
			||||||
        ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
 | 
					        ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
 | 
				
			||||||
            path, path.isdir(), path.exists(), path.islink()
 | 
					            fspath, fspath.is_dir(), fspath.exists(), fspath.is_symlink()
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        ihook = self.gethookproxy(path)
 | 
					        ihook = self.gethookproxy(fspath)
 | 
				
			||||||
        if not self.isinitpath(path):
 | 
					        if not self.isinitpath(fspath):
 | 
				
			||||||
            if ihook.pytest_ignore_collect(
 | 
					            if ihook.pytest_ignore_collect(
 | 
				
			||||||
                fspath=fspath, path=path, config=self.config
 | 
					                fspath=fspath, path=path, config=self.config
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
| 
						 | 
					@ -562,10 +565,10 @@ class Session(nodes.FSCollector):
 | 
				
			||||||
            keepduplicates = self.config.getoption("keepduplicates")
 | 
					            keepduplicates = self.config.getoption("keepduplicates")
 | 
				
			||||||
            if not keepduplicates:
 | 
					            if not keepduplicates:
 | 
				
			||||||
                duplicate_paths = self.config.pluginmanager._duplicatepaths
 | 
					                duplicate_paths = self.config.pluginmanager._duplicatepaths
 | 
				
			||||||
                if path in duplicate_paths:
 | 
					                if fspath in duplicate_paths:
 | 
				
			||||||
                    return ()
 | 
					                    return ()
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    duplicate_paths.add(path)
 | 
					                    duplicate_paths.add(fspath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self)  # type: ignore[no-any-return]
 | 
					        return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self)  # type: ignore[no-any-return]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -652,10 +655,8 @@ class Session(nodes.FSCollector):
 | 
				
			||||||
        from _pytest.python import Package
 | 
					        from _pytest.python import Package
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Keep track of any collected nodes in here, so we don't duplicate fixtures.
 | 
					        # Keep track of any collected nodes in here, so we don't duplicate fixtures.
 | 
				
			||||||
        node_cache1: Dict[py.path.local, Sequence[nodes.Collector]] = {}
 | 
					        node_cache1: Dict[Path, Sequence[nodes.Collector]] = {}
 | 
				
			||||||
        node_cache2: Dict[
 | 
					        node_cache2: Dict[Tuple[Type[nodes.Collector], Path], nodes.Collector] = ({})
 | 
				
			||||||
            Tuple[Type[nodes.Collector], py.path.local], nodes.Collector
 | 
					 | 
				
			||||||
        ] = ({})
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Keep track of any collected collectors in matchnodes paths, so they
 | 
					        # Keep track of any collected collectors in matchnodes paths, so they
 | 
				
			||||||
        # are not collected more than once.
 | 
					        # are not collected more than once.
 | 
				
			||||||
| 
						 | 
					@ -679,31 +680,31 @@ class Session(nodes.FSCollector):
 | 
				
			||||||
                        break
 | 
					                        break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if parent.is_dir():
 | 
					                    if parent.is_dir():
 | 
				
			||||||
                        pkginit = py.path.local(parent / "__init__.py")
 | 
					                        pkginit = parent / "__init__.py"
 | 
				
			||||||
                        if pkginit.isfile() and pkginit not in node_cache1:
 | 
					                        if pkginit.is_file() and pkginit not in node_cache1:
 | 
				
			||||||
                            col = self._collectfile(pkginit, handle_dupes=False)
 | 
					                            col = self._collectfile(pkginit, handle_dupes=False)
 | 
				
			||||||
                            if col:
 | 
					                            if col:
 | 
				
			||||||
                                if isinstance(col[0], Package):
 | 
					                                if isinstance(col[0], Package):
 | 
				
			||||||
                                    pkg_roots[str(parent)] = col[0]
 | 
					                                    pkg_roots[str(parent)] = col[0]
 | 
				
			||||||
                                node_cache1[col[0].fspath] = [col[0]]
 | 
					                                node_cache1[Path(col[0].fspath)] = [col[0]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # If it's a directory argument, recurse and look for any Subpackages.
 | 
					            # If it's a directory argument, recurse and look for any Subpackages.
 | 
				
			||||||
            # Let the Package collector deal with subnodes, don't collect here.
 | 
					            # Let the Package collector deal with subnodes, don't collect here.
 | 
				
			||||||
            if argpath.is_dir():
 | 
					            if argpath.is_dir():
 | 
				
			||||||
                assert not names, "invalid arg {!r}".format((argpath, names))
 | 
					                assert not names, "invalid arg {!r}".format((argpath, names))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                seen_dirs: Set[py.path.local] = set()
 | 
					                seen_dirs: Set[Path] = set()
 | 
				
			||||||
                for direntry in visit(str(argpath), self._recurse):
 | 
					                for direntry in visit(str(argpath), self._recurse):
 | 
				
			||||||
                    if not direntry.is_file():
 | 
					                    if not direntry.is_file():
 | 
				
			||||||
                        continue
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    path = py.path.local(direntry.path)
 | 
					                    path = Path(direntry.path)
 | 
				
			||||||
                    dirpath = path.dirpath()
 | 
					                    dirpath = path.parent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if dirpath not in seen_dirs:
 | 
					                    if dirpath not in seen_dirs:
 | 
				
			||||||
                        # Collect packages first.
 | 
					                        # Collect packages first.
 | 
				
			||||||
                        seen_dirs.add(dirpath)
 | 
					                        seen_dirs.add(dirpath)
 | 
				
			||||||
                        pkginit = dirpath.join("__init__.py")
 | 
					                        pkginit = dirpath / "__init__.py"
 | 
				
			||||||
                        if pkginit.exists():
 | 
					                        if pkginit.exists():
 | 
				
			||||||
                            for x in self._collectfile(pkginit):
 | 
					                            for x in self._collectfile(pkginit):
 | 
				
			||||||
                                yield x
 | 
					                                yield x
 | 
				
			||||||
| 
						 | 
					@ -714,23 +715,22 @@ class Session(nodes.FSCollector):
 | 
				
			||||||
                        continue
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    for x in self._collectfile(path):
 | 
					                    for x in self._collectfile(path):
 | 
				
			||||||
                        key = (type(x), x.fspath)
 | 
					                        key2 = (type(x), Path(x.fspath))
 | 
				
			||||||
                        if key in node_cache2:
 | 
					                        if key2 in node_cache2:
 | 
				
			||||||
                            yield node_cache2[key]
 | 
					                            yield node_cache2[key2]
 | 
				
			||||||
                        else:
 | 
					                        else:
 | 
				
			||||||
                            node_cache2[key] = x
 | 
					                            node_cache2[key2] = x
 | 
				
			||||||
                            yield x
 | 
					                            yield x
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                assert argpath.is_file()
 | 
					                assert argpath.is_file()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                argpath_ = py.path.local(argpath)
 | 
					                if argpath in node_cache1:
 | 
				
			||||||
                if argpath_ in node_cache1:
 | 
					                    col = node_cache1[argpath]
 | 
				
			||||||
                    col = node_cache1[argpath_]
 | 
					 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    collect_root = pkg_roots.get(argpath_.dirname, self)
 | 
					                    collect_root = pkg_roots.get(str(argpath.parent), self)
 | 
				
			||||||
                    col = collect_root._collectfile(argpath_, handle_dupes=False)
 | 
					                    col = collect_root._collectfile(argpath, handle_dupes=False)
 | 
				
			||||||
                    if col:
 | 
					                    if col:
 | 
				
			||||||
                        node_cache1[argpath_] = col
 | 
					                        node_cache1[argpath] = col
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                matching = []
 | 
					                matching = []
 | 
				
			||||||
                work: List[
 | 
					                work: List[
 | 
				
			||||||
| 
						 | 
					@ -846,7 +846,7 @@ def resolve_collection_argument(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    This function ensures the path exists, and returns a tuple:
 | 
					    This function ensures the path exists, and returns a tuple:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (py.path.path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"])
 | 
					        (Path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    When as_pypath is True, expects that the command-line argument actually contains
 | 
					    When as_pypath is True, expects that the command-line argument actually contains
 | 
				
			||||||
    module paths instead of file-system paths:
 | 
					    module paths instead of file-system paths:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,6 +66,8 @@ from _pytest.mark.structures import MarkDecorator
 | 
				
			||||||
from _pytest.mark.structures import normalize_mark_list
 | 
					from _pytest.mark.structures import normalize_mark_list
 | 
				
			||||||
from _pytest.outcomes import fail
 | 
					from _pytest.outcomes import fail
 | 
				
			||||||
from _pytest.outcomes import skip
 | 
					from _pytest.outcomes import skip
 | 
				
			||||||
 | 
					from _pytest.pathlib import bestrelpath
 | 
				
			||||||
 | 
					from _pytest.pathlib import fnmatch_ex
 | 
				
			||||||
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
 | 
				
			||||||
| 
						 | 
					@ -190,11 +192,10 @@ def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]:
 | 
				
			||||||
def pytest_collect_file(
 | 
					def pytest_collect_file(
 | 
				
			||||||
    fspath: Path, path: py.path.local, parent: nodes.Collector
 | 
					    fspath: Path, path: py.path.local, parent: nodes.Collector
 | 
				
			||||||
) -> Optional["Module"]:
 | 
					) -> Optional["Module"]:
 | 
				
			||||||
    ext = path.ext
 | 
					    if fspath.suffix == ".py":
 | 
				
			||||||
    if ext == ".py":
 | 
					 | 
				
			||||||
        if not parent.session.isinitpath(fspath):
 | 
					        if not parent.session.isinitpath(fspath):
 | 
				
			||||||
            if not path_matches_patterns(
 | 
					            if not path_matches_patterns(
 | 
				
			||||||
                path, parent.config.getini("python_files") + ["__init__.py"]
 | 
					                fspath, parent.config.getini("python_files") + ["__init__.py"]
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                return None
 | 
					                return None
 | 
				
			||||||
        ihook = parent.session.gethookproxy(fspath)
 | 
					        ihook = parent.session.gethookproxy(fspath)
 | 
				
			||||||
| 
						 | 
					@ -205,13 +206,13 @@ def pytest_collect_file(
 | 
				
			||||||
    return None
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def path_matches_patterns(path: py.path.local, patterns: Iterable[str]) -> bool:
 | 
					def path_matches_patterns(path: Path, patterns: Iterable[str]) -> bool:
 | 
				
			||||||
    """Return whether path matches any of the patterns in the list of globs given."""
 | 
					    """Return whether path matches any of the patterns in the list of globs given."""
 | 
				
			||||||
    return any(path.fnmatch(pattern) for pattern in patterns)
 | 
					    return any(fnmatch_ex(pattern, path) for pattern in patterns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def pytest_pycollect_makemodule(path: py.path.local, parent) -> "Module":
 | 
					def pytest_pycollect_makemodule(fspath: Path, path: py.path.local, parent) -> "Module":
 | 
				
			||||||
    if path.basename == "__init__.py":
 | 
					    if fspath.name == "__init__.py":
 | 
				
			||||||
        pkg: Package = Package.from_parent(parent, fspath=path)
 | 
					        pkg: Package = Package.from_parent(parent, fspath=path)
 | 
				
			||||||
        return pkg
 | 
					        return pkg
 | 
				
			||||||
    mod: Module = Module.from_parent(parent, fspath=path)
 | 
					    mod: Module = Module.from_parent(parent, fspath=path)
 | 
				
			||||||
| 
						 | 
					@ -677,21 +678,21 @@ class Package(Module):
 | 
				
			||||||
        if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config):
 | 
					        if ihook.pytest_ignore_collect(fspath=fspath, path=path, config=self.config):
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
        norecursepatterns = self.config.getini("norecursedirs")
 | 
					        norecursepatterns = self.config.getini("norecursedirs")
 | 
				
			||||||
        if any(path.check(fnmatch=pat) for pat in norecursepatterns):
 | 
					        if any(fnmatch_ex(pat, fspath) for pat in norecursepatterns):
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _collectfile(
 | 
					    def _collectfile(
 | 
				
			||||||
        self, path: py.path.local, handle_dupes: bool = True
 | 
					        self, fspath: Path, handle_dupes: bool = True
 | 
				
			||||||
    ) -> Sequence[nodes.Collector]:
 | 
					    ) -> Sequence[nodes.Collector]:
 | 
				
			||||||
        fspath = Path(path)
 | 
					        path = py.path.local(fspath)
 | 
				
			||||||
        assert (
 | 
					        assert (
 | 
				
			||||||
            path.isfile()
 | 
					            fspath.is_file()
 | 
				
			||||||
        ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
 | 
					        ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format(
 | 
				
			||||||
            path, path.isdir(), path.exists(), path.islink()
 | 
					            path, fspath.is_dir(), fspath.exists(), fspath.is_symlink()
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        ihook = self.session.gethookproxy(path)
 | 
					        ihook = self.session.gethookproxy(fspath)
 | 
				
			||||||
        if not self.session.isinitpath(path):
 | 
					        if not self.session.isinitpath(fspath):
 | 
				
			||||||
            if ihook.pytest_ignore_collect(
 | 
					            if ihook.pytest_ignore_collect(
 | 
				
			||||||
                fspath=fspath, path=path, config=self.config
 | 
					                fspath=fspath, path=path, config=self.config
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
| 
						 | 
					@ -701,32 +702,32 @@ class Package(Module):
 | 
				
			||||||
            keepduplicates = self.config.getoption("keepduplicates")
 | 
					            keepduplicates = self.config.getoption("keepduplicates")
 | 
				
			||||||
            if not keepduplicates:
 | 
					            if not keepduplicates:
 | 
				
			||||||
                duplicate_paths = self.config.pluginmanager._duplicatepaths
 | 
					                duplicate_paths = self.config.pluginmanager._duplicatepaths
 | 
				
			||||||
                if path in duplicate_paths:
 | 
					                if fspath in duplicate_paths:
 | 
				
			||||||
                    return ()
 | 
					                    return ()
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    duplicate_paths.add(path)
 | 
					                    duplicate_paths.add(fspath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self)  # type: ignore[no-any-return]
 | 
					        return ihook.pytest_collect_file(fspath=fspath, path=path, parent=self)  # type: ignore[no-any-return]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
 | 
					    def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
 | 
				
			||||||
        this_path = self.fspath.dirpath()
 | 
					        this_path = Path(self.fspath).parent
 | 
				
			||||||
        init_module = this_path.join("__init__.py")
 | 
					        init_module = this_path / "__init__.py"
 | 
				
			||||||
        if init_module.check(file=1) and path_matches_patterns(
 | 
					        if init_module.is_file() and path_matches_patterns(
 | 
				
			||||||
            init_module, self.config.getini("python_files")
 | 
					            init_module, self.config.getini("python_files")
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            yield Module.from_parent(self, fspath=init_module)
 | 
					            yield Module.from_parent(self, fspath=py.path.local(init_module))
 | 
				
			||||||
        pkg_prefixes: Set[py.path.local] = set()
 | 
					        pkg_prefixes: Set[Path] = set()
 | 
				
			||||||
        for direntry in visit(str(this_path), recurse=self._recurse):
 | 
					        for direntry in visit(str(this_path), recurse=self._recurse):
 | 
				
			||||||
            path = py.path.local(direntry.path)
 | 
					            path = Path(direntry.path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # 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.
 | 
				
			||||||
            if direntry.is_file():
 | 
					            if direntry.is_file():
 | 
				
			||||||
                if direntry.name == "__init__.py" and path.dirpath() == this_path:
 | 
					                if direntry.name == "__init__.py" and path.parent == this_path:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            parts_ = parts(direntry.path)
 | 
					            parts_ = parts(direntry.path)
 | 
				
			||||||
            if any(
 | 
					            if any(
 | 
				
			||||||
                str(pkg_prefix) in parts_ and pkg_prefix.join("__init__.py") != path
 | 
					                str(pkg_prefix) in parts_ and pkg_prefix / "__init__.py" != path
 | 
				
			||||||
                for pkg_prefix in pkg_prefixes
 | 
					                for pkg_prefix in pkg_prefixes
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
| 
						 | 
					@ -736,7 +737,7 @@ class Package(Module):
 | 
				
			||||||
            elif not direntry.is_dir():
 | 
					            elif not direntry.is_dir():
 | 
				
			||||||
                # Broken symlink or invalid/missing file.
 | 
					                # Broken symlink or invalid/missing file.
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            elif path.join("__init__.py").check(file=1):
 | 
					            elif path.joinpath("__init__.py").is_file():
 | 
				
			||||||
                pkg_prefixes.add(path)
 | 
					                pkg_prefixes.add(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1416,13 +1417,13 @@ def _show_fixtures_per_test(config: Config, session: Session) -> None:
 | 
				
			||||||
    import _pytest.config
 | 
					    import _pytest.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    session.perform_collect()
 | 
					    session.perform_collect()
 | 
				
			||||||
    curdir = py.path.local()
 | 
					    curdir = Path.cwd()
 | 
				
			||||||
    tw = _pytest.config.create_terminal_writer(config)
 | 
					    tw = _pytest.config.create_terminal_writer(config)
 | 
				
			||||||
    verbose = config.getvalue("verbose")
 | 
					    verbose = config.getvalue("verbose")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_best_relpath(func):
 | 
					    def get_best_relpath(func) -> str:
 | 
				
			||||||
        loc = getlocation(func, str(curdir))
 | 
					        loc = getlocation(func, str(curdir))
 | 
				
			||||||
        return curdir.bestrelpath(py.path.local(loc))
 | 
					        return bestrelpath(curdir, Path(loc))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None:
 | 
					    def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None:
 | 
				
			||||||
        argname = fixture_def.argname
 | 
					        argname = fixture_def.argname
 | 
				
			||||||
| 
						 | 
					@ -1472,7 +1473,7 @@ def _showfixtures_main(config: Config, session: Session) -> None:
 | 
				
			||||||
    import _pytest.config
 | 
					    import _pytest.config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    session.perform_collect()
 | 
					    session.perform_collect()
 | 
				
			||||||
    curdir = py.path.local()
 | 
					    curdir = Path.cwd()
 | 
				
			||||||
    tw = _pytest.config.create_terminal_writer(config)
 | 
					    tw = _pytest.config.create_terminal_writer(config)
 | 
				
			||||||
    verbose = config.getvalue("verbose")
 | 
					    verbose = config.getvalue("verbose")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1494,7 +1495,7 @@ def _showfixtures_main(config: Config, session: Session) -> None:
 | 
				
			||||||
                (
 | 
					                (
 | 
				
			||||||
                    len(fixturedef.baseid),
 | 
					                    len(fixturedef.baseid),
 | 
				
			||||||
                    fixturedef.func.__module__,
 | 
					                    fixturedef.func.__module__,
 | 
				
			||||||
                    curdir.bestrelpath(py.path.local(loc)),
 | 
					                    bestrelpath(curdir, Path(loc)),
 | 
				
			||||||
                    fixturedef.argname,
 | 
					                    fixturedef.argname,
 | 
				
			||||||
                    fixturedef,
 | 
					                    fixturedef,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,12 +212,12 @@ class TestCollectFS:
 | 
				
			||||||
        bindir = "Scripts" if sys.platform.startswith("win") else "bin"
 | 
					        bindir = "Scripts" if sys.platform.startswith("win") else "bin"
 | 
				
			||||||
        # no bin/activate, not a virtualenv
 | 
					        # no bin/activate, not a virtualenv
 | 
				
			||||||
        base_path = pytester.mkdir("venv")
 | 
					        base_path = pytester.mkdir("venv")
 | 
				
			||||||
        assert _in_venv(py.path.local(base_path)) is False
 | 
					        assert _in_venv(base_path) is False
 | 
				
			||||||
        # with bin/activate, totally a virtualenv
 | 
					        # with bin/activate, totally a virtualenv
 | 
				
			||||||
        bin_path = base_path.joinpath(bindir)
 | 
					        bin_path = base_path.joinpath(bindir)
 | 
				
			||||||
        bin_path.mkdir()
 | 
					        bin_path.mkdir()
 | 
				
			||||||
        bin_path.joinpath(fname).touch()
 | 
					        bin_path.joinpath(fname).touch()
 | 
				
			||||||
        assert _in_venv(py.path.local(base_path)) is True
 | 
					        assert _in_venv(base_path) is True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_custom_norecursedirs(self, pytester: Pytester) -> None:
 | 
					    def test_custom_norecursedirs(self, pytester: Pytester) -> None:
 | 
				
			||||||
        pytester.makeini(
 | 
					        pytester.makeini(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue