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