Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Field values are lost when pickling jsonmodel #121

Open
msvilp opened this issue May 23, 2018 · 2 comments
Open

Field values are lost when pickling jsonmodel #121

msvilp opened this issue May 23, 2018 · 2 comments

Comments

@msvilp
Copy link

msvilp commented May 23, 2018

I found out that using pickle serializer does not seem to work with jsonmodels. Using this simple model as an example (using Python 2.7.10):

class TestModel(models.Base):
    a = fields.StringField(default="")
>>> m = TestModel(a="foo")

>>> m
TestModel(a='foo')

>>> pickle.loads(pickle.dumps(m))
TestModel(a='')

I'm using Python 2.7.10.

So the field value is lost when pickling. I found out that pickle uses __dict__ variable by default, and as this does not contain field data, it is not saved to the serialized form.

Using customized __getstate__() and __setstate__() methods I managed to make it work, I just had to make sure the _cache_key variable is preserved, as unpickling the object does not run __init__() and _cache_key is not created:

class TestModel(models.Base):
    a = fields.StringField(default="")

    def __getstate__(self):
        state = self.to_struct()
        state['_cache_key'] = self._cache_key
        return state

    def __setstate__(self, data):
        self._cache_key = data.pop('_cache_key')
        self.populate(**data)

Does this seem to be a correct way to handle pickling? Also, is it necessary to pickle the _cache_key, or would it be ok to just initialize it to a new value? (Some kind of _init_cache_key() method would be a good addition in that case).

If this is a correct direction, I can make a pull request and test it with other Python versions. Support for JSON serializer would also be possible.

@user706
Copy link

user706 commented Aug 28, 2018

Thanks for the 'getstate()' and 'setstate()' information.

I was using jsonmodels with python multiprocessing Pool.map and had problems with the copying of arguments, because of this very issue (pickle is used in the background).

I'm now using this hack (runtime patching of models.Base):

def getstate(self):
    state = self.to_struct()
    state['_cache_key'] = self._cache_key
    return state
models.Base.__getstate__ = getstate

def setstate(self, data):
    self._cache_key = data.pop('_cache_key')
    self.populate(**data)
models.Base.__setstate__ = setstate

PS: there's a similar issue with deepcopy

@carstencodes
Copy link

Hi,

I was able to omit this behavior by adding an inherited constructor:

class TestModel(models.Base):
    a = fields.StringField(default="")

   def __init__(self, *args, **kwargs):
       super(TestModel, self).__init__(*args, **kwargs)

Afterwards, the error above disappeared.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants