compressedfhir 3.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. compressedfhir/__init__.py +0 -0
  2. compressedfhir/fhir/__init__.py +0 -0
  3. compressedfhir/fhir/base_resource_list.py +165 -0
  4. compressedfhir/fhir/fhir_bundle.py +295 -0
  5. compressedfhir/fhir/fhir_bundle_entry.py +240 -0
  6. compressedfhir/fhir/fhir_bundle_entry_list.py +97 -0
  7. compressedfhir/fhir/fhir_bundle_entry_request.py +73 -0
  8. compressedfhir/fhir/fhir_bundle_entry_response.py +67 -0
  9. compressedfhir/fhir/fhir_bundle_entry_search.py +75 -0
  10. compressedfhir/fhir/fhir_identifier.py +84 -0
  11. compressedfhir/fhir/fhir_link.py +63 -0
  12. compressedfhir/fhir/fhir_meta.py +47 -0
  13. compressedfhir/fhir/fhir_resource.py +170 -0
  14. compressedfhir/fhir/fhir_resource_list.py +149 -0
  15. compressedfhir/fhir/fhir_resource_map.py +193 -0
  16. compressedfhir/fhir/test/__init__.py +0 -0
  17. compressedfhir/fhir/test/test_bundle_entry.py +129 -0
  18. compressedfhir/fhir/test/test_bundle_entry_list.py +187 -0
  19. compressedfhir/fhir/test/test_bundle_entry_request.py +74 -0
  20. compressedfhir/fhir/test/test_bundle_entry_response.py +65 -0
  21. compressedfhir/fhir/test/test_fhir_bundle.py +245 -0
  22. compressedfhir/fhir/test/test_fhir_resource.py +104 -0
  23. compressedfhir/fhir/test/test_fhir_resource_list.py +160 -0
  24. compressedfhir/fhir/test/test_fhir_resource_map.py +293 -0
  25. compressedfhir/py.typed +0 -0
  26. compressedfhir/utilities/__init__.py +0 -0
  27. compressedfhir/utilities/compressed_dict/__init__.py +0 -0
  28. compressedfhir/utilities/compressed_dict/v1/__init__.py +0 -0
  29. compressedfhir/utilities/compressed_dict/v1/compressed_dict.py +701 -0
  30. compressedfhir/utilities/compressed_dict/v1/compressed_dict_access_error.py +2 -0
  31. compressedfhir/utilities/compressed_dict/v1/compressed_dict_storage_mode.py +50 -0
  32. compressedfhir/utilities/compressed_dict/v1/test/__init__.py +0 -0
  33. compressedfhir/utilities/compressed_dict/v1/test/test_compressed_dict.py +467 -0
  34. compressedfhir/utilities/fhir_json_encoder.py +71 -0
  35. compressedfhir/utilities/json_helpers.py +181 -0
  36. compressedfhir/utilities/json_serializers/__init__.py +0 -0
  37. compressedfhir/utilities/json_serializers/test/__init__.py +0 -0
  38. compressedfhir/utilities/json_serializers/test/test_type_preservation_decoder.py +165 -0
  39. compressedfhir/utilities/json_serializers/test/test_type_preservation_encoder.py +71 -0
  40. compressedfhir/utilities/json_serializers/test/test_type_preservation_serializer.py +197 -0
  41. compressedfhir/utilities/json_serializers/type_preservation_decoder.py +135 -0
  42. compressedfhir/utilities/json_serializers/type_preservation_encoder.py +55 -0
  43. compressedfhir/utilities/json_serializers/type_preservation_serializer.py +57 -0
  44. compressedfhir/utilities/ordered_dict_to_dict_converter/__init__.py +0 -0
  45. compressedfhir/utilities/ordered_dict_to_dict_converter/ordered_dict_to_dict_converter.py +24 -0
  46. compressedfhir/utilities/string_compressor/__init__.py +0 -0
  47. compressedfhir/utilities/string_compressor/v1/__init__.py +0 -0
  48. compressedfhir/utilities/string_compressor/v1/string_compressor.py +99 -0
  49. compressedfhir/utilities/string_compressor/v1/test/__init__.py +0 -0
  50. compressedfhir/utilities/string_compressor/v1/test/test_string_compressor.py +189 -0
  51. compressedfhir/utilities/test/__init__.py +0 -0
  52. compressedfhir/utilities/test/test_fhir_json_encoder.py +177 -0
  53. compressedfhir/utilities/test/test_json_helpers.py +99 -0
  54. compressedfhir-3.0.2.dist-info/METADATA +139 -0
  55. compressedfhir-3.0.2.dist-info/RECORD +59 -0
  56. compressedfhir-3.0.2.dist-info/WHEEL +5 -0
  57. compressedfhir-3.0.2.dist-info/licenses/LICENSE +201 -0
  58. compressedfhir-3.0.2.dist-info/top_level.txt +2 -0
  59. tests/__init__.py +0 -0
