165165
166166except ImportError : # Python 3
167167 import urllib .parse as urlparse
168+ from collections import namedtuple
168169
169170import psycopg2
170171from postgres .context_managers import ConnectionContextManager
171172from postgres .context_managers import CursorContextManager
172- from postgres .context_managers import handle_back_as
173- from postgres .cursors import SimpleNamedTupleCursor , SimpleCursorBase
173+ from postgres .cursors import SimpleTupleCursor , SimpleNamedTupleCursor
174+ from postgres .cursors import SimpleDictCursor , SimpleCursorBase
174175from postgres .orm import Model
175176from psycopg2 .extras import register_composite , CompositeCaster
176177from psycopg2 .pool import ThreadedConnectionPool as ConnectionPool
@@ -236,6 +237,12 @@ class NotRegistered(Exception):
236237 def __str__ (self ):
237238 return "The model {} is not registered." .format (self .args [0 ].__name__ )
238239
240+ class BadBackAs (Exception ):
241+ def __str__ (self ):
242+ return "Bad back_as: {}. Available back_as values are: tuple, " \
243+ "namedtuple, dict, or None (to use the default)." \
244+ .format (self .args [0 ])
245+
239246
240247# The Main Event
241248# ==============
@@ -522,10 +529,15 @@ def all(self, sql, parameters=None, back_as=None, *a, **kw):
522529 return cursor .all (sql , parameters )
523530
524531
525- def get_cursor (self , back_as = None , * a , ** kw ):
532+ def get_cursor (self , * a , ** kw ):
526533 """Return a :py:class:`~postgres.CursorContextManager` that uses
527534 our connection pool.
528535
536+ :param a: passed through to the :py:meth:`cursor` method of instances
537+ of the class returned by :py:func:`~postgres.make_Connection`
538+ :param kw: passed through to the :py:meth:`cursor` method of instances
539+ of the class returned by :py:func:`~postgres.make_Connection`
540+
529541 >>> with db.get_cursor() as cursor:
530542 ... cursor.all("SELECT * FROM foo")
531543 ...
@@ -554,7 +566,7 @@ def get_cursor(self, back_as=None, *a, **kw):
554566 transaction.
555567
556568 """
557- return CursorContextManager (self .pool , back_as = back_as , * a , ** kw )
569+ return CursorContextManager (self .pool , * a , ** kw )
558570
559571
560572 def get_connection (self ):
@@ -680,14 +692,26 @@ def make_Connection(postgres):
680692 :returns: a :py:class:`Connection` class
681693
682694 The class defined and returned here will be linked to the instance of
683- :py:class:`~postgres.Postgres` that is passed in as :py:attr:`postgres` and
684- will use the :py:attr:`default_cursor_factory` attribute of that object.
685- The :py:class:`~postgres.Postgres` instance will use this class as the
686- :py:attr:`connection_factory` for its connection pool. The
687- :py:meth:`cursor` method of this class accepts a :py:attr:`back_as`
688- argument, which is processed according to
689- :py:func:`~postgres.handle_back_as`. We also set client encoding to
690- ``UTF-8``.
695+ :py:class:`~postgres.Postgres` that is passed in as :py:attr:`postgres`,
696+ which will use this class as the :py:attr:`connection_factory` for its
697+ connection pool.
698+
699+ The :py:meth:`cursor` method of this class accepts a :py:attr:`back_as`
700+ keyword argument. If a :py:attr:`cursor_factory` keyword argument is also
701+ given, then any :py:attr:`back_as` is ignored and discarded. Valid values
702+ for :py:attr:`back_as` are :py:class:`tuple`, :py:class:`namedtuple`,
703+ :py:class:`dict` (or the strings ``tuple``, ``namedtuple``, and ``dict``),
704+ and :py:class:`None`. If the value of :py:attr:`back_as` is
705+ :py:class:`None`, then we'll use the default :py:attr:`cursor_factory` with
706+ which our parent :py:class:`~postgres.Postgres` instance was instantiated.
707+ If :py:attr:`back_as` is not :py:class:`None`, then we'll specify a
708+ :py:attr:`cursor_factory` that will result in records of the designated
709+ type: :py:class:`postgres.cursor.SimpleTupleCursor` for :py:class:`tuple`,
710+ :py:class:`postgres.cursor.SimpleNamedTupleCursor` for
711+ :py:class:`namedtuple`, and :py:class:`postgres.cursor.SimpleDictCursor`
712+ for :py:class:`dict`.
713+
714+ We also set client encoding to ``UTF-8``.
691715
692716 """
693717 class Connection (psycopg2 .extensions .connection ):
@@ -700,11 +724,36 @@ def __init__(self, *a, **kw):
700724 def cursor (self , * a , ** kw ):
701725 if 'back_as' in kw :
702726 back_as = kw .pop ('back_as' )
703- kw = handle_back_as (back_as , ** kw )
727+ kw = self . handle_back_as (back_as , ** kw )
704728 if 'cursor_factory' not in kw :
705729 kw ['cursor_factory' ] = self .postgres .default_cursor_factory
706730 return psycopg2 .extensions .connection .cursor (self , * a , ** kw )
707731
732+ def handle_back_as (self , back_as , ** kw ):
733+
734+ if 'cursor_factory' not in kw :
735+
736+ # Compute cursor_factory from back_as.
737+ # ====================================
738+
739+ registry = { tuple : SimpleTupleCursor
740+ , 'tuple' : SimpleTupleCursor
741+ , namedtuple : SimpleNamedTupleCursor
742+ , 'namedtuple' : SimpleNamedTupleCursor
743+ , dict : SimpleDictCursor
744+ , 'dict' : SimpleDictCursor
745+ , None : None
746+ }
747+
748+ if back_as not in registry :
749+ raise BadBackAs (back_as )
750+
751+ cursor_factory = registry [back_as ]
752+ if cursor_factory is not None :
753+ kw ['cursor_factory' ] = cursor_factory
754+
755+ return kw
756+
708757 return Connection
709758
710759
0 commit comments