rspec/rules/S5708/python/rule.adoc
2023-07-03 09:01:04 +02:00

92 lines
3.0 KiB
Plaintext

This rule raises an issue when the expression used in an `except` statement is neither a class deriving from `BaseException` nor a tuple of such classes.
== Why is this an issue?
In Python 3's `except` statement, attempting to catch an object that does not derive from `BaseException` will raise a `TypeError`.
In order to catch multiple exceptions in an `except` statement, a `tuple` of exception classes should be provided. Trying to catch multiple exceptions with a `list` or a `set` will raise a `TypeError`.
If you are about to create a custom exception class, note that custom exceptions should inherit from ``++Exception++``, rather than ``++BaseException++``.
``++BaseException++`` is the base class for all built-in exceptions in Python, including system-exiting exceptions like ``++SystemExit++`` or ``++KeyboardInterrupt++``, which are typically not meant to be caught. On the other hand, ``++Exception++`` is intended for exceptions that are expected to be caught, which is generally the case for user-defined exceptions. See https://www.python.org/dev/peps/pep-0352/#exception-hierarchy-changes[PEP 352] for more information.
To fix this issue, make sure the expression used in an `except` statement is an exception which derives from `BaseException`/`Exception` or a tuple of such exceptions.
=== Code examples
==== Noncompliant code example
[source,python,diff-id=1,diff-type=noncompliant]
----
class CustomException(object):
"""An Invalid exception class."""
pass
try:
...
except CustomException: # Noncompliant: this custom exception does not derive from BaseException or Exception.
print("exception")
try:
...
except [TypeError, ValueError]: # Noncompliant: list of exceptions, only tuples are valid.
print("exception")
----
==== Compliant solution
[source,python,diff-id=1,diff-type=compliant]
----
class CustomException(Exception):
pass
try:
...
except CustomException:
print("exception")
try:
...
except (TypeError, ValueError):
print("exception")
----
*Note*: __In Python 2 it is possible to raise and catch old-style classes, which do not inherit from `BaseException`.__
== Resources
=== Documentation
* Python Documentation - https://docs.python.org/3/tutorial/errors.html[Errors and Exceptions]
* Python Documentation - https://docs.python.org/3/reference/compound_stmts.html#except[The `try` statement]
* Python Documentation - https://docs.python.org/3/library/exceptions.html#exception-hierarchy[Exception hierarchy]
=== Standards
* PEP 352 - https://www.python.org/dev/peps/pep-0352/#exception-hierarchy-changes[Required Superclass for Exceptions]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
* Change this expression to be a class deriving from BaseException or a tuple of such classes.
=== Highlighting
The expression which does not resolve in a valid exception class or a tuple of such classes.
'''
== Comments And Links
(visible only on this page)
include::../comments-and-links.adoc[]
endif::env-github,rspecator-view[]