Skip to content

Commit dd01bf0

Browse files
author
Don Mitchell
committed
Don't unnecessarily copy the key list
1 parent 2d4761a commit dd01bf0

File tree

3 files changed

+61
-7
lines changed

3 files changed

+61
-7
lines changed

bson/son.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,20 @@ def copy(self):
110110
# efficient.
111111
# second level definitions support higher levels
112112
def __iter__(self):
113-
for k in self.keys():
113+
"""
114+
Cannot remove nor add keys while iterating
115+
"""
116+
key_len = len(self.__keys)
117+
for k in self.__keys:
118+
if len(self.__keys) != key_len:
119+
raise RuntimeError("son changed length during iteration")
114120
yield k
115121

116122
def has_key(self, key):
117-
return key in self.keys()
123+
return key in self.__keys
118124

119125
def __contains__(self, key):
120-
return key in self.keys()
126+
return key in self.__keys
121127

122128
# third level takes advantage of second level definitions
123129
def iteritems(self):
@@ -139,8 +145,8 @@ def items(self):
139145
return [(key, self[key]) for key in self]
140146

141147
def clear(self):
142-
for key in self.keys():
143-
del self[key]
148+
self.__keys = []
149+
super(SON, self).clear()
144150

145151
def setdefault(self, key, default=None):
146152
try:
@@ -204,7 +210,7 @@ def __ne__(self, other):
204210
return not self == other
205211

206212
def __len__(self):
207-
return len(self.keys())
213+
return len(self.__keys)
208214

209215
def to_dict(self):
210216
"""Convert a SON document to a normal Python dictionary instance.

doc/contributors.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ The following is a list of people who have contributed to
5353
- Samuel Clay (samuelclay)
5454
- Ross Lawley (rozza)
5555
- Wouter Bolsterlee (wbolster)
56-
- Alex Grönholm (agronholm)
56+
- Alex Gr��nholm (agronholm)
5757
- Christoph Simon (kalanzun)
5858
- Chris Tompkinson (tompko)
5959
- Mike O'Brien (mpobrien)
6060
- T Dampier (dampier)
6161
- Michael Henson (hensom)
62+
- Don Mitchell (dmitchell)

test/test_son.py

+47
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,52 @@ def test_pickle_backwards_compatability(self):
111111
son_2_1_1 = pickle.loads(pickled_with_2_1_1)
112112
self.assertEqual(son_2_1_1, SON([]))
113113

114+
def test_iteration(self):
115+
"""
116+
Test __iter__
117+
"""
118+
# test success case
119+
test_son = SON([(1, 100), (2, 200), (3, 300)])
120+
for ele in test_son:
121+
self.assertEqual(ele * 100, test_son[ele])
122+
# test failure case
123+
def break_iter():
124+
for ele in test_son:
125+
del test_son[ele]
126+
self.assertRaises(RuntimeError, break_iter)
127+
128+
def test_contains_has(self):
129+
"""
130+
has_key and __contains__
131+
"""
132+
test_son = SON([(1, 100), (2, 200), (3, 300)])
133+
self.assertIn(1, test_son)
134+
self.assertTrue(2 in test_son, "in failed")
135+
self.assertFalse(22 in test_son, "in succeeded when it shouldn't")
136+
self.assertTrue(test_son.has_key(2), "has_key failed")
137+
self.assertFalse(test_son.has_key(22), "has_key succeeded when it shouldn't")
138+
139+
def test_clears(self):
140+
"""
141+
Test clear()
142+
"""
143+
test_son = SON([(1, 100), (2, 200), (3, 300)])
144+
test_son.clear()
145+
self.assertNotIn(1, test_son)
146+
self.assertEqual(0, len(test_son))
147+
self.assertEqual(0, len(test_son.keys()))
148+
self.assertEqual({}, test_son.to_dict())
149+
150+
def test_len(self):
151+
"""
152+
Test len
153+
"""
154+
test_son = SON()
155+
self.assertEqual(0, len(test_son))
156+
test_son = SON([(1, 100), (2, 200), (3, 300)])
157+
self.assertEqual(3, len(test_son))
158+
test_son.popitem()
159+
self.assertEqual(2, len(test_son))
160+
114161
if __name__ == "__main__":
115162
unittest.main()

0 commit comments

Comments
 (0)