summaryrefslogtreecommitdiffstats
path: root/Tools
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2024-08-09 09:22:41 (GMT)
committerGitHub <noreply@github.com>2024-08-09 09:22:41 (GMT)
commit8393608dd9f157ae25ee44777541e62fa80a6d82 (patch)
tree4f1b67a9aedd4af5fc4b090740bf21cf7eeebcbe /Tools
parentb6e745a27e9c98127acee436e4855066c58b7a3b (diff)
downloadcpython-8393608dd9f157ae25ee44777541e62fa80a6d82.zip
cpython-8393608dd9f157ae25ee44777541e62fa80a6d82.tar.gz
cpython-8393608dd9f157ae25ee44777541e62fa80a6d82.tar.bz2
gh-122688: Fix support of var-positional parameter in Argument Clinic (GH-122689)
* Parameters after the var-positional parameter are now keyword-only instead of positional-or-keyword. * Correctly calculate min_kw_only. * Raise errors for invalid combinations of the var-positional parameter with "*", "/" and deprecation markers.
Diffstat (limited to 'Tools')
-rw-r--r--Tools/clinic/libclinic/dsl_parser.py20
-rw-r--r--Tools/clinic/libclinic/parse_args.py2
2 files changed, 12 insertions, 10 deletions
diff --git a/Tools/clinic/libclinic/dsl_parser.py b/Tools/clinic/libclinic/dsl_parser.py
index ab9b586..5ca3bd5 100644
--- a/Tools/clinic/libclinic/dsl_parser.py
+++ b/Tools/clinic/libclinic/dsl_parser.py
@@ -915,8 +915,8 @@ class DSLParser:
f"invalid parameter declaration (**kwargs?): {line!r}")
if function_args.vararg:
- if any(p.is_vararg() for p in self.function.parameters.values()):
- fail("Too many var args")
+ self.check_previous_star()
+ self.check_remaining_star()
is_vararg = True
parameter = function_args.vararg
else:
@@ -1124,6 +1124,9 @@ class DSLParser:
key = f"{parameter_name}_as_{c_name}" if c_name else parameter_name
self.function.parameters[key] = p
+ if is_vararg:
+ self.keyword_only = True
+
@staticmethod
def parse_converter(
annotation: ast.expr | None
@@ -1165,8 +1168,6 @@ class DSLParser:
the marker will take effect (None means it is already in effect).
"""
if version is None:
- if self.keyword_only:
- fail(f"Function {function.name!r} uses '*' more than once.")
self.check_previous_star()
self.check_remaining_star()
self.keyword_only = True
@@ -1456,6 +1457,7 @@ class DSLParser:
if p.is_vararg():
p_lines.append("*")
+ added_star = True
name = p.converter.signature_name or p.name
p_lines.append(name)
@@ -1565,7 +1567,8 @@ class DSLParser:
for p in reversed(self.function.parameters.values()):
if self.keyword_only:
- if p.kind == inspect.Parameter.KEYWORD_ONLY:
+ if (p.kind == inspect.Parameter.KEYWORD_ONLY or
+ p.kind == inspect.Parameter.VAR_POSITIONAL):
return
elif self.deprecated_positional:
if p.deprecated_positional == self.deprecated_positional:
@@ -1575,12 +1578,11 @@ class DSLParser:
fail(f"Function {self.function.name!r} specifies {symbol!r} "
f"without following parameters.", line_number=lineno)
- def check_previous_star(self, lineno: int | None = None) -> None:
+ def check_previous_star(self) -> None:
assert isinstance(self.function, Function)
- for p in self.function.parameters.values():
- if p.kind == inspect.Parameter.VAR_POSITIONAL:
- fail(f"Function {self.function.name!r} uses '*' more than once.")
+ if self.keyword_only:
+ fail(f"Function {self.function.name!r} uses '*' more than once.")
def do_post_block_processing_cleanup(self, lineno: int) -> None:
diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py
index 0f67901..96c9b91 100644
--- a/Tools/clinic/libclinic/parse_args.py
+++ b/Tools/clinic/libclinic/parse_args.py
@@ -262,7 +262,7 @@ class ParseArgsCodeGen:
if p.is_keyword_only():
assert not p.is_positional_only()
if not p.is_optional():
- self.min_kw_only = i - self.max_pos
+ self.min_kw_only = i - self.max_pos - int(self.vararg != NO_VARARG)
elif p.is_vararg():
self.pseudo_args += 1
self.vararg = i - 1