diff options
author | Pierre Glaser <pierreglaser@msn.com> | 2019-05-08 19:40:25 (GMT) |
---|---|---|
committer | Antoine Pitrou <antoine@python.org> | 2019-05-08 19:40:25 (GMT) |
commit | 65d98d0f53f558d7c799098da0abf376068c15fd (patch) | |
tree | 4354710a0984cd5afca6e5745309b988d1054213 /Lib/pickle.py | |
parent | 39889864c09741909da4ec489459d0197ea8f1fc (diff) | |
download | cpython-65d98d0f53f558d7c799098da0abf376068c15fd.zip cpython-65d98d0f53f558d7c799098da0abf376068c15fd.tar.gz cpython-65d98d0f53f558d7c799098da0abf376068c15fd.tar.bz2 |
bpo-35900: Add a state_setter arg to save_reduce (GH-12588)
Allow reduction methods to return a 6-item tuple where the 6th item specifies a
custom state-setting method that's called instead of the regular
``__setstate__`` method.
Diffstat (limited to 'Lib/pickle.py')
-rw-r--r-- | Lib/pickle.py | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py index d533e66..47f0d28 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -537,9 +537,9 @@ class _Pickler: # Assert that it returned an appropriately sized tuple l = len(rv) - if not (2 <= l <= 5): + if not (2 <= l <= 6): raise PicklingError("Tuple returned by %s must have " - "two to five elements" % reduce) + "two to six elements" % reduce) # Save the reduce() output and finally memoize the object self.save_reduce(obj=obj, *rv) @@ -561,7 +561,7 @@ class _Pickler: "persistent IDs in protocol 0 must be ASCII strings") def save_reduce(self, func, args, state=None, listitems=None, - dictitems=None, obj=None): + dictitems=None, state_setter=None, obj=None): # This API is called by some subclasses if not isinstance(args, tuple): @@ -655,8 +655,25 @@ class _Pickler: self._batch_setitems(dictitems) if state is not None: - save(state) - write(BUILD) + if state_setter is None: + save(state) + write(BUILD) + else: + # If a state_setter is specified, call it instead of load_build + # to update obj's with its previous state. + # First, push state_setter and its tuple of expected arguments + # (obj, state) onto the stack. + save(state_setter) + save(obj) # simple BINGET opcode as obj is already memoized. + save(state) + write(TUPLE2) + # Trigger a state_setter(obj, state) function call. + write(REDUCE) + # The purpose of state_setter is to carry-out an + # inplace modification of obj. We do not care about what the + # method might return, so its output is eventually removed from + # the stack. + write(POP) # Methods below this point are dispatched through the dispatch table |