Skip to content

Commit 2c2d322

Browse files
committed
SF patch #667730: More DictMixin
* Adds missing pop() methods to weakref.py * Expands test suite to broaden coverage of objects with a mapping interface. Contributed by Sebastien Keim.
1 parent 42182eb commit 2c2d322

File tree

6 files changed

+222
-4
lines changed

6 files changed

+222
-4
lines changed

Lib/test/test_os.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,28 @@ def test_statvfs_attributes(self):
185185
except TypeError:
186186
pass
187187

188+
from test_userdict import TestMappingProtocol
189+
190+
class EnvironTests(TestMappingProtocol):
191+
"""check that os.environ object conform to mapping protocol"""
192+
_tested_class = None
193+
def _reference(self):
194+
return {"KEY1":"VALUE1", "KEY2":"VALUE2", "KEY3":"VALUE3"}
195+
def _empty_mapping(self):
196+
os.environ.clear()
197+
return os.environ
198+
def setUp(self):
199+
self.__save = dict(os.environ)
200+
os.environ.clear()
201+
def tearDown(self):
202+
os.environ.clear()
203+
os.environ.update(self.__save)
204+
188205
def test_main():
189206
suite = unittest.TestSuite()
190207
suite.addTest(unittest.makeSuite(TemporaryFileTests))
191208
suite.addTest(unittest.makeSuite(StatAttributeTests))
209+
suite.addTest(unittest.makeSuite(EnvironTests))
192210
run_suite(suite)
193211

194212
if __name__ == "__main__":

Lib/test/test_shelve.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,54 @@ def test_in_memory_shelf(self):
4343
self.assertEqual(len(d1), 1)
4444
self.assertNotEqual(d1, d2)
4545

46-
def test_main():
47-
test_support.run_unittest(TestCase)
46+
from test_userdict import TestMappingProtocol
4847

48+
class TestShelveBase(TestMappingProtocol):
49+
fn = "shelftemp.db"
50+
counter = 0
51+
def __init__(self, *args, **kw):
52+
self._db = []
53+
TestMappingProtocol.__init__(self, *args, **kw)
54+
_tested_class = shelve.Shelf
55+
def _reference(self):
56+
return {"key1":"value1", "key2":2, "key3":(1,2,3)}
57+
def _empty_mapping(self):
58+
if self._in_mem:
59+
x= shelve.Shelf({}, binary = self._binary)
60+
else:
61+
self.counter+=1
62+
x= shelve.open(self.fn+str(self.counter), binary=self._binary)
63+
self._db.append(x)
64+
return x
65+
def tearDown(self):
66+
for db in self._db:
67+
db.close()
68+
self._db = []
69+
if not self._in_mem:
70+
for f in glob.glob(self.fn+"*"):
71+
os.unlink(f)
72+
73+
class TestAsciiFileShelve(TestShelveBase):
74+
_binary = False
75+
_in_mem = False
76+
class TestBinaryFileShelve(TestShelveBase):
77+
_binary = True
78+
_in_mem = False
79+
class TestAsciiMemShelve(TestShelveBase):
80+
_binary = False
81+
_in_mem = True
82+
class TestBinaryMemShelve(TestShelveBase):
83+
_binary = True
84+
_in_mem = True
85+
86+
def test_main():
87+
suite = unittest.TestSuite()
88+
suite.addTest(unittest.makeSuite(TestAsciiFileShelve))
89+
suite.addTest(unittest.makeSuite(TestBinaryFileShelve))
90+
suite.addTest(unittest.makeSuite(TestAsciiMemShelve))
91+
suite.addTest(unittest.makeSuite(TestBinaryMemShelve))
92+
suite.addTest(unittest.makeSuite(TestCase))
93+
test_support.run_suite(suite)
4994

5095
if __name__ == "__main__":
5196
test_main()

Lib/test/test_userdict.py

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,133 @@
44

55
import UserDict
66

