summaryrefslogtreecommitdiff
path: root/pylint/checkers/typecheck.py
diff options
context:
space:
mode:
Diffstat (limited to 'pylint/checkers/typecheck.py')
-rw-r--r--pylint/checkers/typecheck.py44
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,