mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-11-04 09:47:30 +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