Skip to content

Commit

Permalink
Merge pull request pytest-dev#1979 from nicoddemus/show-traceback-dur…
Browse files Browse the repository at this point in the history
…ing-collection

Show traceback during collection
  • Loading branch information
nicoddemus authored Oct 5, 2016
2 parents 1289cbb + a1d446b commit cf13355
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 22 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@

*

*
* Import errors when collecting test modules now display the full traceback (`#1976`_).
Thanks `@cwitty`_ for the report and `@nicoddemus`_ for the PR.

*

*


.. _@cwitty: https://github.com/cwitty

.. _#1976: https://github.com/pytest-dev/pytest/issues/1976



3.0.3
=====

Expand Down
24 changes: 17 additions & 7 deletions _pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@
getlocation, enum,
)

cutdir2 = py.path.local(_pytest.__file__).dirpath()
cutdir1 = py.path.local(pluggy.__file__.rstrip("oc"))
cutdir2 = py.path.local(_pytest.__file__).dirpath()
cutdir3 = py.path.local(py.__file__).dirpath()


def filter_traceback(entry):
"""Return True if a TracebackEntry instance should be removed from tracebacks:
* dynamically generated code (no code to show up for it);
* internal traceback from pytest or its internal libraries, py and pluggy.
"""
# entry.path might sometimes return a str object when the entry
# points to dynamically generated code
# see https://bitbucket.org/pytest-dev/py/issues/71
Expand All @@ -37,7 +42,7 @@ def filter_traceback(entry):
# entry.path might point to an inexisting file, in which case it will
# alsso return a str object. see #1133
p = py.path.local(entry.path)
return p != cutdir1 and not p.relto(cutdir2)
return p != cutdir1 and not p.relto(cutdir2) and not p.relto(cutdir3)



Expand Down Expand Up @@ -424,12 +429,17 @@ def _importtestmodule(self):
% e.args
)
except ImportError:
exc_class, exc, _ = sys.exc_info()
from _pytest._code.code import ExceptionInfo
exc_info = ExceptionInfo()
if self.config.getoption('verbose') < 2:
exc_info.traceback = exc_info.traceback.filter(filter_traceback)
exc_repr = exc_info.getrepr(style='short') if exc_info.traceback else exc_info.exconly()
formatted_tb = py._builtin._totext(exc_repr)
raise self.CollectError(
"ImportError while importing test module '%s'.\n"
"Original error message:\n'%s'\n"
"Make sure your test modules/packages have valid Python names."
% (self.fspath, exc or exc_class)
"ImportError while importing test module '{fspath}'.\n"
"Hint: make sure your test modules/packages have valid Python names.\n"
"Traceback:\n"
"{traceback}".format(fspath=self.fspath, traceback=formatted_tb)
)
except _pytest.runner.Skipped as e:
if e.allow_module_level:
Expand Down
2 changes: 1 addition & 1 deletion testing/acceptance_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def test_this():
result.stdout.fnmatch_lines([
#XXX on jython this fails: "> import import_fails",
"ImportError while importing test module*",
"'No module named *does_not_work*",
"*No module named *does_not_work*",
])
assert result.ret == 2

Expand Down
35 changes: 34 additions & 1 deletion testing/python/collect.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import os
import sys
from textwrap import dedent

Expand Down Expand Up @@ -68,9 +69,41 @@ def test_invalid_test_module_name(self, testdir):
result = testdir.runpytest("-rw")
result.stdout.fnmatch_lines([
"ImportError while importing test module*test_one.part1*",
"Make sure your test modules/packages have valid Python names.",
"Hint: make sure your test modules/packages have valid Python names.",
])

@pytest.mark.parametrize('verbose', [0, 1, 2])
def test_show_traceback_import_error(self, testdir, verbose):
"""Import errors when collecting modules should display the traceback (#1976).
With low verbosity we omit pytest and internal modules, otherwise show all traceback entries.
"""
testdir.makepyfile(
foo_traceback_import_error="""
from bar_traceback_import_error import NOT_AVAILABLE
""",
bar_traceback_import_error="",
)
testdir.makepyfile("""
import foo_traceback_import_error
""")
args = ('-v',) * verbose
result = testdir.runpytest(*args)
result.stdout.fnmatch_lines([
"ImportError while importing test module*",
"Traceback:",
"*from bar_traceback_import_error import NOT_AVAILABLE",
"*cannot import name *NOT_AVAILABLE*",
])
assert result.ret == 2

stdout = result.stdout.str()
for name in ('_pytest', os.path.join('py', '_path')):
if verbose == 2:
assert name in stdout
else:
assert name not in stdout


class TestClass:
def test_class_with_init_warning(self, testdir):
Expand Down
11 changes: 0 additions & 11 deletions testing/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,17 +172,6 @@ def pytest_collect_directory(self, path, parent):
assert "world" in wascalled

class TestPrunetraceback:
def test_collection_error(self, testdir):
p = testdir.makepyfile("""
import not_exists
""")
result = testdir.runpytest(p)
assert "__import__" not in result.stdout.str(), "too long traceback"
result.stdout.fnmatch_lines([
"*ERROR collecting*",
"ImportError while importing test module*",
"'No module named *not_exists*",
])

def test_custom_repr_failure(self, testdir):
p = testdir.makepyfile("""
Expand Down
2 changes: 1 addition & 1 deletion testing/test_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ def test_collect_fail(self, testdir, option):
result = testdir.runpytest(*option.args)
result.stdout.fnmatch_lines([
"ImportError while importing*",
"'No module named *xyz*",
"*No module named *xyz*",
"*1 error*",
])

Expand Down

0 comments on commit cf13355

Please sign in to comment.