summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiang Zhang <angwerzx@126.com>2017-03-14 07:07:15 (GMT)
committerGitHub <noreply@github.com>2017-03-14 07:07:15 (GMT)
commit7e2a54cdd977078b40b82182e46b201f8163f659 (patch)
tree2a5116ab3cd37f53f7bf5b1ba9b569fb7e887e54
parent9e52c907b5511393ab7e44321e9521fe0967e34d (diff)
downloadcpython-7e2a54cdd977078b40b82182e46b201f8163f659.zip
cpython-7e2a54cdd977078b40b82182e46b201f8163f659.tar.gz
cpython-7e2a54cdd977078b40b82182e46b201f8163f659.tar.bz2
bpo-28856: Let %b format for bytes support objects that follow the buffer protocol (GH-546)
-rw-r--r--Lib/test/test_format.py8
-rw-r--r--Misc/NEWS3
-rw-r--r--Objects/bytesobject.c15
3 files changed, 23 insertions, 3 deletions
diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
index b283501..83804cb 100644
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -332,10 +332,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")
@@ -372,9 +374,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:
diff --git a/Misc/NEWS b/Misc/NEWS
index 72404b3..b2a1a6e 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-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.
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index c4ef495..1050a93 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,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;
}