Skip to content

Commit ac7605e

Browse files
gh-107614: Normalise Argument Clinic error messages (#107615)
- always wrap the offending line, token, or name in quotes - in most cases, put the entire error message on one line Added tests for uncovered branches that were touched by this PR. Co-authored-by: Alex Waygood <[email protected]>
1 parent 2ba7c7f commit ac7605e

File tree

2 files changed

+179
-122
lines changed

2 files changed

+179
-122
lines changed

Lib/test/test_clinic.py

Lines changed: 71 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,8 @@ def test_checksum_mismatch(self):
161161
[clinic start generated code]*/
162162
/*[clinic end generated code: output=0123456789abcdef input=fedcba9876543210]*/
163163
"""
164-
err = (
165-
'Checksum mismatch!\n'
166-
'Expected: 0123456789abcdef\n'
167-
'Computed: da39a3ee5e6b4b0d\n'
168-
)
164+
err = ("Checksum mismatch! "
165+
"Expected '0123456789abcdef', computed 'da39a3ee5e6b4b0d'")
169166
self.expect_failure(raw, err, filename="test.c", lineno=3)
170167

171168
def test_garbage_after_stop_line(self):
@@ -403,7 +400,7 @@ def test_clone_mismatch(self):
403400
self.expect_failure(block, err, lineno=9)
404401

405402
def test_badly_formed_return_annotation(self):
406-
err = "Badly formed annotation for m.f: 'Custom'"
403+
err = "Badly formed annotation for 'm.f': 'Custom'"
407404
block = """
408405
/*[python input]
409406
class Custom_return_converter(CReturnConverter):
@@ -509,6 +506,15 @@ def test_dest_buffer_not_empty_at_eof(self):
509506
self.assertIn(expected_warning, stdout.getvalue())
510507
self.assertEqual(generated, expected_generated)
511508

509+
def test_dest_clear(self):
510+
err = "Can't clear destination 'file': it's not of type 'buffer'"
511+
block = """
512+
/*[clinic input]
513+
destination file clear
514+
[clinic start generated code]*/
515+
"""
516+
self.expect_failure(block, err, lineno=2)
517+
512518
def test_directive_set_misuse(self):
513519
err = "unknown variable 'ets'"
514520
block = """
@@ -598,7 +604,7 @@ def test_directive_printout(self):
598604
self.assertEqual(generated, expected)
599605

600606
def test_directive_preserve_twice(self):
601-
err = "Can't have preserve twice in one block!"
607+
err = "Can't have 'preserve' twice in one block!"
602608
block = """
603609
/*[clinic input]
604610
preserve
@@ -637,13 +643,24 @@ def test_directive_preserve_output(self):
637643
self.assertEqual(generated, block)
638644

639645
def test_directive_output_invalid_command(self):
640-
err = (
641-
"Invalid command / destination name 'cmd', must be one of:\n"
642-
" preset push pop print everything cpp_if docstring_prototype "
643-
"docstring_definition methoddef_define impl_prototype "
644-
"parser_prototype parser_definition cpp_endif methoddef_ifndef "
645-
"impl_definition"
646-
)
646+
err = dedent("""
647+
Invalid command or destination name 'cmd'. Must be one of:
648+
- 'preset'
649+
- 'push'
650+
- 'pop'
651+
- 'print'
652+
- 'everything'
653+
- 'cpp_if'
654+
- 'docstring_prototype'
655+
- 'docstring_definition'
656+
- 'methoddef_define'
657+
- 'impl_prototype'
658+
- 'parser_prototype'
659+
- 'parser_definition'
660+
- 'cpp_endif'
661+
- 'methoddef_ifndef'
662+
- 'impl_definition'
663+
""").strip()
647664
block = """
648665
/*[clinic input]
649666
output cmd buffer
@@ -919,7 +936,7 @@ def test_param_default_expr_named_constant(self):
919936
self.assertEqual("MAXSIZE", p.converter.c_default)
920937

921938
err = (
922-
"When you specify a named constant ('sys.maxsize') as your default value,\n"
939+
"When you specify a named constant ('sys.maxsize') as your default value, "
923940
"you MUST specify a valid c_default."
924941
)
925942
block = """
@@ -931,7 +948,7 @@ def test_param_default_expr_named_constant(self):
931948

932949
def test_param_default_expr_binop(self):
933950
err = (
934-
"When you specify an expression ('a + b') as your default value,\n"
951+
"When you specify an expression ('a + b') as your default value, "
935952
"you MUST specify a valid c_default."
936953
)
937954
block = """
@@ -954,7 +971,7 @@ def test_param_no_docstring(self):
954971

955972
def test_param_default_parameters_out_of_order(self):
956973
err = (
957-
"Can't have a parameter without a default ('something_else')\n"
974+
"Can't have a parameter without a default ('something_else') "
958975
"after a parameter with a default!"
959976
)
960977
block = """
@@ -1088,7 +1105,7 @@ def test_return_converter_invalid_syntax(self):
10881105
module os
10891106
os.stat -> invalid syntax
10901107
"""
1091-
err = "Badly formed annotation for os.stat: 'invalid syntax'"
1108+
err = "Badly formed annotation for 'os.stat': 'invalid syntax'"
10921109
self.expect_failure(block, err)
10931110

10941111
def test_legacy_converter_disallowed_in_return_annotation(self):
@@ -1252,8 +1269,8 @@ def test_nested_groups(self):
12521269

12531270
def test_disallowed_grouping__two_top_groups_on_left(self):
12541271
err = (
1255-
'Function two_top_groups_on_left has an unsupported group '
1256-
'configuration. (Unexpected state 2.b)'
1272+
"Function 'two_top_groups_on_left' has an unsupported group "
1273+
"configuration. (Unexpected state 2.b)"
12571274
)
12581275
block = """
12591276
module foo
@@ -1281,7 +1298,7 @@ def test_disallowed_grouping__two_top_groups_on_right(self):
12811298
]
12821299
"""
12831300
err = (
1284-
"Function two_top_groups_on_right has an unsupported group "
1301+
"Function 'two_top_groups_on_right' has an unsupported group "
12851302
"configuration. (Unexpected state 6.b)"
12861303
)
12871304
self.expect_failure(block, err)
@@ -1317,7 +1334,7 @@ def test_disallowed_grouping__group_after_parameter_on_left(self):
13171334
param: int
13181335
"""
13191336
err = (
1320-
"Function group_after_parameter_on_left has an unsupported group "
1337+
"Function 'group_after_parameter_on_left' has an unsupported group "
13211338
"configuration. (Unexpected state 2.b)"
13221339
)
13231340
self.expect_failure(block, err)
@@ -1334,7 +1351,7 @@ def test_disallowed_grouping__empty_group_on_left(self):
13341351
param: int
13351352
"""
13361353
err = (
1337-
"Function empty_group has an empty group.\n"
1354+
"Function 'empty_group' has an empty group. "
13381355
"All groups must contain at least one parameter."
13391356
)
13401357
self.expect_failure(block, err)
@@ -1351,7 +1368,7 @@ def test_disallowed_grouping__empty_group_on_right(self):
13511368
]
13521369
"""
13531370
err = (
1354-
"Function empty_group has an empty group.\n"
1371+
"Function 'empty_group' has an empty group. "
13551372
"All groups must contain at least one parameter."
13561373
)
13571374
self.expect_failure(block, err)
@@ -1365,7 +1382,7 @@ def test_disallowed_grouping__no_matching_bracket(self):
13651382
group2: int
13661383
]
13671384
"""
1368-
err = "Function empty_group has a ] without a matching [."
1385+
err = "Function 'empty_group' has a ']' without a matching '['"
13691386
self.expect_failure(block, err)
13701387

13711388
def test_no_parameters(self):
@@ -1400,7 +1417,7 @@ def test_illegal_module_line(self):
14001417
foo.bar => int
14011418
/
14021419
"""
1403-
err = "Illegal function name: foo.bar => int"
1420+
err = "Illegal function name: 'foo.bar => int'"
14041421
self.expect_failure(block, err)
14051422

14061423
def test_illegal_c_basename(self):
@@ -1409,7 +1426,7 @@ def test_illegal_c_basename(self):
14091426
foo.bar as 935
14101427
/
14111428
"""
1412-
err = "Illegal C basename: 935"
1429+
err = "Illegal C basename: '935'"
14131430
self.expect_failure(block, err)
14141431

14151432
def test_single_star(self):
@@ -1419,7 +1436,7 @@ def test_single_star(self):
14191436
*
14201437
*
14211438
"""
1422-
err = "Function bar uses '*' more than once."
1439+
err = "Function 'bar' uses '*' more than once."
14231440
self.expect_failure(block, err)
14241441

14251442
def test_parameters_required_after_star(self):
@@ -1429,7 +1446,7 @@ def test_parameters_required_after_star(self):
14291446
"module foo\nfoo.bar\n this: int\n *",
14301447
"module foo\nfoo.bar\n this: int\n *\nDocstring.",
14311448
)
1432-
err = "Function bar specifies '*' without any parameters afterwards."
1449+
err = "Function 'bar' specifies '*' without any parameters afterwards."
14331450
for block in dataset:
14341451
with self.subTest(block=block):
14351452
self.expect_failure(block, err)
@@ -1442,7 +1459,7 @@ def test_single_slash(self):
14421459
/
14431460
"""
14441461
err = (
1445-
"Function bar has an unsupported group configuration. "
1462+
"Function 'bar' has an unsupported group configuration. "
14461463
"(Unexpected state 0.d)"
14471464
)
14481465
self.expect_failure(block, err)
@@ -1456,7 +1473,7 @@ def test_double_slash(self):
14561473
b: int
14571474
/
14581475
"""
1459-
err = "Function bar uses '/' more than once."
1476+
err = "Function 'bar' uses '/' more than once."
14601477
self.expect_failure(block, err)
14611478

14621479
def test_mix_star_and_slash(self):
@@ -1470,7 +1487,7 @@ def test_mix_star_and_slash(self):
14701487
/
14711488
"""
14721489
err = (
1473-
"Function bar mixes keyword-only and positional-only parameters, "
1490+
"Function 'bar' mixes keyword-only and positional-only parameters, "
14741491
"which is unsupported."
14751492
)
14761493
self.expect_failure(block, err)
@@ -1483,7 +1500,7 @@ def test_parameters_not_permitted_after_slash_for_now(self):
14831500
x: int
14841501
"""
14851502
err = (
1486-
"Function bar has an unsupported group configuration. "
1503+
"Function 'bar' has an unsupported group configuration. "
14871504
"(Unexpected state 0.d)"
14881505
)
14891506
self.expect_failure(block, err)
@@ -1582,7 +1599,8 @@ def test_indent_stack_no_tabs(self):
15821599
*vararg1: object
15831600
\t*vararg2: object
15841601
"""
1585-
err = "Tab characters are illegal in the Clinic DSL."
1602+
err = ("Tab characters are illegal in the Clinic DSL: "
1603+
r"'\t*vararg2: object'")
15861604
self.expect_failure(block, err)
15871605

15881606
def test_indent_stack_illegal_outdent(self):
@@ -1841,16 +1859,25 @@ def test_vararg_cannot_take_default_value(self):
18411859
"""
18421860
self.expect_failure(block, err, lineno=1)
18431861

1862+
def test_default_is_not_of_correct_type(self):
1863+
err = ("int_converter: default value 2.5 for field 'a' "
1864+
"is not of type 'int'")
1865+
block = """
1866+
fn
1867+
a: int = 2.5
1868+
"""
1869+
self.expect_failure(block, err, lineno=1)
1870+
18441871
def test_invalid_legacy_converter(self):
1845-
err = "fhi is not a valid legacy converter"
1872+
err = "'fhi' is not a valid legacy converter"
18461873
block = """
18471874
fn
18481875
a: 'fhi'
18491876
"""
18501877
self.expect_failure(block, err, lineno=1)
18511878

18521879
def test_parent_class_or_module_does_not_exist(self):
1853-
err = "Parent class or module z does not exist"
1880+
err = "Parent class or module 'z' does not exist"
18541881
block = """
18551882
module m
18561883
z.func
@@ -1877,7 +1904,7 @@ def test_param_requires_custom_c_name(self):
18771904
self.expect_failure(block, err, lineno=2)
18781905

18791906
def test_state_func_docstring_assert_no_group(self):
1880-
err = "Function func has a ] without a matching [."
1907+
err = "Function 'func' has a ']' without a matching '['"
18811908
block = """
18821909
module m
18831910
m.func
@@ -1887,7 +1914,7 @@ def test_state_func_docstring_assert_no_group(self):
18871914
self.expect_failure(block, err, lineno=2)
18881915

18891916
def test_state_func_docstring_no_summary(self):
1890-
err = "Docstring for m.func does not have a summary line!"
1917+
err = "Docstring for 'm.func' does not have a summary line!"
18911918
block = """
18921919
module m
18931920
m.func
@@ -1983,13 +2010,11 @@ def test_cli_force(self):
19832010
const char *hand_edited = "output block is overwritten";
19842011
/*[clinic end generated code: output=bogus input=bogus]*/
19852012
""")
1986-
fail_msg = dedent("""
1987-
Checksum mismatch!
1988-
Expected: bogus
1989-
Computed: 2ed19
1990-
Suggested fix: remove all generated code including the end marker,
1991-
or use the '-f' option.
1992-
""")
2013+
fail_msg = (
2014+
"Checksum mismatch! Expected 'bogus', computed '2ed19'. "
2015+
"Suggested fix: remove all generated code including the end marker, "
2016+
"or use the '-f' option.\n"
2017+
)
19932018
with os_helper.temp_dir() as tmp_dir:
19942019
fn = os.path.join(tmp_dir, "test.c")
19952020
with open(fn, "w", encoding="utf-8") as f:
@@ -2214,7 +2239,7 @@ def test_file_dest(self):
22142239
f.write("") # Write an empty output file!
22152240
# Clinic should complain about the empty output file.
22162241
_, err = self.expect_failure(in_fn)
2217-
expected_err = (f"Modified destination file {out_fn!r}, "
2242+
expected_err = (f"Modified destination file {out_fn!r}; "
22182243
"not overwriting!")
22192244
self.assertIn(expected_err, err)
22202245
# Run clinic again, this time with the -f option.

0 commit comments

Comments
 (0)