From 7f4b21fe6fad4994a2aaa76bd1f9a955ec73a59a Mon Sep 17 00:00:00 2001 From: rmorshea Date: Thu, 23 Feb 2023 01:25:53 -0800 Subject: [PATCH 1/3] Declare function mutators with inline comment This is accomplised by defining an "error" called decorator-preserves-signature which, when disabled via a comment on a decorator definition, will disable function argument checks on calls to functions that have that decorator. We use an error to do this in order to consume the inline comment state via the linter.file_state._supression_mapping --- .gitignore | 1 + pylint/checkers/typecheck.py | 21 +++++++++++++++++---- tests/functional/a/arguments.py | 17 +++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d807609565..e8ec590f5b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ build-stamp .pytest_cache/ .mypy_cache/ .benchmarks/ +venv diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 8448a0f13b..8a5c051db0 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -381,6 +381,11 @@ def _missing_member_hint( "Used when a slice step is 0 and the object doesn't implement " "a custom __getitem__ method.", ), + "E1145": ( + "", + "decorator-preserves-signature", + "Ignore invalid argument errors on calls to this function", + ), "W1113": ( "Keyword argument before variable positional arguments list " "in the definition of %s function", @@ -1454,10 +1459,18 @@ def visit_call(self, node: nodes.Call) -> None: return # Has the function signature changed in ways we cannot reliably detect? - if hasattr(called, "decorators") and decorated_with( - called, self.linter.config.signature_mutators - ): - return + if getattr(called, "decorators", None): + if decorated_with(called, self.linter.config.signature_mutators): + return + + called_decorator: astroid.NodeNG + for called_decorator in filter( + None, map(safe_infer, called.decorators.nodes) + ): + if not self.linter.file_state._module_msgs_state.get("E1145", {}).get( + called_decorator.lineno, True + ): + return num_positional_args = len(call_site.positional_arguments) keyword_args = list(call_site.keyword_arguments.keys()) diff --git a/tests/functional/a/arguments.py b/tests/functional/a/arguments.py index 6929b98500..bf77dcbc69 100644 --- a/tests/functional/a/arguments.py +++ b/tests/functional/a/arguments.py @@ -240,6 +240,17 @@ def wrapper(*args, do_something=True, **kwargs): return wrapper +def yet_another_mutation_decorator(fun): # pylint: disable=decorator-preserves-signature + """Yet another decorator that changes a function's signature""" + def wrapper(*args, do_something=True, **kwargs): + if do_something: + return fun(*args, **kwargs) + + return None + + return wrapper + + @mutation_decorator def mutated_function(arg): return arg @@ -250,11 +261,17 @@ def mutated(arg): return arg +@yet_another_mutation_decorator +def another_mutated_function(arg): + return arg + + mutated_function(do_something=False) mutated_function() mutated(do_something=True) +another_mutated_function(do_something=False) def func(one, two, three): return one + two + three From 6af39bb15b3282c1afd1ccfed6f28b6a0f6c4afc Mon Sep 17 00:00:00 2001 From: rmorshea Date: Thu, 23 Feb 2023 09:50:05 -0800 Subject: [PATCH 2/3] rename error + better error descriptions --- pylint/checkers/typecheck.py | 7 ++++--- tests/functional/a/arguments.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 8a5c051db0..5459c635fa 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -382,9 +382,10 @@ def _missing_member_hint( "a custom __getitem__ method.", ), "E1145": ( - "", - "decorator-preserves-signature", - "Ignore invalid argument errors on calls to this function", + "Decorator does not preserve function signature", + "signature-mutator", + "Emitted when a decorator does not preserve the signature " + "of the functions is takes as inputs.", ), "W1113": ( "Keyword argument before variable positional arguments list " diff --git a/tests/functional/a/arguments.py b/tests/functional/a/arguments.py index bf77dcbc69..e88462a4e4 100644 --- a/tests/functional/a/arguments.py +++ b/tests/functional/a/arguments.py @@ -240,7 +240,7 @@ def wrapper(*args, do_something=True, **kwargs): return wrapper -def yet_another_mutation_decorator(fun): # pylint: disable=decorator-preserves-signature +def yet_another_mutation_decorator(fun): # pylint: disable=signature-mutator """Yet another decorator that changes a function's signature""" def wrapper(*args, do_something=True, **kwargs): if do_something: From 63f074736831513d43fd3196d63753a9a77b3116 Mon Sep 17 00:00:00 2001 From: Ryan Morshead Date: Fri, 24 Feb 2023 08:10:40 -0800 Subject: [PATCH 3/3] Update .gitignore Co-authored-by: Pierre Sassoulas --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index e8ec590f5b..d807609565 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,3 @@ build-stamp .pytest_cache/ .mypy_cache/ .benchmarks/ -venv