Example #1
0
    def test_renamed_dir_creates_mismatch(self, tmp_path: Path,
                                          monkeypatch: MonkeyPatch) -> None:
        tmp_path.joinpath("a").mkdir()
        p = tmp_path.joinpath("a", "test_x123.py")
        p.touch()
        import_path(p)
        tmp_path.joinpath("a").rename(tmp_path.joinpath("b"))
        with pytest.raises(ImportPathMismatchError):
            import_path(tmp_path.joinpath("b", "test_x123.py"))

        # Errors can be ignored.
        monkeypatch.setenv("PY_IGNORE_IMPORTMISMATCH", "1")
        import_path(tmp_path.joinpath("b", "test_x123.py"))

        # PY_IGNORE_IMPORTMISMATCH=0 does not ignore error.
        monkeypatch.setenv("PY_IGNORE_IMPORTMISMATCH", "0")
        with pytest.raises(ImportPathMismatchError):
            import_path(tmp_path.joinpath("b", "test_x123.py"))
Example #2
0
    def test_importmode_importlib_with_dataclass(self, tmp_path: Path) -> None:
        """Ensure that importlib mode works with a module containing dataclasses (#7856)."""
        fn = tmp_path.joinpath("_src/tests/test_dataclass.py")
        fn.parent.mkdir(parents=True)
        fn.write_text(
            dedent("""
                from dataclasses import dataclass

                @dataclass
                class Data:
                    value: str
                """))

        module = import_path(fn, mode="importlib", root=tmp_path)
        Data: Any = getattr(module, "Data")
        data = Data(value="foo")
        assert data.value == "foo"
        assert data.__module__ == "_src.tests.test_dataclass"
Example #3
0
def test_samefile_false_negatives(tmp_path: Path,
                                  monkeypatch: MonkeyPatch) -> None:
    """
    import_file() should not raise ImportPathMismatchError if the paths are exactly
    equal on Windows. It seems directories mounted as UNC paths make os.path.samefile
    return False, even when they are clearly equal.
    """
    module_path = tmp_path.joinpath("my_module.py")
    module_path.write_text("def foo(): return 42")
    monkeypatch.syspath_prepend(tmp_path)

    with monkeypatch.context() as mp:
        # Forcibly make os.path.samefile() return False here to ensure we are comparing
        # the paths too. Using a context to narrow the patch as much as possible given
        # this is an important system function.
        mp.setattr(os.path, "samefile", lambda x, y: False)
        module = import_path(module_path)
    assert getattr(module, "foo")() == 42
Example #4
0
    def test_importmode_importlib_with_pickle(self, tmp_path: Path) -> None:
        """Ensure that importlib mode works with pickle (#7859)."""
        fn = tmp_path.joinpath("_src/tests/test_pickle.py")
        fn.parent.mkdir(parents=True)
        fn.write_text(
            dedent("""
                import pickle

                def _action():
                    return 42

                def round_trip():
                    s = pickle.dumps(_action)
                    return pickle.loads(s)
                """))

        module = import_path(fn, mode="importlib", root=tmp_path)
        round_trip = getattr(module, "round_trip")
        action = round_trip()
        assert action() == 42
Example #5
0
    def _importconftest(
        self, conftestpath: py.path.local, importmode: Union[str, ImportMode],
    ) -> types.ModuleType:
        # Use a resolved Path object as key to avoid loading the same conftest
        # twice with build systems that create build directories containing
        # symlinks to actual files.
        # Using Path().resolve() is better than py.path.realpath because
        # it resolves to the correct path/drive in case-insensitive file systems (#5792)
        key = Path(str(conftestpath)).resolve()

        with contextlib.suppress(KeyError):
            return self._conftestpath2mod[key]

        pkgpath = conftestpath.pypkgpath()
        if pkgpath is None:
            _ensure_removed_sysmodule(conftestpath.purebasename)

        try:
            mod = import_path(conftestpath, mode=importmode)
        except Exception as e:
            assert e.__traceback__ is not None
            exc_info = (type(e), e, e.__traceback__)
            raise ConftestImportFailure(conftestpath, exc_info) from e

        self._check_non_top_pytest_plugins(mod, conftestpath)

        self._conftest_plugins.add(mod)
        self._conftestpath2mod[key] = mod
        dirpath = conftestpath.dirpath()
        if dirpath in self._dirpath2confmods:
            for path, mods in self._dirpath2confmods.items():
                if path and path.relto(dirpath) or path == dirpath:
                    assert mod not in mods
                    mods.append(mod)
        self.trace("loading conftestmodule {!r}".format(mod))
        self.consider_conftest(mod)
        return mod
