Repository: yukinarit/pyserde
Pull request #284 (2022-11-26 18:00:30)

Pickle serializer/deserializer implementation.
I have copied the yaml serializer and deserializer implementation and adapted it to work with pickle.
I'm not quite sure if this will find uses but I think it is nice to have direct serialization/deserialisation to pickle.
Added from_pickle and to_pickle methods to the tests.


Patch:
diff --git a/serde/pickle.py b/serde/pickle.py
new file mode 100644
index 0000000..a2c0554
--- /dev/null
+++ b/serde/pickle.py
@@ -0,0 +1,31 @@
+"""
+Serialize and Deserialize in Pickle format.
+"""
+import pickle
+from typing import Type
+
+from .compat import T
+from .de import Deserializer, from_dict
+from .se import Serializer, to_dict
+
+__all__ = ["from_pickle", "to_pickle"]
+
+
+class PickleSerializer(Serializer):
+    @classmethod
+    def serialize(cls, obj, **opts) -> bytes:
+        return pickle.dumps(obj, **opts)
+
+
+class PickleDeserializer(Deserializer):
+    @classmethod
+    def deserialize(cls, data, **opts):
+        return pickle.loads(data, **opts)
+
+
+def to_pickle(obj, se: Type[Serializer] = PickleSerializer, **opts) -> str:
+    return se.serialize(to_dict(obj, reuse_instances=False), **opts)
+
+
+def from_pickle(c: Type[T], s: str, de: Type[Deserializer] = PickleDeserializer, **opts) -> T:
+    return from_dict(c, de.deserialize(s, **opts), reuse_instances=False)


Test patch:
diff --git a/tests/common.py b/tests/common.py
index a5dbc9d..d65592d 100644
--- a/tests/common.py
+++ b/tests/common.py
@@ -13,6 +13,7 @@ import more_itertools
 from serde import from_dict, from_tuple, serde, to_dict, to_tuple
 from serde.json import from_json, to_json
 from serde.msgpack import from_msgpack, to_msgpack
+from serde.pickle import from_pickle, to_pickle
 from serde.toml import from_toml, to_toml
 from serde.yaml import from_yaml, to_yaml
 from tests import data
@@ -29,7 +30,11 @@ format_yaml: List = [(to_yaml, from_yaml)]
 
 format_toml: List = [(to_toml, from_toml)]
 
-all_formats: List = format_dict + format_tuple + format_json + format_msgpack + format_yaml + format_toml
+format_pickle: List = [(to_pickle, from_pickle)]
+
+all_formats: List = (
+    format_dict + format_tuple + format_json + format_msgpack + format_yaml + format_toml + format_pickle
+)
 
 T = TypeVar('T')
 
diff --git a/tests/test_basics.py b/tests/test_basics.py
index d4237d8..7e47518 100644
--- a/tests/test_basics.py
+++ b/tests/test_basics.py
@@ -17,6 +17,7 @@ from .common import (
     format_dict,
     format_json,
     format_msgpack,
+    format_pickle,
     format_toml,
     format_tuple,
     format_yaml,
@@ -354,7 +355,9 @@ def test_default(se, de):
     assert True is dataclasses.fields(PriDefault)[3].default
 
 
-@pytest.mark.parametrize('se,de', (format_dict + format_tuple + format_json + format_msgpack + format_yaml))
+@pytest.mark.parametrize(
+    'se,de', (format_dict + format_tuple + format_json + format_msgpack + format_yaml + format_pickle)
+)
 def test_list_pri(se, de):
     p = [data.PRI, data.PRI]
     assert p == de(data.ListPri, se(p))
@@ -363,7 +366,9 @@ def test_list_pri(se, de):
     assert p == de(data.ListPri, se(p))
 
 
-@pytest.mark.parametrize('se,de', (format_dict + format_tuple + format_json + format_msgpack + format_yaml))
+@pytest.mark.parametrize(
+    'se,de', (format_dict + format_tuple + format_json + format_msgpack + format_yaml + format_pickle)
+)
 def test_dict_pri(se, de):
     p = {'1': data.PRI, '2': data.PRI}
     assert p == de(data.DictPri, se(p))
@@ -444,7 +449,7 @@ def test_rename_msgpack(se, de):
     assert f == de(Foo, se(f, named=False), named=False)
 
 
-@pytest.mark.parametrize('se,de', (format_dict + format_json + format_yaml + format_toml))
+@pytest.mark.parametrize('se,de', (format_dict + format_json + format_yaml + format_toml + format_pickle))
 def test_rename_formats(se, de):
     @serde.serde(rename_all='camelcase')
     class Foo:
@@ -454,7 +459,7 @@ def test_rename_formats(se, de):
     assert f == de(Foo, se(f))
 
 
-@pytest.mark.parametrize('se,de', (format_dict + format_json + format_yaml + format_toml))
+@pytest.mark.parametrize('se,de', (format_dict + format_json + format_yaml + format_toml + format_pickle))
 def test_alias(se, de):
     @serde.serde
     class Foo:
@@ -498,7 +503,9 @@ def test_rename_and_alias():
     assert ff.a == 10
 
 
-@pytest.mark.parametrize('se,de', (format_dict + format_json + format_msgpack + format_yaml + format_toml))
+@pytest.mark.parametrize(
+    'se,de', (format_dict + format_json + format_msgpack + format_yaml + format_toml + format_pickle)
+)
 def test_skip_if(se, de):
     @serde.serde
     class Foo:
@@ -524,7 +531,9 @@ def test_skip_if_false(se, de):
     assert f == de(Foo, se(f))
 
 
-@pytest.mark.parametrize('se,de', (format_dict + format_json + format_msgpack + format_yaml + format_toml))
+@pytest.mark.parametrize(
+    'se,de', (format_dict + format_json + format_msgpack + format_yaml + format_toml + format_pickle)
+)
 def test_skip_if_overrides_skip_if_false(se, de):
     @serde.serde
     class Foo:
diff --git a/tests/test_literal.py b/tests/test_literal.py
index 4084847..1e9dbb2 100644
--- a/tests/test_literal.py
+++ b/tests/test_literal.py
@@ -17,6 +17,7 @@ from .common import (
     format_dict,
     format_json,
     format_msgpack,
+    format_pickle,
     format_tuple,
     format_yaml,
     opt_case,