예제 #1
0
def test_deferred_hook_checking(pytester: Pytester) -> None:
    """Check hooks as late as possible (#1821)."""
    pytester.syspathinsert()
    pytester.makepyfile(
        **{
            "plugin.py": """
        class Hooks(object):
            def pytest_my_hook(self, config):
                pass

        def pytest_configure(config):
            config.pluginmanager.add_hookspecs(Hooks)
        """,
            "conftest.py": """
            pytest_plugins = ['plugin']
            def pytest_my_hook(config):
                return 40
        """,
            "test_foo.py": """
            def test(request):
                assert request.config.hook.pytest_my_hook(config=request.config) == [40]
        """,
        }
    )
    result = pytester.runpytest()
    result.stdout.fnmatch_lines(["* 1 passed *"])
예제 #2
0
    def test_filter_traceback_path_no_longer_valid(self, pytester: Pytester) -> None:
        """Test that filter_traceback() works with the fact that
        _pytest._code.code.Code.path attribute might return an str object.

        In this case, one of the files in the traceback no longer exists.
        This fixes #1133.
        """
        from _pytest._code import filter_traceback

        pytester.syspathinsert()
        pytester.makepyfile(
            filter_traceback_entry_as_str="""
            def foo():
                raise ValueError
        """
        )
        tb = None
        try:
            import filter_traceback_entry_as_str

            filter_traceback_entry_as_str.foo()
        except ValueError:
            _, _, tb = sys.exc_info()

        assert tb is not None
        pytester.path.joinpath("filter_traceback_entry_as_str.py").unlink()
        traceback = _pytest._code.Traceback(tb)
        assert isinstance(traceback[-1].path, str)
        assert filter_traceback(traceback[-1])
예제 #3
0
    def invocation_path(self, pytester: Pytester) -> Path:
        pytester.syspathinsert(pytester.path / "src")
        pytester.chdir()

        pkg = pytester.path.joinpath("src/pkg")
        pkg.mkdir(parents=True)
        pkg.joinpath("__init__.py").touch()
        pkg.joinpath("test.py").touch()
        return pytester.path
예제 #4
0
    def test_chained_exceptions_no_reprcrash(self, pytester: Pytester, tw_mock) -> None:
        """Regression test for tracebacks without a reprcrash (#5971)

        This happens notably on exceptions raised by multiprocess.pool: the exception transfer
        from subprocess to main process creates an artificial exception, which ExceptionInfo
        can't obtain the ReprFileLocation from.
        """
        pytester.makepyfile(
            """
            from concurrent.futures import ProcessPoolExecutor

            def func():
                raise ValueError('value error')

            def test_a():
                with ProcessPoolExecutor() as p:
                    p.submit(func).result()
        """
        )

        pytester.syspathinsert()
        reprec = pytester.inline_run()

        reports = reprec.getreports("pytest_runtest_logreport")

        def check_longrepr(longrepr: object) -> None:
            assert isinstance(longrepr, ExceptionChainRepr)
            assert len(longrepr.chain) == 2
            entry1, entry2 = longrepr.chain
            tb1, fileloc1, desc1 = entry1
            tb2, fileloc2, desc2 = entry2

            assert "RemoteTraceback" in str(tb1)
            assert "ValueError: value error" in str(tb2)

            assert fileloc1 is None
            assert fileloc2 is not None
            assert fileloc2.message == "ValueError: value error"

        # 3 reports: setup/call/teardown: get the call report
        assert len(reports) == 3
        report = reports[1]

        assert report.failed
        check_longrepr(report.longrepr)

        data = report._to_json()
        loaded_report = TestReport._from_json(data)

        assert loaded_report.failed
        check_longrepr(loaded_report.longrepr)

        # for same reasons as previous test, ensure we don't blow up here
        assert loaded_report.longrepr is not None
        assert isinstance(loaded_report.longrepr, ExceptionChainRepr)
        loaded_report.longrepr.toterminal(tw_mock)
