mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-25 02:13:44 +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
|
||||
from a database error. Many thanks to Matthew Woodcraft for the
|
||||
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
|
||||
for the initial patch (:ticket:`#108`).
|
||||
- Added a simple way to :ref:`customize casting of composite types
|
||||
|
|
|
@ -27,6 +27,7 @@ More advanced topics
|
|||
wait(aconn)
|
||||
acurs = aconn.cursor()
|
||||
|
||||
|
||||
.. index::
|
||||
double: Subclassing; Cursor
|
||||
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
|
||||
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::
|
||||
single: Example; Cursor subclass
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ The ``connection`` class
|
|||
The *cursor_factory* argument can be used to create non-standard
|
||||
cursors. The class returned must be a subclass of
|
||||
`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.5 added the *scrollable* argument.
|
||||
|
@ -504,6 +505,15 @@ The ``connection`` class
|
|||
the payload was not accessible. To keep backward compatibility,
|
||||
`!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::
|
||||
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|_.
|
||||
|
||||
|
||||
.. class:: connection
|
||||
.. class:: connection(dsn, async=False)
|
||||
|
||||
Is the class usually returned by the `~psycopg2.connect()` function.
|
||||
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.
|
||||
See also :ref:`subclassing-connection`.
|
||||
|
||||
Subclasses should have constructor signature :samp:`({dsn}, {async}=0)`.
|
||||
|
||||
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()`
|
||||
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.
|
||||
|
||||
|
||||
.. index::
|
||||
pair: Cursor; Dictionary
|
||||
|
||||
.. _dict-cursor:
|
||||
|
||||
.. _cursor-subclasses:
|
||||
|
||||
Connection and cursor subclasses
|
||||
--------------------------------
|
||||
|
||||
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`
|
||||
subclasses are passed as *connection_factory* argument to
|
||||
`~psycopg2.connect()` so that the connection will generate the matching
|
||||
`!cursor` subclass. Alternatively a `!cursor` subclass can be used one-off by
|
||||
passing it as the *cursor_factory* argument to the `~connection.cursor()`
|
||||
method of a regular `!connection`.
|
||||
modify the object behavior in some other way. Typically `!cursor` subclasses
|
||||
are passed as *cursor_factory* argument to `~psycopg2.connect()` so that the
|
||||
connection's `~connection.cursor()` method will generate objects of this
|
||||
class. Alternatively a `!cursor` subclass can be used one-off by passing it
|
||||
as the *cursor_factory* argument to the `!cursor()` method.
|
||||
|
||||
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
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -61,6 +66,11 @@ The records still support indexing as the original tuple:
|
|||
|
||||
.. autoclass:: DictConnection
|
||||
|
||||
.. note::
|
||||
|
||||
Not very useful since Psycopg 2.5: you can use `psycopg2.connect`\
|
||||
``(dsn, cursor_factory=DictCursor)`` instead of `!DictConnection`.
|
||||
|
||||
.. autoclass:: DictRow
|
||||
|
||||
|
||||
|
@ -71,6 +81,12 @@ Real dictionary cursor
|
|||
|
||||
.. autoclass:: RealDictConnection
|
||||
|
||||
.. note::
|
||||
|
||||
Not very useful since Psycopg 2.5: you can use `psycopg2.connect`\
|
||||
``(dsn, cursor_factory=RealDictCursor)`` instead of
|
||||
`!RealDictConnection`.
|
||||
|
||||
.. autoclass:: RealDictRow
|
||||
|
||||
|
||||
|
@ -101,6 +117,12 @@ expect it to be... ::
|
|||
|
||||
.. autoclass:: NamedTupleConnection
|
||||
|
||||
.. note::
|
||||
|
||||
Not very useful since Psycopg 2.5: you can use `psycopg2.connect`\
|
||||
``(dsn, cursor_factory=NamedTupleCursor)`` instead of
|
||||
`!NamedTupleConnection`.
|
||||
|
||||
|
||||
.. index::
|
||||
pair: Cursor; Logging
|
||||
|
|
|
@ -17,8 +17,8 @@ The module interface respects the standard defined in the |DBAPI|_.
|
|||
single: DSN (Database Source Name)
|
||||
|
||||
.. function::
|
||||
connect(dsn, connection_factory=None, async=False)
|
||||
connect(\*\*kwargs, connection_factory=None, async=False)
|
||||
connect(dsn, connection_factory=None, cursor_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.
|
||||
|
||||
|
@ -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
|
||||
parameters as keyword arguments together with a connection string; only
|
||||
*connection_factory* and *async* are supported together with the *dsn*
|
||||
argument.
|
||||
the parameters not needed for the database connection (*i.e.*
|
||||
*connection_factory*, *cursor_factory*, and *async*) are supported
|
||||
together with the *dsn* argument.
|
||||
|
||||
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
|
||||
connections factory can be specified. It should be a callable object
|
||||
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
|
||||
: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
|
||||
basic parameters (plus `!sslmode`) were supported as keywords.
|
||||
|
||||
.. versionchanged:: 2.5
|
||||
added the *cursor_factory* parameter.
|
||||
|
||||
.. seealso::
|
||||
|
||||
- libpq `connection string syntax`__
|
||||
|
|
|
@ -101,7 +101,7 @@ del re
|
|||
|
||||
def connect(dsn=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.
|
||||
|
||||
|
@ -126,6 +126,9 @@ def connect(dsn=None,
|
|||
factory can be specified. It should be a callable object taking a dsn
|
||||
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.
|
||||
|
||||
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)))
|
||||
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())
|
||||
|
|
|
@ -121,6 +121,7 @@ struct connectionObject {
|
|||
|
||||
int autocommit;
|
||||
|
||||
PyObject *cursor_factory; /* default cursor factory from cursor() */
|
||||
};
|
||||
|
||||
/* 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);
|
||||
|
||||
if (self->cursor_factory && self->cursor_factory != Py_None) {
|
||||
factory = self->cursor_factory;
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwargs, "|OOOO", kwlist,
|
||||
&name, &factory, &withhold, &scrollable)) {
|
||||
|
@ -1013,6 +1017,8 @@ static struct PyMemberDef connectionObject_members[] = {
|
|||
{"status", T_INT,
|
||||
offsetof(connectionObject, status), READONLY,
|
||||
"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,
|
||||
"A set of typecasters to convert textual values."},
|
||||
{"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))
|
||||
|
||||
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):
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user