|
|
 |
 |
 |
 |
Python Programming Language
|
 |
 |
 |
 |
 |
 |
 |
 |
Storing tracebacks
I'm reading the docs on sys.exc_info() but I can't tell for sure whether I'm using it safely to get a snapshot of an exception and reraise it later. The use case is a class which acts like a deferred callable, a callable that will be called at some point in the future (possibly in a different thread) and whose result or raised exception is to be stored as an attribute. This will be available by calling the result() method, which returns the original result or reraises the exception: class JobRequest(object): def __init__(self, *args, **kwds): self.args = args self.kwds = kwds self._exc_info = None def __call__(self): raise NotImplementedError('Abstract method') def process(self): try: self._result = self(*self.args, **self.kwds) except: self._exc_info = sys.exc_info() else: self._exc_info = None def result(self): if self._exc_info is not None: type,exception,traceback = self._exc_info raise type,exception,traceback try: return self._result except AttributeError: raise UnprocessedRequestError() class UnprocessedRequestError(RuntimeError): pass So far it seems it works as expected but I'd like to know if this is error-prone and why. George
On May 28, 10:46 pm, George Sakkis <george.sak@gmail.com> wrote:
> I'm reading the docs on sys.exc_info() but I can't tell for sure > whether I'm using it safely to get a snapshot of an exception and > reraise it later. The use case is a class which acts like a deferred > callable, a callable that will be called at some point in the future > (possibly in a different thread) and whose result or raised exception > is to be stored as an attribute. This will be available by calling the > result() method, which returns the original result or reraises the > exception: > class JobRequest(object): > def __init__(self, *args, **kwds): > self.args = args > self.kwds = kwds > self._exc_info = None > def __call__(self): > raise NotImplementedError('Abstract method') > def process(self): > try: > self._result = self(*self.args, **self.kwds) > except: > self._exc_info = sys.exc_info() > else: > self._exc_info = None > def result(self): > if self._exc_info is not None: > type,exception,traceback = self._exc_info > raise type,exception,traceback > try: return self._result > except AttributeError: > raise UnprocessedRequestError() > class UnprocessedRequestError(RuntimeError): > pass > So far it seems it works as expected but I'd like to know if this is > error-prone and why. > George
I don't know enough about this method of getting tracebacks, but why wouldn't the traceback module work for you? It sounds like it uses the sys.exc_info() method you refer to. http://python.active-venture.com/lib/module-traceback.html Mike
On May 29, 9:46 am, kyoso@gmail.com wrote:
> On May 28, 10:46 pm, George Sakkis <george.sak @gmail.com> wrote: > > I'm reading the docs on sys.exc_info() but I can't tell for sure > > whether I'm using it safely to get a snapshot of an exception and > > reraise it later. The use case is a class which acts like a deferred > > callable, a callable that will be called at some point in the future > > (possibly in a different thread) and whose result or raised exception > > is to be stored as an attribute. This will be available by calling the > > result() method, which returns the original result or reraises the > > exception: > > class JobRequest(object): > > def __init__(self, *args, **kwds): > > self.args = args > > self.kwds = kwds > > self._exc_info = None > > def __call__(self): > > raise NotImplementedError('Abstract method') > > def process(self): > > try: > > self._result = self(*self.args, **self.kwds) > > except: > > self._exc_info = sys.exc_info() > > else: > > self._exc_info = None > > def result(self): > > if self._exc_info is not None: > > type,exception,traceback = self._exc_info > > raise type,exception,traceback > > try: return self._result > > except AttributeError: > > raise UnprocessedRequestError() > > class UnprocessedRequestError(RuntimeError): > > pass > > So far it seems it works as expected but I'd like to know if this is > > error-prone and why. > > George > I don't know enough about this method of getting tracebacks, but why > wouldn't the traceback module work for you? It sounds like it uses the > sys.exc_info() method you refer to. > http://python.active-venture.com/lib/module-traceback.html
The traceback module is handy if you want a text representation of the traceback, not the actual traceback. The reason I want to store the actual traceback is to make the exception transparent to the user, i.e. not be able to tell whether the exception was thrown in the current stack frame or in another thread or even process. Unfortunately tracebacks are not pickleable, otherwise I could just pickle them in process() and unpickle them in result(). George
En Tue, 29 May 2007 13:51:09 -0300, George Sakkis <george.sak@gmail.com> escribi: > The traceback module is handy if you want a text representation of the > traceback, not the actual traceback. The reason I want to store the > actual traceback is to make the exception transparent to the user, > i.e. not be able to tell whether the exception was thrown in the > current stack frame or in another thread or even process. > Unfortunately tracebacks are not pickleable, otherwise I could just > pickle them in process() and unpickle them in result().
A traceback contains a linked list of frames, each with its own globals and locals and lot of context info. I'm not sure that moving a traceback across processes has any sense; a textual representation should be enough, as t.b. are usually a debugging aid and not supposed to reach the final user. -- Gabriel Genellina
On May 29, 1:21 pm, "Gabriel Genellina" <gagsl-@yahoo.com.ar> wrote:
> En Tue, 29 May 2007 13:51:09 -0300, George Sakkis > <george.sak @gmail.com> escribi: > > The traceback module is handy if you want a text representation of the > > traceback, not the actual traceback. The reason I want to store the > > actual traceback is to make the exception transparent to the user, > > i.e. not be able to tell whether the exception was thrown in the > > current stack frame or in another thread or even process. > > Unfortunately tracebacks are not pickleable, otherwise I could just > > pickle them in process() and unpickle them in result(). > A traceback contains a linked list of frames, each with its own globals > and locals and lot of context info. > I'm not sure that moving a traceback across processes has any sense; a > textual representation should be enough, as t.b. are usually a debugging > aid and not supposed to reach the final user.
The final user in this case is another programmer that uses a library, not some random guy using an application, so he certainly would be interested in seeing the traceback. I agree that the traceback is useful for debugging and the text representation would be enough if, for example, it was stored as an attribute in the Exception object and then used automatically by the runtime system (instead of calling sys.exc_info()). Of course nobody stops me from sticking traceback.format_tb() as an attribute in the Exception object and then have the client access it explicitly, something like: try: r = job.result() except Exception, ex: print ex.traceback The problem with this is that it's not transparent any more. The client must know that the originally raised object has been modified (or wrapped), sys.exc_info() doesn't work as expected, etc. It's not a show stopper by any means, but it would be convenient if there was a standardized optional "traceback" attribute that the runtime looks for and treats as the 3rd item of sys.exc_info() (otherwise it falls back to the current behavior). Would this be a reasonable feature request ? George
En Tue, 29 May 2007 15:13:33 -0300, George Sakkis <george.sak@gmail.com> escribi:
> On May 29, 1:21 pm, "Gabriel Genellina" <gagsl- @yahoo.com.ar> > wrote: >> A traceback contains a linked list of frames, each with its own globals >> and locals and lot of context info. >> I'm not sure that moving a traceback across processes has any sense; a >> textual representation should be enough, as t.b. are usually a debugging >> aid and not supposed to reach the final user. > The final user in this case is another programmer that uses a library, > not some random guy using an application, so he certainly would be > interested in seeing the traceback. I agree that the traceback is > useful for debugging and the text representation would be enough if, > for example, it was stored as an attribute in the Exception object and > then used automatically by the runtime system (instead of calling > sys.exc_info()). Of course nobody stops me from sticking > traceback.format_tb() as an attribute in the Exception object and then > have the client access it explicitly, something like: > try: r = job.result() > except Exception, ex: > print ex.traceback > The problem with this is that it's not transparent any more. The > client must know that the originally raised object has been modified > (or wrapped), sys.exc_info() doesn't work as expected, etc. It's not a > show stopper by any means, but it would be convenient if there was a > standardized optional "traceback" attribute that the runtime looks for > and treats as the 3rd item of sys.exc_info() (otherwise it falls back > to the current behavior). Would this be a reasonable feature request ?
Already requested - see PEP 344 and 3110 for changes on exception handling and tracebacks (in Python 3.0 at least; I'm unsure of the PEP344 status on the 2.X series) -- Gabriel Genellina
|
 |
 |
 |
 |
|