Example #6
0
 def test_importmode_importlib(self, simple_module: Path) -> None:
     """`importlib` mode does not change sys.path."""
     module = import_path(simple_module, mode="importlib")
     assert module.foo(2) == 42  # type: ignore[attr-defined]
     assert str(simple_module.parent) not in sys.path
Example #7
0
 def test_d(self, path1: Path) -> None:
     otherdir = path1 / "otherdir"
     mod = import_path(otherdir / "d.py")
     assert mod.value2 == "got it"  # type: ignore[attr-defined]
Example #8
0
 def test_a(self, path1: Path) -> None:
     otherdir = path1 / "otherdir"
     mod = import_path(otherdir / "a.py")
     assert mod.result == "got it"  # type: ignore[attr-defined]
     assert mod.__name__ == "otherdir.a"
Example #9
0
 def test_b(self, path1):
     otherdir = path1.join("otherdir")
     mod = import_path(otherdir.join("b.py"))
     assert mod.stuff == "got it"  # type: ignore[attr-defined]
     assert mod.__name__ == "otherdir.b"
Example #10
0
 def test_a(self, path1):
     otherdir = path1.join("otherdir")
     mod = import_path(otherdir.join("a.py"))
     assert mod.result == "got it"  # type: ignore[attr-defined]
     assert mod.__name__ == "otherdir.a"
Example #11
0
 def test_messy_name(self, tmpdir):
     # http://bitbucket.org/hpk42/py-trunk/issue/129
     path = tmpdir.ensure("foo__init__.py")
     module = import_path(path)
     assert module.__name__ == "foo__init__"
Example #12
0
 def test_smoke_test(self, path1):
     obj = import_path(path1.join("execfile.py"))
     assert obj.x == 42  # type: ignore[attr-defined]
     assert obj.__name__ == "execfile"
Example #13
0
        def collect(self):
            # When running directly from pytest we need to make sure that we
            # don't accidentally import setup.py!
            if PYTEST_GE_6_3:
                fspath = self.path
                filepath = self.path.name
            else:
                fspath = self.fspath
                filepath = self.fspath.basename

            if filepath == "setup.py":
                return
            elif filepath == "conftest.py":
                if PYTEST_GE_7_0:
                    module = self.config.pluginmanager._importconftest(
                        self.path,
                        self.config.getoption("importmode"),
                        rootpath=self.config.rootpath)
                elif PYTEST_GE_6_3:
                    module = self.config.pluginmanager._importconftest(
                        self.path, self.config.getoption("importmode"))
                elif PYTEST_GT_5:
                    module = self.config.pluginmanager._importconftest(
                        self.fspath, self.config.getoption("importmode"))
                else:
                    module = self.config.pluginmanager._importconftest(
                        self.fspath)
            else:
                try:
                    if PYTEST_GT_5:
                        from _pytest.pathlib import import_path

                    if PYTEST_GE_6_3:
                        module = import_path(fspath, root=self.config.rootpath)
                    elif PYTEST_GT_5:
                        module = import_path(fspath)
                    else:
                        module = fspath.pyimport()
                except ImportError:
                    if self.config.getvalue("doctest_ignore_import_errors"):
                        pytest.skip("unable to import module %r" % fspath)
                    else:
                        raise

            options = get_optionflags(self) | FIX

            # uses internal doctest module parsing mechanism
            finder = DocTestFinderPlus()
            runner = doctest.DebugRunner(verbose=False,
                                         optionflags=options,
                                         checker=OutputChecker())

            for test in finder.find(module):
                if test.examples:  # skip empty doctests
                    ignore_warnings_context_needed = False
                    show_warnings_context_needed = False

                    for example in test.examples:
                        if (config.getoption('remote_data', 'none') != 'any'
                                and example.options.get(REMOTE_DATA)):
                            example.options[doctest.SKIP] = True

                        # If warnings are to be ignored we need to catch them by
                        # wrapping the source in a context manager.
                        elif example.options.get(IGNORE_WARNINGS, False):
                            example.source = (
                                "with _doctestplus_ignore_all_warnings():\n" +
                                indent(example.source, '    '))
                            ignore_warnings_context_needed = True

                        # Same for SHOW_WARNINGS
                        elif example.options.get(SHOW_WARNINGS, False):
                            example.source = (
                                "with _doctestplus_show_all_warnings():\n" +
                                indent(example.source, '    '))
                            show_warnings_context_needed = True

                    # We insert the definition of the context manager to ignore
                    # warnings at the start of the file if needed.
                    if ignore_warnings_context_needed:
                        test.examples.insert(
                            0,
                            doctest.Example(source=IGNORE_WARNINGS_CONTEXT,
                                            want=''))

                    if show_warnings_context_needed:
                        test.examples.insert(
                            0,
                            doctest.Example(source=SHOW_WARNINGS_CONTEXT,
                                            want=''))

                    try:
                        yield doctest_plugin.DoctestItem.from_parent(
                            self, name=test.name, runner=runner, dtest=test)
                    except AttributeError:
                        # pytest < 5.4
                        yield doctest_plugin.DoctestItem(
                            test.name, self, runner, test)
