What's the proper way to declare custom exception classes in modern Python? My primary goal is to follow whatever standard other exception classes have, so that (for instance) any extra string I include in the exception is printed out by whatever tool caught the exception.
By "modern Python" I mean something that will run in Python 2.5 but be 'correct' for the Python 2.6 and Python 3.* way of doing things. And by "custom" I mean an Exception object that can include extra data about the cause of the error: a string, maybe also some other arbitrary object relevant to the exception.
I was tripped up by the following deprecation warning in Python 2.6.2:
>>> class MyError(Exception):
... def __init__(self, message):
... self.message = message
...
>>> MyError("foo")
_sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
It seems crazy that BaseException has a special meaning for attributes named message. I gather from PEP-352 that attribute did have a special meaning in 2.5 they're trying to deprecate away, so I guess that name (and that one alone) is now forbidden? Ugh.
I'm also fuzzily aware that Exception has some magic parameter args, but I've never known how to use it. Nor am I sure it's the right way to do things going forward; a lot of the discussion I found online suggested they were trying to do away with args in Python 3.
Update: two answers have suggested overriding __init__, and __str__/__unicode__/__repr__. That seems like a lot of typing, is it necessary?
Maybe I missed the question, but why not:
class MyException(Exception):
pass
To override something (or pass extra args), do this:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super().__init__(message)
# Now for your custom code...
self.errors = errors
That way you could pass dict of error messages to the second param, and get to it later with e.errors.
In Python 2, you have to use this slightly more complex form of super():
super(ValidationError, self).__init__(message)
With modern Python Exceptions, you don't need to abuse .message, or override .__str__() or .__repr__() or any of it. If all you want is an informative message when your exception is raised, do this:
class MyException(Exception):
pass
raise MyException("My hovercraft is full of eels")
That will give a traceback ending with MyException: My hovercraft is full of eels.
If you want more flexibility from the exception, you could pass a dictionary as the argument:
raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
However, to get at those details in an except block is a bit more complicated. The details are stored in the args attribute, which is a list. You would need to do something like this:
try:
raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
except MyException as e:
details = e.args[0]
print(details["animal"])
It is still possible to pass in multiple items to the exception and access them via tuple indexes, but this is highly discouraged (and was even intended for deprecation a while back). If you do need more than a single piece of information and the above method is not sufficient for you, then you should subclass Exception as described in the tutorial.
class MyError(Exception):
def __init__(self, message, animal):
self.message = message
self.animal = animal
def __str__(self):
return self.message
"What is the proper way to declare custom exceptions in modern Python?"
This is fine unless your exception is really a type of a more specific exception:
class MyException(Exception):
pass
Or better (maybe perfect), instead of pass give a docstring:
class MyException(Exception):
"""Raise for my specific kind of exception"""
Subclassing Exception Subclasses
From the docs
Exception
All built-in, non-system-exiting exceptions are derived from this class.
All user-defined exceptions should also be derived from this
class.
That means that if your exception is a type of a more specific exception, subclass that exception instead of the generic Exception (and the result will be that you still derive from Exception as the docs recommend). Also, you can at least provide a docstring (and not be forced to use the pass keyword):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
Set attributes you create yourself with a custom __init__. Avoid passing a dict as a positional argument, future users of your code will thank you. If you use the deprecated message attribute, assigning it yourself will avoid a DeprecationWarning:
class MyAppValueError(ValueError):
'''Raise when a specific subset of values in context of app is wrong'''
def __init__(self, message, foo, *args):
self.message = message # without this you may get DeprecationWarning
# Special attribute you desire with your Error,
# perhaps the value that caused the error?:
self.foo = foo
# allow users initialize misc. arguments as any other builtin Error
super(MyAppValueError, self).__init__(message, foo, *args)
There's really no need to write your own __str__ or __repr__. The built-in ones are very nice, and your cooperative inheritance ensures that you use them.
Critique of the top answer
Maybe I missed the question, but why not:
class MyException(Exception):
pass
Again, the problem with the above is that in order to catch it, you'll either have to name it specifically (importing it if created elsewhere) or catch Exception, (but you're probably not prepared to handle all types of Exceptions, and you should only catch exceptions you are prepared to handle). Similar criticism to the below, but additionally that's not the way to initialize via super, and you'll get a DeprecationWarning if you access the message attribute:
Edit: to override something (or pass extra args), do this:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super(ValidationError, self).__init__(message)
# Now for your custom code...
self.errors = errors
That way you could pass dict of error messages to the second param, and get to it later with e.errors
It also requires exactly two arguments to be passed in (aside from the self.) No more, no less. That's an interesting constraint that future users may not appreciate.
To be direct - it violates Liskov substitutability.
I'll demonstrate both errors:
>>> ValidationError('foo', 'bar', 'baz').message
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
ValidationError('foo', 'bar', 'baz').message
TypeError: __init__() takes exactly 3 arguments (4 given)
>>> ValidationError('foo', 'bar').message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foo'
Compared to:
>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'
see how exceptions work by default if one vs more attributes are used (tracebacks omitted):
>>> raise Exception('bad thing happened')
Exception: bad thing happened
>>> raise Exception('bad thing happened', 'code is broken')
Exception: ('bad thing happened', 'code is broken')
so you might want to have a sort of "exception template", working as an exception itself, in a compatible way:
>>> nastyerr = NastyError('bad thing happened')
>>> raise nastyerr
NastyError: bad thing happened
>>> raise nastyerr()
NastyError: bad thing happened
>>> raise nastyerr('code is broken')
NastyError: ('bad thing happened', 'code is broken')
this can be done easily with this subclass
class ExceptionTemplate(Exception):
def __call__(self, *args):
return self.__class__(*(self.args + args))
# ...
class NastyError(ExceptionTemplate): pass
and if you don't like that default tuple-like representation, just add __str__ method to the ExceptionTemplate class, like:
# ...
def __str__(self):
return ': '.join(self.args)
and you'll have
>>> raise nastyerr('code is broken')
NastyError: bad thing happened: code is broken
As of Python 3.8 (2018, https://docs.python.org/dev/whatsnew/3.8.html), the recommended method is still:
class CustomExceptionName(Exception):
"""Exception raised when very uncommon things happen"""
pass
Please don't forget to document, why a custom exception is neccessary!
If you need to, this is the way to go for exceptions with more data:
class CustomExceptionName(Exception):
"""Still an exception raised when uncommon things happen"""
def __init__(self, message, payload=None):
self.message = message
self.payload = payload # you could add more args
def __str__(self):
return str(self.message) # __str__() obviously expects a string to be returned, so make sure not to send any other data types
and fetch them like:
try:
raise CustomExceptionName("Very bad mistake.", "Forgot upgrading from Python 1")
except CustomExceptionName as error:
print(str(error)) # Very bad mistake
print("Detail: {}".format(error.payload)) # Detail: Forgot upgrading from Python 1
payload=None is important to make it pickle-able. Before dumping it, you have to call error.__reduce__(). Loading will work as expected.
You maybe should investigate in finding a solution using pythons return statement if you need much data to be transferred to some outer structure. This seems to be clearer/more pythonic to me. Advanced exceptions are heavily used in Java, which can sometimes be annoying, when using a framework and having to catch all possible errors.
To define your own exceptions correctly, there are a few best practices that you should follow:
Define a base class inheriting from Exception. This will allow to easily catch any exceptions related to the project:
class MyProjectError(Exception):
"""A base class for MyProject exceptions."""
Organizing the exception classes in a separate module (e.g. exceptions.py) is generally a good idea.
To create a specific exception, subclass the base exception class.
class CustomError(MyProjectError):
"""A custom exception class for MyProject."""
You can subclass custom exception classes as well to create a hierarchy.
To add support for extra argument(s) to a custom exception, define an __init__() method with a variable number of arguments. Call the base class's __init__(), passing any positional arguments to it (remember that BaseException/Exception expect any number of positional arguments). Store extra keyword arguments to the instance, e.g.:
class CustomError(MyProjectError):
def __init__(self, *args, **kwargs):
super().__init__(*args)
self.custom_kwarg = kwargs.get('custom_kwargs')
Usage example:
try:
raise CustomError('Something bad happened', custom_kwarg='value')
except CustomError as exc:
print(f'Сaught CustomError exception with custom_kwarg={exc.custom_kwarg}')
This design adheres to the Liskov substitution principle, since you can replace an instance of a base exception class with an instance of a derived exception class. Also, it allows you to create an instance of a derived class with the same parameters as the parent.
You should override __repr__ or __unicode__ methods instead of using message, the args you provide when you construct the exception will be in the args attribute of the exception object.
See a very good article "The definitive guide to Python exceptions". The basic principles are:
Always inherit from (at least) Exception.
Always call BaseException.__init__ with only one argument.
When building a library, define a base class inheriting from Exception.
Provide details about the error.
Inherit from builtin exceptions types when it makes sense.
There is also information on organizing (in modules) and wrapping exceptions, I recommend to read the guide.
No, "message" is not forbidden. It's just deprecated. You application will work fine with using message. But you may want to get rid of the deprecation error, of course.
When you create custom Exception classes for your application, many of them do not subclass just from Exception, but from others, like ValueError or similar. Then you have to adapt to their usage of variables.
And if you have many exceptions in your application it's usually a good idea to have a common custom base class for all of them, so that users of your modules can do
try:
...
except NelsonsExceptions:
...
And in that case you can do __init__ and __str__ needed there, so you don't have to repeat it for every exception. But simply calling the message variable something else than message does the trick.
In any case, you only need __init__ or __str__ if you do something different from what Exception itself does. And because if the deprecation, you then need both, or you get an error. That's not a whole lot of extra code you need per class.
For maximum customisation, to define custom errors, you may want to define an intermediate class that inherits from Exception class as:
class BaseCustomException(Exception):
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return self.msg
class MyCustomError(BaseCustomException):
"""raise my custom error"""
Try this Example
class InvalidInputError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
inp = int(input("Enter a number between 1 to 10:"))
try:
if type(inp) != int or inp not in list(range(1,11)):
raise InvalidInputError
except InvalidInputError:
print("Invalid input entered")
A really simple approach:
class CustomError(Exception):
pass
raise CustomError("Hmm, seems like this was custom coded...")
Or, have the error raise without printing __main__ (may look cleaner and neater):
class CustomError(Exception):
__module__ = Exception.__module__
raise CustomError("Improved CustomError!")
I had issues with the above methods, as of Python 3.9.5.
However, I found that this works for me:
class MyException(Exception):
"""Port Exception"""
And then it could be used in code like:
try:
raise MyException('Message')
except MyException as err:
print (err)
I came across this thread. This is how I do custom exceptions. While the Fault class is slightly complex, it makes declaring custom expressive exceptions with variable arguments trivial.
FinalViolation, SingletonViolation are both sub classes of TypeError so will be caught code below.
try:
<do something>
except TypeError as ex:
<handler>
That's why Fault doesn't inherit from Exception. To allow derivative exceptions to inherit from the exception of their choice.
class Fault:
"""Generic Exception base class. Note not descendant of Exception
Inheriting exceptions override formats"""
formats = '' # to be overriden in descendant classes
def __init__(self, *args):
"""Just save args for __str__"""
self.args = args
def __str__(self):
"""Use formats declared in descendant classes, and saved args to build exception text"""
return self.formats.format(*self.args)
class TypeFault(Fault, TypeError):
"""Helper class mixing Fault and TypeError"""
class FinalViolation(TypeFault):
"""Custom exception raised if inheriting from 'final' class"""
formats = "type {} is not an acceptable base type. It cannot be inherited from."
class SingletonViolation(TypeFault):
"""Custom exception raised if instancing 'singleton' class a second time"""
formats = "type {} is a singleton. It can only be instanced once."
FinalViolation, SingletonViolation unfortunately only accept 1 argument.
But one could easily create a multi arg error e.g.
class VesselLoadingError(Fault, BufferError):
formats = "My {} is full of {}."
raise VesselLoadingError('hovercraft', 'eels')
__main__.VesselLoadingError: My hovercraft is full of eels.
For me it is just __init__ and variables but making sometimes testing.
My sample:
Error_codes = { 100: "Not enough parameters", 101: "Number of special characters more than limits", 102: "At least 18 alphanumeric characters and list of special chars !##$&*" }
class localbreak( Exception ) :
Message = ""
def __init__(self, Message):
self.Message = Message
return
def __str__(self):
print(self.Message)
return "False"
### When calling ...
raise localbreak(Error_codes[102])
Output:
Traceback (most recent call last): File "ASCII.py", line 150, in <module>
main(OldPassword, Newpassword) File "ASCII.py", line 39, in main
result = read_input("1", "2", Newpassword, "4")
File "ASCII.py", line 69, in read_input
raise localbreak(Error_codes[102]) At least 18 alphanumeric characters and list of special chars !##$&*
__main__.localbreak: False
Related
What's the proper way to declare custom exception classes in modern Python? My primary goal is to follow whatever standard other exception classes have, so that (for instance) any extra string I include in the exception is printed out by whatever tool caught the exception.
By "modern Python" I mean something that will run in Python 2.5 but be 'correct' for the Python 2.6 and Python 3.* way of doing things. And by "custom" I mean an Exception object that can include extra data about the cause of the error: a string, maybe also some other arbitrary object relevant to the exception.
I was tripped up by the following deprecation warning in Python 2.6.2:
>>> class MyError(Exception):
... def __init__(self, message):
... self.message = message
...
>>> MyError("foo")
_sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
It seems crazy that BaseException has a special meaning for attributes named message. I gather from PEP-352 that attribute did have a special meaning in 2.5 they're trying to deprecate away, so I guess that name (and that one alone) is now forbidden? Ugh.
I'm also fuzzily aware that Exception has some magic parameter args, but I've never known how to use it. Nor am I sure it's the right way to do things going forward; a lot of the discussion I found online suggested they were trying to do away with args in Python 3.
Update: two answers have suggested overriding __init__, and __str__/__unicode__/__repr__. That seems like a lot of typing, is it necessary?
Maybe I missed the question, but why not:
class MyException(Exception):
pass
To override something (or pass extra args), do this:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super().__init__(message)
# Now for your custom code...
self.errors = errors
That way you could pass dict of error messages to the second param, and get to it later with e.errors.
In Python 2, you have to use this slightly more complex form of super():
super(ValidationError, self).__init__(message)
With modern Python Exceptions, you don't need to abuse .message, or override .__str__() or .__repr__() or any of it. If all you want is an informative message when your exception is raised, do this:
class MyException(Exception):
pass
raise MyException("My hovercraft is full of eels")
That will give a traceback ending with MyException: My hovercraft is full of eels.
If you want more flexibility from the exception, you could pass a dictionary as the argument:
raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
However, to get at those details in an except block is a bit more complicated. The details are stored in the args attribute, which is a list. You would need to do something like this:
try:
raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
except MyException as e:
details = e.args[0]
print(details["animal"])
It is still possible to pass in multiple items to the exception and access them via tuple indexes, but this is highly discouraged (and was even intended for deprecation a while back). If you do need more than a single piece of information and the above method is not sufficient for you, then you should subclass Exception as described in the tutorial.
class MyError(Exception):
def __init__(self, message, animal):
self.message = message
self.animal = animal
def __str__(self):
return self.message
"What is the proper way to declare custom exceptions in modern Python?"
This is fine unless your exception is really a type of a more specific exception:
class MyException(Exception):
pass
Or better (maybe perfect), instead of pass give a docstring:
class MyException(Exception):
"""Raise for my specific kind of exception"""
Subclassing Exception Subclasses
From the docs
Exception
All built-in, non-system-exiting exceptions are derived from this class.
All user-defined exceptions should also be derived from this
class.
That means that if your exception is a type of a more specific exception, subclass that exception instead of the generic Exception (and the result will be that you still derive from Exception as the docs recommend). Also, you can at least provide a docstring (and not be forced to use the pass keyword):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
Set attributes you create yourself with a custom __init__. Avoid passing a dict as a positional argument, future users of your code will thank you. If you use the deprecated message attribute, assigning it yourself will avoid a DeprecationWarning:
class MyAppValueError(ValueError):
'''Raise when a specific subset of values in context of app is wrong'''
def __init__(self, message, foo, *args):
self.message = message # without this you may get DeprecationWarning
# Special attribute you desire with your Error,
# perhaps the value that caused the error?:
self.foo = foo
# allow users initialize misc. arguments as any other builtin Error
super(MyAppValueError, self).__init__(message, foo, *args)
There's really no need to write your own __str__ or __repr__. The built-in ones are very nice, and your cooperative inheritance ensures that you use them.
Critique of the top answer
Maybe I missed the question, but why not:
class MyException(Exception):
pass
Again, the problem with the above is that in order to catch it, you'll either have to name it specifically (importing it if created elsewhere) or catch Exception, (but you're probably not prepared to handle all types of Exceptions, and you should only catch exceptions you are prepared to handle). Similar criticism to the below, but additionally that's not the way to initialize via super, and you'll get a DeprecationWarning if you access the message attribute:
Edit: to override something (or pass extra args), do this:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super(ValidationError, self).__init__(message)
# Now for your custom code...
self.errors = errors
That way you could pass dict of error messages to the second param, and get to it later with e.errors
It also requires exactly two arguments to be passed in (aside from the self.) No more, no less. That's an interesting constraint that future users may not appreciate.
To be direct - it violates Liskov substitutability.
I'll demonstrate both errors:
>>> ValidationError('foo', 'bar', 'baz').message
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
ValidationError('foo', 'bar', 'baz').message
TypeError: __init__() takes exactly 3 arguments (4 given)
>>> ValidationError('foo', 'bar').message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foo'
Compared to:
>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'
see how exceptions work by default if one vs more attributes are used (tracebacks omitted):
>>> raise Exception('bad thing happened')
Exception: bad thing happened
>>> raise Exception('bad thing happened', 'code is broken')
Exception: ('bad thing happened', 'code is broken')
so you might want to have a sort of "exception template", working as an exception itself, in a compatible way:
>>> nastyerr = NastyError('bad thing happened')
>>> raise nastyerr
NastyError: bad thing happened
>>> raise nastyerr()
NastyError: bad thing happened
>>> raise nastyerr('code is broken')
NastyError: ('bad thing happened', 'code is broken')
this can be done easily with this subclass
class ExceptionTemplate(Exception):
def __call__(self, *args):
return self.__class__(*(self.args + args))
# ...
class NastyError(ExceptionTemplate): pass
and if you don't like that default tuple-like representation, just add __str__ method to the ExceptionTemplate class, like:
# ...
def __str__(self):
return ': '.join(self.args)
and you'll have
>>> raise nastyerr('code is broken')
NastyError: bad thing happened: code is broken
As of Python 3.8 (2018, https://docs.python.org/dev/whatsnew/3.8.html), the recommended method is still:
class CustomExceptionName(Exception):
"""Exception raised when very uncommon things happen"""
pass
Please don't forget to document, why a custom exception is neccessary!
If you need to, this is the way to go for exceptions with more data:
class CustomExceptionName(Exception):
"""Still an exception raised when uncommon things happen"""
def __init__(self, message, payload=None):
self.message = message
self.payload = payload # you could add more args
def __str__(self):
return str(self.message) # __str__() obviously expects a string to be returned, so make sure not to send any other data types
and fetch them like:
try:
raise CustomExceptionName("Very bad mistake.", "Forgot upgrading from Python 1")
except CustomExceptionName as error:
print(str(error)) # Very bad mistake
print("Detail: {}".format(error.payload)) # Detail: Forgot upgrading from Python 1
payload=None is important to make it pickle-able. Before dumping it, you have to call error.__reduce__(). Loading will work as expected.
You maybe should investigate in finding a solution using pythons return statement if you need much data to be transferred to some outer structure. This seems to be clearer/more pythonic to me. Advanced exceptions are heavily used in Java, which can sometimes be annoying, when using a framework and having to catch all possible errors.
To define your own exceptions correctly, there are a few best practices that you should follow:
Define a base class inheriting from Exception. This will allow to easily catch any exceptions related to the project:
class MyProjectError(Exception):
"""A base class for MyProject exceptions."""
Organizing the exception classes in a separate module (e.g. exceptions.py) is generally a good idea.
To create a specific exception, subclass the base exception class.
class CustomError(MyProjectError):
"""A custom exception class for MyProject."""
You can subclass custom exception classes as well to create a hierarchy.
To add support for extra argument(s) to a custom exception, define an __init__() method with a variable number of arguments. Call the base class's __init__(), passing any positional arguments to it (remember that BaseException/Exception expect any number of positional arguments). Store extra keyword arguments to the instance, e.g.:
class CustomError(MyProjectError):
def __init__(self, *args, **kwargs):
super().__init__(*args)
self.custom_kwarg = kwargs.get('custom_kwargs')
Usage example:
try:
raise CustomError('Something bad happened', custom_kwarg='value')
except CustomError as exc:
print(f'Сaught CustomError exception with custom_kwarg={exc.custom_kwarg}')
This design adheres to the Liskov substitution principle, since you can replace an instance of a base exception class with an instance of a derived exception class. Also, it allows you to create an instance of a derived class with the same parameters as the parent.
You should override __repr__ or __unicode__ methods instead of using message, the args you provide when you construct the exception will be in the args attribute of the exception object.
See a very good article "The definitive guide to Python exceptions". The basic principles are:
Always inherit from (at least) Exception.
Always call BaseException.__init__ with only one argument.
When building a library, define a base class inheriting from Exception.
Provide details about the error.
Inherit from builtin exceptions types when it makes sense.
There is also information on organizing (in modules) and wrapping exceptions, I recommend to read the guide.
No, "message" is not forbidden. It's just deprecated. You application will work fine with using message. But you may want to get rid of the deprecation error, of course.
When you create custom Exception classes for your application, many of them do not subclass just from Exception, but from others, like ValueError or similar. Then you have to adapt to their usage of variables.
And if you have many exceptions in your application it's usually a good idea to have a common custom base class for all of them, so that users of your modules can do
try:
...
except NelsonsExceptions:
...
And in that case you can do __init__ and __str__ needed there, so you don't have to repeat it for every exception. But simply calling the message variable something else than message does the trick.
In any case, you only need __init__ or __str__ if you do something different from what Exception itself does. And because if the deprecation, you then need both, or you get an error. That's not a whole lot of extra code you need per class.
For maximum customisation, to define custom errors, you may want to define an intermediate class that inherits from Exception class as:
class BaseCustomException(Exception):
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return self.msg
class MyCustomError(BaseCustomException):
"""raise my custom error"""
Try this Example
class InvalidInputError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
inp = int(input("Enter a number between 1 to 10:"))
try:
if type(inp) != int or inp not in list(range(1,11)):
raise InvalidInputError
except InvalidInputError:
print("Invalid input entered")
A really simple approach:
class CustomError(Exception):
pass
raise CustomError("Hmm, seems like this was custom coded...")
Or, have the error raise without printing __main__ (may look cleaner and neater):
class CustomError(Exception):
__module__ = Exception.__module__
raise CustomError("Improved CustomError!")
I had issues with the above methods, as of Python 3.9.5.
However, I found that this works for me:
class MyException(Exception):
"""Port Exception"""
And then it could be used in code like:
try:
raise MyException('Message')
except MyException as err:
print (err)
I came across this thread. This is how I do custom exceptions. While the Fault class is slightly complex, it makes declaring custom expressive exceptions with variable arguments trivial.
FinalViolation, SingletonViolation are both sub classes of TypeError so will be caught code below.
try:
<do something>
except TypeError as ex:
<handler>
That's why Fault doesn't inherit from Exception. To allow derivative exceptions to inherit from the exception of their choice.
class Fault:
"""Generic Exception base class. Note not descendant of Exception
Inheriting exceptions override formats"""
formats = '' # to be overriden in descendant classes
def __init__(self, *args):
"""Just save args for __str__"""
self.args = args
def __str__(self):
"""Use formats declared in descendant classes, and saved args to build exception text"""
return self.formats.format(*self.args)
class TypeFault(Fault, TypeError):
"""Helper class mixing Fault and TypeError"""
class FinalViolation(TypeFault):
"""Custom exception raised if inheriting from 'final' class"""
formats = "type {} is not an acceptable base type. It cannot be inherited from."
class SingletonViolation(TypeFault):
"""Custom exception raised if instancing 'singleton' class a second time"""
formats = "type {} is a singleton. It can only be instanced once."
FinalViolation, SingletonViolation unfortunately only accept 1 argument.
But one could easily create a multi arg error e.g.
class VesselLoadingError(Fault, BufferError):
formats = "My {} is full of {}."
raise VesselLoadingError('hovercraft', 'eels')
__main__.VesselLoadingError: My hovercraft is full of eels.
For me it is just __init__ and variables but making sometimes testing.
My sample:
Error_codes = { 100: "Not enough parameters", 101: "Number of special characters more than limits", 102: "At least 18 alphanumeric characters and list of special chars !##$&*" }
class localbreak( Exception ) :
Message = ""
def __init__(self, Message):
self.Message = Message
return
def __str__(self):
print(self.Message)
return "False"
### When calling ...
raise localbreak(Error_codes[102])
Output:
Traceback (most recent call last): File "ASCII.py", line 150, in <module>
main(OldPassword, Newpassword) File "ASCII.py", line 39, in main
result = read_input("1", "2", Newpassword, "4")
File "ASCII.py", line 69, in read_input
raise localbreak(Error_codes[102]) At least 18 alphanumeric characters and list of special chars !##$&*
__main__.localbreak: False
I would like to implement a way to globally handle exceptions in a class coming through my application rather than handle them at the call site because it will cause a lot of duplicate code.
For example's sake say I have a class like so:
class handler():
def throws_value_error(self):
raise ValueError
def throws_not_implemented_error(self):
raise NotImplementedError
# ... Imagine there are hundreds of these
In this handler class I'd like all ValueError and NotImplementedError handled the same way - a message saying [ERROR]: ... where ... is the details from the particular instance.
Instead of reproducing a TON of:
try:
#...
except Exception as e:
# Catch the instances of the exception and handle them
# in more-or-less the same way here
I'd like to have a single method implementable on the class that takes care of this in general:
def exception_watcher(self):
# Big if...elif...else for handling these types of exceptions
Then, this method would be invoked when any Exception inside the class is given.
My motivation is to use this to implement a generic sort of controller interface where a controller method could throw a subclass of an exception (for example - BadRequestException which is subclassed from Error400Exception). From there, the handler could dispatch a method to properly configure a response with an error code tailored to the type of exception, and additionally return a useful reply to the consumer.
Obviously this is doable without this dispatcher - but this way certainly saves a ton of duplicated code (and therefore bugs).
I've done a lot of digging around the internet and I haven't found anything. Admittedly I am borrowing this pattern from the Spring Boot Framework. I will also accept this being non-pythonic as an answer (as long as you can tell me how to do it right!)
Any help would be appreciated - thank you!
Modifying functions without altering their core functionality is exactly what decorators are for. Take a look at this example and try running it:
def catch_exception(func):
def wrapped(self, *args, **kwargs):
try:
return func(self, *args, **kwargs)
except ValueError:
self.value_error_handler()
except NotImplementedError:
self.ni_error_handler()
return wrapped
class Handler:
def value_error_handler(self):
print("found value error")
def ni_error_handler(self):
print("found not implemented error")
#catch_exception
def value_error_raiser(self):
raise ValueError
#catch_exception
def ni_error_raiser(self):
raise NotImplementedError
h = Handler()
h.value_error_raiser()
h.ni_error_raiser()
Because of the #catch_exception decorator, the decorated methods do not raise the errors shown when caled; instead, they call the respective method defined inside wrapped's try/except block, printing a message.
While this is not exactly what you asked for, I believe this solution is more manageable overall. You can both choose exactly what methods should raise exceptions regularly and which should be handled by catch_exception (by deciding which methods are decorated), and add future behaviour for other exception types by writing an extra except block inside wrapped and adding the respective method to the Handler class.
Note that this is not a "clean" solution, since wrapped expects to know that self is an instance of Handler, seeing as it calls a bunch of its methods, even though it is a function outside the Handler class... But hey, that's Python's duck typing for you :-P
This question already has answers here:
How to use "pass" statement?
(18 answers)
Closed 8 years ago.
I have not seen the keyword pass used much in Python, except for the occasional exception, such as in here: Why is "except: pass" a bad programming practice? Are there any other example use-cases of pass which are acceptable/okay programming practice?
One use is to define a "stub" class or method that has a name but doesn't do anything. Maybe the most common case of this is to define a custom Exception class:
class MyCustomException(Exception):
pass
Now you can raise and catch exceptions of this type. The class exists only to be raised and caught, and doesn't need any behavior associated with it.
In similar fashion, APIs may include "do-nothing" functions that are meant to be overridden in subclasses:
class SomeComplexAPI(object):
# This method may be overridden in subclasses, but the base-class implementation is a no-op
def someAPIHook(self):
pass
If you didn't define the method at all, SomeComplexAPI().someAPIHook() would raise an exception because the method doesn't exist. Defining it with pass makes sure you can safely call it even if it doesn't do anything.
Here are a few instances where I find myself using pass:
Renaming a class
This is a really common use. 99% of the time it's the Exception class, because it's the easiest way to avoid the bad practice of raising/excepting general exceptions. Example:
class MyModuleException(Exception):
pass
Declaring a method on a parent class
If subclasses will all be expected to provide a certain method (and that method doesn't have default behavior) I will often define it on the parent class just for documentation purposes. Example:
class Lifeform(object):
def acquire_energy(source, amount):
"""
All Lifeforms must acquire energy from a source to survive, but they
all do it differently.
"""
pass
Preventing default behavior of inherited methods:
I use this sparingly because generally if you don't want a parent class's method it's a sign that you should either refactor the class hierarchy or that you should have a mix-in class that provides that method. Example:
class Pig(Animal):
def fly(destination):
"""Pigs can't fly!"""
pass
Notice here that a better solution would be to add a CapableOfFlight mix-in and remove the Animal.fly() method.
To complement the other good answers, one more case where I find myself using pass is in functions with complex flow, where I want to add comments clarifying the flow. E.g.:
if A:
if B:
...
else: # (added only to make the comment below more readable)
# A and not B: nothing to do because ...
pass
The else block in this example is obviously not necessary, but I sometimes add it just for making my commentary more readable.
As a way to prevent default behavior (for one example)?
class myClass(MySuper):
def overriddenmethod(self):
pass # Calls to instances of this class will do nothing when this method is called.
pass is useful if you want to make a custom exception:
>>> class MyException(Exception):
... pass
...
>>> raise MyException("error!")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyException: error!
>>>
>>>
>>> try:
... raise MyException
... except MyException:
... print("error!")
...
error!
>>>
In the above example, nothing needs to go inside the class MyException because all I want is a custom exception by that name. So, I use pass as a placeholder to prevent the IndentationError that is raised by not placing anything under the class MyException(Exception) line:
>>> class MyExcpetion(Exception):
...
File "<stdin>", line 2
^
IndentationError: expected an indented block
>>>
>>> class MyExcpetion(Exception):
... pass
...
>>>
I'm trying to override the printed output from an Exception subclass in Python after the exception has been raised and I'm having no luck getting my override to actually be called.
def str_override(self):
"""
Override the output with a fixed string
"""
return "Override!"
def reraise(exception):
"""
Re-raise an exception and override its output
"""
exception.__str__ = types.MethodType(str_override, exception, type(exception))
# Re-raise and remove ourselves from the stack trace.
raise exception, None, sys.exc_info()[-1]
def test():
"""
Should output "Override!" Actually outputs "Bah Humbug"
"""
try:
try:
raise Exception("Bah Humbug")
except Exception, e:
reraise(e, "Said Scrooge")
except Exception, e:
print e
Any idea why this doesn't actually override the str method? Introspecting the instance variables shows that the method is actually overridden with the method but it's like Python just refuses to call it through print.
What am I missing here?
The problem is not that __str__() doesn't get overriden (just like you've already said, it does), but rather that str(e) (which invisibly gets called by print) is not always equivalent to e.__str__(). More specifically, if I get it right, str() (and other special methods, such as repr()), won't look for str in the instance dictionary - it would only look for it in the class dictionary. At least that is the case for the so-called new-style classes (which are the only classes in Python 3.x IIRC). You can read more about it here:
http://mail.python.org/pipermail/python-bugs-list/2005-December/031438.html
If you want to change the exception error message for a reraised exception, you can do something like this instead:
def reraise(exception):
"""
Re-raise an exception and override its output
"""
exType = type(exception)
newExType = type(exType.__name__ + "_Override", (exType,), { '__str__': str_override})
exception.__class__ = newExType
# Re-raise and remove ourselves from the stack trace.
raise exception, None, sys.exc_info()[-1]
This will dynamically derive a new exception class with the str override, and change exception to be an instance of that class. Now your code should work.
http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes states that "For new-style classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary". IOW, you can't just assign a method to some_instance.__str__. Also, Monkey Patching will not work on builtin types like exceptions. Which you wouldn't want anyway, not even for a non-builtin exception class, since that patch would change the behaviour of all instances of that class.
If you're feelin' kinda hackish you could instead do something like:
...
except DaUncoolException, e:
e.args = ('cool override stuff!',) + e.args[1:]
raise
I don't like this very much, though. Why would you want to do such a thing anyway?
What's the proper way to declare custom exception classes in modern Python? My primary goal is to follow whatever standard other exception classes have, so that (for instance) any extra string I include in the exception is printed out by whatever tool caught the exception.
By "modern Python" I mean something that will run in Python 2.5 but be 'correct' for the Python 2.6 and Python 3.* way of doing things. And by "custom" I mean an Exception object that can include extra data about the cause of the error: a string, maybe also some other arbitrary object relevant to the exception.
I was tripped up by the following deprecation warning in Python 2.6.2:
>>> class MyError(Exception):
... def __init__(self, message):
... self.message = message
...
>>> MyError("foo")
_sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
It seems crazy that BaseException has a special meaning for attributes named message. I gather from PEP-352 that attribute did have a special meaning in 2.5 they're trying to deprecate away, so I guess that name (and that one alone) is now forbidden? Ugh.
I'm also fuzzily aware that Exception has some magic parameter args, but I've never known how to use it. Nor am I sure it's the right way to do things going forward; a lot of the discussion I found online suggested they were trying to do away with args in Python 3.
Update: two answers have suggested overriding __init__, and __str__/__unicode__/__repr__. That seems like a lot of typing, is it necessary?
Maybe I missed the question, but why not:
class MyException(Exception):
pass
To override something (or pass extra args), do this:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super().__init__(message)
# Now for your custom code...
self.errors = errors
That way you could pass dict of error messages to the second param, and get to it later with e.errors.
In Python 2, you have to use this slightly more complex form of super():
super(ValidationError, self).__init__(message)
With modern Python Exceptions, you don't need to abuse .message, or override .__str__() or .__repr__() or any of it. If all you want is an informative message when your exception is raised, do this:
class MyException(Exception):
pass
raise MyException("My hovercraft is full of eels")
That will give a traceback ending with MyException: My hovercraft is full of eels.
If you want more flexibility from the exception, you could pass a dictionary as the argument:
raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
However, to get at those details in an except block is a bit more complicated. The details are stored in the args attribute, which is a list. You would need to do something like this:
try:
raise MyException({"message":"My hovercraft is full of animals", "animal":"eels"})
except MyException as e:
details = e.args[0]
print(details["animal"])
It is still possible to pass in multiple items to the exception and access them via tuple indexes, but this is highly discouraged (and was even intended for deprecation a while back). If you do need more than a single piece of information and the above method is not sufficient for you, then you should subclass Exception as described in the tutorial.
class MyError(Exception):
def __init__(self, message, animal):
self.message = message
self.animal = animal
def __str__(self):
return self.message
"What is the proper way to declare custom exceptions in modern Python?"
This is fine unless your exception is really a type of a more specific exception:
class MyException(Exception):
pass
Or better (maybe perfect), instead of pass give a docstring:
class MyException(Exception):
"""Raise for my specific kind of exception"""
Subclassing Exception Subclasses
From the docs
Exception
All built-in, non-system-exiting exceptions are derived from this class.
All user-defined exceptions should also be derived from this
class.
That means that if your exception is a type of a more specific exception, subclass that exception instead of the generic Exception (and the result will be that you still derive from Exception as the docs recommend). Also, you can at least provide a docstring (and not be forced to use the pass keyword):
class MyAppValueError(ValueError):
'''Raise when my specific value is wrong'''
Set attributes you create yourself with a custom __init__. Avoid passing a dict as a positional argument, future users of your code will thank you. If you use the deprecated message attribute, assigning it yourself will avoid a DeprecationWarning:
class MyAppValueError(ValueError):
'''Raise when a specific subset of values in context of app is wrong'''
def __init__(self, message, foo, *args):
self.message = message # without this you may get DeprecationWarning
# Special attribute you desire with your Error,
# perhaps the value that caused the error?:
self.foo = foo
# allow users initialize misc. arguments as any other builtin Error
super(MyAppValueError, self).__init__(message, foo, *args)
There's really no need to write your own __str__ or __repr__. The built-in ones are very nice, and your cooperative inheritance ensures that you use them.
Critique of the top answer
Maybe I missed the question, but why not:
class MyException(Exception):
pass
Again, the problem with the above is that in order to catch it, you'll either have to name it specifically (importing it if created elsewhere) or catch Exception, (but you're probably not prepared to handle all types of Exceptions, and you should only catch exceptions you are prepared to handle). Similar criticism to the below, but additionally that's not the way to initialize via super, and you'll get a DeprecationWarning if you access the message attribute:
Edit: to override something (or pass extra args), do this:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super(ValidationError, self).__init__(message)
# Now for your custom code...
self.errors = errors
That way you could pass dict of error messages to the second param, and get to it later with e.errors
It also requires exactly two arguments to be passed in (aside from the self.) No more, no less. That's an interesting constraint that future users may not appreciate.
To be direct - it violates Liskov substitutability.
I'll demonstrate both errors:
>>> ValidationError('foo', 'bar', 'baz').message
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
ValidationError('foo', 'bar', 'baz').message
TypeError: __init__() takes exactly 3 arguments (4 given)
>>> ValidationError('foo', 'bar').message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foo'
Compared to:
>>> MyAppValueError('foo', 'FOO', 'bar').message
'foo'
see how exceptions work by default if one vs more attributes are used (tracebacks omitted):
>>> raise Exception('bad thing happened')
Exception: bad thing happened
>>> raise Exception('bad thing happened', 'code is broken')
Exception: ('bad thing happened', 'code is broken')
so you might want to have a sort of "exception template", working as an exception itself, in a compatible way:
>>> nastyerr = NastyError('bad thing happened')
>>> raise nastyerr
NastyError: bad thing happened
>>> raise nastyerr()
NastyError: bad thing happened
>>> raise nastyerr('code is broken')
NastyError: ('bad thing happened', 'code is broken')
this can be done easily with this subclass
class ExceptionTemplate(Exception):
def __call__(self, *args):
return self.__class__(*(self.args + args))
# ...
class NastyError(ExceptionTemplate): pass
and if you don't like that default tuple-like representation, just add __str__ method to the ExceptionTemplate class, like:
# ...
def __str__(self):
return ': '.join(self.args)
and you'll have
>>> raise nastyerr('code is broken')
NastyError: bad thing happened: code is broken
As of Python 3.8 (2018, https://docs.python.org/dev/whatsnew/3.8.html), the recommended method is still:
class CustomExceptionName(Exception):
"""Exception raised when very uncommon things happen"""
pass
Please don't forget to document, why a custom exception is neccessary!
If you need to, this is the way to go for exceptions with more data:
class CustomExceptionName(Exception):
"""Still an exception raised when uncommon things happen"""
def __init__(self, message, payload=None):
self.message = message
self.payload = payload # you could add more args
def __str__(self):
return str(self.message) # __str__() obviously expects a string to be returned, so make sure not to send any other data types
and fetch them like:
try:
raise CustomExceptionName("Very bad mistake.", "Forgot upgrading from Python 1")
except CustomExceptionName as error:
print(str(error)) # Very bad mistake
print("Detail: {}".format(error.payload)) # Detail: Forgot upgrading from Python 1
payload=None is important to make it pickle-able. Before dumping it, you have to call error.__reduce__(). Loading will work as expected.
You maybe should investigate in finding a solution using pythons return statement if you need much data to be transferred to some outer structure. This seems to be clearer/more pythonic to me. Advanced exceptions are heavily used in Java, which can sometimes be annoying, when using a framework and having to catch all possible errors.
To define your own exceptions correctly, there are a few best practices that you should follow:
Define a base class inheriting from Exception. This will allow to easily catch any exceptions related to the project:
class MyProjectError(Exception):
"""A base class for MyProject exceptions."""
Organizing the exception classes in a separate module (e.g. exceptions.py) is generally a good idea.
To create a specific exception, subclass the base exception class.
class CustomError(MyProjectError):
"""A custom exception class for MyProject."""
You can subclass custom exception classes as well to create a hierarchy.
To add support for extra argument(s) to a custom exception, define an __init__() method with a variable number of arguments. Call the base class's __init__(), passing any positional arguments to it (remember that BaseException/Exception expect any number of positional arguments). Store extra keyword arguments to the instance, e.g.:
class CustomError(MyProjectError):
def __init__(self, *args, **kwargs):
super().__init__(*args)
self.custom_kwarg = kwargs.get('custom_kwargs')
Usage example:
try:
raise CustomError('Something bad happened', custom_kwarg='value')
except CustomError as exc:
print(f'Сaught CustomError exception with custom_kwarg={exc.custom_kwarg}')
This design adheres to the Liskov substitution principle, since you can replace an instance of a base exception class with an instance of a derived exception class. Also, it allows you to create an instance of a derived class with the same parameters as the parent.
You should override __repr__ or __unicode__ methods instead of using message, the args you provide when you construct the exception will be in the args attribute of the exception object.
See a very good article "The definitive guide to Python exceptions". The basic principles are:
Always inherit from (at least) Exception.
Always call BaseException.__init__ with only one argument.
When building a library, define a base class inheriting from Exception.
Provide details about the error.
Inherit from builtin exceptions types when it makes sense.
There is also information on organizing (in modules) and wrapping exceptions, I recommend to read the guide.
No, "message" is not forbidden. It's just deprecated. You application will work fine with using message. But you may want to get rid of the deprecation error, of course.
When you create custom Exception classes for your application, many of them do not subclass just from Exception, but from others, like ValueError or similar. Then you have to adapt to their usage of variables.
And if you have many exceptions in your application it's usually a good idea to have a common custom base class for all of them, so that users of your modules can do
try:
...
except NelsonsExceptions:
...
And in that case you can do __init__ and __str__ needed there, so you don't have to repeat it for every exception. But simply calling the message variable something else than message does the trick.
In any case, you only need __init__ or __str__ if you do something different from what Exception itself does. And because if the deprecation, you then need both, or you get an error. That's not a whole lot of extra code you need per class.
For maximum customisation, to define custom errors, you may want to define an intermediate class that inherits from Exception class as:
class BaseCustomException(Exception):
def __init__(self, msg):
self.msg = msg
def __repr__(self):
return self.msg
class MyCustomError(BaseCustomException):
"""raise my custom error"""
Try this Example
class InvalidInputError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
inp = int(input("Enter a number between 1 to 10:"))
try:
if type(inp) != int or inp not in list(range(1,11)):
raise InvalidInputError
except InvalidInputError:
print("Invalid input entered")
A really simple approach:
class CustomError(Exception):
pass
raise CustomError("Hmm, seems like this was custom coded...")
Or, have the error raise without printing __main__ (may look cleaner and neater):
class CustomError(Exception):
__module__ = Exception.__module__
raise CustomError("Improved CustomError!")
I had issues with the above methods, as of Python 3.9.5.
However, I found that this works for me:
class MyException(Exception):
"""Port Exception"""
And then it could be used in code like:
try:
raise MyException('Message')
except MyException as err:
print (err)
I came across this thread. This is how I do custom exceptions. While the Fault class is slightly complex, it makes declaring custom expressive exceptions with variable arguments trivial.
FinalViolation, SingletonViolation are both sub classes of TypeError so will be caught code below.
try:
<do something>
except TypeError as ex:
<handler>
That's why Fault doesn't inherit from Exception. To allow derivative exceptions to inherit from the exception of their choice.
class Fault:
"""Generic Exception base class. Note not descendant of Exception
Inheriting exceptions override formats"""
formats = '' # to be overriden in descendant classes
def __init__(self, *args):
"""Just save args for __str__"""
self.args = args
def __str__(self):
"""Use formats declared in descendant classes, and saved args to build exception text"""
return self.formats.format(*self.args)
class TypeFault(Fault, TypeError):
"""Helper class mixing Fault and TypeError"""
class FinalViolation(TypeFault):
"""Custom exception raised if inheriting from 'final' class"""
formats = "type {} is not an acceptable base type. It cannot be inherited from."
class SingletonViolation(TypeFault):
"""Custom exception raised if instancing 'singleton' class a second time"""
formats = "type {} is a singleton. It can only be instanced once."
FinalViolation, SingletonViolation unfortunately only accept 1 argument.
But one could easily create a multi arg error e.g.
class VesselLoadingError(Fault, BufferError):
formats = "My {} is full of {}."
raise VesselLoadingError('hovercraft', 'eels')
__main__.VesselLoadingError: My hovercraft is full of eels.
For me it is just __init__ and variables but making sometimes testing.
My sample:
Error_codes = { 100: "Not enough parameters", 101: "Number of special characters more than limits", 102: "At least 18 alphanumeric characters and list of special chars !##$&*" }
class localbreak( Exception ) :
Message = ""
def __init__(self, Message):
self.Message = Message
return
def __str__(self):
print(self.Message)
return "False"
### When calling ...
raise localbreak(Error_codes[102])
Output:
Traceback (most recent call last): File "ASCII.py", line 150, in <module>
main(OldPassword, Newpassword) File "ASCII.py", line 39, in main
result = read_input("1", "2", Newpassword, "4")
File "ASCII.py", line 69, in read_input
raise localbreak(Error_codes[102]) At least 18 alphanumeric characters and list of special chars !##$&*
__main__.localbreak: False