From 46ab7389605df0a9062e08cb23e430aefc82f639 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 7 Mar 2017 18:32:14 +0800 Subject: [PATCH 1/3] bpo-28856 --- Lib/test/test_format.py | 8 ++++++-- Objects/bytesobject.c | 14 +++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 83eb29faf88d6cd..b6ba2e566b295f6 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -315,10 +315,12 @@ def __bytes__(self): 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 @@ def test_exc(formatstr, args, exception, excmsg): 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: diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index f0ddb95de57833a..89869790aee8bba 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -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,18 @@ 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)) { + 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; } From 9e165f9b49b942c91c049a667f8a3f0ce0a8cf50 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 14 Mar 2017 11:28:49 +0800 Subject: [PATCH 2/3] add comment and NEWS --- Misc/NEWS | 3 +++ Objects/bytesobject.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS b/Misc/NEWS index bcd049661edb1f2..daf71460e7493aa 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1? Core and Builtins ----------------- +- bpo-28856: Fix an oversight that %b format for bytes should support objects + follow the buffer protocol. + - bpo-29714: Fix a regression that bytes format may fail when containing zero bytes inside. diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 89869790aee8bba..7518e50740ba682 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -566,7 +566,9 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) *plen = PyBytes_GET_SIZE(result); return result; } - /* does it support buffer protocol? */ + /* does it support buffer protocol? + maybe we can avoid making a copy of the buffer object here? + */ if (PyObject_CheckBuffer(v)) { result = _PyBytes_FromBuffer(v); if (result == NULL) From ca66a64c19a96eae50830643e16b75b46a0e3e76 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 14 Mar 2017 11:42:57 +0800 Subject: [PATCH 3/3] put the comment into more right place --- Objects/bytesobject.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index a667fe3086d7f98..1050a93e6e46f19 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -566,10 +566,9 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) *plen = PyBytes_GET_SIZE(result); return result; } - /* does it support buffer protocol? - maybe we can avoid making a copy of the buffer object here? - */ + /* 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;