예제 #5
0
 def test_consider_module(self, pytester: Pytester,
                          pytestpm: PytestPluginManager) -> None:
     pytester.syspathinsert()
     pytester.makepyfile(pytest_p1="#")
     pytester.makepyfile(pytest_p2="#")
     mod = types.ModuleType("temp")
     mod.__dict__["pytest_plugins"] = ["pytest_p1", "pytest_p2"]
     pytestpm.consider_module(mod)
     assert pytestpm.get_plugin("pytest_p1").__name__ == "pytest_p1"
     assert pytestpm.get_plugin("pytest_p2").__name__ == "pytest_p2"
예제 #6
0
    def test_newfirst_usecase(self, pytester: Pytester) -> None:
        pytester.makepyfile(
            **{
                "test_1/test_1.py": """
                def test_1(): assert 1
            """,
                "test_2/test_2.py": """
                def test_1(): assert 1
            """,
            }
        )

        p1 = pytester.path.joinpath("test_1/test_1.py")
        os.utime(p1, ns=(p1.stat().st_atime_ns, int(1e9)))

        result = pytester.runpytest("-v")
        result.stdout.fnmatch_lines(
            ["*test_1/test_1.py::test_1 PASSED*", "*test_2/test_2.py::test_1 PASSED*"]
        )

        result = pytester.runpytest("-v", "--nf")
        result.stdout.fnmatch_lines(
            ["*test_2/test_2.py::test_1 PASSED*", "*test_1/test_1.py::test_1 PASSED*"]
        )

        p1.write_text("def test_1(): assert 1\n" "def test_2(): assert 1\n")
        os.utime(p1, ns=(p1.stat().st_atime_ns, int(1e9)))

        result = pytester.runpytest("--nf", "--collect-only", "-q")
        result.stdout.fnmatch_lines(
            [
                "test_1/test_1.py::test_2",
                "test_2/test_2.py::test_1",
                "test_1/test_1.py::test_1",
            ]
        )

        # Newest first with (plugin) pytest_collection_modifyitems hook.
        pytester.makepyfile(
            myplugin="""
            def pytest_collection_modifyitems(items):
                items[:] = sorted(items, key=lambda item: item.nodeid)
                print("new_items:", [x.nodeid for x in items])
            """
        )
        pytester.syspathinsert()
        result = pytester.runpytest("--nf", "-p", "myplugin", "--collect-only", "-q")
        result.stdout.fnmatch_lines(
            [
                "new_items: *test_1.py*test_1.py*test_2.py*",
                "test_1/test_1.py::test_2",
                "test_2/test_2.py::test_1",
                "test_1/test_1.py::test_1",
            ]
        )
예제 #7
0
    def test_import_plugin_dotted_name(self, pytester: Pytester,
                                       pytestpm: PytestPluginManager) -> None:
        pytest.raises(ImportError, pytestpm.import_plugin, "qweqwex.y")
        pytest.raises(ImportError, pytestpm.import_plugin, "pytest_qweqwex.y")

        pytester.syspathinsert()
        pytester.mkpydir("pkg").joinpath("plug.py").write_text("x=3")
        pluginname = "pkg.plug"
        pytestpm.import_plugin(pluginname)
        mod = pytestpm.get_plugin("pkg.plug")
        assert mod.x == 3
예제 #8
0
    def test_external_test_module_imports_not_cleaned_up(
            self, pytester: Pytester) -> None:
        pytester.syspathinsert()
        pytester.makepyfile(imported="data = 'you son of a silly person'")
        import imported

        test_mod = pytester.makepyfile("""
            def test_foo():
                import imported
                imported.data = 42""")
        pytester.inline_run(str(test_mod))
        assert imported.data == 42
