From cb97ac8eb208be3745bbd8a0752acfb8c4169ad1 Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 18 Mar 2024 15:21:36 +0900 Subject: [PATCH 1/5] Raise A002 for lambda --- flake8_builtins.py | 4 ++-- run_tests.py | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/flake8_builtins.py b/flake8_builtins.py index 1473b9f..224006f 100644 --- a/flake8_builtins.py +++ b/flake8_builtins.py @@ -58,7 +58,7 @@ def run(self): for child in ast.iter_child_nodes(statement): child.__flake8_builtins_parent = statement - function_nodes = [ast.FunctionDef] + function_nodes = [ast.FunctionDef, ast.Lambda] if getattr(ast, 'AsyncFunctionDef', None): function_nodes.append(ast.AsyncFunctionDef) function_nodes = tuple(function_nodes) @@ -136,7 +136,7 @@ def check_assignment(self, statement): stack.extend(list(item.value.elts)) def check_function_definition(self, statement): - if statement.name in self.names: + if not isinstance(statement, ast.Lambda) and statement.name in self.names: msg = self.assign_msg if type(statement.__flake8_builtins_parent) is ast.ClassDef: msg = self.class_attribute_msg diff --git a/run_tests.py b/run_tests.py index 522edec..bc831be 100644 --- a/run_tests.py +++ b/run_tests.py @@ -140,6 +140,11 @@ def bla(list): check_code(source, 'A002') +def test_lambda_argument_message(): + source = 'takefirst = lambda list: list[0]' + check_code(source, 'A002') + + def test_keyword_argument_message(): source = """ def bla(dict=3): From 9c95b9c7e9409a9db7fac36c74ec32497228492c Mon Sep 17 00:00:00 2001 From: cielavenir Date: Wed, 20 Mar 2024 11:01:01 +0900 Subject: [PATCH 2/5] introduce A005 for lambda --- flake8_builtins.py | 22 ++++++++++++++++++++-- run_tests.py | 11 ++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/flake8_builtins.py b/flake8_builtins.py index 224006f..472f3a9 100644 --- a/flake8_builtins.py +++ b/flake8_builtins.py @@ -12,6 +12,7 @@ class BuiltinsChecker: argument_msg = 'A002 argument "{0}" is shadowing a Python builtin' class_attribute_msg = 'A003 class attribute "{0}" is shadowing a Python builtin' import_msg = 'A004 import statement "{0}" is shadowing a Python builtin' + lambda_argument_msg = 'A005 lambda argument "{0}" is shadowing a Python builtin' names = [] ignore_list = { @@ -58,7 +59,7 @@ def run(self): for child in ast.iter_child_nodes(statement): child.__flake8_builtins_parent = statement - function_nodes = [ast.FunctionDef, ast.Lambda] + function_nodes = [ast.FunctionDef] if getattr(ast, 'AsyncFunctionDef', None): function_nodes.append(ast.AsyncFunctionDef) function_nodes = tuple(function_nodes) @@ -88,6 +89,9 @@ def run(self): elif isinstance(statement, function_nodes): value = self.check_function_definition(statement) + elif isinstance(statement, ast.Lambda): + value = self.check_lambda_definition(statement) + elif isinstance(statement, for_nodes): value = self.check_for_loop(statement) @@ -136,7 +140,7 @@ def check_assignment(self, statement): stack.extend(list(item.value.elts)) def check_function_definition(self, statement): - if not isinstance(statement, ast.Lambda) and statement.name in self.names: + if statement.name in self.names: msg = self.assign_msg if type(statement.__flake8_builtins_parent) is ast.ClassDef: msg = self.class_attribute_msg @@ -156,6 +160,20 @@ def check_function_definition(self, statement): variable=arg.arg, ) + def check_lambda_definition(self, statement): + all_arguments = [] + all_arguments.extend(statement.args.args) + all_arguments.extend(getattr(statement.args, 'kwonlyargs', [])) + all_arguments.extend(getattr(statement.args, 'posonlyargs', [])) + + for arg in all_arguments: + if isinstance(arg, ast.arg) and arg.arg in self.names: + yield self.error( + arg, + message=self.lambda_argument_msg, + variable=arg.arg, + ) + def check_for_loop(self, statement): stack = [statement.target] while stack: diff --git a/run_tests.py b/run_tests.py index bc831be..53f1c59 100644 --- a/run_tests.py +++ b/run_tests.py @@ -142,7 +142,7 @@ def bla(list): def test_lambda_argument_message(): source = 'takefirst = lambda list: list[0]' - check_code(source, 'A002') + check_code(source, 'A005') def test_keyword_argument_message(): @@ -171,6 +171,15 @@ def bla(list, /): """ check_code(source, 'A002') +@pytest.mark.skipif( + sys.version_info < (3, 8), + reason='This syntax is only valid in Python 3.8+', +) +def test_lambda_posonly_argument_message(): + source = """ + takefirst = lambda list, /: list[0] + """ + check_code(source, 'A005') def test_no_error(): source = """def bla(first):\n b = 4""" From 5b3cbc3fe450f8186b1ff34a652e22afe48b2572 Mon Sep 17 00:00:00 2001 From: cielavenir Date: Thu, 28 Mar 2024 16:50:21 +0900 Subject: [PATCH 3/5] Update readme --- README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.rst b/README.rst index f867f63..4a1b7d7 100644 --- a/README.rst +++ b/README.rst @@ -101,6 +101,9 @@ A003: A004: An import statement is shadowing a Python builtin. +A005: + A lambda argument is shadowing a Python builtin. + License ------- GPL 2.0 From 5ab7ab68fb42619492ec627ae2e0550def2838e1 Mon Sep 17 00:00:00 2001 From: cielavenir Date: Sun, 31 Mar 2024 03:01:22 +0900 Subject: [PATCH 4/5] Fix test's error id --- run_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run_tests.py b/run_tests.py index 78e342b..8e15e8b 100644 --- a/run_tests.py +++ b/run_tests.py @@ -158,7 +158,7 @@ def bla(list): def test_lambda_argument_message(): source = 'takefirst = lambda list: list[0]' - check_code(source, 'A005') + check_code(source, 'A006') def test_keyword_argument_message(): @@ -195,7 +195,7 @@ def test_lambda_posonly_argument_message(): source = """ takefirst = lambda list, /: list[0] """ - check_code(source, 'A005') + check_code(source, 'A006') def test_no_error(): source = """def bla(first):\n b = 4""" From 8702675502b6bcfe64b0141f1e6a35ea340cf5f4 Mon Sep 17 00:00:00 2001 From: cielavenir Date: Mon, 1 Apr 2024 15:28:38 +0900 Subject: [PATCH 5/5] update changes --- CHANGES.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 00bff2b..31c0f43 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,10 +3,11 @@ Changelog ========= -2.3.1 (unreleased) +2.3.1 (2024-04-01) ------------------ -- Nothing changed yet. +- Add rule for lambda argument shadowing (`A006`). + [cielavenir] 2.3.0 (2024-03-29)