diff options
Diffstat (limited to 'pylint/checkers/typecheck.py')
-rw-r--r-- | pylint/checkers/typecheck.py | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index 9a8d8cbbe..6885e8cbf 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -1457,6 +1457,10 @@ accessed. Python regular expressions are accepted.", elif called.args.kwarg is not None: # The keyword argument gets assigned to the **kwargs parameter. pass + elif isinstance( + called, nodes.FunctionDef + ) and self._keyword_argument_is_in_all_decorator_returns(called, keyword): + pass elif not overload_function: # Unexpected keyword argument. self.add_message( @@ -1496,6 +1500,46 @@ accessed. Python regular expressions are accepted.", ): self.add_message("missing-kwoa", node=node, args=(name, callable_name)) + @staticmethod + def _keyword_argument_is_in_all_decorator_returns( + func: nodes.FunctionDef, keyword: str + ) -> bool: + """Check if the keyword argument exists in all signatures of the + return values of all decorators of the function. + """ + if not func.decorators: + return False + + for decorator in func.decorators.nodes: + inferred = safe_infer(decorator) + + # If we can't infer the decorator we assume it satisfies consumes + # the keyword, so we don't raise false positives + if not inferred: + return True + + # We only check arguments of function decorators + if not isinstance(inferred, nodes.FunctionDef): + return False + + for return_value in inferred.infer_call_result(): + # infer_call_result() returns nodes.Const.None for None return values + # so this also catches non-returning decorators + if not isinstance(return_value, nodes.FunctionDef): + return False + + # If the return value uses a kwarg the keyword will be consumed + if return_value.args.kwarg: + continue + + # Check if the keyword is another type of argument + if return_value.args.is_argument(keyword): + continue + + return False + + return True + def _check_invalid_sequence_index(self, subscript: nodes.Subscript): # Look for index operations where the parent is a sequence type. # If the types can be determined, only allow indices to be int, |