mirror of
https://github.com/python/cpython.git
synced 2025-08-03 08:34:29 +00:00
gh-106359: Fix corner case bugs in Argument Clinic converter parser (#106361)
DSLParser.parse_converter() could return unusable kwdicts in some rare cases Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
60e41a0cbb
commit
0da4c883cf
3 changed files with 27 additions and 7 deletions
|
@ -813,6 +813,22 @@ Annotations must be either a name, a function call, or a string.
|
|||
)
|
||||
self.assertEqual(s, expected_failure_message)
|
||||
|
||||
def test_kwarg_splats_disallowed_in_function_call_annotations(self):
|
||||
expected_error_msg = (
|
||||
"Error on line 0:\n"
|
||||
"Cannot use a kwarg splat in a function-call annotation\n"
|
||||
)
|
||||
dataset = (
|
||||
'module fo\nfo.barbaz\n o: bool(**{None: "bang!"})',
|
||||
'module fo\nfo.barbaz -> bool(**{None: "bang!"})',
|
||||
'module fo\nfo.barbaz -> bool(**{"bang": 42})',
|
||||
'module fo\nfo.barbaz\n o: bool(**{"bang": None})',
|
||||
)
|
||||
for fn in dataset:
|
||||
with self.subTest(fn=fn):
|
||||
out = self.parse_function_should_fail(fn)
|
||||
self.assertEqual(out, expected_error_msg)
|
||||
|
||||
def test_unused_param(self):
|
||||
block = self.parse("""
|
||||
module foo
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Argument Clinic now explicitly forbids "kwarg splats" in function calls used as
|
||||
annotations.
|
|
@ -4291,6 +4291,7 @@ class IndentStack:
|
|||
|
||||
|
||||
StateKeeper = Callable[[str | None], None]
|
||||
ConverterArgs = dict[str, Any]
|
||||
|
||||
class DSLParser:
|
||||
function: Function | None
|
||||
|
@ -5033,10 +5034,10 @@ class DSLParser:
|
|||
key = f"{parameter_name}_as_{c_name}" if c_name else parameter_name
|
||||
self.function.parameters[key] = p
|
||||
|
||||
KwargDict = dict[str | None, Any]
|
||||
|
||||
@staticmethod
|
||||
def parse_converter(annotation: ast.expr | None) -> tuple[str, bool, KwargDict]:
|
||||
def parse_converter(
|
||||
annotation: ast.expr | None
|
||||
) -> tuple[str, bool, ConverterArgs]:
|
||||
match annotation:
|
||||
case ast.Constant(value=str() as value):
|
||||
return value, True, {}
|
||||
|
@ -5044,10 +5045,11 @@ class DSLParser:
|
|||
return name, False, {}
|
||||
case ast.Call(func=ast.Name(name)):
|
||||
symbols = globals()
|
||||
kwargs = {
|
||||
node.arg: eval_ast_expr(node.value, symbols)
|
||||
for node in annotation.keywords
|
||||
}
|
||||
kwargs: ConverterArgs = {}
|
||||
for node in annotation.keywords:
|
||||
if not isinstance(node.arg, str):
|
||||
fail("Cannot use a kwarg splat in a function-call annotation")
|
||||
kwargs[node.arg] = eval_ast_expr(node.value, symbols)
|
||||
return name, False, kwargs
|
||||
case _:
|
||||
fail(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue