473,805 Members | 2,027 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Re-raising exceptions with modified message

What is the best way to re-raise any exception with a message
supplemented with additional information (e.g. line number in a
template)? Let's say for simplicity I just want to add "sorry" to every
exception message. My naive solution was this:

try:
...
except Exception, e:
raise e.__class__, str(e) + ", sorry!"

This works pretty well for most exceptions, e.g.
>>try:
.... 1/0
.... except Exception, e:
.... raise e.__class__, str(e) + ", sorry!"
....
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ZeroDivisionErr or: integer division or modulo by zero, sorry!

But it fails for some exceptions that cannot be instantiated with a
single string argument, like UnicodeDecodeEr ror which gets "converted"
to a TypeError:
>>try:
.... unicode('\xe4')
.... except Exception, e:
.... raise e.__class__, str(e) + ", sorry!"
....
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
TypeError: function takes exactly 5 arguments (1 given)

Another approach is using a wrapper Extension class:

class SorryEx(Excepti on):
def __init__(self, e):
self._e = e
def __getattr__(sel f, name):
return getattr(self._e , name)
def __str__(self):
return str(self._e) + ", sorry!"

try:
unicode('\xe4')
except Exception, e:
raise SorryEx(e)

But then I get the name of the wrapper class in the message:

__main__.SorryE x: 'ascii' codec can't decode byte 0xe4 in position 0:
ordinal not in range(128), sorry!

Yet another approach would be to replace the __str__ method of e, but
this does not work for new style Exceptions (Python 2.5).

Any suggestions?

-- Chris
Jul 5 '07
28 5900
On Jul 12, 11:48 am, samwyse <samw...@gmail. comwrote:
On Jul 12, 6:31 am,samwyse<samw ...@gmail.comwr ote:
On Jul 8, 8:50 am, Christoph Zwerschke <c...@online.de wrote:
With Py 2.5 I get:
new.__class__ = old.__class__
TypeError: __class__ must be set to a class

Hmmm, under Python 2.4.X, printing repr(old.__clas s__) gives me this:
<class exceptions.Unic odeDecodeError at 0x00A24F00>
while under 2.5.X, I get this:
<type 'exceptions.Uni codeDecodeError '>

So, let's try sub-classing the type:

def modify_message( old, f):
class Empty: pass
new = Empty()
print "old.__clas s__ =", repr(old.__clas s__)
print "Empty =", repr(Empty)
new.__class__ = Empty

class Excpt(old.__cla ss__): pass
print "Excpt =", repr(Excpt)
print "Excpt.__class_ _ =", repr(Excpt.__cl ass__)
new.__class__ = Excpt

new.__dict__ = old.__dict__.co py()
new.__str__ = f
return new

Nope, that gives us the same message:

old.__class__ = <type 'exceptions.Uni codeDecodeError '>
Empty = <class __main__.Empty at 0x00AB0AB0>
Excpt = <class '__main__.Excpt '>
Excpt.__class__ = <type 'type'>
Traceback (most recent call last):
[...]
TypeError: __class__ must be set to a class

Excpt certainly appears to be a class. Does anyone smarter than me
know what's going on here?
OK, in classobject.h, we find this:

#define PyClass_Check(o p) ((op)->ob_type == &PyClass_Typ e)

That seems straightforward enough. And the relevant message appears
in classobject.c here:

static int
instance_setatt r(PyInstanceObj ect *inst, PyObject *name, PyObject *v)
[...]
if (strcmp(sname, "__class__" ) == 0) {
if (v == NULL || !PyClass_Check( v)) {
PyErr_SetString (PyExc_TypeErro r,
"__class__ must be set to a class");
return -1;
}

Back in our test code, we got these:
Empty = <class __main__.Empty at 0x00AB0AB0>
Excpt = <class '__main__.Excpt '>
The first class (Empty) passes the PyClass_Check macro, the second one
(Excpt) evidently fails. I'll need to dig deeper. Meanwhile, I still
have to wonder why the code doesn't allow __class_ to be assigned a
type instead of a class. Why can't we do this in the C code (assuming
the appropriate PyType_Check macro):

