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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html