]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-112438: Fix support of format units with the "e" prefix in nested tuples in PyArg_...
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 27 Nov 2023 17:32:55 +0000 (19:32 +0200)
committerGitHub <noreply@github.com>
Mon, 27 Nov 2023 17:32:55 +0000 (18:32 +0100)
Lib/test/test_capi/test_getargs.py
Misc/NEWS.d/next/C API/2023-11-27-09-44-16.gh-issue-112438.GdNZiI.rst [new file with mode: 0644]
Modules/_testcapi/getargs.c
Python/getargs.c

index c964b1efd577ba42d4fb89259a5b071928c770d0..9b6aef27625ad0e5cb03f10d1d1f988ba5f6bcc2 100644 (file)
@@ -1314,6 +1314,34 @@ class ParseTupleAndKeywords_Test(unittest.TestCase):
                             f"'{name2}' is an invalid keyword argument"):
                         parse((), {name2: 1, name3: 2}, '|OO', [name, name3])
 
+    def test_nested_tuple(self):
+        parse = _testcapi.parse_tuple_and_keywords
+
+        self.assertEqual(parse(((1, 2, 3),), {}, '(OOO)', ['a']), (1, 2, 3))
+        self.assertEqual(parse((1, (2, 3), 4), {}, 'O(OO)O', ['a', 'b', 'c']),
+                         (1, 2, 3, 4))
+        parse(((1, 2, 3),), {}, '(iii)', ['a'])
+
+        with self.assertRaisesRegex(TypeError,
+                "argument 1 must be sequence of length 2, not 3"):
+            parse(((1, 2, 3),), {}, '(ii)', ['a'])
+        with self.assertRaisesRegex(TypeError,
+                "argument 1 must be sequence of length 2, not 1"):
+            parse(((1,),), {}, '(ii)', ['a'])
+        with self.assertRaisesRegex(TypeError,
+                "argument 1 must be 2-item sequence, not int"):
+            parse((1,), {}, '(ii)', ['a'])
+        with self.assertRaisesRegex(TypeError,
+                "argument 1 must be 2-item sequence, not bytes"):
+            parse((b'ab',), {}, '(ii)', ['a'])
+
+        for f in 'es', 'et', 'es#', 'et#':
+            with self.assertRaises(LookupError):  # empty encoding ""
+                parse((('a',),), {}, '(' + f + ')', ['a'])
+            with self.assertRaisesRegex(TypeError,
+                    "argument 1 must be sequence of length 1, not 0"):
+                parse(((),), {}, '(' + f + ')', ['a'])
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/C API/2023-11-27-09-44-16.gh-issue-112438.GdNZiI.rst b/Misc/NEWS.d/next/C API/2023-11-27-09-44-16.gh-issue-112438.GdNZiI.rst
new file mode 100644 (file)
index 0000000..113119e
--- /dev/null
@@ -0,0 +1,2 @@
+Fix support of format units "es", "et", "es#", and "et#" in nested tuples in
+:c:func:`PyArg_ParseTuple`-like functions.
index e4cd15503fd11feafb9de853bb6387dd6525bf79..33e8af7d7bbb390a5f49841a184d298dfd0d8325 100644 (file)
@@ -71,18 +71,22 @@ parse_tuple_and_keywords(PyObject *self, PyObject *args)
 
     if (result) {
         int objects_only = 1;
+        int count = 0;
         for (const char *f = sub_format; *f; f++) {
-            if (Py_ISALNUM(*f) && strchr("OSUY", *f) == NULL) {
-                objects_only = 0;
-                break;
+            if (Py_ISALNUM(*f)) {
+                if (strchr("OSUY", *f) == NULL) {
+                    objects_only = 0;
+                    break;
+                }
+                count++;
             }
         }
         if (objects_only) {
-            return_value = PyTuple_New(size);
+            return_value = PyTuple_New(count);
             if (return_value == NULL) {
                 goto exit;
             }
-            for (Py_ssize_t i = 0; i < size; i++) {
+            for (Py_ssize_t i = 0; i < count; i++) {
                 PyObject *arg = *(PyObject **)(buffers + i);
                 if (arg == NULL) {
                     arg = Py_None;
index c0c2eb27184e3ca551ba76e28583d8806ff30bf4..5ff8f7473609f5ebdddc223682b874f95305672f 100644 (file)
@@ -477,7 +477,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
         }
         else if (c == ':' || c == ';' || c == '\0')
             break;
-        else if (level == 0 && Py_ISALPHA(c))
+        else if (level == 0 && Py_ISALPHA(c) && c != 'e')
             n++;
     }