mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
[3.13] gh-122688: Fix support of var-positional parameter in Argument Clinic (GH-122689) (#122852)
* 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.
(cherry picked from commit 8393608dd9
)
This commit is contained in:
parent
60e4c3f710
commit
8b6dd92db7
7 changed files with 203 additions and 96 deletions
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue