From 9e1e7fcabe4ebcdbcdadbd1f3eb8866f3c1821a7 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 16 May 2020 16:05:12 -0300 Subject: [PATCH] Use a nice string repr for ConftestImportFailure The default message is often hard to read: E _pytest.config.ConftestImportFailure: (local('D:\\projects\\pytest\\.tmp\\root\\foo\\conftest.py'), (, RuntimeError('some error',), )) Using a shorter message is better: E _pytest.config.ConftestImportFailure: RuntimeError: some error (from D:\projects\pytest\.tmp\root\foo\conftest.py) And we don't really lose any information due to exception chaining. --- src/_pytest/config/__init__.py | 7 ++++++- testing/test_config.py | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index d45feb624..a4fc6e7c1 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -88,10 +88,15 @@ class ExitCode(enum.IntEnum): class ConftestImportFailure(Exception): def __init__(self, path, excinfo): - Exception.__init__(self, path, excinfo) + super().__init__(path, excinfo) self.path = path self.excinfo = excinfo # type: Tuple[Type[Exception], Exception, TracebackType] + def __str__(self): + return "{}: {} (from {})".format( + self.excinfo[0].__name__, self.excinfo[1], self.path + ) + def main(args=None, plugins=None) -> Union[int, ExitCode]: """ return exit code, after performing an in-process test run. diff --git a/testing/test_config.py b/testing/test_config.py index f6bf0499f..7d553e63b 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -10,6 +10,7 @@ import pytest from _pytest.compat import importlib_metadata from _pytest.config import _iter_rewritable_modules from _pytest.config import Config +from _pytest.config import ConftestImportFailure from _pytest.config import ExitCode from _pytest.config.exceptions import UsageError from _pytest.config.findpaths import determine_setup @@ -1471,3 +1472,19 @@ class TestPytestPluginsVariable: assert res.ret == 0 msg = "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported" assert msg not in res.stdout.str() + + +def test_conftest_import_error_repr(tmpdir): + """ + ConftestImportFailure should use a short error message and readable path to the failed + conftest.py file + """ + path = tmpdir.join("foo/conftest.py") + with pytest.raises( + ConftestImportFailure, + match=re.escape("RuntimeError: some error (from {})".format(path)), + ): + try: + raise RuntimeError("some error") + except Exception: + raise ConftestImportFailure(path, sys.exc_info())