예제 #9
0
    def test_consider_module_import_module(self, pytester: Pytester,
                                           _config_for_test: Config) -> None:
        pytestpm = _config_for_test.pluginmanager
        mod = types.ModuleType("x")
        mod.__dict__["pytest_plugins"] = "pytest_a"
        aplugin = pytester.makepyfile(pytest_a="#")
        reprec = pytester.make_hook_recorder(pytestpm)
        pytester.syspathinsert(aplugin.parent)
        pytestpm.consider_module(mod)
        call = reprec.getcall(pytestpm.hook.pytest_plugin_registered.name)
        assert call.plugin.__name__ == "pytest_a"

        # check that it is not registered twice
        pytestpm.consider_module(mod)
        values = reprec.getcalls("pytest_plugin_registered")
        assert len(values) == 1
예제 #10
0
 def test_inline_run_taking_and_restoring_a_sys_modules_snapshot(
         self, pytester: Pytester, monkeypatch: MonkeyPatch) -> None:
     spy_factory = self.spy_factory()
     monkeypatch.setattr(pytester_mod, "SysModulesSnapshot", spy_factory)
     pytester.syspathinsert()
     original = dict(sys.modules)
     pytester.makepyfile(import1="# you son of a silly person")
     pytester.makepyfile(import2="# my hovercraft is full of eels")
     test_mod = pytester.makepyfile("""
         import import1
         def test_foo(): import import2""")
     pytester.inline_run(str(test_mod))
     assert len(spy_factory.instances) == 1
     spy = spy_factory.instances[0]
     assert spy._spy_restore_count == 1
     assert sys.modules == original
     assert all(sys.modules[x] is original[x] for x in sys.modules)
예제 #11
0
    def test_import_plugin_importname(self, pytester: Pytester,
                                      pytestpm: PytestPluginManager) -> None:
        pytest.raises(ImportError, pytestpm.import_plugin, "qweqwex.y")
        pytest.raises(ImportError, pytestpm.import_plugin, "pytest_qweqwx.y")

        pytester.syspathinsert()
        pluginname = "pytest_hello"
        pytester.makepyfile(**{pluginname: ""})
        pytestpm.import_plugin("pytest_hello")
        len1 = len(pytestpm.get_plugins())
        pytestpm.import_plugin("pytest_hello")
        len2 = len(pytestpm.get_plugins())
        assert len1 == len2
        plugin1 = pytestpm.get_plugin("pytest_hello")
        assert plugin1.__name__.endswith("pytest_hello")
        plugin2 = pytestpm.get_plugin("pytest_hello")
        assert plugin2 is plugin1
예제 #12
0
 def test_consider_env_plugin_instantiation(
     self,
     pytester: Pytester,
     monkeypatch: MonkeyPatch,
     pytestpm: PytestPluginManager,
 ) -> None:
     pytester.syspathinsert()
     pytester.makepyfile(xy123="#")
     monkeypatch.setitem(os.environ, "PYTEST_PLUGINS", "xy123")
     l1 = len(pytestpm.get_plugins())
     pytestpm.consider_env()
     l2 = len(pytestpm.get_plugins())
     assert l2 == l1 + 1
     assert pytestpm.get_plugin("xy123")
     pytestpm.consider_env()
     l3 = len(pytestpm.get_plugins())
     assert l2 == l3
예제 #13
0
    def test_early_load_setuptools_name(
        self, pytester: Pytester, monkeypatch, load_cov_early
    ) -> None:
        monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")

        pytester.makepyfile(mytestplugin1_module="")
        pytester.makepyfile(mytestplugin2_module="")
        pytester.makepyfile(mycov_module="")
        pytester.syspathinsert()

        loaded = []

        @attr.s
        class DummyEntryPoint:
            name = attr.ib()
            module = attr.ib()
            group = "pytest11"

            def load(self):
                __import__(self.module)
                loaded.append(self.name)
                return sys.modules[self.module]

        entry_points = [
            DummyEntryPoint("myplugin1", "mytestplugin1_module"),
            DummyEntryPoint("myplugin2", "mytestplugin2_module"),
            DummyEntryPoint("mycov", "mycov_module"),
        ]

        @attr.s
        class DummyDist:
            entry_points = attr.ib()
            files = ()

        def my_dists():
            return (DummyDist(entry_points),)

        monkeypatch.setattr(importlib_metadata, "distributions", my_dists)
        params = ("-p", "mycov") if load_cov_early else ()
        pytester.runpytest_inprocess(*params)
        if load_cov_early:
            assert loaded == ["mycov", "myplugin1", "myplugin2"]
        else:
            assert loaded == ["myplugin1", "myplugin2", "mycov"]
