mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Issue #27506: Support bytes/bytearray.translate() delete as keyword argument
Patch by Xiang Zhang.
This commit is contained in:
		
							parent
							
								
									8c3c52b19f
								
							
						
					
					
						commit
						1b6c6da85d
					
				
					 7 changed files with 76 additions and 80 deletions
				
			
		|  | @ -2631,8 +2631,8 @@ arbitrary binary data. | |||
|    The prefix(es) to search for may be any :term:`bytes-like object`. | ||||
| 
 | ||||
| 
 | ||||
| .. method:: bytes.translate(table[, delete]) | ||||
|             bytearray.translate(table[, delete]) | ||||
| .. method:: bytes.translate(table, delete=b'') | ||||
|             bytearray.translate(table, delete=b'') | ||||
| 
 | ||||
|    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 | ||||
|  | @ -2648,6 +2648,9 @@ arbitrary binary data. | |||
|       >>> b'read this short text'.translate(None, b'aeiou') | ||||
|       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 | ||||
| that assume the use of ASCII compatible binary formats, but can still be used | ||||
|  |  | |||
|  | @ -689,6 +689,37 @@ def test_free_after_iterating(self): | |||
|         test.support.check_free_after_iterating(self, iter, 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): | ||||
|     type2test = bytes | ||||
|  | @ -1449,24 +1480,6 @@ def test_literal(self): | |||
|             self.assertRaises(SyntaxError, eval, | ||||
|                               '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): | ||||
|         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 | ||||
| ----------------- | ||||
| 
 | ||||
| - Issue #27506: Support passing the bytes/bytearray.translate() "delete" | ||||
|   argument by keyword. | ||||
| 
 | ||||
| - Issue #27587: Fix another issue found by PVS-Studio: Null pointer check | ||||
|   after use of 'def' in _PyState_AddModule(). | ||||
|   Initial patch by Christian Heimes. | ||||
|  |  | |||
|  | @ -1175,21 +1175,19 @@ bytearray.translate | |||
| 
 | ||||
|     table: object | ||||
|         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. | ||||
| 
 | ||||
| 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. | ||||
| [clinic start generated code]*/ | ||||
| 
 | ||||
| static PyObject * | ||||
| bytearray_translate_impl(PyByteArrayObject *self, PyObject *table, | ||||
|                          int group_right_1, PyObject *deletechars) | ||||
| /*[clinic end generated code: output=2bebc86a9a1ff083 input=846a01671bccc1c5]*/ | ||||
|                          PyObject *deletechars) | ||||
| /*[clinic end generated code: output=b6a8f01c2a74e446 input=cfff956d4d127a9b]*/ | ||||
| { | ||||
|     char *input, *output; | ||||
|     const char *table_chars; | ||||
|  | @ -1258,8 +1256,7 @@ bytearray_translate_impl(PyByteArrayObject *self, PyObject *table, | |||
|     for (i = inlen; --i >= 0; ) { | ||||
|         c = Py_CHARMASK(*input++); | ||||
|         if (trans_table[c] != -1) | ||||
|             if (Py_CHARMASK(*output++ = (char)trans_table[c]) == c) | ||||
|                     continue; | ||||
|             *output++ = (char)trans_table[c]; | ||||
|     } | ||||
|     /* Fix the size of the resulting string */ | ||||
|     if (inlen > 0) | ||||
|  |  | |||
|  | @ -2045,21 +2045,19 @@ bytes.translate | |||
| 
 | ||||
|     table: object | ||||
|         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. | ||||
| 
 | ||||
| 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. | ||||
| [clinic start generated code]*/ | ||||
| 
 | ||||
| static PyObject * | ||||
| bytes_translate_impl(PyBytesObject *self, PyObject *table, int group_right_1, | ||||
| bytes_translate_impl(PyBytesObject *self, PyObject *table, | ||||
|                      PyObject *deletechars) | ||||
| /*[clinic end generated code: output=233df850eb50bf8d input=ca20edf39d780d49]*/ | ||||
| /*[clinic end generated code: output=43be3437f1956211 input=0ecdf159f654233c]*/ | ||||
| { | ||||
|     char *input, *output; | ||||
|     Py_buffer table_view = {NULL, NULL}; | ||||
|  |  | |||
|  | @ -39,47 +39,38 @@ bytearray_copy(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) | |||
| } | ||||
| 
 | ||||
| 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" | ||||
| "\n" | ||||
| "  table\n" | ||||
| "    Translation table, which must be a bytes object of length 256.\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."); | ||||
| 
 | ||||
| #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 * | ||||
| bytearray_translate_impl(PyByteArrayObject *self, PyObject *table, | ||||
|                          int group_right_1, PyObject *deletechars); | ||||
|                          PyObject *deletechars); | ||||
| 
 | ||||
| static PyObject * | ||||
| bytearray_translate(PyByteArrayObject *self, PyObject *args) | ||||
| bytearray_translate(PyByteArrayObject *self, PyObject *args, PyObject *kwargs) | ||||
| { | ||||
|     PyObject *return_value = NULL; | ||||
|     static const char * const _keywords[] = {"", "delete", NULL}; | ||||
|     static _PyArg_Parser _parser = {"O|O:translate", _keywords, 0}; | ||||
|     PyObject *table; | ||||
|     int group_right_1 = 0; | ||||
|     PyObject *deletechars = NULL; | ||||
| 
 | ||||
|     switch (PyTuple_GET_SIZE(args)) { | ||||
|         case 1: | ||||
|             if (!PyArg_ParseTuple(args, "O:translate", &table)) { | ||||
|                 goto exit; | ||||
|             } | ||||
|             break; | ||||
|         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; | ||||
|     if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, | ||||
|         &table, &deletechars)) { | ||||
|         goto exit; | ||||
|     } | ||||
|     return_value = bytearray_translate_impl(self, table, group_right_1, deletechars); | ||||
|     return_value = bytearray_translate_impl(self, table, deletechars); | ||||
| 
 | ||||
| exit: | ||||
|     return return_value; | ||||
|  | @ -720,4 +711,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) | |||
| { | ||||
|     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__, | ||||
| "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" | ||||
| "\n" | ||||
| "  table\n" | ||||
| "    Translation table, which must be a bytes object of length 256.\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."); | ||||
| 
 | ||||
