diff --git a/Pipfile b/Pipfile index ce52a55..94d3047 100644 --- a/Pipfile +++ b/Pipfile @@ -11,6 +11,7 @@ green = "==3.0.0" coverage = "==4.5.4" codecov = "==2.0.15" wheel = "==0.33.6" +mashumaro = "==1.7" [packages] path-py = "==12.0.1" diff --git a/Pipfile.lock b/Pipfile.lock index e54b335..fa46c3d 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a170c578d0e4a535931b9ac3629ec5c3fb74ee5b765e83c1443db26263480d28" + "sha256": "35e0de744675ec036e94f8d69f99a53fed6a2a2568328a47971a13fad24f2cd0" }, "pipfile-spec": 6, "requires": {}, @@ -183,6 +183,39 @@ ], "version": "==4.4.1" }, + "mashumaro": { + "hashes": [ + "sha256:0e513d5c39c4c0db360628988bc86dfb7a4cbcefc6559d7aa42340caf639b4e5" + ], + "index": "pypi", + "version": "==1.7" + }, + "msgpack": { + "hashes": [ + "sha256:0cc7ca04e575ba34fea7cfcd76039f55def570e6950e4155a4174368142c8e1b", + "sha256:187794cd1eb73acccd528247e3565f6760bd842d7dc299241f830024a7dd5610", + "sha256:1904b7cb65342d0998b75908304a03cb004c63ef31e16c8c43fee6b989d7f0d7", + "sha256:229a0ccdc39e9b6c6d1033cd8aecd9c296823b6c87f0de3943c59b8bc7c64bee", + "sha256:24149a75643aeaa81ece4259084d11b792308a6cf74e796cbb35def94c89a25a", + "sha256:30b88c47e0cdb6062daed88ca283b0d84fa0d2ad6c273aa0788152a1c643e408", + "sha256:32fea0ea3cd1ef820286863a6202dcfd62a539b8ec3edcbdff76068a8c2cc6ce", + "sha256:355f7fd0f90134229eaeefaee3cf42e0afc8518e8f3cd4b25f541a7104dcb8f9", + "sha256:4abdb88a9b67e64810fb54b0c24a1fd76b12297b4f7a1467d85a14dd8367191a", + "sha256:757bd71a9b89e4f1db0622af4436d403e742506dbea978eba566815dc65ec895", + "sha256:76df51492bc6fa6cc8b65d09efdb67cbba3cbfe55004c3afc81352af92b4a43c", + "sha256:774f5edc3475917cd95fe593e625d23d8580f9b48b570d8853d06cac171cd170", + "sha256:8a3ada8401736df2bf497f65589293a86c56e197a80ae7634ec2c3150a2f5082", + "sha256:a06efd0482a1942aad209a6c18321b5e22d64eb531ea20af138b28172d8f35ba", + "sha256:b24afc52e18dccc8c175de07c1d680bdf315844566f4952b5bedb908894bec79", + "sha256:b8b4bd3dafc7b92608ae5462add1c8cc881851c2d4f5d8977fdea5b081d17f21", + "sha256:c6e5024fc0cdf7f83b6624850309ddd7e06c48a75fa0d1c5173de4d93300eb19", + "sha256:db7ff14abc73577b0bcbcf73ecff97d3580ecaa0fc8724babce21fdf3fe08ef6", + "sha256:dedf54d72d9e7b6d043c244c8213fe2b8bbfe66874b9a65b39c4cc892dd99dd4", + "sha256:ea3c2f859346fcd55fc46e96885301d9c2f7a36d453f5d8f2967840efa1e1830", + "sha256:f0f47bafe9c9b8ed03e19a100a743662dd8c6d0135e684feea720a0d0046d116" + ], + "version": "==0.6.2" + }, "pkginfo": { "hashes": [ "sha256:7424f2c8511c186cd5424bbf31045b77435b37a8d604990b79d4e70d741148bb", @@ -197,6 +230,24 @@ ], "version": "==2.4.2" }, + "pyyaml": { + "hashes": [ + "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", + "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4", + "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8", + "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696", + "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34", + "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9", + "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73", + "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299", + "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b", + "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae", + "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681", + "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41", + "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8" + ], + "version": "==5.1.2" + }, "readme-renderer": { "hashes": [ "sha256:bb16f55b259f27f75f640acf5e00cf897845a8b3e4731b5c1a436e4b8529202f", diff --git a/mutapath/decorator.py b/mutapath/decorator.py index 8c89889..51f7dc5 100644 --- a/mutapath/decorator.py +++ b/mutapath/decorator.py @@ -19,7 +19,7 @@ "__delattr__", "__setattr__", "__getattr__", "joinpath", "clone", "__exit__", "__fspath__", "'_Path__wrap_attribute'", "__wrap_decorator", "_op_context", "__hash__", "__enter__", "_norm", "open", "lock", "getcwd", "dirname", "owner", "uncshare", "posix_format", "posix_string", "__add__", "__radd__", "_set_contained", - "with_poxis_enabled", "_hash_cache" + "with_poxis_enabled", "_hash_cache", "_serialize", "_deserialize" ] __MUTABLE_FUNCTIONS = {"rename", "renames", "copy", "copy2", "copyfile", "copymode", "copystat", "copytree", "move", diff --git a/mutapath/immutapath.py b/mutapath/immutapath.py index b0c0fd0..e26080c 100644 --- a/mutapath/immutapath.py +++ b/mutapath/immutapath.py @@ -19,11 +19,18 @@ from mutapath.exceptions import PathException from mutapath.lock_dummy import DummyFileLock +try: + from mashumaro.types import SerializableType +except ImportError: + SerializableType = object +except NotImplementedError: + SerializableType = object + POSIX_ENABLED_DEFAULT = False @path_wrapper -class Path(object): +class Path(SerializableType): """Immutable Path""" _contained: Union[path.Path, pathlib.PurePath, str] = path.Path("") __always_posix_format: bool @@ -147,6 +154,13 @@ def __invert__(self): from mutapath import MutaPath return MutaPath(self._contained, self.posix_enabled) + def _serialize(self) -> str: + return str(self._contained) + + @classmethod + def _deserialize(cls, value: str) -> Path: + return cls(value) + @property def to_pathlib(self) -> pathlib.Path: """ diff --git a/tests/test_serializable.py b/tests/test_serializable.py new file mode 100644 index 0000000..7728167 --- /dev/null +++ b/tests/test_serializable.py @@ -0,0 +1,43 @@ +from dataclasses import dataclass + +from mutapath import Path +from tests.helper import PathTest + +try: + from mashumaro.types import DataClassDictMixin +except ImportError: + DataClassDictMixin = object +except NotImplementedError: + DataClassDictMixin = object +else: + + @dataclass + class DataClass(DataClassDictMixin): + path: Path = Path() + + + class TestSerialization(PathTest): + def test_empty_serialization(self): + expected = {'path': ''} + actual = DataClass().to_dict() + self.assertEqual(expected, actual) + + def test_serialization(self): + expected = {'path': "/A/B/test1.txt"} + actual = DataClass(Path("/A/B/test1.txt", posix=True)).to_dict() + self.assertEqual(expected, actual) + + def test_empty_deserialization(self): + expected = DataClass() + actual = DataClass().from_dict({'path': ''}) + self.assertEqual(expected, actual) + + def test_deserialization(self): + expected = DataClass(Path("/A/B/test1.txt", posix=True)) + actual = DataClass().from_dict({'path': "/A/B/test1.txt"}) + self.assertEqual(expected, actual) + + def test_deserialization_static(self): + expected = DataClass(Path("/A/B/test1.txt", posix=True)) + actual = DataClass.from_dict({'path': "/A/B/test1.txt"}) + self.assertEqual(expected, actual)