Commit 5ff3f73d authored by Benjamin Peterson's avatar Benjamin Peterson

try to call __bytes__ before __index__ (closes #16722)

parent 1f415cf2
...@@ -701,6 +701,12 @@ class BytesTest(BaseBytesTest): ...@@ -701,6 +701,12 @@ class BytesTest(BaseBytesTest):
def __bytes__(self): def __bytes__(self):
return None return None
self.assertRaises(TypeError, bytes, A()) self.assertRaises(TypeError, bytes, A())
class A:
def __bytes__(self):
return b'a'
def __index__(self):
return 42
self.assertEqual(bytes(A()), b'a')
# Test PyBytes_FromFormat() # Test PyBytes_FromFormat()
def test_from_format(self): def test_from_format(self):
......
...@@ -12,6 +12,9 @@ What's New in Python 3.3.1? ...@@ -12,6 +12,9 @@ What's New in Python 3.3.1?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #16722: In the bytes() constructor, try to call __bytes__ on the
argument before __index__.
- Issue #16602: When a weakref's target was part of a long deallocation - Issue #16602: When a weakref's target was part of a long deallocation
chain, the object could remain reachable through its weakref even though chain, the object could remain reachable through its weakref even though
its refcount had dropped to zero. its refcount had dropped to zero.
......
...@@ -2505,8 +2505,10 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -2505,8 +2505,10 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
const char *encoding = NULL; const char *encoding = NULL;
const char *errors = NULL; const char *errors = NULL;
PyObject *new = NULL; PyObject *new = NULL;
PyObject *func;
Py_ssize_t size; Py_ssize_t size;
static char *kwlist[] = {"source", "encoding", "errors", 0}; static char *kwlist[] = {"source", "encoding", "errors", 0};
_Py_IDENTIFIER(__bytes__);
if (type != &PyBytes_Type) if (type != &PyBytes_Type)
return str_subtype_new(type, args, kwds); return str_subtype_new(type, args, kwds);
...@@ -2536,6 +2538,28 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -2536,6 +2538,28 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
assert(PyBytes_Check(new)); assert(PyBytes_Check(new));
return new; return new;
} }
/* We'd like to call PyObject_Bytes here, but we need to check for an
integer argument before deferring to PyBytes_FromObject, something
PyObject_Bytes doesn't do. */
func = _PyObject_LookupSpecial(x, &PyId___bytes__);
if (func != NULL) {
new = PyObject_CallFunctionObjArgs(func, NULL);
Py_DECREF(func);
if (new == NULL)
return NULL;
if (!PyBytes_Check(new)) {
PyErr_Format(PyExc_TypeError,
"__bytes__ returned non-bytes (type %.200s)",
Py_TYPE(new)->tp_name);
Py_DECREF(new);
return NULL;
}
return new;
}
else if (PyErr_Occurred())
return NULL;
/* Is it an integer? */ /* Is it an integer? */
size = PyNumber_AsSsize_t(x, PyExc_OverflowError); size = PyNumber_AsSsize_t(x, PyExc_OverflowError);
if (size == -1 && PyErr_Occurred()) { if (size == -1 && PyErr_Occurred()) {
...@@ -2549,12 +2573,10 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -2549,12 +2573,10 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
} }
else { else {
new = PyBytes_FromStringAndSize(NULL, size); new = PyBytes_FromStringAndSize(NULL, size);
if (new == NULL) { if (new == NULL)
return NULL; return NULL;
} if (size > 0)
if (size > 0) {
memset(((PyBytesObject*)new)->ob_sval, 0, size); memset(((PyBytesObject*)new)->ob_sval, 0, size);
}
return new; return new;
} }
...@@ -2564,7 +2586,8 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -2564,7 +2586,8 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
"encoding or errors without a string argument"); "encoding or errors without a string argument");
return NULL; return NULL;
} }
return PyObject_Bytes(x);
return PyBytes_FromObject(x);
} }
PyObject * PyObject *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment