How to manipulate exception in __exit__ context manager?

I know this is a bad style to re-create an exception from the __exit__() context manager. Thus, I would like to apply an attribute to an instance that can carry contextual information that is not available if I allow the exception to leak or if I catch it. This will avoid raising it again.

An alternative to attaching an attribute to an exception would be to swallow the exception, set some state in the instance, which doubles as the context manager in question, and then check that state. The problem is that this will result in a catch of 22, right? Since an exception means that execution inside the with block completes. It is not possible to repeat the operation except re-entering the with block, right? Thus, the instance in which I am trying to save contextual information will disappear after the __exit__() method __exit__() .

In short: how can I manipulate the actual exception that expects (if any, which I will consider asked for this question), while in the __exit__() method?

+7
python contextmanager
source share
1 answer

The context manager does not exit just because it exits the block. You can save it in two ways:

  • First create a context manager, assign it to a variable, then use with with this object:

     cm = ContextManager() with cm: # .... state = cm.attribute 
  • Return the context manager itself from the __enter__ method, use with ... as ... to bind it to the local name. This name is not disabled when with completes:

     with ContextManager as cm: # .... state = cm.attribute 

    where ContextManager.__enter__ uses return self .

You can also set additional attributes for the exception itself; no need to re-raise the exception:

 >>> class ContextManager(object): ... def __enter__(self): ... return self ... def __exit__(self, tp, v, tb): ... if tp is None: return ... v.extra_attribute = 'foobar' ... self.other_extra_attribute = 'spam-n-ham' ... >>> try: ... with ContextManager() as cm: ... raise ValueError('barfoo') ... except ValueError as ex: ... print vars(ex) ... {'extra_attribute': 'foobar'} >>> vars(cm) {'other_extra_attribute': 'spam-n-ham'} 

Here the exception provided an additional attribute that persisted until the exception handler. In the above example, I also show that cm is still bound to the context manager.

+6
source share

All Articles