Skip to content

Commit 8e11fe5

Browse files
committed
Improve tracebacks for ImportErrors in conftest.py files
Fix #3332
1 parent 36dc671 commit 8e11fe5

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

changelog/3332.feature.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Improve the error displayed when a ``conftest.py`` file could not be imported.
2+
3+
In order to implement this, a new ``chain`` parameter was added to ``ExceptionInfo.getrepr``
4+
to show or hide chained tracebacks in Python 3 (defaults to ``True``).

src/_pytest/config/__init__.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,24 @@ def main(args=None, plugins=None):
5757
try:
5858
config = _prepareconfig(args, plugins)
5959
except ConftestImportFailure as e:
60+
from _pytest._code import ExceptionInfo
61+
62+
exc_info = ExceptionInfo(e.excinfo)
6063
tw = py.io.TerminalWriter(sys.stderr)
61-
for line in traceback.format_exception(*e.excinfo):
64+
tw.line(
65+
"ImportError while loading conftest '{e.path}'.".format(e=e), red=True
66+
)
67+
from _pytest.python import filter_traceback
68+
69+
exc_info.traceback = exc_info.traceback.filter(filter_traceback)
70+
exc_repr = (
71+
exc_info.getrepr(style="short", chain=False)
72+
if exc_info.traceback
73+
else exc_info.exconly()
74+
)
75+
formatted_tb = safe_str(exc_repr)
76+
for line in formatted_tb.splitlines():
6277
tw.line(line.rstrip(), red=True)
63-
tw.line("ERROR: could not load %s\n" % (e.path,), red=True)
6478
return 4
6579
else:
6680
try:

testing/acceptance_test.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,16 @@ def test_not_collectable_arguments(self, testdir):
133133
assert result.ret
134134
result.stderr.fnmatch_lines(["*ERROR: not found:*{}".format(p2.basename)])
135135

136-
def test_issue486_better_reporting_on_conftest_load_failure(self, testdir):
136+
def test_better_reporting_on_conftest_load_failure(self, testdir, request):
137+
"""Show a user-friendly traceback on conftest import failures (#486, #3332)"""
137138
testdir.makepyfile("")
138-
testdir.makeconftest("import qwerty")
139+
testdir.makeconftest(
140+
"""
141+
def foo():
142+
import qwerty
143+
foo()
144+
"""
145+
)
139146
result = testdir.runpytest("--help")
140147
result.stdout.fnmatch_lines(
141148
"""
@@ -144,10 +151,23 @@ def test_issue486_better_reporting_on_conftest_load_failure(self, testdir):
144151
"""
145152
)
146153
result = testdir.runpytest()
154+
dirname = request.node.name + "0"
155+
exc_name = (
156+
"ModuleNotFoundError" if sys.version_info >= (3, 6) else "ImportError"
157+
)
147158
result.stderr.fnmatch_lines(
148-
"""
149-
*ERROR*could not load*conftest.py*
150-
"""
159+
[
160+
"ImportError while loading conftest '*{sep}{dirname}{sep}conftest.py'.".format(
161+
dirname=dirname, sep=os.sep
162+
),
163+
"conftest.py:3: in <module>",
164+
" foo()",
165+
"conftest.py:2: in foo",
166+
" import qwerty",
167+
"E {}: No module named {q}qwerty{q}".format(
168+
exc_name, q="'" if six.PY3 else ""
169+
),
170+
]
151171
)
152172

153173
def test_early_skip(self, testdir):

0 commit comments

Comments
 (0)