if (v == NULL || !(PyClass_Check (v) || PyType_Check(v) )) {

Jul 13 '07 #21
(Yes, I probably should have said CPython in my subject, not Python.
Sorry.)

On Jul 13, 12:56 am, samwyse <samw...@gmail. comwrote:
OK, in classobject.h, we find this:

#define PyClass_Check(o p) ((op)->ob_type == &PyClass_Typ e)

That seems straightforward enough. And the relevant message appears
in classobject.c here:

static int
instance_setatt r(PyInstanceObj ect *inst, PyObject *name, PyObject *v)
[...]
if (strcmp(sname, "__class__" ) == 0) {
if (v == NULL || !PyClass_Check( v)) {
PyErr_SetString (PyExc_TypeErro r,
"__class__ must be set to a class");
return -1;
}

Back in our test code, we got these:
Empty = <class __main__.Empty at 0x00AB0AB0>
Excpt = <class '__main__.Excpt '>

The first class (Empty) passes the PyClass_Check macro, the second one
(Excpt) evidently fails. I'll need to dig deeper. Meanwhile, I still
have to wonder why the code doesn't allow __class_ to be assigned a
type instead of a class. Why can't we do this in the C code (assuming
the appropriate PyType_Check macro):

if (v == NULL || !(PyClass_Check (v) || PyType_Check(v) )) {
After a good night's sleep, I can see that Empty is a "real" class;
i.e. its repr() is handled by class_repr() in classobject.c. Excpt,
on the other hand, is a type; i.e. its repr is handled by type_repr()
in typeobject.c. (You can tell because class_repr() returns a value
formatted as "<class %s.%s at %p>" whereas type_repr returns a value
formatted as "<%s '%s.%s'>", where the first %s gets filled with
either "type" or "class".)

This is looking more and more like a failure to abide by PEP 252/253.
I think that the patch is simple, but I'm unusre of the
ramifications. I also haven't looked at the 2.4 source to see how
things used to work. Still, I think that I've got a work-around for
OP's problem, I just need to test it under both 2.4 and 2.5.

Jul 13 '07 #22
On Jul 13, 12:45 am, Christoph Zwerschke <c...@online.de wrote:
samwyse wrote:
TypeError: __class__ must be set to a class
Excpt ceratinly appears to be a class. Does anyone smarter than me
know what's going on here?

Not that I want to appear smarter, but I think the problem here is that
exceptions are new-style classes now, whereas Empty is an old-style
class. But even if you define Empty as a new-style class, it will not
work, you get:

TypeError: __class__ assignment: only for heap types

This tells us that we cannot change the attributes of a built-in
exception. If it would be possible, I simply would have overridden the
__str__ method of the original exception in the first place.

-- Chris
Chris, you owe me a beer if you're ever in St. Louis, or I'm ever in
Germany.

# ----- CUT HERE -----

# Written by Sam Denton <sa*****@gmail. com>
# You may use, copy, or distribute this work,
# as long as you give credit to the original author.

# tested successfully under Python 2.4.1, 2.4.3, 2.5.1

"""
On Jul 5, 2007, at 8:53 am, Christoph Zwerschke <c...@online.de >
wrote:
What is the best way to re-raise any exception with a message
supplemented with additional information (e.g. line number in a
template)? Let's say for simplicity I just want to add "sorry" to
every exception message.
Here is an example of typical usage:
>>def typical_usage(c ode):
.... try:
.... code()
.... except Exception, e:
.... simplicity = lambda self: str(e) + ", sorry!"
.... raise modify_message( e, simplicity)

Note that if we want to re-cycle the original exception's message,
then we need our re-formatter (here called 'simplicity') to be
defined inside the exception handler. I tried verious approaches
to defining the re-formater, but all of them eventually needed a
closure; I decided that I liked this approach best.

This harness wraps the example so that doctest doesn't get upset.
>>def test_harness(co de):
.... try:
.... typical_usage(c ode)
.... except Exception, e:
.... print "%s: %s" % (e.__class__.__ name__, str(e))

Now for some test cases:
>>test_harness( lambda: 1/0)
ZeroDivisionErr or: integer division or modulo by zero, sorry!
>>test_harness( lambda: unicode('\xe4') )
UnicodeDecodeEr ror: 'ascii' codec can't decode byte 0xe4 in position
0: ordinal not in range(128), sorry!

"""

def modify_message( old, f):
"""modify_messa ge(exception, mutator) --exception

Modifies the string representation of an exception.
"""
class NewStyle(old.__ class__):
def __init__(self): pass
NewStyle.__name __ = old.__class__._ _name__
NewStyle.__str_ _ = f
new = NewStyle()
new.__dict__ = old.__dict__.co py()
return new

def _test():
import doctest
return doctest.testmod (verbose=True)

if __name__ == "__main__":
_test()

Jul 13 '07 #23
samwyse wrote:
NewStyle.__name __ = old.__class__._ _name__
Simple, but that does the trick!
new.__dict__ = old.__dict__.co py()
Unfortunately, that does not work, since the attributes are not
writeable and thus do not appear in __dict__.

But my __getattr__ solution does not work either, since the attributes
are set to None when initialized, so __getattr__ is never called.

Need to think about this point some more...

Anyway, the beer is on me ;-)

-- Chris
Jul 15 '07 #24
Christoph Zwerschke wrote:
But my __getattr__ solution does not work either, since the attributes
are set to None when initialized, so __getattr__ is never called.
Here is a simple solution, but it depends on the existence of the args
attribute that "will eventually be deprecated" according to the docs:

def PoliteException (e):
E = e.__class__
class PoliteException (E):
def __str__(self):
return str(e) + ", sorry!"
PoliteException .__name__ = E.__name__
return PoliteException (*e.args)

try:
unicode('\xe4')
except Exception, e:
p = PoliteException (e)
assert p.reason == e.reason
raise p
Jul 15 '07 #25
Christoph Zwerschke wrote:
Here is a simple solution, but it depends on the existence of the args
attribute that "will eventually be deprecated" according to the docs:
Ok, here is another solution that does not depend on args:

def PoliteException (e):
E = e.__class__
class PoliteException (E):
def __init__(self):
for arg in dir(e):
if not arg.startswith( '_'):
setattr(self, arg, getattr(e, arg))
def __str__(self):
return str(e) + ", sorry!"
PoliteException .__name__ = E.__name__
return PoliteException ()

try:
unicode('\xe4')
except Exception, e:
p = PoliteException (e)
assert p.reason == e.reason
raise p
Jul 15 '07 #26
Christoph Zwerschke wrote:
Here is a simple solution, but it depends on the existence of the args
attribute that "will eventually be deprecated" according to the docs:
Just found another amazingly simple solution that does neither use teh
..args (docs: "will eventually be deprecated") attribute nor the dir()
function (docs: "its detailed behavior may change across releases").
Instead it relies on the fact that the exception itselfs behaves like
its args tuple (checked with Py 2.3, 2.4 and 2.5).

As another twist, I set the wrapper exception module to the module of
the original exception so that the output looks more like the output of
the original exception (i.e. simply "UnicodeDecodeE rror" instead of
"__main__.Unico deDecodeError") .

The code now looks like this:

def PoliteException (e):
E = e.__class__
class PoliteException (E):
def __str__(self):
return str(e) + ", sorry!"
PoliteException .__name__ = E.__name__
PoliteException .__module__ = E.__module__
return PoliteException (*e)

try:
unicode('\xe4')
except Exception, e:
p = PoliteException (e)
assert p.reason == e.reason
raise p
Jul 15 '07 #27
On Jul 15, 2:55 am, Christoph Zwerschke <c...@online.de wrote:
Here is a simple solution, but it depends
on the existence of the args attribute that
"will eventually be deprecated" according
to the docs
If you don't mind using .args, then the solution is usually as simple
as:
try:
Thing.do(arg1, arg2)
except Exception, e:
e.args += (Thing.state, arg1, arg2)
raise
No over-engineering needed. ;)
Robert Brewer
System Architect
Amor Ministries
fu******@amor.o rg

