@@ -22,6 +22,158 @@ def test_undefinedInListComp(self):
22
22
''' ,
23
23
m .UndefinedName )
24
24
25
+ @skipIf (version_info < (3 ,),
26
+ 'in Python 2 exception names stay bound after the except: block' )
27
+ def test_undefinedExceptionName (self ):
28
+ """Exception names can't be used after the except: block."""
29
+ self .flakes ('''
30
+ try:
31
+ raise ValueError('ve')
32
+ except ValueError as exc:
33
+ pass
34
+ exc
35
+ ''' ,
36
+ m .UndefinedName )
37
+
38
+ def test_namesDeclaredInExceptBlocks (self ):
39
+ """Locals declared in except: blocks can be used after the block.
40
+
41
+ This shows the example in test_undefinedExceptionName is
42
+ different."""
43
+ self .flakes ('''
44
+ try:
45
+ raise ValueError('ve')
46
+ except ValueError as exc:
47
+ e = exc
48
+ e
49
+ ''' )
50
+
51
+ @skip ('error reporting disabled due to false positives below' )
52
+ def test_undefinedExceptionNameObscuringLocalVariable (self ):
53
+ """Exception names obscure locals, can't be used after.
54
+
55
+ Last line will raise UnboundLocalError on Python 3 after exiting
56
+ the except: block. Note next two examples for false positives to
57
+ watch out for."""
58
+ self .flakes ('''
59
+ exc = 'Original value'
60
+ try:
61
+ raise ValueError('ve')
62
+ except ValueError as exc:
63
+ pass
64
+ exc
65
+ ''' ,
66
+ m .UndefinedName )
67
+
68
+ def test_undefinedExceptionNameObscuringLocalVariableFalsePositive1 (self ):
69
+ """Exception names obscure locals, can't be used after. Unless.
70
+
71
+ Last line will never raise UnboundLocalError because it's only
72
+ entered if no exception was raised."""
73
+ self .flakes ('''
74
+ exc = 'Original value'
75
+ try:
76
+ raise ValueError('ve')
77
+ except ValueError as exc:
78
+ print('exception logged')
79
+ raise
80
+ exc
81
+ ''' )
82
+
83
+ def test_undefinedExceptionNameObscuringLocalVariableFalsePositive2 (self ):
84
+ """Exception names obscure locals, can't be used after. Unless.
85
+
86
+ Last line will never raise UnboundLocalError because `error` is
87
+ only falsy if the `except:` block has not been entered."""
88
+ self .flakes ('''
89
+ exc = 'Original value'
90
+ error = None
91
+ try:
92
+ raise ValueError('ve')
93
+ except ValueError as exc:
94
+ error = 'exception logged'
95
+ if error:
96
+ print(error)
97
+ else:
98
+ exc
99
+ ''' )
100
+
101
+ @skip ('error reporting disabled due to false positives below' )
102
+ def test_undefinedExceptionNameObscuringGlobalVariable (self ):
103
+ """Exception names obscure globals, can't be used after.
104
+
105
+ Last line will raise UnboundLocalError on both Python 2 and
106
+ Python 3 because the existence of that exception name creates
107
+ a local scope placeholder for it, obscuring any globals, etc."""
108
+ self .flakes ('''
109
+ exc = 'Original value'
110
+ def func():
111
+ try:
112
+ pass # nothing is raised
113
+ except ValueError as exc:
114
+ pass # block never entered, exc stays unbound
115
+ exc
116
+ ''' ,
117
+ m .UndefinedLocal )
118
+
119
+ @skip ('error reporting disabled due to false positives below' )
120
+ def test_undefinedExceptionNameObscuringGlobalVariable2 (self ):
121
+ """Exception names obscure globals, can't be used after.
122
+
123
+ Last line will raise NameError on Python 3 because the name is
124
+ locally unbound after the `except:` block, even if it's
125
+ nonlocal. We should issue an error in this case because code
126
+ only working correctly if an exception isn't raised, is invalid.
127
+ Unless it's explicitly silenced, see false positives below."""
128
+ self .flakes ('''
129
+ exc = 'Original value'
130
+ def func():
131
+ global exc
132
+ try:
133
+ raise ValueError('ve')
134
+ except ValueError as exc:
135
+ pass # block never entered, exc stays unbound
136
+ exc
137
+ ''' ,
138
+ m .UndefinedLocal )
139
+
140
+ def test_undefinedExceptionNameObscuringGlobalVariableFalsePositive1 (self ):
141
+ """Exception names obscure globals, can't be used after. Unless.
142
+
143
+ Last line will never raise NameError because it's only entered
144
+ if no exception was raised."""
145
+ self .flakes ('''
146
+ exc = 'Original value'
147
+ def func():
148
+ global exc
149
+ try:
150
+ raise ValueError('ve')
151
+ except ValueError as exc:
152
+ print('exception logged')
153
+ raise
154
+ exc
155
+ ''' )
156
+
157
+ def test_undefinedExceptionNameObscuringGlobalVariableFalsePositive2 (self ):
158
+ """Exception names obscure globals, can't be used after. Unless.
159
+
160
+ Last line will never raise NameError because `error` is only
161
+ falsy if the `except:` block has not been entered."""
162
+ self .flakes ('''
163
+ exc = 'Original value'
164
+ def func():
165
+ global exc
166
+ error = None
167
+ try:
168
+ raise ValueError('ve')
169
+ except ValueError as exc:
170
+ error = 'exception logged'
171
+ if error:
172
+ print(error)
173
+ else:
174
+ exc
175
+ ''' )
176
+
25
177
def test_functionsNeedGlobalScope (self ):
26
178
self .flakes ('''
27
179
class a:
0 commit comments