Skip to content

Commit 46047bb

Browse files
[3.12] gh-112438: Fix support of format units with the "e" prefix in nested tuples in PyArg_Parse (gh-112439) (GH-112460)
(cherry picked from commit 4eea1e8) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent 3ef75ee commit 46047bb

File tree

4 files changed

+40
-6
lines changed

4 files changed

+40
-6
lines changed

Lib/test/test_capi/test_getargs.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,34 @@ class Test_testcapi(unittest.TestCase):
13411341
for name in dir(_testcapi)
13421342
if name.startswith('test_') and name.endswith('_code'))
13431343

1344+
def test_nested_tuple(self):
1345+
parse = _testcapi.parse_tuple_and_keywords
1346+
1347+
self.assertEqual(parse(((1, 2, 3),), {}, '(OOO)', ['a']), (1, 2, 3))
1348+
self.assertEqual(parse((1, (2, 3), 4), {}, 'O(OO)O', ['a', 'b', 'c']),
1349+
(1, 2, 3, 4))
1350+
parse(((1, 2, 3),), {}, '(iii)', ['a'])
1351+
1352+
with self.assertRaisesRegex(TypeError,
1353+
"argument 1 must be sequence of length 2, not 3"):
1354+
parse(((1, 2, 3),), {}, '(ii)', ['a'])
1355+
with self.assertRaisesRegex(TypeError,
1356+
"argument 1 must be sequence of length 2, not 1"):
1357+
parse(((1,),), {}, '(ii)', ['a'])
1358+
with self.assertRaisesRegex(TypeError,
1359+
"argument 1 must be 2-item sequence, not int"):
1360+
parse((1,), {}, '(ii)', ['a'])
1361+
with self.assertRaisesRegex(TypeError,
1362+
"argument 1 must be 2-item sequence, not bytes"):
1363+
parse((b'ab',), {}, '(ii)', ['a'])
1364+
1365+
for f in 'es', 'et', 'es#', 'et#':
1366+
with self.assertRaises(LookupError): # empty encoding ""
1367+
parse((('a',),), {}, '(' + f + ')', ['a'])
1368+
with self.assertRaisesRegex(TypeError,
1369+
"argument 1 must be sequence of length 1, not 0"):
1370+
parse(((),), {}, '(' + f + ')', ['a'])
1371+
13441372

13451373
if __name__ == "__main__":
13461374
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix support of format units "es", "et", "es#", and "et#" in nested tuples in
2+
:c:func:`PyArg_ParseTuple`-like functions.

Modules/_testcapi/getargs.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,22 @@ parse_tuple_and_keywords(PyObject *self, PyObject *args)
7373

7474
if (result) {
7575
int objects_only = 1;
76+
int count = 0;
7677
for (const char *f = sub_format; *f; f++) {
77-
if (Py_ISALNUM(*f) && strchr("OSUY", *f) == NULL) {
78-
objects_only = 0;
79-
break;
78+
if (Py_ISALNUM(*f)) {
79+
if (strchr("OSUY", *f) == NULL) {
80+
objects_only = 0;
81+
break;
82+
}
83+
count++;
8084
}
8185
}
8286
if (objects_only) {
83-
return_value = PyTuple_New(size);
87+
return_value = PyTuple_New(count);
8488
if (return_value == NULL) {
8589
goto exit;
8690
}
87-
for (Py_ssize_t i = 0; i < size; i++) {
91+
for (Py_ssize_t i = 0; i < count; i++) {
8892
PyObject *arg = *(PyObject **)(buffers + i);
8993
if (arg == NULL) {
9094
arg = Py_None;

Python/getargs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
522522
}
523523
else if (c == ':' || c == ';' || c == '\0')
524524
break;
525-
else if (level == 0 && Py_ISALPHA(c))
525+
else if (level == 0 && Py_ISALPHA(c) && c != 'e')
526526
n++;
527527
}
528528

0 commit comments

Comments
 (0)