Repository: enthought/okonomiyaki

Issue:
Move EggMetadata json serialization from edm 
See enthought/edm#719

Discussion:

Patch:
diff --git a/okonomiyaki/file_formats/_egg_info.py b/okonomiyaki/file_formats/_egg_info.py
index ddc2e2f..afc373c 100644
--- a/okonomiyaki/file_formats/_egg_info.py
+++ b/okonomiyaki/file_formats/_egg_info.py
@@ -663,6 +663,18 @@ def _normalized_info_from_string(spec_depend_string, epd_platform=None,
     return data, epd_platform
 
 
+_JSON_METADATA_VERSION = "metadata_version"
+_JSON__RAW_NAME = "_raw_name"
+_JSON_VERSION = "version"
+_JSON_EPD_PLATFORM = "epd_platform"
+_JSON_PYTHON_TAG = "python_tag"
+_JSON_ABI_TAG = "abi_tag"
+_JSON_PLATFORM_TAG = "platform_tag"
+_JSON_PLATFORM_ABI_TAG = "platform_abi_tag"
+_JSON_RUNTIME_DEPENDENCIES = "runtime_dependencies"
+_JSON_SUMMARY = "summary"
+
+
 class EggMetadata(object):
     """ Enthought egg metadata for format 1.x.
     """
@@ -707,6 +719,32 @@ class EggMetadata(object):
                 sha256 = compute_sha256(path_or_file.fp)
         return cls._from_egg(path_or_file, sha256, strict)
 
+    @classmethod
+    def from_json_dict(cls, json_dict, pkg_info):
+        version = EnpkgVersion.from_string(json_dict[_JSON_VERSION])
+
+        if json_dict[_JSON_PYTHON_TAG] is not None:
+            python = PythonImplementation.from_string(json_dict[_JSON_PYTHON_TAG])
+        else:
+            python = None
+
+        if json_dict[_JSON_EPD_PLATFORM] is None:
+            epd_platform = None
+        else:
+            epd_platform = EPDPlatform.from_epd_string(json_dict[_JSON_EPD_PLATFORM])
+
+        dependencies = Dependencies(tuple(json_dict[_JSON_RUNTIME_DEPENDENCIES]))
+        metadata_version = MetadataVersion.from_string(
+            json_dict[_JSON_METADATA_VERSION]
+        )
+
+        return cls(
+            json_dict[_JSON__RAW_NAME], version, epd_platform, python,
+            json_dict[_JSON_ABI_TAG], json_dict[_JSON_PLATFORM_ABI_TAG],
+            dependencies, pkg_info, json_dict[_JSON_SUMMARY],
+            metadata_version=metadata_version
+        )
+
     @classmethod
     def _from_egg(cls, path_or_file, sha256, strict=True):
         def _read_summary(fp):
@@ -1015,6 +1053,27 @@ class EggMetadata(object):
             if self.pkg_info:
                 self.pkg_info._dump_as_zip(zp)
 
+    def to_json_dict(self):
+        if self.platform is None:
+            epd_platform = None
+        else:
+            epd_platform = six.text_type(self.platform)
+
+        return {
+            _JSON_METADATA_VERSION: six.text_type(self.metadata_version),
+            _JSON__RAW_NAME: self._raw_name,
+            _JSON_VERSION: six.text_type(self.version),
+            _JSON_EPD_PLATFORM: epd_platform,
+            _JSON_PYTHON_TAG: self.python_tag,
+            _JSON_ABI_TAG: self.abi_tag,
+            _JSON_PLATFORM_TAG: self.platform_tag,
+            _JSON_PLATFORM_ABI_TAG: self.platform_abi_tag,
+            _JSON_RUNTIME_DEPENDENCIES: [
+                six.text_type(p) for p in self.runtime_dependencies
+            ],
+            _JSON_SUMMARY: self.summary,
+        }
+
     # Protocol implementations
     def __eq__(self, other):
         if isinstance(other, self.__class__):


Test patch:
diff --git a/okonomiyaki/file_formats/tests/test__egg_info.py b/okonomiyaki/file_formats/tests/test__egg_info.py
index 80dd58b..b658c36 100644
--- a/okonomiyaki/file_formats/tests/test__egg_info.py
+++ b/okonomiyaki/file_formats/tests/test__egg_info.py
@@ -17,7 +17,9 @@ from ...errors import (
     InvalidEggName, InvalidMetadata, InvalidMetadataField, MissingMetadata,
     UnsupportedMetadata)
 from ...utils import tempdir
-from ...utils.test_data import NOSE_1_3_4_OSX_X86_64
+from ...utils.test_data import (
+    MKL_10_3_RH5_X86_64, NOSE_1_3_4_OSX_X86_64, NOSE_1_3_4_RH5_X86_64
+)
 from ...platforms import EPDPlatform, PlatformABI, PythonImplementation
 from ...platforms.legacy import LegacyEPDPlatform
 from ...versions import EnpkgVersion, MetadataVersion, RuntimeVersion
@@ -1552,3 +1554,68 @@ class TestEggMetadata(unittest.TestCase):
         # Then
         metadata = EggMetadata.from_egg(path)
         self.assertEqual(metadata.platform_tag, "win32")
+
+    def test_to_json_dict(self):
+        # Given
+        egg = NOSE_1_3_4_RH5_X86_64
+        metadata = EggMetadata.from_egg(egg)
+
+        r_json_dict = {
+            "metadata_version": u"1.3",
+            "_raw_name": u"nose",
+            "version": u"1.3.4-1",
+            "epd_platform": u"rh5_x86_64",
+            "python_tag": u"cp27",
+            "abi_tag": u"cp27m",
+            "platform_tag": u"linux_x86_64",
+            "platform_abi_tag": u"gnu",
+            "runtime_dependencies": [],
+            "summary": (
+                u"Extends the Python Unittest module with additional "
+                "disocvery and running\noptions\n"
+            )
+        }
+
+        # When
+        json_dict = metadata.to_json_dict()
+
+        # Then
+        self.assertEqual(json_dict, r_json_dict)
+
+    def test_from_json_dict(self):
+        # Given
+        egg = NOSE_1_3_4_RH5_X86_64
+        r_metadata = EggMetadata.from_egg(egg)
+
+        json_dict = {
+            "metadata_version": u"1.3",
+            "_raw_name": u"nose",
+            "version": u"1.3.4-1",
+            "epd_platform": u"rh5_x86_64",
+            "python_tag": u"cp27",
+            "abi_tag": u"cp27m",
+            "platform_tag": u"linux_x86_64",
+            "platform_abi_tag": u"gnu",
+            "runtime_dependencies": [],
+            "summary": (
+                u"Extends the Python Unittest module with additional "
+                "disocvery and running\noptions\n"
+            )
+        }
+
+        # When
+        metadata = EggMetadata.from_json_dict(json_dict, r_metadata.pkg_info)
+
+        # Then
+        self.assertEqual(metadata, r_metadata)
+
+    def _test_roundtrip(self, egg):
+        r_metadata = EggMetadata.from_egg(egg)
+        metadata = EggMetadata.from_json_dict(
+            r_metadata.to_json_dict(), r_metadata.pkg_info
+        )
+
+        self.assertEqual(metadata, r_metadata)
+
+    def test_mkl_roundtrip(self):
+        self._test_roundtrip(MKL_10_3_RH5_X86_64)