| #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 * | ||||
| bytes_translate_impl(PyBytesObject *self, PyObject *table, int group_right_1, | ||||
| bytes_translate_impl(PyBytesObject *self, PyObject *table, | ||||
|                      PyObject *deletechars); | ||||
| 
 | ||||
| static PyObject * | ||||
| bytes_translate(PyBytesObject *self, PyObject *args) | ||||
| bytes_translate(PyBytesObject *self, PyObject *args, PyObject *kwargs) | ||||
| { | ||||
|     PyObject *return_value = NULL; | ||||
|     static const char * const _keywords[] = {"", "delete", NULL}; | ||||
|     static _PyArg_Parser _parser = {"O|O:translate", _keywords, 0}; | ||||
|     PyObject *table; | ||||
|     int group_right_1 = 0; | ||||
|     PyObject *deletechars = NULL; | ||||
| 
 | ||||
|     switch (PyTuple_GET_SIZE(args)) { | ||||
|         case 1: | ||||
|             if (!PyArg_ParseTuple(args, "O:translate", &table)) { | ||||
|                 goto exit; | ||||
|             } | ||||
|             break; | ||||
|         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; | ||||
|     if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, | ||||
|         &table, &deletechars)) { | ||||
|         goto exit; | ||||
|     } | ||||
|     return_value = bytes_translate_impl(self, table, group_right_1, deletechars); | ||||
|     return_value = bytes_translate_impl(self, table, deletechars); | ||||
| 
 | ||||
| exit: | ||||
|     return return_value; | ||||
|  | @ -508,4 +499,4 @@ bytes_fromhex(PyTypeObject *type, PyObject *arg) | |||
| exit: | ||||
|     return return_value; | ||||
| } | ||||
| /*[clinic end generated code: output=637c2c14610d3c8d input=a9049054013a1b77]*/ | ||||
| /*[clinic end generated code: output=5618c05c24c1e617 input=a9049054013a1b77]*/ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Martin Panter
						Martin Panter