Skip to content

Commit 116ce7b

Browse files
authored
Merge pull request #123 from cielavenir/raiseA002ForLambda
Introduce A006 for lambda shadowing
2 parents 5f02040 + 8702675 commit 116ce7b

File tree

4 files changed

+38
-2
lines changed

4 files changed

+38
-2
lines changed

CHANGES.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
Changelog
44
=========
55

6-
2.3.1 (unreleased)
6+
2.3.1 (2024-04-01)
77
------------------
88

9-
- Nothing changed yet.
9+
- Add rule for lambda argument shadowing (`A006`).
10+
[cielavenir]
1011

1112

1213
2.3.0 (2024-03-29)

README.rst

+3
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ A004:
104104
A005:
105105
A module is shadowing a Python builtin module (e.g: `logging` or `socket`)
106106

107+
A006:
108+
A lambda argument is shadowing a Python builtin.
109+
107110
License
108111
-------
109112
GPL 2.0

flake8_builtins.py

+18
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class BuiltinsChecker:
1515
class_attribute_msg = 'A003 class attribute "{0}" is shadowing a Python builtin'
1616
import_msg = 'A004 import statement "{0}" is shadowing a Python builtin'
1717
module_name_msg = 'A005 the module is shadowing a Python builtin module "{0}"'
18+
lambda_argument_msg = 'A006 lambda argument "{0}" is shadowing a Python builtin'
1819

1920
names = []
2021
ignore_list = {
@@ -113,6 +114,9 @@ def run(self):
113114
elif isinstance(statement, function_nodes):
114115
value = self.check_function_definition(statement)
115116

117+
elif isinstance(statement, ast.Lambda):
118+
value = self.check_lambda_definition(statement)
119+
116120
elif isinstance(statement, for_nodes):
117121
value = self.check_for_loop(statement)
118122

@@ -181,6 +185,20 @@ def check_function_definition(self, statement):
181185
variable=arg.arg,
182186
)
183187

188+
def check_lambda_definition(self, statement):
189+
all_arguments = []
190+
all_arguments.extend(statement.args.args)
191+
all_arguments.extend(getattr(statement.args, 'kwonlyargs', []))
192+
all_arguments.extend(getattr(statement.args, 'posonlyargs', []))
193+
194+
for arg in all_arguments:
195+
if isinstance(arg, ast.arg) and arg.arg in self.names:
196+
yield self.error(
197+
arg,
198+
message=self.lambda_argument_msg,
199+
variable=arg.arg,
200+
)
201+
184202
def check_for_loop(self, statement):
185203
stack = [statement.target]
186204
while stack:

run_tests.py

+14
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ def bla(list):
156156
check_code(source, 'A002')
157157

158158

159+
def test_lambda_argument_message():
160+
source = 'takefirst = lambda list: list[0]'
161+
check_code(source, 'A006')
162+
163+
159164
def test_keyword_argument_message():
160165
source = """
161166
def bla(dict=3):
@@ -182,6 +187,15 @@ def bla(list, /):
182187
"""
183188
check_code(source, 'A002')
184189

190+
@pytest.mark.skipif(
191+
sys.version_info < (3, 8),
192+
reason='This syntax is only valid in Python 3.8+',
193+
)
194+
def test_lambda_posonly_argument_message():
195+
source = """
196+
takefirst = lambda list, /: list[0]
197+
"""
198+
check_code(source, 'A006')
185199

186200
def test_no_error():
187201
source = """def bla(first):\n b = 4"""

0 commit comments

Comments
 (0)