Index: Objects/bytesobject.c =================================================================== --- Objects/bytesobject.c 2010-09-08 15:50:30.000000000 +0300 +++ Objects/bytesobject.c 2010-09-26 00:50:46.937500000 +0200 @@ -2402,6 +2402,48 @@ return NULL; } +PyDoc_STRVAR(hex_doc, +"B.hex() -> string\n\ +\n\ +Create a string of hexadecimal numbers from a bytes object.\n\ +Example: b'\\xb9\\x01\\xef'.hex() -> 'b901ef'."); + +static PyObject * +bytes_hex(PyObject *self) +{ + char* argbuf; + Py_ssize_t arglen; + PyObject *retval; + wchar_t* retbuf; + Py_ssize_t i, j; + + argbuf = STRINGLIB_STR(self); + arglen = STRINGLIB_LEN(self); + + assert(arglen >= 0); + if (arglen > PY_SSIZE_T_MAX / 2) { + return PyErr_NoMemory(); + } + + retval = PyUnicode_FromStringAndSize(NULL, arglen*2); + if (!retval) { + return NULL; + } + retbuf = PyUnicode_AS_UNICODE(retval); + + /* make hex version of string, taken from shamodule.c */ + for (i=j=0; i < arglen; i++) { + char c; + c = (argbuf[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + retbuf[j++] = c; + c = argbuf[i] & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + retbuf[j++] = c; + } + return retval; +} + PyDoc_STRVAR(sizeof__doc__, "B.__sizeof__() -> size of B in memory, in bytes"); @@ -2436,6 +2478,7 @@ {"find", (PyCFunction)bytes_find, METH_VARARGS, find__doc__}, {"fromhex", (PyCFunction)bytes_fromhex, METH_VARARGS|METH_CLASS, fromhex_doc}, + {"hex", (PyCFunction)bytes_hex, METH_NOARGS, hex_doc}, {"index", (PyCFunction)bytes_index, METH_VARARGS, index__doc__}, {"isalnum", (PyCFunction)stringlib_isalnum, METH_NOARGS, _Py_isalnum__doc__}, Index: Objects/bytearrayobject.c =================================================================== --- bytearrayobject.c 2010-08-15 20:12:56.000000000 +0300 +++ bytearrayobject.c 2010-09-26 00:53:03.515625000 +0200 @@ -2663,6 +2663,48 @@ return NULL; } +PyDoc_STRVAR(hex_doc, +"B.hex() -> string\n\ +\n\ +Create a string of hexadecimal numbers from a bytearray object.\n\ +Example: bytearray([0xb9, 0x01, 0xef]).hex() -> 'b901ef'."); + +static PyObject * +bytearray_hex(PyObject *self) +{ + char* argbuf; + Py_ssize_t arglen; + PyObject *retval; + wchar_t* retbuf; + Py_ssize_t i, j; + + argbuf = STRINGLIB_STR(self); + arglen = STRINGLIB_LEN(self); + + assert(arglen >= 0); + if (arglen > PY_SSIZE_T_MAX / 2) { + return PyErr_NoMemory(); + } + + retval = PyUnicode_FromStringAndSize(NULL, arglen*2); + if (!retval) { + return NULL; + } + retbuf = PyUnicode_AS_UNICODE(retval); + + /* make hex version of string, taken from shamodule.c */ + for (i=j=0; i < arglen; i++) { + char c; + c = (argbuf[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + retbuf[j++] = c; + c = argbuf[i] & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + retbuf[j++] = c; + } + return retval; +} + PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); static PyObject * @@ -2740,6 +2782,7 @@ {"find", (PyCFunction)bytearray_find, METH_VARARGS, find__doc__}, {"fromhex", (PyCFunction)bytearray_fromhex, METH_VARARGS|METH_CLASS, fromhex_doc}, + {"hex", (PyCFunction)bytearray_hex, METH_NOARGS, hex_doc}, {"index", (PyCFunction)bytearray_index, METH_VARARGS, index__doc__}, {"insert", (PyCFunction)bytearray_insert, METH_VARARGS, insert__doc__}, {"isalnum", (PyCFunction)stringlib_isalnum, METH_NOARGS, Index: Doc/Library/stdtypes.rst =================================================================== --- stdtypes.rst 2010-09-26 00:43:48.218750000 +0200 +++ stdtypes.rst 2010-09-26 00:58:32.921875000 +0200 @@ -1769,6 +1769,18 @@ b'\xf0\xf1\xf2' +A reverse conversion function exists to transform a bytes object into its +hexadecimal representation. + +.. method:: bytes.hex() + bytearray.hex() + + Return a string object containing two hexadecimal digits for each byte in the instance. + + >>> b'\xf0\xf1\xf2'.hex() + 'f0f1f2' + + The maketrans and translate methods differ in semantics from the versions available on strings: Index: Lib/Test/test_bytes.py =================================================================== --- test_bytes.py 2010-09-03 23:00:38.000000000 +0300 +++ test_bytes.py 2010-09-26 01:14:49.015625000 +0200 @@ -278,6 +278,13 @@ self.assertRaises(ValueError, self.type2test.fromhex, '\x00') self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34') + def test_hex(self): + self.assertRaises(TypeError, self.type2test.hex) + self.assertRaises(TypeError, self.type2test.hex, 1) + self.assertEquals(self.type2test(b"").hex(), "") + self.assertEquals(bytearray([0x1a, 0x2b, 0x30]).hex(), '1a2b30') + self.assertEquals(self.type2test(b"\x1a\x2b\x30").hex(), '1a2b30') + def test_join(self): self.assertEqual(self.type2test(b"").join([]), b"") self.assertEqual(self.type2test(b"").join([b""]), b"")