]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-107972: Argument Clinic: Ensure a C basename is provided after 'as' (#107973)
authorErlend E. Aasland <erlend@python.org>
Tue, 15 Aug 2023 14:41:40 +0000 (16:41 +0200)
committerGitHub <noreply@github.com>
Tue, 15 Aug 2023 14:41:40 +0000 (14:41 +0000)
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Lib/test/test_clinic.py
Tools/clinic/clinic.py

index a67cd301f6eaa88c28f9d77570133eb2a91e3365..896730571d815226dd934ac1d971b2bf551b09c3 100644 (file)
@@ -28,7 +28,8 @@ def _make_clinic(*, filename='clinic_tests'):
     return c
 
 
-def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None):
+def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None,
+                    strip=True):
     """Helper for the parser tests.
 
     tc: unittest.TestCase; passed self in the wrapper
@@ -38,7 +39,9 @@ def _expect_failure(tc, parser, code, errmsg, *, filename=None, lineno=None):
     filename: str, optional filename
     lineno: int, optional line number
     """
-    code = dedent(code).strip()
+    code = dedent(code)
+    if strip:
+        code = code.strip()
     errmsg = re.escape(errmsg)
     with tc.assertRaisesRegex(clinic.ClinicError, errmsg) as cm:
         parser(code)
@@ -638,6 +641,19 @@ class ClinicWholeFileTest(TestCase):
         err = "'__new__' must be a class method"
         self.expect_failure(block, err, lineno=7)
 
+    def test_no_c_basename_cloned(self):
+        block = """
+            /*[clinic input]
+            foo2
+            [clinic start generated code]*/
+            /*[clinic input]
+            foo as = foo2
+            [clinic start generated code]*/
+        """
+        err = "No C basename provided after 'as' keyword"
+        self.expect_failure(block, err, lineno=5)
+
+
 
 class ParseFileUnitTest(TestCase):
     def expect_parsing_failure(
@@ -857,9 +873,10 @@ class ClinicParserTest(TestCase):
         assert isinstance(s[function_index], clinic.Function)
         return s[function_index]
 
-    def expect_failure(self, block, err, *, filename=None, lineno=None):
+    def expect_failure(self, block, err, *,
+                       filename=None, lineno=None, strip=True):
         return _expect_failure(self, self.parse_function, block, err,
-                               filename=filename, lineno=lineno)
+                               filename=filename, lineno=lineno, strip=strip)
 
     def checkDocstring(self, fn, expected):
         self.assertTrue(hasattr(fn, "docstring"))
@@ -1520,6 +1537,11 @@ class ClinicParserTest(TestCase):
         err = "Illegal C basename: '935'"
         self.expect_failure(block, err)
 
+    def test_no_c_basename(self):
+        block = "foo as "
+        err = "No C basename provided after 'as' keyword"
+        self.expect_failure(block, err, strip=False)
+
     def test_single_star(self):
         block = """
             module foo
index 11dbfb3fbe858ecc6df36c631788fa7601585bd8..6ff2622d33b381a0a3d07823907a8835743ce39c 100755 (executable)
@@ -4879,9 +4879,11 @@ class DSLParser:
         before, equals, existing = line.rpartition('=')
         c_basename: str | None
         if equals:
-            full_name, _, c_basename = before.partition(' as ')
+            full_name, as_, c_basename = before.partition(' as ')
             full_name = full_name.strip()
             c_basename = c_basename.strip()
+            if as_ and not c_basename:
+                fail("No C basename provided after 'as' keyword")
             existing = existing.strip()
             if (is_legal_py_identifier(full_name) and
                 (not c_basename or is_legal_c_identifier(c_basename)) and
@@ -4932,10 +4934,11 @@ class DSLParser:
         line, _, returns = line.partition('->')
         returns = returns.strip()
 
-        full_name, _, c_basename = line.partition(' as ')
+        full_name, as_, c_basename = line.partition(' as ')
         full_name = full_name.strip()
         c_basename = c_basename.strip() or None
-
+        if as_ and not c_basename:
+            fail("No C basename provided after 'as' keyword")
         if not is_legal_py_identifier(full_name):
             fail(f"Illegal function name: {full_name!r}")
         if c_basename and not is_legal_c_identifier(c_basename):