-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathcontext_managers.py
156 lines (111 loc) · 5.15 KB
/
context_managers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
from __future__ import absolute_import, division, print_function, unicode_literals
from psycopg2 import InterfaceError
class CursorContextManager(object):
"""Instantiated once per :func:`~postgres.Postgres.get_cursor` call.
:param pool: see :mod:`psycopg2_pool`
:param bool autocommit: see :attr:`psycopg2:connection.autocommit`
:param bool readonly: see :attr:`psycopg2:connection.readonly`
:param \**cursor_kwargs: passed to :meth:`psycopg2:connection.cursor`
During construction, a connection is checked out of the connection pool
and its :attr:`autocommit` and :attr:`readonly` attributes are set, then a
:class:`psycopg2:cursor` is created from that connection.
Upon exit of the ``with`` block, the connection is rolled back if an
exception was raised, or committed otherwise. There are two exceptions to
this:
1. if :attr:`autocommit` is :obj:`True`, then the connection is neither
rolled back nor committed;
2. if :attr:`readonly` is :obj:`True`, then the connection is always rolled
back, never committed.
In all cases the cursor is closed and the connection is put back in the pool.
"""
__slots__ = ('pool', 'conn', 'cursor')
def __init__(self, pool, autocommit=False, readonly=False, **cursor_kwargs):
self.pool = pool
conn = self.pool.getconn()
conn.autocommit = autocommit
conn.readonly = readonly
self.cursor = conn.cursor(**cursor_kwargs)
self.conn = conn
def __enter__(self):
return self.cursor
def __exit__(self, exc_type, exc_val, exc_tb):
"""Put our connection back in the pool.
"""
self.cursor.close()
self.conn.__exit__(exc_type, exc_val, exc_tb)
self.pool.putconn(self.conn)
class ConnectionCursorContextManager(object):
"""Creates a cursor from the given connection, then wraps it in a context
manager that automatically commits or rolls back the changes on exit.
:param conn: a :class:`psycopg2:connection`
:param bool autocommit: see :attr:`psycopg2:connection.autocommit`
:param bool readonly: see :attr:`psycopg2:connection.readonly`
:param \**cursor_kwargs: passed to :meth:`psycopg2:connection.cursor`
During construction, the connection's :attr:`autocommit` and :attr:`readonly`
attributes are set, then :meth:`psycopg2:connection.cursor` is called with
`cursor_kwargs`.
Upon exit of the ``with`` block, the connection is rolled back if an
exception was raised, or committed otherwise. There are two exceptions to
this:
1. if :attr:`autocommit` is :obj:`True`, then the connection is neither
rolled back nor committed;
2. if :attr:`readonly` is :obj:`True`, then the connection is always rolled
back, never committed.
In all cases the cursor is closed.
"""
__slots__ = ('conn', 'cursor')
def __init__(self, conn, autocommit=False, readonly=False, **cursor_kwargs):
conn.autocommit = autocommit
conn.readonly = readonly
self.conn = conn
self.cursor = conn.cursor(**cursor_kwargs)
def __enter__(self):
return self.cursor
def __exit__(self, exc_type, exc_val, exc_tb):
self.cursor.close()
self.conn.__exit__(exc_type, exc_val, exc_tb)
class CursorSubcontextManager(object):
"""Wraps a cursor so that it can be used for a subtransaction.
See :meth:`~postgres.Postgres.get_cursor` for an explanation of subtransactions.
:param cursor: the :class:`psycopg2:cursor` to wrap
:param back_as: temporarily overwrites the cursor's
:attr:`~postgres.cursors.SimpleCursorBase.back_as` attribute
"""
__slots__ = ('cursor', 'back_as', 'outer_back_as')
def __init__(self, cursor, back_as=None):
self.cursor = cursor
self.back_as = back_as
def __enter__(self):
self.outer_back_as = self.cursor.back_as
self.cursor.back_as = self.back_as
return self.cursor
def __exit__(self, exc_type, exc_val, exc_tb):
self.cursor.back_as = self.outer_back_as
class ConnectionContextManager(object):
"""Instantiated once per :func:`~postgres.Postgres.get_connection` call.
:param pool: see :mod:`psycopg2_pool`
:param bool autocommit: see :attr:`psycopg2:connection.autocommit`
:param bool readonly: see :attr:`psycopg2:connection.readonly`
This context manager checks out a connection out of the specified pool, sets
its :attr:`autocommit` and :attr:`readonly` attributes.
The :meth:`__enter__` method returns the :class:`~postgres.Connection`.
The :meth:`__exit__` method rolls back the connection and puts it back in
the pool.
"""
__slots__ = ('pool', 'conn')
def __init__(self, pool, autocommit=False, readonly=False):
self.pool = pool
conn = self.pool.getconn()
conn.autocommit = autocommit
conn.readonly = readonly
self.conn = conn
def __enter__(self):
return self.conn
def __exit__(self, *exc_info):
"""Put our connection back in the pool.
"""
try:
self.conn.rollback()
except InterfaceError:
pass
self.pool.putconn(self.conn)