Commit a2314283 authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

bpo-20047: Make bytearray methods partition() and rpartition() rejecting (#4158)

separators that are not bytes-like objects.
parent 5a4bbcd4
...@@ -2573,8 +2573,9 @@ arbitrary binary data. ...@@ -2573,8 +2573,9 @@ arbitrary binary data.
bytearray.partition(sep) bytearray.partition(sep)
Split the sequence at the first occurrence of *sep*, and return a 3-tuple Split the sequence at the first occurrence of *sep*, and return a 3-tuple
containing the part before the separator, the separator, and the part containing the part before the separator, the separator itself or its
after the separator. If the separator is not found, return a 3-tuple bytearray copy, and the part after the separator.
If the separator is not found, return a 3-tuple
containing a copy of the original sequence, followed by two empty bytes or containing a copy of the original sequence, followed by two empty bytes or
bytearray objects. bytearray objects.
...@@ -2629,8 +2630,9 @@ arbitrary binary data. ...@@ -2629,8 +2630,9 @@ arbitrary binary data.
bytearray.rpartition(sep) bytearray.rpartition(sep)
Split the sequence at the last occurrence of *sep*, and return a 3-tuple Split the sequence at the last occurrence of *sep*, and return a 3-tuple
containing the part before the separator, the separator, and the part containing the part before the separator, the separator itself or its
after the separator. If the separator is not found, return a 3-tuple bytearray copy, and the part after the separator.
If the separator is not found, return a 3-tuple
containing a copy of the original sequence, followed by two empty bytes or containing a copy of the original sequence, followed by two empty bytes or
bytearray objects. bytearray objects.
......
...@@ -548,8 +548,16 @@ class BaseBytesTest: ...@@ -548,8 +548,16 @@ class BaseBytesTest:
self.assertEqual(b.replace(b'i', b'a'), b'massassappa') self.assertEqual(b.replace(b'i', b'a'), b'massassappa')
self.assertEqual(b.replace(b'ss', b'x'), b'mixixippi') self.assertEqual(b.replace(b'ss', b'x'), b'mixixippi')
def test_replace_int_error(self):
self.assertRaises(TypeError, self.type2test(b'a b').replace, 32, b'')
def test_split_string_error(self): def test_split_string_error(self):
self.assertRaises(TypeError, self.type2test(b'a b').split, ' ') self.assertRaises(TypeError, self.type2test(b'a b').split, ' ')
self.assertRaises(TypeError, self.type2test(b'a b').rsplit, ' ')
def test_split_int_error(self):
self.assertRaises(TypeError, self.type2test(b'a b').split, 32)
self.assertRaises(TypeError, self.type2test(b'a b').rsplit, 32)
def test_split_unicodewhitespace(self): def test_split_unicodewhitespace(self):
for b in (b'a\x1Cb', b'a\x1Db', b'a\x1Eb', b'a\x1Fb'): for b in (b'a\x1Cb', b'a\x1Db', b'a\x1Eb', b'a\x1Fb'):
...@@ -558,9 +566,6 @@ class BaseBytesTest: ...@@ -558,9 +566,6 @@ class BaseBytesTest:
b = self.type2test(b"\x09\x0A\x0B\x0C\x0D\x1C\x1D\x1E\x1F") b = self.type2test(b"\x09\x0A\x0B\x0C\x0D\x1C\x1D\x1E\x1F")
self.assertEqual(b.split(), [b'\x1c\x1d\x1e\x1f']) self.assertEqual(b.split(), [b'\x1c\x1d\x1e\x1f'])
def test_rsplit_string_error(self):
self.assertRaises(TypeError, self.type2test(b'a b').rsplit, ' ')
def test_rsplit_unicodewhitespace(self): def test_rsplit_unicodewhitespace(self):
b = self.type2test(b"\x09\x0A\x0B\x0C\x0D\x1C\x1D\x1E\x1F") b = self.type2test(b"\x09\x0A\x0B\x0C\x0D\x1C\x1D\x1E\x1F")
self.assertEqual(b.rsplit(), [b'\x1c\x1d\x1e\x1f']) self.assertEqual(b.rsplit(), [b'\x1c\x1d\x1e\x1f'])
...@@ -576,6 +581,14 @@ class BaseBytesTest: ...@@ -576,6 +581,14 @@ class BaseBytesTest:
self.assertEqual(b.rpartition(b'i'), (b'mississipp', b'i', b'')) self.assertEqual(b.rpartition(b'i'), (b'mississipp', b'i', b''))
self.assertEqual(b.rpartition(b'w'), (b'', b'', b'mississippi')) self.assertEqual(b.rpartition(b'w'), (b'', b'', b'mississippi'))
def test_partition_string_error(self):
self.assertRaises(TypeError, self.type2test(b'a b').partition, ' ')
self.assertRaises(TypeError, self.type2test(b'a b').rpartition, ' ')
def test_partition_int_error(self):
self.assertRaises(TypeError, self.type2test(b'a b').partition, 32)
self.assertRaises(TypeError, self.type2test(b'a b').rpartition, 32)
def test_pickling(self): def test_pickling(self):
for proto in range(pickle.HIGHEST_PROTOCOL + 1): for proto in range(pickle.HIGHEST_PROTOCOL + 1):
for b in b"", b"a", b"abc", b"\xffab\x80", b"\0\0\377\0\0": for b in b"", b"a", b"abc", b"\xffab\x80", b"\0\0\377\0\0":
...@@ -608,9 +621,14 @@ class BaseBytesTest: ...@@ -608,9 +621,14 @@ class BaseBytesTest:
self.assertEqual(self.type2test(b'abc').rstrip(memoryview(b'ac')), b'ab') self.assertEqual(self.type2test(b'abc').rstrip(memoryview(b'ac')), b'ab')
def test_strip_string_error(self): def test_strip_string_error(self):
self.assertRaises(TypeError, self.type2test(b'abc').strip, 'b') self.assertRaises(TypeError, self.type2test(b'abc').strip, 'ac')
self.assertRaises(TypeError, self.type2test(b'abc').lstrip, 'b') self.assertRaises(TypeError, self.type2test(b'abc').lstrip, 'ac')
self.assertRaises(TypeError, self.type2test(b'abc').rstrip, 'b') self.assertRaises(TypeError, self.type2test(b'abc').rstrip, 'ac')
def test_strip_int_error(self):
self.assertRaises(TypeError, self.type2test(b' abc ').strip, 32)
self.assertRaises(TypeError, self.type2test(b' abc ').lstrip, 32)
self.assertRaises(TypeError, self.type2test(b' abc ').rstrip, 32)
def test_center(self): def test_center(self):
# Fill character can be either bytes or bytearray (issue 12380) # Fill character can be either bytes or bytearray (issue 12380)
...@@ -633,6 +651,11 @@ class BaseBytesTest: ...@@ -633,6 +651,11 @@ class BaseBytesTest:
self.assertEqual(b.rjust(7, fill_type(b'-')), self.assertEqual(b.rjust(7, fill_type(b'-')),
self.type2test(b'----abc')) self.type2test(b'----abc'))
def test_xjust_int_error(self):
self.assertRaises(TypeError, self.type2test(b'abc').center, 7, 32)
self.assertRaises(TypeError, self.type2test(b'abc').ljust, 7, 32)
self.assertRaises(TypeError, self.type2test(b'abc').rjust, 7, 32)
def test_ord(self): def test_ord(self):
b = self.type2test(b'\0A\x7f\x80\xff') b = self.type2test(b'\0A\x7f\x80\xff')
self.assertEqual([ord(b[i:i+1]) for i in range(len(b))], self.assertEqual([ord(b[i:i+1]) for i in range(len(b))],
......
Bytearray methods partition() and rpartition() now accept only bytes-like
objects as separator, as documented. In particular they now raise TypeError
rather of returning a bogus result when an integer is passed as a separator.
...@@ -104,6 +104,26 @@ PyByteArray_FromObject(PyObject *input) ...@@ -104,6 +104,26 @@ PyByteArray_FromObject(PyObject *input)
input, NULL); input, NULL);
} }
static PyObject *
_PyByteArray_FromBufferObject(PyObject *obj)
{
PyObject *result;
Py_buffer view;
if (PyObject_GetBuffer(obj, &view, PyBUF_FULL_RO) < 0) {
return NULL;
}
result = PyByteArray_FromStringAndSize(NULL, view.len);
if (result != NULL &&
PyBuffer_ToContiguous(PyByteArray_AS_STRING(result),
&view, view.len, 'C') < 0)
{
Py_CLEAR(result);
}
PyBuffer_Release(&view);
return result;
}
PyObject * PyObject *
PyByteArray_FromStringAndSize(const char *bytes, Py_ssize_t size) PyByteArray_FromStringAndSize(const char *bytes, Py_ssize_t size)
{ {
...@@ -536,7 +556,8 @@ bytearray_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi, ...@@ -536,7 +556,8 @@ bytearray_setslice(PyByteArrayObject *self, Py_ssize_t lo, Py_ssize_t hi,
if (values == (PyObject *)self) { if (values == (PyObject *)self) {
/* Make a copy and call this function recursively */ /* Make a copy and call this function recursively */
int err; int err;
values = PyByteArray_FromObject(values); values = PyByteArray_FromStringAndSize(PyByteArray_AS_STRING(values),
PyByteArray_GET_SIZE(values));
if (values == NULL) if (values == NULL)
return -1; return -1;
err = bytearray_setslice(self, lo, hi, values); err = bytearray_setslice(self, lo, hi, values);
...@@ -1387,19 +1408,19 @@ Partition the bytearray into three parts using the given separator. ...@@ -1387,19 +1408,19 @@ Partition the bytearray into three parts using the given separator.
This will search for the separator sep in the bytearray. If the separator is This will search for the separator sep in the bytearray. If the separator is
found, returns a 3-tuple containing the part before the separator, the found, returns a 3-tuple containing the part before the separator, the
separator itself, and the part after it. separator itself, and the part after it as new bytearray objects.
If the separator is not found, returns a 3-tuple containing the original If the separator is not found, returns a 3-tuple containing the copy of the
bytearray object and two empty bytearray objects. original bytearray object and two empty bytearray objects.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
bytearray_partition(PyByteArrayObject *self, PyObject *sep) bytearray_partition(PyByteArrayObject *self, PyObject *sep)
/*[clinic end generated code: output=45d2525ddd35f957 input=86f89223892b70b5]*/ /*[clinic end generated code: output=45d2525ddd35f957 input=8f644749ee4fc83a]*/
{ {
PyObject *bytesep, *result; PyObject *bytesep, *result;
bytesep = PyByteArray_FromObject(sep); bytesep = _PyByteArray_FromBufferObject(sep);
if (! bytesep) if (! bytesep)
return NULL; return NULL;
...@@ -1420,23 +1441,24 @@ bytearray.rpartition ...@@ -1420,23 +1441,24 @@ bytearray.rpartition
sep: object sep: object
/ /
Partition the bytes into three parts using the given separator. Partition the bytearray into three parts using the given separator.
This will search for the separator sep in the bytearray, starting and the end. This will search for the separator sep in the bytearray, starting at the end.
If the separator is found, returns a 3-tuple containing the part before the If the separator is found, returns a 3-tuple containing the part before the
separator, the separator itself, and the part after it. separator, the separator itself, and the part after it as new bytearray
objects.
If the separator is not found, returns a 3-tuple containing two empty bytearray If the separator is not found, returns a 3-tuple containing two empty bytearray
objects and the original bytearray object. objects and the copy of the original bytearray object.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
bytearray_rpartition(PyByteArrayObject *self, PyObject *sep) bytearray_rpartition(PyByteArrayObject *self, PyObject *sep)
/*[clinic end generated code: output=440de3c9426115e8 input=5f4094f2de87c8f3]*/ /*[clinic end generated code: output=440de3c9426115e8 input=7e3df3e6cb8fa0ac]*/
{ {
PyObject *bytesep, *result; PyObject *bytesep, *result;
bytesep = PyByteArray_FromObject(sep); bytesep = _PyByteArray_FromBufferObject(sep);
if (! bytesep) if (! bytesep)
return NULL; return NULL;
......
...@@ -1834,7 +1834,7 @@ bytes.rpartition ...@@ -1834,7 +1834,7 @@ bytes.rpartition
Partition the bytes into three parts using the given separator. Partition the bytes into three parts using the given separator.
This will search for the separator sep in the bytes, starting and the end. If This will search for the separator sep in the bytes, starting at the end. If
the separator is found, returns a 3-tuple containing the part before the the separator is found, returns a 3-tuple containing the part before the
separator, the separator itself, and the part after it. separator, the separator itself, and the part after it.
...@@ -1844,7 +1844,7 @@ objects and the original bytes object. ...@@ -1844,7 +1844,7 @@ objects and the original bytes object.
static PyObject * static PyObject *
bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep) bytes_rpartition_impl(PyBytesObject *self, Py_buffer *sep)
/*[clinic end generated code: output=191b114cbb028e50 input=67f689e63a62d478]*/ /*[clinic end generated code: output=191b114cbb028e50 input=d78db010c8cfdbe1]*/
{ {
return stringlib_rpartition( return stringlib_rpartition(
(PyObject*) self, (PyObject*) self,
......
...@@ -214,10 +214,10 @@ PyDoc_STRVAR(bytearray_partition__doc__, ...@@ -214,10 +214,10 @@ PyDoc_STRVAR(bytearray_partition__doc__,
"\n" "\n"
"This will search for the separator sep in the bytearray. If the separator is\n" "This will search for the separator sep in the bytearray. If the separator is\n"
"found, returns a 3-tuple containing the part before the separator, the\n" "found, returns a 3-tuple containing the part before the separator, the\n"
"separator itself, and the part after it.\n" "separator itself, and the part after it as new bytearray objects.\n"
"\n" "\n"
"If the separator is not found, returns a 3-tuple containing the original\n" "If the separator is not found, returns a 3-tuple containing the copy of the\n"
"bytearray object and two empty bytearray objects."); "original bytearray object and two empty bytearray objects.");
#define BYTEARRAY_PARTITION_METHODDEF \ #define BYTEARRAY_PARTITION_METHODDEF \
{"partition", (PyCFunction)bytearray_partition, METH_O, bytearray_partition__doc__}, {"partition", (PyCFunction)bytearray_partition, METH_O, bytearray_partition__doc__},
...@@ -226,14 +226,15 @@ PyDoc_STRVAR(bytearray_rpartition__doc__, ...@@ -226,14 +226,15 @@ PyDoc_STRVAR(bytearray_rpartition__doc__,
"rpartition($self, sep, /)\n" "rpartition($self, sep, /)\n"
"--\n" "--\n"
"\n" "\n"
"Partition the bytes into three parts using the given separator.\n" "Partition the bytearray into three parts using the given separator.\n"
"\n" "\n"
"This will search for the separator sep in the bytearray, starting and the end.\n" "This will search for the separator sep in the bytearray, starting at the end.\n"
"If the separator is found, returns a 3-tuple containing the part before the\n" "If the separator is found, returns a 3-tuple containing the part before the\n"
"separator, the separator itself, and the part after it.\n" "separator, the separator itself, and the part after it as new bytearray\n"
"objects.\n"
"\n" "\n"
"If the separator is not found, returns a 3-tuple containing two empty bytearray\n" "If the separator is not found, returns a 3-tuple containing two empty bytearray\n"
"objects and the original bytearray object."); "objects and the copy of the original bytearray object.");
#define BYTEARRAY_RPARTITION_METHODDEF \ #define BYTEARRAY_RPARTITION_METHODDEF \
{"rpartition", (PyCFunction)bytearray_rpartition, METH_O, bytearray_rpartition__doc__}, {"rpartition", (PyCFunction)bytearray_rpartition, METH_O, bytearray_rpartition__doc__},
...@@ -711,4 +712,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) ...@@ -711,4 +712,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
{ {
return bytearray_sizeof_impl(self); return bytearray_sizeof_impl(self);
} }
/*[clinic end generated code: output=e53f10084457a46b input=a9049054013a1b77]*/ /*[clinic end generated code: output=c2804d009182328c input=a9049054013a1b77]*/
...@@ -86,7 +86,7 @@ PyDoc_STRVAR(bytes_rpartition__doc__, ...@@ -86,7 +86,7 @@ PyDoc_STRVAR(bytes_rpartition__doc__,
"\n" "\n"
"Partition the bytes into three parts using the given separator.\n" "Partition the bytes into three parts using the given separator.\n"
"\n" "\n"
"This will search for the separator sep in the bytes, starting and the end. If\n" "This will search for the separator sep in the bytes, starting at the end. If\n"
"the separator is found, returns a 3-tuple containing the part before the\n" "the separator is found, returns a 3-tuple containing the part before the\n"
"separator, the separator itself, and the part after it.\n" "separator, the separator itself, and the part after it.\n"
"\n" "\n"
...@@ -499,4 +499,4 @@ bytes_fromhex(PyTypeObject *type, PyObject *arg) ...@@ -499,4 +499,4 @@ bytes_fromhex(PyTypeObject *type, PyObject *arg)
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=9e3374bd7d04c163 input=a9049054013a1b77]*/ /*[clinic end generated code: output=fc9e02359cc56d36 input=a9049054013a1b77]*/
...@@ -682,7 +682,7 @@ PyDoc_STRVAR(unicode_rpartition__doc__, ...@@ -682,7 +682,7 @@ PyDoc_STRVAR(unicode_rpartition__doc__,
"\n" "\n"
"Partition the string into three parts using the given separator.\n" "Partition the string into three parts using the given separator.\n"
"\n" "\n"
"This will search for the separator in the string, starting and the end. If\n" "This will search for the separator in the string, starting at the end. If\n"
"the separator is found, returns a 3-tuple containing the part before the\n" "the separator is found, returns a 3-tuple containing the part before the\n"
"separator, the separator itself, and the part after it.\n" "separator, the separator itself, and the part after it.\n"
"\n" "\n"
...@@ -930,4 +930,4 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) ...@@ -930,4 +930,4 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
return unicode_sizeof_impl(self); return unicode_sizeof_impl(self);
} }
/*[clinic end generated code: output=8fd799fd7f2cc724 input=a9049054013a1b77]*/ /*[clinic end generated code: output=816292e81a8a732e input=a9049054013a1b77]*/
...@@ -13067,7 +13067,7 @@ str.rpartition as unicode_rpartition = str.partition ...@@ -13067,7 +13067,7 @@ str.rpartition as unicode_rpartition = str.partition
Partition the string into three parts using the given separator. Partition the string into three parts using the given separator.
This will search for the separator in the string, starting and the end. If This will search for the separator in the string, starting at the end. If
the separator is found, returns a 3-tuple containing the part before the the separator is found, returns a 3-tuple containing the part before the
separator, the separator itself, and the part after it. separator, the separator itself, and the part after it.
...@@ -13077,7 +13077,7 @@ and the original string. ...@@ -13077,7 +13077,7 @@ and the original string.
static PyObject * static PyObject *
unicode_rpartition(PyObject *self, PyObject *sep) unicode_rpartition(PyObject *self, PyObject *sep)
/*[clinic end generated code: output=1aa13cf1156572aa input=e77c7acb69bdfca6]*/ /*[clinic end generated code: output=1aa13cf1156572aa input=c4b7db3ef5cf336a]*/
{ {
return PyUnicode_RPartition(self, sep); return PyUnicode_RPartition(self, sep);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment