helix.fhir.client.sdk 4.2.3__py3-none-any.whl → 4.2.19__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.
- helix_fhir_client_sdk/fhir_auth_mixin.py +17 -10
- helix_fhir_client_sdk/fhir_client.py +152 -79
- helix_fhir_client_sdk/fhir_delete_mixin.py +62 -48
- helix_fhir_client_sdk/fhir_merge_mixin.py +188 -166
- helix_fhir_client_sdk/fhir_merge_resources_mixin.py +200 -15
- helix_fhir_client_sdk/fhir_patch_mixin.py +97 -84
- helix_fhir_client_sdk/fhir_update_mixin.py +71 -57
- helix_fhir_client_sdk/graph/simulated_graph_processor_mixin.py +147 -49
- helix_fhir_client_sdk/open_telemetry/__init__.py +0 -0
- helix_fhir_client_sdk/open_telemetry/attribute_names.py +7 -0
- helix_fhir_client_sdk/open_telemetry/span_names.py +12 -0
- helix_fhir_client_sdk/queue/request_queue_mixin.py +17 -12
- helix_fhir_client_sdk/responses/fhir_client_protocol.py +10 -6
- helix_fhir_client_sdk/responses/fhir_get_response.py +3 -4
- helix_fhir_client_sdk/responses/fhir_response_processor.py +73 -54
- helix_fhir_client_sdk/responses/get/fhir_get_bundle_response.py +49 -28
- helix_fhir_client_sdk/responses/get/fhir_get_error_response.py +0 -1
- helix_fhir_client_sdk/responses/get/fhir_get_list_by_resource_type_response.py +1 -1
- helix_fhir_client_sdk/responses/get/fhir_get_list_response.py +1 -1
- helix_fhir_client_sdk/responses/get/fhir_get_response_factory.py +0 -1
- helix_fhir_client_sdk/responses/get/fhir_get_single_response.py +1 -1
- helix_fhir_client_sdk/responses/merge/fhir_merge_resource_response_entry.py +30 -0
- helix_fhir_client_sdk/responses/resource_separator.py +35 -40
- helix_fhir_client_sdk/utilities/cache/request_cache.py +32 -43
- helix_fhir_client_sdk/utilities/retryable_aiohttp_client.py +185 -154
- helix_fhir_client_sdk/utilities/retryable_aiohttp_response.py +2 -1
- helix_fhir_client_sdk/validators/async_fhir_validator.py +3 -0
- helix_fhir_client_sdk-4.2.19.dist-info/METADATA +200 -0
- {helix_fhir_client_sdk-4.2.3.dist-info → helix_fhir_client_sdk-4.2.19.dist-info}/RECORD +36 -29
- tests/async/test_benchmark_compress.py +448 -0
- tests/async/test_benchmark_merge.py +506 -0
- tests/async/test_retryable_client_session_management.py +159 -0
- tests/test_fhir_client_clone.py +155 -0
- helix_fhir_client_sdk-4.2.3.dist-info/METADATA +0 -115
- {helix_fhir_client_sdk-4.2.3.dist-info → helix_fhir_client_sdk-4.2.19.dist-info}/WHEEL +0 -0
- {helix_fhir_client_sdk-4.2.3.dist-info → helix_fhir_client_sdk-4.2.19.dist-info}/licenses/LICENSE +0 -0
- {helix_fhir_client_sdk-4.2.3.dist-info → helix_fhir_client_sdk-4.2.19.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for FhirClient.clone() method to ensure all properties are properly copied.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import UTC, datetime, timedelta
|
|
6
|
+
|
|
7
|
+
from compressedfhir.utilities.compressed_dict.v1.compressed_dict_storage_mode import (
|
|
8
|
+
CompressedDictStorageMode,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from helix_fhir_client_sdk.fhir_client import FhirClient
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_clone_preserves_compress_setting() -> None:
|
|
15
|
+
"""Test that clone() preserves the _compress setting"""
|
|
16
|
+
# Create a client with compression disabled
|
|
17
|
+
fhir_client = FhirClient().url("http://example.com").compress(False)
|
|
18
|
+
assert fhir_client._compress is False
|
|
19
|
+
|
|
20
|
+
# Clone and verify compression is still disabled
|
|
21
|
+
cloned_client = fhir_client.clone()
|
|
22
|
+
assert cloned_client._compress is False
|
|
23
|
+
|
|
24
|
+
# Test with compression enabled
|
|
25
|
+
fhir_client2 = FhirClient().url("http://example.com").compress(True)
|
|
26
|
+
assert fhir_client2._compress is True
|
|
27
|
+
|
|
28
|
+
cloned_client2 = fhir_client2.clone()
|
|
29
|
+
assert cloned_client2._compress is True
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_clone_preserves_storage_mode() -> None:
|
|
33
|
+
"""Test that clone() preserves the _storage_mode setting"""
|
|
34
|
+
# Create a client with msgpack storage mode
|
|
35
|
+
storage_mode = CompressedDictStorageMode(storage_type="msgpack")
|
|
36
|
+
fhir_client = FhirClient().url("http://example.com").set_storage_mode(storage_mode)
|
|
37
|
+
assert fhir_client._storage_mode.storage_type == "msgpack"
|
|
38
|
+
|
|
39
|
+
# Clone and verify storage mode is preserved
|
|
40
|
+
cloned_client = fhir_client.clone()
|
|
41
|
+
assert cloned_client._storage_mode.storage_type == "msgpack"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_clone_preserves_additional_settings() -> None:
|
|
45
|
+
"""Test that clone() preserves other compression-related settings"""
|
|
46
|
+
fhir_client = (
|
|
47
|
+
FhirClient()
|
|
48
|
+
.url("http://example.com")
|
|
49
|
+
.compress(False)
|
|
50
|
+
.send_data_as_chunked(True)
|
|
51
|
+
.use_post_for_search(True)
|
|
52
|
+
.maximum_time_to_retry_on_429(120)
|
|
53
|
+
.retry_count(5)
|
|
54
|
+
.throw_exception_on_error(False)
|
|
55
|
+
.set_log_all_response_urls(True)
|
|
56
|
+
.set_create_operation_outcome_for_error(True)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
cloned_client = fhir_client.clone()
|
|
60
|
+
|
|
61
|
+
assert cloned_client._compress is False
|
|
62
|
+
assert cloned_client._send_data_as_chunked is True
|
|
63
|
+
assert cloned_client._use_post_for_search is True
|
|
64
|
+
assert cloned_client._maximum_time_to_retry_on_429 == 120
|
|
65
|
+
assert cloned_client._retry_count == 5
|
|
66
|
+
assert cloned_client._throw_exception_on_error is False
|
|
67
|
+
assert cloned_client._log_all_response_urls is True
|
|
68
|
+
assert cloned_client._create_operation_outcome_for_error is True
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_default_compression_is_enabled() -> None:
|
|
72
|
+
"""Test that compression is enabled by default"""
|
|
73
|
+
fhir_client = FhirClient()
|
|
74
|
+
assert fhir_client._compress is True
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_default_storage_mode_is_raw() -> None:
|
|
78
|
+
"""Test that the default storage mode is 'raw'"""
|
|
79
|
+
fhir_client = FhirClient()
|
|
80
|
+
assert fhir_client._storage_mode.storage_type == "raw"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_clone_preserves_access_token() -> None:
|
|
84
|
+
"""Test that clone() preserves access token and expiry date"""
|
|
85
|
+
expiry_date = datetime.now(UTC) + timedelta(hours=1)
|
|
86
|
+
fhir_client = (
|
|
87
|
+
FhirClient()
|
|
88
|
+
.url("http://example.com")
|
|
89
|
+
.set_access_token("test-access-token-12345")
|
|
90
|
+
.set_access_token_expiry_date(expiry_date)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
assert fhir_client._access_token == "test-access-token-12345"
|
|
94
|
+
assert fhir_client._access_token_expiry_date == expiry_date
|
|
95
|
+
|
|
96
|
+
# Clone and verify access token is preserved
|
|
97
|
+
cloned_client = fhir_client.clone()
|
|
98
|
+
|
|
99
|
+
assert cloned_client._access_token == "test-access-token-12345"
|
|
100
|
+
assert cloned_client._access_token_expiry_date == expiry_date
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_clone_preserves_max_concurrent_requests() -> None:
|
|
104
|
+
"""Test that clone() preserves max_concurrent_requests setting"""
|
|
105
|
+
fhir_client = FhirClient().url("http://example.com").set_max_concurrent_requests(10)
|
|
106
|
+
|
|
107
|
+
assert fhir_client._max_concurrent_requests == 10
|
|
108
|
+
|
|
109
|
+
# Clone and verify max_concurrent_requests is preserved
|
|
110
|
+
cloned_client = fhir_client.clone()
|
|
111
|
+
|
|
112
|
+
assert cloned_client._max_concurrent_requests == 10
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_use_http_session() -> None:
|
|
116
|
+
"""Test that use_http_session sets the callable correctly"""
|
|
117
|
+
from aiohttp import ClientSession
|
|
118
|
+
|
|
119
|
+
def custom_session_factory() -> ClientSession:
|
|
120
|
+
return ClientSession()
|
|
121
|
+
|
|
122
|
+
fhir_client = FhirClient().url("http://example.com")
|
|
123
|
+
|
|
124
|
+
# Initially None
|
|
125
|
+
assert fhir_client._fn_create_http_session is None
|
|
126
|
+
|
|
127
|
+
# Set the callable
|
|
128
|
+
result = fhir_client.use_http_session(custom_session_factory)
|
|
129
|
+
|
|
130
|
+
# Returns self for chaining
|
|
131
|
+
assert result is fhir_client
|
|
132
|
+
|
|
133
|
+
# Callable is stored
|
|
134
|
+
assert fhir_client._fn_create_http_session is custom_session_factory
|
|
135
|
+
|
|
136
|
+
# Can set to None
|
|
137
|
+
fhir_client.use_http_session(None)
|
|
138
|
+
assert fhir_client._fn_create_http_session is None
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_clone_preserves_fn_create_http_session() -> None:
|
|
142
|
+
"""Test that clone() preserves the _fn_create_http_session callable"""
|
|
143
|
+
from aiohttp import ClientSession
|
|
144
|
+
|
|
145
|
+
def custom_session_factory() -> ClientSession:
|
|
146
|
+
return ClientSession()
|
|
147
|
+
|
|
148
|
+
fhir_client = FhirClient().url("http://example.com").use_http_session(custom_session_factory)
|
|
149
|
+
|
|
150
|
+
assert fhir_client._fn_create_http_session is custom_session_factory
|
|
151
|
+
|
|
152
|
+
# Clone and verify fn_create_http_session is preserved
|
|
153
|
+
cloned_client = fhir_client.clone()
|
|
154
|
+
|
|
155
|
+
assert cloned_client._fn_create_http_session is custom_session_factory
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: helix.fhir.client.sdk
|
|
3
|
-
Version: 4.2.3
|
|
4
|
-
Summary: helix.fhir.client.sdk
|
|
5
|
-
Home-page: https://github.com/icanbwell/helix.fhir.client.sdk
|
|
6
|
-
Author: Imran Qureshi
|
|
7
|
-
Author-email: imran@icanbwell.com
|
|
8
|
-
Classifier: Development Status :: 4 - Beta
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.10
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: furl
|
|
16
|
-
Requires-Dist: requests
|
|
17
|
-
Requires-Dist: urllib3
|
|
18
|
-
Requires-Dist: chardet
|
|
19
|
-
Requires-Dist: aiohttp
|
|
20
|
-
Requires-Dist: async-timeout>=4.0.3
|
|
21
|
-
Requires-Dist: python-dateutil
|
|
22
|
-
Requires-Dist: compressedfhir>=1.0.3
|
|
23
|
-
Dynamic: author
|
|
24
|
-
Dynamic: author-email
|
|
25
|
-
Dynamic: classifier
|
|
26
|
-
Dynamic: description
|
|
27
|
-
Dynamic: description-content-type
|
|
28
|
-
Dynamic: home-page
|
|
29
|
-
Dynamic: license-file
|
|
30
|
-
Dynamic: requires-dist
|
|
31
|
-
Dynamic: requires-python
|
|
32
|
-
Dynamic: summary
|
|
33
|
-
|
|
34
|
-
# helix.fhir.client.sdk
|
|
35
|
-
|
|
36
|
-
<p align="left">
|
|
37
|
-
<a href="https://github.com/icanbwell/helix.fhir.client.sdk/actions">
|
|
38
|
-
<img src="https://github.com/icanbwell/helix.fhir.client.sdk/workflows/Build%20and%20Test/badge.svg"
|
|
39
|
-
alt="Continuous Integration">
|
|
40
|
-
</a>
|
|
41
|
-
<a href="https://github.com/icanbwell/helix.fhir.client.sdk/releases/latest">
|
|
42
|
-
<img src="https://img.shields.io/github/v/release/icanbwell/helix.fhir.client.sdk?display_name=tag"
|
|
43
|
-
alt="Latest Release">
|
|
44
|
-
</a>
|
|
45
|
-
<a href="https://github.com/icanbwell/helix.fhir.client.sdk/blob/main/LICENSE">
|
|
46
|
-
<img src="https://img.shields.io/badge/license-Apache%202-blue"
|
|
47
|
-
alt="GitHub license">
|
|
48
|
-
</a>
|
|
49
|
-
</p>
|
|
50
|
-
|
|
51
|
-
Fluent API to call the FHIR server that handles:
|
|
52
|
-
|
|
53
|
-
1. Authentication to FHIR server
|
|
54
|
-
2. Renewing access token when they expire
|
|
55
|
-
3. Retry when there are transient errors
|
|
56
|
-
4. Un-bundling the resources received from FHIR server
|
|
57
|
-
5. Paging
|
|
58
|
-
6. Streaming
|
|
59
|
-
7. Logging
|
|
60
|
-
8. Simulating a $graph call when the server does not support it
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# Usage
|
|
64
|
-
`pip install helix.fhir.client.sdk`
|
|
65
|
-
|
|
66
|
-
# Documentation
|
|
67
|
-
https://icanbwell.github.io/helix.fhir.client.sdk/
|
|
68
|
-
|
|
69
|
-
# Test Project using this
|
|
70
|
-
https://github.com/icanbwell/fhir-server-performance
|
|
71
|
-
|
|
72
|
-
# Python Version Support
|
|
73
|
-
* 1.x supports python 3.7+
|
|
74
|
-
* 2.x supports python 3.10+
|
|
75
|
-
* 3.x supports python 3.12+
|
|
76
|
-
|
|
77
|
-
# Asynchronous Support
|
|
78
|
-
When communicating with FHIR servers, a lot of time is spent waiting for the server to respond.
|
|
79
|
-
This is a good use case for using asynchronous programming.
|
|
80
|
-
This SDK supports asynchronous programming using the `async` and `await` keywords.
|
|
81
|
-
|
|
82
|
-
The return types are Python AsyncGenerators. Python makes it very easy to work with AsyncGenerators.
|
|
83
|
-
|
|
84
|
-
For example, if the SDK provides a function like this:
|
|
85
|
-
```python
|
|
86
|
-
|
|
87
|
-
async def get_resources(self) -> AsyncGenerator[FhirGetResponse, None]:
|
|
88
|
-
...
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
You can iterate over the results as they become available:
|
|
92
|
-
```python
|
|
93
|
-
response: Optional[FhirGetResponse]
|
|
94
|
-
async for response in client.get_resources():
|
|
95
|
-
print(response.resource)
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Or you can get a list of responses (which will return AFTER all the responses are received:
|
|
99
|
-
```python
|
|
100
|
-
|
|
101
|
-
responses: List[FhirGetResponse] = [response async for response in client.get_resources()]
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Or you can aggregate the responses into one response (which will return AFTER all the responses are received:
|
|
105
|
-
```python
|
|
106
|
-
|
|
107
|
-
response: Optional[FhirGetResponse] = await FhirGetResponse.from_async_generator(client.get_resources())
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
# Data Streaming
|
|
111
|
-
For FHIR servers that support data streaming (e.g., b.well FHIR server), you can just set the `use_data_streaming` parameter to stream the data as it i received.
|
|
112
|
-
The data will be streamed in AsyncGenerators as described above.
|
|
113
|
-
|
|
114
|
-
# Storage Compression
|
|
115
|
-
The FHIR client SDK natively stores the FHIR resources compressed in memory. This allows use in environments where you are processing large number of FHIR resources.
|
|
File without changes
|
{helix_fhir_client_sdk-4.2.3.dist-info → helix_fhir_client_sdk-4.2.19.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{helix_fhir_client_sdk-4.2.3.dist-info → helix_fhir_client_sdk-4.2.19.dist-info}/top_level.txt
RENAMED
|
File without changes
|