예제 #14
0
def test_importplugin_error_message(pytester: Pytester,
                                    pytestpm: PytestPluginManager) -> None:
    """Don't hide import errors when importing plugins and provide
    an easy to debug message.

    See #375 and #1998.
    """
    pytester.syspathinsert(pytester.path)
    pytester.makepyfile(qwe="""\
        def test_traceback():
            raise ImportError('Not possible to import: ☺')
        test_traceback()
        """)
    with pytest.raises(ImportError) as excinfo:
        pytestpm.import_plugin("qwe")

    assert str(excinfo.value).endswith(
        'Error importing plugin "qwe": Not possible to import: ☺')
    assert "in test_traceback" in str(excinfo.traceback[-1])
예제 #15
0
    def test_issue4445_import_plugin(self, pytester: Pytester,
                                     capwarn) -> None:
        """#4445: Make sure the warning points to a reasonable location"""
        pytester.makepyfile(some_plugin="""
            import pytest
            pytest.skip("thing", allow_module_level=True)
            """)
        pytester.syspathinsert()
        pytester.parseconfig("-p", "some_plugin")

        # with stacklevel=2 the warning should originate from
        # config.PytestPluginManager.import_plugin is thrown by a skipped plugin

        assert len(capwarn.captured) == 1
        warning, location = capwarn.captured.pop()
        file, _, func = location

        assert "skipped plugin 'some_plugin': thing" in str(warning.message)
        assert f"config{os.sep}__init__.py" in file
        assert func == "_warn_about_skipped_plugins"
예제 #16
0
def test_group_warnings_by_message_summary(pytester: Pytester) -> None:
    pytester.copy_example("warnings/test_group_warnings_by_message_summary")
    pytester.syspathinsert()
    result = pytester.runpytest()
    result.stdout.fnmatch_lines(
        [
            "*== %s ==*" % WARNINGS_SUMMARY_HEADER,
            "test_1.py: 21 warnings",
            "test_2.py: 1 warning",
            "  */test_1.py:7: UserWarning: foo",
            "    warnings.warn(UserWarning(msg))",
            "",
            "test_1.py: 20 warnings",
            "  */test_1.py:7: UserWarning: bar",
            "    warnings.warn(UserWarning(msg))",
            "",
            "-- Docs: *",
            "*= 42 passed, 42 warnings *",
        ],
        consecutive=True,
    )
예제 #17
0
def pyfile_with_warnings(pytester: Pytester, request: FixtureRequest) -> str:
    """Create a test file which calls a function in a module which generates warnings."""
    pytester.syspathinsert()
    test_name = request.function.__name__
    module_name = test_name.lstrip("test_") + "_module"
    test_file = pytester.makepyfile(
        """
        import {module_name}
        def test_func():
            assert {module_name}.foo() == 1
        """.format(module_name=module_name),
        **{
            module_name:
            """
            import warnings
            def foo():
                warnings.warn(UserWarning("user warning"))
                warnings.warn(RuntimeWarning("runtime warning"))
                return 1
            """,
        },
    )
    return str(test_file)
예제 #18
0
def test_external_plugins_integrated(pytester: Pytester, plugin) -> None:
    pytester.syspathinsert()
    pytester.makepyfile(**{plugin: ""})

    with pytest.warns(pytest.PytestConfigWarning):
        pytester.parseconfig("-p", plugin)