Merge branch 'types-arrays' into devel

This commit is contained in:
Daniele Varrazzo 2012-02-24 00:35:21 +00:00
commit b2c61eaa18
7 changed files with 78 additions and 12 deletions

1
NEWS
View File

@ -11,6 +11,7 @@ What's new in psycopg 2.4.5
to Menno Smits (tickets #94, #95).
- Fixed 'rownumber' during iteration on cursor subclasses.
Regression introduced in 2.4.4 (ticket #100).
- Added support for 'inet' arrays.
What's new in psycopg 2.4.4

View File

@ -325,6 +325,20 @@ details.
.. versionadded:: 2.4.3
.. _cast-array-unknown:
.. note::
The function can be used to create a generic array typecaster,
returning a list of strings: just use the `~psycopg2.STRING` as base
typecaster. For instance, if you want to receive from the database an
array of :sql:`macaddr`, each address represented by string, you can
use::
psycopg2.extensions.register_type(
psycopg2.extensions.new_array_type(
(1040,), 'MACADDR[]', psycopg2.STRING))
.. function:: register_type(obj [, scope])

View File

@ -250,6 +250,7 @@ UUID data type
^^^^^^^^^^^^^^^^^^^^^^
.. versionadded:: 2.0.9
.. versionchanged:: 2.4.5 added inet array support.
.. doctest::
@ -264,7 +265,7 @@ UUID data type
'192.168.0.1/24'
.. autofunction:: register_inet()
.. autofunction:: register_inet
.. autoclass:: Inet

View File

@ -109,6 +109,13 @@ Transferring binary data from PostgreSQL 9.0 doesn't work.
.. __: http://www.postgresql.org/docs/9.0/static/datatype-binary.html
.. __: http://www.postgresql.org/docs/9.0/static/runtime-config-client.html#GUC-BYTEA-OUTPUT
Arrays of *TYPE* are not casted to list.
Arrays are only casted to list when their oid is known, and an array
typecaster is registered for them. If there is no typecaster, the array is
returned unparsed from PostgreSQL (e.g. ``{a,b,c}``). It is easy to create
a generic arrays typecaster, returning a list of array: an example is
provided in the `~psycopg2.extensions.new_array_type()` documentation.
Best practices
--------------

View File

@ -294,7 +294,7 @@ the SQL string that would be sent to the database.
`bytea_output`__ configuration parameter to ``escape``, either in the
server configuration file or in the client session (using a query such as
``SET bytea_output TO escape;``) before receiving binary data.
.. __: http://www.postgresql.org/docs/9.0/static/datatype-binary.html
.. __: http://www.postgresql.org/docs/9.0/static/runtime-config-client.html#GUC-BYTEA-OUTPUT
@ -334,6 +334,14 @@ the SQL string that would be sent to the database.
>>> cur.mogrify("SELECT %s;", ([10, 20, 30], ))
'SELECT ARRAY[10, 20, 30];'
.. note::
Reading back from PostgreSQL, arrays are converted to list of Python
objects as expected, but only if the types are known one. Arrays of
unknown types are returned as represented by the database (e.g.
``{a,b,c}``). You can easily create a typecaster for :ref:`array of
unknown types <cast-array-unknown>`.
.. _adapt-tuple:
.. index::

View File

@ -455,14 +455,21 @@ class UUID_adapter(object):
__str__ = getquoted
def register_uuid(oids=None, conn_or_curs=None):
"""Create the UUID type and an uuid.UUID adapter."""
"""Create the UUID type and an uuid.UUID adapter.
:param oids: oid for the PostgreSQL :sql:`uuid` type, or 2-items sequence
with oids of the type and the array. If not specified, use PostgreSQL
standard oids.
:param conn_or_curs: where to register the typecaster. If not specified,
register it globally.
"""
import uuid
if not oids:
oid1 = 2950
oid2 = 2951
elif type(oids) == list:
elif isinstance(oids, (list, tuple)):
oid1, oid2 = oids
else:
oid1 = oids
@ -491,13 +498,13 @@ class Inet(object):
"""
def __init__(self, addr):
self.addr = addr
def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, self.addr)
def prepare(self, conn):
self._conn = conn
def getquoted(self):
obj = _A(self.addr)
if hasattr(obj, 'prepare'):
@ -510,13 +517,32 @@ class Inet(object):
def __str__(self):
return str(self.addr)
def register_inet(oid=None, conn_or_curs=None):
"""Create the INET type and an Inet adapter."""
if not oid: oid = 869
_ext.INET = _ext.new_type((oid, ), "INET",
"""Create the INET type and an Inet adapter.
:param oid: oid for the PostgreSQL :sql:`inet` type, or 2-items sequence
with oids of the type and the array. If not specified, use PostgreSQL
standard oids.
:param conn_or_curs: where to register the typecaster. If not specified,
register it globally.
"""
if not oid:
oid1 = 869
oid2 = 1041
elif isinstance(oid, (list, tuple)):
oid1, oid2 = oid
else:
oid1 = oid
oid2 = 1041
_ext.INET = _ext.new_type((oid1, ), "INET",
lambda data, cursor: data and Inet(data) or None)
_ext.INETARRAY = _ext.new_array_type((oid2, ), "INETARRAY", _ext.INET)
_ext.register_type(_ext.INET, conn_or_curs)
_ext.register_type(_ext.INETARRAY, conn_or_curs)
return _ext.INET

View File

@ -82,13 +82,22 @@ class TypesExtrasTests(unittest.TestCase):
def testINET(self):
psycopg2.extras.register_inet()
i = "192.168.1.0/24";
i = psycopg2.extras.Inet("192.168.1.0/24")
s = self.execute("SELECT %s AS foo", (i,))
self.failUnless(i == s)
self.failUnless(i.addr == s.addr)
# must survive NULL cast to inet
s = self.execute("SELECT NULL::inet AS foo")
self.failUnless(s is None)
def testINETARRAY(self):
psycopg2.extras.register_inet()
i = psycopg2.extras.Inet("192.168.1.0/24")
s = self.execute("SELECT %s AS foo", ([i],))
self.failUnless(i.addr == s[0].addr)
# must survive NULL cast to inet
s = self.execute("SELECT NULL::inet[] AS foo")
self.failUnless(s is None)
def test_inet_conform(self):
from psycopg2.extras import Inet
i = Inet("192.168.1.0/24")