Skip to content

Commit

Permalink
Make serialization methods more concise
Browse files Browse the repository at this point in the history
Reviewed the style of the (de)serialization methods. Removed redundant
or rather cryptic instructions. Leveraged comprehensions, dried a few
bits of code. Made the code more concise and expressive. Unified names
a bit.
  • Loading branch information
Glutexo committed Aug 6, 2019
1 parent ebceb60 commit 660501a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 40 deletions.
73 changes: 33 additions & 40 deletions app/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,71 +19,64 @@


def deserialize_host(data):
canonical_facts = _deserialize_canonical_facts(data)
facts = _deserialize_facts(data.get("facts"))
return Host(
canonical_facts,
data.get("display_name", None),
_deserialize_canonical_facts(data),
data.get("display_name"),
data.get("ansible_host"),
data.get("account"),
facts,
_deserialize_facts(data.get("facts")),
data.get("system_profile", {}),
)


def serialize_host(host):
json_dict = _serialize_canonical_facts(host.canonical_facts)
json_dict["id"] = str(host.id)
json_dict["account"] = host.account
json_dict["display_name"] = host.display_name
json_dict["ansible_host"] = host.ansible_host
json_dict["facts"] = _serialize_facts(host.facts)
json_dict["created"] = host.created_on.isoformat() + "Z"
json_dict["updated"] = host.modified_on.isoformat() + "Z"
return json_dict
return {
**_serialize_canonical_facts(host.canonical_facts),
"id": _serialize_uuid(host.id),
"account": host.account,
"display_name": host.display_name,
"ansible_host": host.ansible_host,
"facts": _serialize_facts(host.facts),
"created": _serialize_datetime(host.created_on),
"updated": _serialize_datetime(host.modified_on),
}


def serialize_host_system_profile(host):
json_dict = {"id": str(host.id), "system_profile": host.system_profile_facts or {}}
return json_dict
return {"id": _serialize_uuid(host.id), "system_profile": host.system_profile_facts or {}}


def _deserialize_canonical_facts(data):
canonical_fact_list = {}
for cf in _CANONICAL_FACTS_FIELDS:
# Do not allow the incoming canonical facts to be None or ''
if cf in data and data[cf]:
canonical_fact_list[cf] = data[cf]
return canonical_fact_list
return {field: data[field] for field in _CANONICAL_FACTS_FIELDS if data.get(field)}


def _serialize_canonical_facts(canonical_facts):
canonical_fact_dict = dict.fromkeys(_CANONICAL_FACTS_FIELDS, None)
for cf in _CANONICAL_FACTS_FIELDS:
if cf in canonical_facts:
canonical_fact_dict[cf] = canonical_facts[cf]
return canonical_fact_dict
return {field: canonical_facts.get(field) for field in _CANONICAL_FACTS_FIELDS}


def _deserialize_facts(data):
if data is None:
data = []

fact_dict = {}
for fact in data:
if "namespace" in fact and "facts" in fact:
if fact["namespace"] in fact_dict:
fact_dict[fact["namespace"]].update(fact["facts"])
facts = {}
for fact in [] if data is None else data:
try:
if fact["namespace"] in facts:
facts[fact["namespace"]].update(fact["facts"])
else:
fact_dict[fact["namespace"]] = fact["facts"]
else:
facts[fact["namespace"]] = fact["facts"]
except KeyError:
# The facts from the request are formatted incorrectly
raise InputFormatException(
"Invalid format of Fact object. Fact must contain 'namespace' and 'facts' keys."
)
return fact_dict
return facts


def _serialize_facts(facts):
fact_list = [{"namespace": namespace, "facts": facts if facts else {}} for namespace, facts in facts.items()]
return fact_list
return [{"namespace": namespace, "facts": facts or {}} for namespace, facts in facts.items()]


def _serialize_datetime(dt):
return dt.isoformat() + "Z"


def _serialize_uuid(u):
return str(u)
23 changes: 23 additions & 0 deletions test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from unittest import TestCase
from unittest.mock import Mock
from unittest.mock import patch
from uuid import UUID
from uuid import uuid4

from api import api_operation
Expand All @@ -23,7 +24,9 @@
from app.serialization import _deserialize_canonical_facts
from app.serialization import _deserialize_facts
from app.serialization import _serialize_canonical_facts
from app.serialization import _serialize_datetime
from app.serialization import _serialize_facts
from app.serialization import _serialize_uuid
from app.serialization import deserialize_host
from app.serialization import serialize_host
from app.serialization import serialize_host_system_profile
Expand Down Expand Up @@ -824,5 +827,25 @@ def test_empty_namespaces_have_facts_as_empty_dicts(self):
)


class SerializationSerializeDatetime(TestCase):
def test_short_utc_timezone_is_included(self):
now = datetime.utcnow()
self.assertEqual(f"{now.isoformat()}Z", _serialize_datetime(now))

def test_iso_format_is_used(self):
dt = datetime(2019, 7, 3, 1, 1, 4, 20647)
self.assertEqual("2019-07-03T01:01:04.020647Z", _serialize_datetime(dt))


class SerializationSerializeUuid(TestCase):
def test_uuid_has_hyphens_computed(self):
u = uuid4()
self.assertEqual(str(u), _serialize_uuid(u))

def test_uuid_has_hyphens_literal(self):
u = "4950e534-bbef-4432-bde2-aa3dd2bd0a52"
self.assertEqual(u, _serialize_uuid(UUID(u)))


if __name__ == "__main__":
main()

0 comments on commit 660501a

Please sign in to comment.