Skip to content

Commit 5f20152

Browse files
miss-islingtonerlend-aaslandAlexWaygood
authored
[3.12] gh-106359: Fix corner case bugs in Argument Clinic converter parser (GH-106361) (#106364)
gh-106359: Fix corner case bugs in Argument Clinic converter parser (GH-106361) DSLParser.parse_converter() could return unusable kwdicts in some rare cases (cherry picked from commit 0da4c88) Co-authored-by: Erlend E. Aasland <erlend@python.org> Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parent 5e85604 commit 5f20152

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

Lib/test/test_clinic.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,22 @@ def test_other_bizarre_things_in_annotations_fail(self):
813813
)
814814
self.assertEqual(s, expected_failure_message)
815815

816+
def test_kwarg_splats_disallowed_in_function_call_annotations(self):
817+
expected_error_msg = (
818+
"Error on line 0:\n"
819+
"Cannot use a kwarg splat in a function-call annotation\n"
820+
)
821+
dataset = (
822+
'module fo\nfo.barbaz\n o: bool(**{None: "bang!"})',
823+
'module fo\nfo.barbaz -> bool(**{None: "bang!"})',
824+
'module fo\nfo.barbaz -> bool(**{"bang": 42})',
825+
'module fo\nfo.barbaz\n o: bool(**{"bang": None})',
826+
)
827+
for fn in dataset:
828+
with self.subTest(fn=fn):
829+
out = self.parse_function_should_fail(fn)
830+
self.assertEqual(out, expected_error_msg)
831+
816832
def test_unused_param(self):
817833
block = self.parse("""
818834
module foo
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Argument Clinic now explicitly forbids "kwarg splats" in function calls used as
2+
annotations.

Tools/clinic/clinic.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4289,6 +4289,7 @@ def dedent(self, line):
42894289

42904290

42914291
StateKeeper = Callable[[str | None], None]
4292+
ConverterArgs = dict[str, Any]
42924293

42934294
class DSLParser:
42944295
def __init__(self, clinic: Clinic) -> None:
@@ -5016,21 +5017,22 @@ def bad_node(self, node):
50165017
key = f"{parameter_name}_as_{c_name}" if c_name else parameter_name
50175018
self.function.parameters[key] = p
50185019

5019-
KwargDict = dict[str | None, Any]
5020-
50215020
@staticmethod
5022-
def parse_converter(annotation: ast.expr | None) -> tuple[str, bool, KwargDict]:
5021+
def parse_converter(
5022+
annotation: ast.expr | None
5023+
) -> tuple[str, bool, ConverterArgs]:
50235024
match annotation:
50245025
case ast.Constant(value=str() as value):
50255026
return value, True, {}
50265027
case ast.Name(name):
50275028
return name, False, {}
50285029
case ast.Call(func=ast.Name(name)):
50295030
symbols = globals()
5030-
kwargs = {
5031-
node.arg: eval_ast_expr(node.value, symbols)
5032-
for node in annotation.keywords
5033-
}
5031+
kwargs: ConverterArgs = {}
5032+
for node in annotation.keywords:
5033+
if not isinstance(node.arg, str):
5034+
fail("Cannot use a kwarg splat in a function-call annotation")
5035+
kwargs[node.arg] = eval_ast_expr(node.value, symbols)
50345036
return name, False, kwargs
50355037
case _:
50365038
fail(

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy