mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-25 10:23:43 +03:00
Added cursor_factory connection attribute and connect() parameter
This commit is contained in:
parent
0e06addc9f
commit
9e15f54fe8
2
NEWS
2
NEWS
|
@ -10,6 +10,8 @@ New features:
|
||||||
- Added `~psycopg2.extensions.Diagnostics` object to get extended info
|
- Added `~psycopg2.extensions.Diagnostics` object to get extended info
|
||||||
from a database error. Many thanks to Matthew Woodcraft for the
|
from a database error. Many thanks to Matthew Woodcraft for the
|
||||||
implementation (:ticket:`#149`).
|
implementation (:ticket:`#149`).
|
||||||
|
- Added `connection.cursor_factory` attribute to customize the default
|
||||||
|
object returned by `~connection.cursor()`.
|
||||||
- Added support for backward scrollable cursors. Thanks to Jon Nelson
|
- Added support for backward scrollable cursors. Thanks to Jon Nelson
|
||||||
for the initial patch (:ticket:`#108`).
|
for the initial patch (:ticket:`#108`).
|
||||||
- Added a simple way to :ref:`customize casting of composite types
|
- Added a simple way to :ref:`customize casting of composite types
|
||||||
|
|
|
@ -27,6 +27,7 @@ More advanced topics
|
||||||
wait(aconn)
|
wait(aconn)
|
||||||
acurs = aconn.cursor()
|
acurs = aconn.cursor()
|
||||||
|
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
double: Subclassing; Cursor
|
double: Subclassing; Cursor
|
||||||
double: Subclassing; Connection
|
double: Subclassing; Connection
|
||||||
|
@ -45,6 +46,16 @@ but other uses are possible. `cursor` is much more interesting, because
|
||||||
it is the class where query building, execution and result type-casting into
|
it is the class where query building, execution and result type-casting into
|
||||||
Python variables happens.
|
Python variables happens.
|
||||||
|
|
||||||
|
The `~psycopg2.extras` module contains several examples of :ref:`connection
|
||||||
|
and cursor sublcasses <cursor-subclasses>`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
If you only need a customized cursor class, since Psycopg 2.5 you can use
|
||||||
|
the `~connection.cursor_factory` parameter of a regular connection instead
|
||||||
|
of creating a new `!connection` subclass.
|
||||||
|
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
single: Example; Cursor subclass
|
single: Example; Cursor subclass
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,8 @@ The ``connection`` class
|
||||||
The *cursor_factory* argument can be used to create non-standard
|
The *cursor_factory* argument can be used to create non-standard
|
||||||
cursors. The class returned must be a subclass of
|
cursors. The class returned must be a subclass of
|
||||||
`psycopg2.extensions.cursor`. See :ref:`subclassing-cursor` for
|
`psycopg2.extensions.cursor`. See :ref:`subclassing-cursor` for
|
||||||
details.
|
details. A default factory for the connection can also be specified
|
||||||
|
using the `~connection.cursor_factory` attribute.
|
||||||
|
|
||||||
.. versionchanged:: 2.4.3 added the *withhold* argument.
|
.. versionchanged:: 2.4.3 added the *withhold* argument.
|
||||||
.. versionchanged:: 2.5 added the *scrollable* argument.
|
.. versionchanged:: 2.5 added the *scrollable* argument.
|
||||||
|
@ -504,6 +505,15 @@ The ``connection`` class
|
||||||
the payload was not accessible. To keep backward compatibility,
|
the payload was not accessible. To keep backward compatibility,
|
||||||
`!Notify` objects can still be accessed as 2 items tuples.
|
`!Notify` objects can still be accessed as 2 items tuples.
|
||||||
|
|
||||||
|
|
||||||
|
.. attribute:: cursor_factory
|
||||||
|
|
||||||
|
The default cursor factory used by `~connection.cursor()` if the
|
||||||
|
parameter is no specified.
|
||||||
|
|
||||||
|
.. versionadded:: 2.5
|
||||||
|
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
pair: Backend; PID
|
pair: Backend; PID
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ The module contains a few objects and function extending the minimum set of
|
||||||
functionalities defined by the |DBAPI|_.
|
functionalities defined by the |DBAPI|_.
|
||||||
|
|
||||||
|
|
||||||
.. class:: connection
|
.. class:: connection(dsn, async=False)
|
||||||
|
|
||||||
Is the class usually returned by the `~psycopg2.connect()` function.
|
Is the class usually returned by the `~psycopg2.connect()` function.
|
||||||
It is exposed by the `extensions` module in order to allow
|
It is exposed by the `extensions` module in order to allow
|
||||||
|
@ -21,11 +21,9 @@ functionalities defined by the |DBAPI|_.
|
||||||
`!connect()` function using the `connection_factory` parameter.
|
`!connect()` function using the `connection_factory` parameter.
|
||||||
See also :ref:`subclassing-connection`.
|
See also :ref:`subclassing-connection`.
|
||||||
|
|
||||||
Subclasses should have constructor signature :samp:`({dsn}, {async}=0)`.
|
|
||||||
|
|
||||||
For a complete description of the class, see `connection`.
|
For a complete description of the class, see `connection`.
|
||||||
|
|
||||||
.. class:: cursor
|
.. class:: cursor(conn, name=None)
|
||||||
|
|
||||||
It is the class usually returnded by the `connection.cursor()`
|
It is the class usually returnded by the `connection.cursor()`
|
||||||
method. It is exposed by the `extensions` module in order to allow
|
method. It is exposed by the `extensions` module in order to allow
|
||||||
|
|
|
@ -16,22 +16,27 @@ This module is a generic place used to hold little helper functions and
|
||||||
classes until a better place in the distribution is found.
|
classes until a better place in the distribution is found.
|
||||||
|
|
||||||
|
|
||||||
.. index::
|
.. _cursor-subclasses:
|
||||||
pair: Cursor; Dictionary
|
|
||||||
|
|
||||||
.. _dict-cursor:
|
|
||||||
|
|
||||||
|
|
||||||
Connection and cursor subclasses
|
Connection and cursor subclasses
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
A few objects that change the way the results are returned by the cursor or
|
A few objects that change the way the results are returned by the cursor or
|
||||||
modify the object behavior in some other way. Typically `!connection`
|
modify the object behavior in some other way. Typically `!cursor` subclasses
|
||||||
subclasses are passed as *connection_factory* argument to
|
are passed as *cursor_factory* argument to `~psycopg2.connect()` so that the
|
||||||
`~psycopg2.connect()` so that the connection will generate the matching
|
connection's `~connection.cursor()` method will generate objects of this
|
||||||
`!cursor` subclass. Alternatively a `!cursor` subclass can be used one-off by
|
class. Alternatively a `!cursor` subclass can be used one-off by passing it
|
||||||
passing it as the *cursor_factory* argument to the `~connection.cursor()`
|
as the *cursor_factory* argument to the `!cursor()` method.
|
||||||
method of a regular `!connection`.
|
|
||||||
|
If you want to use a `!connection` subclass you can pass it as the
|
||||||
|
*connection_factory* argument of the `!connect()` function.
|
||||||
|
|
||||||
|
|
||||||
|
.. index::
|
||||||
|
pair: Cursor; Dictionary
|
||||||
|
|
||||||
|
.. _dict-cursor:
|
||||||
|
|
||||||
|
|
||||||
Dictionary-like cursor
|
Dictionary-like cursor
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -61,6 +66,11 @@ The records still support indexing as the original tuple:
|
||||||
|
|
||||||
.. autoclass:: DictConnection
|
.. autoclass:: DictConnection
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Not very useful since Psycopg 2.5: you can use `psycopg2.connect`\
|
||||||
|
``(dsn, cursor_factory=DictCursor)`` instead of `!DictConnection`.
|
||||||
|
|
||||||
.. autoclass:: DictRow
|
.. autoclass:: DictRow
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,6 +81,12 @@ Real dictionary cursor
|
||||||
|
|
||||||
.. autoclass:: RealDictConnection
|
.. autoclass:: RealDictConnection
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Not very useful since Psycopg 2.5: you can use `psycopg2.connect`\
|
||||||
|
``(dsn, cursor_factory=RealDictCursor)`` instead of
|
||||||
|
`!RealDictConnection`.
|
||||||
|
|
||||||
.. autoclass:: RealDictRow
|
.. autoclass:: RealDictRow
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,6 +117,12 @@ expect it to be... ::
|
||||||
|
|
||||||
.. autoclass:: NamedTupleConnection
|
.. autoclass:: NamedTupleConnection
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Not very useful since Psycopg 2.5: you can use `psycopg2.connect`\
|
||||||
|
``(dsn, cursor_factory=NamedTupleCursor)`` instead of
|
||||||
|
`!NamedTupleConnection`.
|
||||||
|
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
pair: Cursor; Logging
|
pair: Cursor; Logging
|
||||||
|
|
|
@ -17,8 +17,8 @@ The module interface respects the standard defined in the |DBAPI|_.
|
||||||
single: DSN (Database Source Name)
|
single: DSN (Database Source Name)
|
||||||
|
|
||||||
.. function::
|
.. function::
|
||||||
connect(dsn, connection_factory=None, async=False)
|
connect(dsn, connection_factory=None, cursor_factory=None, async=False)
|
||||||
connect(\*\*kwargs, connection_factory=None, async=False)
|
connect(\*\*kwargs, connection_factory=None, cursor_factory=None, async=False)
|
||||||
|
|
||||||
Create a new database session and return a new `connection` object.
|
Create a new database session and return a new `connection` object.
|
||||||
|
|
||||||
|
@ -33,8 +33,9 @@ The module interface respects the standard defined in the |DBAPI|_.
|
||||||
|
|
||||||
The two call styles are mutually exclusive: you cannot specify connection
|
The two call styles are mutually exclusive: you cannot specify connection
|
||||||
parameters as keyword arguments together with a connection string; only
|
parameters as keyword arguments together with a connection string; only
|
||||||
*connection_factory* and *async* are supported together with the *dsn*
|
the parameters not needed for the database connection (*i.e.*
|
||||||
argument.
|
*connection_factory*, *cursor_factory*, and *async*) are supported
|
||||||
|
together with the *dsn* argument.
|
||||||
|
|
||||||
The basic connection parameters are:
|
The basic connection parameters are:
|
||||||
|
|
||||||
|
@ -61,7 +62,9 @@ The module interface respects the standard defined in the |DBAPI|_.
|
||||||
Using the *connection_factory* parameter a different class or
|
Using the *connection_factory* parameter a different class or
|
||||||
connections factory can be specified. It should be a callable object
|
connections factory can be specified. It should be a callable object
|
||||||
taking a *dsn* string argument. See :ref:`subclassing-connection` for
|
taking a *dsn* string argument. See :ref:`subclassing-connection` for
|
||||||
details.
|
details. If a *cursor_factory* is specified, the connection's
|
||||||
|
`~connection.cursor_factory` is set to it. If you only need customized
|
||||||
|
cursors you can use this parameter instead of subclassing a connection.
|
||||||
|
|
||||||
Using *async*\=\ `!True` an asynchronous connection will be created: see
|
Using *async*\=\ `!True` an asynchronous connection will be created: see
|
||||||
:ref:`async-support` to know about advantages and limitations.
|
:ref:`async-support` to know about advantages and limitations.
|
||||||
|
@ -70,6 +73,9 @@ The module interface respects the standard defined in the |DBAPI|_.
|
||||||
any keyword argument is passed to the connection. Previously only the
|
any keyword argument is passed to the connection. Previously only the
|
||||||
basic parameters (plus `!sslmode`) were supported as keywords.
|
basic parameters (plus `!sslmode`) were supported as keywords.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.5
|
||||||
|
added the *cursor_factory* parameter.
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
- libpq `connection string syntax`__
|
- libpq `connection string syntax`__
|
||||||
|
|
|
@ -101,7 +101,7 @@ del re
|
||||||
|
|
||||||
def connect(dsn=None,
|
def connect(dsn=None,
|
||||||
database=None, user=None, password=None, host=None, port=None,
|
database=None, user=None, password=None, host=None, port=None,
|
||||||
connection_factory=None, async=False, **kwargs):
|
connection_factory=None, cursor_factory=None, async=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Create a new database connection.
|
Create a new database connection.
|
||||||
|
|
||||||
|
@ -126,6 +126,9 @@ def connect(dsn=None,
|
||||||
factory can be specified. It should be a callable object taking a dsn
|
factory can be specified. It should be a callable object taking a dsn
|
||||||
argument.
|
argument.
|
||||||
|
|
||||||
|
Using the *cursor_factory* parameter, a new default cursor factory will be
|
||||||
|
used by cursor().
|
||||||
|
|
||||||
Using *async*=True an asynchronous connection will be created.
|
Using *async*=True an asynchronous connection will be created.
|
||||||
|
|
||||||
Any other keyword parameter will be passed to the underlying client
|
Any other keyword parameter will be passed to the underlying client
|
||||||
|
@ -158,7 +161,11 @@ def connect(dsn=None,
|
||||||
dsn = " ".join(["%s=%s" % (k, _param_escape(str(v)))
|
dsn = " ".join(["%s=%s" % (k, _param_escape(str(v)))
|
||||||
for (k, v) in items])
|
for (k, v) in items])
|
||||||
|
|
||||||
return _connect(dsn, connection_factory=connection_factory, async=async)
|
conn = _connect(dsn, connection_factory=connection_factory, async=async)
|
||||||
|
if cursor_factory is not None:
|
||||||
|
conn.cursor_factory = cursor_factory
|
||||||
|
|
||||||
|
return conn
|
||||||
|
|
||||||
|
|
||||||
__all__ = filter(lambda k: not k.startswith('_'), locals().keys())
|
__all__ = filter(lambda k: not k.startswith('_'), locals().keys())
|
||||||
|
|
|
@ -121,6 +121,7 @@ struct connectionObject {
|
||||||
|
|
||||||
int autocommit;
|
int autocommit;
|
||||||
|
|
||||||
|
PyObject *cursor_factory; /* default cursor factory from cursor() */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* map isolation level values into a numeric const */
|
/* map isolation level values into a numeric const */
|
||||||
|
|
|
@ -64,6 +64,10 @@ psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *kwargs)
|
||||||
|
|
||||||
EXC_IF_CONN_CLOSED(self);
|
EXC_IF_CONN_CLOSED(self);
|
||||||
|
|
||||||
|
if (self->cursor_factory && self->cursor_factory != Py_None) {
|
||||||
|
factory = self->cursor_factory;
|
||||||
|
}
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(
|
if (!PyArg_ParseTupleAndKeywords(
|
||||||
args, kwargs, "|OOOO", kwlist,
|
args, kwargs, "|OOOO", kwlist,
|
||||||
&name, &factory, &withhold, &scrollable)) {
|
&name, &factory, &withhold, &scrollable)) {
|
||||||
|
@ -1013,6 +1017,8 @@ static struct PyMemberDef connectionObject_members[] = {
|
||||||
{"status", T_INT,
|
{"status", T_INT,
|
||||||
offsetof(connectionObject, status), READONLY,
|
offsetof(connectionObject, status), READONLY,
|
||||||
"The current transaction status."},
|
"The current transaction status."},
|
||||||
|
{"cursor_factory", T_OBJECT, offsetof(connectionObject, cursor_factory), 0,
|
||||||
|
"Default cursor_factory for cursor()."},
|
||||||
{"string_types", T_OBJECT, offsetof(connectionObject, string_types), READONLY,
|
{"string_types", T_OBJECT, offsetof(connectionObject, string_types), READONLY,
|
||||||
"A set of typecasters to convert textual values."},
|
"A set of typecasters to convert textual values."},
|
||||||
{"binary_types", T_OBJECT, offsetof(connectionObject, binary_types), READONLY,
|
{"binary_types", T_OBJECT, offsetof(connectionObject, binary_types), READONLY,
|
||||||
|
|
|
@ -224,6 +224,31 @@ class ConnectionTests(ConnectingTestCase):
|
||||||
|
|
||||||
self.assert_(not notices, "%d notices raised" % len(notices))
|
self.assert_(not notices, "%d notices raised" % len(notices))
|
||||||
|
|
||||||
|
def test_connect_cursor_factory(self):
|
||||||
|
import psycopg2.extras
|
||||||
|
conn = self.connect(cursor_factory=psycopg2.extras.DictCursor)
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("select 1 as a")
|
||||||
|
self.assertEqual(cur.fetchone()['a'], 1)
|
||||||
|
|
||||||
|
def test_cursor_factory(self):
|
||||||
|
self.assertEqual(self.conn.cursor_factory, None)
|
||||||
|
cur = self.conn.cursor()
|
||||||
|
cur.execute("select 1 as a")
|
||||||
|
self.assertRaises(TypeError, (lambda r: r['a']), cur.fetchone())
|
||||||
|
|
||||||
|
self.conn.cursor_factory = psycopg2.extras.DictCursor
|
||||||
|
self.assertEqual(self.conn.cursor_factory, psycopg2.extras.DictCursor)
|
||||||
|
cur = self.conn.cursor()
|
||||||
|
cur.execute("select 1 as a")
|
||||||
|
self.assertEqual(cur.fetchone()['a'], 1)
|
||||||
|
|
||||||
|
self.conn.cursor_factory = None
|
||||||
|
self.assertEqual(self.conn.cursor_factory, None)
|
||||||
|
cur = self.conn.cursor()
|
||||||
|
cur.execute("select 1 as a")
|
||||||
|
self.assertRaises(TypeError, (lambda r: r['a']), cur.fetchone())
|
||||||
|
|
||||||
|
|
||||||
class IsolationLevelsTestCase(ConnectingTestCase):
|
class IsolationLevelsTestCase(ConnectingTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user