mirror of https://github.com/python/cpython
gh-121645: Add PyBytes_Join() function (#121646)
* Replace _PyBytes_Join() with PyBytes_Join(). * Keep _PyBytes_Join() as an alias to PyBytes_Join().
This commit is contained in:
parent
7fca268bee
commit
3d60dfbe17
|
@ -189,6 +189,24 @@ called with a non-bytes parameter.
|
|||
to *newpart* (i.e. decrements its reference count).
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable)
|
||||
|
||||
Similar to ``sep.join(iterable)`` in Python.
|
||||
|
||||
*sep* must be Python :class:`bytes` object.
|
||||
(Note that :c:func:`PyUnicode_Join` accepts ``NULL`` separator and treats
|
||||
it as a space, whereas :c:func:`PyBytes_Join` doesn't accept ``NULL``
|
||||
separator.)
|
||||
|
||||
*iterable* must be an iterable object yielding objects that implement the
|
||||
:ref:`buffer protocol <bufferobjects>`.
|
||||
|
||||
On success, return a new :class:`bytes` object.
|
||||
On error, set an exception and return ``NULL``.
|
||||
|
||||
.. versionadded: 3.14
|
||||
|
||||
|
||||
.. c:function:: int _PyBytes_Resize(PyObject **bytes, Py_ssize_t newsize)
|
||||
|
||||
Resize a bytes object. *newsize* will be the new length of the bytes object.
|
||||
|
|
|
@ -485,6 +485,11 @@ New Features
|
|||
|
||||
(Contributed by Victor Stinner in :gh:`120389`.)
|
||||
|
||||
* Add :c:func:`PyBytes_Join(sep, iterable) <PyBytes_Join>` function,
|
||||
similar to ``sep.join(iterable)`` in Python.
|
||||
(Contributed by Victor Stinner in :gh:`121645`.)
|
||||
|
||||
|
||||
Porting to Python 3.14
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ static inline Py_ssize_t PyBytes_GET_SIZE(PyObject *op) {
|
|||
}
|
||||
#define PyBytes_GET_SIZE(self) PyBytes_GET_SIZE(_PyObject_CAST(self))
|
||||
|
||||
/* _PyBytes_Join(sep, x) is like sep.join(x). sep must be PyBytesObject*,
|
||||
x must be an iterable object. */
|
||||
PyAPI_FUNC(PyObject*) _PyBytes_Join(PyObject *sep, PyObject *x);
|
||||
PyAPI_FUNC(PyObject*) PyBytes_Join(PyObject *sep, PyObject *iterable);
|
||||
|
||||
// Alias kept for backward compatibility
|
||||
#define _PyBytes_Join PyBytes_Join
|
||||
|
|
|
@ -249,6 +249,46 @@ class CAPITest(unittest.TestCase):
|
|||
# CRASHES resize(NULL, 0, False)
|
||||
# CRASHES resize(NULL, 3, False)
|
||||
|
||||
def test_join(self):
|
||||
"""Test PyBytes_Join()"""
|
||||
bytes_join = _testcapi.bytes_join
|
||||
|
||||
self.assertEqual(bytes_join(b'', []), b'')
|
||||
self.assertEqual(bytes_join(b'sep', []), b'')
|
||||
|
||||
self.assertEqual(bytes_join(b'', [b'a', b'b', b'c']), b'abc')
|
||||
self.assertEqual(bytes_join(b'-', [b'a', b'b', b'c']), b'a-b-c')
|
||||
self.assertEqual(bytes_join(b' - ', [b'a', b'b', b'c']), b'a - b - c')
|
||||
self.assertEqual(bytes_join(b'-', [bytearray(b'abc'),
|
||||
memoryview(b'def')]),
|
||||
b'abc-def')
|
||||
|
||||
self.assertEqual(bytes_join(b'-', iter([b'a', b'b', b'c'])), b'a-b-c')
|
||||
|
||||
# invalid 'sep' argument
|
||||
with self.assertRaises(TypeError):
|
||||
bytes_join(bytearray(b'sep'), [])
|
||||
with self.assertRaises(TypeError):
|
||||
bytes_join(memoryview(b'sep'), [])
|
||||
with self.assertRaises(TypeError):
|
||||
bytes_join('', []) # empty Unicode string
|
||||
with self.assertRaises(TypeError):
|
||||
bytes_join('unicode', [])
|
||||
with self.assertRaises(TypeError):
|
||||
bytes_join(123, [])
|
||||
with self.assertRaises(SystemError):
|
||||
self.assertEqual(bytes_join(NULL, [b'a', b'b', b'c']), b'abc')
|
||||
|
||||
# invalid 'iterable' argument
|
||||
with self.assertRaises(TypeError):
|
||||
bytes_join(b'', [b'bytes', 'unicode'])
|
||||
with self.assertRaises(TypeError):
|
||||
bytes_join(b'', [b'bytes', 123])
|
||||
with self.assertRaises(TypeError):
|
||||
bytes_join(b'', 123)
|
||||
with self.assertRaises(SystemError):
|
||||
bytes_join(b'', NULL)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Add :c:func:`PyBytes_Join(sep, iterable) <PyBytes_Join>` function, similar to
|
||||
``sep.join(iterable)`` in Python. Patch by Victor Stinner.
|
|
@ -1283,7 +1283,7 @@ found:
|
|||
Py_CLEAR(res);
|
||||
goto end;
|
||||
}
|
||||
Py_XSETREF(res, _PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks));
|
||||
Py_XSETREF(res, PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks));
|
||||
|
||||
end:
|
||||
LEAVE_BUFFERED(self)
|
||||
|
@ -1736,7 +1736,7 @@ _bufferedreader_read_all(buffered *self)
|
|||
goto cleanup;
|
||||
}
|
||||
else {
|
||||
tmp = _PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks);
|
||||
tmp = PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks);
|
||||
res = tmp;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
|
@ -999,7 +999,7 @@ _io__RawIOBase_readall_impl(PyObject *self)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
result = _PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks);
|
||||
result = PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), chunks);
|
||||
Py_DECREF(chunks);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1287,7 +1287,7 @@ pattern_subx(_sremodulestate* module_state,
|
|||
}
|
||||
else {
|
||||
if (state.isbytes)
|
||||
item = _PyBytes_Join(joiner, list);
|
||||
item = PyBytes_Join(joiner, list);
|
||||
else
|
||||
item = PyUnicode_Join(joiner, list);
|
||||
Py_DECREF(joiner);
|
||||
|
@ -2918,7 +2918,7 @@ expand_template(TemplateObject *self, MatchObject *match)
|
|||
}
|
||||
else {
|
||||
Py_SET_SIZE(list, count);
|
||||
result = _PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), list);
|
||||
result = PyBytes_Join((PyObject *)&_Py_SINGLETON(bytes_empty), list);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
|
|
@ -37,8 +37,23 @@ bytes_resize(PyObject *Py_UNUSED(module), PyObject *args)
|
|||
}
|
||||
|
||||
|
||||
/* Test PyBytes_Join() */
|
||||
static PyObject *
|
||||
bytes_join(PyObject *Py_UNUSED(module), PyObject *args)
|
||||
{
|
||||
PyObject *sep, *iterable;
|
||||
if (!PyArg_ParseTuple(args, "OO", &sep, &iterable)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(sep);
|
||||
NULLABLE(iterable);
|
||||
return PyBytes_Join(sep, iterable);
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"bytes_resize", bytes_resize, METH_VARARGS},
|
||||
{"bytes_join", bytes_join, METH_VARARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -1867,11 +1867,19 @@ bytes_join(PyBytesObject *self, PyObject *iterable_of_bytes)
|
|||
}
|
||||
|
||||
PyObject *
|
||||
_PyBytes_Join(PyObject *sep, PyObject *x)
|
||||
PyBytes_Join(PyObject *sep, PyObject *iterable)
|
||||
{
|
||||
assert(sep != NULL && PyBytes_Check(sep));
|
||||
assert(x != NULL);
|
||||
return bytes_join((PyBytesObject*)sep, x);
|
||||
if (sep == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
}
|
||||
if (!PyBytes_Check(sep)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"sep: expected bytes, got %T", sep);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return stringlib_bytes_join(sep, iterable);
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
|
Loading…
Reference in New Issue