165
165
166
166
except ImportError : # Python 3
167
167
import urllib .parse as urlparse
168
+ from collections import namedtuple
168
169
169
170
import psycopg2
170
171
from postgres .context_managers import ConnectionContextManager
171
172
from 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
174
175
from postgres .orm import Model
175
176
from psycopg2 .extras import register_composite , CompositeCaster
176
177
from psycopg2 .pool import ThreadedConnectionPool as ConnectionPool
@@ -236,6 +237,12 @@ class NotRegistered(Exception):
236
237
def __str__ (self ):
237
238
return "The model {} is not registered." .format (self .args [0 ].__name__ )
238
239
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
+
239
246
240
247
# The Main Event
241
248
# ==============
@@ -522,10 +529,15 @@ def all(self, sql, parameters=None, back_as=None, *a, **kw):
522
529
return cursor .all (sql , parameters )
523
530
524
531
525
- def get_cursor (self , back_as = None , * a , ** kw ):
532
+ def get_cursor (self , * a , ** kw ):
526
533
"""Return a :py:class:`~postgres.CursorContextManager` that uses
527
534
our connection pool.
528
535
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
+
529
541
>>> with db.get_cursor() as cursor:
530
542
... cursor.all("SELECT * FROM foo")
531
543
...
@@ -554,7 +566,7 @@ def get_cursor(self, back_as=None, *a, **kw):
554
566
transaction.
555
567
556
568
"""
557
- return CursorContextManager (self .pool , back_as = back_as , * a , ** kw )
569
+ return CursorContextManager (self .pool , * a , ** kw )
558
570
559
571
560
572
def get_connection (self ):
@@ -680,14 +692,26 @@ def make_Connection(postgres):
680
692
:returns: a :py:class:`Connection` class
681
693
682
694
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``.
691
715
692
716
"""
693
717
class Connection (psycopg2 .extensions .connection ):
@@ -700,11 +724,36 @@ def __init__(self, *a, **kw):
700
724
def cursor (self , * a , ** kw ):
701
725
if 'back_as' in kw :
702
726
back_as = kw .pop ('back_as' )
703
- kw = handle_back_as (back_as , ** kw )
727
+ kw = self . handle_back_as (back_as , ** kw )
704
728
if 'cursor_factory' not in kw :
705
729
kw ['cursor_factory' ] = self .postgres .default_cursor_factory
706
730
return psycopg2 .extensions .connection .cursor (self , * a , ** kw )
707
731
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
+
708
757
return Connection
709
758
710
759
0 commit comments