]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-117613: Argument Clinic: ensure that defining class params are positional...
authorneonene <53406459+neonene@users.noreply.github.com>
Wed, 17 Apr 2024 21:11:17 +0000 (06:11 +0900)
committerGitHub <noreply@github.com>
Wed, 17 Apr 2024 21:11:17 +0000 (21:11 +0000)
Lib/test/test_clinic.py
Tools/clinic/clinic.py

index 3a0ff940d6a62063d63ead43cf1cf47c49222f8f..c114a62ce09d8d1e9e34cf5b127a97305d4624d0 100644 (file)
@@ -1347,6 +1347,28 @@ class ClinicParserTest(_ParserBase):
                 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 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"
+        )
+        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)
index d2ff422911ce150cc3d9210c54044e9d15dd7e1e..efd519ff5ee6299ef5fedf0890141a10ff23f05a 100755 (executable)
@@ -4997,6 +4997,9 @@ class DSLParser:
                     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.function.cls is None:
+                    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'.")
 
@@ -5074,7 +5077,10 @@ class DSLParser:
             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