mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-12 07:10:33 +03:00
Merge branch 'devel'
This commit is contained in:
commit
3762c67cd4
2
NEWS
2
NEWS
|
@ -28,6 +28,8 @@ What's new in psycopg 2.4
|
||||||
available.
|
available.
|
||||||
- Added missing icon to ZPsycopgDA package, not available in Zope 2.12.9
|
- Added missing icon to ZPsycopgDA package, not available in Zope 2.12.9
|
||||||
(ticket #30). Bug report and patch by Pumukel.
|
(ticket #30). Bug report and patch by Pumukel.
|
||||||
|
- Fixed conversion of negative infinity (ticket #40). Bug report and patch
|
||||||
|
by Marti Raudsepp.
|
||||||
|
|
||||||
|
|
||||||
What's new in psycopg 2.3.2
|
What's new in psycopg 2.3.2
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
# their work without bothering about the module dependencies.
|
# their work without bothering about the module dependencies.
|
||||||
|
|
||||||
|
|
||||||
ALLOWED_PSYCOPG_VERSIONS = ('2.4-beta1',)
|
ALLOWED_PSYCOPG_VERSIONS = ('2.4-beta1', '2.4-beta2')
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
|
@ -89,14 +89,33 @@ by the `psycopg2.extensions.adapt()` function.
|
||||||
The `~cursor.execute()` method adapts its arguments to the
|
The `~cursor.execute()` method adapts its arguments to the
|
||||||
`~psycopg2.extensions.ISQLQuote` protocol. Objects that conform to this
|
`~psycopg2.extensions.ISQLQuote` protocol. Objects that conform to this
|
||||||
protocol expose a `!getquoted()` method returning the SQL representation
|
protocol expose a `!getquoted()` method returning the SQL representation
|
||||||
of the object as a string.
|
of the object as a string (the method must return `!bytes` in Python 3).
|
||||||
|
Optionally the conform object may expose a
|
||||||
|
`~psycopg2.extensions.ISQLQuote.prepare()` method.
|
||||||
|
|
||||||
The easiest way to adapt an object to an SQL string is to register an adapter
|
There are two basic ways to have a Python object adapted to SQL:
|
||||||
function via the `~psycopg2.extensions.register_adapter()` function. The
|
|
||||||
adapter function must take the value to be adapted as argument and return a
|
- the object itself is conform, or knows how to make itself conform. Such
|
||||||
conform object. A convenient object is the `~psycopg2.extensions.AsIs`
|
object must expose a `__conform__()` method that will be called with the
|
||||||
wrapper, whose `!getquoted()` result is simply the `!str()`\ ing
|
protocol object as argument. The object can check that the protocol is
|
||||||
conversion of the wrapped object.
|
`!ISQLQuote`, in which case it can return `!self` (if the object also
|
||||||
|
implements `!getquoted()`) or a suitable wrapper object. This option is
|
||||||
|
viable if you are the author of the object and if the object is specifically
|
||||||
|
designed for the database (i.e. having Psycopg as a dependency and polluting
|
||||||
|
its interface with the required methods doesn't bother you). For a simple
|
||||||
|
example you can take a look to the source code for the
|
||||||
|
`psycopg2.extras.Inet` object.
|
||||||
|
|
||||||
|
- If implementing the `!ISQLQuote` interface directly in the object is not an
|
||||||
|
option, you can use an adaptation function, taking the object to be adapted
|
||||||
|
as argument and returning a conforming object. The adapter must be
|
||||||
|
registered via the `~psycopg2.extensions.register_adapter()` function. A
|
||||||
|
simple example wrapper is the `!psycopg2.extras.UUID_adapter` used by the
|
||||||
|
`~psycopg2.extras.register_uuid()` function.
|
||||||
|
|
||||||
|
A convenient object to write adapters is the `~psycopg2.extensions.AsIs`
|
||||||
|
wrapper, whose `!getquoted()` result is simply the `!str()`\ ing conversion of
|
||||||
|
the wrapped object.
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
single: Example; Types adaptation
|
single: Example; Types adaptation
|
||||||
|
|
|
@ -189,8 +189,9 @@ deal with Python objects adaptation:
|
||||||
.. method:: getquoted()
|
.. method:: getquoted()
|
||||||
|
|
||||||
Subclasses or other conforming objects should return a valid SQL
|
Subclasses or other conforming objects should return a valid SQL
|
||||||
string representing the wrapped object. The `!ISQLQuote`
|
string representing the wrapped object. In Python 3 the SQL must be
|
||||||
implementation does nothing.
|
returned in a `!bytes` object. The `!ISQLQuote` implementation does
|
||||||
|
nothing.
|
||||||
|
|
||||||
.. method:: prepare(conn)
|
.. method:: prepare(conn)
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,18 @@ Psycopg converts :sql:`decimal`\/\ :sql:`numeric` database types into Python `!D
|
||||||
documentation. If you find `!psycopg2.extensions.DECIMAL` not avalable, use
|
documentation. If you find `!psycopg2.extensions.DECIMAL` not avalable, use
|
||||||
`!psycopg2._psycopg.DECIMAL` instead.
|
`!psycopg2._psycopg.DECIMAL` instead.
|
||||||
|
|
||||||
|
Transferring binary data from PostgreSQL 9.0 doesn't work.
|
||||||
|
PostgreSQL 9.0 uses by default `the "hex" format`__ to transfer
|
||||||
|
:sql:`bytea` data: the format can't be parsed by the libpq 8.4 and
|
||||||
|
earlier. Three options to solve the problem are:
|
||||||
|
|
||||||
|
- set the bytea_output__ parameter to ``escape`` in the server;
|
||||||
|
- use ``SET bytea_output TO escape`` in the client before reading binary
|
||||||
|
data;
|
||||||
|
- upgrade the libpq library on the client to at least 9.0.
|
||||||
|
|
||||||
|
.. __: 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
|
||||||
|
|
||||||
Best practices
|
Best practices
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -233,15 +233,37 @@ the SQL string that would be sent to the database.
|
||||||
.. index::
|
.. index::
|
||||||
pair: Strings; Adaptation
|
pair: Strings; Adaptation
|
||||||
single: Unicode; Adaptation
|
single: Unicode; Adaptation
|
||||||
|
|
||||||
|
- String types: `!str`, `!unicode` are converted in SQL string syntax.
|
||||||
|
`!unicode` objects (`!str` in Python 3) are encoded in the connection
|
||||||
|
`~connection.encoding` to be sent to the backend: trying to send a character
|
||||||
|
not supported by the encoding will result in an error. Received data can be
|
||||||
|
converted either as `!str` or `!unicode`: see :ref:`unicode-handling` for
|
||||||
|
received, either `!str` or `!unicode`
|
||||||
|
|
||||||
|
.. index::
|
||||||
single: Buffer; Adaptation
|
single: Buffer; Adaptation
|
||||||
single: bytea; Adaptation
|
single: bytea; Adaptation
|
||||||
single: Binary string
|
single: Binary string
|
||||||
|
|
||||||
- String types: `!str`, `!unicode` are converted in SQL string
|
- Binary types: Python types such as `!bytes`, `!bytearray`, `!buffer`,
|
||||||
syntax. `!buffer` is converted in PostgreSQL binary string syntax,
|
`!memoryview` are converted in PostgreSQL binary string syntax, suitable for
|
||||||
suitable for :sql:`bytea` fields. When reading textual fields, either
|
:sql:`bytea` fields. Received data is returned as `!buffer` (in Python 2) or
|
||||||
`!str` or `!unicode` can be received: see
|
`!memoryview` (in Python 3).
|
||||||
:ref:`unicode-handling`.
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
PostgreSQL 9 uses by default `a new "hex" format`__ to emit :sql:`bytea`
|
||||||
|
fields. Unfortunately this format can't be parsed by libpq versions
|
||||||
|
before 9.0. This means that using a library client with version lesser
|
||||||
|
than 9.0 to talk with a server 9.0 or later you may have problems
|
||||||
|
receiving :sql:`bytea` data. To work around this problem you can set the
|
||||||
|
`bytea_output`__ parameter to ``escape``, either in the server
|
||||||
|
configuration or in the client session using a query such as ``SET
|
||||||
|
bytea_output TO escape;`` before trying to receive 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
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
single: Adaptation; Date/Time objects
|
single: Adaptation; Date/Time objects
|
||||||
|
@ -338,8 +360,8 @@ defined on the database connection (the `PostgreSQL encoding`__, available in
|
||||||
.. __: http://www.postgresql.org/docs/9.0/static/multibyte.html
|
.. __: http://www.postgresql.org/docs/9.0/static/multibyte.html
|
||||||
.. __: http://docs.python.org/library/codecs.html#standard-encodings
|
.. __: http://docs.python.org/library/codecs.html#standard-encodings
|
||||||
|
|
||||||
When reading data from the database, the strings returned are usually 8 bit
|
When reading data from the database, in Python 2 the strings returned are
|
||||||
`!str` objects encoded in the database client encoding::
|
usually 8 bit `!str` objects encoded in the database client encoding::
|
||||||
|
|
||||||
>>> print conn.encoding
|
>>> print conn.encoding
|
||||||
UTF8
|
UTF8
|
||||||
|
@ -356,9 +378,10 @@ When reading data from the database, the strings returned are usually 8 bit
|
||||||
>>> print type(x), repr(x)
|
>>> print type(x), repr(x)
|
||||||
<type 'str'> '\xe0\xe8\xec\xf2\xf9\xa4'
|
<type 'str'> '\xe0\xe8\xec\xf2\xf9\xa4'
|
||||||
|
|
||||||
In order to obtain `!unicode` objects instead, it is possible to
|
In Python 3 instead the strings are automatically *decoded* in the connection
|
||||||
register a typecaster so that PostgreSQL textual types are automatically
|
`~connection.encoding`, as the `!str` object can represent Unicode characters.
|
||||||
*decoded* using the current client encoding::
|
In Python 2 you must register a :ref:`typecaster
|
||||||
|
<type-casting-from-sql-to-python>` in order to receive `!unicode` objects::
|
||||||
|
|
||||||
>>> psycopg2.extensions.register_type(psycopg2.extensions.UNICODE, cur)
|
>>> psycopg2.extensions.register_type(psycopg2.extensions.UNICODE, cur)
|
||||||
|
|
||||||
|
@ -375,9 +398,9 @@ the connection or globally: see the function
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If you want to receive uniformly all your database input in Unicode, you
|
In Python 2, if you want to receive uniformly all your database input in
|
||||||
can register the related typecasters globally as soon as Psycopg is
|
Unicode, you can register the related typecasters globally as soon as
|
||||||
imported::
|
Psycopg is imported::
|
||||||
|
|
||||||
import psycopg2
|
import psycopg2
|
||||||
import psycopg2.extensions
|
import psycopg2.extensions
|
||||||
|
|
|
@ -835,14 +835,22 @@ class CompositeCaster(object):
|
||||||
# Store the transaction status of the connection to revert it after use
|
# Store the transaction status of the connection to revert it after use
|
||||||
conn_status = conn.status
|
conn_status = conn.status
|
||||||
|
|
||||||
|
# Use the correct schema
|
||||||
|
if '.' in name:
|
||||||
|
schema, tname = name.split('.', 1)
|
||||||
|
else:
|
||||||
|
tname = name
|
||||||
|
schema = 'public'
|
||||||
|
|
||||||
# get the type oid and attributes
|
# get the type oid and attributes
|
||||||
curs.execute("""\
|
curs.execute("""\
|
||||||
SELECT t.oid, attname, atttypid
|
SELECT t.oid, attname, atttypid
|
||||||
FROM pg_type t
|
FROM pg_type t
|
||||||
JOIN pg_namespace ns ON typnamespace = ns.oid
|
JOIN pg_namespace ns ON typnamespace = ns.oid
|
||||||
JOIN pg_attribute a ON attrelid = typrelid
|
JOIN pg_attribute a ON attrelid = typrelid
|
||||||
WHERE typname = %s and nspname = 'public';
|
WHERE typname = %s and nspname = %s
|
||||||
""", (name, ))
|
ORDER BY attnum;
|
||||||
|
""", (tname, schema))
|
||||||
|
|
||||||
recs = curs.fetchall()
|
recs = curs.fetchall()
|
||||||
|
|
||||||
|
@ -858,7 +866,7 @@ WHERE typname = %s and nspname = 'public';
|
||||||
type_oid = recs[0][0]
|
type_oid = recs[0][0]
|
||||||
type_attrs = [ (r[1], r[2]) for r in recs ]
|
type_attrs = [ (r[1], r[2]) for r in recs ]
|
||||||
|
|
||||||
return CompositeCaster(name, type_oid, type_attrs)
|
return CompositeCaster(tname, type_oid, type_attrs)
|
||||||
|
|
||||||
def register_composite(name, conn_or_curs, globally=False):
|
def register_composite(name, conn_or_curs, globally=False):
|
||||||
"""Register a typecaster to convert a composite type into a tuple.
|
"""Register a typecaster to convert a composite type into a tuple.
|
||||||
|
|
15
psycopg/_psycopg.vc9.amd64.manifest
Normal file
15
psycopg/_psycopg.vc9.amd64.manifest
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="amd64" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</assembly>
|
15
psycopg/_psycopg.vc9.x86.manifest
Normal file
15
psycopg/_psycopg.vc9.x86.manifest
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
</assembly>
|
|
@ -42,8 +42,12 @@ pfloat_getquoted(pfloatObject *self, PyObject *args)
|
||||||
double n = PyFloat_AsDouble(self->wrapped);
|
double n = PyFloat_AsDouble(self->wrapped);
|
||||||
if (isnan(n))
|
if (isnan(n))
|
||||||
rv = Bytes_FromString("'NaN'::float");
|
rv = Bytes_FromString("'NaN'::float");
|
||||||
else if (isinf(n))
|
else if (isinf(n)) {
|
||||||
rv = Bytes_FromString("'Infinity'::float");
|
if (n > 0)
|
||||||
|
rv = Bytes_FromString("'Infinity'::float");
|
||||||
|
else
|
||||||
|
rv = Bytes_FromString("'-Infinity'::float");
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
rv = PyObject_Repr(self->wrapped);
|
rv = PyObject_Repr(self->wrapped);
|
||||||
|
|
||||||
|
|
21
setup.py
21
setup.py
|
@ -54,6 +54,8 @@ from distutils.errors import DistutilsFileError
|
||||||
from distutils.command.build_ext import build_ext
|
from distutils.command.build_ext import build_ext
|
||||||
from distutils.sysconfig import get_python_inc
|
from distutils.sysconfig import get_python_inc
|
||||||
from distutils.ccompiler import get_default_compiler
|
from distutils.ccompiler import get_default_compiler
|
||||||
|
from distutils.dep_util import newer_group
|
||||||
|
from distutils.util import get_platform
|
||||||
try:
|
try:
|
||||||
from distutils.command.build_py import build_py_2to3 as build_py
|
from distutils.command.build_py import build_py_2to3 as build_py
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -73,7 +75,7 @@ except ImportError:
|
||||||
# Take a look at http://www.python.org/dev/peps/pep-0386/
|
# Take a look at http://www.python.org/dev/peps/pep-0386/
|
||||||
# for a consistent versioning pattern.
|
# for a consistent versioning pattern.
|
||||||
|
|
||||||
PSYCOPG_VERSION = '2.4-beta1'
|
PSYCOPG_VERSION = '2.4-beta2'
|
||||||
|
|
||||||
version_flags = ['dt', 'dec']
|
version_flags = ['dt', 'dec']
|
||||||
|
|
||||||
|
@ -149,6 +151,23 @@ class psycopg_build_ext(build_ext):
|
||||||
def get_pg_config(self, kind):
|
def get_pg_config(self, kind):
|
||||||
return get_pg_config(kind, self.pg_config)
|
return get_pg_config(kind, self.pg_config)
|
||||||
|
|
||||||
|
def build_extension(self, ext):
|
||||||
|
build_ext.build_extension(self, ext)
|
||||||
|
|
||||||
|
# For MSVC compiler and Python 2.6/2.7 (aka VS 2008), re-insert the
|
||||||
|
# Manifest into the resulting .pyd file.
|
||||||
|
sysVer = sys.version_info[:2]
|
||||||
|
if self.get_compiler().lower().startswith('msvc') and \
|
||||||
|
sysVer in ((2,6), (2,7)):
|
||||||
|
platform = get_platform()
|
||||||
|
# Default to the x86 manifest
|
||||||
|
manifest = '_psycopg.vc9.x86.manifest'
|
||||||
|
if platform == 'win-amd64':
|
||||||
|
manifest = '_psycopg.vc9.amd64.manifest'
|
||||||
|
self.compiler.spawn(['mt.exe', '-nologo', '-manifest',
|
||||||
|
os.path.join('psycopg', manifest),
|
||||||
|
'-outputresource:%s;2' % (os.path.join(self.build_lib, 'psycopg2', '_psycopg.pyd'))])
|
||||||
|
|
||||||
def finalize_win32(self):
|
def finalize_win32(self):
|
||||||
"""Finalize build system configuration on win32 platform."""
|
"""Finalize build system configuration on win32 platform."""
|
||||||
import struct
|
import struct
|
||||||
|
|
|
@ -143,7 +143,7 @@ class ConnectionTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_weakref(self):
|
def test_weakref(self):
|
||||||
from weakref import ref
|
from weakref import ref
|
||||||
conn = psycopg2.connect(self.conn.dsn)
|
conn = psycopg2.connect(dsn)
|
||||||
w = ref(conn)
|
w = ref(conn)
|
||||||
conn.close()
|
conn.close()
|
||||||
del conn
|
del conn
|
||||||
|
|
|
@ -136,9 +136,9 @@ class CursorTests(unittest.TestCase):
|
||||||
# timestamp will not be influenced by the pause in Python world.
|
# timestamp will not be influenced by the pause in Python world.
|
||||||
curs.execute("""select clock_timestamp() from generate_series(1,2)""")
|
curs.execute("""select clock_timestamp() from generate_series(1,2)""")
|
||||||
i = iter(curs)
|
i = iter(curs)
|
||||||
t1 = i.next()[0]
|
t1 = (i.next())[0] # the brackets work around a 2to3 bug
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
t2 = i.next()[0]
|
t2 = (i.next())[0]
|
||||||
self.assert_((t2 - t1).microseconds * 1e-6 < 0.1,
|
self.assert_((t2 - t1).microseconds * 1e-6 < 0.1,
|
||||||
"named cursor records fetched in 2 roundtrips (delta: %s)"
|
"named cursor records fetched in 2 roundtrips (delta: %s)"
|
||||||
% (t2 - t1))
|
% (t2 - t1))
|
||||||
|
|
|
@ -6,6 +6,7 @@ dbname = os.environ.get('PSYCOPG2_TESTDB', 'psycopg2_test')
|
||||||
dbhost = os.environ.get('PSYCOPG2_TESTDB_HOST', None)
|
dbhost = os.environ.get('PSYCOPG2_TESTDB_HOST', None)
|
||||||
dbport = os.environ.get('PSYCOPG2_TESTDB_PORT', None)
|
dbport = os.environ.get('PSYCOPG2_TESTDB_PORT', None)
|
||||||
dbuser = os.environ.get('PSYCOPG2_TESTDB_USER', None)
|
dbuser = os.environ.get('PSYCOPG2_TESTDB_USER', None)
|
||||||
|
dbpass = os.environ.get('PSYCOPG2_TESTDB_PASSWORD', None)
|
||||||
|
|
||||||
# Check if we want to test psycopg's green path.
|
# Check if we want to test psycopg's green path.
|
||||||
green = os.environ.get('PSYCOPG2_TEST_GREEN', None)
|
green = os.environ.get('PSYCOPG2_TEST_GREEN', None)
|
||||||
|
@ -29,5 +30,7 @@ if dbport is not None:
|
||||||
dsn += ' port=%s' % dbport
|
dsn += ' port=%s' % dbport
|
||||||
if dbuser is not None:
|
if dbuser is not None:
|
||||||
dsn += ' user=%s' % dbuser
|
dsn += ' user=%s' % dbuser
|
||||||
|
if dbpass is not None:
|
||||||
|
dsn += ' password=%s' % dbpass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# testutils.py - utility module for psycopg2 testing.
|
# testutils.py - utility module for psycopg2 testing.
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (C) 2010-2011 Daniele Varrazzo <daniele.varrazzo@gmail.com>
|
# Copyright (C) 2010-2011 Daniele Varrazzo <daniele.varrazzo@gmail.com>
|
||||||
#
|
#
|
||||||
|
@ -190,21 +191,24 @@ def script_to_py3(script):
|
||||||
return script
|
return script
|
||||||
|
|
||||||
import tempfile
|
import tempfile
|
||||||
f = tempfile.NamedTemporaryFile(suffix=".py")
|
f = tempfile.NamedTemporaryFile(suffix=".py", delete=False)
|
||||||
f.write(script.encode())
|
f.write(script.encode())
|
||||||
f.flush()
|
f.flush()
|
||||||
|
filename = f.name
|
||||||
|
f.close()
|
||||||
|
|
||||||
# 2to3 is way too chatty
|
# 2to3 is way too chatty
|
||||||
import logging
|
import logging
|
||||||
logging.basicConfig(filename=os.devnull)
|
logging.basicConfig(filename=os.devnull)
|
||||||
|
|
||||||
from lib2to3.main import main
|
from lib2to3.main import main
|
||||||
if main("lib2to3.fixes", ['--no-diffs', '-w', '-n', f.name]):
|
if main("lib2to3.fixes", ['--no-diffs', '-w', '-n', filename]):
|
||||||
raise Exception('py3 conversion failed')
|
raise Exception('py3 conversion failed')
|
||||||
|
|
||||||
f2 = open(f.name)
|
f2 = open(filename)
|
||||||
try:
|
try:
|
||||||
return f2.read()
|
return f2.read()
|
||||||
finally:
|
finally:
|
||||||
f2.close()
|
f2.close()
|
||||||
|
os.remove(filename)
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,9 @@ class TypesBasicTests(unittest.TestCase):
|
||||||
self.failUnless(str(s) == "inf", "wrong float quoting: " + str(s))
|
self.failUnless(str(s) == "inf", "wrong float quoting: " + str(s))
|
||||||
self.failUnless(type(s) == float, "wrong float conversion: " + repr(s))
|
self.failUnless(type(s) == float, "wrong float conversion: " + repr(s))
|
||||||
|
|
||||||
|
s = self.execute("SELECT %s AS foo", (float("-inf"),))
|
||||||
|
self.failUnless(str(s) == "-inf", "wrong float quoting: " + str(s))
|
||||||
|
|
||||||
def testBinary(self):
|
def testBinary(self):
|
||||||
if sys.version_info[0] < 3:
|
if sys.version_info[0] < 3:
|
||||||
s = ''.join([chr(x) for x in range(256)])
|
s = ''.join([chr(x) for x in range(256)])
|
||||||
|
|
|
@ -267,7 +267,7 @@ class HstoreTestCase(unittest.TestCase):
|
||||||
oids = HstoreAdapter.get_oids(self.conn)
|
oids = HstoreAdapter.get_oids(self.conn)
|
||||||
try:
|
try:
|
||||||
register_hstore(self.conn, globally=True)
|
register_hstore(self.conn, globally=True)
|
||||||
conn2 = psycopg2.connect(self.conn.dsn)
|
conn2 = psycopg2.connect(dsn)
|
||||||
try:
|
try:
|
||||||
cur2 = self.conn.cursor()
|
cur2 = self.conn.cursor()
|
||||||
cur2.execute("select 'a => b'::hstore")
|
cur2.execute("select 'a => b'::hstore")
|
||||||
|
@ -489,8 +489,8 @@ class AdaptTypeTestCase(unittest.TestCase):
|
||||||
def test_register_on_connection(self):
|
def test_register_on_connection(self):
|
||||||
self._create_type("type_ii", [("a", "integer"), ("b", "integer")])
|
self._create_type("type_ii", [("a", "integer"), ("b", "integer")])
|
||||||
|
|
||||||
conn1 = psycopg2.connect(self.conn.dsn)
|
conn1 = psycopg2.connect(dsn)
|
||||||
conn2 = psycopg2.connect(self.conn.dsn)
|
conn2 = psycopg2.connect(dsn)
|
||||||
try:
|
try:
|
||||||
psycopg2.extras.register_composite("type_ii", conn1)
|
psycopg2.extras.register_composite("type_ii", conn1)
|
||||||
curs1 = conn1.cursor()
|
curs1 = conn1.cursor()
|
||||||
|
@ -507,8 +507,8 @@ class AdaptTypeTestCase(unittest.TestCase):
|
||||||
def test_register_globally(self):
|
def test_register_globally(self):
|
||||||
self._create_type("type_ii", [("a", "integer"), ("b", "integer")])
|
self._create_type("type_ii", [("a", "integer"), ("b", "integer")])
|
||||||
|
|
||||||
conn1 = psycopg2.connect(self.conn.dsn)
|
conn1 = psycopg2.connect(dsn)
|
||||||
conn2 = psycopg2.connect(self.conn.dsn)
|
conn2 = psycopg2.connect(dsn)
|
||||||
try:
|
try:
|
||||||
t = psycopg2.extras.register_composite("type_ii", conn1, globally=True)
|
t = psycopg2.extras.register_composite("type_ii", conn1, globally=True)
|
||||||
try:
|
try:
|
||||||
|
@ -525,6 +525,24 @@ class AdaptTypeTestCase(unittest.TestCase):
|
||||||
conn1.close()
|
conn1.close()
|
||||||
conn2.close()
|
conn2.close()
|
||||||
|
|
||||||
|
@skip_if_no_composite
|
||||||
|
def test_composite_namespace(self):
|
||||||
|
curs = self.conn.cursor()
|
||||||
|
curs.execute("""
|
||||||
|
select nspname from pg_namespace
|
||||||
|
where nspname = 'typens';
|
||||||
|
""")
|
||||||
|
if not curs.fetchone():
|
||||||
|
curs.execute("create schema typens;")
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
self._create_type("typens.typens_ii",
|
||||||
|
[("a", "integer"), ("b", "integer")])
|
||||||
|
t = psycopg2.extras.register_composite(
|
||||||
|
"typens.typens_ii", self.conn)
|
||||||
|
curs.execute("select (4,8)::typens.typens_ii")
|
||||||
|
self.assertEqual(curs.fetchone()[0], (4,8))
|
||||||
|
|
||||||
def _create_type(self, name, fields):
|
def _create_type(self, name, fields):
|
||||||
curs = self.conn.cursor()
|
curs = self.conn.cursor()
|
||||||
try:
|
try:
|
||||||
|
@ -534,11 +552,16 @@ class AdaptTypeTestCase(unittest.TestCase):
|
||||||
|
|
||||||
curs.execute("create type %s as (%s);" % (name,
|
curs.execute("create type %s as (%s);" % (name,
|
||||||
", ".join(["%s %s" % p for p in fields])))
|
", ".join(["%s %s" % p for p in fields])))
|
||||||
|
if '.' in name:
|
||||||
|
schema, name = name.split('.')
|
||||||
|
else:
|
||||||
|
schema = 'public'
|
||||||
|
|
||||||
curs.execute("""\
|
curs.execute("""\
|
||||||
SELECT t.oid
|
SELECT t.oid
|
||||||
FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid
|
FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid
|
||||||
WHERE typname = %s and nspname = 'public';
|
WHERE typname = %s and nspname = %s;
|
||||||
""", (name,))
|
""", (name, schema))
|
||||||
oid = curs.fetchone()[0]
|
oid = curs.fetchone()[0]
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
return oid
|
return oid
|
||||||
|
|
Loading…
Reference in New Issue
Block a user