summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/whatsnew/fragments/8570.false_positive3
-rw-r--r--pylint/checkers/typecheck.py8
-rw-r--r--tests/functional/k/keyword_arg_before_vararg_positional_only.py13
-rw-r--r--tests/functional/k/keyword_arg_before_vararg_positional_only.rc2
-rw-r--r--tests/functional/k/keyword_arg_before_vararg_positional_only.txt3
5 files changed, 28 insertions, 1 deletions
diff --git a/doc/whatsnew/fragments/8570.false_positive b/doc/whatsnew/fragments/8570.false_positive
new file mode 100644
index 000000000..fec3a855e
--- /dev/null
+++ b/doc/whatsnew/fragments/8570.false_positive
@@ -0,0 +1,3 @@
+Fix false positive for ``keyword-arg-before-vararg`` when a positional-only parameter with a default value precedes ``*args``.
+
+Closes #8570
diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py
index 0c8c44a15..1a628f231 100644
--- a/pylint/checkers/typecheck.py
+++ b/pylint/checkers/typecheck.py
@@ -1001,8 +1001,14 @@ accessed. Python regular expressions are accepted.",
@only_required_for_messages("keyword-arg-before-vararg")
def visit_functiondef(self, node: nodes.FunctionDef) -> None:
- # check for keyword arg before varargs
+ # check for keyword arg before varargs.
+
if node.args.vararg and node.args.defaults:
+ # When `positional-only` parameters are present then only
+ # `positional-or-keyword` parameters are checked. I.e:
+ # >>> def name(pos_only_params, /, pos_or_keyword_params, *args): ...
+ if node.args.posonlyargs and not node.args.args:
+ return
self.add_message("keyword-arg-before-vararg", node=node, args=(node.name))
visit_asyncfunctiondef = visit_functiondef
diff --git a/tests/functional/k/keyword_arg_before_vararg_positional_only.py b/tests/functional/k/keyword_arg_before_vararg_positional_only.py
new file mode 100644
index 000000000..70b5f9929
--- /dev/null
+++ b/tests/functional/k/keyword_arg_before_vararg_positional_only.py
@@ -0,0 +1,13 @@
+"""Test `keyword-arg-before-vararg` in the context of positional-only parameters"""
+
+# pylint: disable=missing-function-docstring, unused-argument
+
+
+def name1(param1, /, param2=True, *args): ... # [keyword-arg-before-vararg]
+def name2(param1=True, /, param2=True, *args): ... # [keyword-arg-before-vararg]
+def name3(param1, param2=True, /, param3=True, *args): ... # [keyword-arg-before-vararg]
+def name4(param1, /, *args): ...
+def name5(param1=True, /, *args): ...
+def name6(param1, /, *args, param2=True): ...
+def name7(param1=True, /, *args, param2=True): ...
+def name8(param1, param2=True, /, *args, param3=True): ...
diff --git a/tests/functional/k/keyword_arg_before_vararg_positional_only.rc b/tests/functional/k/keyword_arg_before_vararg_positional_only.rc
new file mode 100644
index 000000000..85fc502b3
--- /dev/null
+++ b/tests/functional/k/keyword_arg_before_vararg_positional_only.rc
@@ -0,0 +1,2 @@
+[testoptions]
+min_pyver=3.8
diff --git a/tests/functional/k/keyword_arg_before_vararg_positional_only.txt b/tests/functional/k/keyword_arg_before_vararg_positional_only.txt
new file mode 100644
index 000000000..18700e2e4
--- /dev/null
+++ b/tests/functional/k/keyword_arg_before_vararg_positional_only.txt
@@ -0,0 +1,3 @@
+keyword-arg-before-vararg:6:0:6:9:name1:Keyword argument before variable positional arguments list in the definition of name1 function:UNDEFINED
+keyword-arg-before-vararg:7:0:7:9:name2:Keyword argument before variable positional arguments list in the definition of name2 function:UNDEFINED
+keyword-arg-before-vararg:8:0:8:9:name3:Keyword argument before variable positional arguments list in the definition of name3 function:UNDEFINED