Skip to content

Commit e904f01

Browse files
committed
PYTHON-709 insert _id in document after applying non-copying SONManipulators.
1 parent 79df8d7 commit e904f01

File tree

3 files changed

+41
-6
lines changed

3 files changed

+41
-6
lines changed

pymongo/collection.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,14 @@ def insert(self, doc_or_docs, manipulate=True,
378378
def gen():
379379
db = self.__database
380380
for doc in docs:
381+
# Apply user-configured SON manipulators. This order of
382+
# operations is required for backwards compatibility,
383+
# see PYTHON-709.
384+
doc = db._apply_incoming_manipulators(doc, self)
381385
if '_id' not in doc:
382386
doc['_id'] = ObjectId()
383387

384-
# Apply user-configured SON manipulators.
385-
doc = db._fix_incoming(doc, self)
388+
doc = db._apply_incoming_copying_manipulators(doc, self)
386389
ids.append(doc['_id'])
387390
yield doc
388391
else:

pymongo/database.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,17 +247,25 @@ def create_collection(self, name, **kwargs):
247247

248248
return Collection(self, name, **opts)
249249

250+
def _apply_incoming_manipulators(self, son, collection):
251+
for manipulator in self.__incoming_manipulators:
252+
son = manipulator.transform_incoming(son, collection)
253+
return son
254+
255+
def _apply_incoming_copying_manipulators(self, son, collection):
256+
for manipulator in self.__incoming_copying_manipulators:
257+
son = manipulator.transform_incoming(son, collection)
258+
return son
259+
250260
def _fix_incoming(self, son, collection):
251261
"""Apply manipulators to an incoming SON object before it gets stored.
252262
253263
:Parameters:
254264
- `son`: the son object going into the database
255265
- `collection`: the collection the son object is being saved in
256266
"""
257-
for manipulator in self.__incoming_manipulators:
258-
son = manipulator.transform_incoming(son, collection)
259-
for manipulator in self.__incoming_copying_manipulators:
260-
son = manipulator.transform_incoming(son, collection)
267+
son = self._apply_incoming_manipulators(son, collection)
268+
son = self._apply_incoming_copying_manipulators(son, collection)
261269
return son
262270

263271
def _fix_outgoing(self, son, collection):

test/test_database.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
OperationFailure)
4646
from pymongo.son_manipulator import (AutoReference,
4747
NamespaceInjector,
48+
SONManipulator,
4849
ObjectIdShuffler)
4950
from test import version
5051
from test.utils import (catch_warnings, get_command_line,
@@ -996,6 +997,29 @@ def test_command_max_time_ms(self):
996997
"maxTimeAlwaysTimeOut",
997998
mode="off")
998999

1000+
def test_object_to_dict_transformer(self):
1001+
# PYTHON-709: Some users rely on their custom SONManipulators to run
1002+
# before any other checks, so they can insert non-dict objects and
1003+
# have them dictified before the _id is inserted or any other
1004+
# processing.
1005+
class Thing(object):
1006+
def __init__(self, value):
1007+
self.value = value
1008+
1009+
class ThingTransformer(SONManipulator):
1010+
def transform_incoming(self, thing, collection):
1011+
return {'value': thing.value}
1012+
1013+
db = self.client.foo
1014+
db.add_son_manipulator(ThingTransformer())
1015+
t = Thing('value')
1016+
1017+
db.test.remove()
1018+
db.test.insert([t])
1019+
out = db.test.find_one()
1020+
self.assertEqual('value', out.get('value'))
1021+
1022+
9991023

10001024
if __name__ == "__main__":
10011025
unittest.main()

0 commit comments

Comments
 (0)