Skip to content

Commit b8db156

Browse files
committed
apply @brondsem patch, update now resets state.original_document
1 parent 25c2982 commit b8db156

File tree

5 files changed

+33
-11
lines changed

5 files changed

+33
-11
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ parsetab_*
2323
.tox
2424
.eggs/
2525
venv/
26+
.\#*
27+
\#*\#

ming/odm/mapper.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ def update(self, obj, state, session, **kwargs):
8787
doc = self.collection(state.document, skip_from_bson=True)
8888
ret = session.impl.save(doc, validate=False, state=state)
8989
state.status = state.clean
90+
# Make sure that st.document is never the same as st.original_document
91+
# otherwise mutating one mutates the other.
92+
state.original_document = deepcopy(doc)
9093
return ret
9194

9295
@_with_hooks('delete')
@@ -183,8 +186,6 @@ def _from_doc(self, doc, options, validate=True):
183186

184187
# Make sure that st.document is never the same as st.original_document
185188
# otherwise mutating one mutates the other.
186-
# There is no need to deepcopy as nested mutable objects are already
187-
# copied by InstrumentedList and InstrumentedObj to instrument them.
188189
st.original_document = deepcopy(doc)
189190

190191
if validate is False:

ming/session.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
log = logging.getLogger(__name__)
1616

17+
1718
def annotate_doc_failure(func):
1819
'''Decorator to wrap a session operation so that any pymongo errors raised
1920
will note the document that caused the failure
@@ -30,7 +31,7 @@ def wrapper(self, doc, *args, **kwargs):
3031
return update_wrapper(wrapper, func)
3132

3233

33-
class Session(object):
34+
class Session:
3435
_registry = {}
3536
_datastores = {}
3637

@@ -152,15 +153,13 @@ def _prep_save(self, doc, validate):
152153
return data
153154

154155
@annotate_doc_failure
155-
def save(self, doc, state=None, **kwargs):
156-
# args was meant to be the list of changed fields
157-
# but actually we ended up checking the differences here
156+
def save(self, doc, *args, state=None, **kwargs):
158157
data = self._prep_save(doc, kwargs.pop('validate', True))
159-
if state is not None and state.original_document:
160-
if state is not None:
161-
args = tuple(set((k for k, v in
162-
doc_to_set(state.original_document)
163-
^ doc_to_set(data))))
158+
if not args and state is not None and state.original_document:
159+
args = tuple(set((k for k, v in
160+
doc_to_set(state.original_document)
161+
^ doc_to_set(data))))
162+
if args:
164163
values = dict((arg, data[arg]) for arg in args)
165164
result = self._impl(doc).update(
166165
dict(_id=doc._id), {'$set': values}, **fix_write_concern(kwargs))

ming/tests/odm/test_mapper.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,23 @@ def test_group(self, pymongo_group):
277277
self.Basic.query.group()
278278
assert pymongo_group.called
279279

280+
def test_multiple_update_flushes(self):
281+
initial_doc = self.Basic()
282+
initial_doc.a = 1
283+
self.session.flush()
284+
self.session.close()
285+
286+
doc_updating = self.Basic.query.get(_id=initial_doc._id)
287+
doc_updating.a = 2
288+
self.session.flush()
289+
doc_updating.a = 1 # back to "initial" value
290+
doc_updating.e = 'foo' # change something else too
291+
self.session.flush()
292+
self.session.close()
293+
294+
doc_after_updates = self.Basic.query.get(_id=doc_updating._id)
295+
assert doc_after_updates.a == 1
296+
280297

281298
class TestRelation(TestCase):
282299
def setUp(self):

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
[pylint]
2+
# disabling protected-access because of mongodb _id property
3+
disable = protected-access
14

25
[nosetests]
36
detailed-errors=1

0 commit comments

Comments
 (0)