idiomatic way to collect and report multiple exceptions?

Ben Cohen ncohen at ucsd.edu
Fri May 7 21:06:43 EDT 2010


Many thanks for the excellent example!!  You rock!

Ben

On May 6, 2010, at 10:56 PM, Chris Rebert wrote:

> On Thu, May 6, 2010 at 8:50 PM, Ben Cohen <ncohen at ucsd.edu> wrote:
>> Is there a pythonic way to collect and display multiple exceptions at the same time?
>> 
>> For example let's say you're trying to validate the elements of a list and you'd like to validate as many of the elements as possible in one run and still report exception's raised while validating a failed element.
>> 
>> eg -- I'd like to do something like this:
>> 
>> errors = []
>> for item in data:
>>        try:
>>                process(item)
>>        except ValidationError as e:
>>                errors.append(e)
>> raise MultipleValidationErrors(*errors)
>> 
>> where if the raised MultipleValidationErrors exception goes uncaught the interpreter will print a nice traceback that includes the tracebacks of each raised ValidationError.  But I don't know how MultipleValidationErrors should be written ...
> 
> import sys, traceback
> 
> def _traceback_for(exc_info):
>    return ''.join(traceback.format_exception(*exc_info))
> 
> # StandardError can obviously be replaced with
> # whatever exception superclass you want.
> class MultipleValidationErrors(StandardError):
>    def __init__(self, errors=None):
>        self.errors = errors or []
> 
>    def __str__(self):
>        tracebacks = "\n\n".join(_traceback_for(exc_info) for exc_info in \
>            self.errors)
>        parts=("See the following exception tracebacks:", "="*78, tracebacks)
>        msg = '\n'.join(parts)
>        return msg
> 
>    def capture_current_exception(self):
>        self.errors.append(sys.exc_info())
> 
>    def do_raise(self):
>        """Raises itself if it contains any errors"""
>        if self.errors:
>            raise self
> 
> 
> #Example usage:
> multiple_err = MultipleValidationErrors()
> for c in "hello":
>    try:
>        int(c) # obviously fails
>    except ValueError: # whatever error type you care about
>        multiple_err.capture_current_exception()
> multiple_err.do_raise()
> 
> 
> Output from example:
> Traceback (most recent call last):
>  File "tmp.py", line 35, in <module>
>    multiple_err.do_raise()
>  File "tmp.py", line 25, in do_raise
>    raise self
> __main__.MultipleValidationErrors: See the following exception tracebacks:
> ==============================================================================
> Traceback (most recent call last):
>  File "tmp.py", line 32, in <module>
>    int(c) # obviously fails
> ValueError: invalid literal for int() with base 10: 'h'
> 
> 
> Traceback (most recent call last):
>  File "tmp.py", line 32, in <module>
>    int(c) # obviously fails
> ValueError: invalid literal for int() with base 10: 'e'
> 
> 
> Traceback (most recent call last):
>  File "tmp.py", line 32, in <module>
>    int(c) # obviously fails
> ValueError: invalid literal for int() with base 10: 'l'
> 
> 
> Traceback (most recent call last):
>  File "tmp.py", line 32, in <module>
>    int(c) # obviously fails
> ValueError: invalid literal for int() with base 10: 'l'
> 
> 
> Traceback (most recent call last):
>  File "tmp.py", line 32, in <module>
>    int(c) # obviously fails
> ValueError: invalid literal for int() with base 10: 'o'
> 
> 
> Cheers,
> Chris
> --
> Go Tritons!
> http://blog.rebertia.com





More information about the Python-list mailing list