From 6546d1f7257d986c2598dd2ebd2bbd8d04285585 Mon Sep 17 00:00:00 2001 From: Florian Dahlitz Date: Mon, 25 May 2020 13:53:56 +0200 Subject: [PATCH 1/4] Prevent pytest from printing ConftestImportFailure traceback --- changelog/6956.bugfix.rst | 1 + src/_pytest/nodes.py | 3 +++ testing/python/collect.py | 9 +++------ testing/test_reports.py | 12 ++++++++++++ 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 changelog/6956.bugfix.rst diff --git a/changelog/6956.bugfix.rst b/changelog/6956.bugfix.rst new file mode 100644 index 000000000..a88ef94b6 --- /dev/null +++ b/changelog/6956.bugfix.rst @@ -0,0 +1 @@ +Prevent pytest from printing ConftestImportFailure traceback to stdout. diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 2f5f9bdb8..4c2a0a3a7 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -19,6 +19,7 @@ from _pytest._code.code import ReprExceptionInfo from _pytest.compat import cached_property from _pytest.compat import TYPE_CHECKING from _pytest.config import Config +from _pytest.config import ConftestImportFailure from _pytest.config import PytestPluginManager from _pytest.deprecated import NODE_USE_FROM_PARENT from _pytest.fixtures import FixtureDef @@ -340,6 +341,8 @@ class Node(metaclass=NodeMeta): return excinfo.value.formatrepr() if self.config.getoption("fulltrace", False): style = "long" + if excinfo.type is ConftestImportFailure: # type: ignore + excinfo = ExceptionInfo.from_exc_info(excinfo.value.excinfo) # type: ignore else: tb = _pytest._code.Traceback([excinfo.traceback[-1]]) self._prunetraceback(excinfo) diff --git a/testing/python/collect.py b/testing/python/collect.py index 2807cacc9..cbc798ad8 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -1251,7 +1251,7 @@ def test_syntax_error_with_non_ascii_chars(testdir): result.stdout.fnmatch_lines(["*ERROR collecting*", "*SyntaxError*", "*1 error in*"]) -def test_collecterror_with_fulltrace(testdir): +def test_collect_error_with_fulltrace(testdir): testdir.makepyfile("assert 0") result = testdir.runpytest("--fulltrace") result.stdout.fnmatch_lines( @@ -1259,15 +1259,12 @@ def test_collecterror_with_fulltrace(testdir): "collected 0 items / 1 error", "", "*= ERRORS =*", - "*_ ERROR collecting test_collecterror_with_fulltrace.py _*", - "", - "*/_pytest/python.py:*: ", - "_ _ _ _ _ _ _ _ *", + "*_ ERROR collecting test_collect_error_with_fulltrace.py _*", "", "> assert 0", "E assert 0", "", - "test_collecterror_with_fulltrace.py:1: AssertionError", + "test_collect_error_with_fulltrace.py:1: AssertionError", "*! Interrupted: 1 error during collection !*", ] ) diff --git a/testing/test_reports.py b/testing/test_reports.py index 13f593215..64d86e953 100644 --- a/testing/test_reports.py +++ b/testing/test_reports.py @@ -396,6 +396,18 @@ class TestReportSerialization: # for same reasons as previous test, ensure we don't blow up here loaded_report.longrepr.toterminal(tw_mock) + def test_report_prevent_ConftestImportFailure_hiding_exception(self, testdir): + sub_dir = testdir.tmpdir.join("ns").ensure_dir() + sub_dir.join("conftest").new(ext=".py").write("import unknown") + + result = testdir.runpytest_subprocess(".") + result.stdout.fnmatch_lines( + ["E ModuleNotFoundError: No module named 'unknown'"] + ) + result.stdout.no_fnmatch_line( + "ERROR - _pytest.config.ConftestImportFailure: ModuleNotFoundError:*" + ) + class TestHooks: """Test that the hooks are working correctly for plugins""" From 5ebcb34fb595c7652ccda889f69b2d4e3ca6443b Mon Sep 17 00:00:00 2001 From: Florian Dahlitz Date: Mon, 25 May 2020 20:19:28 +0200 Subject: [PATCH 2/4] Move ConftestImportFailure check to correct position and add typing --- src/_pytest/nodes.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 4c2a0a3a7..5aae211cd 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -332,17 +332,21 @@ class Node(metaclass=NodeMeta): pass def _repr_failure_py( - self, excinfo: ExceptionInfo[Union[Failed, FixtureLookupError]], style=None + self, + excinfo: ExceptionInfo[ + Union[Failed, FixtureLookupError, ConftestImportFailure] + ], + style=None, ) -> Union[str, ReprExceptionInfo, ExceptionChainRepr, FixtureLookupErrorRepr]: if isinstance(excinfo.value, fail.Exception): if not excinfo.value.pytrace: return str(excinfo.value) if isinstance(excinfo.value, FixtureLookupError): return excinfo.value.formatrepr() + if isinstance(excinfo.value, ConftestImportFailure): + excinfo = ExceptionInfo(excinfo.value.excinfo) # type: ignore if self.config.getoption("fulltrace", False): style = "long" - if excinfo.type is ConftestImportFailure: # type: ignore - excinfo = ExceptionInfo.from_exc_info(excinfo.value.excinfo) # type: ignore else: tb = _pytest._code.Traceback([excinfo.traceback[-1]]) self._prunetraceback(excinfo) From 95bd232e57603329e16bb3a4c694e4fe78655c7b Mon Sep 17 00:00:00 2001 From: Florian Dahlitz Date: Tue, 26 May 2020 10:31:53 +0200 Subject: [PATCH 3/4] Apply suggestions from @bluetech --- src/_pytest/nodes.py | 11 +++-------- testing/test_reports.py | 4 +--- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 5aae211cd..2ed250610 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -29,7 +29,6 @@ from _pytest.mark.structures import Mark from _pytest.mark.structures import MarkDecorator from _pytest.mark.structures import NodeKeywords from _pytest.outcomes import fail -from _pytest.outcomes import Failed from _pytest.store import Store if TYPE_CHECKING: @@ -332,19 +331,15 @@ class Node(metaclass=NodeMeta): pass def _repr_failure_py( - self, - excinfo: ExceptionInfo[ - Union[Failed, FixtureLookupError, ConftestImportFailure] - ], - style=None, + self, excinfo: ExceptionInfo[BaseException], style=None, ) -> Union[str, ReprExceptionInfo, ExceptionChainRepr, FixtureLookupErrorRepr]: + if isinstance(excinfo.value, ConftestImportFailure): + excinfo = ExceptionInfo(excinfo.value.excinfo) if isinstance(excinfo.value, fail.Exception): if not excinfo.value.pytrace: return str(excinfo.value) if isinstance(excinfo.value, FixtureLookupError): return excinfo.value.formatrepr() - if isinstance(excinfo.value, ConftestImportFailure): - excinfo = ExceptionInfo(excinfo.value.excinfo) # type: ignore if self.config.getoption("fulltrace", False): style = "long" else: diff --git a/testing/test_reports.py b/testing/test_reports.py index 64d86e953..9e4e7d09d 100644 --- a/testing/test_reports.py +++ b/testing/test_reports.py @@ -404,9 +404,7 @@ class TestReportSerialization: result.stdout.fnmatch_lines( ["E ModuleNotFoundError: No module named 'unknown'"] ) - result.stdout.no_fnmatch_line( - "ERROR - _pytest.config.ConftestImportFailure: ModuleNotFoundError:*" - ) + result.stdout.no_fnmatch_line("ERROR - *ConftestImportFailure*") class TestHooks: From 5b9924e1444ee662a58d50fb22eaff23c38d6c03 Mon Sep 17 00:00:00 2001 From: Florian Dahlitz Date: Wed, 27 May 2020 09:27:13 +0200 Subject: [PATCH 4/4] Fix py35 CI run --- testing/test_reports.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/testing/test_reports.py b/testing/test_reports.py index 9e4e7d09d..81778e27d 100644 --- a/testing/test_reports.py +++ b/testing/test_reports.py @@ -401,9 +401,7 @@ class TestReportSerialization: sub_dir.join("conftest").new(ext=".py").write("import unknown") result = testdir.runpytest_subprocess(".") - result.stdout.fnmatch_lines( - ["E ModuleNotFoundError: No module named 'unknown'"] - ) + result.stdout.fnmatch_lines(["E *Error: No module named 'unknown'"]) result.stdout.no_fnmatch_line("ERROR - *ConftestImportFailure*")