Raising custom exceptions and output - python

I have the following code from a tutorial:
class Ex(Exception):
def __init__(self,msg):
Exception.__init__(self,msg+msg)
self.args=(msg,)
try:
raise Ex('ex')
except Ex as e:
print(e)
The question is what the output will be? I thought it would be exex. However, the output is ex. Now I am not understanding the construction. As far as I can see I can ignore the self.args=(msg,). This does not matter. What I am not understanding is the line Exception.__init__(self,msg+msg). I am not that used to exceptions.

when calling Exception.__init__(self,msg+msg) the msg+msg (in this case exex is stored in the args attribute. by doing self.args=(msg,) afterwards, you are overwriting the previous assignment of the args attribute. if you want to print exex instead of just ex, simply remove self.args=(msg,)

Related

Passing Errors Types into a Custom Error Handling Class, Python

Being a Python novice, I resolve problems in interesting ways. This being one of them.
I'm wanting to pass Error messages into a Error Handling script (a Class), so I can customise the error message. For example, when 'FileNotFoundError' is raised, I want to display/send a message like 'Cant find xxx file, check yyy directory.'. Or 'ConnectionResetError', message ... 'Database connection restarted'.. and so on (about 15 different messages).
So, when an Exception is raised, I am passing the error:
if __name__ == "__main__":
try:
do stuff...
except Exception as e:
ErrorHandlingClass.ErrorMessageHandler(e)
to
class ErrorMessageHandler:
def __init__(self, error):
err_type = str(type(error)) # obviously this is dumb
err_type = (err_type[8:-2])
if err_type == 'FileNotFoundError':
print("Can not reach 'jconfig.json': {}".format(error))
Firstly, how to capture e.g. 'FileNotFoundError' without pulling out of a string.
Secondly, what the professional way?
Thirdly, since I need a bunch of if/elif to generate the unique message, why bother with a special Class, just put e.g. Except FileNotFoundError as e... with unique message, and put under 'main', and do 20 times, for each Error type raised? Then main becomes messy.
Thanks
Firstly, exceptions are instances of the Exception base class, and can be used as exceptions… so in your handler, you could:
def __init__(self, error):
try:
raise error
except FileNotFoundError:
print("Can not reach 'jconfig.json': {}".format(error)
except Exception as e:
print(e)
If you insist on using if statements then maybe you can use isinstance(obj, class) instead of string comparison. So in your case if isinstance(error, FileNotFoundError): ....
Secondly, this is alright if you want to centralize error handling. That really depends on your code. I don’t like this way because control is still in the main function and it is unclear what will happen after the handler finished handling. Will you exit(error_code_bigger_than_zero) or exit(0). Would you raise e to get the Python error trace back for debugging or do you want to end clean?
Thirdly. In Python it is better to create small functions that does one thing and does it good. I don’t think there should be anything in your main except:
if __name__ == “__main__”:
main()
Of course the function main() should be defined somewhere in the same or in another file.
just put e.g. Except FileNotFoundError as e... with unique message, and put under 'main', and do 20 times, for each Error type raised? Then main becomes messy.
It's often considered a code smell to manage a long chain of if statements for different object types, in this case exceptions. The most common way to avoid this is through single dispatch. Use either #singledispatch or #singledispatchmethod (it works essentially the same as the first, except you use it for class methods) if your use case actually requires a class:
from functools import singledispatch
#singledispatch
def handle(err):
raise err # pass on errors by default
#handle.register(FileNotFoundError)
def _(err):
print('File not found!') # do what you want here
For example:
try:
raise FileNotFoundError
except Exception as e:
handle(e) # prints 'File not found!'
PS: In your original code you do not have to convert the exception to a string to check its type, you may simply use isinstance(error, FileNotFoundError) to check if your exception object is of a specified exception class.

How to target an Exception more accurately?

Consider the (compressed for the sake of example) code below:
import ics
import arrow
import requests
a = min(list(ics.Calendar(requests(get('http://asitewithcalendar.org').text).timeline.on(arrow.now())))
Quite a lot of things are happening here, I am fine with issues (connection, problems with the URL, ...) crashing the code but not with the following error:
ValueError: min() arg is an empty sequence
I would like to catch that specific error: the fact that what is provided to min() is an empty sequence (and pass on it). Even more specifically, I want the other exceptions to crash, including ValueError ones that are not related to the empty sequence fed to min().
A straightforward try catching ValueError would be fine for everything except the last constraint.
Is there a way to say "except ValueError when the error is min() arg is an empty sequence"?
Note: I know that the code in my example is ugly - I wrote it to showcase my question so if the only answer is "impossible - you have to rewrite it to pinpoint the line you want to try" then fine, otherwise I am looking for general solutions
You can do something like:
try:
# Put your code to try here
a = min(list(ics.Calendar(requests(get('http://asitewithcalendar.org').text).timeline.on(arrow.now())))
except ValueError as e:
if str(e) == 'min() arg is an empty sequence':
pass
else:
raise e
This is a case where I would simply check the value before calling min rather than wait for an exception. There is no expression-level way to handle exceptions.
foo = list(ics.Calendar(requests(get('http://asitewithcalendar.org').text).timeline.on(arrow.now()))
if foo:
a = min(foo)
It remains to decide what a should be if foo is empty, but you would have the same problem with a try statement:
foo = list(ics.Calendar(requests(get('http://asitewithcalendar.org').text).timeline.on(arrow.now()))
try:
a = min(foo)
except ValueError:
???
I also wouldn't worry too much about only dealing with empty-sequence errors. Even if it is a different ValueError, a is just as undefined.
how about this.
import numpy
a = min(list(ics.Calendar(requests(get('http://asitewithcalendar.org').text).timeline.on(arrow.now())) + [-np.inf])
when -inf has returned. list has nothing inside it.

Python 3 - dynamically catch unknown number of exceptions [duplicate]

I know that I can do:
try:
# do something that may fail
except:
# do this if ANYTHING goes wrong
I can also do this:
try:
# do something that may fail
except IDontLikeYouException:
# say please
except YouAreTooShortException:
# stand on a ladder
But if I want to do the same thing inside two different exceptions, the best I can think of right now is to do this:
try:
# do something that may fail
except IDontLikeYouException:
# say please
except YouAreBeingMeanException:
# say please
Is there any way that I can do something like this (since the action to take in both exceptions is to say please):
try:
# do something that may fail
except IDontLikeYouException, YouAreBeingMeanException:
# say please
Now this really won't work, as it matches the syntax for:
try:
# do something that may fail
except Exception, e:
# say please
So, my effort to catch the two distinct exceptions doesn't exactly come through.
Is there a way to do this?
From Python Documentation:
An except clause may name multiple exceptions as a parenthesized tuple, for example
except (IDontLikeYouException, YouAreBeingMeanException) as e:
pass
Or, for Python 2 only:
except (IDontLikeYouException, YouAreBeingMeanException), e:
pass
Separating the exception from the variable with a comma will still work in Python 2.6 and 2.7, but is now deprecated and does not work in Python 3; now you should be using as.
How do I catch multiple exceptions in one line (except block)
Do this:
try:
may_raise_specific_errors():
except (SpecificErrorOne, SpecificErrorTwo) as error:
handle(error) # might log or have some other default behavior...
The parentheses are required due to older syntax that used the commas to assign the error object to a name. The as keyword is used for the assignment. You can use any name for the error object, I prefer error personally.
Best Practice
To do this in a manner currently and forward compatible with Python, you need to separate the Exceptions with commas and wrap them with parentheses to differentiate from earlier syntax that assigned the exception instance to a variable name by following the Exception type to be caught with a comma.
Here's an example of simple usage:
import sys
try:
mainstuff()
except (KeyboardInterrupt, EOFError): # the parens are necessary
sys.exit(0)
I'm specifying only these exceptions to avoid hiding bugs, which if I encounter I expect the full stack trace from.
This is documented here: https://docs.python.org/tutorial/errors.html
You can assign the exception to a variable, (e is common, but you might prefer a more verbose variable if you have long exception handling or your IDE only highlights selections larger than that, as mine does.) The instance has an args attribute. Here is an example:
import sys
try:
mainstuff()
except (KeyboardInterrupt, EOFError) as err:
print(err)
print(err.args)
sys.exit(0)
Note that in Python 3, the err object falls out of scope when the except block is concluded.
Deprecated
You may see code that assigns the error with a comma. This usage, the only form available in Python 2.5 and earlier, is deprecated, and if you wish your code to be forward compatible in Python 3, you should update the syntax to use the new form:
import sys
try:
mainstuff()
except (KeyboardInterrupt, EOFError), err: # don't do this in Python 2.6+
print err
print err.args
sys.exit(0)
If you see the comma name assignment in your codebase, and you're using Python 2.5 or higher, switch to the new way of doing it so your code remains compatible when you upgrade.
The suppress context manager
The accepted answer is really 4 lines of code, minimum:
try:
do_something()
except (IDontLikeYouException, YouAreBeingMeanException) as e:
pass
The try, except, pass lines can be handled in a single line with the suppress context manager, available in Python 3.4:
from contextlib import suppress
with suppress(IDontLikeYouException, YouAreBeingMeanException):
do_something()
So when you want to pass on certain exceptions, use suppress.
From Python documentation -> 8.3 Handling Exceptions:
A try statement may have more than one except clause, to specify
handlers for different exceptions. At most one handler will be
executed. Handlers only handle exceptions that occur in the
corresponding try clause, not in other handlers of the same try
statement. An except clause may name multiple exceptions as a
parenthesized tuple, for example:
except (RuntimeError, TypeError, NameError):
pass
Note that the parentheses around this tuple are required, because
except ValueError, e: was the syntax used for what is normally
written as except ValueError as e: in modern Python (described
below). The old syntax is still supported for backwards compatibility.
This means except RuntimeError, TypeError is not equivalent to
except (RuntimeError, TypeError): but to except RuntimeError as
TypeError: which is not what you want.
If you frequently use a large number of exceptions, you can pre-define a tuple, so you don't have to re-type them many times.
#This example code is a technique I use in a library that connects with websites to gather data
ConnectErrs = (URLError, SSLError, SocketTimeoutError, BadStatusLine, ConnectionResetError)
def connect(url, data):
#do connection and return some data
return(received_data)
def some_function(var_a, var_b, ...):
try: o = connect(url, data)
except ConnectErrs as e:
#do the recovery stuff
blah #do normal stuff you would do if no exception occurred
NOTES:
If you, also, need to catch other exceptions than those in the
pre-defined tuple, you will need to define another except block.
If you just cannot tolerate a global variable, define it in main()
and pass it around where needed...
One of the way to do this is..
try:
You do your operations here;
......................
except(Exception1[, Exception2[,...ExceptionN]]]):
If there is any exception from the given exception list,
then execute this block.
......................
else:
If there is no exception then execute this block.
and another way is to create method which performs task executed by except block and call it through all of the except block that you write..
try:
You do your operations here;
......................
except Exception1:
functionname(parameterList)
except Exception2:
functionname(parameterList)
except Exception3:
functionname(parameterList)
else:
If there is no exception then execute this block.
def functionname( parameters ):
//your task..
return [expression]
I know that second one is not the best way to do this, but i'm just showing number of ways to do this thing.
As of Python 3.11 you can take advantage of the except* clause that is used to handle multiple exceptions.
PEP-654 introduced a new standard exception type called ExceptionGroup that corresponds to a group of exceptions that are being propagated together. The ExceptionGroup can be handled using a new except* syntax. The * symbol indicates that multiple exceptions can be handled by each except* clause.
For example, you can handle multiple exceptions
try:
raise ExceptionGroup('Example ExceptionGroup', (
TypeError('Example TypeError'),
ValueError('Example ValueError'),
KeyError('Example KeyError'),
AttributeError('Example AttributeError')
))
except* TypeError:
...
except* ValueError as e:
...
except* (KeyError, AttributeError) as e:
...
For more details see PEP-654.

Using try exception/catch in the method definition or in the calling method?

Which of the following snippet codes is common?
#1:
def foo():
try:
pass # Some process
except Exception as e:
print(e)
foo()
#2:
def foo():
pass # Some process
try:
foo()
except Exception as e:
print(e)
It depends on what foo does, and the type of Exception, i'd say.
Should the caller handle it or should the method?
For instance, consider the following example:
def try_get_value(registry, key):
try:
return registry[key]
except KeyError:
return None
This function will attempt to fetch a value from a dictionary using its key. If the value is not there, it should return None.
The method should handle KeyError, because it needs to return None when this happens, so as to comply with its expected behavior. (It's the method's responsability to catch this error)
But think of other exception types, such as TypeError (e.g., if the registry is not a dict).
Why should our method handle that? That's the caller mess-up. He should handle that, and he should worry about that.
Besides, what can our method do if we get such Exception? There's no way we can handle that from this scope.
try_get_value has one simple task: to get a value from the registry (a default one if there is none). It's not responsible for the caller breaking the rules.
So we don't catch TypeError because it's not our responsability.
Hence, the caller's code may look like something like this:
try:
value = try_get_value(reg, 'some_key')
# Handle value
except TypeError:
# reg is not a dict, do something about it...
P.S.: There may be times when our foo method needs to do some cleanup if there is an unexpected exit (e.g. it has allocated some resources which would leak if not closed).
In this case, foo should catch the exceptions, just so it can fix its state appropriately, but should then raise them back again to the caller.
I think the first part is cleaner and more elegant. Also more logical because as an implementer of the function, you want to handle all exceptions that it might throw rather than leave it to the client or caller. Even if you'll be the only one using the method, you still want to handle exceptions inside the function as in the future you may not remember what exception it is throwing.

Any value in catching an exception and immediately raising it again? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Does a exception with just a raise have any use?
Is there any value to re-raising an exception with no other code in between?
try:
#code
except Exception:
raise
I was recently looking through some code and saw a few blocks like these with nothing extra in the except block but another raise. I assume this was a mistake and poor decision making, am I right?
I've seen similar code before in a (set of) horrible VB.NET projects. Either the intent was to catch and log exceptions, without ever coming back to finish the logging, or they heard "you must catch exceptions", implemented this functionality, and someone else decided it should just re-raise.
There is no benefit to the above code.
I am not able to come up with something useful, other than to keep it as a placeholder for later insertion to catch useful exceptions.
It kind of avoids re-indenting the code, when you want to include the "try .. except.." blocks later on.
Example built on this question. If there's some other except's in the try block, it can be used to filter the exceptions, but alone it's pointless.
class FruitException(Exception): pass
try:
raise FruitException
except FruitException:
print "we got a bad fruit"
raise
except Exception:
print "not fruit related, irrelevant."
Yes, this is usually a bad practice. The only (somewhat) correct usage I've seen of this pattern was before VB.NET had a Using construct available. Usage looked something like:
Dim myResource As DisposableService
Try
myResource = New DisposableService()
' This might throw an exception....
myResource.DoSomething()
Catch
Throw
Finally
' Perform cleanup on resource
If Not myResource Is Nothing Then
myResource.Dispose()
End If
End Try
Other than that, I really can't think of a good use case for this sort of thing.
sometimes it useful let me give you a real example that i did i my work :
this was is in a decorator that wrap func : so basically what i have wanted is to re-raise the error that i catched when i called the function func so that the decorator don't change the behavior of the function func, because when func raise an exception the exception are send to the GUI so that an error message can pop up to the user,
and for the try except i use it because i want to execute the code in finally even if an exception is raised
try:
result = func(self, *args, **kws)
return result
except Exception, ex:
# If an exception is raised save it also.
logging_data['message'] = str(ex)
logging_data['type'] = 'exception'
# Raise the error catched here so that we could have
# the same behavior as the decorated method.
raise
finally:
# Save logging data in the database
....
hope this will help to understand the use of re-raise
Typically in a try-catch model, any uncaught exception will automatically be thrown (raised?). Catching the exception only to re-throw it may be in the spirit Allman style coding, but serves no functional purpose.
Uh, Imagine
def something(a,b):
try:
// do stuff
except SomethingSpecificToThisFunction:
//handle
except: //Everything else, should likely be handled somewhere else
raise
try:
something("a","b")
except e:
Log(e)
Then again its default behaviour anyways, so might just want to leave it out
There are some approaches with such technics in multithread enviroment. For example to throw something to upper stack level.

Categories