Adapt bytearray and memoryview to bytes if available

This commit is contained in:
Daniele Varrazzo 2011-02-15 17:30:43 +00:00
parent c96ba553da
commit 3ae2f221b3
5 changed files with 55 additions and 13 deletions

3
NEWS
View File

@ -3,6 +3,9 @@ What's new in psycopg 2.4
* New features and changes: * New features and changes:
- Added support for Python 3.1 and 3.2.
- Adapt types 'bytearray' (from Python 2.6) and 'memoryview' (from Python
2.7) to bytea data type.
- Added `register_composite()` function to cast PostgreSQL composite types - Added `register_composite()` function to cast PostgreSQL composite types
into Python tuples/namedtuples. into Python tuples/namedtuples.
- More efficient iteration on named cursors. - More efficient iteration on named cursors.

View File

@ -244,12 +244,27 @@ the SQL string that would be sent to the database.
.. index:: .. index::
single: Buffer; Adaptation single: Buffer; Adaptation
single: bytea; Adaptation single: bytea; Adaptation
single: bytes; Adaptation
single: bytearray; Adaptation
single: memoryview; Adaptation
single: Binary string single: Binary string
- Binary types: Python types such as `!bytes`, `!bytearray`, `!buffer`, - Binary types: Python types representing binary objects are converted in
`!memoryview` are converted in PostgreSQL binary string syntax, suitable for PostgreSQL binary string syntax, suitable for :sql:`bytea` fields. Such
:sql:`bytea` fields. Received data is returned as `!buffer` (in Python 2) or types are `!buffer` (only available in Python 2), `!memoryview` (available
`!memoryview` (in Python 3). from Python 2.7), `!bytearray` (available from Python 2.6) and `!bytes`
(only form Python 3: the name is available from Python 2.6 but it's only an
alias for the type `!str`). Received data is returned as `!buffer` (in
Python 2) or `!memoryview` (in Python 3).
.. note::
In Python 2, if you have binary data in a `!str` object, you can pass them
to a :sql:`bytea` field using the `psycopg2.Binary` wrapper::
mypic = open('picture.png', 'rb').read()
curs.execute("insert into blobs (file) values (%s)",
(psycopg2.Binary(mypic),))
.. warning:: .. warning::

View File

@ -61,8 +61,11 @@ binary_quote(binaryObject *self)
if (Bytes_Check(self->wrapped) if (Bytes_Check(self->wrapped)
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
|| PyBuffer_Check(self->wrapped) || PyBuffer_Check(self->wrapped)
#else #endif
#if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 6
|| PyByteArray_Check(self->wrapped) || PyByteArray_Check(self->wrapped)
#endif
#if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 7
|| PyMemoryView_Check(self->wrapped) || PyMemoryView_Check(self->wrapped)
#endif #endif
) { ) {

View File

@ -315,17 +315,26 @@ psyco_adapters_init(PyObject *mod)
microprotocols_add(&PyLong_Type, NULL, (PyObject*)&asisType); microprotocols_add(&PyLong_Type, NULL, (PyObject*)&asisType);
microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType); microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType);
/* strings */
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType); microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType);
#endif #endif
microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType); microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType);
/* binary */
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType); microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType);
#else #else
microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType); microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType);
#endif
#if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 6
microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType); microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType);
#endif
#if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 7
microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType); microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType);
#endif #endif
microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType); microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType);
if ((type = (PyTypeObject*)psyco_GetDecimalType()) != NULL) if ((type = (PyTypeObject*)psyco_GetDecimalType()) != NULL)

View File

@ -207,27 +207,39 @@ class TypesBasicTests(unittest.TestCase):
o2 = self.execute("select %s;", (o1,)) o2 = self.execute("select %s;", (o1,))
self.assertEqual(memoryview, type(o2[0])) self.assertEqual(memoryview, type(o2[0]))
@testutils.skip_before_python(3) @testutils.skip_before_python(2, 6)
def testAdaptBytearray(self): def testAdaptBytearray(self):
o1 = bytearray(range(256)) o1 = bytearray(range(256))
o2 = self.execute("select %s;", (o1,)) o2 = self.execute("select %s;", (o1,))
self.assertEqual(memoryview, type(o2)) if sys.version_info[0] < 3:
self.assertEqual(buffer, type(o2))
else:
self.assertEqual(memoryview, type(o2))
# Test with an empty buffer # Test with an empty buffer
o1 = bytearray([]) o1 = bytearray([])
o2 = self.execute("select %s;", (o1,)) o2 = self.execute("select %s;", (o1,))
self.assertEqual(memoryview, type(o2)) if sys.version_info[0] < 3:
self.assertEqual(buffer, type(o2))
else:
self.assertEqual(memoryview, type(o2))
@testutils.skip_before_python(3) @testutils.skip_before_python(2, 7)
def testAdaptMemoryview(self): def testAdaptMemoryview(self):
o1 = memoryview(bytes(range(256))) o1 = memoryview(bytearray(range(256)))
o2 = self.execute("select %s;", (o1,)) o2 = self.execute("select %s;", (o1,))
self.assertEqual(memoryview, type(o2)) if sys.version_info[0] < 3:
self.assertEqual(buffer, type(o2))
else:
self.assertEqual(memoryview, type(o2))
# Test with an empty buffer # Test with an empty buffer
o1 = memoryview(bytes([])) o1 = memoryview(bytearray([]))
o2 = self.execute("select %s;", (o1,)) o2 = self.execute("select %s;", (o1,))
self.assertEqual(memoryview, type(o2)) if sys.version_info[0] < 3:
self.assertEqual(buffer, type(o2))
else:
self.assertEqual(memoryview, type(o2))
class AdaptSubclassTest(unittest.TestCase): class AdaptSubclassTest(unittest.TestCase):