diff -r 829117ae2e55 Doc/library/functions.rst --- a/Doc/library/functions.rst Tue Jul 19 16:46:09 2016 -0500 +++ b/Doc/library/functions.rst Fri Jul 22 14:53:36 2016 +0800 @@ -680,9 +680,9 @@ :meth:`x.__int__() `. For floating point numbers, this truncates towards zero. - If *x* is not a number or if *base* is given, then *x* must be a string, - :class:`bytes`, or :class:`bytearray` instance representing an :ref:`integer - literal ` in radix *base*. Optionally, the literal can be + If *x* is not a number or if *base* is given, then *x* must be a string or + :term:`bytes-like object` representing an :ref:`integer literal ` + in radix *base*. Optionally, the literal can be preceded by ``+`` or ``-`` (with no space in between) and surrounded by whitespace. A base-n literal consists of the digits 0 to n-1, with ``a`` to ``z`` (or ``A`` to ``Z``) having @@ -702,6 +702,10 @@ :meth:`base.__int__ ` instead of :meth:`base.__index__ `. + .. versionchanged:: 3.6 + Besides :class:`bytes` and :class:`bytearray`, :term:`bytes-like objects + ` are also supported when *base* is given. + .. function:: isinstance(object, classinfo) Return true if the *object* argument is an instance of the *classinfo* diff -r 829117ae2e55 Lib/test/test_int.py --- a/Lib/test/test_int.py Tue Jul 19 16:46:09 2016 -0500 +++ b/Lib/test/test_int.py Fri Jul 22 14:53:36 2016 +0800 @@ -272,7 +272,7 @@ self.assertEqual(int('101', base=MyIndexable(10)), 101) self.assertEqual(int('101', base=MyIndexable(36)), 1 + 36**2) - def test_non_numeric_input_types(self): + def test_string_and_bytes_like_objects(self): # Test possible non-numeric types for the argument x, including # subclasses of the explicitly documented accepted types. class CustomStr(str): pass @@ -298,12 +298,7 @@ x = f(b'100') with self.subTest(type(x)): self.assertEqual(int(x), 100) - if isinstance(x, (str, bytes, bytearray)): - self.assertEqual(int(x, 2), 4) - else: - msg = "can't convert non-string" - with self.assertRaisesRegex(TypeError, msg): - int(x, 2) + self.assertEqual(int(x, 2), 4) with self.assertRaisesRegex(ValueError, 'invalid literal'): int(f(b'A' * 0x10)) diff -r 829117ae2e55 Lib/test/test_long.py --- a/Lib/test/test_long.py Tue Jul 19 16:46:09 2016 -0500 +++ b/Lib/test/test_long.py Fri Jul 22 14:53:36 2016 +0800 @@ -339,6 +339,44 @@ except ValueError: pass + # Check conversions from bytes and bytearray + BS = [ + (b'', b'1' + b'0'*20, 10**20), + (b'', b'1' + b'0'*100, 10**100), + (bytearray(), bytearray(b'1' + b'0'*20), 10**20), + (bytearray(), bytearray(b'1' + b'0'*100), 10**100), + ] + for t, s, v in BS: + for sign in b"", b"+", b"-": + for prefix in b" ", b"\t", b" \t\t ": + ss = t + prefix + sign + s + vv = v + if sign == b'-': + vv = -v + self.assertEqual(int(ss, base=10), vv) + + # Check conversions from bytes-like objects + BL = [ + (memoryview(b'1' + b'0'*20), 10**20), + (memoryview(b'1' + b'0'*100), 10**100), + (memoryview(b' 1' + b'0'*20), 10**20), + (memoryview(b' 1' + b'0'*100), 10**100), + (memoryview(b'\t1' + b'0'*20), 10**20), + (memoryview(b'\t1' + b'0'*100), 10**100), + (memoryview(b' \t\t 1' + b'0'*20), 10**20), + (memoryview(b' \t\t 1' + b'0'*100), 10**100), + (memoryview(b'-1' + b'0'*20), -10**20), + (memoryview(b'-1' + b'0'*100), -10**100), + (memoryview(b' -1' + b'0'*20), -10**20), + (memoryview(b' -1' + b'0'*100), -10**100), + (memoryview(b'\t-1' + b'0'*20), -10**20), + (memoryview(b'\t-1' + b'0'*100), -10**100), + (memoryview(b' \t\t -1' + b'0'*20), -10**20), + (memoryview(b' \t\t -1' + b'0'*100), -10**100), + ] + for s, v in BL: + self.assertEqual(int(s, base=10), v) + # trailing L should no longer be accepted... self.assertRaises(ValueError, int, '123L') self.assertRaises(ValueError, int, '123l') diff -r 829117ae2e55 Objects/longobject.c --- a/Objects/longobject.c Tue Jul 19 16:46:09 2016 -0500 +++ b/Objects/longobject.c Fri Jul 22 14:53:36 2016 +0800 @@ -4709,6 +4709,7 @@ long_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *obase = NULL, *x = NULL; + Py_buffer view; Py_ssize_t base; static char *kwlist[] = {"x", "base", 0}; @@ -4739,13 +4740,24 @@ if (PyUnicode_Check(x)) return PyLong_FromUnicodeObject(x, (int)base); - else if (PyByteArray_Check(x) || PyBytes_Check(x)) { - char *string; - if (PyByteArray_Check(x)) - string = PyByteArray_AS_STRING(x); - else - string = PyBytes_AS_STRING(x); - return _PyLong_FromBytes(string, Py_SIZE(x), (int)base); + else if (PyBytes_Check(x)) + return _PyLong_FromBytes(PyBytes_AS_STRING(x), + PyBytes_GET_SIZE(x), (int)base); + else if (PyByteArray_Check(x)) + return _PyLong_FromBytes(PyByteArray_AS_STRING(x), + PyByteArray_GET_SIZE(x), (int)base); + else if (PyObject_GetBuffer(x, &view, PyBUF_SIMPLE) == 0) { + PyObject *bytes, *result; + bytes = PyBytes_FromStringAndSize((const char *)view.buf, view.len); + if (bytes == NULL) { + PyBuffer_Release(&view); + return NULL; + } + result = _PyLong_FromBytes(PyBytes_AS_STRING(bytes), + PyBytes_GET_SIZE(bytes), (int)base); + Py_DECREF(bytes); + PyBuffer_Release(&view); + return result; } else { PyErr_SetString(PyExc_TypeError,