Skip to content

Commit 2a53c66

Browse files
committed
Added options to ignore lambdas and nested functions.
1 parent 1ed880d commit 2a53c66

3 files changed

Lines changed: 113 additions & 2 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Configuration options also exist:
1111
- `unused-arguments-ignore-abstract-functions` - don't show warnings for abstract functions.
1212
- `unused-arguments-ignore-stub-functions` - don't show warnings for empty functions.
1313
- `unused-arguments-ignore-variadic-names` - don't show warnings for unused *args and **kwargs.
14+
- `unused-arguments-ignore-lambdas` - don't show warnings for all lambdas.
15+
- `unused-arguments-ignore-nested-functions` - don't show warnings for nested
16+
functions. Only show warnings for functions in the top level of a module, or methods
17+
of a class in the top level of a module.
1418

1519

1620
## Changelog

flake8_unused_arguments.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ class Plugin:
1717
ignore_abstract = False
1818
ignore_stubs = False
1919
ignore_variadic_names = False
20+
ignore_lambdas = False
21+
ignore_nested_functions = False
2022

2123
def __init__(self, tree: ast.Module):
2224
self.tree = tree
@@ -50,14 +52,37 @@ def add_options(cls, option_manager: flake8.options.manager.OptionManager) -> No
5052
help="If provided, then unused *args and **kwargs won't produce warnings.",
5153
)
5254

55+
option_manager.add_option(
56+
"--unused-arguments-ignore-lambdas",
57+
action="store_true",
58+
parse_from_config=True,
59+
default=cls.ignore_lambdas,
60+
dest="unused_arguments_ignore_lambdas",
61+
help="If provided, all lambdas are ignored.",
62+
)
63+
64+
option_manager.add_option(
65+
"--unused-arguments-ignore-nested-functions",
66+
action="store_true",
67+
parse_from_config=True,
68+
default=cls.ignore_nested_functions,
69+
dest="unused_arguments_ignore_nested_functions",
70+
help=(
71+
"If provided, only functions at the top level of a module or "
72+
"methods of a class in the top level of a module are checked.",
73+
),
74+
)
75+
5376
@classmethod
5477
def parse_options(cls, options: optparse.Values) -> None:
5578
cls.ignore_abstract = options.unused_arguments_ignore_abstract_functions
5679
cls.ignore_stubs = options.unused_arguments_ignore_stub_functions
5780
cls.ignore_variadic_names = options.unused_arguments_ignore_variadic_names
81+
cls.ignore_lambdas = options.unused_arguments_ignore_lambdas
82+
cls.ignore_nested_functions = options.unused_arguments_ignore_nested_functions
5883

5984
def run(self) -> Iterable[LintResult]:
60-
finder = FunctionFinder()
85+
finder = FunctionFinder(self.ignore_nested_functions)
6186
finder.visit(self.tree)
6287

6388
for function in finder.functions:
@@ -70,6 +95,10 @@ def run(self) -> Iterable[LintResult]:
7095
if self.ignore_stubs and is_stub_function(function):
7196
continue
7297

98+
# ignore lambdas
99+
if self.ignore_lambdas and isinstance(function, ast.Lambda):
100+
continue
101+
73102
for i, argument in get_unused_arguments(function):
74103
name = argument.arg
75104
if self.ignore_variadic_names:
@@ -198,12 +227,15 @@ def is_stub_function(function: FunctionTypes) -> bool:
198227
class FunctionFinder(NodeVisitor):
199228
functions: List[FunctionTypes]
200229

201-
def __init__(self) -> None:
230+
def __init__(self, only_top_level=False) -> None:
202231
super().__init__()
203232
self.functions = []
233+
self.only_top_level = only_top_level
204234

205235
def visit_function_types(self, function: FunctionTypes) -> None:
206236
self.functions.append(function)
237+
if self.only_top_level:
238+
return
207239
if isinstance(function, ast.Lambda):
208240
self.visit(function.body)
209241
else:

test_unused_arguments.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,44 @@ def foo(**kwargs):
223223
{"ignore_variadic_names": False},
224224
[(2, 10, "U100 Unused argument 'kwargs'", "unused argument")],
225225
),
226+
(
227+
"foo = lambda a: 1\n",
228+
{"ignore_lambdas": True},
229+
[],
230+
),
231+
(
232+
"foo = lambda a: 1\n",
233+
{"ignore_lambdas": False},
234+
[(1, 13, "U100 Unused argument 'a'", "unused argument")],
235+
),
236+
(
237+
"""
238+
def foo(a):
239+
def bar(b):
240+
pass
241+
zed = lambda c: lambda d: 1
242+
""",
243+
{"ignore_nested_functions": False},
244+
[
245+
(2, 8, "U100 Unused argument 'a'", "unused argument"),
246+
(3, 12, "U100 Unused argument 'b'", "unused argument"),
247+
(5, 13, "U100 Unused argument 'c'", "unused argument"),
248+
(5, 23, "U100 Unused argument 'd'", "unused argument"),
249+
],
250+
),
251+
(
252+
"""
253+
def foo(a):
254+
def bar(b):
255+
pass
256+
zed = lambda c: lambda d: 1
257+
""",
258+
{"ignore_nested_functions": True},
259+
[
260+
(2, 8, "U100 Unused argument 'a'", "unused argument"),
261+
(5, 13, "U100 Unused argument 'c'", "unused argument"),
262+
],
263+
),
226264
(
227265
"""
228266
def foo(_a):
@@ -309,6 +347,43 @@ def test_check_version() -> None:
309347
assert get_most_recent_tag() == Plugin.version
310348

311349

350+
FF_CODE = """
351+
def some_function(a=1):
352+
def some_nested_function(b=1):
353+
return b
354+
return some_nested_function(a)
355+
356+
class SomeClass:
357+
def some_method(a=1):
358+
def some_nested_method(b=1):
359+
return b
360+
return some_nested_method(a)
361+
"""
362+
FF_ALL_FUNCTIONS = [
363+
"some_function",
364+
"some_nested_function",
365+
"some_method",
366+
"some_nested_method",
367+
]
368+
369+
370+
@pytest.mark.parametrize(
371+
"only_top_level, expected",
372+
[
373+
(False, FF_ALL_FUNCTIONS),
374+
(True, [n for n in FF_ALL_FUNCTIONS if "nested" not in n]),
375+
],
376+
)
377+
def test_function_finder(only_top_level, expected):
378+
from flake8_unused_arguments import FunctionFinder
379+
380+
finder = FunctionFinder(only_top_level=only_top_level)
381+
finder.visit(ast.parse(FF_CODE))
382+
names = [node.name for node in finder.functions]
383+
384+
assert names == expected
385+
386+
312387
def get_most_recent_tag() -> str:
313388
return (
314389
subprocess.check_output(["git", "describe", "--tags", "--abbrev=0"], text=True)

0 commit comments

Comments
 (0)