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?

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.


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.


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.  

== How to fix it

Re-raise `SystemExit`, `BaseException` and any exceptions caught in a bare `except` clause.

=== Code examples

==== Noncompliant code example

[source,python,diff-id=1,diff-type=noncompliant]
----
try:
    ...
except SystemExit:  # Noncompliant: the SystemExit exception is not re-raised.
    pass

try:
    ...
except BaseException:  # Noncompliant: BaseExceptions encompass SystemExit exceptions and should be re-raised.
    pass

try:
    ...
except:  # Noncompliant: exceptions caught by this statement should be re-raised or a more specific exception should be caught.
    pass
----


==== Compliant solution

[source,python,diff-id=1,diff-type=compliant]
----
try:
    ...
except SystemExit as e:
    ...
    raise e

try:
    ...
except BaseException as e:
    ...
    raise e

try:
    ...
except FileNotFoundError:
    ... # Handle a more specific exception
----


== Resources

=== Documentation

* 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]
* 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[]
