Issue 33249: Unpickling objects with recursive references and partials fail due to incomplete state passed to setstate (original) (raw)
The code below causes a
AttributeError: 'Event' object has no attribute 'name'
It seems like the entries of Machine.events
are not available during __setstate__
. However, the behaviour depends on the Python version.
For Python 3.6.4 it's always the 'first' (as in it's always 'to_A' which has been added first) element in Machine.events
that is incomplete. For Python 3.4.8 and 3.5.5 it looks like a racing condition since sometimes there is no error, sometimes its the first or the second element which is incomplete.
Letting Machine
serve as its own model and pickling that does work for all three versions.
Tested on MacOS High Sierra.
import pickle
from functools import partial
class Event:
def __init__(self, name, machine):
self.name = name
self.machine = machine
def trigger(self):
pass
class Machine:
def __init__(self, model, states):
self.events = {}
self.model = model if model != 'self' else self
for state in states:
trigger = 'to_%s' % state
self.events[trigger] = Event(trigger, self)
trig_func = partial(self.events[trigger].trigger)
setattr(self.model, trigger, trig_func)
def __getstate__(self):
return self.__dict__
def __setstate__(self, state):
self.__dict__.update(state)
print(self.events['to_B'].name)
print(self.events['to_A'].name)
class Model:
def __init__(self):
self.machine = Machine(self, states=['A', 'B'])
model = Model()
dump = pickle.dumps(model)
model2 = pickle.loads(dump)