Skip to content

Commit 79c3208

Browse files
committed
Change shelve to require a bytes-oriented dict as
the underlying storage, and yet provide string keys.
1 parent 8dfc4a9 commit 79c3208

File tree

2 files changed

+53
-19
lines changed

2 files changed

+53
-19
lines changed

Lib/shelve.py

+18-14
Original file line numberDiff line numberDiff line change
@@ -71,33 +71,36 @@ class Shelf(UserDict.DictMixin):
7171
See the module's __doc__ string for an overview of the interface.
7272
"""
7373

74-
def __init__(self, dict, protocol=None, writeback=False):
74+
def __init__(self, dict, protocol=None, writeback=False,
75+
keyencoding="utf-8"):
7576
self.dict = dict
7677
if protocol is None:
7778
protocol = 0
7879
self._protocol = protocol
7980
self.writeback = writeback
8081
self.cache = {}
82+
self.keyencoding = "utf-8"
8183

8284
def keys(self):
83-
return self.dict.keys()
85+
for k in self.dict.keys():
86+
yield k.decode(self.keyencoding)
8487

8588
def __len__(self):
8689
return len(self.dict)
8790

8891
def __contains__(self, key):
89-
return key in self.dict
92+
return key.encode(self.keyencoding) in self.dict
9093

9194
def get(self, key, default=None):
92-
if key in self.dict:
95+
if key.encode(self.keyencoding) in self.dict:
9396
return self[key]
9497
return default
9598

9699
def __getitem__(self, key):
97100
try:
98101
value = self.cache[key]
99102
except KeyError:
100-
f = BytesIO(self.dict[key])
103+
f = BytesIO(self.dict[key.encode(self.keyencoding)])
101104
value = Unpickler(f).load()
102105
if self.writeback:
103106
self.cache[key] = value
@@ -109,10 +112,10 @@ def __setitem__(self, key, value):
109112
f = BytesIO()
110113
p = Pickler(f, self._protocol)
111114
p.dump(value)
112-
self.dict[key] = f.getvalue()
115+
self.dict[key.encode(self.keyencoding)] = f.getvalue()
113116

114117
def __delitem__(self, key):
115-
del self.dict[key]
118+
del self.dict[key.encode(self.keyencoding)]
116119
try:
117120
del self.cache[key]
118121
except KeyError:
@@ -156,33 +159,34 @@ class BsdDbShelf(Shelf):
156159
See the module's __doc__ string for an overview of the interface.
157160
"""
158161

159-
def __init__(self, dict, protocol=None, writeback=False):
160-
Shelf.__init__(self, dict, protocol, writeback)
162+
def __init__(self, dict, protocol=None, writeback=False,
163+
keyencoding="utf-8"):
164+
Shelf.__init__(self, dict, protocol, writeback, keyencoding)
161165

162166
def set_location(self, key):
163167
(key, value) = self.dict.set_location(key)
164168
f = BytesIO(value)
165-
return (key, Unpickler(f).load())
169+
return (key.decode(self.keyencoding), Unpickler(f).load())
166170

167171
def next(self):
168172
(key, value) = next(self.dict)
169173
f = BytesIO(value)
170-
return (key, Unpickler(f).load())
174+
return (key.decode(self.keyencoding), Unpickler(f).load())
171175

172176
def previous(self):
173177
(key, value) = self.dict.previous()
174178
f = BytesIO(value)
175-
return (key, Unpickler(f).load())
179+
return (key.decode(self.keyencoding), Unpickler(f).load())
176180

177181
def first(self):
178182
(key, value) = self.dict.first()
179183
f = BytesIO(value)
180-
return (key, Unpickler(f).load())
184+
return (key.decode(self.keyencoding), Unpickler(f).load())
181185

182186
def last(self):
183187
(key, value) = self.dict.last()
184188
f = BytesIO(value)
185-
return (key, Unpickler(f).load())
189+
return (key.decode(self.keyencoding), Unpickler(f).load())
186190

187191

188192
class DbfilenameShelf(Shelf):

Lib/test/test_shelve.py

+35-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,36 @@
22
import shelve
33
import glob
44
from test import test_support
5+
from UserDict import DictMixin
6+
7+
def L1(s):
8+
return s.decode("latin-1")
9+
10+
class byteskeydict(DictMixin):
11+
"Mapping that supports bytes keys"
12+
13+
def __init__(self):
14+
self.d = {}
15+
16+
def __getitem__(self, key):
17+
return self.d[L1(key)]
18+
19+
def __setitem__(self, key, value):
20+
self.d[L1(key)] = value
21+
22+
def __delitem__(self, key):
23+
del self.d[L1(key)]
24+
25+
def iterkeys(self):
26+
for k in self.d.keys():
27+
yield k.decode("latin-1")
28+
29+
def keys(self):
30+
return list(self.iterkeys())
31+
32+
def copy(self):
33+
return byteskeydict(self.d)
34+
535

636
class TestCase(unittest.TestCase):
737

@@ -36,12 +66,12 @@ def test_proto2_file_shelf(self):
3666
s.close()
3767

3868
def test_in_memory_shelf(self):
39-
d1 = {}
69+
d1 = byteskeydict()
4070
s = shelve.Shelf(d1, protocol=0)
4171
s['key1'] = (1,2,3,4)
4272
self.assertEqual(s['key1'], (1,2,3,4))
4373
s.close()
44-
d2 = {}
74+
d2 = byteskeydict()
4575
s = shelve.Shelf(d2, protocol=1)
4676
s['key1'] = (1,2,3,4)
4777
self.assertEqual(s['key1'], (1,2,3,4))
@@ -51,15 +81,15 @@ def test_in_memory_shelf(self):
5181
self.assertNotEqual(d1, d2)
5282

5383
def test_mutable_entry(self):
54-
d1 = {}
84+
d1 = byteskeydict()
5585
s = shelve.Shelf(d1, protocol=2, writeback=False)
5686
s['key1'] = [1,2,3,4]
5787
self.assertEqual(s['key1'], [1,2,3,4])
5888
s['key1'].append(5)
5989
self.assertEqual(s['key1'], [1,2,3,4])
6090
s.close()
6191

62-
d2 = {}
92+
d2 = byteskeydict()
6393
s = shelve.Shelf(d2, protocol=2, writeback=True)
6494
s['key1'] = [1,2,3,4]
6595
self.assertEqual(s['key1'], [1,2,3,4])
@@ -84,7 +114,7 @@ def _reference(self):
84114
return {"key1":"value1", "key2":2, "key3":(1,2,3)}
85115
def _empty_mapping(self):
86116
if self._in_mem:
87-
x= shelve.Shelf({}, **self._args)
117+
x= shelve.Shelf(byteskeydict(), **self._args)
88118
else:
89119
self.counter+=1
90120
x= shelve.open(self.fn+str(self.counter), **self._args)

0 commit comments

Comments
 (0)