Example #14
0
 def test_import_path_missing_file(self, path1: Path) -> None:
     with pytest.raises(ImportPathMismatchError):
         import_path(path1 / "sampledir", root=path1)
Example #15
0
    def collect(self) -> Iterable[IPDoctestItem]:
        import doctest
        from .ipdoctest import DocTestFinder, IPDocTestParser

        class MockAwareDocTestFinder(DocTestFinder):
            """A hackish ipdoctest finder that overrides stdlib internals to fix a stdlib bug.

            https://github.com/pytest-dev/pytest/issues/3456
            https://bugs.python.org/issue25532
            """
            def _find_lineno(self, obj, source_lines):
                """Doctest code does not take into account `@property`, this
                is a hackish way to fix it. https://bugs.python.org/issue17446

                Wrapped Doctests will need to be unwrapped so the correct
                line number is returned. This will be reported upstream. #8796
                """
                if isinstance(obj, property):
                    obj = getattr(obj, "fget", obj)

                if hasattr(obj, "__wrapped__"):
                    # Get the main obj in case of it being wrapped
                    obj = inspect.unwrap(obj)

                # Type ignored because this is a private function.
                return super()._find_lineno(  # type:ignore[misc]
                    obj,
                    source_lines,
                )

            def _find(self, tests, obj, name, module, source_lines, globs,
                      seen) -> None:
                if _is_mocked(obj):
                    return
                with _patch_unwrap_mock_aware():

                    # Type ignored because this is a private function.
                    super()._find(  # type:ignore[misc]
                        tests, obj, name, module, source_lines, globs, seen)

        if self.path.name == "conftest.py":
            if int(pytest.__version__.split(".")[0]) < 7:
                module = self.config.pluginmanager._importconftest(
                    self.path,
                    self.config.getoption("importmode"),
                )
            else:
                module = self.config.pluginmanager._importconftest(
                    self.path,
                    self.config.getoption("importmode"),
                    rootpath=self.config.rootpath,
                )
        else:
            try:
                module = import_path(self.path, root=self.config.rootpath)
            except ImportError:
                if self.config.getvalue("ipdoctest_ignore_import_errors"):
                    pytest.skip("unable to import module %r" % self.path)
                else:
                    raise
        # Uses internal doctest module parsing mechanism.
        finder = MockAwareDocTestFinder(parser=IPDocTestParser())
        optionflags = get_optionflags(self)
        runner = _get_runner(
            verbose=False,
            optionflags=optionflags,
            checker=_get_checker(),
            continue_on_failure=_get_continue_on_failure(self.config),
        )

        for test in finder.find(module, module.__name__):
            if test.examples:  # skip empty ipdoctests
                yield IPDoctestItem.from_parent(self,
                                                name=test.name,
                                                runner=runner,
                                                dtest=test)
