mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-03-03 15:45:46 +03:00
Merge branch 'types-arrays' into devel
This commit is contained in:
commit
b2c61eaa18
1
NEWS
1
NEWS
|
@ -11,6 +11,7 @@ What's new in psycopg 2.4.5
|
||||||
to Menno Smits (tickets #94, #95).
|
to Menno Smits (tickets #94, #95).
|
||||||
- Fixed 'rownumber' during iteration on cursor subclasses.
|
- Fixed 'rownumber' during iteration on cursor subclasses.
|
||||||
Regression introduced in 2.4.4 (ticket #100).
|
Regression introduced in 2.4.4 (ticket #100).
|
||||||
|
- Added support for 'inet' arrays.
|
||||||
|
|
||||||
|
|
||||||
What's new in psycopg 2.4.4
|
What's new in psycopg 2.4.4
|
||||||
|
|
|
@ -325,6 +325,20 @@ details.
|
||||||
|
|
||||||
.. versionadded:: 2.4.3
|
.. 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])
|
.. function:: register_type(obj [, scope])
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,7 @@ UUID data type
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
.. versionadded:: 2.0.9
|
.. versionadded:: 2.0.9
|
||||||
|
.. versionchanged:: 2.4.5 added inet array support.
|
||||||
|
|
||||||
.. doctest::
|
.. doctest::
|
||||||
|
|
||||||
|
@ -264,7 +265,7 @@ UUID data type
|
||||||
'192.168.0.1/24'
|
'192.168.0.1/24'
|
||||||
|
|
||||||
|
|
||||||
.. autofunction:: register_inet()
|
.. autofunction:: register_inet
|
||||||
|
|
||||||
.. autoclass:: Inet
|
.. autoclass:: Inet
|
||||||
|
|
||||||
|
|
|
@ -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/datatype-binary.html
|
||||||
.. __: http://www.postgresql.org/docs/9.0/static/runtime-config-client.html#GUC-BYTEA-OUTPUT
|
.. __: 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
|
Best practices
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -294,7 +294,7 @@ the SQL string that would be sent to the database.
|
||||||
`bytea_output`__ configuration parameter to ``escape``, either in the
|
`bytea_output`__ configuration parameter to ``escape``, either in the
|
||||||
server configuration file or in the client session (using a query such as
|
server configuration file or in the client session (using a query such as
|
||||||
``SET bytea_output TO escape;``) before receiving binary data.
|
``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/datatype-binary.html
|
||||||
.. __: http://www.postgresql.org/docs/9.0/static/runtime-config-client.html#GUC-BYTEA-OUTPUT
|
.. __: 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], ))
|
>>> cur.mogrify("SELECT %s;", ([10, 20, 30], ))
|
||||||
'SELECT ARRAY[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:
|
.. _adapt-tuple:
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
|
|
|
@ -455,14 +455,21 @@ class UUID_adapter(object):
|
||||||
__str__ = getquoted
|
__str__ = getquoted
|
||||||
|
|
||||||
def register_uuid(oids=None, conn_or_curs=None):
|
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
|
import uuid
|
||||||
|
|
||||||
if not oids:
|
if not oids:
|
||||||
oid1 = 2950
|
oid1 = 2950
|
||||||
oid2 = 2951
|
oid2 = 2951
|
||||||
elif type(oids) == list:
|
elif isinstance(oids, (list, tuple)):
|
||||||
oid1, oid2 = oids
|
oid1, oid2 = oids
|
||||||
else:
|
else:
|
||||||
oid1 = oids
|
oid1 = oids
|
||||||
|
@ -491,13 +498,13 @@ class Inet(object):
|
||||||
"""
|
"""
|
||||||
def __init__(self, addr):
|
def __init__(self, addr):
|
||||||
self.addr = addr
|
self.addr = addr
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.addr)
|
return "%s(%r)" % (self.__class__.__name__, self.addr)
|
||||||
|
|
||||||
def prepare(self, conn):
|
def prepare(self, conn):
|
||||||
self._conn = conn
|
self._conn = conn
|
||||||
|
|
||||||
def getquoted(self):
|
def getquoted(self):
|
||||||
obj = _A(self.addr)
|
obj = _A(self.addr)
|
||||||
if hasattr(obj, 'prepare'):
|
if hasattr(obj, 'prepare'):
|
||||||
|
@ -510,13 +517,32 @@ class Inet(object):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.addr)
|
return str(self.addr)
|
||||||
|
|
||||||
def register_inet(oid=None, conn_or_curs=None):
|
def register_inet(oid=None, conn_or_curs=None):
|
||||||
"""Create the INET type and an Inet adapter."""
|
"""Create the INET type and an Inet adapter.
|
||||||
if not oid: oid = 869
|
|
||||||
_ext.INET = _ext.new_type((oid, ), "INET",
|
: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)
|
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.INET, conn_or_curs)
|
||||||
|
_ext.register_type(_ext.INETARRAY, conn_or_curs)
|
||||||
|
|
||||||
return _ext.INET
|
return _ext.INET
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -82,13 +82,22 @@ class TypesExtrasTests(unittest.TestCase):
|
||||||
|
|
||||||
def testINET(self):
|
def testINET(self):
|
||||||
psycopg2.extras.register_inet()
|
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,))
|
s = self.execute("SELECT %s AS foo", (i,))
|
||||||
self.failUnless(i == s)
|
self.failUnless(i.addr == s.addr)
|
||||||
# must survive NULL cast to inet
|
# must survive NULL cast to inet
|
||||||
s = self.execute("SELECT NULL::inet AS foo")
|
s = self.execute("SELECT NULL::inet AS foo")
|
||||||
self.failUnless(s is None)
|
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):
|
def test_inet_conform(self):
|
||||||
from psycopg2.extras import Inet
|
from psycopg2.extras import Inet
|
||||||
i = Inet("192.168.1.0/24")
|
i = Inet("192.168.1.0/24")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user