summaryrefslogtreecommitdiffstats
path: root/Lib/pickle.py
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2003-01-24 19:29:52 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2003-01-24 19:29:52 (GMT)
commit3422c99de1d1c001ebc1416e3efc1b10452347b5 (patch)
tree1a2ec5eb8d8719c98528b467ecb88032167e17f8 /Lib/pickle.py
parent234d9a9eb390fc0975ca6fe8d010c45642bcdfed (diff)
downloadcpython-3422c99de1d1c001ebc1416e3efc1b10452347b5.zip
cpython-3422c99de1d1c001ebc1416e3efc1b10452347b5.tar.gz
cpython-3422c99de1d1c001ebc1416e3efc1b10452347b5.tar.bz2
Raise PicklingError when __reduce__() fails, and
add memoize() helper function to update the memo. The first element of the tuple returned by __reduce__() must be a callable. If it isn't the Unpickler will raise an error. Catch this error in the pickler and raise the error there. The memoize() helper also has a comment explaining how the memo works. So methods can't use memoize() because the write funny codes.
Diffstat (limited to 'Lib/pickle.py')
-rw-r--r--Lib/pickle.py62
1 files changed, 30 insertions, 32 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py
index a8b2b51..981cfe1 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -167,6 +167,22 @@ class Pickler:
self.save(object)
self.write(STOP)
+ def memoize(self, obj):
+ """Store an object in the memo."""
+
+ # The memo is a dictionary mapping object ids to 2-tuples
+ # that contains the memo value and the object being memoized.
+ # The memo value is written to the pickle and will become
+ # the key in the Unpickler's memo. The object is stored in the
+ # memo so that transient objects are kept alive during pickling.
+
+ # The use of the memo length as the memo value is just a convention.
+ # The only requirement is that the memo values by unique.
+ d = id(obj)
+ memo_len = len(self.memo)
+ self.write(self.put(memo_len))
+ self.memo[d] = memo_len, obj
+
def put(self, i):
if self.bin:
s = mdumps(i)[1:]
@@ -280,11 +296,15 @@ class Pickler:
self.save(pid)
self.write(BINPERSID)
- def save_reduce(self, callable, arg_tup, state = None):
+ def save_reduce(self, acallable, arg_tup, state = None):
write = self.write
save = self.save
- save(callable)
+ if not callable(acallable):
+ raise PicklingError("__reduce__() must return callable as "
+ "first argument, not %s" % `acallable`)
+
+ save(acallable)
save(arg_tup)
write(REDUCE)
@@ -340,9 +360,6 @@ class Pickler:
dispatch[FloatType] = save_float
def save_string(self, object):
- d = id(object)
- memo = self.memo
-
if self.bin:
l = len(object)
s = mdumps(l)[1:]
@@ -352,16 +369,10 @@ class Pickler:
self.write(BINSTRING + s + object)
else:
self.write(STRING + `object` + '\n')
-
- memo_len = len(memo)
- self.write(self.put(memo_len))
- memo[d] = (memo_len, object)
+ self.memoize(object)
dispatch[StringType] = save_string
def save_unicode(self, object):
- d = id(object)
- memo = self.memo
-
if self.bin:
encoding = object.encode('utf-8')
l = len(encoding)
@@ -371,17 +382,12 @@ class Pickler:
object = object.replace("\\", "\\u005c")
object = object.replace("\n", "\\u000a")
self.write(UNICODE + object.encode('raw-unicode-escape') + '\n')
-
- memo_len = len(memo)
- self.write(self.put(memo_len))
- memo[d] = (memo_len, object)
+ self.memoize(object)
dispatch[UnicodeType] = save_unicode
if StringType == UnicodeType:
# This is true for Jython
def save_string(self, object):
- d = id(object)
- memo = self.memo
unicode = object.isunicode()
if self.bin:
@@ -404,14 +410,10 @@ class Pickler:
self.write(UNICODE + object + '\n')
else:
self.write(STRING + `object` + '\n')
-
- memo_len = len(memo)
- self.write(self.put(memo_len))
- memo[d] = (memo_len, object)
+ self.memoize(object)
dispatch[StringType] = save_string
def save_tuple(self, object):
-
write = self.write
save = self.save
memo = self.memo
@@ -434,6 +436,7 @@ class Pickler:
memo_len = len(memo)
self.write(TUPLE + self.put(memo_len))
memo[d] = (memo_len, object)
+
dispatch[TupleType] = save_tuple
def save_empty_tuple(self, object):
@@ -451,9 +454,7 @@ class Pickler:
else:
write(MARK + LIST)
- memo_len = len(memo)
- write(self.put(memo_len))
- memo[d] = (memo_len, object)
+ self.memoize(object)
using_appends = (self.bin and (len(object) > 1))
@@ -471,20 +472,15 @@ class Pickler:
dispatch[ListType] = save_list
def save_dict(self, object):
- d = id(object)
-
write = self.write
save = self.save
- memo = self.memo
if self.bin:
write(EMPTY_DICT)
else:
write(MARK + DICT)
- memo_len = len(memo)
- self.write(self.put(memo_len))
- memo[d] = (memo_len, object)
+ self.memoize(object)
using_setitems = (self.bin and (len(object) > 1))
@@ -529,6 +525,8 @@ class Pickler:
for arg in args:
save(arg)
+ # This method does not use memoize() so that it can handle
+ # the special case for non-binary mode.
memo_len = len(memo)
if self.bin:
write(OBJ + self.put(memo_len))