How do I manually throw/raise an exception in Python?
Use the most specific Exception constructor that semantically fits your issue.
Be specific in your message, e.g.:
raise ValueError('A very specific bad thing happened.')
Don't raise generic exceptions
Avoid raising a generic Exception. To catch it, you'll have to catch all other more specific exceptions that subclass it.
Problem 1: Hiding bugs
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
For example:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
Problem 2: Won't catch
And more specific catches won't catch the general exception:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
Best Practices: raise statement
Instead, use the most specific Exception constructor that semantically fits your issue.
raise ValueError('A very specific bad thing happened')
which also handily allows an arbitrary number of arguments to be passed to the constructor:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
These arguments are accessed by the args attribute on the Exception object. For example:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
prints
('message', 'foo', 'bar', 'baz')
In Python 2.5, an actual message attribute was added to BaseException in favor of encouraging users to subclass Exceptions and stop using args, but the introduction of message and the original deprecation of args has been retracted.
Best Practices: except clause
When inside an except clause, you might want to, for example, log that a specific type of error happened, and then re-raise. The best way to do this while preserving the stack trace is to use a bare raise statement. For example:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Don't modify your errors... but if you insist.
You can preserve the stacktrace (and error value) with sys.exc_info(), but this is way more error prone and has compatibility problems between Python 2 and 3, prefer to use a bare raise to re-raise.
To explain - the sys.exc_info() returns the type, value, and traceback.
type, value, traceback = sys.exc_info()
This is the syntax in Python 2 - note this is not compatible with Python 3:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
If you want to, you can modify what happens with your new raise - e.g. setting new args for the instance:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
And we have preserved the whole traceback while modifying the args. Note that this is not a best practice and it is invalid syntax in Python 3 (making keeping compatibility much harder to work around).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
In Python 3:
raise error.with_traceback(sys.exc_info()[2])
Again: avoid manually manipulating tracebacks. It's less efficient and more error prone. And if you're using threading and sys.exc_info you may even get the wrong traceback (especially if you're using exception handling for control flow - which I'd personally tend to avoid.)
Python 3, Exception chaining
In Python 3, you can chain Exceptions, which preserve tracebacks:
raise RuntimeError('specific message') from error
Be aware:
- this does allow changing the error type raised, and
- this is not compatible with Python 2.
Deprecated Methods:
These can easily hide and even get into production code. You want to raise an exception, and doing them will raise an exception, but not the one intended!
Valid in Python 2, but not in Python 3 is the following:
raise ValueError, 'message' # Don't do this, it's deprecated!
Only valid in much older versions of Python (2.4 and lower), you may still see people raising strings:
raise 'message' # really really wrong. don't do this.
In all modern versions, this will actually raise a TypeError, because you're not raising a BaseException type. If you're not checking for the right exception and don't have a reviewer that's aware of the issue, it could get into production.
Example Usage
I raise Exceptions to warn consumers of my API if they're using it incorrectly:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
Create your own error types when apropos
"I want to make an error on purpose, so that it would go into the except"
You can create your own error types, if you want to indicate something specific is wrong with your application, just subclass the appropriate point in the exception hierarchy:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
and usage:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
Answer from Aaron Hall on Stack OverflowFor context, I'm primarily a database guy but have been using Python a lot lately. I know enough to figure out how to do most things I want to do, but sometimes lack the context of why certain patterns are used/preferred.
Looking through some of the code the software engineers at my organization have written in Python, they make use of try/except blocks frequently and I generally understand why. However, they're often writing except blocks that do nothing but raise the exception. For example:
def main() -> None:
try:
run_etl()
except Exception as err:
raise err
Sometimes (not always), I'll at least see logger.error(f"Encountered an exception: {err} before they raise the exception (I have no idea why they're not using logger.exception). Still, since we just let the logging module write to sys.stderr I don't know what we're really gaining.
What is the point of wrapping something in a try/except block when the only thing we're doing is raising the exception? I would understand if we were trying to handle exceptions so the program could continue or if we made use of a finally block to do some sort of post-error cleanup, but we're not. It seems to me like we're just catching the error to raise it, when we could have just let the error get raised directly.
TIA!
Manually raising (throwing) an exception in Python - Stack Overflow
try catch - How to work with try and except in python? - Stack Overflow
[SOLVED]How to catch error signals without try / except
Why raise an exception if python raises it for me? - Software Engineering Stack Exchange
How do I manually throw/raise an exception in Python?
Use the most specific Exception constructor that semantically fits your issue.
Be specific in your message, e.g.:
raise ValueError('A very specific bad thing happened.')
Don't raise generic exceptions
Avoid raising a generic Exception. To catch it, you'll have to catch all other more specific exceptions that subclass it.
Problem 1: Hiding bugs
raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.
For example:
def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))
>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)
Problem 2: Won't catch
And more specific catches won't catch the general exception:
def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')
>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling
Best Practices: raise statement
Instead, use the most specific Exception constructor that semantically fits your issue.
raise ValueError('A very specific bad thing happened')
which also handily allows an arbitrary number of arguments to be passed to the constructor:
raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz')
These arguments are accessed by the args attribute on the Exception object. For example:
try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)
prints
('message', 'foo', 'bar', 'baz')
In Python 2.5, an actual message attribute was added to BaseException in favor of encouraging users to subclass Exceptions and stop using args, but the introduction of message and the original deprecation of args has been retracted.
Best Practices: except clause
When inside an except clause, you might want to, for example, log that a specific type of error happened, and then re-raise. The best way to do this while preserving the stack trace is to use a bare raise statement. For example:
logger = logging.getLogger(__name__)
try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!
Don't modify your errors... but if you insist.
You can preserve the stacktrace (and error value) with sys.exc_info(), but this is way more error prone and has compatibility problems between Python 2 and 3, prefer to use a bare raise to re-raise.
To explain - the sys.exc_info() returns the type, value, and traceback.
type, value, traceback = sys.exc_info()
This is the syntax in Python 2 - note this is not compatible with Python 3:
raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]
If you want to, you can modify what happens with your new raise - e.g. setting new args for the instance:
def error():
raise ValueError('oops!')
def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback
And we have preserved the whole traceback while modifying the args. Note that this is not a best practice and it is invalid syntax in Python 3 (making keeping compatibility much harder to work around).
>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>
In Python 3:
raise error.with_traceback(sys.exc_info()[2])
Again: avoid manually manipulating tracebacks. It's less efficient and more error prone. And if you're using threading and sys.exc_info you may even get the wrong traceback (especially if you're using exception handling for control flow - which I'd personally tend to avoid.)
Python 3, Exception chaining
In Python 3, you can chain Exceptions, which preserve tracebacks:
raise RuntimeError('specific message') from error
Be aware:
- this does allow changing the error type raised, and
- this is not compatible with Python 2.
Deprecated Methods:
These can easily hide and even get into production code. You want to raise an exception, and doing them will raise an exception, but not the one intended!
Valid in Python 2, but not in Python 3 is the following:
raise ValueError, 'message' # Don't do this, it's deprecated!
Only valid in much older versions of Python (2.4 and lower), you may still see people raising strings:
raise 'message' # really really wrong. don't do this.
In all modern versions, this will actually raise a TypeError, because you're not raising a BaseException type. If you're not checking for the right exception and don't have a reviewer that's aware of the issue, it could get into production.
Example Usage
I raise Exceptions to warn consumers of my API if they're using it incorrectly:
def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))
Create your own error types when apropos
"I want to make an error on purpose, so that it would go into the except"
You can create your own error types, if you want to indicate something specific is wrong with your application, just subclass the appropriate point in the exception hierarchy:
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
and usage:
if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')
Don't do this. Raising a bare
Exceptionis absolutely not the right thing to do; see Aaron Hall's excellent answer instead.
It can't get much more Pythonic than this:
raise Exception("I know Python!")
Replace Exception with the specific type of exception you want to throw.
See the raise statement documentation for Python if you'd like more information.
Okey, so there a few things that need to be explained where.
What is try-except used for?
It is used for catching errors raised by the program. Any code susceptible of raising an exception is inserted inside a try statement, and below that statement, any number of except statements with any single error that you want to catch.
try:
user_input = int(input('Give me a number: '))
except ValueError:
print('That is not a number!')
When should i use try-except?
It is not a good practice to use a try-except on every single line of code that could raise an error, because that may be half of it, or more. So when shall you use it? Simple, ask this question: Do I want to do any custom action with that error being raised? If the answer is yes, you are good to go.
Catching Exception or empty except
As I see in your example, you are using an empty except. Using an empty except statement will catch every single error raised that the surrounded code, which is similar (but not the same) as catching Exception. The Exception class is the superclass of every single built-in exception in the Python environment that are non-system-exiting (read here) and its generally a bad practice to catch either all exceptions with except: or Exception with except Exception:. Why? Because you are not letting the user (or even you, the programmer) know what error you are handling. For example:
fruits = ['apple', 'pear', 'banana']
try:
selection = fruits[int(input('Select a fruit number (0-2): '))]
except Exception:
print('Error!')
# But wait, are you catching ValueError because the user did not input a number,
# or are you catching IndexError because he selected an out of bound array index?
# You don't know
Catching multiple exceptions
Based on the previous example, you can use multiple try-except statements to difference which errors are being raised.
fruits = ['apple', 'pear', 'banana']
try:
selection = fruits[int(input('Select a fruit number (0-2): '))]
except ValueError:
print('That is not a number')
except IndexError:
print('That fruit number does not exist!')
Grouping exceptions
If there are two particular exceptions that you want to use for a same purpose, you can group them in a tuple:
fruits = ['apple', 'pear', 'banana']
try:
selection = fruits[int(input('Select a fruit number (0-2): '))]
except (ValueError, IndexError):
print('Invalid selection!')
Your case
Based on this information, add those try-except blocks to your code, and see what possible errors that could be raised during its execution, asking the previously recommended question Do I want to execute some custom action with this error?
Additionally
- There are
try-except-elsestatements. See here - There are
try-except-finallystatements. See here - You can combine them all in a
try-except1-except2...exceptN-else-finallystatement. - I recommend you get familiar with built-in errors why practicing this!
try: code that might cause an errorexcept: code that runs if an error happenselse: runs if no error happensfinally: always runs (good for cleanup, closing files, etc.)
Example 1: Basic Example
try:
num = int("abc") # This will raise an error
print("Number:", num)
except ValueError:
print("Oops! Could not convert to int.")
Example 2:
try:
x = 10 / 0
except ZeroDivisionError:
print("You cannot divide by zero!")
except ValueError:
print("Invalid value!")
Example 3:
try:
x = 5 / 1
except ZeroDivisionError:
print("Division by zero not allowed.")
else:
print("Division successful:", x) # runs if no error
finally:
print("Always runs, even if there was an error.")
Example 4: General
try:
# risky code
x = 10 / 0
y = int("abc")
except Exception as e:
print("Error occurred:", e)
The answer to your question is you want meaningful exceptions.
In most contexts, this involves an exception that adds actionable information in one of two ways:
- Useful typing to the developer who might be catching the exception
- Useful error information to the user (and/or to the developer who can translate to that the user)
In your example, you aren't really adding anything to the normal exception. Catching and then effectively reraising the exception isn't useful. You could log this information, in which case you now added some value to the exception, but otherwise it's pointless.
Imagine this scenario:
try:
my_web_function()
except my_custom_web_exception:
do_something_with_this_exception()
It's entirely reasonable to imagine this scenario. You might make an http request. Most libraries have defined exception types, so you could catch those exceptions, and if it happens, do something.
The "something" is dependent on the specific application. In a http exception, maybe it's just retry the request. Etc.
But the point is catching the exception adds value and information and is actionable.
An error I encountered late last week wasn't due to a python script, but the same principle applies. I had the "privilege" of having to use an old version of subversion on a project. I mistakenly mistyped
prompt: svn co https://some.site.com/some/path
The system's response was
svn: OPTIONS of 'https://some.site.com/some/path': 200 OK (https://some.site.com)
This message was not only unhelpful, it was incorrect. (Giving someone an HTTP/HTTPS "200 OK" status when what happened was far from okay is not OK.) Moreover, there are multiple pathways in subversion 1.9 that result in that erroneous "200 OK" error message. A much more helpful message would have been to tell me that I had mistyped the repository's URL.
Strictly speaking, this was not a bug in subversion. It was just a poorly worded error message. After all, subversion did properly detect and report the problem. From a user perspective, this was a huge bug that was mostly fixed in 2010. Thankfully, a quick google search resulted in multiple hits at stackoverflow.com.
Programmers are often taught that they should simply let an exception pass through if they can't do something about it. Instructors as well as students think "doing something" means correcting the problem. In many cases, there is nothing that can be done to correct a problem. This is an overly narrow view of "doing something." Adding context that enables a user to hone in on the problem and then fix it is "doing something."
Another way of looking at letting low level exceptions bubble up is that doing so is a leaky abstraction.
In comparison to try, except, else, and finally blocks, raise statement seems not always needed. I guess it is an optional tool in exception handling that may well be redundant in some scenarios.
For example, these are the two codes with and without use of raise:
Without raise
def check_input(val):
if val < 0:
print("Input must be non-negative")
else:
print(f"Processing value: {val}")
check_input(-10)With raise:
def check_input(val):
if val < 0:
raise ValueError("Input must be non-negative")
print(f"Processing value: {val}")
try:
check_input(-10)
except ValueError as e:
print(f"Error: {e}")Given print function achieving the desired result, not sure if raise statement really needed.
You should never use except: because that catches ALL exceptions, including SystemExit, you should probably do:
try:
if not check():
raise MyNewException()
except ExceptionRaisedByCheck:
raise MyNewException()
If the exception coming from check() is the same as the one you want to raise, you should change that.
Edit: If the exception is the same, you can also simply do this (Mark Byers had this in his answer, but it's gone now):
if not check():
raise TheSameException()
This will propagate the exception or raise if False.
try:
# whatever
except MyException:
raise # reraise it
except Exception as e:
raise MyException(some_info(e)) # unify user-visible exception type
I can never seem to wrap my head around try/except and if/else. I've written a custom exception called InvalidInput. Right now, I have my main code written to raise the exception like this:
data = someString.split('.')[0]
try:
if data == 'blah':
#do more stuff
else:
raise InvalidInput('You have submitted an invalid value.")
except InvalidInput as e:
InvalidInput(e)This is a flask app so it routes the exception to this:
@main.app_errorhandler(InvalidInput) def handle_invalid_input(error): response= jsonify(error.to_dict()) response.status = error.status_code return response
The try/except block seems redundant. Do I need it or could I just raise it from the else and be done with it? I do not surround my whole entire code with a try/except, but I assume raising an exception anywhere means it gets caught by default, whether you explicitly have it contained in a try/except block or not. I assume it's bad form though to not use try/except. I've looked at a lot of stackoverflow threads but I rarely see an example like this. Please help me understand :)