From 660501ab95bba2fdd5ec0f2c1e61972aed9b9b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20Tomsa?= Date: Wed, 3 Jul 2019 14:47:43 +0200 Subject: [PATCH] Make serialization methods more concise 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. --- app/serialization.py | 73 ++++++++++++++++++++------------------------ test_unit.py | 23 ++++++++++++++ 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/app/serialization.py b/app/serialization.py index 7b666c1e4..2d0945e0a 100644 --- a/app/serialization.py +++ b/app/serialization.py @@ -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) diff --git a/test_unit.py b/test_unit.py index 3659d5b97..68b8ea84a 100755 --- a/test_unit.py +++ b/test_unit.py @@ -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 @@ -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 @@ -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()