Re: Re-raising exceptions with modified message

2007-07-16 Thread fumanchu
On Jul 15, 2:55 am, Christoph Zwerschke [EMAIL PROTECTED] 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
[EMAIL PROTECTED]

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-16 Thread Gabriel Genellina
En Mon, 16 Jul 2007 13:50:50 -0300, fumanchu [EMAIL PROTECTED] escribiĆ³:

 On Jul 15, 2:55 am, Christoph Zwerschke [EMAIL PROTECTED] 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:

py try:
...   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'
py try:
...   x = uĆ”.encode(ascii)
... except Exception,e:
...   e.args += (Sorry,)
...   raise
...
Traceback (most recent call last):
   File stdin, line 2, in module
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in  
position 0:
ordinal not in range(128)

-- 
Gabriel Genellina

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-15 Thread Christoph Zwerschke
samwyse wrote:
  NewStyle.__name__ = old.__class__.__name__

Simple, but that does the trick!

  new.__dict__ = old.__dict__.copy()

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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-15 Thread Christoph Zwerschke
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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-15 Thread Christoph Zwerschke
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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-15 Thread Christoph Zwerschke
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 UnicodeDecodeError instead of 
__main__.UnicodeDecodeError).

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
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-13 Thread samwyse
On Jul 13, 12:45 am, Christoph Zwerschke [EMAIL PROTECTED] 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 [EMAIL PROTECTED]
# 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 [EMAIL PROTECTED]
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(code):
... 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(code):
... try:
... typical_usage(code)
... except Exception, e:
... print %s: %s % (e.__class__.__name__, str(e))

Now for some test cases:

 test_harness(lambda: 1/0)
