Skip to content

Commit

Permalink
Fix pylint-dev#5608: Emit redefined-outer-name for redefinitions of…
Browse files Browse the repository at this point in the history
… loop variables in body
  • Loading branch information
jacobtylerwalls committed Jan 8, 2022
1 parent 3fc855f commit 2de3d11
Show file tree
Hide file tree
Showing 10 changed files with 54 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .copyrite_aliases
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,10 @@
"mails": ["[email protected]", "[email protected]"],
"authoritative_mail": "[email protected]",
"name": "Tushar Sadhwani"
},
{
"mails": ["[email protected]"],
"authoritative_mail": "[email protected]",
"name": "Jacob Walls"
}
]
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ Release date: TBA
Closes #4434
Closes #5370

* Emit ``redefined-outer-name`` when a loop variable is redefined in the loop
body. Previously, only redefinitions taking place in nested loops were flagged.

Closes #5608

* ``encoding`` can now be supplied as a positional argument to calls that open
files without triggering ``unspecified-encoding``.

Expand Down
5 changes: 5 additions & 0 deletions doc/whatsnew/2.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ Other Changes
Closes #4434
Closes #5370

* Emit ``redefined-outer-name`` when a loop variable is redefined in the loop
body. Previously, only redefinitions taking place in nested loops were flagged.

Closes #5608

* ``encoding`` can now be supplied as a positional argument to calls that open
files without triggering ``unspecified-encoding``.

Expand Down
20 changes: 17 additions & 3 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,9 +482,10 @@ def _has_locals_call_after_node(stmt, scope):
"`'from X import *'` style import.",
),
"W0621": (
"Redefining name %r from outer scope (line %s)",
"Redefining name %r from outer scope or loop (line %s)",
"redefined-outer-name",
"Used when a variable's name hides a name defined in the outer scope.",
"Used when a variable's name hides a name defined in an outer scope, "
"for loop, or except handler.",
),
"W0622": (
"Redefining built-in %r",
Expand Down Expand Up @@ -740,7 +741,7 @@ class VariablesChecker(BaseChecker):
"""checks for
* unused variables / imports
* undefined variables
* redefinition of variable from builtins or from an outer scope
* redefinition of variable from builtins or from an outer scope, for loop, or except handler
* use of variable before assignment
* __all__ consistency
* self/cls assignment
Expand Down Expand Up @@ -1112,6 +1113,19 @@ def visit_global(self, node: nodes.Global) -> None:
self.add_message("global-statement", node=node)

def visit_assignname(self, node: nodes.AssignName) -> None:
if self.linter.is_message_enabled("redefined-outer-name") and isinstance(
node.parent, nodes.Assign
):
for outer_for, outer_variables in self._loop_variables:
if node.name in outer_variables and not in_for_else_branch(
outer_for, node
):
self.add_message(
"redefined-outer-name",
args=(node.name, outer_for.fromlineno),
node=node,
)
break
if isinstance(node.assign_type(), nodes.AugAssign):
self.visit_name(node)

Expand Down
1 change: 1 addition & 0 deletions tests/functional/b/bad_indentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def titii():

def tataa(kdict):
for key in ['1', '2', '3']:
# pylint: disable=redefined-outer-name
key = key.lower()

if key in kdict:
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/c/cellvar_escaping_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def good_case10():
lst = []
for i in range(10): # pylint: disable=unused-variable
def func():
i = 100
i = 100 # pylint: disable=redefined-outer-name
def func2(arg=i):
return arg

Expand Down
15 changes: 15 additions & 0 deletions tests/functional/r/redefined_loop_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""Tests for redefinitions of loop variables inside the loop body.
See: https://github.com/PyCQA/pylint/issues/5608
"""
# pylint: disable=invalid-name

lines = ["1\t", "2\t"]
for line in lines:
line = line.strip() # [redefined-outer-name]

lines = [(1, "1\t"), (2, "2\t")]
for i, line in lines:
line = line.strip() # [redefined-outer-name]

line = "no warning"
2 changes: 2 additions & 0 deletions tests/functional/r/redefined_loop_name.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
redefined-outer-name:9:4:9:8::Redefining name 'line' from outer scope (line 8):UNDEFINED
redefined-outer-name:13:4:13:8::Redefining name 'line' from outer scope (line 12):UNDEFINED
2 changes: 1 addition & 1 deletion tests/functional/u/undefined/undefined_loop_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def do_else(some_random_list):
VAR2 = B # nor this one

for var1, var2 in TEST_LC:
var1 = var2 + 4
var1 = var2 + 4 # pylint: disable=redefined-outer-name
VAR3 = var1 # [undefined-loop-variable]

for note in __revision__:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

for k, v in b_dict.items():
print(k)
k = "another key"
k = "another key" # pylint: disable=redefined-outer-name
print(b_dict[k]) # This is fine, key reassigned


Expand Down Expand Up @@ -68,7 +68,7 @@ class Foo:
for item in d.items():
print(item[0])
print(d[item[0]]) # [unnecessary-dict-index-lookup]
item = (2, "b")
item = (2, "b") # pylint: disable=redefined-outer-name
print(d[item[0]]) # This is fine, no warning thrown as key has been reassigned


Expand Down

0 comments on commit 2de3d11

Please sign in to comment.