right now I have a problem where I want to raise a specific TypeError if there is one. However, what ends up happening is the interpreter sees the first error, and then in the middle of handling it it raises the other one as well saying "During handling of the above exception, another exception occurred:"
this is what I have
def function(dictionary)
try:
value = max(dictionary.values())
except TypeError:
raise TypeError("some error")
I plug in the following into the shell:
function({1:'a', 2:3})
How can I approach this?
If you want to discard the exception context, you can explicitly discard it using from None, e.g.:
try:
value = max(dictionary.values())
except TypeError:
raise TypeError("some error") from None
That said, it's usually best to leave the context in place; the only time you'll see it is if the exception is uncaught and the default logging occurs, or you try to log the exception (e.g. with logger.exception). That additional information is often useful, especially for extremely broad exception types like TypeError and ValueError (where you intend to catch specific known subtypes, and unexpectedly catch one caused in a completely different way).
To be clear, this only works on Python 3, but then, exception context chaining only exists on Python 3; on Python 2, the context is lost automatically.
Since you are raising the exception while handling it, the exception is sent back to the caller function.
If you just want to handle it and print the error and move on with rest of the execution, you can do sth like this
except TypeError as t:
print ("Error", t)
Related
I'm trying to create a try-except block that re-raises an arbitrary exception, but only includes the final block in the traceback stack.
Something like this:
import traceback
def my_func(shorten_tracebacks=True):
try:
# Do stuff here
except Exception as e:
if shorten_tracebacks:
raise TheSameTypeOfError, e, traceback.print_exc(limit=1)
else:
raise(e)
Is there a preferred way to do this?
In case it matters, I'm doing this for convenience in debugging certain APIs that are often used in jupyter notebooks---they tend to generate really long stack traces where only the last block is informative. This forces the user to scroll a lot. If you don't want to shorten the traceback, you can always set shorten_tracebacks=False
My preference is to create a new exception without a context (if an exception has a context python will print both the exception and the exception which caused that exception, and the exception which caused that exception, and so on...)
try:
...
except:
raise Exception("Can't ramistat the foo, is foo installed?") from None
Some best practices:
Include relevant debugging information in the exception message.
Use a custom exception type, so callers can catch the new exception.
Catch only the specific error types you're expecting, to let unexpected errors fall through with the extended traceback.
The downside to this approach is that if your exception catching is overly broad, you can end up suppressing useful context which is important to debugging the exception. An alternate pattern might look like this:
try:
...
except Exception as e:
if "ramistat not found" in e.message:
# The ramistat is missing. This is a common kind of error.
# Create a more helpful and shorter message
raise Exception("Can't ramistat the foo, is foo installed?") from None
else:
# Some other kind of problem
raise e
Essentially, you check the exception, and replace it with a custom message if it's a kind of error you know how to deal with. Otherwise, you re-raise the original exception, and let the user figure out what to do.
I'm reading the Python Tutorial.
I came across a part that says:
'''
If you need to determine whether an exception was raised but don’t intend to handle it, a simpler form of the raise statement allows you to re-raise the exception:
'''
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise
I don't understand why would one raise an exception, handle it and then re-raise it??
If the programmer doesn't want to handle the exception they shouldn't use a try..except statement in the first place??
It helps if you don't think of exceptions as "mistakes" that have to be caught/corrected, and instead think of them as a way of communicating information.
Sometimes when you catch an exception it's expected, or you can find a way around it. Other times, the exception means you can't do the thing you were trying to do, and so you want to raise an exception to your own caller to let them know why it's not going to work out.
When you're in that situation, sometimes you'll catch the lower-level exception that thwarted your plans, and then raise your own exception (maybe with a more specific type) to communicate your own failure to the caller. Sometimes it might work just as well to simply raise the same exception back to the caller. In the situation where you just want the lower level exception to go all the way up to the caller, you might opt to just not catch it, but what if you want to log a message or clean up some piece of internal state before you go down in flames? That's where the except/raise pattern is useful.
begin_complicated_process()
try:
do_risky_thing()
except ShenanigansError:
log("Did someone say shenanigans?!")
unwind_complicated_process()
raise
complete_complicated_process()
import sys
def worker(a):
try:
return 1 / a
except ZeroDivisionError:
return None
def master():
res = worker(0)
if not res:
print(sys.exc_info())
raise sys.exc_info()[0]
As code piece above, I have a bunch of functions like worker. They already have their own try-except block to handle exceptions. And then one master function will call each worker. Right now, sys.exc_info() return all None to 3 elements, how to re-raise the exceptions in the master function?
I am using Python 2.7
One update:
I have more than 1000 workers and some worker has very complex logic, they may deal multiple types of exceptions at same time. So my question is can I just raise those exceptions from master rather than edit works?
In your case, the exception in worker returns None. Once that happens, there's no getting the exception back. If your master function knows what the return values should be for each function (for example, ZeroDivisionError in worker reutrns None, you can manually reraise an exception.
If you're not able to edit the worker functions themselves, I don't think there's too much you can do. You might be able to use some of the solutions from this answer, if they work in code as well as on the console.
krflol's code above is kind of like how C handled exceptions - there was a global variable that, whenever an exception happened, was assigned a number which could later be cross-referenced to figure out what the exception was. That is also a possible solution.
If you're willing to edit the worker functions, though, then escalating an exception to the code that called the function is actually really simple:
try:
# some code
except:
# some response
raise
If you use a blank raise at the end of a catch block, it'll reraise the same exception it just caught. Alternatively, you can name the exception if you need to debug print, and do the same thing, or even raise a different exception.
except Exception as e:
# some code
raise e
What you're trying to do won't work. Once you handle an exception (without re-raising it), the exception, and the accompanying state, is cleared, so there's no way to access it. If you want the exception to stay alive, you have to either not handle it, or keep it alive manually.
This isn't that easy to find in the docs (the underlying implementation details about CPython are a bit easier, but ideally we want to know what Python the language defines), but it's there, buried in the except reference:
… This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.
Before an except clause’s suite is executed, details about the exception are stored in the sys module and can be accessed via sys.exc_info(). sys.exc_info() returns a 3-tuple consisting of the exception class, the exception instance and a traceback object (see section The standard type hierarchy) identifying the point in the program where the exception occurred. sys.exc_info() values are restored to their previous values (before the call) when returning from a function that handled an exception.
Also, this is really the point of exception handlers: when a function handles an exception, to the world outside that function, it looks like no exception happened. This is even more important in Python than in many other languages, because Python uses exceptions so promiscuously—every for loop, every hasattr call, etc. is raising and handling an exception, and you don't want to see them.
So, the simplest way to do this is to just change the workers to not handle the exceptions (or to log and then re-raise them, or whatever), and let exception handling work the way it's meant to.
There are a few cases where you can't do this. For example, if your actual code is running the workers in background threads, the caller won't see the exception. In that case, you need to pass it back manually. For a simple example, let's change the API of your worker functions to return a value and an exception:
def worker(a):
try:
return 1 / a, None
except ZeroDivisionError as e:
return None, e
def master():
res, e = worker(0)
if e:
print(e)
raise e
Obviously you can extend this farther to return the whole exc_info triple, or whatever else you want; I'm just keeping this as simple as possible for the example.
If you look inside the covers of things like concurrent.futures, this is how they handle passing exceptions from tasks running on a thread or process pool back to the parent (e.g., when you wait on a Future).
If you can't modify the workers, you're basically out of luck. Sure, you could write some horrible code to patch the workers at runtime (by using inspect to get their source and then using ast to parse, transform, and re-compile it, or by diving right down into the bytecode), but this is almost never going to be a good idea for any kind of production code.
Not tested, but I suspect you could do something like this. Depending on the scope of the variable you'd have to change it, but I think you'll get the idea
try:
something
except Exception as e:
variable_to_make_exception = e
.....later on use variable
an example of using this way of handling errors:
errors = {}
try:
print(foo)
except Exception as e:
errors['foo'] = e
try:
print(bar)
except Exception as e:
errors['bar'] = e
print(errors)
raise errors['foo']
output..
{'foo': NameError("name 'foo' is not defined",), 'bar': NameError("name 'bar' is not defined",)}
Traceback (most recent call last):
File "<input>", line 13, in <module>
File "<input>", line 3, in <module>
NameError: name 'foo' is not defined
I am trying to understand what is a difference between raising a ValueError and an Exception. I have tried both in the same code (even in the same branch) and the result was the same - I got an error message.
I have made a research on this question on SO, but found no discussion on this. Then I read the documentation of exceptions, and found the following definition of ValueError:
Raised when a built-in operation or function receives an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception such as IndexError.
So as I understand, an Exception is a more general term, and ValueError can be applied in some specific cases. But since the results of raising both things are the same, I want to understand, what is the practical meaning of differentiating between a ValueError and an Exception. Python version should be here not relevant. Thank you!
EDIT:
Thanks to your answers I got it, what is the difference between both terms in try-exception construct. But how do they differ in case of just raising them, not excepting?
raise Exception('blah')
and
raise ValueError('blah')
Answering to #PeterWood: in both cases I just got the error message "blah", but in one case it was "Exception: blah", and in the second: "ValueError: blah". And I see in this case no practical difference between them both.
ValueError inherits from Exception. You can decide to trap either only ValueError, or Exception, that's what exception inheritance is for.
In this example:
try:
a=12+"xxx"
except Exception:
# exception is trapped (TypeError)
exception is trapped, all exceptions (except BaseException exceptions) are trapped by the except statement.
In this other example:
try:
a=12+"xxx"
except ValueError:
# not trapped
Here, exception is NOT trapped (TypeError is not ValueError and does not inherit)
You generally use specific exceptions to trap only the ones that are likely to occur (best example is IOError when handling files), and leave the rest untrapped. The danger of catching all exceptions is to get a piece of code that does not crash, but does nothing.
(editing the answer in response to your edit:) when you raise an exception: you're creating an instance of Exception which will be filtered out by future except ValueError: statements. the message is different because the representation of the exception (when printed) includes the exception class name.
You said it, ValueError is a specific Exception. A short example :
try:
print int("hello world")
except ValueError:
print "A short description for ValueError"
If you change "hello world" with an int, print int(42), you will not raise the exception.
You can see doc about exceptions here.
To add extra detail onto the above answers, you can chain the except statements in the try clause. So you might first check for ValueError, or another type, then lastly you can check for Exception (anything that wasn't already caught by ValueError).
As mentioned above, ValueError inherits from Exception, so it is a more specific type of Exception. docs: https://docs.python.org/3/library/exceptions.html
Example:
Assuming mycheck() function passes back some exception text, we can access it with the below variable 'e'.
try:
value = mycheck(value)
except ValueError as e:
print(f"'{value}' did not pass mycheck ValueCheck: {e}")
except Exception as e:
print(f"'{value}' did not pass mycheck validation: {e}")
You asked about the difference of raising ValueError versus raising Exception. Both behave similarly. It's a matter of how specific you want to be. It would be recommended generally to raise the most specific type of error in order to provide the most useful error feedback to the user.
If you look at how error trapping can be chained in my example, then you might see how your choice of which type of error to raise would affect the output to the user.
I've got a situation where I'm catching a specific exception type, inspecting the exception's message to check if it's actually an exception I want to catch, and then re-raising the exception if not:
try:
# do something exception-prone
except FooException as e:
if e.message == 'Something I want to handle':
# handle the exception
else:
raise e
This works fine, with one problem. In the case I re-raise the exception, that exception now occurs at the line I re-raised it (i.e. at raise e), rather than at the location the exception originally occurred. This isn't ideal for debugging, where you want to know where the original exception happened.
Thus my question: is there any way to re-raise or otherwise "pass on" an exception after catching it while maintaining the original exception location?
NOTE: In case you are wondering what the actual situation is: I'm dynamically importing some modules using __import__. I'm catching ImportError to gracefully deal with the case that any of these modules do not exist. However, in the case that any of these modules themselves contain an import statement that raises ImportError, I want those "real" (from the point of view of my application) exceptions to be raised -- and at the original location as far as debugging tools are concerned.
Just do:
raise
instead of raise e. See the tutorial section on raising exceptions, and also the language reference on raise statements:
If no expressions are present, raise re-raises the last exception that was active in the current scope. If no exception is active in the current scope, a TypeError exception is raised indicating that this is an error (if running under IDLE, a Queue.Empty exception is raised instead).