Example #1
0
def test_visit_ignores_errors(tmp_path: Path) -> None:
    symlink_or_skip("recursive", tmp_path / "recursive")
    tmp_path.joinpath("foo").write_bytes(b"")
    tmp_path.joinpath("bar").write_bytes(b"")

    assert [
        entry.name
        for entry in visit(str(tmp_path), recurse=lambda entry: False)
    ] == ["bar", "foo"]
Example #2
0
def test_visit_ignores_errors(tmpdir) -> None:
    symlink_or_skip("recursive", tmpdir.join("recursive"))
    tmpdir.join("foo").write_binary(b"")
    tmpdir.join("bar").write_binary(b"")

    assert [
        entry.name for entry in visit(tmpdir, recurse=lambda entry: False)
    ] == [
        "bar",
        "foo",
    ]
Example #3
0
    def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:
        from _pytest.python import Package

        # Keep track of any collected nodes in here, so we don't duplicate fixtures.
        node_cache1: Dict[py.path.local, Sequence[nodes.Collector]] = {}
        node_cache2: Dict[
            Tuple[Type[nodes.Collector], py.path.local], nodes.Collector
        ] = ({})

        # Keep track of any collected collectors in matchnodes paths, so they
        # are not collected more than once.
        matchnodes_cache: Dict[Tuple[Type[nodes.Collector], str], CollectReport] = ({})

        # Dirnames of pkgs with dunder-init files.
        pkg_roots: Dict[str, Package] = {}

        for argpath, names in self._initial_parts:
            self.trace("processing argument", (argpath, names))
            self.trace.root.indent += 1

            # Start with a Session root, and delve to argpath item (dir or file)
            # and stack all Packages found on the way.
            # No point in finding packages when collecting doctests.
            if not self.config.getoption("doctestmodules", False):
                pm = self.config.pluginmanager
                confcutdir = pm._confcutdir
                for parent in (argpath, *argpath.parents):
                    if confcutdir and parent in confcutdir.parents:
                        break

                    if parent.is_dir():
                        pkginit = py.path.local(parent / "__init__.py")
                        if pkginit.isfile() and pkginit not in node_cache1:
                            col = self._collectfile(pkginit, handle_dupes=False)
                            if col:
                                if isinstance(col[0], Package):
                                    pkg_roots[str(parent)] = col[0]
                                node_cache1[col[0].fspath] = [col[0]]

            # If it's a directory argument, recurse and look for any Subpackages.
            # Let the Package collector deal with subnodes, don't collect here.
            if argpath.is_dir():
                assert not names, "invalid arg {!r}".format((argpath, names))

                seen_dirs: Set[py.path.local] = set()
                for direntry in visit(str(argpath), self._recurse):
                    if not direntry.is_file():
                        continue

                    path = py.path.local(direntry.path)
                    dirpath = path.dirpath()

                    if dirpath not in seen_dirs:
                        # Collect packages first.
                        seen_dirs.add(dirpath)
                        pkginit = dirpath.join("__init__.py")
                        if pkginit.exists():
                            for x in self._collectfile(pkginit):
                                yield x
                                if isinstance(x, Package):
                                    pkg_roots[str(dirpath)] = x
                    if str(dirpath) in pkg_roots:
                        # Do not collect packages here.
                        continue

                    for x in self._collectfile(path):
                        key = (type(x), x.fspath)
                        if key in node_cache2:
                            yield node_cache2[key]
                        else:
                            node_cache2[key] = x
                            yield x
            else:
                assert argpath.is_file()

                argpath_ = py.path.local(argpath)
                if argpath_ in node_cache1:
                    col = node_cache1[argpath_]
                else:
                    collect_root = pkg_roots.get(argpath_.dirname, self)
                    col = collect_root._collectfile(argpath_, handle_dupes=False)
                    if col:
                        node_cache1[argpath_] = col

                matching = []
                work: List[
                    Tuple[Sequence[Union[nodes.Item, nodes.Collector]], Sequence[str]]
                ] = [(col, names)]
                while work:
                    self.trace("matchnodes", col, names)
                    self.trace.root.indent += 1

                    matchnodes, matchnames = work.pop()
                    for node in matchnodes:
                        if not matchnames:
                            matching.append(node)
                            continue
                        if not isinstance(node, nodes.Collector):
                            continue
                        key = (type(node), node.nodeid)
                        if key in matchnodes_cache:
                            rep = matchnodes_cache[key]
                        else:
                            rep = collect_one_node(node)
                            matchnodes_cache[key] = rep
                        if rep.passed:
                            submatchnodes = []
                            for r in rep.result:
                                # TODO: Remove parametrized workaround once collection structure contains
                                # parametrization.
                                if (
                                    r.name == matchnames[0]
                                    or r.name.split("[")[0] == matchnames[0]
                                ):
                                    submatchnodes.append(r)
                            if submatchnodes:
                                work.append((submatchnodes, matchnames[1:]))
                            # XXX Accept IDs that don't have "()" for class instances.
                            elif len(rep.result) == 1 and rep.result[0].name == "()":
                                work.append((rep.result, matchnames))
                        else:
                            # Report collection failures here to avoid failing to run some test
                            # specified in the command line because the module could not be
                            # imported (#134).
                            node.ihook.pytest_collectreport(report=rep)

                    self.trace("matchnodes finished -> ", len(matching), "nodes")
                    self.trace.root.indent -= 1

                if not matching:
                    report_arg = "::".join((str(argpath), *names))
                    self._notfound.append((report_arg, col))
                    continue

                # If __init__.py was the only file requested, then the matched
                # node will be the corresponding Package (by default), and the
                # first yielded item will be the __init__ Module itself, so
                # just use that. If this special case isn't taken, then all the
                # files in the package will be yielded.
                if argpath.name == "__init__.py" and isinstance(matching[0], Package):
                    try:
                        yield next(iter(matching[0].collect()))
                    except StopIteration:
                        # The package collects nothing with only an __init__.py
                        # file in it, which gets ignored by the default
                        # "python_files" option.
                        pass
                    continue

                yield from matching

            self.trace.root.indent -= 1
