Thanks Steve, I appreciate your patience.
On Jan 31, 1:39 am, Steven D'Aprano <s...@REMOVEME.cybersource.com.au>
wrote:
If the built-in isn't Unicode aware, subclassing it won't magically make
it so :-)
Oh, I agree. If I have a string mesg that is unicode-not-ascii and I
say
try:
raise Exception mesg
except Exception, err:
print "Trouble"+mesg
then I have problems. I however am under the impression, perhaps
mistaken, that the built-in exceptions in the library will return as
error strings only ascii. (I take as evidence of my understanding
that the built-in exceptions have a __str__() method but do not have
an explicit __unicode__() and so rely on a unicode(err) call being
passed on to __str__(). But as I've said above, I've been wrong so
many times before. ;-)
My main point about the built-ins is that I want to catch them along
with my own exceptions. That's what I meant by the next paragraph.
My class myException is a subclass of Exception so I can catch my
stuff and the standard stuff with an all-in-one panic button.
>
For instance, I write a lot of CGI and I want to wrap everything in a
try .. except.
try:
main()
except Exception, err:
print "Terrible blunder: ",str(err)
so that the err can be one of my exceptions, or can be one that came
with Python.
(And, that I can see, err.args can be either the relevant
string or a tuple containing the relevant string and the documentation
is silent on whether in the built-in exceptions if err.args is a tuple
then the string is guaranteed to be first in the tuple.)
Does it matter? Just print the tuple.
In truth, it does matter. In that example, for instance, some error
message is passed on to the user and I don't want it to be too bad.
"Database cannot be opened" is better than a "(u'Database cannot be
opened,1)"-type thing. Besides which, Python is a nice language, and
I'm certain there is a nice way to do this; it is just that I'm having
trouble making it out.
(2) convert the file name to ASCII before you store it; or
I need the non-ascii information, though, which is why I included it
in the error message.
If you have the exception captured in "err", then you can grab it with
err.where_i_put_the_unicode.
I want a method of grabbing it that is the same as the method used by
the built-ins, for the uniformity reasons that I gave above. That I
could make out, the documentation was silent on what is the approved
way to grab the string.
(3) add a __str__ method to your exception that is Unicode aware.
I have two difficulties with this: (1) as above I often raise Python's
built-in exceptions and for those __str__() is what it is, and
Then don't use the built-in exception. If it won't do what you want it do
do, use something else.
I use my exceptions for errors in my logic, etc. But not being
perfect, sometimes I raise exceptions that I had not anticipated;
these are built-ins.
(2) this
goes against the meaning of __str__() that I find in the documentation
in ref/customization.html which says that the return value must be a
string object.
I didn't mean return a unicode object :)
You're absolutely correct. Your __str__ would need to return a string
object, which means encoding the Unicode correctly to get a string object
without raising an exception.
e.g. something like this maybe (untested, not thought-through, probably
won't work correctly, blah blah blah):
def __str__(self):
s = self.args.encode('ascii', 'replace')
return "Unicode error converted to plain ASCII:\n" + s
or whatever encoding scheme works for your application.
I did discuss this suggestion from another person above. That would
mean either (a) throwing away the unicode-not-ascii parts of the error
message (but I want those parts, which is why I put them in there) or
(b) hard-coding the output encoding for error strings in hundreds of
error cases (yes, I have hundreds) or (c) passing as a parameter the
errorEncoding to each function that I write. That last case doesn't
seem to be to be a likely best practice for such a nice language as
Python; I want a way to get the unicode object and go forward in the
program with that.
It can take whatever you want it to take:
class MyStupidException(Exception):
def __init__(self, dayofweek, breakfast="spam and baked beans",
*everythingelse):
self.day = dayofweek
self.breakfast = breakfast
self.args = everythingelse
def __str__(self):
s = "On %s I ate %s and then an error '%s' occurred." % \
(self.day.title(), self.breakfast, self.args)
return s
>raise MyStupidException('monday', 'cheese', 'bad things', 'happened', 2)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
__main__.MyStupidException: On Monday I ate cheese and then an error
'('bad things', 'happened', 2)' occurred.
Thank you for the example; I learned something from it. But as I
mentioned above, I need to guard against the system raising built-ins
also and so I am still a bit puzzled by how to get at the error
strings in built-ins.
In case anyone is still reading this :-) someone else suggested the
err.message attribute. I had missed that in the documentation
somehow, but on rereading it, I thought he had solved my problem.
However, sadly, I cannot get Python to like a call to err.message:
.................................................. .........
$ python
Python 2.4.4c1 (#2, Oct 11 2006, 21:51:02)
[GCC 4.1.2 20060928 (prerelease) (Ubuntu 4.1.1-13ubuntu5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>try:
.... raise Exception, 'this is the error message'
.... except Exception, err:
.... print "result: ",err.message
....
result:
Traceback (most recent call last):
File "<stdin>", line 4, in ?
AttributeError: Exception instance has no attribute 'message'
>>>
.................................................. .....................................
So, in case it helps anyone, I am going with this:
.................................................. ....................................
def errorValue(err):
"""Return the string error message from an exception message
string.
err exception instance
Note: I cannot get err.message to work. I sent a note to clp on
Jan 29 2007 with a related query and this is the best that I
figured
out.
"""
return err[0]
class jhError(StandardError):
"""Subclass this to get exceptions that behave correctly when
you do this.
try:
raise subclassOfJhError, 'some error message with unicode
chars'
except subclassOfJhError, err
mesg='the message is '+unicode(err)
"""
def __unicode__(self):
return errorValue(self)
class myException(jhError):
pass
.................................................. ...................................
No doubt I'll discover what is wrong with it today. :-)
Jim