Ensure deepcopy clones using the correct type - PYTHON-459
This commit is contained in:
parent
2435f8609d
commit
828aad3aad
@ -32,7 +32,7 @@ from bson.max_key import MaxKey
|
||||
from bson.min_key import MinKey
|
||||
from bson.objectid import ObjectId
|
||||
from bson.py3compat import b, binary_type
|
||||
from bson.son import SON
|
||||
from bson.son import SON, RE_TYPE
|
||||
from bson.timestamp import Timestamp
|
||||
from bson.tz_util import utc
|
||||
|
||||
@ -52,9 +52,6 @@ except ImportError:
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
|
||||
# This sort of sucks, but seems to be as good as it gets...
|
||||
RE_TYPE = type(re.compile(""))
|
||||
|
||||
MAX_INT32 = 2147483647
|
||||
MIN_INT32 = -2147483648
|
||||
MAX_INT64 = 9223372036854775807
|
||||
|
||||
12
bson/son.py
12
bson/son.py
@ -19,6 +19,10 @@ of keys is important. A SON object can be used just like a normal Python
|
||||
dictionary."""
|
||||
|
||||
import copy
|
||||
import re
|
||||
|
||||
# This sort of sucks, but seems to be as good as it gets...
|
||||
RE_TYPE = type(re.compile(""))
|
||||
|
||||
|
||||
class SON(dict):
|
||||
@ -227,6 +231,12 @@ class SON(dict):
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
out = SON()
|
||||
val_id = id(self)
|
||||
if val_id in memo:
|
||||
return memo.get(val_id)
|
||||
memo[val_id] = out
|
||||
for k, v in self.iteritems():
|
||||
out[k] = copy.deepcopy(v, memo)
|
||||
if not isinstance(v, RE_TYPE):
|
||||
v = copy.deepcopy(v, memo)
|
||||
out[k] = v
|
||||
return out
|
||||
|
||||
@ -854,7 +854,7 @@ class Cursor(object):
|
||||
return memo.get(val_id)
|
||||
memo[val_id] = y
|
||||
for key, value in x.iteritems():
|
||||
if isinstance(value, dict):
|
||||
if isinstance(value, dict) and not isinstance(value, SON):
|
||||
value = self.__deepcopy(value, memo)
|
||||
elif not isinstance(value, RE_TYPE):
|
||||
value = copy.deepcopy(value, memo)
|
||||
|
||||
@ -24,6 +24,7 @@ sys.path[0:0] = [""]
|
||||
from nose.plugins.skip import SkipTest
|
||||
|
||||
from bson.code import Code
|
||||
from bson.son import SON
|
||||
from pymongo import (ASCENDING,
|
||||
DESCENDING)
|
||||
from pymongo.database import Database
|
||||
@ -522,6 +523,12 @@ class TestCursor(unittest.TestCase):
|
||||
id(cursor2._Cursor__spec))
|
||||
self.assertEqual(len(cursor2._Cursor__spec), 2)
|
||||
|
||||
# Ensure hints are cloned as the correct type
|
||||
cursor = self.db.test.find().hint([('z', 1), ("a", 1)])
|
||||
cursor2 = copy.deepcopy(cursor)
|
||||
self.assertTrue(isinstance(cursor2._Cursor__hint, SON))
|
||||
self.assertEqual(cursor._Cursor__hint, cursor2._Cursor__hint)
|
||||
|
||||
def test_add_remove_option(self):
|
||||
cursor = self.db.test.find()
|
||||
self.assertEqual(0, cursor._Cursor__query_options())
|
||||
|
||||
@ -14,9 +14,11 @@
|
||||
|
||||
"""Tests for the son module."""
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
import copy
|
||||
import pickle
|
||||
import re
|
||||
import sys
|
||||
import unittest
|
||||
sys.path[0:0] = [""]
|
||||
|
||||
from nose.plugins.skip import SkipTest
|
||||
@ -111,5 +113,40 @@ class TestSON(unittest.TestCase):
|
||||
son_2_1_1 = pickle.loads(pickled_with_2_1_1)
|
||||
self.assertEqual(son_2_1_1, SON([]))
|
||||
|
||||
def test_copying(self):
|
||||
simple_son = SON([])
|
||||
complex_son = SON([('son', simple_son),
|
||||
('list', [simple_son, simple_son])])
|
||||
regex_son = SON([("x", re.compile("^hello.*"))])
|
||||
reflexive_son = SON([('son', simple_son)])
|
||||
reflexive_son["reflexive"] = reflexive_son
|
||||
|
||||
simple_son1 = copy.copy(simple_son)
|
||||
self.assertEqual(simple_son, simple_son1)
|
||||
|
||||
complex_son1 = copy.copy(complex_son)
|
||||
self.assertEqual(complex_son, complex_son1)
|
||||
|
||||
regex_son1 = copy.copy(regex_son)
|
||||
self.assertEqual(regex_son, regex_son1)
|
||||
|
||||
reflexive_son1 = copy.copy(reflexive_son)
|
||||
self.assertEqual(reflexive_son, reflexive_son1)
|
||||
|
||||
# Test deepcopying
|
||||
simple_son1 = copy.deepcopy(simple_son)
|
||||
self.assertEqual(simple_son, simple_son1)
|
||||
|
||||
regex_son1 = copy.deepcopy(regex_son)
|
||||
self.assertEqual(regex_son, regex_son1)
|
||||
|
||||
complex_son1 = copy.deepcopy(complex_son)
|
||||
self.assertEqual(complex_son, complex_son1)
|
||||
|
||||
reflexive_son1 = copy.deepcopy(reflexive_son)
|
||||
self.assertEqual(reflexive_son.keys(), reflexive_son1.keys())
|
||||
self.assertEqual(id(reflexive_son1), id(reflexive_son1["reflexive"]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user