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.
- compressedfhir/__init__.py +0 -0
- compressedfhir/fhir/__init__.py +0 -0
- compressedfhir/fhir/base_resource_list.py +165 -0
- compressedfhir/fhir/fhir_bundle.py +295 -0
- compressedfhir/fhir/fhir_bundle_entry.py +240 -0
- compressedfhir/fhir/fhir_bundle_entry_list.py +97 -0
- compressedfhir/fhir/fhir_bundle_entry_request.py +73 -0
- compressedfhir/fhir/fhir_bundle_entry_response.py +67 -0
- compressedfhir/fhir/fhir_bundle_entry_search.py +75 -0
- compressedfhir/fhir/fhir_identifier.py +84 -0
- compressedfhir/fhir/fhir_link.py +63 -0
- compressedfhir/fhir/fhir_meta.py +47 -0
- compressedfhir/fhir/fhir_resource.py +170 -0
- compressedfhir/fhir/fhir_resource_list.py +149 -0
- compressedfhir/fhir/fhir_resource_map.py +193 -0
- compressedfhir/fhir/test/__init__.py +0 -0
- compressedfhir/fhir/test/test_bundle_entry.py +129 -0
- compressedfhir/fhir/test/test_bundle_entry_list.py +187 -0
- compressedfhir/fhir/test/test_bundle_entry_request.py +74 -0
- compressedfhir/fhir/test/test_bundle_entry_response.py +65 -0
- compressedfhir/fhir/test/test_fhir_bundle.py +245 -0
- compressedfhir/fhir/test/test_fhir_resource.py +104 -0
- compressedfhir/fhir/test/test_fhir_resource_list.py +160 -0
- compressedfhir/fhir/test/test_fhir_resource_map.py +293 -0
- compressedfhir/py.typed +0 -0
- compressedfhir/utilities/__init__.py +0 -0
- compressedfhir/utilities/compressed_dict/__init__.py +0 -0
- compressedfhir/utilities/compressed_dict/v1/__init__.py +0 -0
- compressedfhir/utilities/compressed_dict/v1/compressed_dict.py +701 -0
- compressedfhir/utilities/compressed_dict/v1/compressed_dict_access_error.py +2 -0
- compressedfhir/utilities/compressed_dict/v1/compressed_dict_storage_mode.py +50 -0
- compressedfhir/utilities/compressed_dict/v1/test/__init__.py +0 -0
- compressedfhir/utilities/compressed_dict/v1/test/test_compressed_dict.py +467 -0
- compressedfhir/utilities/fhir_json_encoder.py +71 -0
- compressedfhir/utilities/json_helpers.py +181 -0
- compressedfhir/utilities/json_serializers/__init__.py +0 -0
- compressedfhir/utilities/json_serializers/test/__init__.py +0 -0
- compressedfhir/utilities/json_serializers/test/test_type_preservation_decoder.py +165 -0
- compressedfhir/utilities/json_serializers/test/test_type_preservation_encoder.py +71 -0
- compressedfhir/utilities/json_serializers/test/test_type_preservation_serializer.py +197 -0
- compressedfhir/utilities/json_serializers/type_preservation_decoder.py +135 -0
- compressedfhir/utilities/json_serializers/type_preservation_encoder.py +55 -0
- compressedfhir/utilities/json_serializers/type_preservation_serializer.py +57 -0
- compressedfhir/utilities/ordered_dict_to_dict_converter/__init__.py +0 -0
- compressedfhir/utilities/ordered_dict_to_dict_converter/ordered_dict_to_dict_converter.py +24 -0
- compressedfhir/utilities/string_compressor/__init__.py +0 -0
- compressedfhir/utilities/string_compressor/v1/__init__.py +0 -0
- compressedfhir/utilities/string_compressor/v1/string_compressor.py +99 -0
- compressedfhir/utilities/string_compressor/v1/test/__init__.py +0 -0
- compressedfhir/utilities/string_compressor/v1/test/test_string_compressor.py +189 -0
- compressedfhir/utilities/test/__init__.py +0 -0
- compressedfhir/utilities/test/test_fhir_json_encoder.py +177 -0
- compressedfhir/utilities/test/test_json_helpers.py +99 -0
- compressedfhir-3.0.2.dist-info/METADATA +139 -0
- compressedfhir-3.0.2.dist-info/RECORD +59 -0
- compressedfhir-3.0.2.dist-info/WHEEL +5 -0
- compressedfhir-3.0.2.dist-info/licenses/LICENSE +201 -0
- compressedfhir-3.0.2.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
from typing import (
|
|
3
|
+
Deque,
|
|
4
|
+
Optional,
|
|
5
|
+
AsyncGenerator,
|
|
6
|
+
List,
|
|
7
|
+
Any,
|
|
8
|
+
Dict,
|
|
9
|
+
Set,
|
|
10
|
+
override,
|
|
11
|
+
Iterable,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from compressedfhir.fhir.fhir_bundle_entry import FhirBundleEntry
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FhirBundleEntryList(Deque[FhirBundleEntry]):
|
|
18
|
+
"""
|
|
19
|
+
Represents a list of FHIR Bundle entries.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
__slots__: List[str] = ["_keys"]
|
|
23
|
+
|
|
24
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
25
|
+
super().__init__(*args, **kwargs)
|
|
26
|
+
self._keys: Set[str] = set()
|
|
27
|
+
for entry in self:
|
|
28
|
+
key = getattr(entry, "resource_type_and_id", None)
|
|
29
|
+
if key is not None:
|
|
30
|
+
self._keys.add(key)
|
|
31
|
+
|
|
32
|
+
async def consume_resource_async(
|
|
33
|
+
self,
|
|
34
|
+
*,
|
|
35
|
+
batch_size: Optional[int],
|
|
36
|
+
) -> AsyncGenerator["FhirBundleEntryList", None]:
|
|
37
|
+
"""
|
|
38
|
+
Consume bundle entries in batches asynchronously.
|
|
39
|
+
|
|
40
|
+
:param batch_size: The size of each batch.
|
|
41
|
+
:return: An async generator yielding batches of FhirResourceList.
|
|
42
|
+
"""
|
|
43
|
+
if batch_size is None:
|
|
44
|
+
while self:
|
|
45
|
+
yield FhirBundleEntryList([self.popleft()])
|
|
46
|
+
elif batch_size <= 0:
|
|
47
|
+
raise ValueError("Batch size must be greater than 0.")
|
|
48
|
+
else:
|
|
49
|
+
while self:
|
|
50
|
+
batch = FhirBundleEntryList()
|
|
51
|
+
for _ in range(min(batch_size, len(self))):
|
|
52
|
+
batch.append(self.popleft())
|
|
53
|
+
yield batch
|
|
54
|
+
|
|
55
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirBundleEntryList":
|
|
56
|
+
"""
|
|
57
|
+
Create a shallow copy of the FhirBundleEntryList.
|
|
58
|
+
|
|
59
|
+
:return: A new FhirBundleEntryList instance with the same entries.
|
|
60
|
+
"""
|
|
61
|
+
return FhirBundleEntryList([copy.deepcopy(entry) for entry in self])
|
|
62
|
+
|
|
63
|
+
def __repr__(self) -> str:
|
|
64
|
+
"""
|
|
65
|
+
Return a string representation of the FhirBundleEntryList.
|
|
66
|
+
|
|
67
|
+
:return: A string representation of the FhirBundleEntryList.
|
|
68
|
+
"""
|
|
69
|
+
return f"FhirBundleEntryList(entries: {len(self)})"
|
|
70
|
+
|
|
71
|
+
@override
|
|
72
|
+
def append(self, x: FhirBundleEntry, /) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Append an entry to the FhirBundleEntryList.
|
|
75
|
+
|
|
76
|
+
:param x: The entry to append.
|
|
77
|
+
"""
|
|
78
|
+
if not isinstance(x, FhirBundleEntry):
|
|
79
|
+
raise TypeError("Only FhirBundleEntry instances can be appended.")
|
|
80
|
+
|
|
81
|
+
# check that we don't have a duplicate entry
|
|
82
|
+
key: Optional[str] = x.resource_type_and_id
|
|
83
|
+
if key is not None and key in self._keys:
|
|
84
|
+
return
|
|
85
|
+
if key is not None:
|
|
86
|
+
self._keys.add(key)
|
|
87
|
+
super().append(x)
|
|
88
|
+
|
|
89
|
+
@override
|
|
90
|
+
def extend(self, iterable: Iterable[FhirBundleEntry], /) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Extend the FhirBundleEntryList with entries from an iterable.
|
|
93
|
+
|
|
94
|
+
:param iterable: The iterable containing entries to extend.
|
|
95
|
+
"""
|
|
96
|
+
for entry in iterable:
|
|
97
|
+
self.append(entry)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Dict, Optional, OrderedDict
|
|
3
|
+
|
|
4
|
+
from compressedfhir.utilities.json_helpers import FhirClientJsonHelpers
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FhirBundleEntryRequest:
|
|
8
|
+
"""
|
|
9
|
+
FHIR Bundle Entry Request class for encapsulating the request to be sent to FHIR server
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__slots__ = ["url", "method", "ifModifiedSince", "ifNoneMatch", "ifNoneExist"]
|
|
13
|
+
|
|
14
|
+
# noinspection PyPep8Naming
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
*,
|
|
18
|
+
url: str,
|
|
19
|
+
method: str = "GET",
|
|
20
|
+
ifNoneMatch: Optional[str] = None,
|
|
21
|
+
ifModifiedSince: Optional[datetime] = None,
|
|
22
|
+
ifNoneExist: Optional[str] = None,
|
|
23
|
+
) -> None:
|
|
24
|
+
self.url: str = url or "https://example.com"
|
|
25
|
+
self.method: str = method or "GET"
|
|
26
|
+
self.ifModifiedSince: Optional[datetime] = ifModifiedSince
|
|
27
|
+
self.ifNoneMatch: Optional[str] = ifNoneMatch
|
|
28
|
+
self.ifNoneExist: Optional[str] = ifNoneExist
|
|
29
|
+
|
|
30
|
+
def dict(self) -> OrderedDict[str, Any]:
|
|
31
|
+
result: OrderedDict[str, Any] = OrderedDict[str, Any](
|
|
32
|
+
{"url": self.url, "method": self.method}
|
|
33
|
+
)
|
|
34
|
+
if self.ifModifiedSince is not None:
|
|
35
|
+
result["ifModifiedSince"] = self.ifModifiedSince.isoformat()
|
|
36
|
+
if self.ifNoneMatch is not None:
|
|
37
|
+
result["ifNoneMatch"] = self.ifNoneMatch
|
|
38
|
+
if self.ifNoneExist is not None:
|
|
39
|
+
result["ifNoneExist"] = self.ifNoneExist
|
|
40
|
+
return FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(result)
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def from_dict(
|
|
44
|
+
cls, d: Dict[str, Any] | OrderedDict[str, Any]
|
|
45
|
+
) -> "FhirBundleEntryRequest":
|
|
46
|
+
date_if_modified_since: Optional[datetime] = None
|
|
47
|
+
if "ifModifiedSince" in d:
|
|
48
|
+
if isinstance(d["ifModifiedSince"], datetime):
|
|
49
|
+
date_if_modified_since = d["ifModifiedSince"]
|
|
50
|
+
elif isinstance(d["ifModifiedSince"], str):
|
|
51
|
+
date_if_modified_since = datetime.fromisoformat(d["ifModifiedSince"])
|
|
52
|
+
return cls(
|
|
53
|
+
url=d.get("url", "https://example.com"),
|
|
54
|
+
method=d.get("method", "GET"),
|
|
55
|
+
ifModifiedSince=date_if_modified_since,
|
|
56
|
+
ifNoneMatch=d["ifNoneMatch"] if "ifNoneMatch" in d else None,
|
|
57
|
+
ifNoneExist=d["ifNoneExist"] if "ifNoneExist" in d else None,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirBundleEntryRequest":
|
|
61
|
+
return FhirBundleEntryRequest(
|
|
62
|
+
url=self.url,
|
|
63
|
+
method=self.method,
|
|
64
|
+
ifModifiedSince=self.ifModifiedSince,
|
|
65
|
+
ifNoneMatch=self.ifNoneMatch,
|
|
66
|
+
ifNoneExist=self.ifNoneExist,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def __repr__(self) -> str:
|
|
70
|
+
return (
|
|
71
|
+
f"FhirBundleEntryRequest(url={self.url}, method={self.method}, "
|
|
72
|
+
f"ifModifiedSince={self.ifModifiedSince}, ifNoneMatch={self.ifNoneMatch})"
|
|
73
|
+
)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Dict, Optional, OrderedDict
|
|
3
|
+
|
|
4
|
+
from compressedfhir.utilities.json_helpers import FhirClientJsonHelpers
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FhirBundleEntryResponse:
|
|
8
|
+
"""
|
|
9
|
+
FHIR Bundle Entry Response class for encapsulating the response from FHIR server when processing bundle entries
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__slots__ = ["status", "lastModified", "etag", "location"]
|
|
13
|
+
|
|
14
|
+
# noinspection PyPep8Naming
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
*,
|
|
18
|
+
status: str = "200",
|
|
19
|
+
etag: Optional[str] = None,
|
|
20
|
+
lastModified: Optional[datetime] = None,
|
|
21
|
+
location: Optional[str] = None,
|
|
22
|
+
) -> None:
|
|
23
|
+
self.status: str = status or "200"
|
|
24
|
+
if isinstance(status, int):
|
|
25
|
+
self.status = str(status)
|
|
26
|
+
self.lastModified: Optional[datetime] = lastModified
|
|
27
|
+
self.etag: Optional[str] = etag
|
|
28
|
+
self.location: Optional[str] = location
|
|
29
|
+
|
|
30
|
+
def dict(self) -> OrderedDict[str, Any]:
|
|
31
|
+
result: OrderedDict[str, Any] = OrderedDict[str, Any]({"status": self.status})
|
|
32
|
+
if self.lastModified is not None:
|
|
33
|
+
result["lastModified"] = self.lastModified.isoformat()
|
|
34
|
+
if self.etag is not None:
|
|
35
|
+
result["etag"] = self.etag
|
|
36
|
+
if self.location is not None:
|
|
37
|
+
result["location"] = self.location
|
|
38
|
+
return FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(result)
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def from_dict(
|
|
42
|
+
cls, d: Dict[str, Any] | OrderedDict[str, Any]
|
|
43
|
+
) -> "FhirBundleEntryResponse":
|
|
44
|
+
date_last_modified: Optional[datetime] = None
|
|
45
|
+
if "lastModified" in d:
|
|
46
|
+
if isinstance(d["lastModified"], datetime):
|
|
47
|
+
date_last_modified = d["lastModified"]
|
|
48
|
+
elif isinstance(d["lastModified"], str):
|
|
49
|
+
date_last_modified = datetime.fromisoformat(d["lastModified"])
|
|
50
|
+
|
|
51
|
+
return cls(
|
|
52
|
+
status=d["status"] if "status" in d else "200",
|
|
53
|
+
lastModified=date_last_modified,
|
|
54
|
+
etag=d["etag"] if "etag" in d else None,
|
|
55
|
+
location=d["location"] if "location" in d else None,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirBundleEntryResponse":
|
|
59
|
+
return FhirBundleEntryResponse(
|
|
60
|
+
status=self.status,
|
|
61
|
+
lastModified=self.lastModified,
|
|
62
|
+
etag=self.etag,
|
|
63
|
+
location=self.location,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def __repr__(self) -> str:
|
|
67
|
+
return f"FhirBundleEntryResponse(status: {self.status}, lastModified: {self.lastModified}, etag: {self.etag})"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Optional, Dict, Any, OrderedDict
|
|
3
|
+
|
|
4
|
+
from compressedfhir.utilities.fhir_json_encoder import FhirJSONEncoder
|
|
5
|
+
from compressedfhir.utilities.json_helpers import FhirClientJsonHelpers
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FhirBundleEntrySearch:
|
|
9
|
+
"""
|
|
10
|
+
FhirBundleEntrySearch is a class that represents a search entry in a FHIR Bundle.
|
|
11
|
+
It contains the resource, search mode, and search parameters.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__slots__ = ["mode", "score"]
|
|
15
|
+
|
|
16
|
+
def __init__(self, *, mode: Optional[str], score: Optional[float]) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Initializes the FhirBundleEntrySearch with the given parameters.
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
self.mode: Optional[str] = mode
|
|
22
|
+
self.score: Optional[float] = score
|
|
23
|
+
|
|
24
|
+
def dict(self) -> OrderedDict[str, Any]:
|
|
25
|
+
"""
|
|
26
|
+
Converts the FhirBundleEntrySearch instance to a dictionary.
|
|
27
|
+
|
|
28
|
+
:return: A dictionary representation of the FhirBundleEntrySearch instance.
|
|
29
|
+
"""
|
|
30
|
+
result: OrderedDict[str, Any] = OrderedDict[str, Any]()
|
|
31
|
+
if self.mode is not None:
|
|
32
|
+
result["mode"] = self.mode
|
|
33
|
+
if self.score is not None:
|
|
34
|
+
result["score"] = self.score
|
|
35
|
+
|
|
36
|
+
return FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(result)
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def from_dict(
|
|
40
|
+
cls, data: Dict[str, Any] | OrderedDict[str, Any]
|
|
41
|
+
) -> "FhirBundleEntrySearch":
|
|
42
|
+
"""
|
|
43
|
+
Creates a FhirBundleEntrySearch object from a dictionary.
|
|
44
|
+
|
|
45
|
+
:param data: A dictionary containing the search entry data.
|
|
46
|
+
:return: An instance of FhirBundleEntrySearch.
|
|
47
|
+
"""
|
|
48
|
+
return cls(
|
|
49
|
+
mode=data.get("mode"),
|
|
50
|
+
score=data.get("score"),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def to_json(self) -> str:
|
|
54
|
+
"""
|
|
55
|
+
Converts the FhirBundleEntrySearch instance to a JSON string.
|
|
56
|
+
|
|
57
|
+
:return: A JSON string representation of the FhirBundleEntrySearch instance.
|
|
58
|
+
"""
|
|
59
|
+
return json.dumps(self.dict(), cls=FhirJSONEncoder)
|
|
60
|
+
|
|
61
|
+
def __repr__(self) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Returns a string representation of the FhirBundleEntrySearch instance.
|
|
64
|
+
|
|
65
|
+
:return: A string representation of the FhirBundleEntrySearch instance.
|
|
66
|
+
"""
|
|
67
|
+
return f"FhirBundleEntrySearch(mode={self.mode}, score={self.score})"
|
|
68
|
+
|
|
69
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirBundleEntrySearch":
|
|
70
|
+
"""
|
|
71
|
+
Creates a copy of the FhirBundleEntrySearch instance.
|
|
72
|
+
|
|
73
|
+
:return: A new FhirBundleEntrySearch instance with the same attributes.
|
|
74
|
+
"""
|
|
75
|
+
return FhirBundleEntrySearch(mode=self.mode, score=self.score)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Optional, Dict, Any, OrderedDict
|
|
3
|
+
|
|
4
|
+
from compressedfhir.utilities.json_helpers import FhirClientJsonHelpers
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FhirIdentifier:
|
|
8
|
+
"""
|
|
9
|
+
FHIR Identifier class for representing identifiers in FHIR resources.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__slots__ = ["use", "system", "value"]
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
use: Optional[str] = None,
|
|
17
|
+
system: Optional[str] = None,
|
|
18
|
+
value: Optional[str] = None,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Initialize the FhirIdentifier object.
|
|
22
|
+
|
|
23
|
+
:param use: The purpose of the identifier (e.g., official, secondary).
|
|
24
|
+
:param system: The namespace for the identifier.
|
|
25
|
+
:param value: The actual identifier value.
|
|
26
|
+
"""
|
|
27
|
+
self.use: Optional[str] = use
|
|
28
|
+
self.system: Optional[str] = system
|
|
29
|
+
self.value: Optional[str] = value
|
|
30
|
+
|
|
31
|
+
def dict(self) -> OrderedDict[str, Any]:
|
|
32
|
+
"""
|
|
33
|
+
Convert the FhirIdentifier object to a dictionary.
|
|
34
|
+
|
|
35
|
+
:return: A dictionary representation of the FhirIdentifier object.
|
|
36
|
+
"""
|
|
37
|
+
result: OrderedDict[str, Any] = OrderedDict[str, Any]()
|
|
38
|
+
if self.use is not None:
|
|
39
|
+
result["use"] = self.use
|
|
40
|
+
if self.system is not None:
|
|
41
|
+
result["system"] = self.system
|
|
42
|
+
if self.value is not None:
|
|
43
|
+
result["value"] = self.value
|
|
44
|
+
return FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(result)
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def from_dict(
|
|
48
|
+
cls, data: Dict[str, Any] | OrderedDict[str, Any]
|
|
49
|
+
) -> "FhirIdentifier":
|
|
50
|
+
"""
|
|
51
|
+
Create a FhirIdentifier object from a dictionary.
|
|
52
|
+
|
|
53
|
+
:param data: A dictionary containing the identifier data.
|
|
54
|
+
:return: An instance of FhirIdentifier.
|
|
55
|
+
"""
|
|
56
|
+
return cls(
|
|
57
|
+
use=data.get("use"),
|
|
58
|
+
system=data.get("system"),
|
|
59
|
+
value=data.get("value"),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def json(self) -> str:
|
|
63
|
+
"""
|
|
64
|
+
Convert the FhirIdentifier object to a JSON string.
|
|
65
|
+
:return: A JSON string representation of the FhirIdentifier object.
|
|
66
|
+
"""
|
|
67
|
+
return json.dumps(self.dict())
|
|
68
|
+
|
|
69
|
+
def __repr__(self) -> str:
|
|
70
|
+
"""
|
|
71
|
+
Return a string representation of the FhirIdentifier object.
|
|
72
|
+
:return: A string representation of the FhirIdentifier object.
|
|
73
|
+
"""
|
|
74
|
+
return (
|
|
75
|
+
f"FhirIdentifier(use={self.use}, system={self.system}, value={self.value})"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirIdentifier":
|
|
79
|
+
"""
|
|
80
|
+
Create a copy of the FhirIdentifier object.
|
|
81
|
+
|
|
82
|
+
:return: A new FhirIdentifier object with the same attributes.
|
|
83
|
+
"""
|
|
84
|
+
return FhirIdentifier(use=self.use, system=self.system, value=self.value)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any, Dict, OrderedDict
|
|
3
|
+
|
|
4
|
+
from compressedfhir.utilities.fhir_json_encoder import FhirJSONEncoder
|
|
5
|
+
from compressedfhir.utilities.json_helpers import FhirClientJsonHelpers
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FhirLink:
|
|
9
|
+
"""
|
|
10
|
+
Represents a link in a FHIR
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__slots__ = ["url", "relation"]
|
|
14
|
+
|
|
15
|
+
def __init__(self, *, url: str, relation: str) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Initializes a FhirLink instance.
|
|
18
|
+
|
|
19
|
+
:param url: The URL of the link.
|
|
20
|
+
:param relation: The relation type of the link.
|
|
21
|
+
"""
|
|
22
|
+
self.url: str = url
|
|
23
|
+
self.relation: str = relation
|
|
24
|
+
|
|
25
|
+
def dict(self) -> OrderedDict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Converts the FhirLink instance to a dictionary.
|
|
28
|
+
|
|
29
|
+
:return: A dictionary representation of the link.
|
|
30
|
+
"""
|
|
31
|
+
result = OrderedDict[str, Any]({"url": self.url, "relation": self.relation})
|
|
32
|
+
return FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(result)
|
|
33
|
+
|
|
34
|
+
def json(self) -> str:
|
|
35
|
+
"""
|
|
36
|
+
Converts the FhirLink instance to a JSON string.
|
|
37
|
+
|
|
38
|
+
:return: A JSON string representation of the link.
|
|
39
|
+
"""
|
|
40
|
+
return json.dumps(self.dict(), cls=FhirJSONEncoder)
|
|
41
|
+
|
|
42
|
+
def __repr__(self) -> str:
|
|
43
|
+
return f"FhirLink(url={self.url}, relation={self.relation})"
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_dict(cls, data: Dict[str, Any] | OrderedDict[str, Any]) -> "FhirLink":
|
|
47
|
+
"""
|
|
48
|
+
Populates the FhirLink instance from a dictionary.
|
|
49
|
+
|
|
50
|
+
:param data: A dictionary containing the link data.
|
|
51
|
+
"""
|
|
52
|
+
return cls(
|
|
53
|
+
url=data.get("url") or "unknown",
|
|
54
|
+
relation=data.get("relation") or "unknown",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirLink":
|
|
58
|
+
"""
|
|
59
|
+
Creates a copy of the FhirLink instance.
|
|
60
|
+
|
|
61
|
+
:return: A new FhirLink instance with the same attributes.
|
|
62
|
+
"""
|
|
63
|
+
return FhirLink(url=self.url, relation=self.relation)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
from typing import Any, Dict, OrderedDict
|
|
3
|
+
|
|
4
|
+
from compressedfhir.utilities.json_helpers import FhirClientJsonHelpers
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclasses.dataclass(slots=True)
|
|
8
|
+
class FhirMeta:
|
|
9
|
+
"""
|
|
10
|
+
FhirMeta represents the meta information of a FHIR resource.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
version_id: str | None = None
|
|
14
|
+
last_updated: str | None = None
|
|
15
|
+
source: str | None = None
|
|
16
|
+
profile: list[str] | None = None
|
|
17
|
+
security: list[Dict[str, Any]] | None = None
|
|
18
|
+
tag: list[str] | None = None
|
|
19
|
+
|
|
20
|
+
def dict(self) -> OrderedDict[str, Any]:
|
|
21
|
+
result: OrderedDict[str, Any] = OrderedDict[str, Any]()
|
|
22
|
+
if self.version_id is not None:
|
|
23
|
+
result["versionId"] = self.version_id
|
|
24
|
+
if self.last_updated is not None:
|
|
25
|
+
result["lastUpdated"] = self.last_updated
|
|
26
|
+
if self.source is not None:
|
|
27
|
+
result["source"] = self.source
|
|
28
|
+
if self.profile is not None:
|
|
29
|
+
result["profile"] = [p for p in self.profile if p]
|
|
30
|
+
if self.security is not None:
|
|
31
|
+
result["security"] = [
|
|
32
|
+
FhirClientJsonHelpers.remove_empty_elements(s) for s in self.security
|
|
33
|
+
]
|
|
34
|
+
if self.tag is not None:
|
|
35
|
+
result["tag"] = [t for t in self.tag if t]
|
|
36
|
+
return FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(result)
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def from_dict(cls, data: Dict[str, Any]) -> "FhirMeta":
|
|
40
|
+
return cls(
|
|
41
|
+
version_id=data.get("versionId"),
|
|
42
|
+
last_updated=data.get("lastUpdated"),
|
|
43
|
+
source=data.get("source"),
|
|
44
|
+
profile=data.get("profile"),
|
|
45
|
+
security=data.get("security"),
|
|
46
|
+
tag=data.get("tag"),
|
|
47
|
+
)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import json
|
|
3
|
+
from typing import Any, Optional, Dict, List, cast, OrderedDict, override
|
|
4
|
+
|
|
5
|
+
from compressedfhir.fhir.fhir_meta import FhirMeta
|
|
6
|
+
from compressedfhir.utilities.compressed_dict.v1.compressed_dict import (
|
|
7
|
+
CompressedDict,
|
|
8
|
+
)
|
|
9
|
+
from compressedfhir.utilities.compressed_dict.v1.compressed_dict_storage_mode import (
|
|
10
|
+
CompressedDictStorageMode,
|
|
11
|
+
)
|
|
12
|
+
from compressedfhir.utilities.fhir_json_encoder import FhirJSONEncoder
|
|
13
|
+
from compressedfhir.utilities.json_helpers import FhirClientJsonHelpers
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FhirResource(CompressedDict[str, Any]):
|
|
17
|
+
"""
|
|
18
|
+
FhirResource is a class that represents a FHIR resource.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
__slots__ = CompressedDict.__slots__
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
initial_dict: Dict[str, Any] | OrderedDict[str, Any] | None = None,
|
|
26
|
+
*,
|
|
27
|
+
meta: Optional[FhirMeta] = None,
|
|
28
|
+
storage_mode: CompressedDictStorageMode | None = None,
|
|
29
|
+
properties_to_cache: Optional[List[str]] = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
if storage_mode is None:
|
|
32
|
+
storage_mode = CompressedDictStorageMode.default()
|
|
33
|
+
if meta is not None:
|
|
34
|
+
initial_dict = initial_dict or {}
|
|
35
|
+
initial_dict["meta"] = meta.dict()
|
|
36
|
+
super().__init__(
|
|
37
|
+
initial_dict=initial_dict,
|
|
38
|
+
storage_mode=storage_mode,
|
|
39
|
+
properties_to_cache=properties_to_cache or ["resourceType", "id", "meta"],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def construct(cls, **kwargs: Any) -> "FhirResource":
|
|
44
|
+
"""
|
|
45
|
+
Constructs a FhirResource object from keyword arguments.
|
|
46
|
+
|
|
47
|
+
:param kwargs: Keyword arguments to initialize the resource.
|
|
48
|
+
:return: A FhirResource object.
|
|
49
|
+
"""
|
|
50
|
+
return cls(initial_dict=kwargs)
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def resource_type(self) -> Optional[str]:
|
|
54
|
+
"""Get the resource type from the resource dictionary."""
|
|
55
|
+
return self.get("resourceType")
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def resource_type_and_id(self) -> Optional[str]:
|
|
59
|
+
"""Get the resource type and ID from the resource dictionary."""
|
|
60
|
+
return (
|
|
61
|
+
f"{self.resource_type}/{self.id}"
|
|
62
|
+
if self.resource_type and self.id
|
|
63
|
+
else None
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirResource":
|
|
67
|
+
"""Create a copy of the resource."""
|
|
68
|
+
return FhirResource(
|
|
69
|
+
initial_dict=super().raw_dict(),
|
|
70
|
+
storage_mode=self._storage_mode,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def __repr__(self) -> str:
|
|
74
|
+
"""Custom string representation for debugging."""
|
|
75
|
+
return f"FhirResource({self.resource_type}/{self.id})"
|
|
76
|
+
|
|
77
|
+
def copy(self) -> "FhirResource":
|
|
78
|
+
"""
|
|
79
|
+
Creates a copy of the BundleEntry object.
|
|
80
|
+
|
|
81
|
+
:return: A new BundleEntry object with the same attributes.
|
|
82
|
+
"""
|
|
83
|
+
return copy.deepcopy(self)
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def id(self) -> Optional[str]:
|
|
87
|
+
"""Get the ID from the resource dictionary."""
|
|
88
|
+
return self.get("id")
|
|
89
|
+
|
|
90
|
+
@id.setter
|
|
91
|
+
def id(self, value: Optional[str]) -> None:
|
|
92
|
+
"""Set the ID of the Bundle."""
|
|
93
|
+
self["id"] = value
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def meta(self) -> FhirMeta | None:
|
|
97
|
+
"""Get the meta information from the resource dictionary."""
|
|
98
|
+
return (
|
|
99
|
+
FhirMeta.from_dict(cast(Dict[str, Any], self.get("meta")))
|
|
100
|
+
if "meta" in self
|
|
101
|
+
else None
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
@meta.setter
|
|
105
|
+
def meta(self, value: FhirMeta | None) -> None:
|
|
106
|
+
"""Set the meta information of the resource."""
|
|
107
|
+
if value is None:
|
|
108
|
+
self.pop("meta", None)
|
|
109
|
+
else:
|
|
110
|
+
assert isinstance(value, FhirMeta)
|
|
111
|
+
self["meta"] = value.dict()
|
|
112
|
+
|
|
113
|
+
@classmethod
|
|
114
|
+
@override
|
|
115
|
+
def from_json(cls, json_str: str) -> "FhirResource":
|
|
116
|
+
"""
|
|
117
|
+
Creates a FhirResource object from a JSON string.
|
|
118
|
+
|
|
119
|
+
:param json_str: JSON string representing the resource.
|
|
120
|
+
:return: A FhirResource object.
|
|
121
|
+
"""
|
|
122
|
+
return cast(FhirResource, super().from_json(json_str=json_str))
|
|
123
|
+
|
|
124
|
+
@classmethod
|
|
125
|
+
@override
|
|
126
|
+
def from_dict(
|
|
127
|
+
cls,
|
|
128
|
+
d: Dict[str, Any],
|
|
129
|
+
*,
|
|
130
|
+
storage_mode: CompressedDictStorageMode | None = None,
|
|
131
|
+
properties_to_cache: List[str] | None = None,
|
|
132
|
+
) -> "FhirResource":
|
|
133
|
+
"""
|
|
134
|
+
Creates a FhirResource object from a dictionary.
|
|
135
|
+
|
|
136
|
+
:param d: Dictionary representing the resource.
|
|
137
|
+
:param storage_mode: Storage mode for the CompressedDict.
|
|
138
|
+
:param properties_to_cache: List of properties to cache.
|
|
139
|
+
:return: A FhirResource object.
|
|
140
|
+
"""
|
|
141
|
+
if storage_mode is None:
|
|
142
|
+
storage_mode = CompressedDictStorageMode.default()
|
|
143
|
+
return cast(
|
|
144
|
+
FhirResource,
|
|
145
|
+
super().from_dict(
|
|
146
|
+
d=d,
|
|
147
|
+
storage_mode=storage_mode,
|
|
148
|
+
properties_to_cache=properties_to_cache,
|
|
149
|
+
),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
@override
|
|
153
|
+
def json(self) -> str:
|
|
154
|
+
"""Convert the resource to a JSON string."""
|
|
155
|
+
|
|
156
|
+
# working_dict preserves the python types so create a fhir friendly version
|
|
157
|
+
raw_dict: OrderedDict[str, Any] = self.raw_dict()
|
|
158
|
+
|
|
159
|
+
raw_dict = FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(
|
|
160
|
+
raw_dict
|
|
161
|
+
)
|
|
162
|
+
return json.dumps(obj=raw_dict, cls=FhirJSONEncoder)
|
|
163
|
+
|
|
164
|
+
def to_fhir_dict(self) -> Dict[str, Any]:
|
|
165
|
+
"""
|
|
166
|
+
Convert the resource to a FHIR-compliant dictionary.
|
|
167
|
+
|
|
168
|
+
:return: A dictionary representation of the resource.
|
|
169
|
+
"""
|
|
170
|
+
return cast(Dict[str, Any], json.loads(self.json()))
|