Jul 16 '07 #28
En Mon, 16 Jul 2007 13:50:50 -0300, fumanchu <fu******@amor. orgescribió:
On Jul 15, 2:55 am, Christoph Zwerschke <c...@online.de wrote:
>Here is a simple solution, but it depends
on the existence of the args attribute that
"will eventually be deprecated" according
to the docs

If you don't mind using .args, then the solution is usually as simple
as:
try:
Thing.do(arg1, arg2)
except Exception, e:
e.args += (Thing.state, arg1, arg2)
raise
No over-engineering needed. ;)
If you read enough of this long thread, you'll see that the original
requirement was to enhance the *message* displayed by a normal traceback -
the OP has no control over the callers, but wants to add useful
information to any exception.
Your code does not qualify:

pytry:
.... open("a file that does not exist")
.... except Exception,e:
.... e.args += ("Sorry",)
.... raise
....
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IOError: [Errno 2] No such file or directory: 'a file that does not exist'
pytry:
.... x = u"á".encode("as cii")
.... except Exception,e:
.... e.args += ("Sorry",)
.... raise
....
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
UnicodeEncodeEr ror: 'ascii' codec can't encode character u'\xe1' in
position 0:
ordinal not in range(128)

--
Gabriel Genellina

Jul 16 '07 #29

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
4325
by: Nel | last post by:
I have a question related to the "security" issues posed by Globals ON. It is good programming technique IMO to initialise variables, even if it's just $foo = 0; $bar = ""; Surely it would be better to promote better programming than rely on PHP to compensate for lazy programming?
4
6431
by: Craig Bailey | last post by:
Anyone recommend a good script editor for Mac OS X? Just finished a 4-day PHP class in front of a Windows machine, and liked the editor we used. Don't recall the name, but it gave line numbers as well as some color coding, etc. Having trouble finding the same in an editor that'll run on OS X. -- Floydian Slip(tm) - "Broadcasting from the dark side of the moon"
1
4102
by: Chris | last post by:
Sorry to post so much code all at once but I'm banging my head against the wall trying to get this to work! Does anyone have any idea where I'm going wrong? Thanks in advance and sorry again for adding so much code... <TABLE border="1" bordercolor="#000000" cellspacing="0"> <TR>
11
4016
by: James | last post by:
My form and results are on one page. If I use : if ($Company) { $query = "Select Company, Contact From tblworking Where ID = $Company Order By Company ASC"; }
4
18544
by: Alan Walkington | last post by:
Folks: How can I get an /exec'ed/ process to run in the background on an XP box? I have a monitor-like process which I am starting as 'exec("something.exe");' and, of course the exec function blocks until something.exe terminates. Just what I /don't/ want. (Wouldn't an & be nice here! Sigh) I need something.exe to disconnect and run in the background while I
1
3706
by: John Ryan | last post by:
What PHP code would I use to check if submitted sites to my directory actually exist?? I want to use something that can return the server code to me, ie HTTP 300 OK, or whatever. Can I do this with sockets??
10
4228
by: James | last post by:
What is the best method for creating a Web Page that uses both PHP and HTML ? <HTML> BLA BLA BLA BLA BLA
8
3662
by: Lothar Scholz | last post by:
Because PHP5 does not include the mysql extension any more is there a chance that we will see more Providers offering webspace with Firebird or Postgres Databases ? What is your opinion ? I must say that i like it to see mysql replaced by a real database (stored procedures etc.)
1
3641
by: joost | last post by:
Hello, I'm kind of new to mySQL but more used to Sybase/PHP What is illegal about this query or can i not use combined query's in mySQL? DELETE FROM manufacturers WHERE manufacturers_id NOT IN ( SELECT manufacturers_id FROM products )
2
106621
by: sky2070 | last post by:
i have two file with jobapp.html calling jobapp_action.php <HTML> <!-- jobapp.html --> <BODY> <H1>Phop's Bicycles Job Application</H1> <P>Are you looking for an exciting career in the world of cyclery? Look no further! </P> <FORM NAME='frmJobApp' METHOD=post ACTION="jobapp_action.php"> Please enter your name:
0
9716
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9596
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10604
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10356
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10361
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
7644
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5536
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5676
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3839
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.