compressedfhir 0.0.1__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.

Potentially problematic release.


This version of compressedfhir might be problematic. Click here for more details.

Files changed (41) 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 +291 -0
  5. compressedfhir/fhir/fhir_bundle_entry.py +234 -0
  6. compressedfhir/fhir/fhir_bundle_entry_list.py +82 -0
  7. compressedfhir/fhir/fhir_bundle_entry_request.py +71 -0
  8. compressedfhir/fhir/fhir_bundle_entry_response.py +64 -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 +163 -0
  14. compressedfhir/fhir/fhir_resource_list.py +143 -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 +225 -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 +635 -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 +360 -0
  34. compressedfhir/utilities/fhir_json_encoder.py +30 -0
  35. compressedfhir/utilities/json_helpers.py +181 -0
  36. compressedfhir-0.0.1.dist-info/METADATA +28 -0
  37. compressedfhir-0.0.1.dist-info/RECORD +41 -0
  38. compressedfhir-0.0.1.dist-info/WHEEL +5 -0
  39. compressedfhir-0.0.1.dist-info/licenses/LICENSE +201 -0
  40. compressedfhir-0.0.1.dist-info/top_level.txt +2 -0
  41. tests/__init__.py +0 -0
@@ -0,0 +1,82 @@
1
+ import copy
2
+ from typing import Deque, Optional, AsyncGenerator, List, Any, Dict, override, Iterable
3
+
4
+ from compressedfhir.fhir.fhir_bundle_entry import FhirBundleEntry
5
+
6
+
7
+ class FhirBundleEntryList(Deque[FhirBundleEntry]):
8
+ """
9
+ Represents a list of FHIR Bundle entries.
10
+ """
11
+
12
+ __slots__: List[str] = []
13
+
14
+ async def consume_resource_async(
15
+ self,
16
+ *,
17
+ batch_size: Optional[int],
18
+ ) -> AsyncGenerator["FhirBundleEntryList", None]:
19
+ """
20
+ Consume bundle entries in batches asynchronously.
21
+
22
+ :param batch_size: The size of each batch.
23
+ :return: An async generator yielding batches of FhirResourceList.
24
+ """
25
+ if batch_size is None:
26
+ while self:
27
+ yield FhirBundleEntryList([self.popleft()])
28
+ elif batch_size <= 0:
29
+ raise ValueError("Batch size must be greater than 0.")
30
+ else:
31
+ while self:
32
+ batch = FhirBundleEntryList()
33
+ for _ in range(min(batch_size, len(self))):
34
+ batch.append(self.popleft())
35
+ yield batch
36
+
37
+ def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirBundleEntryList":
38
+ """
39
+ Create a shallow copy of the FhirBundleEntryList.
40
+
41
+ :return: A new FhirBundleEntryList instance with the same entries.
42
+ """
43
+ return FhirBundleEntryList([copy.deepcopy(entry) for entry in self])
44
+
45
+ def __repr__(self) -> str:
46
+ """
47
+ Return a string representation of the FhirBundleEntryList.
48
+
49
+ :return: A string representation of the FhirBundleEntryList.
50
+ """
51
+ return f"FhirBundleEntryList(entries: {len(self)})"
52
+
53
+ @override
54
+ def append(self, x: FhirBundleEntry, /) -> None:
55
+ """
56
+ Append an entry to the FhirBundleEntryList.
57
+
58
+ :param x: The entry to append.
59
+ """
60
+ if not isinstance(x, FhirBundleEntry):
61
+ raise TypeError("Only FhirBundleEntry instances can be appended.")
62
+
63
+ # check that we don't have a duplicate entry
64
+ key: Optional[str] = x.resource_type_and_id
65
+ if key is None:
66
+ super().append(x)
67
+ else:
68
+ for entry in self:
69
+ if entry.resource_type_and_id == key:
70
+ # we have a duplicate entry
71
+ return
72
+ super().append(x)
73
+
74
+ @override
75
+ def extend(self, iterable: Iterable[FhirBundleEntry], /) -> None:
76
+ """
77
+ Extend the FhirBundleEntryList with entries from an iterable.
78
+
79
+ :param iterable: The iterable containing entries to extend.
80
+ """
81
+ for entry in iterable:
82
+ self.append(entry)
@@ -0,0 +1,71 @@
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
+ return cls(
47
+ url=d.get("url", "https://example.com"),
48
+ method=d.get("method", "GET"),
49
+ ifModifiedSince=(
50
+ datetime.fromisoformat(d["ifModifiedSince"])
51
+ if "ifModifiedSince" in d
52
+ else None
53
+ ),
54
+ ifNoneMatch=d["ifNoneMatch"] if "ifNoneMatch" in d else None,
55
+ ifNoneExist=d["ifNoneExist"] if "ifNoneExist" in d else None,
56
+ )
57
+
58
+ def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirBundleEntryRequest":
59
+ return FhirBundleEntryRequest(
60
+ url=self.url,
61
+ method=self.method,
62
+ ifModifiedSince=self.ifModifiedSince,
63
+ ifNoneMatch=self.ifNoneMatch,
64
+ ifNoneExist=self.ifNoneExist,
65
+ )
66
+
67
+ def __repr__(self) -> str:
68
+ return (
69
+ f"FhirBundleEntryRequest(url={self.url}, method={self.method}, "
70
+ f"ifModifiedSince={self.ifModifiedSince}, ifNoneMatch={self.ifNoneMatch})"
71
+ )
@@ -0,0 +1,64 @@
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
+ return cls(
45
+ status=d["status"] if "status" in d else "200",
46
+ lastModified=(
47
+ datetime.fromisoformat(d["lastModified"])
48
+ if "lastModified" in d
49
+ else None
50
+ ),
51
+ etag=d["etag"] if "etag" in d else None,
52
+ location=d["location"] if "location" in d else None,
53
+ )
54
+
55
+ def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirBundleEntryResponse":
56
+ return FhirBundleEntryResponse(
57
+ status=self.status,
58
+ lastModified=self.lastModified,
59
+ etag=self.etag,
60
+ location=self.location,
61
+ )
62
+
63
+ def __repr__(self) -> str:
64
+ 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,163 @@
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 = CompressedDictStorageMode.default(),
29
+ properties_to_cache: Optional[List[str]] = None,
30
+ ) -> None:
31
+ if meta is not None:
32
+ initial_dict = initial_dict or {}
33
+ initial_dict["meta"] = meta.dict()
34
+ super().__init__(
35
+ initial_dict=initial_dict,
36
+ storage_mode=storage_mode,
37
+ properties_to_cache=properties_to_cache or ["resourceType", "id", "meta"],
38
+ )
39
+
40
+ @classmethod
41
+ def construct(cls, **kwargs: Any) -> "FhirResource":
42
+ """
43
+ Constructs a FhirResource object from keyword arguments.
44
+
45
+ :param kwargs: Keyword arguments to initialize the resource.
46
+ :return: A FhirResource object.
47
+ """
48
+ return cls(initial_dict=kwargs)
49
+
50
+ @property
51
+ def resource_type(self) -> Optional[str]:
52
+ """Get the resource type from the resource dictionary."""
53
+ return self.get("resourceType")
54
+
55
+ @property
56
+ def resource_type_and_id(self) -> Optional[str]:
57
+ """Get the resource type and ID from the resource dictionary."""
58
+ return (
59
+ f"{self.resource_type}/{self.id}"
60
+ if self.resource_type and self.id
61
+ else None
62
+ )
63
+
64
+ def json(self) -> str:
65
+ """Convert the resource to a JSON string."""
66
+ return json.dumps(obj=self.dict(), cls=FhirJSONEncoder)
67
+
68
+ @classmethod
69
+ def from_json(cls, json_str: str) -> "FhirResource":
70
+ """
71
+ Create a FhirResource object from a JSON string.
72
+
73
+ :param json_str: The JSON string to convert.
74
+ :return: A FhirResource object.
75
+ """
76
+ data = json.loads(json_str)
77
+ return cls.from_dict(data)
78
+
79
+ def __deepcopy__(self, memo: Dict[int, Any]) -> "FhirResource":
80
+ """Create a copy of the resource."""
81
+ return FhirResource(
82
+ initial_dict=super().dict(),
83
+ storage_mode=self._storage_mode,
84
+ )
85
+
86
+ def __repr__(self) -> str:
87
+ """Custom string representation for debugging."""
88
+ return f"FhirResource({self.resource_type}/{self.id})"
89
+
90
+ def copy(self) -> "FhirResource":
91
+ """
92
+ Creates a copy of the BundleEntry object.
93
+
94
+ :return: A new BundleEntry object with the same attributes.
95
+ """
96
+ return copy.deepcopy(self)
97
+
98
+ @override
99
+ def dict(self, *, remove_nulls: bool = True) -> OrderedDict[str, Any]:
100
+ """
101
+ Converts the FhirResource object to a dictionary.
102
+
103
+ :param remove_nulls: If True, removes None values from the dictionary.
104
+ :return: A dictionary representation of the FhirResource object.
105
+ """
106
+ ordered_dict = super().dict()
107
+ result: OrderedDict[str, Any] = copy.deepcopy(ordered_dict)
108
+ if remove_nulls:
109
+ result = FhirClientJsonHelpers.remove_empty_elements_from_ordered_dict(
110
+ result
111
+ )
112
+
113
+ return result
114
+
115
+ @classmethod
116
+ def from_dict(
117
+ cls,
118
+ d: Dict[str, Any],
119
+ *,
120
+ storage_mode: CompressedDictStorageMode = CompressedDictStorageMode.default(),
121
+ ) -> "FhirResource":
122
+ """
123
+ Creates a FhirResource object from a dictionary.
124
+
125
+ :param d: The dictionary to convert.
126
+ :param storage_mode: The storage mode for the CompressedDict.
127
+ :return: A FhirResource object.
128
+ """
129
+ return cls(initial_dict=d, storage_mode=storage_mode)
130
+
131
+ def remove_nulls(self) -> None:
132
+ """
133
+ Removes None values from the resource dictionary.
134
+ """
135
+ self.replace(value=self.dict(remove_nulls=True))
136
+
137
+ @property
138
+ def id(self) -> Optional[str]:
139
+ """Get the ID from the resource dictionary."""
140
+ return self.get("id")
141
+
142
+ @id.setter
143
+ def id(self, value: Optional[str]) -> None:
144
+ """Set the ID of the Bundle."""
145
+ self["id"] = value
146
+
147
+ @property
148
+ def meta(self) -> FhirMeta | None:
149
+ """Get the meta information from the resource dictionary."""
150
+ return (
151
+ FhirMeta.from_dict(cast(Dict[str, Any], self.get("meta")))
152
+ if "meta" in self
153
+ else None
154
+ )
155
+
156
+ @meta.setter
157
+ def meta(self, value: FhirMeta | None) -> None:
158
+ """Set the meta information of the resource."""
159
+ if value is None:
160
+ self.pop("meta", None)
161
+ else:
162
+ assert isinstance(value, FhirMeta)
163
+ self["meta"] = value.dict()