From ff5dad7b0f3aaeb3d9e3955bf860fa97afb5aa6b Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Thu, 27 Jul 2023 11:46:28 +0100 Subject: [PATCH 1/3] Argument clinic: cleanup `state_modulename_name()` --- Tools/clinic/clinic.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 5d3ed4167b06c4..3c0d279586ce4a 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4743,23 +4743,21 @@ def state_modulename_name(self, line: str | None) -> None: return_converter = None if returns: ast_input = f"def x() -> {returns}: pass" - module = None try: - module = ast.parse(ast_input) + module_node = ast.parse(ast_input) except SyntaxError: - pass - if not module: fail("Badly-formed annotation for " + full_name + ": " + returns) + function_node = module_node.body[0] + assert isinstance(function_node, ast.FunctionDef) try: - name, legacy, kwargs = self.parse_converter(module.body[0].returns) + name, legacy, kwargs = self.parse_converter(function_node.returns) if legacy: - fail("Legacy converter {!r} not allowed as a return converter" - .format(name)) + fail(f"Legacy converter {name!r} not allowed as a return converter") if name not in return_converters: - fail("No available return converter called " + repr(name)) + fail(f"No available return converter called {name!r}") return_converter = return_converters[name](**kwargs) except ValueError: - fail("Badly-formed annotation for " + full_name + ": " + returns) + fail(f"Badly-formed annotation for {full_name}: {returns}") fields = [x.strip() for x in full_name.split('.')] function_name = fields.pop() From 00e87b07041bcd471a0c283a32cc90eb1ed652c2 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 27 Jul 2023 12:00:23 +0100 Subject: [PATCH 2/3] Update clinic.py --- Tools/clinic/clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 3c0d279586ce4a..255a186219d0c0 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4746,7 +4746,7 @@ def state_modulename_name(self, line: str | None) -> None: try: module_node = ast.parse(ast_input) except SyntaxError: - fail("Badly-formed annotation for " + full_name + ": " + returns) + fail(f"Badly-formed annotation for {full_name}: {returns}") function_node = module_node.body[0] assert isinstance(function_node, ast.FunctionDef) try: From 37865cae64c283999449536aa45f1e5dc1fa9748 Mon Sep 17 00:00:00 2001 From: AlexWaygood Date: Thu, 27 Jul 2023 14:32:55 +0100 Subject: [PATCH 3/3] Add some tests --- Lib/test/test_clinic.py | 26 ++++++++++++++++++++++++++ Tools/clinic/clinic.py | 5 +++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index d1c61b1d401b98..d21c7d84c88d2d 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -679,6 +679,32 @@ def test_return_converter(self): """) self.assertIsInstance(function.return_converter, clinic.int_return_converter) + def test_return_converter_invalid_syntax(self): + stdout = self.parse_function_should_fail(""" + module os + os.stat -> invalid syntax + """) + expected_error = "Badly formed annotation for os.stat: 'invalid syntax'" + self.assertIn(expected_error, stdout) + + def test_legacy_converter_disallowed_in_return_annotation(self): + stdout = self.parse_function_should_fail(""" + module os + os.stat -> "s" + """) + expected_error = "Legacy converter 's' not allowed as a return converter" + self.assertIn(expected_error, stdout) + + def test_unknown_return_converter(self): + stdout = self.parse_function_should_fail(""" + module os + os.stat -> foooooooooooooooooooooooo + """) + expected_error = ( + "No available return converter called 'foooooooooooooooooooooooo'" + ) + self.assertIn(expected_error, stdout) + def test_star(self): function = self.parse_function(""" module os diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 255a186219d0c0..a343dc5c7fc080 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4730,6 +4730,7 @@ def state_modulename_name(self, line: str | None) -> None: return line, _, returns = line.partition('->') + returns = returns.strip() full_name, _, c_basename = line.partition(' as ') full_name = full_name.strip() @@ -4746,7 +4747,7 @@ def state_modulename_name(self, line: str | None) -> None: try: module_node = ast.parse(ast_input) except SyntaxError: - fail(f"Badly-formed annotation for {full_name}: {returns}") + fail(f"Badly formed annotation for {full_name}: {returns!r}") function_node = module_node.body[0] assert isinstance(function_node, ast.FunctionDef) try: @@ -4757,7 +4758,7 @@ def state_modulename_name(self, line: str | None) -> None: fail(f"No available return converter called {name!r}") return_converter = return_converters[name](**kwargs) except ValueError: - fail(f"Badly-formed annotation for {full_name}: {returns}") + fail(f"Badly formed annotation for {full_name}: {returns!r}") fields = [x.strip() for x in full_name.split('.')] function_name = fields.pop()