1
+ < p > This rule raises an issue when an < code > except</ code > statement has had all its exceptions caught by a previous < code > except</ code > clause.</ p >
1
2
< h2 > Why is this an issue?</ h2 >
2
- < p > Exceptions handlers (< code > except: </ code > ) are evaluated in the order they are written. Once a match is found, the evaluation stops.</ p >
3
- < p > In some contexts an except block is dead code as it will never catch any exception:</ p >
3
+ < p > Exceptions handlers (< code > except</ code > ) are evaluated in the order they are written. Once a match is found, the evaluation stops.</ p >
4
+ < p > In some contexts, an except block is dead code as it will never catch any exception:</ p >
4
5
< ul >
5
6
< li > 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
6
7
handler for the base class will match the derived class, and will be the only executed handler. </ li >
7
8
< li > When multiple < code > except</ code > statements try to catch the same exception class, only the first one will be executed. </ li >
8
- < li > In python 3, < code > BaseException</ code > is the parent of every exception class. When < code > BaseException</ code > is caught and the same
9
- try-except block has a bare < code > except: </ code > statement, i.e. an < code > except</ code > with no expression, the bare except will never catch
10
- anything . </ li >
9
+ < li > In Python 3, < code > BaseException</ code > is the parent of every exception class. When a < code > BaseException</ code > is caught by an
10
+ < code > except</ code > clause, none of the subsequent < code > except</ code > statement will catch anything. This is true as well for the bare except
11
+ statement ( < code > except: </ code > ) . </ li >
11
12
</ ul >
12
- < p > This rule raises an issue when an < code > except</ code > block catches every exception before a later < code > except</ code > block could catch it.</ p >
13
- < h3 > Noncompliant code example</ h3 >
14
- < pre >
13
+ < h2 > How to fix it</ h2 >
14
+ < p > When using multiple < code > except</ code > statements, make sure to:</ p >
15
+ < ul >
16
+ < li > Order the < code > except</ code > blocks from the most specialzed exception to the most generic, i.e when wanting to catch a
17
+ < code > FloatingPointError</ code > and an < code > ArithemticError</ code > , as < code > FloatingPointError</ code > is a subclass of
18
+ < code > ArithmeticError</ code > , the first < code > except</ code > statement should be < code > FloatingPointError</ code > . </ li >
19
+ < li > Catch the same exception only once. </ li >
20
+ < li > Catch a < code > BaseException</ code > only once with either an < code > except BaseException:</ code > statement or a bare < code > except:</ code >
21
+ statement, as the two statements are equivalent. </ li >
22
+ </ ul >
23
+ < h3 > Code examples</ h3 >
24
+ < h4 > Noncompliant code example</ h4 >
25
+ < pre data-diff-id ="1 " data-diff-type ="noncompliant ">
15
26
def foo():
16
27
try:
17
28
raise FloatingPointError()
18
29
except (ArithmeticError, RuntimeError) as e:
19
30
print(e)
20
- except FloatingPointError as e: # Noncompliant. FloatingPointError is a subclass of ArithmeticError
31
+ except FloatingPointError as e: # Noncompliant: FloatingPointError is a subclass of ArithmeticError.
21
32
print("Never executed")
22
- except OverflowError as e: # Noncompliant. OverflowError is a subclass of ArithmeticError
33
+ except OverflowError as e: # Noncompliant: OverflowError is a subclass of ArithmeticError.
23
34
print("Never executed")
24
35
25
36
try:
26
37
raise TypeError()
27
38
except TypeError as e:
28
39
print(e)
29
- except TypeError as e: # Noncompliant. Duplicate Except .
40
+ except TypeError as e: # Noncompliant: duplicate except .
30
41
print("Never executed")
31
42
32
43
try:
33
44
raise ValueError()
34
45
except BaseException as e:
35
46
print(e)
36
- except: # Noncompliant. This is equivalent to "except BaseException" block
47
+ except: # Noncompliant: this is equivalent to "except BaseException" block.
37
48
print("Never executed")
38
49
</ pre >
39
- < h3 > Compliant solution</ h3 >
40
- < pre >
50
+ < h4 > Compliant solution</ h4 >
51
+ < pre data-diff-id =" 1 " data-diff-type =" compliant " >
41
52
def foo():
42
53
try:
43
54
raise FloatingPointError()
@@ -58,9 +69,13 @@ <h3>Compliant solution</h3>
58
69
except BaseException as e:
59
70
print(e)
60
71
</ pre >
72
+ < p > < strong > Note</ strong > : < em > It is generally not recommended to try catching < code > BaseException</ code > , as it is the base class for all built-in
73
+ exceptions in Python, including system-exiting exceptions like < code > SystemExit</ code > or < code > KeyboardInterrupt</ code > , which are typically not
74
+ meant to be caught. See < a href ="https://www.python.org/dev/peps/pep-0352/#exception-hierarchy-changes "> PEP 352</ a > for more information.</ em > </ p >
61
75
< h2 > Resources</ h2 >
76
+ < h3 > Documentation</ h3 >
62
77
< ul >
63
- < li > Python Documentation - < a href ="https://docs.python.org/3/reference/compound_stmts.html#the-try-statement "> The < code > try</ code > statement</ a >
64
- </ li >
78
+ < li > < a href ="https://docs.python.org/3/reference/compound_stmts.html#the-try-statement "> The < code > try</ code > statement</ a > </ li >
79
+ < li > < a href =" https://docs.python.org/3/library/exceptions.html#exception-hierarchy " > Exception hierarchy </ a > < /li >
65
80
</ ul >
66
81
0 commit comments