[Python-3000-checkins] r66038 - in python/branches/py3k: Doc/c-api/bytes.rst Doc/c-api/object.rst Include/bytesobject.h Include/object.h Lib/test/test_bytes.py Misc/NEWS Objects/bytesobject.c Objects/object.c

benjamin.peterson python-3000-checkins at python.org
Tue Aug 26 18:46:48 CEST 2008


Author: benjamin.peterson
Date: Tue Aug 26 18:46:47 2008
New Revision: 66038

Log:
make bytes(o) respect __bytes__ #2415

This adds two new C-API functions: PyObject_Bytes and PyBytes_FromObject.

Reviewer: Barry


Modified:
   python/branches/py3k/Doc/c-api/bytes.rst
   python/branches/py3k/Doc/c-api/object.rst
   python/branches/py3k/Include/bytesobject.h
   python/branches/py3k/Include/object.h
   python/branches/py3k/Lib/test/test_bytes.py
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Objects/bytesobject.c
   python/branches/py3k/Objects/object.c

Modified: python/branches/py3k/Doc/c-api/bytes.rst
==============================================================================
--- python/branches/py3k/Doc/c-api/bytes.rst	(original)
+++ python/branches/py3k/Doc/c-api/bytes.rst	Tue Aug 26 18:46:47 2008
@@ -118,6 +118,12 @@
    arguments.
 
 
+.. cfunction:: PyObject* PyBytes_FromObject(PyObject *o)
+
+   Return the bytes representation of object *o* that implements the buffer
+   protocol.
+
+
 .. cfunction:: Py_ssize_t PyBytes_Size(PyObject *o)
 
    Return the length of the bytes in bytes object *o*.

Modified: python/branches/py3k/Doc/c-api/object.rst
==============================================================================
--- python/branches/py3k/Doc/c-api/object.rst	(original)
+++ python/branches/py3k/Doc/c-api/object.rst	Tue Aug 26 18:46:47 2008
@@ -139,6 +139,14 @@
    Python expression ``str(o)``.  Called by the :func:`str` built-in function
    and, therefore, by the :func:`print` function.
 
+.. cfunction:: PyObject* PyObject_Bytes(PyObject *o)
+
+   .. index:: builtin: bytes
+
+   Compute a bytes representation of object *o*.  *NULL* is returned on failure
+   and a bytes object on success.  This is equivalent to the Python expression
+   ``bytes(o)``.
+
 
 .. cfunction:: int PyObject_IsInstance(PyObject *inst, PyObject *cls)
 

Modified: python/branches/py3k/Include/bytesobject.h
==============================================================================
--- python/branches/py3k/Include/bytesobject.h	(original)
+++ python/branches/py3k/Include/bytesobject.h	Tue Aug 26 18:46:47 2008
@@ -48,6 +48,7 @@
 
 PyAPI_FUNC(PyObject *) PyBytes_FromStringAndSize(const char *, Py_ssize_t);
 PyAPI_FUNC(PyObject *) PyBytes_FromString(const char *);
+PyAPI_FUNC(PyObject *) PyBytes_FromObject(PyObject *);
 PyAPI_FUNC(PyObject *) PyBytes_FromFormatV(const char*, va_list)
 				Py_GCC_ATTRIBUTE((format(printf, 1, 0)));
 PyAPI_FUNC(PyObject *) PyBytes_FromFormat(const char*, ...)

Modified: python/branches/py3k/Include/object.h
==============================================================================
--- python/branches/py3k/Include/object.h	(original)
+++ python/branches/py3k/Include/object.h	Tue Aug 26 18:46:47 2008
@@ -423,6 +423,7 @@
 PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_ASCII(PyObject *);
+PyAPI_FUNC(PyObject *) PyObject_Bytes(PyObject *);
 PyAPI_FUNC(int) PyObject_Compare(PyObject *, PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int);
 PyAPI_FUNC(int) PyObject_RichCompareBool(PyObject *, PyObject *, int);