@@ -0,0 +1,181 @@
1
+ import json
2
+ from typing import Any, Dict, List, cast, Union, Optional, OrderedDict, overload
3
+ from datetime import datetime, date
4
+
5
+ import orjson
6
+
7
+
8
+ class FhirClientJsonHelpers:
9
+ def __init__(self) -> None:
10
+ pass
11
+
12
+ @staticmethod
13
+ def json_serial(obj: Any) -> str:
14
+ """JSON serializer for objects not serializable by default json code"""
15
+
16
+ # https://stackoverflow.com/questions/11875770/how-to-overcome-datetime-datetime-not-json-serializable
17
+ if isinstance(obj, (datetime, date)):
18
+ return obj.isoformat()
19
+ return str(obj)
20
+
21
+ @staticmethod
22
+ def remove_empty_elements(
23
+ d: List[Dict[str, Any]] | Dict[str, Any],
24
+ ) -> List[Dict[str, Any]] | Dict[str, Any]:
25
+ """
26
+ Recursively remove empty lists, empty dicts, or None elements from a dictionary
27
+ or a list of dictionaries
28
+ :param d: dictionary or list of dictionaries
29
+ :return: dictionary or list of dictionaries
30
+ """
31
+
32
+ def empty(x: Any) -> bool:
33
+ # Check if the input is None, an empty list, an empty dict, or an empty string
34
+ return (
35
+ x is None
36
+ or x == []
37
+ or x == {}
38
+ or (isinstance(x, str) and x.strip() == "")
39
+ )
40
+
41
+ if not isinstance(d, (dict, list)):
42
+ return d
43
+ elif isinstance(d, list):
44
+ return [
45
+ cast(Dict[str, Any], v)
46
+ for v in (FhirClientJsonHelpers.remove_empty_elements(v) for v in d)
47
+ if not empty(v)
48
+ ]
49
+ else:
50
+ return {
51
+ k: v
52
+ for k, v in (
53
+ (k, FhirClientJsonHelpers.remove_empty_elements(v))
54
+ for k, v in d.items()
55
+ )
56
+ if not empty(v)
57
+ }
58
+
59
+ @staticmethod
60
+ @overload
61
+ def remove_empty_elements_from_ordered_dict(
62
+ d: List[OrderedDict[str, Any]],
63
+ ) -> List[OrderedDict[str, Any]]: ...
64
+
65
+ @staticmethod
66
+ @overload
67
+ def remove_empty_elements_from_ordered_dict(
68
+ d: OrderedDict[str, Any],
69
+ ) -> OrderedDict[str, Any]: ...
70
+
71
+ @staticmethod
72
+ def remove_empty_elements_from_ordered_dict(
73
+ d: List[OrderedDict[str, Any]] | OrderedDict[str, Any],
74
+ ) -> List[OrderedDict[str, Any]] | OrderedDict[str, Any]:
75
+ """
76
+ Recursively remove empty lists, empty dicts, or None elements from a dictionary
77
+ or a list of dictionaries
78
+ :param d: dictionary or list of dictionaries
79
+ :return: dictionary or list of dictionaries
80
+ """
81
+
82
+ def empty(x: Any) -> bool:
83
+ # Check if the input is None, an empty list, an empty dict, or an empty string
84
+ return (
85
+ x is None
86
+ or x == []
87
+ or x == {}
88
+ or (isinstance(x, str) and x.strip() == "")
89
+ )
90
+
91
+ if not isinstance(d, (OrderedDict, list, Dict)):
92
+ return d
93
+ elif isinstance(d, list):
94
+ return [
95
+ v
96
+ for v in (
97
+ FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(v)
98
+ for v in d
99
+ )
100
+ if not empty(v)
101
+ ]
102
+ else:
103
+ return OrderedDict[str, Any](
104
+ {
105
+ k: v
106
+ for k, v in (
107
+ (
108
+ k,
109
+ FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(
110
+ v
111
+ ),
112
+ )
113
+ for k, v in d.items()
114
+ )
115
+ if not empty(v)
116
+ }
117
+ )
118
+
119
+ @staticmethod
120
+ def convert_dict_to_fhir_json(dict_: Dict[str, Any]) -> str:
121
+ """
122
+ Returns dictionary as json string
123
+
124
+
125
+ :return:
126
+ """
127
+ instance_variables: Dict[str, Any] = cast(
128
+ Dict[str, Any], FhirClientJsonHelpers.remove_empty_elements(dict_)
129
+ )
130
+
131
+ instance_variables_text: str = json.dumps(
132
+ instance_variables, default=FhirClientJsonHelpers.json_serial
133
+ )
134
+ return instance_variables_text
135
+
136
+ @staticmethod
137
+ def orjson_dumps(
138
+ obj: Any, indent: Optional[int] = None, sort_keys: bool = False
139
+ ) -> str:
140
+ """
141
+ Wrapper for orjson.dumps() to mimic json.dumps() behavior
142
+
143
+ Args:
144
+ obj: Object to serialize
145
+ indent: Optional indentation (note: orjson has limited indent support)
146
+ sort_keys: Whether to sort dictionary keys
147
+
148
+ Returns:
149
+ JSON string
150
+ """
151
+ # Serialization options
152
+ options = 0
153
+
154
+ # Handle sorting keys
155
+ if sort_keys:
156
+ options |= orjson.OPT_SORT_KEYS
157
+
158
+ # Handle indentation (limited support)
159
+ if indent is not None:
160
+ options |= orjson.OPT_INDENT_2 # Fixed indentation
161
+
162
+ # Serialize to bytes
163
+ json_bytes = orjson.dumps(obj, option=options)
164
+
165
+ # Convert bytes to string
166
+ return json_bytes.decode("utf-8")
167
+
168
+ @staticmethod
169
+ def orjson_loads(json_input: Union[str, bytes]) -> Any:
170
+ """
171
+ Safely load JSON with type flexibility
172
+ """
173
+ try:
174
+ # Converts input to appropriate type if needed
175
+ if isinstance(json_input, str):
176
+ json_input = json_input.encode("utf-8")
177
+
178
+ return orjson.loads(json_input)
179
+ except (orjson.JSONDecodeError, TypeError) as e:
180
+ print(f"JSON Parsing Error: {e}")
181
+ return None
File without changes
@@ -0,0 +1,165 @@
1
+ from datetime import datetime, date, time
2
+ from decimal import Decimal
3
+ from typing import Type, Any, Dict, Optional
4
+ import pytest
5
+
6
+ from compressedfhir.utilities.json_serializers.type_preservation_decoder import (
7
+ TypePreservationDecoder,
8
+ )
9
+
10
+
11
+ class TestCustomObject:
12
+ def __init__(
13
+ self,
14
+ name: str,
15
+ value: int,
16
+ created_at: Optional[datetime] = None,
17
+ nested_data: Optional[Dict[str, Any]] = None,
18
+ ):
19
+ self.name: str = name
20
+ self.value: int = value
21
+ self.created_at: Optional[datetime] = created_at
22
+ self.nested_data: Optional[Dict[str, Any]] = nested_data
23
+
24
+ def __eq__(self, other: Any) -> bool:
25
+ if not isinstance(other, TestCustomObject):
26
+ return False
27
+ return (
28
+ self.name == other.name
29
+ and self.value == other.value
30
+ and self.created_at == other.created_at
31
+ and self.nested_data == other.nested_data
32
+ )
33
+
34
+
35
+ @pytest.mark.parametrize(
36
+ "input_type, input_dict, expected_type",
37
+ [
38
+ (
39
+ "datetime",
40
+ {"__type__": "datetime", "iso": "2023-01-01T00:00:00+00:00"},
41
+ datetime,
42
+ ),
43
+ (
44
+ "datetime",
45
+ {
46
+ "__type__": "datetime",
47
+ "iso": "2023-01-01T00:00:00-08:00",
48
+ "tzinfo": "Pacific/Honolulu",
49
+ },
50
+ datetime,
51
+ ),
52
+ ("date", {"__type__": "date", "iso": "2023-01-01"}, date),
53
+ ("time", {"__type__": "time", "iso": "14:30:15"}, time),
54
+ (
55
+ "time",
56
+ {"__type__": "time", "iso": "14:30:15", "tzinfo": "Pacific/Honolulu"},
57
+ time,
58
+ ),
59
+ ("decimal", {"__type__": "decimal", "value": "3.14"}, Decimal),
60
+ ("complex", {"__type__": "complex", "real": 3, "imag": 4}, complex),
61
+ ("bytes", {"__type__": "bytes", "value": "test"}, bytes),
62
+ ("set", {"__type__": "set", "values": [1, 2, 3]}, set),
63
+ ],
64
+ )
65
+ def test_complex_type_decoding(
66
+ input_type: str, input_dict: Dict[str, Any], expected_type: Type[Any]
67
+ ) -> None:
68
+ """
69
+ Test decoding of various complex types
70
+ """
71
+ decoded = TypePreservationDecoder.decode(input_dict)
72
+ assert isinstance(decoded, expected_type)
73
+
74
+
75
+ def test_custom_object_decoding() -> None:
76
+ """
77
+ Test decoding of custom objects
78
+ """
79
+ custom_obj_dict = {
80
+ "__type__": "TestCustomObject",
81
+ "__module__": __name__,
82
+ "attributes": {"name": "test", "value": 42},
83
+ }
84
+ decoded = TypePreservationDecoder.decode(custom_obj_dict)
85
+ assert isinstance(decoded, TestCustomObject)
86
+ assert decoded.name == "test"
87
+ assert decoded.value == 42
88
+
89
+
90
+ def test_custom_decoder() -> None:
91
+ """
92
+ Test custom decoder functionality
93
+ """
94
+
95
+ def custom_decoder(data: Dict[str, Any]) -> Any:
96
+ if data.get("__type__") == "special_type":
97
+ return f"Decoded: {data['value']}"
98
+ return data
99
+
100
+ special_dict = {"__type__": "special_type", "value": "test"}
101
+ decoded = TypePreservationDecoder.decode(
102
+ special_dict, custom_decoders={"special_type": custom_decoder}
103
+ )
104
+ assert decoded == "Decoded: test"
105
+
106
+
107
+ def test_nested_datetime_decoding() -> None:
108
+ """
109
+ Test decoding of nested datetime fields
110
+ """
111
+ nested_datetime_dict = {
112
+ "__type__": "TestCustomObject",
113
+ "__module__": __name__,
114
+ "attributes": {
115
+ "name": "test",
116
+ "value": 42,
117
+ "created_at": {"__type__": "datetime", "iso": "2023-06-15T10:30:00"},
118
+ "nested_data": {
119
+ "timestamp": {"__type__": "datetime", "iso": "2023-06-16T15:45:00"}
120
+ },
121
+ },
122
+ }
123
+
124
+ decoded: TestCustomObject = TypePreservationDecoder.decode(nested_datetime_dict)
125
+
126
+ assert isinstance(decoded, TestCustomObject)
127
+ assert decoded.name == "test"
128
+ assert decoded.value == 42
129
+
130
+ # Check nested datetime fields
131
+ assert hasattr(decoded, "created_at")
132
+ assert isinstance(decoded.created_at, datetime)
133
+ assert decoded.created_at.year == 2023
134
+ assert decoded.created_at.month == 6
135
+ assert decoded.created_at.day == 15
136
+
137
+ assert hasattr(decoded, "nested_data")
138
+ assert isinstance(decoded.nested_data, dict)
139
+ assert "timestamp" in decoded.nested_data
140
+ assert isinstance(decoded.nested_data["timestamp"], datetime)
141
+ assert decoded.nested_data["timestamp"].year == 2023
142
+ assert decoded.nested_data["timestamp"].month == 6
143
+ assert decoded.nested_data["timestamp"].day == 16
144
+
145
+
146
+ def test_direct_value_decoding() -> None:
147
+ """
148
+ Test decoding of direct values without type markers
149
+ """
150
+ # Test datetime direct string
151
+ datetime_str = "2023-01-01T00:00:00"
152
+ decoded_datetime = TypePreservationDecoder.decode(datetime_str)
153
+ assert decoded_datetime == datetime_str
154
+
155
+ # Test list with mixed types
156
+ mixed_list = [
157
+ {"__type__": "datetime", "iso": "2023-06-15T10:30:00"},
158
+ 42,
159
+ "plain string",
160
+ ]
161
+ decoded_list = TypePreservationDecoder.decode(mixed_list)
162
+ assert len(decoded_list) == 3
163
+ assert isinstance(decoded_list[0], datetime)
164
+ assert decoded_list[1] == 42
165
+ assert decoded_list[2] == "plain string"
@@ -0,0 +1,71 @@
1
+ import logging
2
+ from datetime import datetime, timezone, date, time
3
+ from decimal import Decimal
4
+ from logging import Logger
5
+ from typing import Type, Any
6
+ from zoneinfo import ZoneInfo
7
+
8
+ import pytest
9
+
10
+ from compressedfhir.utilities.json_serializers.type_preservation_encoder import (
11
+ TypePreservationEncoder,
12
+ )
13
+
14
+
15
+ class TestCustomObject:
16
+ def __init__(self, name: str, value: int):
17
+ self.name: str = name
18
+ self.value: int = value
19
+
20
+ def __eq__(self, other: Any) -> bool:
21
+ if not isinstance(other, TestCustomObject):
22
+ return False
23
+ return self.name == other.name and self.value == other.value
24
+
25
+
26
+ @pytest.mark.parametrize(
27
+ "input_type, input_value, expected_type",
28
+ [
29
+ (datetime, datetime(2023, 1, 1, tzinfo=timezone.utc), "datetime"),
30
+ (
31
+ datetime,
32
+ datetime(2023, 1, 1, tzinfo=ZoneInfo("Pacific/Honolulu")),
33
+ "datetime",
34
+ ),
35
+ (date, date(2023, 1, 1), "date"),
36
+ (time, time(14, 30, 15), "time"),
37
+ (time, time(14, 30, 15, tzinfo=ZoneInfo("Pacific/Honolulu")), "time"),
38
+ (Decimal, Decimal("3.14"), "decimal"),
39
+ (complex, 3 + 4j, "complex"),
40
+ (bytes, b"test", "bytes"),
41
+ (set, {1, 2, 3}, "set"),
42
+ ],
43
+ )
44
+ def test_complex_type_serialization(
45
+ input_type: Type[Any], input_value: Any, expected_type: str
46
+ ) -> None:
47
+ """
48
+ Test serialization of various complex types
49
+ """
50
+ logger: Logger = logging.getLogger(__name__)
51
+ encoder = TypePreservationEncoder()
52
+ serialized = encoder.default(input_value)
53
+
54
+ logger.info(serialized)
55
+ assert isinstance(serialized, dict)
56
+ assert serialized.get("__type__") == expected_type
57
+
58
+
59
+ # noinspection PyMethodMayBeStatic
60
+ def test_custom_object_serialization() -> None:
61
+ """
62
+ Test serialization of custom objects
63
+ """
64
+ custom_obj = TestCustomObject("test", 42)
65
+ encoder = TypePreservationEncoder()
66
+ serialized = encoder.default(custom_obj)
67
+
68
+ assert isinstance(serialized, dict)
69
+ assert serialized.get("__type__") == "TestCustomObject"
70
+ assert serialized.get("__module__") == __name__
71
+ assert "attributes" in serialized
@@ -0,0 +1,197 @@
1
+ import logging
2
+ from collections import OrderedDict
3
+ from datetime import datetime, timezone, date, time
4
+ from decimal import Decimal
5
+ from logging import Logger
6
+ from typing import Any
7
+ from zoneinfo import ZoneInfo
8
+
9
+ from compressedfhir.utilities.json_serializers.type_preservation_serializer import (
10
+ TypePreservationSerializer,
11
+ )
12
+
13
+
14
+ class TestCustomObject:
15
+ def __init__(self, name: str, value: int):
16
+ self.name: str = name
17
+ self.value: int = value
18
+
19
+ def __eq__(self, other: Any) -> bool:
20
+ if not isinstance(other, TestCustomObject):
21
+ return False
22
+ return self.name == other.name and self.value == other.value
23
+
24
+
25
+ def test_complex_data_serialization() -> None:
26
+ """
27
+ Test serialization and deserialization of complex data
28
+ """
29
+ complex_data = {
30
+ "timestamp_no_tz": datetime.now(),
31
+ "timestamp": datetime.now(timezone.utc),
32
+ "timestamp_pst": datetime.now(ZoneInfo("Pacific/Honolulu")),
33
+ "today": date.today(),
34
+ "my_time": time(14, 30, 15),
35
+ "my_time_pst": time(14, 30, 15, tzinfo=ZoneInfo("Pacific/Honolulu")),
36
+ "precise_value": Decimal("3.14159"),
37
+ "complex_number": 3 + 4j,
38
+ "byte_data": b"Hello",
39
+ "unique_items": {1, 2, 3},
40
+ "custom_obj": TestCustomObject("test", 42),
41
+ }
42
+
43
+ # Serialize
44
+ serialized = TypePreservationSerializer.serialize(complex_data)
45
+
46
+ # Deserialize
47
+ deserialized = TypePreservationSerializer.deserialize(serialized)
48
+
49
+ # Verify types
50
+ assert isinstance(deserialized, OrderedDict)
51
+ assert isinstance(deserialized["timestamp_no_tz"], datetime)
52
+ assert deserialized["timestamp_no_tz"] == complex_data["timestamp_no_tz"]
53
+ assert isinstance(deserialized["timestamp"], datetime)
54
+ assert deserialized["timestamp"] == complex_data["timestamp"]
55
+ assert isinstance(deserialized["timestamp_pst"], datetime)
56
+ assert deserialized["timestamp_pst"] == complex_data["timestamp_pst"]
57
+ assert isinstance(deserialized["today"], date)
58
+ assert deserialized["today"] == complex_data["today"]
59
+ assert isinstance(deserialized["my_time"], time)
60
+ assert deserialized["my_time"] == complex_data["my_time"]
61
+ assert isinstance(deserialized["my_time_pst"], time)
62
+ assert deserialized["my_time_pst"] == complex_data["my_time_pst"]
63
+ assert isinstance(deserialized["precise_value"], Decimal)
64
+ assert deserialized["precise_value"] == complex_data["precise_value"]
65
+ assert isinstance(deserialized["complex_number"], complex)
66
+ assert deserialized["complex_number"] == complex_data["complex_number"]
67
+ assert isinstance(deserialized["byte_data"], bytes)
68
+ assert deserialized["byte_data"] == complex_data["byte_data"]
69
+ assert isinstance(deserialized["unique_items"], set)
70
+ assert deserialized["unique_items"] == complex_data["unique_items"]
71
+ assert isinstance(deserialized["custom_obj"], TestCustomObject)
72
+ assert deserialized["custom_obj"] == complex_data["custom_obj"]
73
+
74
+
75
+ def test_nested_complex_data() -> None:
76
+ """
77
+ Test serialization of nested complex data
78
+ """
79
+ nested_data = {"level1": {"level2": {"timestamp": datetime.now(timezone.utc)}}}
80
+
81
+ serialized = TypePreservationSerializer.serialize(nested_data)
82
+ deserialized = TypePreservationSerializer.deserialize(serialized)
83
+
84
+ assert isinstance(deserialized["level1"]["level2"]["timestamp"], datetime)
85
+
86
+
87
+ def test_nested_dict() -> None:
88
+ """
89
+ Test serialization of nested dictionaries
90
+ """
91
+ logger: Logger = logging.getLogger(__name__)
92
+ nested_dict = {
93
+ "resourceType": "Coverage",
94
+ "id": "3456789012345670304",
95
+ "beneficiary": {"reference": "Patient/1234567890123456703", "type": "Patient"},
96
+ "class": [
97
+ {
98
+ "name": "Aetna Plan",
99
+ "type": {
100
+ "coding": [
101
+ {
102
+ "code": "plan",
103
+ "display": "Plan",
104
+ "system": "http://terminology.hl7.org/CodeSystem/coverage-class",
105
+ }
106
+ ]
107
+ },
108
+ "value": "AE303",
109
+ }
110
+ ],
111
+ "costToBeneficiary": [
112
+ {
113
+ "type": {"text": "Annual Physical Exams NMC - In Network"},
114
+ "valueQuantity": {
115
+ "system": "http://aetna.com/Medicare/CostToBeneficiary/ValueQuantity/code",
116
+ "unit": "$",
117
+ "value": 50.0,
118
+ },
119
+ }
120
+ ],
121
+ "identifier": [
122
+ {
123
+ "system": "https://sources.aetna.com/coverage/identifier/membershipid/59",
124
+ "type": {
125
+ "coding": [
126
+ {
127
+ "code": "SN",
128
+ "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
129
+ }
130
+ ]
131
+ },
132
+ "value": "435679010300+AE303+2021-01-01",
133
+ },
134
+ {
135
+ "id": "uuid",
136
+ "system": "https://www.icanbwell.com/uuid",
137
+ "value": "92266603-aa8b-58c6-99bd-326fd1da1896",
138
+ },
139
+ ],
140
+ "meta": {
141
+ "security": [
142
+ {"code": "aetna", "system": "https://www.icanbwell.com/owner"},
143
+ {"code": "aetna", "system": "https://www.icanbwell.com/access"},
144
+ {"code": "aetna", "system": "https://www.icanbwell.com/vendor"},
145
+ {"code": "proa", "system": "https://www.icanbwell.com/connectionType"},
146
+ ],
147
+ "source": "http://mock-server:1080/test_patient_access_transformer/source/4_0_0/Coverage/3456789012345670304",
148
+ },
149
+ "network": "Medicare - MA/NY/NJ - Full Reciprocity",
150
+ "payor": [
151
+ {
152
+ "display": "Aetna",
153
+ "reference": "Organization/6667778889990000015",
154
+ "type": "Organization",
155
+ }
156
+ ],
157
+ "period": {
158
+ "end": datetime.fromisoformat("2021-12-31").date(),
159
+ "start": datetime.fromisoformat("2021-01-01").date(),
160
+ },
161
+ "policyHolder": {"reference": "Patient/1234567890123456703", "type": "Patient"},
162
+ "relationship": {
163
+ "coding": [
164
+ {
165
+ "code": "self",
166
+ "system": "http://terminology.hl7.org/CodeSystem/subscriber-relationship",
167
+ }
168
+ ]
169
+ },
170
+ "status": "active",
171
+ "subscriber": {"reference": "Patient/1234567890123456703", "type": "Patient"},
172
+ "subscriberId": "435679010300",
173
+ "type": {
174
+ "coding": [
175
+ {
176
+ "code": "PPO",
177
+ "display": "preferred provider organization policy",
178
+ "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
179
+ }
180
+ ]
181
+ },
182
+ }
183
+
184
+ logger.info("-------- Serialized --------")
185
+ serialized: str = TypePreservationSerializer.serialize(nested_dict)
186
+ logger.info(serialized)
187
+ logger.info("-------- Deserialized --------")
188
+ deserialized: OrderedDict[str, Any] = TypePreservationSerializer.deserialize(
189
+ serialized
190
+ )
191
+ logger.info(deserialized)
192
+
193
+ assert isinstance(deserialized, OrderedDict)
194
+
195
+ assert isinstance(deserialized["period"]["start"], date)
196
+ assert isinstance(deserialized["period"]["end"], date)
197
+ assert nested_dict == deserialized