show a short and nice traceback for funcarg lookup errors

--HG--
branch : trunk
This commit is contained in:
holger krekel 2010-02-04 16:01:02 +01:00
parent 7bd60b5abb
commit f95877a09b
4 changed files with 48 additions and 5 deletions

View File

@ -1,6 +1,7 @@
Changes between 1.2.1 and 1.2.0 Changes between 1.2.1 and 1.2.0
===================================== =====================================
- display a short and concise traceback if a funcarg lookup fails
- early-load "test*/conftest.py" files, i.e. conftest.py files in - early-load "test*/conftest.py" files, i.e. conftest.py files in
directories starting with 'test'. allows to conveniently keep and access directories starting with 'test'. allows to conveniently keep and access
test-related options without having to put a conftest.py into the package root dir. test-related options without having to put a conftest.py into the package root dir.

View File

@ -64,7 +64,7 @@ class FuncargRequest:
_argprefix = "pytest_funcarg__" _argprefix = "pytest_funcarg__"
_argname = None _argname = None
class Error(LookupError): class LookupError(LookupError):
""" error on performing funcarg request. """ """ error on performing funcarg request. """
def __init__(self, pyfuncitem): def __init__(self, pyfuncitem):
@ -170,7 +170,6 @@ class FuncargRequest:
if name not in available: if name not in available:
available.append(name) available.append(name)
fspath, lineno, msg = self._pyfuncitem.reportinfo() fspath, lineno, msg = self._pyfuncitem.reportinfo()
line = "%s:%s" %(fspath, lineno) msg = "LookupError: no factory found for function argument %r" % (argname,)
msg = "funcargument %r not found for: %s" %(argname, line)
msg += "\n available funcargs: %s" %(", ".join(available),) msg += "\n available funcargs: %s" %(", ".join(available),)
raise self.Error(msg) raise self.LookupError(msg)

View File

@ -5,6 +5,7 @@ import py
import inspect import inspect
from py._test.collect import configproperty, warnoldcollect from py._test.collect import configproperty, warnoldcollect
from py._test import funcargs from py._test import funcargs
from py._code.code import TerminalRepr
class PyobjMixin(object): class PyobjMixin(object):
def obj(): def obj():
@ -252,12 +253,38 @@ class FunctionMixin(PyobjMixin):
traceback = ntraceback.filter() traceback = ntraceback.filter()
return traceback return traceback
def _repr_failure_py(self, excinfo):
if excinfo.errisinstance(funcargs.FuncargRequest.LookupError):
fspath, lineno, msg = self.reportinfo()
lines, _ = inspect.getsourcelines(self.obj)
for i, line in enumerate(lines):
if line.strip().startswith('def'):
return FuncargLookupErrorRepr(fspath, lineno,
lines[:i+1], str(excinfo.value))
return super(FunctionMixin, self)._repr_failure_py(excinfo)
def repr_failure(self, excinfo, outerr=None): def repr_failure(self, excinfo, outerr=None):
assert outerr is None, "XXX outerr usage is deprecated" assert outerr is None, "XXX outerr usage is deprecated"
return self._repr_failure_py(excinfo) return self._repr_failure_py(excinfo)
shortfailurerepr = "F" shortfailurerepr = "F"
class FuncargLookupErrorRepr(TerminalRepr):
def __init__(self, filename, firstlineno, deflines, errorstring):
self.deflines = deflines
self.errorstring = errorstring
self.filename = filename
self.firstlineno = firstlineno
def toterminal(self, tw):
tw.line()
for line in self.deflines:
tw.line(" " + line.strip())
for line in self.errorstring.split("\n"):
tw.line(" " + line.strip(), red=True)
tw.line()
tw.line("%s:%d" % (self.filename, self.firstlineno+1))
class Generator(FunctionMixin, PyCollectorMixin, py.test.collect.Collector): class Generator(FunctionMixin, PyCollectorMixin, py.test.collect.Collector):
def collect(self): def collect(self):
# test generators are seen as collectors but they also # test generators are seen as collectors but they also

View File

@ -30,7 +30,8 @@ class TestFillFuncArgs:
return 42 return 42
""") """)
item = testdir.getitem("def test_func(some): pass") item = testdir.getitem("def test_func(some): pass")
exc = py.test.raises(LookupError, "funcargs.fillfuncargs(item)") exc = py.test.raises(funcargs.FuncargRequest.LookupError,
"funcargs.fillfuncargs(item)")
s = str(exc.value) s = str(exc.value)
assert s.find("xyzsomething") != -1 assert s.find("xyzsomething") != -1
@ -560,3 +561,18 @@ def test_funcarg_non_pycollectobj(testdir): # rough jstests usage
funcargs.fillfuncargs(clscol) funcargs.fillfuncargs(clscol)
assert clscol.funcargs['arg1'] == 42 assert clscol.funcargs['arg1'] == 42
def test_funcarg_lookup_error(testdir):
p = testdir.makepyfile("""
def test_lookup_error(unknown):
pass
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"*ERROR at setup of test_lookup_error*",
"*def test_lookup_error(unknown):*",
"*LookupError: no factory found*unknown*",
"*available funcargs*",
"*1 error*",
])
assert "INTERNAL" not in result.stdout.str()