Skip to content

Commit f80c79b

Browse files
author
Ted S
authored
Merge pull request #19 from laslabs/hotfix/0.1/session-handling
[FIX] carepoint: Fix session handling
2 parents 5218f42 + 06c1d40 commit f80c79b

3 files changed

Lines changed: 55 additions & 84 deletions

File tree

carepoint/db/carepoint.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ def __init__(
6767
"""
6868

6969
super(Carepoint, self).__init__()
70-
global env, dbs
71-
self.env = env
70+
global dbs
71+
self.env = {}
7272
self.dbs = dbs
7373
self.iter_refresh = False
7474
params = {
@@ -85,7 +85,12 @@ def __init__(
8585
if not self.dbs.get('cph'):
8686
self.dbs['cph'] = Db(**params)
8787
if not self.env.get('cph'):
88-
self.env['cph'] = sessionmaker(bind=self.dbs['cph'])
88+
self.env['cph'] = sessionmaker(
89+
autocommit=False,
90+
autoflush=False,
91+
bind=self.dbs['cph'],
92+
expire_on_commit=True,
93+
)
8994
if smb_user is None:
9095
self.smb_creds = {
9196
'user': user,
@@ -97,9 +102,13 @@ def __init__(
97102
'passwd': smb_passwd,
98103
}
99104

105+
def _get_model_session(self, model_obj):
106+
""" It yields a session for the model_obj """
107+
return self._get_session(model_obj.__dbname__)
108+
100109
@contextmanager
101-
def _get_session(self, model_obj):
102-
session = self.env[model_obj.__dbname__]()
110+
def _get_session(self, db_name):
111+
session = self.env[db_name]()
103112
try:
104113
yield session
105114
session.commit()
@@ -223,13 +232,13 @@ def read(self, model_obj, record_id, with_entities=None):
223232
:type with_entities: list or None
224233
:rtype: :class:`sqlalchemy.engine.ResultProxy`
225234
"""
226-
with self._get_session(model_obj) as session:
235+
with self._get_model_session(model_obj) as session:
227236
res = session.query(model_obj).get(record_id)
228237
if with_entities:
229238
res.with_entities(*self._create_entities(
230239
model_obj, with_entities
231240
))
232-
return res
241+
return res
233242

234243
def search(self, model_obj, filters=None, with_entities=None):
235244
""" Search table by filters and return records
@@ -241,7 +250,7 @@ def search(self, model_obj, filters=None, with_entities=None):
241250
:type with_entities: list or None
242251
:rtype: :class:`sqlalchemy.engine.ResultProxy`
243252
"""
244-
with self._get_session(model_obj) as session:
253+
with self._get_model_session(model_obj) as session:
245254
if filters is None:
246255
filters = {}
247256
filters = self._unwrap_filters(model_obj, filters)
@@ -250,7 +259,7 @@ def search(self, model_obj, filters=None, with_entities=None):
250259
res.with_entities(*self._create_entities(
251260
model_obj, with_entities
252261
))
253-
return res
262+
return res
254263

255264
def create(self, model_obj, vals):
256265
""" Wrapper to create a record in Carepoint
@@ -260,10 +269,10 @@ def create(self, model_obj, vals):
260269
:type vals: dict
261270
:rtype: :class:`sqlalchemy.ext.declarative.Declarative`
262271
"""
263-
with self._get_session(model_obj) as session:
272+
with self._get_model_session(model_obj) as session:
264273
record = model_obj(**vals)
265274
session.add(record)
266-
return record
275+
return record
267276

268277
def update(self, model_obj, record_id, vals):
269278
""" Wrapper to update a record in Carepoint
@@ -275,11 +284,11 @@ def update(self, model_obj, record_id, vals):
275284
:type vals: dict
276285
:rtype: :class:`sqlalchemy.ext.declarative.Declarative`
277286
"""
278-
with self._get_session(model_obj) as session:
287+
with self._get_model_session(model_obj) as session:
279288
record = self.read(model_obj, record_id)
280289
for key, val in vals.items():
281290
setattr(record, key, val)
282-
return record
291+
return record
283292

284293
def delete(self, model_obj, record_id):
285294
""" Wrapper to delete a record in Carepoint
@@ -290,7 +299,7 @@ def delete(self, model_obj, record_id):
290299
:return: Whether the record was found, and deleted
291300
:rtype: bool
292301
"""
293-
with self._get_session(model_obj) as session:
302+
with self._get_model_session(model_obj) as session:
294303
record = self.read(model_obj, record_id)
295304
result_cnt = record.count()
296305
if result_cnt == 0:
@@ -308,17 +317,16 @@ def get_pks(self, model_obj):
308317
"""
309318
return tuple(k.name for k in inspect(model_obj).primary_key)
310319

311-
def get_next_sequence(self, sequence_name):
320+
def get_next_sequence(self, sequence_name, db_name='cph'):
312321
""" It generates and returns the next int in sequence
313322
Params:
314323
sequence_name: ``str`` Name of the sequence in Carepoint DB
324+
db_name: ``str`` Name of DB containing sequence stored proc
315325
Return:
316326
Integer to use as pk
317327
"""
318-
conn = self.dbs['cph'].connect()
319-
trans = conn.begin()
320-
try:
321-
res = conn.execute(
328+
with self._get_session(db_name) as session:
329+
res = session.execute(
322330
text(
323331
"SET NOCOUNT ON;"
324332
"DECLARE @out int = 0;"
@@ -330,13 +338,7 @@ def get_next_sequence(self, sequence_name):
330338
seq_name=sequence_name,
331339
)
332340
id_int = res.fetchall()[0][0]
333-
trans.commit()
334-
except:
335-
trans.rollback()
336-
raise
337-
finally:
338-
conn.close()
339-
return id_int
341+
return id_int
340342

341343
def __getattr__(self, key):
342344
""" Re-implement __getattr__ to use __getitem__ if attr not found """

carepoint/tests/db/test_carepoint.py

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def __get_model_obj(self):
3737

3838
@contextmanager
3939
def __get_mock_session(self, unwrapped=True):
40-
with mock.patch.object(self.carepoint, '_get_session') as mk:
40+
with mock.patch.object(self.carepoint, '_get_model_session') as mk:
4141
enter, session = mock.MagicMock(), mock.MagicMock()
4242
enter.return_value = enter
4343
mk.return_value = session
@@ -107,47 +107,47 @@ def test_model_methods(self):
107107
# Test the session handler
108108
#
109109

110-
def test_get_session_gets_session(self):
110+
def test_get_model_session_gets_session(self):
111111
""" It should get session for the database """
112112
model_obj = self.__get_model_obj()
113113
with mock.patch.object(self.carepoint, 'env') as env:
114-
with self.carepoint._get_session(model_obj):
114+
with self.carepoint._get_model_session(model_obj):
115115
pass
116116
env[model_obj.__dbname__].assert_called_once_with()
117117

118-
def test_get_session_yields_session(self):
118+
def test_get_model_session_yields_session(self):
119119
""" It should yield session for the database """
120120
model_obj = self.__get_model_obj()
121121
with mock.patch.object(self.carepoint, 'env') as env:
122-
with self.carepoint._get_session(model_obj) as res:
122+
with self.carepoint._get_model_session(model_obj) as res:
123123
self.assertEqual(
124124
env[model_obj.__dbname__](),
125125
res,
126126
)
127127

128-
def test_get_session_commit(self):
128+
def test_get_model_session_commit(self):
129129
""" It should commit session after yield """
130130
model_obj = self.__get_model_obj()
131131
with mock.patch.object(self.carepoint, 'env') as env:
132-
with self.carepoint._get_session(model_obj):
132+
with self.carepoint._get_model_session(model_obj):
133133
pass
134134
env[model_obj.__dbname__]().commit.assert_called_once_with()
135135

136-
def test_get_session_rollback(self):
136+
def test_get_model_session_rollback(self):
137137
""" It should roll session back on error """
138138
model_obj = self.__get_model_obj()
139139
with mock.patch.object(self.carepoint, 'env') as env:
140140
env[model_obj.__dbname__]().commit.side_effect = EndTestException
141141
with self.assertRaises(EndTestException):
142-
with self.carepoint._get_session(model_obj):
142+
with self.carepoint._get_model_session(model_obj):
143143
pass
144144
env[model_obj.__dbname__]().rollback.assert_called_once_with()
145145

146-
def test_get_session_close(self):
146+
def test_get_model_session_close(self):
147147
""" It should always close session """
148148
model_obj = self.__get_model_obj()
149149
with mock.patch.object(self.carepoint, 'env') as env:
150-
with self.carepoint._get_session(model_obj):
150+
with self.carepoint._get_model_session(model_obj):
151151
pass
152152
env[model_obj.__dbname__]().close.assert_called_once_with()
153153

@@ -279,66 +279,35 @@ def test_search_returns_response(self):
279279
)
280280

281281
# Get Next Sequence
282-
def test_get_next_sequence_connect(self):
283-
""" It should establish connection to underlying DB """
284-
with mock.patch.object(self.carepoint, 'dbs') as dbs:
285-
self.carepoint.get_next_sequence(None)
286-
dbs['cph'].connect.assert_called_once_with()
287-
288-
def test_get_next_sequence_transaction(self):
289-
""" It should create a new transaction """
290-
with mock.patch.object(self.carepoint, 'dbs') as dbs:
291-
self.carepoint.get_next_sequence(None)
292-
dbs['cph'].connect().begin.assert_called_once_with()
282+
283+
def test_get_next_sequence_session(self):
284+
""" It should get session for db """
285+
expect = 'expect'
286+
with mock.patch.object(self.carepoint, '_get_session') as mk:
287+
res = self.carepoint.get_next_sequence(None, expect)
288+
mk.assert_called_once_with(expect)
293289

294290
@mock.patch('carepoint.db.carepoint.text')
295291
def test_get_next_sequence_execute(self, text):
296292
""" It should execute stored procedure on connection """
297293
expect = 'expect'
298-
with mock.patch.object(self.carepoint, 'dbs') as dbs:
294+
with mock.patch.object(self.carepoint, '_get_session') as mk:
299295
self.carepoint.get_next_sequence(expect)
300-
dbs['cph'].connect().execute.assert_called_once_with(
296+
mk().__enter__().execute.assert_called_once_with(
301297
text(), seq_name=expect,
302298
)
303299

304300
def test_get_next_sequence_fetch(self):
305301
""" It should return result of fetch """
306-
with mock.patch.object(self.carepoint, 'dbs') as dbs:
302+
with mock.patch.object(self.carepoint, '_get_session') as mk:
307303
res = self.carepoint.get_next_sequence(None)
308-
expect = dbs['cph'].connect().execute().fetchall()[0][0]
304+
expect = mk().__enter__().execute().fetchall()[0][0]
309305
self.assertEqual(
310306
expect, res,
311307
)
312308

313-
def test_get_next_sequence_commit(self):
314-
""" It should commit the transaction """
315-
with mock.patch.object(self.carepoint, 'dbs') as dbs:
316-
self.carepoint.get_next_sequence(None)
317-
dbs['cph'].connect().begin().commit.assert_called_once_with()
318-
319-
def test_get_next_sequence_transaction(self):
320-
""" It should create a new transaction """
321-
with mock.patch.object(self.carepoint, 'dbs') as dbs:
322-
self.carepoint.get_next_sequence(None)
323-
dbs['cph'].connect().begin.assert_called_once_with()
324-
325-
def test_get_next_sequence_rollback(self):
326-
""" It should rollback transaction and raise on error """
327-
with mock.patch.object(self.carepoint, 'dbs') as dbs:
328-
conn = dbs['cph'].connect()
329-
conn.execute.side_effect = EndTestException
330-
with self.assertRaises(EndTestException):
331-
self.carepoint.get_next_sequence(None)
332-
conn.begin().rollback.assert_called_once_with()
333-
334-
def test_get_next_sequence_close(self):
335-
""" It should close the connection """
336-
with mock.patch.object(self.carepoint, 'dbs') as dbs:
337-
self.carepoint.get_next_sequence(None)
338-
dbs['cph'].connect().close.assert_called_once_with()
339-
340309
# Create
341-
def test_create_calls_get_session_with_model_obj(self):
310+
def test_create_calls_get_model_session_with_model_obj(self):
342311
model_obj = mock.MagicMock()
343312
with self.__get_mock_session(False) as mk:
344313
self.carepoint.create(model_obj, {})
@@ -370,7 +339,7 @@ def test_create_returns_new_record(self):
370339
self.assertEqual(response, response_expect)
371340

372341
# Update
373-
def test_update_calls_get_session_with_model_obj(self):
342+
def test_update_calls_get_model_session_with_model_obj(self):
374343
model_obj = self.__get_model_obj()
375344
record_id = 1
376345
with self.__get_mock_session(False) as mk:
@@ -413,7 +382,7 @@ def test_update_returns_record(self):
413382
self.assertEqual(read(), response)
414383

415384
# Delete
416-
def test_delete_calls_get_session_with_model_obj(self):
385+
def test_delete_calls_get_model_session_with_model_obj(self):
417386
model_obj = self.__get_model_obj()
418387
record_id = 1
419388
with self.__get_mock_session(False) as mk:

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99

1010
setup_vals = {
1111
'name': 'carepoint',
12-
'version': '0.1.3',
12+
'version': '0.1.4',
1313
'author': 'LasLabs Inc.',
1414
'author_email': 'support@laslabs.com',
15-
'description': 'This library will allow you to interact with CarePoint'
15+
'description': 'This library will allow you to interact with CarePoint '
1616
'using Python.',
1717
'url': 'https://github.com/laslabs/python-carepoint',
1818
'license': 'MIT',

0 commit comments

Comments
 (0)