Example #16
0
 def test_smoke_test(self, path1: Path) -> None:
     obj = import_path(path1 / "execfile.py")
     assert obj.x == 42  # type: ignore[attr-defined]
     assert obj.__name__ == "execfile"
Example #17
0
 def test_messy_name(self, tmp_path: Path) -> None:
     # http://bitbucket.org/hpk42/py-trunk/issue/129
     path = tmp_path / "foo__init__.py"
     path.touch()
     module = import_path(path)
     assert module.__name__ == "foo__init__"
Example #18
0
 def test_d(self, path1):
     otherdir = path1.join("otherdir")
     mod = import_path(otherdir.join("d.py"))
     assert mod.value2 == "got it"  # type: ignore[attr-defined]
Example #19
0
 def test_b(self, path1: Path) -> None:
     otherdir = path1 / "otherdir"
     mod = import_path(otherdir / "b.py")
     assert mod.stuff == "got it"  # type: ignore[attr-defined]
     assert mod.__name__ == "otherdir.b"
Example #20
0
 def test_invalid_path(self, tmpdir):
     with pytest.raises(ImportError):
         import_path(tmpdir.join("invalid.py"))
Example #21
0
 def test_invalid_path(self, tmp_path: Path) -> None:
     with pytest.raises(ImportError):
         import_path(tmp_path / "invalid.py")
Example #22
0
 def test_importmode_importlib(self, simple_module):
     """importlib mode does not change sys.path"""
     module = import_path(simple_module, mode="importlib")
     assert module.foo(2) == 42  # type: ignore[attr-defined]
     assert simple_module.dirname not in sys.path
Example #23
0
 def test_importmode_twice_is_different_module(self,
                                               simple_module: Path) -> None:
     """`importlib` mode always returns a new module."""
     module1 = import_path(simple_module, mode="importlib")
     module2 = import_path(simple_module, mode="importlib")
     assert module1 is not module2
Example #24
0
 def test_importmode_twice_is_different_module(self, simple_module):
     """importlib mode always returns a new module"""
     module1 = import_path(simple_module, mode="importlib")
     module2 = import_path(simple_module, mode="importlib")
     assert module1 is not module2
Example #25
0
    def collect(self) -> Iterable[DoctestItem]:
        import doctest

        class MockAwareDocTestFinder(doctest.DocTestFinder):
            """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug.

            https://github.com/pytest-dev/pytest/issues/3456
            https://bugs.python.org/issue25532
            """

            def _find_lineno(self, obj, source_lines):
                """Doctest code does not take into account `@property`, this
                is a hackish way to fix it.

                https://bugs.python.org/issue17446
                """
                if isinstance(obj, property):
                    obj = getattr(obj, "fget", obj)
                # Type ignored because this is a private function.
                return doctest.DocTestFinder._find_lineno(  # type: ignore
                    self,
                    obj,
                    source_lines,
                )

            def _find(
                self, tests, obj, name, module, source_lines, globs, seen
            ) -> None:
                if _is_mocked(obj):
                    return
                with _patch_unwrap_mock_aware():

                    # Type ignored because this is a private function.
                    doctest.DocTestFinder._find(  # type: ignore
                        self, tests, obj, name, module, source_lines, globs, seen
                    )

        if self.path.name == "conftest.py":
            module = self.config.pluginmanager._importconftest(
                self.path, self.config.getoption("importmode")
            )
        else:
            try:
                module = import_path(self.path)
            except ImportError:
                if self.config.getvalue("doctest_ignore_import_errors"):
                    pytest.skip("unable to import module %r" % self.path)
                else:
                    raise
        # Uses internal doctest module parsing mechanism.
        finder = MockAwareDocTestFinder()
        optionflags = get_optionflags(self)
        runner = _get_runner(
            verbose=False,
            optionflags=optionflags,
            checker=_get_checker(),
            continue_on_failure=_get_continue_on_failure(self.config),
        )

        for test in finder.find(module, module.__name__):
            if test.examples:  # skip empty doctests
                yield DoctestItem.from_parent(
                    self, name=test.name, runner=runner, dtest=test
                )
Example #26
0
 def test_c(self, path1: Path) -> None:
     otherdir = path1 / "otherdir"
     mod = import_path(otherdir / "c.py", root=path1)
     assert mod.value == "got it"  # type: ignore[attr-defined]