Skip to content

Commit

Permalink
Declare function mutators with inline comment
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rmorshea committed Feb 23, 2023
1 parent d064010 commit 4d984e0
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ build-stamp
.pytest_cache/
.mypy_cache/
.benchmarks/
venv
22 changes: 18 additions & 4 deletions pylint/checkers/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -1454,10 +1459,19 @@ 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

for called_decorator in filter(
None, map(safe_infer, called.decorators.nodes)
):
if decorated_with(called, ["yet_another_mutation_decorator"]):
print(self.linter.file_state._module_msgs_state.get("E1145", {}))
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())
Expand Down
17 changes: 17 additions & 0 deletions tests/functional/a/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 4d984e0

Please sign in to comment.