[Twisted-web] formatFailure recursion problems

Phil Christensen phil at bubblehouse.org
Wed Mar 26 14:30:39 EDT 2008


I've been using formatFailure recently to provide pretty tracebacks in  
my webapp, and I'm loving it, but I've run into a scenario where I've  
got a recursive data structure that occasionally pops up in  
tracebacks, and causes formatFailure all kinds of problems.

Now, I can't really do much about the recursion itself, because it  
appears to be an unfortunate side effect of embedding Trac into a WSGI  
app I've written (the app just passes its environ variable to trac,  
acting as pseudo-transparent middleware).

So, the real question is, is there anything that can be done to make  
formatFailure deal with recursion more gracefully? I'm currently using  
a extremely quick-and-dirty hack that just caches the id of each  
non-'primitive' object, and returns '==RECURSION==' when it encounters  
the id a second time.

I guess what would be ideal is if it were possible could set some kind  
of depth limit for the htmlrepr() stuff, since most of the time I have  
no need to see that "deeply" into a local or global variable.

I'm glad to work on the patch myself, but I was wondering if anyone  
has any suggestions as to how this should work. The current patch I'm  
using is attached below, but it's pretty overzealous about preventing  
recursion; if you output the object once anywhere in the entire  
traceback, it will never be output again, even in a non-recursive  
scenario.

Anyways, any input would be appreciated...

-phil





Index: twisted/web/util.py
===================================================================
--- twisted/web/util.py (revision 23090)
+++ twisted/web/util.py (working copy)
@@ -234,8 +234,13 @@
  </style>
  """

-
+repr_cache = None
  def htmlrepr(x):
+    if(repr_cache is not None and type(x) not in (str, int, long,  
float, unicode)):
+        if(id(x) in repr_cache):
+            return '==RECURSION=='
+        else:
+            repr_cache[id(x)] = 1
      return htmlReprTypes.get(type(x), htmlUnknown)(x)

  def saferepr(x):
@@ -304,7 +309,6 @@
      return ret

  def formatFailure(myFailure):
-
      exceptionHTML = """
  <p class="error">%s: %s</p>
  """
@@ -325,6 +329,9 @@
  <tr class="varRow"><td class="varName">%s</td><td class="varValue"> 
%s</td></tr>
  """

+    global repr_cache
+    repr_cache = {}
+
      if not isinstance(myFailure, failure.Failure):
          return html.PRE(str(myFailure))
      io = StringIO()
@@ -387,4 +394,5 @@
      w(exceptionHTML % (html.escape(str(myFailure.type)),
                         html.escape(str(myFailure.value))))

+    repr_cache = None
      return io.getvalue()



More information about the Twisted-web mailing list