Repository: enthought/okonomiyaki

Issue:
Make it easier to create Platform instance from a json dictionary of values.
We make it easier to create a new Platform instance from a json dictionary

At the moment the only way to perform the operation is 
```
Platform(
            os_kind=OSKind.__members__[data['os_kind']],
            family_kind=FamilyKind.__members__[data['family_kind']],
            name_kind=NameKind.__members__[data['name_kind']],
            release=data['release'],
            arch=Arch.from_name(data['arch']),
            machine=Arch.from_name(data['machine']))
```

We can add a new constructor or update the Platform class to coerse the string values to the necessary nametuples and classes

Discussion:

Patch:
diff --git a/okonomiyaki/platforms/_platform.py b/okonomiyaki/platforms/_platform.py
index f5f6e55..21a12ac 100644
--- a/okonomiyaki/platforms/_platform.py
+++ b/okonomiyaki/platforms/_platform.py
@@ -75,9 +75,10 @@ class Platform(object):
 
     machine = attr(validator=instance_of(Arch))
     """
-    The machine. This is the CPU architecture (e.g. for a 32 bits python
-    running on 64 bits Intel OS, machine will be an x86_64 arch, whereas arch
-    will be an 'x86' arch)
+    This is the CPU architecture of the host machine (e.g. for a
+    32 bits python running on 64 bits Intel OS, machine will be an
+    x86_64 arch, whereas arch will be an 'x86' arch)
+
     """
 
     @classmethod
@@ -103,6 +104,53 @@ class Platform(object):
             arch = Arch.from_name(arch_string)
         return _guess_platform(arch)
 
+    @classmethod
+    def from_dict(cls, **kw):
+        """ Create a Platfrom instace from dictionary values.
+
+        Parameters
+        ----------
+        os_kind: str, OSKind
+            The most generic OS description.
+
+        name_kind: str, NameKind
+            The most specific platform description.
+
+        family_kind: str, FamilyKind
+            The 'family' of platforms. For example, both debian and
+            ubuntu distributions share the same kind, 'debian'.
+
+        release: str
+            The release string. May be an empty string.
+        arch: str, Arch
+             Actual architecture of the Python runtime
+        machine: str, Arch
+             This is the CPU architecture of the host machine
+             (e.g. for a 32 bits python running on 64 bits Intel OS,
+             machine will be an x86_64 arch, whereas arch will be an 'x86'
+             arch)
+
+        """
+        os_kind, name_kind, family_kind, arch, machine = (
+            kw['os_kind'], kw['name_kind'], kw['family_kind'], kw['arch'], kw['machine'])
+        if isinstance(os_kind, str):
+            os_kind = OSKind[os_kind]
+        if isinstance(name_kind, str):
+            name_kind = NameKind[name_kind]
+        if isinstance(family_kind, str):
+            family_kind = FamilyKind[family_kind]
+        if isinstance(arch, str):
+            arch = Arch.from_name(arch)
+        if isinstance(machine, str):
+            machine = Arch.from_name(machine)
+        return cls(
+            os_kind=os_kind,
+            family_kind=family_kind,
+            name_kind=name_kind,
+            release=kw['release'],
+            arch=arch,
+            machine=machine)
+
     @property
     def family(self):
         return self.family_kind.name
diff --git a/okonomiyaki/utils/misc.py b/okonomiyaki/utils/misc.py
index 89452d4..81199d4 100644
--- a/okonomiyaki/utils/misc.py
+++ b/okonomiyaki/utils/misc.py
@@ -20,7 +20,7 @@ class _AssignmentParser(ast.NodeVisitor):
         return self._data
 
     def generic_visit(self, node):
-        if type(node) != ast.Module:
+        if type(node) is not ast.Module:
             raise OkonomiyakiError("Unexpected expression @ line {0}".
                                    format(node.lineno))
         super(_AssignmentParser, self).generic_visit(node)
diff --git a/okonomiyaki/versions/pep440.py b/okonomiyaki/versions/pep440.py
index 8481b2c..9badf45 100644
--- a/okonomiyaki/versions/pep440.py
+++ b/okonomiyaki/versions/pep440.py
@@ -147,7 +147,7 @@ class PEP440Version(object):
         return hash(self._parts)
 
     def _ensure_compatible(self, other):
-        if type(self) != type(other):
+        if type(self) != type(other):  # noqa
             raise TypeError('cannot compare %r and %r' % (self, other))
 
     def _compute_string(self, epoch, nums, pre, post, dev, local):


Test patch:
diff --git a/okonomiyaki/platforms/tests/test_platform.py b/okonomiyaki/platforms/tests/test_platform.py
index 52b83c9..fb6e808 100644
--- a/okonomiyaki/platforms/tests/test_platform.py
+++ b/okonomiyaki/platforms/tests/test_platform.py
@@ -4,7 +4,7 @@ from parameterized import parameterized
 
 from okonomiyaki.errors import OkonomiyakiError
 from .._arch import X86, X86_64, ARM, ARM64
-from .._platform import Platform
+from .._platform import Platform, OSKind, NameKind, FamilyKind
 
 from .common import (
     mock_x86, mock_x86_64,
@@ -273,3 +273,32 @@ class TestPlatform(unittest.TestCase):
         self.assertFalse(win32_1 == win64)
 
         self.assertNotEqual(win32_1, None)
+
+    @parameterized.expand([
+        (OSKind.linux, NameKind.rocky, FamilyKind.rhel, X86, X86_64),
+        (OSKind.linux, NameKind.rocky, FamilyKind.rhel, X86, X86),
+        (OSKind.linux, NameKind.rocky, FamilyKind.rhel, X86, ARM64),
+        (OSKind.linux, NameKind.rocky, FamilyKind.rhel, ARM64, ARM64),
+        ('linux', 'rocky', 'rhel', 'x86', 'x86_64'),
+        ('linux', 'rocky', 'rhel', 'x86', 'x86'),
+        ('linux', 'rocky', 'rhel', 'x86', 'arm64'),
+        ('linux', 'rocky', 'rhel', 'arm64', 'arm64')])
+    def test_from_dict(self, os, name, family, arch, machine):
+        # Given
+        dictionary = {
+            'os_kind': os,
+            'name_kind': name,
+            'family_kind': family,
+            'release': '8.9',
+            'arch': arch,
+            'machine': machine}
+
+        # When
+        platform = Platform.from_dict(**dictionary)
+
+        # Then
+        self.assertEqual(platform.os, 'linux')
+        self.assertEqual(platform.name, 'rocky')
+        self.assertEqual(platform.family, 'rhel')
+        self.assertEqual(platform.release, '8.9')
+        self.assertEqual(str(platform), f'Rocky Linux 8.9 on {machine} using {arch} arch')