try to call __bytes__ before __index__ (closes #16722)

This commit is contained in:
Benjamin Peterson 2012-12-19 15:27:41 -06:00
parent 1f415cf2c2
commit 5ff3f73d94
3 changed files with 37 additions and 5 deletions

View File

@ -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):

View File

@ -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.

View File

@ -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)
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)
} }
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)
"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 *