Modified: python/branches/py3k/Lib/test/test_bytes.py
==============================================================================
--- python/branches/py3k/Lib/test/test_bytes.py	(original)
+++ python/branches/py3k/Lib/test/test_bytes.py	Tue Aug 26 18:46:47 2008
@@ -458,6 +458,18 @@
         with open(fd, "rb", buffering=0) as f:
             self.assertRaises(TypeError, f.readinto, b"")
 
+    def test_custom(self):
+        class A:
+            def __bytes__(self):
+                return b'abc'
+        self.assertEqual(bytes(A()), b'abc')
+        class A: pass
+        self.assertRaises(TypeError, bytes, A())
+        class A:
+            def __bytes__(self):
+                return None
+        self.assertRaises(TypeError, bytes, A())
+
 
 class ByteArrayTest(BaseBytesTest):
     type2test = bytearray

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Tue Aug 26 18:46:47 2008
@@ -27,6 +27,13 @@
 
 - Issue #3650: Fixed a reference leak in bytes.split('x').
 
+- bytes(o) now tries to use o.__bytes__() before using fallbacks.
+
+C API
+-----
+
+- PyObject_Bytes and PyBytes_FromObject were added.
+
 Library
 -------
 

Modified: python/branches/py3k/Objects/bytesobject.c
==============================================================================
--- python/branches/py3k/Objects/bytesobject.c	(original)
+++ python/branches/py3k/Objects/bytesobject.c	Tue Aug 26 18:46:47 2008
@@ -2882,11 +2882,10 @@
 static PyObject *
 string_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
-	PyObject *x = NULL, *it;
+	PyObject *x = NULL;
 	const char *encoding = NULL;
 	const char *errors = NULL;
 	PyObject *new = NULL;
-	Py_ssize_t i, size;
 	static char *kwlist[] = {"source", "encoding", "errors", 0};
 
 	if (type != &PyBytes_Type)
@@ -2924,6 +2923,14 @@
 			"encoding or errors without a string argument");
 		return NULL;
 	}
+        return PyObject_Bytes(x);
+}
+
+PyObject *
+PyBytes_FromObject(PyObject *x)
+{
+	PyObject *new, *it;
+	Py_ssize_t i, size;
 
 	/* Is it an int? */
 	size = PyNumber_AsSsize_t(x, PyExc_ValueError);

Modified: python/branches/py3k/Objects/object.c
==============================================================================
--- python/branches/py3k/Objects/object.c	(original)
+++ python/branches/py3k/Objects/object.c	Tue Aug 26 18:46:47 2008
@@ -453,6 +453,45 @@
 	return res;
 }
 
+PyObject *
+PyObject_Bytes(PyObject *v)
+{
+	PyObject *bytesmeth, *result, *func;
+	static PyObject *bytesstring = NULL;
+
+	if (bytesstring == NULL) {
+		bytesstring = PyUnicode_InternFromString("__bytes__");
+		if (bytesstring == NULL)
+			return NULL;
+	}
+
+	if (v == NULL)
+		return PyBytes_FromString("<NULL>");
+
+	if (PyBytes_CheckExact(v)) {
+		Py_INCREF(v);
+		return v;
+	}
+
+        /* Doesn't create a reference */
+	func = _PyType_Lookup(Py_TYPE(v), bytesstring);
+	if (func != NULL) {
+            result = PyObject_CallFunctionObjArgs(func, v, NULL);
+            if (result == NULL)
+		return NULL;
+            if (!PyBytes_Check(result)) {
+		PyErr_Format(PyExc_TypeError,
+			     "__bytes__ returned non-bytes (type %.200s)",
+			     Py_TYPE(result)->tp_name);
+		Py_DECREF(result);
+		return NULL;
+            }
+            return result;
+	}
+        PyErr_Clear();
+	return PyBytes_FromObject(v);
+}
+
 /* The new comparison philosophy is: we completely separate three-way
    comparison from rich comparison.  That is, PyObject_Compare() and
    PyObject_Cmp() *just* use the tp_compare slot.  And PyObject_RichCompare()


More information about the Python-3000-checkins mailing list