mirror of https://github.com/python/cpython
Issue #27506: Support bytes/bytearray.translate() delete as keyword argument
Patch by Xiang Zhang.
This commit is contained in:
parent
8c3c52b19f
commit
1b6c6da85d
|
@ -2631,8 +2631,8 @@ arbitrary binary data.
|
||||||
The prefix(es) to search for may be any :term:`bytes-like object`.
|
The prefix(es) to search for may be any :term:`bytes-like object`.
|
||||||
|
|
||||||
|
|
||||||
.. method:: bytes.translate(table[, delete])
|
.. method:: bytes.translate(table, delete=b'')
|
||||||
bytearray.translate(table[, delete])
|
bytearray.translate(table, delete=b'')
|
||||||
|
|
||||||
Return a copy of the bytes or bytearray object where all bytes occurring in
|
Return a copy of the bytes or bytearray object where all bytes occurring in
|
||||||
the optional argument *delete* are removed, and the remaining bytes have
|
the optional argument *delete* are removed, and the remaining bytes have
|
||||||
|
@ -2648,6 +2648,9 @@ arbitrary binary data.
|
||||||
>>> b'read this short text'.translate(None, b'aeiou')
|
>>> b'read this short text'.translate(None, b'aeiou')
|
||||||
b'rd ths shrt txt'
|
b'rd ths shrt txt'
|
||||||
|
|
||||||
|
.. versionchanged:: 3.6
|
||||||
|
*delete* is now supported as a keyword argument.
|
||||||
|
|
||||||
|
|
||||||
The following methods on bytes and bytearray objects have default behaviours
|
The following methods on bytes and bytearray objects have default behaviours
|
||||||
that assume the use of ASCII compatible binary formats, but can still be used
|
that assume the use of ASCII compatible binary formats, but can still be used
|
||||||
|
|
|
@ -689,6 +689,37 @@ class BaseBytesTest:
|
||||||
test.support.check_free_after_iterating(self, iter, self.type2test)
|
test.support.check_free_after_iterating(self, iter, self.type2test)
|
||||||
test.support.check_free_after_iterating(self, reversed, self.type2test)
|
test.support.check_free_after_iterating(self, reversed, self.type2test)
|
||||||
|
|
||||||
|
def test_translate(self):
|
||||||
|
b = self.type2test(b'hello')
|
||||||
|
rosetta = bytearray(range(256))
|
||||||
|
rosetta[ord('o')] = ord('e')
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, b.translate)
|
||||||
|
self.assertRaises(TypeError, b.translate, None, None)
|
||||||
|
self.assertRaises(ValueError, b.translate, bytes(range(255)))
|
||||||
|
|
||||||
|
c = b.translate(rosetta, b'hello')
|
||||||
|
self.assertEqual(b, b'hello')
|
||||||
|
self.assertIsInstance(c, self.type2test)
|
||||||
|
|
||||||
|
c = b.translate(rosetta)
|
||||||
|
d = b.translate(rosetta, b'')
|
||||||
|
self.assertEqual(c, d)
|
||||||
|
self.assertEqual(c, b'helle')
|
||||||
|
|
||||||
|
c = b.translate(rosetta, b'l')
|
||||||
|
self.assertEqual(c, b'hee')
|
||||||
|
c = b.translate(None, b'e')
|
||||||
|
self.assertEqual(c, b'hllo')
|
||||||
|
|
||||||
|
# test delete as a keyword argument
|
||||||
|
c = b.translate(rosetta, delete=b'')
|
||||||
|
self.assertEqual(c, b'helle')
|
||||||
|
c = b.translate(rosetta, delete=b'l')
|
||||||
|
self.assertEqual(c, b'hee')
|
||||||
|
c = b.translate(None, delete=b'e')
|
||||||
|
self.assertEqual(c, b'hllo')
|
||||||
|
|
||||||
|
|
||||||
class BytesTest(BaseBytesTest, unittest.TestCase):
|
class BytesTest(BaseBytesTest, unittest.TestCase):
|
||||||
type2test = bytes
|
type2test = bytes
|
||||||
|
@ -1449,24 +1480,6 @@ class AssortedBytesTest(unittest.TestCase):
|
||||||
self.assertRaises(SyntaxError, eval,
|
self.assertRaises(SyntaxError, eval,
|
||||||
'b"%s"' % chr(c))
|
'b"%s"' % chr(c))
|
||||||
|
|
||||||
def test_translate(self):
|
|
||||||
b = b'hello'
|
|
||||||
ba = bytearray(b)
|
|
||||||
rosetta = bytearray(range(0, 256))
|
|
||||||
rosetta[ord('o')] = ord('e')
|
|
||||||
c = b.translate(rosetta, b'l')
|
|
||||||
self.assertEqual(b, b'hello')
|
|
||||||
self.assertEqual(c, b'hee')
|
|
||||||
c = ba.translate(rosetta, b'l')
|
|
||||||
self.assertEqual(ba, b'hello')
|
|
||||||
self.assertEqual(c, b'hee')
|
|
||||||
c = b.translate(None, b'e')
|
|
||||||
self.assertEqual(c, b'hllo')
|
|
||||||
c = ba.translate(None, b'e')
|
|
||||||
self.assertEqual(c, b'hllo')
|
|
||||||
self.assertRaises(TypeError, b.translate, None, None)
|
|
||||||
self.assertRaises(TypeError, ba.translate, None, None)
|
|
||||||
|
|
||||||
def test_split_bytearray(self):
|
def test_split_bytearray(self):
|
||||||
self.assertEqual(b'a b'.split(memoryview(b' ')), [b'a', b'b'])
|
self.assertEqual(b'a b'.split(memoryview(b' ')), [b'a', b'b'])
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@ What's New in Python 3.6.0 beta 1
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #27506: Support passing the bytes/bytearray.translate() "delete"
|
||||||
|
argument by keyword.
|
||||||
|
|
||||||
- Issue #27587: Fix another issue found by PVS-Studio: Null pointer check
|
- Issue #27587: Fix another issue found by PVS-Studio: Null pointer check
|
||||||
after use of 'def' in _PyState_AddModule().
|
after use of 'def' in _PyState_AddModule().
|
||||||
Initial patch by Christian Heimes.
|
Initial patch by Christian Heimes.
|
||||||
|
|
|
@ -1175,21 +1175,19 @@ bytearray.translate
|
||||||
|
|
||||||
table: object
|
table: object
|
||||||
Translation table, which must be a bytes object of length 256.
|
Translation table, which must be a bytes object of length 256.
|
||||||
[
|
|
||||||
deletechars: object
|
|
||||||
]
|
|
||||||
/
|
/
|
||||||
|
delete as deletechars: object(c_default="NULL") = b''
|
||||||
|
|
||||||
Return a copy with each character mapped by the given translation table.
|
Return a copy with each character mapped by the given translation table.
|
||||||
|
|
||||||
All characters occurring in the optional argument deletechars are removed.
|
All characters occurring in the optional argument delete are removed.
|
||||||
The remaining characters are mapped through the given translation table.
|
The remaining characters are mapped through the given translation table.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytearray_translate_impl(PyByteArrayObject *self, PyObject *table,
|
bytearray_translate_impl(PyByteArrayObject *self, PyObject *table,
|
||||||
int group_right_1, PyObject *deletechars)
|
PyObject *deletechars)
|
||||||
/*[clinic end generated code: output=2bebc86a9a1ff083 input=846a01671bccc1c5]*/
|
/*[clinic end generated code: output=b6a8f01c2a74e446 input=cfff956d4d127a9b]*/
|
||||||
{
|
{
|
||||||
char *input, *output;
|
char *input, *output;
|
||||||
const char *table_chars;
|
const char *table_chars;
|
||||||
|
@ -1258,8 +1256,7 @@ bytearray_translate_impl(PyByteArrayObject *self, PyObject *table,
|
||||||
for (i = inlen; --i >= 0; ) {
|
for (i = inlen; --i >= 0; ) {
|
||||||
c = Py_CHARMASK(*input++);
|
c = Py_CHARMASK(*input++);
|
||||||
if (trans_table[c] != -1)
|
if (trans_table[c] != -1)
|
||||||
if (Py_CHARMASK(*output++ = (char)trans_table[c]) == c)
|
*output++ = (char)trans_table[c];
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
/* Fix the size of the resulting string */
|
/* Fix the size of the resulting string */
|
||||||
if (inlen > 0)
|
if (inlen > 0)
|
||||||
|
|
|
@ -2045,21 +2045,19 @@ bytes.translate
|
||||||
|
|
||||||
table: object
|
table: object
|
||||||
Translation table, which must be a bytes object of length 256.
|
Translation table, which must be a bytes object of length 256.
|
||||||
[
|
|
||||||
deletechars: object
|
|
||||||
]
|
|
||||||
/
|
/
|
||||||
|
delete as deletechars: object(c_default="NULL") = b''
|
||||||
|
|
||||||
Return a copy with each character mapped by the given translation table.
|
Return a copy with each character mapped by the given translation table.
|
||||||
|
|
||||||
All characters occurring in the optional argument deletechars are removed.
|
All characters occurring in the optional argument delete are removed.
|
||||||
The remaining characters are mapped through the given translation table.
|
The remaining characters are mapped through the given translation table.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytes_translate_impl(PyBytesObject *self, PyObject *table, int group_right_1,
|
bytes_translate_impl(PyBytesObject *self, PyObject *table,
|
||||||
PyObject *deletechars)
|
PyObject *deletechars)
|
||||||
/*[clinic end generated code: output=233df850eb50bf8d input=ca20edf39d780d49]*/
|
/*[clinic end generated code: output=43be3437f1956211 input=0ecdf159f654233c]*/
|
||||||
{
|
{
|
||||||
char *input, *output;
|
char *input, *output;
|
||||||
Py_buffer table_view = {NULL, NULL};
|
Py_buffer table_view = {NULL, NULL};
|
||||||
|
|
|
@ -39,47 +39,38 @@ bytearray_copy(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(bytearray_translate__doc__,
|
PyDoc_STRVAR(bytearray_translate__doc__,
|
||||||
"translate(table, [deletechars])\n"
|
"translate($self, table, /, delete=b\'\')\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
"Return a copy with each character mapped by the given translation table.\n"
|
"Return a copy with each character mapped by the given translation table.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" table\n"
|
" table\n"
|
||||||
" Translation table, which must be a bytes object of length 256.\n"
|
" Translation table, which must be a bytes object of length 256.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"All characters occurring in the optional argument deletechars are removed.\n"
|
"All characters occurring in the optional argument delete are removed.\n"
|
||||||
"The remaining characters are mapped through the given translation table.");
|
"The remaining characters are mapped through the given translation table.");
|
||||||
|
|
||||||
#define BYTEARRAY_TRANSLATE_METHODDEF \
|
#define BYTEARRAY_TRANSLATE_METHODDEF \
|
||||||
{"translate", (PyCFunction)bytearray_translate, METH_VARARGS, bytearray_translate__doc__},
|
{"translate", (PyCFunction)bytearray_translate, METH_VARARGS|METH_KEYWORDS, bytearray_translate__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytearray_translate_impl(PyByteArrayObject *self, PyObject *table,
|
bytearray_translate_impl(PyByteArrayObject *self, PyObject *table,
|
||||||
int group_right_1, PyObject *deletechars);
|
PyObject *deletechars);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytearray_translate(PyByteArrayObject *self, PyObject *args)
|
bytearray_translate(PyByteArrayObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
|
static const char * const _keywords[] = {"", "delete", NULL};
|
||||||
|
static _PyArg_Parser _parser = {"O|O:translate", _keywords, 0};
|
||||||
PyObject *table;
|
PyObject *table;
|
||||||
int group_right_1 = 0;
|
|
||||||
PyObject *deletechars = NULL;
|
PyObject *deletechars = NULL;
|
||||||
|
|
||||||
switch (PyTuple_GET_SIZE(args)) {
|
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
|
||||||
case 1:
|
&table, &deletechars)) {
|
||||||
if (!PyArg_ParseTuple(args, "O:translate", &table)) {
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
return_value = bytearray_translate_impl(self, table, deletechars);
|
||||||
case 2:
|
|
||||||
if (!PyArg_ParseTuple(args, "OO:translate", &table, &deletechars)) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
group_right_1 = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PyErr_SetString(PyExc_TypeError, "bytearray.translate requires 1 to 2 arguments");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
return_value = bytearray_translate_impl(self, table, group_right_1, deletechars);
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -720,4 +711,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
|
||||||
{
|
{
|
||||||
return bytearray_sizeof_impl(self);
|
return bytearray_sizeof_impl(self);
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=0af30f8c0b1ecd76 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=59a0c86b29ff06d1 input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -269,47 +269,38 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(bytes_translate__doc__,
|
PyDoc_STRVAR(bytes_translate__doc__,
|
||||||
"translate(table, [deletechars])\n"
|
"translate($self, table, /, delete=b\'\')\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
"Return a copy with each character mapped by the given translation table.\n"
|
"Return a copy with each character mapped by the given translation table.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" table\n"
|
" table\n"
|
||||||
" Translation table, which must be a bytes object of length 256.\n"
|
" Translation table, which must be a bytes object of length 256.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"All characters occurring in the optional argument deletechars are removed.\n"
|
"All characters occurring in the optional argument delete are removed.\n"
|
||||||
"The remaining characters are mapped through the given translation table.");
|
"The remaining characters are mapped through the given translation table.");
|
||||||
|
|
||||||
#define BYTES_TRANSLATE_METHODDEF \
|
#define BYTES_TRANSLATE_METHODDEF \
|
||||||
{"translate", (PyCFunction)bytes_translate, METH_VARARGS, bytes_translate__doc__},
|
{"translate", (PyCFunction)bytes_translate, METH_VARARGS|METH_KEYWORDS, bytes_translate__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytes_translate_impl(PyBytesObject *self, PyObject *table, int group_right_1,
|
bytes_translate_impl(PyBytesObject *self, PyObject *table,
|
||||||
PyObject *deletechars);
|
PyObject *deletechars);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
bytes_translate(PyBytesObject *self, PyObject *args)
|
bytes_translate(PyBytesObject *self, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
|
static const char * const _keywords[] = {"", "delete", NULL};
|
||||||
|
static _PyArg_Parser _parser = {"O|O:translate", _keywords, 0};
|
||||||
PyObject *table;
|
PyObject *table;
|
||||||
int group_right_1 = 0;
|
|
||||||
PyObject *deletechars = NULL;
|
PyObject *deletechars = NULL;
|
||||||
|
|
||||||
switch (PyTuple_GET_SIZE(args)) {
|
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser,
|
||||||
case 1:
|
&table, &deletechars)) {
|
||||||
if (!PyArg_ParseTuple(args, "O:translate", &table)) {
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
return_value = bytes_translate_impl(self, table, deletechars);
|
||||||
case 2:
|
|
||||||
if (!PyArg_ParseTuple(args, "OO:translate", &table, &deletechars)) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
group_right_1 = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PyErr_SetString(PyExc_TypeError, "bytes.translate requires 1 to 2 arguments");
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
return_value = bytes_translate_impl(self, table, group_right_1, deletechars);
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -508,4 +499,4 @@ bytes_fromhex(PyTypeObject *type, PyObject *arg)
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=637c2c14610d3c8d input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=5618c05c24c1e617 input=a9049054013a1b77]*/
|
||||||
|
|
Loading…
Reference in New Issue