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()
participants (1)
-
Phil Christensen