Example #4
0
    def _collect(
        self, argpath: py.path.local, names: List[str]
    ) -> Iterator[Union[nodes.Item, nodes.Collector]]:
        from _pytest.python import Package

        # Start with a Session root, and delve to argpath item (dir or file)
        # and stack all Packages found on the way.
        # No point in finding packages when collecting doctests.
        if not self.config.getoption("doctestmodules", False):
            pm = self.config.pluginmanager
            for parent in reversed(argpath.parts()):
                if pm._confcutdir and pm._confcutdir.relto(parent):
                    break

                if parent.isdir():
                    pkginit = parent.join("__init__.py")
                    if pkginit.isfile():
                        if pkginit not in self._collection_node_cache1:
                            col = self._collectfile(pkginit, handle_dupes=False)
                            if col:
                                if isinstance(col[0], Package):
                                    self._collection_pkg_roots[str(parent)] = col[0]
                                # Always store a list in the cache, matchnodes expects it.
                                self._collection_node_cache1[col[0].fspath] = [col[0]]

        # If it's a directory argument, recurse and look for any Subpackages.
        # Let the Package collector deal with subnodes, don't collect here.
        if argpath.check(dir=1):
            assert not names, "invalid arg {!r}".format((argpath, names))

            seen_dirs = set()  # type: Set[py.path.local]
            for direntry in visit(str(argpath), self._recurse):
                if not direntry.is_file():
                    continue

                path = py.path.local(direntry.path)
                dirpath = path.dirpath()

                if dirpath not in seen_dirs:
                    # Collect packages first.
                    seen_dirs.add(dirpath)
                    pkginit = dirpath.join("__init__.py")
                    if pkginit.exists():
                        for x in self._collectfile(pkginit):
                            yield x
                            if isinstance(x, Package):
                                self._collection_pkg_roots[str(dirpath)] = x
                if str(dirpath) in self._collection_pkg_roots:
                    # Do not collect packages here.
                    continue

                for x in self._collectfile(path):
                    key = (type(x), x.fspath)
                    if key in self._collection_node_cache2:
                        yield self._collection_node_cache2[key]
                    else:
                        self._collection_node_cache2[key] = x
                        yield x
        else:
            assert argpath.check(file=1)

            if argpath in self._collection_node_cache1:
                col = self._collection_node_cache1[argpath]
            else:
                collect_root = self._collection_pkg_roots.get(argpath.dirname, self)
                col = collect_root._collectfile(argpath, handle_dupes=False)
                if col:
                    self._collection_node_cache1[argpath] = col
            m = self.matchnodes(col, names)
            # If __init__.py was the only file requested, then the matched node will be
            # the corresponding Package, and the first yielded item will be the __init__
            # Module itself, so just use that. If this special case isn't taken, then all
            # the files in the package will be yielded.
            if argpath.basename == "__init__.py":
                assert isinstance(m[0], nodes.Collector)
                try:
                    yield next(iter(m[0].collect()))
                except StopIteration:
                    # The package collects nothing with only an __init__.py
                    # file in it, which gets ignored by the default
                    # "python_files" option.
                    pass
                return
            yield from m