7+
class TestMappingProtocol(unittest.TestCase):
8+
# This base class can be used to check that an object conforms to the
9+
# mapping protocol
10+
11+
# Functions that can be useful to override to adapt to dictionary
12+
# semantics
13+
_tested_class = dict # which class is being tested
14+
15+
def _reference(self):
16+
"""Return a dictionary of values which are invariant by storage
17+
in the object under test."""
18+
return {1:2, "key1":"value1", "key2":(1,2,3)}
19+
def _empty_mapping(self):
20+
"""Return an empty mapping object"""
21+
return self._tested_class()
22+
def _full_mapping(self, data):
23+
"""Return a mapping object with the value contained in data
24+
dictionary"""
25+
x = self._empty_mapping()
26+
for key, value in data.items():
27+
x[key] = value
28+
return x
29+
30+
def __init__(self, *args, **kw):
31+
unittest.TestCase.__init__(self, *args, **kw)
32+
self.reference = self._reference().copy()
33+
key, value = self.reference.popitem()
34+
self.other = {key:value}
35+
36+
def test_read(self):
37+
# Test for read only operations on mapping
38+
p = self._empty_mapping()
39+
p1 = dict(p) #workaround for singleton objects
40+
d = self._full_mapping(self.reference)
41+
if d is p:
42+
p = p1
43+
#Indexing
44+
for key, value in self.reference.items():
45+
self.assertEqual(d[key], value)
46+
knownkey = self.other.keys()[0]
47+
self.failUnlessRaises(KeyError, lambda:d[knownkey])
48+
#len
49+
self.assertEqual(len(p), 0)
50+
self.assertEqual(len(d), len(self.reference))
51+
#has_key
52+
for k in self.reference:
53+
self.assert_(d.has_key(k))
54+
self.assert_(k in d)
55+
for k in self.other:
56+
self.failIf(d.has_key(k))
57+
self.failIf(k in d)
58+
#cmp
59+
self.assertEqual(cmp(p,p), 0)
60+
self.assertEqual(cmp(d,d), 0)
61+
self.assertEqual(cmp(p,d), -1)
62+
self.assertEqual(cmp(d,p), 1)
63+
#__non__zero__
64+
if p: self.fail("Empty mapping must compare to False")
65+
if not d: self.fail("Full mapping must compare to True")
66+
# keys(), items(), iterkeys() ...
67+
def check_iterandlist(iter, lst, ref):
68+
self.assert_(hasattr(iter, 'next'))
69+
self.assert_(hasattr(iter, '__iter__'))
70+
x = list(iter)
71+
x.sort()
72+
lst.sort()
73+
ref.sort()
74+
self.assert_(x==lst==ref)
75+
check_iterandlist(d.iterkeys(), d.keys(), self.reference.keys())
76+
check_iterandlist(iter(d), d.keys(), self.reference.keys())
77+
check_iterandlist(d.itervalues(), d.values(), self.reference.values())
78+
check_iterandlist(d.iteritems(), d.items(), self.reference.items())
79+
#get
80+
key, value = d.iteritems().next()
81+
knownkey, knownvalue = self.other.iteritems().next()
82+
self.assertEqual(d.get(key, knownvalue), value)
83+
self.assertEqual(d.get(knownkey, knownvalue), knownvalue)
84+
self.failIf(knownkey in d)
85+
86+
def test_write(self):
87+
# Test for write operations on mapping
88+
p = self._empty_mapping()
89+
#Indexing
90+
for key, value in self.reference.items():
91+
p[key] = value
92+
self.assertEqual(p[key], value)
93+
for key in self.reference.keys():
94+
del p[key]
95+
self.failUnlessRaises(KeyError, lambda:p[key])
96+
p = self._empty_mapping()
97+
#update
98+
p.update(self.reference)
99+
self.assertEqual(dict(p), self.reference)
100+
d = self._full_mapping(self.reference)
101+
#setdefaullt
102+
key, value = d.iteritems().next()
103+
knownkey, knownvalue = self.other.iteritems().next()
104+
self.assertEqual(d.setdefault(key, knownvalue), value)
105+
self.assertEqual(d[key], value)
106+
self.assertEqual(d.setdefault(knownkey, knownvalue), knownvalue)
107+
self.assertEqual(d[knownkey], knownvalue)
108+
#pop
109+
self.assertEqual(d.pop(knownkey), knownvalue)
110+
self.failIf(knownkey in d)
111+
self.assertRaises(KeyError, d.pop, knownkey)
112+
default = 909
113+
d[knownkey] = knownvalue
114+
self.assertEqual(d.pop(knownkey, default), knownvalue)
115+
self.failIf(knownkey in d)
116+
self.assertEqual(d.pop(knownkey, default), default)
117+
#popitem
118+
key, value = d.popitem()
119+
self.failIf(key in d)
120+
self.assertEqual(value, self.reference[key])
121+
p=self._empty_mapping()
122+
self.assertRaises(KeyError, p.popitem)
123+
7124
d0 = {}
8125
d1 = {"one": 1}
9126
d2 = {"one": 1, "two": 2}
10127
d3 = {"one": 1, "two": 3, "three": 5}
11128
d4 = {"one": None, "two": None}
12129
d5 = {"one": 1, "two": 1}
13130

