bpo-28856: Let %b format for bytes support objects that follow the buffer protocol (GH-664)

This commit is contained in:
Xiang Zhang 2017-03-14 15:27:01 +08:00 committed by GitHub
parent 388e2568fc
commit faa2cc63e4
3 changed files with 23 additions and 3 deletions

View File

@ -315,10 +315,12 @@ class FormatTest(unittest.TestCase):
testcommon(b"%b", b"abc", b"abc")
testcommon(b"%b", bytearray(b"def"), b"def")
testcommon(b"%b", fb, b"123")
testcommon(b"%b", memoryview(b"abc"), b"abc")
# # %s is an alias for %b -- should only be used for Py2/3 code
testcommon(b"%s", b"abc", b"abc")
testcommon(b"%s", bytearray(b"def"), b"def")
testcommon(b"%s", fb, b"123")
testcommon(b"%s", memoryview(b"abc"), b"abc")
# %a will give the equivalent of
# repr(some_obj).encode('ascii', 'backslashreplace')
testcommon(b"%a", 3.14, b"3.14")
@ -377,9 +379,11 @@ class FormatTest(unittest.TestCase):
test_exc(b"%c", 3.14, TypeError,
"%c requires an integer in range(256) or a single byte")
test_exc(b"%b", "Xc", TypeError,
"%b requires bytes, or an object that implements __bytes__, not 'str'")
"%b requires a bytes-like object, "
"or an object that implements __bytes__, not 'str'")
test_exc(b"%s", "Wd", TypeError,
"%b requires bytes, or an object that implements __bytes__, not 'str'")
"%b requires a bytes-like object, "
"or an object that implements __bytes__, not 'str'")
if maxsize == 2**31-1:
# crashes 2.2.1 and earlier:

View File

@ -12,6 +12,9 @@ Core and Builtins
- bpo-29600: Fix wrapping coroutine return values in StopIteration.
- bpo-28856: Fix an oversight that %b format for bytes should support objects
follow the buffer protocol.
- bpo-29723: The ``sys.path[0]`` initialization change for bpo-29139 caused a
regression by revealing an inconsistency in how sys.path is initialized when
executing ``__main__`` from a zipfile, directory, or other import location.

View File

@ -528,6 +528,8 @@ byte_converter(PyObject *arg, char *p)
return 0;
}
static PyObject *_PyBytes_FromBuffer(PyObject *x);
static PyObject *
format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
{
@ -564,8 +566,19 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
*plen = PyBytes_GET_SIZE(result);
return result;
}
/* does it support buffer protocol? */
if (PyObject_CheckBuffer(v)) {
/* maybe we can avoid making a copy of the buffer object here? */
result = _PyBytes_FromBuffer(v);
if (result == NULL)
return NULL;
*pbuf = PyBytes_AS_STRING(result);
*plen = PyBytes_GET_SIZE(result);
return result;
}
PyErr_Format(PyExc_TypeError,
"%%b requires bytes, or an object that implements __bytes__, not '%.100s'",
"%%b requires a bytes-like object, "
"or an object that implements __bytes__, not '%.100s'",
Py_TYPE(v)->tp_name);
return NULL;
}