Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit 7e2a54c

Browse files
authored
bpo-28856: Let %b format for bytes support objects that follow the buffer protocol (pythonGH-546)
1 parent 9e52c90 commit 7e2a54c

File tree

3 files changed

+23
-3
lines changed

3 files changed

+23
-3
lines changed

Lib/test/test_format.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,12 @@ def __bytes__(self):
332332
testcommon(b"%b", b"abc", b"abc")
333333
testcommon(b"%b", bytearray(b"def"), b"def")
334334
testcommon(b"%b", fb, b"123")
335+
testcommon(b"%b", memoryview(b"abc"), b"abc")
335336
# # %s is an alias for %b -- should only be used for Py2/3 code
336337
testcommon(b"%s", b"abc", b"abc")
337338
testcommon(b"%s", bytearray(b"def"), b"def")
338339
testcommon(b"%s", fb, b"123")
340+
testcommon(b"%s", memoryview(b"abc"), b"abc")
339341
# %a will give the equivalent of
340342
# repr(some_obj).encode('ascii', 'backslashreplace')
341343
testcommon(b"%a", 3.14, b"3.14")
@@ -372,9 +374,11 @@ def __bytes__(self):
372374
test_exc(b"%c", 3.14, TypeError,
373375
"%c requires an integer in range(256) or a single byte")
374376
test_exc(b"%b", "Xc", TypeError,
375-
"%b requires bytes, or an object that implements __bytes__, not 'str'")
377+
"%b requires a bytes-like object, "
378+
"or an object that implements __bytes__, not 'str'")
376379
test_exc(b"%s", "Wd", TypeError,
377-
"%b requires bytes, or an object that implements __bytes__, not 'str'")
380+
"%b requires a bytes-like object, "
381+
"or an object that implements __bytes__, not 'str'")
378382

379383
if maxsize == 2**31-1:
380384
# crashes 2.2.1 and earlier:

Misc/NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- bpo-28856: Fix an oversight that %b format for bytes should support objects
14+
follow the buffer protocol.
15+
1316
- bpo-29723: The ``sys.path[0]`` initialization change for bpo-29139 caused a
1417
regression by revealing an inconsistency in how sys.path is initialized when
1518
executing ``__main__`` from a zipfile, directory, or other import location.

Objects/bytesobject.c

+14-1
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,8 @@ byte_converter(PyObject *arg, char *p)
528528
return 0;
529529
}
530530

531+
static PyObject *_PyBytes_FromBuffer(PyObject *x);
532+
531533
static PyObject *
532534
format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
533535
{
@@ -564,8 +566,19 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
564566
*plen = PyBytes_GET_SIZE(result);
565567
return result;
566568
}
569+
/* does it support buffer protocol? */
570+
if (PyObject_CheckBuffer(v)) {
571+
/* maybe we can avoid making a copy of the buffer object here? */
572+
result = _PyBytes_FromBuffer(v);
573+
if (result == NULL)
574+
return NULL;
575+
*pbuf = PyBytes_AS_STRING(result);
576+
*plen = PyBytes_GET_SIZE(result);
577+
return result;
578+
}
567579
PyErr_Format(PyExc_TypeError,
568-
"%%b requires bytes, or an object that implements __bytes__, not '%.100s'",
580+
"%%b requires a bytes-like object, "
581+
"or an object that implements __bytes__, not '%.100s'",
569582
Py_TYPE(v)->tp_name);
570583
return NULL;
571584
}

0 commit comments

Comments
 (0)