14-
class UserDictTest(unittest.TestCase):
131+
class UserDictTest(TestMappingProtocol):
132+
_tested_class = UserDict.IterableUserDict
133+
15134
def test_all(self):
16135
# Test constructors
17136
u = UserDict.UserDict()
@@ -182,7 +301,9 @@ def __delitem__(self, key):
182301
def keys(self):
183302
return list(self.keylist)
184303

185-
class UserDictMixinTest(unittest.TestCase):
304+
class UserDictMixinTest(TestMappingProtocol):
305+
_tested_class = SeqDict
306+
186307
def test_all(self):
187308
## Setup test and verify working of the test class
188309

@@ -275,6 +396,7 @@ def test_all(self):
275396

276397
def test_main():
277398
suite = unittest.TestSuite()
399+
suite.addTest(unittest.makeSuite(TestMappingProtocol))
278400
suite.addTest(unittest.makeSuite(UserDictTest))
279401
suite.addTest(unittest.makeSuite(UserDictMixinTest))
280402
test.test_support.run_suite(suite)

Lib/test/test_weakref.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,11 +517,28 @@ def test_weak_valued_delitem(self):
517517
self.assert_(len(d) == 1)
518518
self.assert_(d.items() == [('something else', o2)])
519519

520+
from test_userdict import TestMappingProtocol
521+
522+
class WeakValueDictionaryTestCase(TestMappingProtocol):
523+
"""Check that WeakValueDictionary class conforms to the mapping protocol"""
524+
__ref = {"key1":Object(1), "key2":Object(2), "key3":Object(3)}
525+
_tested_class = weakref.WeakValueDictionary
526+
def _reference(self):
527+
return self.__ref.copy()
528+
529+
class WeakKeyDictionaryTestCase(TestMappingProtocol):
530+
"""Check that WeakKeyDictionary class conforms to the mapping protocol"""
531+
__ref = {Object("key1"):1, Object("key2"):2, Object("key3"):3}
532+
_tested_class = weakref.WeakKeyDictionary
533+
def _reference(self):
534+
return self.__ref.copy()
520535

521536
def test_main():
522537
suite = unittest.TestSuite()
523538
suite.addTest(unittest.makeSuite(ReferencesTestCase))
524539
suite.addTest(unittest.makeSuite(MappingTestCase))
540+
suite.addTest(unittest.makeSuite(WeakValueDictionaryTestCase))
541+
suite.addTest(unittest.makeSuite(WeakKeyDictionaryTestCase))
525542
test_support.run_suite(suite)
526543

527544

Lib/weakref.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,18 @@ def popitem(self):
101101
if o is not None:
102102
return key, o
103103

104+
def pop(self, key, *args):
105+
try:
106+
o = self.data.pop(key)()
107+
except KeyError:
108+
if args:
109+
return args[0]
110+
raise
111+
if o is None:
112+
raise KeyError, key
113+
else:
114+
return o
115+
104116
def setdefault(self, key, default):
105117
try:
106118
wr = self.data[key]
@@ -225,6 +237,9 @@ def popitem(self):
225237
if o is not None:
226238
return o, value
227239

240+
def pop(self, key, *args):
241+
return self.data.pop(ref(key), *args)
242+
228243
def setdefault(self, key, default):
229244
return self.data.setdefault(ref(key, self._remove),default)
230245

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ Bob Kahn
281281
Tamito Kajiyama
282282
Jacob Kaplan-Moss
283283
Lou Kates
284+
Sebastien Keim
284285
Randall Kern
285286
Robert Kern
286287
Magnus Kessler

0 commit comments

Comments
 (0)