Skip to content

Commit

Permalink
adding pickle support, fix #40
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin committed Jun 21, 2017
1 parent ea38c29 commit dce9dee
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 6 deletions.
15 changes: 10 additions & 5 deletions pydantic/main.py
Expand Up @@ -64,7 +64,6 @@ def __new__(mcs, name, bases, namespace):
for ann_name, ann_type in annotations.items():
if ann_name.startswith('_'):
continue
print(ann_type)
fields[ann_name] = Field.infer(
name=ann_name,
value=...,
Expand Down Expand Up @@ -93,7 +92,7 @@ class BaseModel(metaclass=MetaModel):
__slots__ = '__values__',

def __init__(self, **data):
object.__setattr__(self, '__values__', self._process_values(data))
self.__setstate__(self._process_values(data))

def __getattr__(self, name):
try:
Expand All @@ -108,6 +107,12 @@ def __setattr__(self, name, value):
raise TypeError(f'"{self.__class__.__name__}" is immutable and does not support item assignment')
self.__values__[name] = value

def __getstate__(self):
return self.__values__

def __setstate__(self, state):
object.__setattr__(self, '__values__', state)

def values(self, *, include: Set[str]=None, exclude: Set[str]=set()) -> Dict[str, Any]:
"""
Get a dict of the values processed by the model, optionally specifying which fields to include or exclude.
Expand All @@ -126,16 +131,16 @@ def construct(cls, **values):
data. Chances are you don't want to use this method directly.
"""
m = cls.__new__(cls)
object.__setattr__(m, '__values__', values)
m.__setstate__(values)
return m

def copy(self, *, include: Set[str]=None, exclude: Set[str]=None, update: Dict[str, Any]=None):
"""
Duplicate a model, optionally choose which fields to include, exclude and change
:param include: fields to include in new model.
:param exclude: fields to exclude from new model, as with values this takes precedence over include
:param update: values to changed/update in the new model. Note: the data is not validated before creating
the new model, so you should trust this data.
:param update: values to change/add in the new model. Note: the data is not validated before creating
the new model: you should trust this data.
:return: new model instance
"""
if include is None and exclude is None and update is None:
Expand Down
25 changes: 24 additions & 1 deletion tests/test_construction.py
@@ -1,10 +1,12 @@
import pickle

import pytest

from pydantic import BaseModel


class Model(BaseModel):
a: float
a: float = ...
b: int = 10


Expand Down Expand Up @@ -83,3 +85,24 @@ def test_copy_update():
assert set(m.values().keys()) == set(m2.values().keys()) == {'a', 'b', 'c', 'd'}

assert m != m2


def test_simple_pickle():
m = Model(a='24')
b = pickle.dumps(m)
m2 = pickle.loads(b)
assert m.a == m2.a == 24
assert m.b == m2.b == 10
assert m == m2
assert m is not m2
assert tuple(m) == (('a', 24.0), ('b', 10))
assert tuple(m2) == (('a', 24.0), ('b', 10))


def test_recursive_pickle():
m = ModelTwo(a=24, d=Model(a='123.45'))
m2 = pickle.loads(pickle.dumps(m))
assert m == m2

assert m.d.a == 123.45
assert m2.d.a == 123.45

0 comments on commit dce9dee

Please sign in to comment.