126 lines
4.4 KiB
Plaintext
126 lines
4.4 KiB
Plaintext
This rule raises an issue when an `except` statement has had all its exceptions caught by a previous `except` clause.
|
|
|
|
== Why is this an issue?
|
|
|
|
Exceptions handlers (`except`) are evaluated in the order they are written. Once a match is found, the evaluation stops.
|
|
|
|
In some contexts, an except block is dead code as it will never catch any exception:
|
|
|
|
* If there is a handler for a base class followed by a handler for class derived from that base class, the second handler will never trigger: The handler for the base class will match the derived class, and will be the only executed handler.
|
|
* When multiple `except` statements try to catch the same exception class, only the first one will be executed.
|
|
* In Python 3, `BaseException` is the parent of every exception class. When a `BaseException` is caught by an `except` clause, none of the subsequent `except` statement will catch anything. This is true as well for the bare except statement (`except:`).
|
|
|
|
|
|
== How to fix it
|
|
|
|
When using multiple `except` statements, make sure to:
|
|
|
|
* Order the `except` blocks from the most specialzed exception to the most generic, i.e when wanting to catch a `FloatingPointError` and an `ArithemticError`, as `FloatingPointError` is a subclass of `ArithmeticError`, the first `except` statement should be `FloatingPointError`.
|
|
|
|
* Catch the same exception only once.
|
|
|
|
* Catch a `BaseException` only once with either an `except BaseException:` statement or a bare `except:` statement, as the two statements are equivalent.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,python,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
def foo():
|
|
try:
|
|
raise FloatingPointError()
|
|
except (ArithmeticError, RuntimeError) as e:
|
|
print(e)
|
|
except FloatingPointError as e: # Noncompliant: FloatingPointError is a subclass of ArithmeticError.
|
|
print("Never executed")
|
|
except OverflowError as e: # Noncompliant: OverflowError is a subclass of ArithmeticError.
|
|
print("Never executed")
|
|
|
|
try:
|
|
raise TypeError()
|
|
except TypeError as e:
|
|
print(e)
|
|
except TypeError as e: # Noncompliant: duplicate except.
|
|
print("Never executed")
|
|
|
|
try:
|
|
raise ValueError()
|
|
except BaseException as e:
|
|
print(e)
|
|
except: # Noncompliant: this is equivalent to "except BaseException" block.
|
|
print("Never executed")
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,python,diff-id=1,diff-type=compliant]
|
|
----
|
|
def foo():
|
|
try:
|
|
raise FloatingPointError()
|
|
except FloatingPointError as e:
|
|
print("Executed")
|
|
except OverflowError as e:
|
|
print("Executed")
|
|
except (ArithmeticError, RuntimeError) as e:
|
|
print(e)
|
|
|
|
try:
|
|
raise TypeError()
|
|
except TypeError as e:
|
|
print(e)
|
|
|
|
try:
|
|
raise ValueError()
|
|
except BaseException as e:
|
|
print(e)
|
|
----
|
|
|
|
*Note*: __It is generally not recommended to try catching `BaseException`, as it 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. See https://www.python.org/dev/peps/pep-0352/#exception-hierarchy-changes[PEP 352] for more information.__
|
|
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://docs.python.org/3/reference/compound_stmts.html#the-try-statement[The `try` statement]
|
|
* https://docs.python.org/3/library/exceptions.html#exception-hierarchy[Exception hierarchy]
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Highlighting
|
|
|
|
Primary:
|
|
|
|
* All exceptions which will never match because they are subclasses or duplicate of the first exception caught.
|
|
* The "except:" statement if "BaseException" is caught before.
|
|
|
|
Secondary:
|
|
|
|
* The exception class which shadows other except blocks.
|
|
message should be: 'Exceptions will be caught here.'
|
|
|
|
|
|
=== Message
|
|
|
|
* When a parent except block is caught before derived classes
|
|
* Catch this exception only once; it is already handled by a previous except clause.
|
|
* When the same exception class is caught multiple times:
|
|
* Catch this exception only once; it is already handled by a previous except clause.
|
|
* When an "BaseException" is caught in the same try-except as a bare "except:"
|
|
* Merge this bare "except:" with the "BaseException" catch
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
include::../comments-and-links.adoc[]
|
|
|
|
endif::env-github,rspecator-view[]
|