On Mon, Jan 03, 2011 at 09:48:02PM +0200, Michael Goldish wrote: > On 01/03/2011 09:26 PM, Eduardo Habkost wrote: > > On Mon, Jan 03, 2011 at 08:34:07PM +0200, Michael Goldish wrote: > >> +# Exception context information: > >> +# ------------------------------ > >> +# Every function can have some context string associated with it. > >> +# The context string can be changed by calling context(str) and cleared by > >> +# calling context() with no parameters. > >> +# get_context() joins the current context strings of all functions in the > >> +# provided traceback. The result is a brief description of what the test was > >> +# doing in the provided traceback (which should be the traceback of a caught > >> +# exception). > > > > I am sure people will eventually forget to call context() to clear > > previous context calls, and people won't notice until an actual error is > > raised on another section. > > > > What about a decorator like: > > > > @context("hello") > > def a() > > ... > > > > That would set/clear the context automatically when the function is > > called/returns? > > - In most cases it isn't necessary. The context dict maps whole stack > traces to context strings, which means that if a function is called > twice from different places in the code, it won't have the same context > string. The only problematic case is functions that are called in loops > and declare context strings. I suppose those should be rare, and all > they need to do to prevent the problem is call error.context() at the top. > - A function can (and should) change its context string at runtime (for > example: before reboot, after reboot). If each function could only > declare a single context, we could just use the function's name and we > wouldn't need a context. OK, I am convinced about the general features of the API (one context per function call). Now, about the internal implementation: what about something to avoid using the stack trace tricks on context()? Basically what you need is something that adds a new "context entry" when a function is called and clear it once the function returns. What about a decorator tyat indicates "this function will push/pop a context when it is called/returns"? It looks much simpler than doing the tricks involving the stack on every context() call. e.g. I would find something like the following much easier to understand: CTX = threading.local() CTX.contexts = [] def context(s): """Change current context""" CTX.contexts[-1] = s def new_context(s): """Push new context in the stack""" CTX.contexts.append(s) def clear_context(): """Remove current context from the stack""" CTX.contexts.pop() def get_context(): return " --> ".join(CTX.contexts) def context_aware(fn): # quick solution. using decorator util functions to keep function metadata would be better def docall(*args, **kwargs): new_context("[%s function begin]" % (fn.__name__)) try: return fn(*args, **kwargs) finally: clear_context() return docall ### sample usage: @context_aware def a(): context("hello") b() context("world") print 'b:',get_context() # ----> 'world' @context_aware def b(): context("foo") c() @context_aware def c(): context("bar") print 'c:',get_context() # ----> 'hello --> foo --> bar' -- Eduardo -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html