Skip to content

Commit b080a21

Browse files
Fix inconsistent used-before-assignment for partial bindings (#10975)
Signed-off-by: Emmanuel Ferdman <[email protected]>
1 parent 0e3b9eb commit b080a21

7 files changed

Lines changed: 59 additions & 41 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix ``used-before-assignment`` false positive for names bound in only some arms of an ``if/elif/else`` chain.
2+
3+
Closes #9879

pylint/checkers/variables.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -740,10 +740,10 @@ def _inferred_to_define_name_raise_or_return_for_if_node(
740740
# Search both if and else branches
741741
if_branch_handles = self._branch_handles_name(name, node.body)
742742
else_branch_handles = self._branch_handles_name(name, node.orelse)
743-
if if_branch_handles ^ else_branch_handles:
743+
if if_branch_handles and else_branch_handles:
744+
self.names_defined_under_one_branch_only.discard(name)
745+
elif if_branch_handles ^ else_branch_handles:
744746
self.names_defined_under_one_branch_only.add(name)
745-
elif name in self.names_defined_under_one_branch_only:
746-
self.names_defined_under_one_branch_only.remove(name)
747747
return if_branch_handles and else_branch_handles
748748

749749
def _branch_handles_name(self, name: str, body: Iterable[nodes.NodeNG]) -> bool:
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""Regression test for https://github.com/pylint-dev/pylint/issues/9879"""
2+
# pylint: disable=missing-function-docstring
3+
4+
5+
def func(mode):
6+
if mode == "a":
7+
pass
8+
elif mode == "b":
9+
x = 1
10+
elif mode == "c":
11+
pass
12+
else:
13+
assert False
14+
print(x) # [possibly-used-before-assignment]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
possibly-used-before-assignment:14:10:14:11:func:Possibly using variable 'x' before assignment:CONTROL_FLOW
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
undefined-variable:79:20:79:27:MyClass.incorrect_default_method:Undefined variable 'MyClass':UNDEFINED
22
possibly-used-before-assignment:171:14:171:20:TypeCheckingMultiBranch.defined_in_elif_branch:Possibly using variable 'bisect' before assignment:INFERENCE
33
possibly-used-before-assignment:172:15:172:23:TypeCheckingMultiBranch.defined_in_elif_branch:Possibly using variable 'calendar' before assignment:INFERENCE
4-
used-before-assignment:175:14:175:22:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'zoneinfo' before assignment:INFERENCE
5-
used-before-assignment:176:14:176:20:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'pprint' before assignment:INFERENCE
6-
used-before-assignment:177:14:177:25:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'collections' before assignment:INFERENCE
4+
possibly-used-before-assignment:175:14:175:22:TypeCheckingMultiBranch.defined_in_else_branch:Possibly using variable 'zoneinfo' before assignment:INFERENCE
5+
possibly-used-before-assignment:176:14:176:20:TypeCheckingMultiBranch.defined_in_else_branch:Possibly using variable 'pprint' before assignment:INFERENCE
6+
possibly-used-before-assignment:177:14:177:25:TypeCheckingMultiBranch.defined_in_else_branch:Possibly using variable 'collections' before assignment:INFERENCE
77
possibly-used-before-assignment:181:14:181:19:TypeCheckingMultiBranch.defined_in_nested_if_else:Possibly using variable 'heapq' before assignment:INFERENCE
8-
used-before-assignment:185:14:185:19:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'types' before assignment:INFERENCE
9-
used-before-assignment:186:14:186:18:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'copy' before assignment:INFERENCE
10-
used-before-assignment:187:14:187:21:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'numbers' before assignment:INFERENCE
11-
used-before-assignment:188:15:188:20:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'array' before assignment:INFERENCE
12-
used-before-assignment:191:14:191:19:TypeCheckingMultiBranch.defined_in_loops:Using variable 'email' before assignment:INFERENCE
13-
used-before-assignment:192:14:192:21:TypeCheckingMultiBranch.defined_in_loops:Using variable 'mailbox' before assignment:INFERENCE
14-
used-before-assignment:193:14:193:23:TypeCheckingMultiBranch.defined_in_loops:Using variable 'mimetypes' before assignment:INFERENCE
15-
used-before-assignment:197:14:197:22:TypeCheckingMultiBranch.defined_in_with:Using variable 'binascii' before assignment:INFERENCE
8+
possibly-used-before-assignment:185:14:185:19:TypeCheckingMultiBranch.defined_in_try_except:Possibly using variable 'types' before assignment:INFERENCE
9+
possibly-used-before-assignment:186:14:186:18:TypeCheckingMultiBranch.defined_in_try_except:Possibly using variable 'copy' before assignment:INFERENCE
10+
possibly-used-before-assignment:187:14:187:21:TypeCheckingMultiBranch.defined_in_try_except:Possibly using variable 'numbers' before assignment:INFERENCE
11+
possibly-used-before-assignment:188:15:188:20:TypeCheckingMultiBranch.defined_in_try_except:Possibly using variable 'array' before assignment:INFERENCE
12+
possibly-used-before-assignment:191:14:191:19:TypeCheckingMultiBranch.defined_in_loops:Possibly using variable 'email' before assignment:INFERENCE
13+
possibly-used-before-assignment:192:14:192:21:TypeCheckingMultiBranch.defined_in_loops:Possibly using variable 'mailbox' before assignment:INFERENCE
14+
possibly-used-before-assignment:193:14:193:23:TypeCheckingMultiBranch.defined_in_loops:Possibly using variable 'mimetypes' before assignment:INFERENCE
15+
possibly-used-before-assignment:197:14:197:22:TypeCheckingMultiBranch.defined_in_with:Possibly using variable 'binascii' before assignment:INFERENCE

tests/functional/u/used/used_before_assignment_typing.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -172,29 +172,29 @@ def defined_in_elif_branch(self) -> calendar.Calendar: # <3.14:[possibly-used-b
172172
return calendar.Calendar() # >=3.14:[possibly-used-before-assignment]
173173

174174
def defined_in_else_branch(self) -> urlopen:
175-
print(zoneinfo) # [used-before-assignment]
176-
print(pprint()) # [used-before-assignment]
177-
print(collections()) # [used-before-assignment]
175+
print(zoneinfo) # [possibly-used-before-assignment]
176+
print(pprint()) # [possibly-used-before-assignment]
177+
print(collections()) # [possibly-used-before-assignment]
178178
return urlopen
179179

180180
def defined_in_nested_if_else(self) -> heapq: # <3.14:[possibly-used-before-assignment]
181181
print(heapq) # >=3.14:[possibly-used-before-assignment]
182182
return heapq
183183

184-
def defined_in_try_except(self) -> array: # <3.14:[used-before-assignment]
185-
print(types) # [used-before-assignment]
186-
print(copy) # [used-before-assignment]
187-
print(numbers) # [used-before-assignment]
188-
return array # >=3.14:[used-before-assignment]
184+
def defined_in_try_except(self) -> array: # <3.14:[possibly-used-before-assignment]
185+
print(types) # [possibly-used-before-assignment]
186+
print(copy) # [possibly-used-before-assignment]
187+
print(numbers) # [possibly-used-before-assignment]
188+
return array # >=3.14:[possibly-used-before-assignment]
189189

190-
def defined_in_loops(self) -> json: # <3.14:[used-before-assignment]
191-
print(email) # [used-before-assignment]
192-
print(mailbox) # [used-before-assignment]
193-
print(mimetypes) # [used-before-assignment]
190+
def defined_in_loops(self) -> json: # <3.14:[possibly-used-before-assignment]
191+
print(email) # [possibly-used-before-assignment]
192+
print(mailbox) # [possibly-used-before-assignment]
193+
print(mimetypes) # [possibly-used-before-assignment]
194194
return json
195195

196-
def defined_in_with(self) -> base64: # <3.14:[used-before-assignment]
197-
print(binascii) # [used-before-assignment]
196+
def defined_in_with(self) -> base64: # <3.14:[possibly-used-before-assignment]
197+
print(binascii) # [possibly-used-before-assignment]
198198
return base64
199199

200200

tests/functional/u/used/used_before_assignment_typing.txt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ used-before-assignment:140:35:140:39:MyFourthClass.is_close:Using variable 'math
55
used-before-assignment:153:20:153:28:VariableAnnotationsGuardedByTypeChecking:Using variable 'datetime' before assignment:INFERENCE
66
possibly-used-before-assignment:170:40:170:48:TypeCheckingMultiBranch.defined_in_elif_branch:Possibly using variable 'calendar' before assignment:INFERENCE
77
possibly-used-before-assignment:171:14:171:20:TypeCheckingMultiBranch.defined_in_elif_branch:Possibly using variable 'bisect' before assignment:INFERENCE
8-
used-before-assignment:175:14:175:22:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'zoneinfo' before assignment:INFERENCE
9-
used-before-assignment:176:14:176:20:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'pprint' before assignment:INFERENCE
10-
used-before-assignment:177:14:177:25:TypeCheckingMultiBranch.defined_in_else_branch:Using variable 'collections' before assignment:INFERENCE
8+
possibly-used-before-assignment:175:14:175:22:TypeCheckingMultiBranch.defined_in_else_branch:Possibly using variable 'zoneinfo' before assignment:INFERENCE
9+
possibly-used-before-assignment:176:14:176:20:TypeCheckingMultiBranch.defined_in_else_branch:Possibly using variable 'pprint' before assignment:INFERENCE
10+
possibly-used-before-assignment:177:14:177:25:TypeCheckingMultiBranch.defined_in_else_branch:Possibly using variable 'collections' before assignment:INFERENCE
1111
possibly-used-before-assignment:180:43:180:48:TypeCheckingMultiBranch.defined_in_nested_if_else:Possibly using variable 'heapq' before assignment:INFERENCE
12-
used-before-assignment:184:39:184:44:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'array' before assignment:INFERENCE
13-
used-before-assignment:185:14:185:19:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'types' before assignment:INFERENCE
14-
used-before-assignment:186:14:186:18:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'copy' before assignment:INFERENCE
15-
used-before-assignment:187:14:187:21:TypeCheckingMultiBranch.defined_in_try_except:Using variable 'numbers' before assignment:INFERENCE
16-
used-before-assignment:190:34:190:38:TypeCheckingMultiBranch.defined_in_loops:Using variable 'json' before assignment:INFERENCE
17-
used-before-assignment:191:14:191:19:TypeCheckingMultiBranch.defined_in_loops:Using variable 'email' before assignment:INFERENCE
18-
used-before-assignment:192:14:192:21:TypeCheckingMultiBranch.defined_in_loops:Using variable 'mailbox' before assignment:INFERENCE
19-
used-before-assignment:193:14:193:23:TypeCheckingMultiBranch.defined_in_loops:Using variable 'mimetypes' before assignment:INFERENCE
20-
used-before-assignment:196:33:196:39:TypeCheckingMultiBranch.defined_in_with:Using variable 'base64' before assignment:INFERENCE
21-
used-before-assignment:197:14:197:22:TypeCheckingMultiBranch.defined_in_with:Using variable 'binascii' before assignment:INFERENCE
12+
possibly-used-before-assignment:184:39:184:44:TypeCheckingMultiBranch.defined_in_try_except:Possibly using variable 'array' before assignment:INFERENCE
13+
possibly-used-before-assignment:185:14:185:19:TypeCheckingMultiBranch.defined_in_try_except:Possibly using variable 'types' before assignment:INFERENCE
14+
possibly-used-before-assignment:186:14:186:18:TypeCheckingMultiBranch.defined_in_try_except:Possibly using variable 'copy' before assignment:INFERENCE
15+
possibly-used-before-assignment:187:14:187:21:TypeCheckingMultiBranch.defined_in_try_except:Possibly using variable 'numbers' before assignment:INFERENCE
16+
possibly-used-before-assignment:190:34:190:38:TypeCheckingMultiBranch.defined_in_loops:Possibly using variable 'json' before assignment:INFERENCE
17+
possibly-used-before-assignment:191:14:191:19:TypeCheckingMultiBranch.defined_in_loops:Possibly using variable 'email' before assignment:INFERENCE
18+
possibly-used-before-assignment:192:14:192:21:TypeCheckingMultiBranch.defined_in_loops:Possibly using variable 'mailbox' before assignment:INFERENCE
19+
possibly-used-before-assignment:193:14:193:23:TypeCheckingMultiBranch.defined_in_loops:Possibly using variable 'mimetypes' before assignment:INFERENCE
20+
possibly-used-before-assignment:196:33:196:39:TypeCheckingMultiBranch.defined_in_with:Possibly using variable 'base64' before assignment:INFERENCE
21+
possibly-used-before-assignment:197:14:197:22:TypeCheckingMultiBranch.defined_in_with:Possibly using variable 'binascii' before assignment:INFERENCE

0 commit comments

Comments
 (0)