rspec/rules/S5754/python/rule.adoc

112 lines
3.7 KiB
Plaintext
Raw Normal View History

2023-08-04 16:50:19 +02:00
This rule raises an issue when a bare ``++except:++``, an ``++except BaseException++`` or an ``++except SystemExit++`` block does not re-raise the exception caught.
== Why is this an issue?
2023-08-04 16:50:19 +02:00
A https://docs.python.org/3/library/exceptions.html#SystemExit[``++SystemExit++``] exception is raised when https://docs.python.org/3/library/sys.html#sys.exit[``++sys.exit()++``] is called.
This exception is used to signal the interpreter to exit. The exception is expected to propagate up until the program stops.
It is possible to catch this exception in order to perform, for example, clean-up tasks. It should, however, be raised again to allow the interpreter to exit as expected.
Not re-raising such exception could lead to undesired behaviour.
2021-04-28 16:49:39 +02:00
2023-08-04 16:50:19 +02:00
A https://docs.python.org/3/reference/compound_stmts.html#the-try-statement[bare ``++except:++`` statement], i.e. an `except` block without any exception class, is equivalent to https://docs.python.org/3/library/exceptions.html#BaseException[``++except BaseException++``].
Both statements will catch every exceptions, including `SystemExit`. It is recommended to catch instead a more specific exception.
If it is not possible, the exception should be raised again.
2021-04-28 16:49:39 +02:00
2023-08-04 16:50:19 +02:00
It is also a good idea to re-raise the https://docs.python.org/3/library/exceptions.html#KeyboardInterrupt[``++KeyboardInterrupt++``] exception. Similarly to `SystemExit`,`KeyboardInterrupt` is used to signal the interpreter to exit. Not re-raising such exception could also lead to undesired behaviour.
2021-04-28 16:49:39 +02:00
2023-08-04 16:50:19 +02:00
== How to fix it
2021-04-28 16:49:39 +02:00
2023-08-04 16:50:19 +02:00
Re-raise `SystemExit`, `BaseException` and any exceptions caught in a bare `except` clause.
2021-04-28 16:49:39 +02:00
2023-08-04 16:50:19 +02:00
=== Code examples
2023-08-04 16:50:19 +02:00
==== Noncompliant code example
2021-04-28 16:49:39 +02:00
2023-08-04 16:50:19 +02:00
[source,python,diff-id=1,diff-type=noncompliant]
2021-04-28 16:49:39 +02:00
----
try:
2023-08-04 16:50:19 +02:00
...
except SystemExit: # Noncompliant: the SystemExit exception is not re-raised.
2021-04-28 16:49:39 +02:00
pass
try:
2023-08-04 16:50:19 +02:00
...
except BaseException: # Noncompliant: BaseExceptions encompass SystemExit exceptions and should be re-raised.
2021-04-28 16:49:39 +02:00
pass
2023-08-04 16:50:19 +02:00
try:
...
except: # Noncompliant: exceptions caught by this statement should be re-raised or a more specific exception should be caught.
2021-04-28 16:49:39 +02:00
pass
----
2023-08-04 16:50:19 +02:00
==== Compliant solution
2021-04-28 16:49:39 +02:00
2023-08-04 16:50:19 +02:00
[source,python,diff-id=1,diff-type=compliant]
2021-04-28 16:49:39 +02:00
----
try:
2023-08-04 16:50:19 +02:00
...
except SystemExit as e:
...
raise e
2021-04-28 16:49:39 +02:00
try:
2023-08-04 16:50:19 +02:00
...
2021-04-28 16:49:39 +02:00
except BaseException as e:
2023-08-04 16:50:19 +02:00
...
2021-04-28 16:49:39 +02:00
raise e
try:
2023-08-04 16:50:19 +02:00
...
2021-04-28 16:49:39 +02:00
except FileNotFoundError:
2023-08-04 16:50:19 +02:00
... # Handle a more specific exception
2021-04-28 16:49:39 +02:00
----
== Resources
2021-04-28 16:49:39 +02:00
2023-08-04 16:50:19 +02:00
=== Documentation
2021-04-28 16:49:39 +02:00
* PEP 352 - https://www.python.org/dev/peps/pep-0352/#id5[Required Superclass for Exceptions]
* Python Documentation - https://docs.python.org/3/library/exceptions.html[Built-in exceptions]
* Python Documentation - https://docs.python.org/3/reference/compound_stmts.html#the-try-statement[The ``++try++`` statement]
2023-08-04 16:50:19 +02:00
* CWE - https://cwe.mitre.org/data/definitions/391[MITRE, CWE-391, Unchecked Error Condition]
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
* if it is a bare "except:":
* specify an exception class to catch or reraise the exception.
* if it catches a BaseException:
* catch a more specific exception or reraise the exception.
* if SystemExit is caught:the application as the user expects.
=== Highlighting
the "except" statement
'''
== Comments And Links
(visible only on this page)
=== relates to: S1181
=== relates to: S2142
=== relates to: S2738
=== on 6 Mar 2020, 15:05:41 Nicolas Harraudeau wrote:
This rule is similar to RSPEC-2142 but this one is a code smell because python 2 forced developers to use a bare ``++except:++`` for a long time. Thus old projects will have many issues. Yet even in python 2 it is possible to handle properly the exception. Thus we raise a code smell issue for both python 2 and python 3.
endif::env-github,rspecator-view[]