Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

change an exception's message and re-raise it

2 views
Skip to first unread message

Phlip

unread,
Dec 31, 2009, 3:18:42 PM12/31/09
to
Pythonistas:

I need to do this:

try:
deep_arcane_layer()
except e:
e.message = 'the deep arcane layer says: ' + e.message
raise e

The point is I need to augment that layer's exceptions with extra
information that I know about that layer.

I naturally cannot use the argless version of 'raise', because it only
re-raises whatever exception object is currently in play - and it
appears to be read-only or locked or something.

I also should not do this...

raise Exception('blah ' + e.message)

...because that stripped off the exception type itself, and higher
layers need to know this.

My question is a common pattern in layered architectures, where
exceptions get decorated with extra info as they bubble up from the
engine room to the bridge. Any ideas?

--
Phlip
http://zeekland.zeroplayer.com/The_Elaborate_Art_of_Play_Part_1/1

Cameron Simpson

unread,
Dec 31, 2009, 4:59:38 PM12/31/09
to Phlip, pytho...@python.org
On 31Dec2009 12:18, Phlip <phli...@gmail.com> wrote:
| Pythonistas:
|
| I need to do this:
|
| try:
| deep_arcane_layer()
| except e:
| e.message = 'the deep arcane layer says: ' + e.message
| raise e
|
| The point is I need to augment that layer's exceptions with extra
| information that I know about that layer.

Doesn't the above work (modulo changing the right exception attributes)?

I've got a context manager that does something like this.
It is hampered by the fact that not all exceptions have the same
internal structure, for historic reasons I believe.

So I've got this ugly stuff in the __exit__ method:

if exc_value is not None:
if hasattr(exc_value, 'args') and len(exc_value.args) > 0:
exc_value.args = [pfx + ": " + str(exc_value.args[0])] \
+ list(exc_value.args[1:])
else:
# we can't modify this - at least report the current prefix
# state
sys.stderr.write("%s: Pfx.__exit__: exc_value = %s\n" % (pfx,
repr(exc_value),))

You can see I modify the .args value.
The method returns False to let the exception percolate back out
the stack.

The "else" part is to handle exceptions I can't change, so for now I've
just printing the "pfx" context on stderr as the exception bubbles out.
Nasty.

The calling code looks like this:

with Pfx("some tag"):
... suite ...

Cheers,
--
Cameron Simpson <c...@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/

There is this special biologist word we use for 'stable'. It is 'dead'.
- Jack Cohen

Steven D'Aprano

unread,
Dec 31, 2009, 7:30:32 PM12/31/09
to
On Thu, 31 Dec 2009 12:18:42 -0800, Phlip wrote:

> Pythonistas:
>
> I need to do this:
>
> try:
> deep_arcane_layer()
> except e:
> e.message = 'the deep arcane layer says: ' + e.message
> raise e

Use e.args, not e.message. The message attribute is deprecated from
Python 2.6 and will print a warning if you try to use it.


> The point is I need to augment that layer's exceptions with extra
> information that I know about that layer.
>
> I naturally cannot use the argless version of 'raise', because it only
> re-raises whatever exception object is currently in play - and it
> appears to be read-only or locked or something.

Changing args works:


>>> try:
... 1/0
... except ZeroDivisionError, e:
... e.args = e.args + ('fe', 'fi', 'fo', 'fum')
... raise
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: ('integer division or modulo by zero', 'fe', 'fi',
'fo', 'fum')


> I also should not do this...
>
> raise Exception('blah ' + e.message)
>
> ...because that stripped off the exception type itself, and higher
> layers need to know this.

For the record you can get the exception type from type(e):

raise type(e)("whatever you want")

but that creates a new exception, not re-raising the old one.


--
Steven

Alan G Isaac

unread,
Dec 31, 2009, 11:20:09 PM12/31/09
to
On 12/31/2009 7:30 PM, Steven D'Aprano wrote:
> The message attribute is deprecated from
> Python 2.6 and will print a warning if you try to use it.


http://bugs.python.org/issue6844

fwiw,
Alan Isaac

Phlip

unread,
Jan 1, 2010, 10:10:51 AM1/1/10
to
On Dec 31 2009, 4:30 pm, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.au> wrote:

> ...     1/0
> ... except ZeroDivisionError, e:
> ...     e.args = e.args + ('fe', 'fi', 'fo', 'fum')
> ...     raise

When I added print e.args it showed the old args. Maybe I was trying
too hard - this is why I said e seemed locked or something.

This started working:

new_exception = self.format_fault(e.args[0])
e.args = (new_exception,) + (e.args[1:])
raise

May I ask if args always has more than one entry? I need to bypass the
silly "'tuple' object does not support item assignment" issue...

Phlip

unread,
Jan 1, 2010, 10:21:13 AM1/1/10
to
On Dec 31 2009, 4:30 pm, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.au> wrote:

> For the record you can get the exception type from type(e):
>
> raise type(e)("whatever you want")
>
> but that creates a new exception, not re-raising the old one.

Except if a type constructs with some other number of arguments,
apparently...

0 new messages