[py-svn] py-trunk commit 63605bbed9cd: show a short and nice traceback for funcarg lookup errors

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Thu Feb 4 16:01:36 CET 2010


# HG changeset patch -- Bitbucket.org
# Project py-trunk
# URL http://bitbucket.org/hpk42/py-trunk/overview/
# User holger krekel <holger at merlinux.eu>
# Date 1265295662 -3600
# Node ID 63605bbed9cd43bb510c68d8ee9617e9ba43fd4e
# Parent 63eee427687c806c84c024fbcf82e23f8d8c6744
show a short and nice traceback for funcarg lookup errors

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

--- a/py/_test/pycollect.py
+++ b/py/_test/pycollect.py
@@ -5,6 +5,7 @@ import py
 import inspect
 from py._test.collect import configproperty, warnoldcollect
 from py._test import funcargs
+from py._code.code import TerminalRepr
 
 class PyobjMixin(object):
     def obj(): 
@@ -252,12 +253,38 @@ class FunctionMixin(PyobjMixin):
             traceback = ntraceback.filter()
         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):
         assert outerr is None, "XXX outerr usage is deprecated"
         return self._repr_failure_py(excinfo)
 
     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): 
     def collect(self):
         # test generators are seen as collectors but they also 

--- a/testing/test_funcargs.py
+++ b/testing/test_funcargs.py
@@ -30,7 +30,8 @@ class TestFillFuncArgs:
                 return 42
         """)
         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)
         assert s.find("xyzsomething") != -1
 
@@ -560,3 +561,18 @@ def test_funcarg_non_pycollectobj(testdi
     funcargs.fillfuncargs(clscol)
     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() 

--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 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
   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.



More information about the pytest-commit mailing list