import pickle class Upgradable: class_version = '3.0' def __init__(self): self.version = self.__class__.class_version self.new_attr = 42 def pickle(self): return pickle.dumps(self) def new_method(self): ''' Return the answer to life the universe and everything. Would normally break pickles prior to the introduction of new_attr. ''' return self.new_attr @staticmethod def unpickle(data): out = pickle.loads(data) if not hasattr(out, 'version'): out.version = '0.0' if out.version != out.class_version: out.upgrade() return out def upgrade(self): version = float(self.version) print 'upgrade from version %s' % self.version if version < 1.: self.version = '1.0' print 'upgrade to version 1.0' if version < 2.: self.version = '2.0' print 'upgrade to version 2.0' if version < 3.: self.version = '3.0' self.new_attr = 42 print 'upgrade to version 3.0' def __test__(): ug0 = Upgradable() # downgrade to lower version del ug0.version del ug0.new_attr try: # breaks old pickles! ug0.new_method() raise Exception('Should have raised AttributeError!') except AttributeError: pass # check to see if automatic upgrade works ug3 = ug0.unpickle(ug0.pickle()) assert ug3.version == '3.0' assert ug3.new_attr == 42 assert ug3.new_method() == 42 __test__()