ZeroDivisionError: integer division or modulo by zero, sorry!

 test_harness(lambda: unicode('\xe4'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position
0: ordinal not in range(128), sorry!



def modify_message(old, f):
modify_message(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__.copy()
return new

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

if __name__ == __main__:
_test()

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-12 Thread samwyse
On Jul 8, 8:50 am, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Did you run this?
 With Py  2.5 I get a syntax error, and with Py 2.5 I get:

  new.__class__ = old.__class__
 TypeError: __class__ must be set to a class

 -- Chris

Damn, I'd have sworn I ran the final copy that I posted, but
apparently I did manage to have a typo creep in as I was prettifying
the code.  You need to lose the '()' in the definition of Empty.  (I'd
orignally had it subclass Exception but discovered that it wasn't
needed.)

class Empty: pass

I can't figure out the other complaint, though, as old.__class_ should
be a class.  I guess I need to upgrade; I am using PythonWin 2.4.3
(#69, Apr 11 2006, 15:32:42) [MSC v.1310 32 bit (Intel)] on win32.
(Of course, at work they're still stuck on 2.4.2.)  Printing
type(old.__class__) gives me type 'classobj'; maybe using
setattr(new, '__class__', old.__class__)
instead of the assignment would work, or maybe it's a bug/feature
introduced in 2.5.  (Trying this code:
class Empty(old.__class__): pass
brings us back to the TypeError: function takes exactly 5 arguments
(0 given) message that we're trying to avoid.)


Anyway, running the corrected version under 2.4.X gives me this:

Traceback (most recent call last):
  File C:\Python24\Lib\site-packages\pythonwin\pywin\framework
\scriptutils.py, line 310, in RunScript
exec codeObject in __main__.__dict__
  File C:\Documents and Settings\dentos\Desktop\scripting
\modify_message.py, line 19, in ?
test(lambda: unicode('\xe4'))
  File C:\Documents and Settings\dentos\Desktop\scripting
\modify_message.py, line 16, in test
raise modify_message(e, lambda: str(e) + , sorry!)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position
0: ordinal not in range(128), sorry!


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-12 Thread samwyse
On Jul 12, 6:31 am, samwyse [EMAIL PROTECTED] wrote:
 On Jul 8, 8:50 am, Christoph Zwerschke [EMAIL PROTECTED] 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.__class__) gives me this:
  class exceptions.UnicodeDecodeError at 0x00A24F00
while under 2.5.X, I get this:
  type 'exceptions.UnicodeDecodeError'


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

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

class Excpt(old.__class__): pass
print Excpt =, repr(Excpt)
print Excpt.__class__ =, repr(Excpt.__class__)
new.__class__ = Excpt

new.__dict__ = old.__dict__.copy()
new.__str__ = f
return new

Nope, that gives us the same message:

old.__class__ = type 'exceptions.UnicodeDecodeError'
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 ceratinly appears to be a class.  Does anyone smarter than me
know what's going on here?

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-12 Thread Christoph Zwerschke
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


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-08 Thread Christoph Zwerschke
Did you run this?
With Py  2.5 I get a syntax error, and with Py 2.5 I get:

 new.__class__ = old.__class__
TypeError: __class__ must be set to a class

-- Chris
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-08 Thread Christoph Zwerschke
samwyse wrote:
 def test(code):
   try:
 code()
   except Exception, e:
 try:
   raise e.__class__, str(e) + , sorry!
 except TypeError:
   raise SorryFactory(e)()

Ok, you're suggestig the naive approach if it works and the factory 
approach I came up with last as a fallback. Maybe a suitable compromize.

-- Chris
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-07 Thread Christoph Zwerschke
Gerard Flanagan wrote:
 Would a decorator work here?

Depends on how you want to use that functionality. In my use case I only 
need to catch the excpetion once.

Note that in your code the exception has not the right type which is 
what I targeted in my last posting. I.e. the following will raise an 
Exception if function is decorated:

try:
 print funktion()
except ArithmeticError:
 pass

-- Chris
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-07 Thread samwyse
On Jul 5, 8:53 am, Christoph Zwerschke [EMAIL PROTECTED] 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. 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
 ZeroDivisionError: integer division or modulo by zero, sorry!

 But it fails for some exceptions that cannot be instantiated with a
 single string argument, like UnicodeDecodeError 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(Exception):
  def __init__(self, e):
  self._e = e
  def __getattr__(self, 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__.SorryEx: '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

Can try statements be used in except clauses?  It appears so, thus
a hybrid approach might work well enough.

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

That leaves the issue of the name being changed for
UnicodeDecodeError, which might be fixable by diddling with __name__
properties.  Or perhaps SorryEx needs to be a factory that returns
exception classes; the last line would be SorryEx(e)().  I'll have
to play with this a bit.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-07 Thread samwyse
On Jul 7, 4:13 pm, samwyse [EMAIL PROTECTED] wrote:
 On Jul 5, 8:53 am, Christoph Zwerschke [EMAIL PROTECTED] 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)?
[...]
 That leaves the issue of the name being changed for
 UnicodeDecodeError, which might be fixable by diddling with __name__
 properties.  Or perhaps SorryEx needs to be a factory that returns
 exception classes; the last line would be SorryEx(e)().  I'll have
 to play with this a bit.

OK, the following mostly works.  You probably want the factory to copy
more of the original class into the SorryEx class each time, since
someone catching an exception may expect to look at things besides its
string representation.

def SorryFactory(e):
class SorryEx(Exception):
def __init__(self):
self._e = e
def __getattr__(self, name):
return getattr(self._e, name)
def __str__(self):
return str(self._e) + , sorry!
SorryEx.__name__ = e.__class__.__name__
return SorryEx

def test(code):
  try:
code()
  except Exception, e:
try:
  raise e.__class__, str(e) + , sorry!
except TypeError:
  raise SorryFactory(e)()

test(lambda: unicode('\xe4'))


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-07 Thread samwyse
On Jul 5, 8:53 am, Christoph Zwerschke [EMAIL PROTECTED] 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.

OK, this seems pretty minimal, yet versatile.   It would be nice to be
able to patch the traceback, but it turns out that it's fairly hard to
do. If you really want to do that, however, go take a look at
http://lucumr.pocoo.org/cogitations/2007/06/16/patching-python-tracebacks-part-two/


# Written by Sam Denton [EMAIL PROTECTED]
# You may use, copy, or distribute this work,
# as long as you give credit to the original author.
def rewriten_exception(old, f):
class Empty(): pass
new = Empty()
new.__class__ = old.__class__
new.__dict__ = old.__dict__.copy()
new.__str__ = f
return new

def test(code):
try:
code()
except Exception, e:
raise rewriten_exception(e, lambda: str(e) + , sorry!)

test(lambda: unicode('\xe4'))
test(lambda: 1/0)

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-06 Thread Alex Popescu
On Jul 6, 4:20 am, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Alex Popescu wrote:


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-06 Thread Alex Popescu
On Jul 6, 4:20 am, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Alex Popescu wrote:
  Probably the simplest solution would be to create a new exception and
  wrapping the old one and the additional info. Unfortunately, this
  may have a huge impact on 3rd party code that was catching the
  original exception. So, I think you should create an utility
  factory-like function that is either creating a new exception
  instance as the one caught and with the additional information,

 Right, I have gone with that (see the example with the PoliteException
 class somewhere below).

  or an utility that knows how to modify the caught exception according
  to its type.

 I guess you mean something like this (simplified):

 except Exception, e:
  if getattr(e, 'reason'):
  e.reason += sorry
  else:
  e.message += sorry

 The problem is that these attribute names are not standardized and can
 change between Python versions. Not even args is sure, and if a class
 has message it does not mean that it is displayed. Therefore I think
 the first approach is better.

  In the first case you will need somehow to tell to the new instance
  exception the real stack trace, because by simply raising
  a new one the original stack trace may get lost.

 Yes, but thats a different problem that is easy to solve.


Yeah maybe for a python guy, but I am a newbie. I would really
appreciate if you can show in this thread how this can be done in
Python.

tia,

./alex
--
.w( the_mindstorm )p.

PS: sorry for reposting, but it looks like my previous message hasn't
gone through :-(.



-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-06 Thread Neil Cerutti
On 2007-07-06, Alex Popescu [EMAIL PROTECTED] wrote:
 On Jul 6, 4:20 am, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Alex Popescu wrote:
  Probably the simplest solution would be to create a new exception and
  wrapping the old one and the additional info. Unfortunately, this
  may have a huge impact on 3rd party code that was catching the
  original exception. So, I think you should create an utility
  factory-like function that is either creating a new exception
  instance as the one caught and with the additional information,

 Right, I have gone with that (see the example with the PoliteException
 class somewhere below).

  or an utility that knows how to modify the caught exception according
  to its type.

 I guess you mean something like this (simplified):

 except Exception, e:
  if getattr(e, 'reason'):
  e.reason += sorry
  else:
  e.message += sorry

 The problem is that these attribute names are not standardized and can
 change between Python versions. Not even args is sure, and if a class
 has message it does not mean that it is displayed. Therefore I think
 the first approach is better.

  In the first case you will need somehow to tell to the new instance
  exception the real stack trace, because by simply raising
  a new one the original stack trace may get lost.

 Yes, but thats a different problem that is easy to solve.

 Yeah maybe for a python guy, but I am a newbie. I would really
 appreciate if you can show in this thread how this can be done
 in Python.

Chech out the docs for sys.exc_info(), and for the raise
statement.

When handling an exception, you can rethrow a different
exception, but with the same traceback, by using the three-arg
version of raise.

See one of my earlier posts in this thread for a working example
(although it didn't solve Chris's problem).

-- 
Neil Cerutti
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-06 Thread Gerard Flanagan
On Jul 6, 12:18 am, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Sorry for the soliloquy, but what I am really using is the following so
 that the re-raised excpetion has the same type:

 def PoliteException(e):
  class PoliteException(e.__class__):
  def __init__(self, e):
  self._e = e
  def __getattr__(self, name):
  return getattr(self._e, name)
  def __str__(self):
  if isinstance(self._e, PoliteException):
  return str(self._e)
  else:
  return '\n%s: %s, I am sorry!' % (
  self._e.__class__.__name__, str(self._e))
  return PoliteException(e)

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

Would a decorator work here?


class PoliteException(Exception):
def __init__(self, e):
self._e = e
def __getattr__(self, name):
return getattr(self._e, name)
def __str__(self):
return '\n%s: %s, I am sorry!' % (
self._e.__class__.__name__, str(self._e))

def politefail(fn):
def wrapper(*args, **kwargs):
try:
return fn(*args, **kwargs)
except Exception, e:
raise PoliteException(e)
return wrapper

@politefail
def funktion():
 unicode('\xe4')

funktion()

@politefail
def raise_exception(err, *args):
raise err(*args)


def funktion():
if 1 != 2:
raise_exception(ArithmeticError, '1 is not equal to 2.')

print
funktion()

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Thomas Heller
Christoph Zwerschke schrieb:
 What is the best way to re-raise any exception with a message 
 supplemented with additional information (e.g. line number in a 
 template)?

I have the impression that you do NOT want to change the exceptions,
instead you want to print the traceback in a customized way.  But I may be 
wrong...

Thomas

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Christoph Zwerschke
Thomas Heller wrote:
 I have the impression that you do NOT want to change the exceptions,
 instead you want to print the traceback in a customized way.  But I may be 
 wrong...

No, I really want to modify the exception, supplementing its message 
with additional information about the state of the program.

The use case are compiled Kid templates (http://kid-templating.org). If 
an error occurs, I want to add the corresponding line number of the XML 
file as information for the template developer. Since the final error 
handling may happen somewhere else (e.g. by TurboGears importing a Kid 
template), I do not want to modify trackeback handling or something.

-- Chris
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Neil Cerutti
On 2007-07-05, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Thomas Heller wrote:
 I have the impression that you do NOT want to change the
 exceptions, instead you want to print the traceback in a
 customized way.  But I may be wrong...

 No, I really want to modify the exception, supplementing its
 message with additional information about the state of the
 program.

 The use case are compiled Kid templates
 (http://kid-templating.org). If an error occurs, I want to add
 the corresponding line number of the XML file as information
 for the template developer. Since the final error handling may
 happen somewhere else (e.g. by TurboGears importing a Kid
 template), I do not want to modify trackeback handling or
 something.

The documentation for BaseException contains something that might
be relevant:

   [...] If more data needs to be attached to the exception,
   attach it through arbitrary attributes on the instance. All
   arguments are also stored in args as a tuple, but it will
   eventually be deprecated and thus its use is discouraged. New
   in version 2.5. [...]

I don't know if something like the following would help:

 def foo():
...   try:
... 12/0
...   except ZeroDivisionError, e:
... e.my_info = Oops!
... raise
...
 try:
...   foo()
... except ZeroDivisionError, e:
...   print e.my_info
...
Oops!

Users could get at the extra info you attached, but it wouldn't
be automatically displayed by the interpreter.

-- 
Neil Cerutti
Symphonies of the Romantic era were a lot longer in length. --Music Lit Essay
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Christoph Zwerschke
Neil Cerutti wrote:
 The documentation for BaseException contains something that might
 be relevant:
 
[...] If more data needs to be attached to the exception,
attach it through arbitrary attributes on the instance. All

 Users could get at the extra info you attached, but it wouldn't
 be automatically displayed by the interpreter.

Yes, that's the problem here. It wouldn't be displayed automatically and 
the users must be aware of this attribute. I'd like to have a more 
transparent solution.

-- Chris
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Neil Cerutti
On 2007-07-05, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Neil Cerutti wrote:
 The documentation for BaseException contains something that might
 be relevant:
 
[...] If more data needs to be attached to the exception,
attach it through arbitrary attributes on the instance. All

 Users could get at the extra info you attached, but it wouldn't
 be automatically displayed by the interpreter.

 Yes, that's the problem here. It wouldn't be displayed
 automatically and the users must be aware of this attribute.
 I'd like to have a more transparent solution.

You ought to be able to use the third arg of raise to raise a new
exception as if it were from the previous location, but now with
a new message.

You may need the traceback module to get at the error message, if
trying to read e.message can fail.

Something like this mess here: ;)

   ...
   except Exception, e:
 etype, evalue, etb = sys.exc_info()
 ex = traceback.format_exception_only(etype, evalue)
 message = ex[0].partition(':')[2].strip()
 raise etype, message+. Sorry!, etb

Note that the above will break for SyntaxError (who's message
contains more than one line) and any kind of exception that
doesn't inherit from Exception.

You might need some crufty try, finally to avoid having a
circular reference hang around, according to the docs for
sys.exc_info.

-- 
Neil Cerutti
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Christoph Zwerschke
Neil Cerutti wrote:
 You may need the traceback module to get at the error message, if
 trying to read e.message can fail.
 
 Something like this mess here: ;)
 
...
except Exception, e:
  etype, evalue, etb = sys.exc_info()
  ex = traceback.format_exception_only(etype, evalue)
  message = ex[0].partition(':')[2].strip()
  raise etype, message+. Sorry!, etb
 
 Note that the above will break for SyntaxError (who's message
 contains more than one line) and any kind of exception that
 doesn't inherit from Exception.

That's actually similar to what I was using in Kid already.

The problem is that there are some Exceptions which cannot be 
instantiated with a single string argument, such as UnicodeDeocdeError.
Please try the above with unicode('\xe4') instead of the dots.
Instead of re-raising the UnicodeDecodeError, you will get a TypeError 
because of this problem.

-- Chris

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Neil Cerutti
On 2007-07-05, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Neil Cerutti wrote:
 You may need the traceback module to get at the error message, if
 trying to read e.message can fail.
 
 Something like this mess here: ;)
 
...
except Exception, e:
  etype, evalue, etb = sys.exc_info()
  ex = traceback.format_exception_only(etype, evalue)
  message = ex[0].partition(':')[2].strip()
  raise etype, message+. Sorry!, etb
 
 Note that the above will break for SyntaxError (who's message
 contains more than one line) and any kind of exception that
 doesn't inherit from Exception.

 That's actually similar to what I was using in Kid already.

 The problem is that there are some Exceptions which cannot be
 instantiated with a single string argument, such as
 UnicodeDeocdeError. Please try the above with unicode('\xe4')
 instead of the dots. Instead of re-raising the
 UnicodeDecodeError, you will get a TypeError because of this
 problem.

Crud. After my third answer, I'll finally understand the
question. Unfortunately, I only had two in me.

-- 
Neil Cerutti
Low Self-Esteem Support Group will meet Thursday at 7 to 8:30 p.m. Please use
the back door. --Church Bulletin Blooper
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Kay Schluehr
On Jul 5, 3:53 pm, Christoph Zwerschke [EMAIL PROTECTED] 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. 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
 ZeroDivisionError: integer division or modulo by zero, sorry!

 But it fails for some exceptions that cannot be instantiated with a
 single string argument, like UnicodeDecodeError 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(Exception):
  def __init__(self, e):
  self._e = e
  def __getattr__(self, 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__.SorryEx: '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

If you are sure that the exception isn't caught on another level just
use the following showtraceback() function, manipulate it's output
slightly and terminate your program with sys.exit()

def showtraceback():
'''
(Copied from code.py)
'''
try:
type, value, tb = sys.exc_info()
sys.last_type = type
sys.last_value = value
sys.last_traceback = tb
tblist = traceback.extract_tb(tb)
del tblist[:1]
lst = traceback.format_list(tblist)
if lst:
lst.insert(0, Traceback (most recent call last):\n)
lst[len(lst):] = traceback.format_exception_only(type,
value)
finally:
tblist = tb = None
sys.stderr.write(.join(lst))


-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Christoph Zwerschke
Kay Schluehr wrote:
 If you are sure that the exception isn't caught on another level just
 use the following showtraceback() function, manipulate it's output
 slightly and terminate your program with sys.exit()

That's what I want to avoid. In my case the error is displayed and 
evaluated in a completly different piece of software.

-- Chris
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Christoph Zwerschke
Seems that no simple solution exists,
so for now, I will be using something like this:

class PoliteException(Exception):
 def __init__(self, e):
 self._e = e
 def __getattr__(self, name):
 return getattr(self._e, name)
 def __str__(self):
 if isinstance(self._e, PoliteException):
 return str(self._e)
 else:
 return '\n%s: %s, I am sorry!' % (
 self._e.__class__.__name__, str(self._e))

try:
 unicode('\xe4')
except Exception, e:
 raise PoliteException(e)
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Alex Popescu
On Jul 6, 12:21 am, Christoph Zwerschke [EMAIL PROTECTED] wrote:
 Kay Schluehr wrote:
  If you are sure that the exception isn't caught on another level just
  use the following showtraceback() function, manipulate it's output
  slightly and terminate your program with sys.exit()

 That's what I want to avoid. In my case the error is displayed and
 evaluated in a completly different piece of software.

 -- Chris

Probably the simplest solution would be to create a new exception and
wrapping the old one and the additional info. Unfortunately,
this may have a huge impact on 3rd party code that was catching the
original exception.

So, I think you should create an utility factory-like function that is
either creating a new exception instance as the one caught
and with the additional information, or an utility that knows how to
modify the caught exception according to its type.
In the first case you will need somehow to tell to the new instance
exception the real stack trace, because by simply raising
a new one the original stack trace may get lost.

bests,

./alex
--
.w( the_mindstorm )p.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Christoph Zwerschke
Sorry for the soliloquy, but what I am really using is the following so 
that the re-raised excpetion has the same type:

def PoliteException(e):
 class PoliteException(e.__class__):
 def __init__(self, e):
 self._e = e
 def __getattr__(self, name):
 return getattr(self._e, name)
 def __str__(self):
 if isinstance(self._e, PoliteException):
 return str(self._e)
 else:
 return '\n%s: %s, I am sorry!' % (
 self._e.__class__.__name__, str(self._e))
 return PoliteException(e)

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

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-raising exceptions with modified message

2007-07-05 Thread Christoph Zwerschke
Alex Popescu wrote:
 Probably the simplest solution would be to create a new exception and
 wrapping the old one and the additional info. Unfortunately, this 
 may have a huge impact on 3rd party code that was catching the 
 original exception. So, I think you should create an utility 
 factory-like function that is either creating a new exception 
 instance as the one caught and with the additional information,

Right, I have gone with that (see the example with the PoliteException 
class somewhere below).

 or an utility that knows how to modify the caught exception according
 to its type.

I guess you mean something like this (simplified):

except Exception, e:
 if getattr(e, 'reason'):
 e.reason += sorry
 else:
 e.message += sorry

The problem is that these attribute names are not standardized and can 
change between Python versions. Not even args is sure, and if a class 
has message it does not mean that it is displayed. Therefore I think 
the first approach is better.

 In the first case you will need somehow to tell to the new instance
 exception the real stack trace, because by simply raising
 a new one the original stack trace may get lost.

Yes, but thats a different problem that is easy to solve.

-- Chris
-- 
http://mail.python.org/mailman/listinfo/python-list