From 597db53c56722b11f2298c50cd1b9e070cf9db59 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 17 Apr 2024 01:43:18 +0900 Subject: [PATCH 1/7] make defining_class params positional-only --- Lib/test/test_clinic.py | 10 ++++++++++ Tools/clinic/clinic.py | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 3a0ff940d6a6206..95d8dbbaabaa810 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1347,6 +1347,16 @@ def test_unused_param(self): parser_decl = p.simple_declaration(in_parser=True) self.assertNotIn("Py_UNUSED", parser_decl) + def test_kind_defining_class(self): + function = self.parse_function(""" + module m + class m.C "PyObject *" "" + m.C.meth + cls: defining_class + """, signatures_in_block=3, function_index=2) + p = function.parameters['cls'] + self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) + def parse(self, text): c = FakeClinic() parser = DSLParser(c) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index d2ff422911ce150..c88dfdc3b30cd05 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4997,6 +4997,7 @@ def bad_node(self, node): fail("A 'defining_class' parameter cannot have a default value.") if self.group: fail("A 'defining_class' parameter cannot be in an optional group.") + kind = inspect.Parameter.POSITIONAL_ONLY else: fail("A 'defining_class' parameter, if specified, must either be the first thing in the parameter block, or come just after 'self'.") @@ -5074,7 +5075,8 @@ def parse_special_symbol(self, symbol): for p in self.function.parameters.values(): if p.is_vararg(): continue - if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)): + if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter) + and not isinstance(p.converter, defining_class_converter)): fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") p.kind = inspect.Parameter.POSITIONAL_ONLY From a0d4186d4e8e219b512633efa6fd0d8b9d94097e Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 17 Apr 2024 06:01:05 +0900 Subject: [PATCH 2/7] disallow defining_class inside a module block --- Lib/test/test_clinic.py | 12 ++++++++++++ Tools/clinic/clinic.py | 2 ++ 2 files changed, 14 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 95d8dbbaabaa810..b65edd34491f68d 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1357,6 +1357,18 @@ class m.C "PyObject *" "" p = function.parameters['cls'] self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) + def test_disallow_defining_class_inside_module(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'defining_class' parameter can be specified inside a class method.\n" + ) + out = self.parse_function_should_fail(""" + module m + m.func + cls: defining_class + """) + self.assertEqual(out, expected_error_msg) + def parse(self, text): c = FakeClinic() parser = DSLParser(c) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index c88dfdc3b30cd05..49a40626a88cdd3 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4997,6 +4997,8 @@ def bad_node(self, node): fail("A 'defining_class' parameter cannot have a default value.") if self.group: fail("A 'defining_class' parameter cannot be in an optional group.") + if self.block.signatures[-1].cls is None: + fail("A 'defining_class' parameter can be specified inside a class method.") kind = inspect.Parameter.POSITIONAL_ONLY else: fail("A 'defining_class' parameter, if specified, must either be the first thing in the parameter block, or come just after 'self'.") From e8b7df8df2653078f4bc388c1832a7f022f39d14 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 17 Apr 2024 07:08:42 +0900 Subject: [PATCH 3/7] correct error msg --- Lib/test/test_clinic.py | 2 +- Tools/clinic/clinic.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index b65edd34491f68d..28514401513656a 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1360,7 +1360,7 @@ class m.C "PyObject *" "" def test_disallow_defining_class_inside_module(self): expected_error_msg = ( "Error on line 0:\n" - "A 'defining_class' parameter can be specified inside a class method.\n" + "A 'defining_class' parameter cannot be defined at module level.\n" ) out = self.parse_function_should_fail(""" module m diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 49a40626a88cdd3..945ac4a507cd77f 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4998,7 +4998,7 @@ def bad_node(self, node): if self.group: fail("A 'defining_class' parameter cannot be in an optional group.") if self.block.signatures[-1].cls is None: - fail("A 'defining_class' parameter can be specified inside a class method.") + fail("A 'defining_class' parameter cannot be defined at module level.") kind = inspect.Parameter.POSITIONAL_ONLY else: fail("A 'defining_class' parameter, if specified, must either be the first thing in the parameter block, or come just after 'self'.") From 7ecf41dd81c0a4ccc7286ad58cb776322b5dcc6e Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 17 Apr 2024 07:19:02 +0900 Subject: [PATCH 4/7] correct test name --- Lib/test/test_clinic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 28514401513656a..c114a62ce09d8d1 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1357,7 +1357,7 @@ class m.C "PyObject *" "" p = function.parameters['cls'] self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) - def test_disallow_defining_class_inside_module(self): + def test_disallow_defining_class_at_module_level(self): expected_error_msg = ( "Error on line 0:\n" "A 'defining_class' parameter cannot be defined at module level.\n" From 319756e33dbcda94c9fb998516862e12a271ea42 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Wed, 17 Apr 2024 21:31:36 +0900 Subject: [PATCH 5/7] suppress a mypy error --- Tools/clinic/clinic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 945ac4a507cd77f..4ad22cad36930cc 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4997,6 +4997,7 @@ def bad_node(self, node): fail("A 'defining_class' parameter cannot have a default value.") if self.group: fail("A 'defining_class' parameter cannot be in an optional group.") + assert isinstance(self.block.signatures[-1], Function) if self.block.signatures[-1].cls is None: fail("A 'defining_class' parameter cannot be defined at module level.") kind = inspect.Parameter.POSITIONAL_ONLY From 42b855af56a53b6614c43bafee860fb85195c6c0 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Thu, 18 Apr 2024 00:02:20 +0900 Subject: [PATCH 6/7] simplify the check --- Tools/clinic/clinic.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 4ad22cad36930cc..2618c3b16d39148 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4997,8 +4997,7 @@ def bad_node(self, node): fail("A 'defining_class' parameter cannot have a default value.") if self.group: fail("A 'defining_class' parameter cannot be in an optional group.") - assert isinstance(self.block.signatures[-1], Function) - if self.block.signatures[-1].cls is None: + if self.function.cls is None: fail("A 'defining_class' parameter cannot be defined at module level.") kind = inspect.Parameter.POSITIONAL_ONLY else: From 6b866d814e0cf457af63382c56e5ae76b046cb81 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 17 Apr 2024 22:47:16 +0200 Subject: [PATCH 7/7] Style nit --- Tools/clinic/clinic.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 2618c3b16d39148..efd519ff5ee6299 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5077,8 +5077,10 @@ def parse_special_symbol(self, symbol): for p in self.function.parameters.values(): if p.is_vararg(): continue - if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter) - and not isinstance(p.converter, defining_class_converter)): + if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and + not isinstance(p.converter, self_converter) and + not isinstance(p.converter, defining_class_converter) + ): fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") p.kind = inspect.Parameter.POSITIONAL_ONLY