Skip to content

gh-112068: C API: Add support of nullable arguments in PyArg_Parse (suffix) #121303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Merge branch 'main' into zipimport-namespace-suffix
  • Loading branch information
serhiy-storchaka committed Apr 8, 2025
commit 76f506e54d3588c03c3dcd8eec577b0c846bab57
14 changes: 14 additions & 0 deletions Doc/c-api/arg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,20 @@ Other objects
in *items*. The C arguments must correspond to the individual format units in
*items*. Format units for sequences may be nested.

If *items* contains format units which store a :ref:`borrowed buffer
<c-arg-borrowed-buffer>` (``s``, ``s#``, ``z``, ``z#``, ``y``, or ``y#``)
or a :term:`borrowed reference` (``S``, ``Y``, ``U``, ``O``, or ``O!``),
the object must be a Python tuple.
The *converter* for the ``O&`` format unit in *items* must not store
a borrowed buffer or a borrowed reference.

.. versionchanged:: next
:class:`str` and :class:`bytearray` objects no longer accepted as a sequence.

.. deprecated:: next
Non-tuple sequences are deprecated if *items* contains format units
which store a borrowed buffer or a borrowed reference.

``unit?`` (anything or ``None``) [*matching-variable(s)*]
``?`` modifies the behavior of the preceding format unit.
The C variable(s) corresponding to that parameter should be initialized
Expand Down
6 changes: 3 additions & 3 deletions Lib/test/test_capi/test_getargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1435,9 +1435,9 @@ def check(format, arg, expected, got='list'):
check('U?', [], 'str or None')
check('Y', [], 'bytearray')
check('Y?', [], 'bytearray or None')
check('(OO)', 42, '2-item sequence', 'int')
check('(OO)?', 42, '2-item sequence or None', 'int')
check('(OO)', (1, 2, 3), 'sequence of length 2', '3')
check('(OO)', 42, '2-item tuple', 'int')
check('(OO)?', 42, '2-item tuple or None', 'int')
check('(OO)', (1, 2, 3), 'tuple of length 2', '3')

def test_nullable(self):
parse = _testcapi.parse_tuple_and_keywords
Expand Down
11 changes: 9 additions & 2 deletions Python/getargs.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,8 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
int i;
Py_ssize_t len;
bool nullable = false;
int istuple = PyTuple_Check(arg);
int mustbetuple = istuple;

assert(*format == '(');
format++;
Expand Down Expand Up @@ -529,10 +531,15 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
return msg;
}
if (!PySequence_Check(arg) || PyBytes_Check(arg)) {
if (istuple) {
/* fallthrough */
}
else if (!PySequence_Check(arg) ||
PyUnicode_Check(arg) || PyBytes_Check(arg) || PyByteArray_Check(arg))
{
levels[0] = 0;
PyOS_snprintf(msgbuf, bufsize,
"must be %d-item sequence%s, not %.50s",
"must be %d-item tuple%s, not %.50s",
n,
nullable ? " or None" : "",
arg == Py_None ? "None" : Py_TYPE(arg)->tp_name);
Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.