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__()

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__()

Return the answer to life the universe and everything.         Would normally break pickles prior to the introduction of new_attr. # downgrade to lower version # breaks old pickles! # check to see if automatic upgrade works