Python Forum
raising multiple exceptions - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: raising multiple exceptions (/thread-2455.html)

Pages: 1 2


raising multiple exceptions - Skaperen - Mar-18-2017

in a function that is to be given a list of tuples i want to raise an exception for an error.  for example each tuple must be of length 2 or 3 and the first element must always be a string.  anything else makes no sense, or is ambiguous.  i want to raise an exception for this kind of error.  for an empty list it will just return None (an empty list means nothing to do).  it would be nice to see what all the errors are in the first bad run so they all can be fixed in one cycle.  i was thinking of outputting an error message describing each error then raise an exception if there were any errors.  but i have heard of schemes used to record exceptions with their types and descriptions.  that sounds like i need to raise an exception for each errorhow should i approach this?  back in my C days i would do the multiple output approach since the only exception handling there was, was to exit/kill the process.


RE: raising multiple exceptions - wavic - Mar-18-2017

Something like this? Subclassing the tuple class
In [19]: class Mytup(tuple):
    ...:     def __new__(cls, obj):
    ...:         if 2 <= len(obj) <= 3 and isinstance(obj[0], str):
    ...:             return tuple.__new__(cls, obj)
    ...:         elif 2 > len(obj) > 3:
    ...:             raise Exception("Wrong number of arguments in {}".format(obj.__repr__()))
    ...:         elif isinstance(obj[0], str):
    ...:             raise Exception("{} must be string! {} is given.".format(obj[0], type(obj[0])))
    ...:                

In [20]: x = Mytup(['yes', 2, 3])

In [21]: x
Out[21]: ('yes', 2, 3)

In [22]: x = Mytup([42, 2, 3])

In [23]: x

In [24]: print(x)
None
Except it didn't rise an Exception.


RE: raising multiple exceptions - metulburr - Mar-18-2017

I think he wants the exceptions to be triggered

class Mytup(tuple):
    def __new__(cls, obj):
        if not obj:
            return None
        elif 2 > len(obj) > 3:
            raise Exception("Wrong number of arguments in {}".format(obj.__repr__()))
        elif not isinstance(obj[0], str):
            raise Exception("{} must be string! {} is given.".format(obj[0], type(obj[0])))
        else:
            return tuple.__new__(cls, obj)
            
x = Mytup(['yes', 2, 3])
print(x)
x = Mytup([])
print(x)
x = Mytup([42, 2, 3])
print(x)
Output:
('yes', 2, 3) None Traceback (most recent call last):   File "test2.py", line 17, in <module>     x = Mytup([42, 2, 3])   File "test2.py", line 9, in __new__     raise Exception("{} must be string! {} is given.".format(obj[0], type(obj[0]))) Exception: 42 must be string! <type 'int'> is given.



RE: raising multiple exceptions - wavic - Mar-18-2017

(Mar-18-2017, 12:45 PM)metulburr Wrote: I think he wants the exceptions to be triggered
Yes, I noticed it but mine didn't work. Don't know why. I am not dating with classes very often


RE: raising multiple exceptions - zivoni - Mar-18-2017

Condition 2 > len(obj) > 3 should be  rewritten as False , less typing :)  a > x > b means a > x and x > b, not a > x or x > b.

I think that Skaparen wants to do something like (pseudocode) :
line 1  # triggers exception1
line 2  # triggers exception2
line 3  # triggers exception3

raise exception1 and exception2 and exception3
I dont think that something such that could be done easily (well, you can use lot of try/except, store exception infos to a list, extend Exception to accept another parameter and at the end of code do raise MySuperException('exceptions', list_of_exceptions) to send info about all exceptions if your list_of_exceptions is not empty ... but why?).

If you insist on "ignoring" exceptions and going on, why not just log it?
import logging
logging.basicConfig(filename='logfile.log')

try:
    1/0
except:
    logging.exception("my exception comment")

try:
    int("foo")
except:
    logging.exception("another comment")
Output:
ERROR:root:my exception comment Traceback (most recent call last):   File "exceptlog.py", line 9, in <module>     1/0 ZeroDivisionError: division by zero ERROR:root:another comment Traceback (most recent call last):   File "exceptlog.py", line 14, in <module>     int("foo") ValueError: invalid literal for int() with base 10: 'foo'



RE: raising multiple exceptions - ichabod801 - Mar-18-2017

Except I think he wants all the exceptions raised at once. That is, if it's four long and starts with an int, it should raise two exceptions. But you can't really do that, AFAIK. The closest you could get is raising an exception while handling another exception, but that would imply a try/except block somewhere to handle the first exception. I think that would just be a mess:

try:
    if not 2 <= len(x) <= 3:
        raise ValueError('Size must be two or three.')
except ValueError:
    if not isinstance(x[0], str):
        raise ValueError('First item must be string.')
if not isinstance(x[0], str):
    raise ValueError('First item must be string.')
You have to check the first item twice, once if there is a length error and once if there isn't. If you have three items to check it becomes huge.

So if you want all the errors at once, you would want to collect the error conditions without raising exceptions, and then raise one exception if you found any error conditions. However, if you're doing this for development purposes, I would do it with unit tests. Have one test for each condition, and the run all the tests to see which ones throw exceptions.


RE: raising multiple exceptions - wavic - Mar-18-2017

I think he wants to get all exception at once as he says: "it would be nice to see what all the errors are in the first bad run so they all can be fixed in one cycle. "
So, logging will come in handy but I never touch it, though. However, it points to some direction at least.


RE: raising multiple exceptions - Skaperen - Mar-19-2017

for each item in the list, i want to check it for errors in some order and raise one exception for that one item.  but the list may contain 6144 items of which #89, #1024, #4317, and #6133 have an error.  i want to let whoever deals with fixing these know about all of the errors.  if the tuple is too long and has an int as the first item in the tuple, then it is good enough to indicate it is too long.  being too long, the contents no longer makes any sense, so the type of the first element of the tuple is not relevant.  what i need to do is point out all 4 errors (or however many there really are).

what would be nice is a means to do the raise in a way that keeps on running.  but then that makes no sense to outer layer code that is catching the exception(s). multiple threads could create new problems and many bugs.


RE: raising multiple exceptions - wavic - Mar-19-2017

Well, instead of raising errors it can check for conditions and if the tuple is out of what is wanted, to put messages indicating the problems found in a dictionary and the index of the tuple as the key, returning None.
Something like this? I don't know if the error dictionary must be passed as an argument to the class definition. Can't test it now.
But you get the idea
from collections import defaultdict

def tuples_validation(tuples):
    errors = defaultdict(list)
    
    class Mytup(tuple):
        def isvalid(self, index, obj):
            valid = True
            
            if obj:
                errors[index].append("An empy tuple")
                valid = False
            if 2 > len(obj) > 3:
                erros[index].append("Wrong number of arguments in {}".format(obj.__repr__()))
                valid = False
            if isinstance(obj[0], str):
                errors[index].append("{} must be string! {} is given.".format(obj[0], type(obj[0])))
                valid = False
            
            return valid
            
            def __new__(cls, obj):
            if self.valid(obj):
                return None
            else:
                return tuple.__new__(cls, obj)
    
    new_tuples = []
    for t in tuples:
        new_t = Mytup(tuples.index(t), t)
        if new_t:
            new_tuples.append(new_t)
        #~ else:
            #~ pass
            
    return (errors, new_tuples)



RE: raising multiple exceptions - Skaperen - Mar-19-2017

using a defaultdict looks interesting.  i still don't understand all of it.  when would it be better than a plain dict using .get() to fetch from it?