helix.fhir.client.sdk 4.2.6__py3-none-any.whl → 4.2.8__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 +2 -0
- helix_fhir_client_sdk/fhir_client.py +0 -18
- helix_fhir_client_sdk/fhir_delete_mixin.py +1 -2
- helix_fhir_client_sdk/fhir_merge_mixin.py +0 -2
- helix_fhir_client_sdk/fhir_merge_resources_mixin.py +1 -199
- helix_fhir_client_sdk/fhir_patch_mixin.py +0 -2
- helix_fhir_client_sdk/fhir_update_mixin.py +0 -2
- helix_fhir_client_sdk/graph/simulated_graph_processor_mixin.py +0 -23
- helix_fhir_client_sdk/queue/request_queue_mixin.py +0 -4
- helix_fhir_client_sdk/responses/fhir_client_protocol.py +0 -2
- helix_fhir_client_sdk/responses/merge/fhir_merge_resource_response_entry.py +0 -28
- helix_fhir_client_sdk/utilities/retryable_aiohttp_client.py +4 -7
- {helix_fhir_client_sdk-4.2.6.dist-info → helix_fhir_client_sdk-4.2.8.dist-info}/METADATA +1 -1
- {helix_fhir_client_sdk-4.2.6.dist-info → helix_fhir_client_sdk-4.2.8.dist-info}/RECORD +17 -17
- {helix_fhir_client_sdk-4.2.6.dist-info → helix_fhir_client_sdk-4.2.8.dist-info}/WHEEL +0 -0
- {helix_fhir_client_sdk-4.2.6.dist-info → helix_fhir_client_sdk-4.2.8.dist-info}/licenses/LICENSE +0 -0
- {helix_fhir_client_sdk-4.2.6.dist-info → helix_fhir_client_sdk-4.2.8.dist-info}/top_level.txt +0 -0
|
@@ -180,6 +180,7 @@ class FhirAuthMixin(FhirClientProtocol):
|
|
|
180
180
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
181
181
|
refresh_token_func=self._refresh_token_function,
|
|
182
182
|
tracer_request_func=self._trace_request_function,
|
|
183
|
+
persistent_session=self._persistent_session,
|
|
183
184
|
) as client:
|
|
184
185
|
if self._auth_wellknown_url:
|
|
185
186
|
host_name: str = furl(self._auth_wellknown_url).host
|
|
@@ -281,6 +282,7 @@ class FhirAuthMixin(FhirClientProtocol):
|
|
|
281
282
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
282
283
|
refresh_token_func=self._refresh_token_function,
|
|
283
284
|
tracer_request_func=self._trace_request_function,
|
|
285
|
+
persistent_session=self._persistent_session,
|
|
284
286
|
) as client:
|
|
285
287
|
response: RetryableAioHttpResponse = await client.post(url=auth_server_url, headers=headers, data=payload)
|
|
286
288
|
# token = response.text.encode('utf8')
|
|
@@ -480,24 +480,6 @@ class FhirClient(
|
|
|
480
480
|
self._persistent_session = session
|
|
481
481
|
return self
|
|
482
482
|
|
|
483
|
-
def use_persistent_session(self, value: bool) -> FhirClient:
|
|
484
|
-
"""
|
|
485
|
-
Sets the use_persistent_session flag
|
|
486
|
-
|
|
487
|
-
:param value: whether to use the persistent session
|
|
488
|
-
"""
|
|
489
|
-
self._use_persistent_session = value
|
|
490
|
-
return self
|
|
491
|
-
|
|
492
|
-
def close_session_after_request(self, value: bool) -> FhirClient:
|
|
493
|
-
"""
|
|
494
|
-
Sets the _close_session flag (default is True)
|
|
495
|
-
|
|
496
|
-
:param value: whether to close the session after each request
|
|
497
|
-
"""
|
|
498
|
-
self._close_session = value
|
|
499
|
-
return self
|
|
500
|
-
|
|
501
483
|
# noinspection PyUnusedLocal
|
|
502
484
|
@staticmethod
|
|
503
485
|
async def on_request_end(
|
|
@@ -57,8 +57,6 @@ class FhirDeleteMixin(FhirClientProtocol):
|
|
|
57
57
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
58
58
|
tracer_request_func=self._trace_request_function,
|
|
59
59
|
persistent_session=self._persistent_session,
|
|
60
|
-
use_persistent_session=self._use_persistent_session,
|
|
61
|
-
close_session_on_exit=self._close_session,
|
|
62
60
|
) as client:
|
|
63
61
|
response: RetryableAioHttpResponse = await client.delete(url=full_uri.tostr(), headers=headers)
|
|
64
62
|
request_id = response.response_headers.get("X-Request-ID", None)
|
|
@@ -128,6 +126,7 @@ class FhirDeleteMixin(FhirClientProtocol):
|
|
|
128
126
|
access_token=self._access_token,
|
|
129
127
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
130
128
|
tracer_request_func=self._trace_request_function,
|
|
129
|
+
persistent_session=self._persistent_session,
|
|
131
130
|
) as client:
|
|
132
131
|
response: RetryableAioHttpResponse = await client.delete(url=full_url, headers=headers)
|
|
133
132
|
request_id = response.response_headers.get("X-Request-ID", None)
|
|
@@ -182,8 +182,6 @@ class FhirMergeMixin(FhirClientProtocol):
|
|
|
182
182
|
access_token=self._access_token,
|
|
183
183
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
184
184
|
persistent_session=self._persistent_session,
|
|
185
|
-
use_persistent_session=self._use_persistent_session,
|
|
186
|
-
close_session_on_exit=self._close_session,
|
|
187
185
|
) as client:
|
|
188
186
|
# should we check if it exists and do a POST then?
|
|
189
187
|
response: RetryableAioHttpResponse = await client.post(
|
|
@@ -3,7 +3,7 @@ import time
|
|
|
3
3
|
from collections import deque
|
|
4
4
|
from collections.abc import AsyncGenerator
|
|
5
5
|
from typing import (
|
|
6
|
-
cast,
|
|
6
|
+
cast,
|
|
7
7
|
)
|
|
8
8
|
from urllib import parse
|
|
9
9
|
|
|
@@ -45,200 +45,6 @@ from helix_fhir_client_sdk.validators.async_fhir_validator import AsyncFhirValid
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
class FhirMergeResourcesMixin(FhirClientProtocol):
|
|
48
|
-
async def merge_bundle_without_storage(
|
|
49
|
-
self,
|
|
50
|
-
id_: str | None,
|
|
51
|
-
bundle: FhirBundle,
|
|
52
|
-
) -> FhirMergeResourceResponse:
|
|
53
|
-
"""
|
|
54
|
-
Optimized version of merge_bundle_async without storage_mode overhead.
|
|
55
|
-
Calls $merge function on FHIR server with minimal processing.
|
|
56
|
-
|
|
57
|
-
:param id_: id of the resource to merge
|
|
58
|
-
:param bundle: FHIR Bundle to merge
|
|
59
|
-
:return: FhirMergeResourceResponse
|
|
60
|
-
"""
|
|
61
|
-
# Initialize profiling dictionary
|
|
62
|
-
profiling: dict[str, float] = {
|
|
63
|
-
"total_time": 0.0,
|
|
64
|
-
"build_url": 0.0,
|
|
65
|
-
"get_access_token": 0.0,
|
|
66
|
-
"prepare_payload": 0.0,
|
|
67
|
-
"http_post": 0.0,
|
|
68
|
-
"parse_response": 0.0,
|
|
69
|
-
"create_response_objects": 0.0,
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
merge_start_time = time.time()
|
|
73
|
-
|
|
74
|
-
assert self._url, "No FHIR server url was set"
|
|
75
|
-
assert isinstance(bundle, FhirBundle), f"Expected FhirBundle, got {type(bundle)}"
|
|
76
|
-
assert len(bundle.entry) > 0, "Bundle must have at least one entry"
|
|
77
|
-
|
|
78
|
-
request_id: str | None = None
|
|
79
|
-
response_status: int = 500
|
|
80
|
-
|
|
81
|
-
# Build URL
|
|
82
|
-
build_url_start = time.time()
|
|
83
|
-
full_uri: furl = furl(self._url)
|
|
84
|
-
assert self._resource
|
|
85
|
-
full_uri /= self._resource
|
|
86
|
-
|
|
87
|
-
# Prepare headers
|
|
88
|
-
headers = {"Content-Type": "application/fhir+json"}
|
|
89
|
-
headers.update(self._additional_request_headers)
|
|
90
|
-
profiling["build_url"] = time.time() - build_url_start
|
|
91
|
-
|
|
92
|
-
# Get access token
|
|
93
|
-
get_token_start = time.time()
|
|
94
|
-
access_token_result: GetAccessTokenResult = await self.get_access_token_async()
|
|
95
|
-
access_token: str | None = access_token_result.access_token
|
|
96
|
-
if access_token:
|
|
97
|
-
headers["Authorization"] = f"Bearer {access_token}"
|
|
98
|
-
profiling["get_access_token"] = time.time() - get_token_start
|
|
99
|
-
|
|
100
|
-
# Prepare JSON payload
|
|
101
|
-
prepare_payload_start = time.time()
|
|
102
|
-
first_resource: FhirResource | None = bundle.entry[0].resource
|
|
103
|
-
assert first_resource is not None
|
|
104
|
-
json_payload: str = first_resource.json() if len(bundle.entry) == 1 else bundle.json()
|
|
105
|
-
|
|
106
|
-
# Build merge URL
|
|
107
|
-
obj_id: str = id_ or "1"
|
|
108
|
-
resource_uri: furl = full_uri / parse.quote(str(obj_id), safe="") / "$merge"
|
|
109
|
-
profiling["prepare_payload"] = time.time() - prepare_payload_start
|
|
110
|
-
|
|
111
|
-
response_text: str | None = None
|
|
112
|
-
responses: list[dict[str, Any]] = []
|
|
113
|
-
errors: list[dict[str, Any]] = []
|
|
114
|
-
|
|
115
|
-
try:
|
|
116
|
-
async with RetryableAioHttpClient(
|
|
117
|
-
fn_get_session=lambda: self.create_http_session(),
|
|
118
|
-
refresh_token_func=self._refresh_token_function,
|
|
119
|
-
tracer_request_func=self._trace_request_function,
|
|
120
|
-
retries=self._retry_count,
|
|
121
|
-
exclude_status_codes_from_retry=self._exclude_status_codes_from_retry,
|
|
122
|
-
use_data_streaming=self._use_data_streaming,
|
|
123
|
-
send_data_as_chunked=self._send_data_as_chunked,
|
|
124
|
-
compress=self._compress,
|
|
125
|
-
throw_exception_on_error=self._throw_exception_on_error,
|
|
126
|
-
log_all_url_results=self._log_all_response_urls,
|
|
127
|
-
access_token=self._access_token,
|
|
128
|
-
access_token_expiry_date=self._access_token_expiry_date,
|
|
129
|
-
persistent_session=self._persistent_session,
|
|
130
|
-
use_persistent_session=self._use_persistent_session,
|
|
131
|
-
close_session_on_exit=self._close_session,
|
|
132
|
-
) as client:
|
|
133
|
-
http_post_start = time.time()
|
|
134
|
-
response: RetryableAioHttpResponse = await client.post(
|
|
135
|
-
url=resource_uri.url,
|
|
136
|
-
data=json_payload,
|
|
137
|
-
headers=headers,
|
|
138
|
-
)
|
|
139
|
-
profiling["http_post"] = time.time() - http_post_start
|
|
140
|
-
|
|
141
|
-
response_status = response.status
|
|
142
|
-
request_id = response.response_headers.get("X-Request-ID", None)
|
|
143
|
-
|
|
144
|
-
parse_response_start = time.time()
|
|
145
|
-
if response.status == 200:
|
|
146
|
-
response_text = await response.get_text_async()
|
|
147
|
-
if response_text:
|
|
148
|
-
try:
|
|
149
|
-
# Parse response as plain dicts for speed
|
|
150
|
-
parsed_response = json.loads(response_text)
|
|
151
|
-
if isinstance(parsed_response, list):
|
|
152
|
-
responses = parsed_response
|
|
153
|
-
else:
|
|
154
|
-
responses = [parsed_response]
|
|
155
|
-
except (ValueError, json.JSONDecodeError) as e:
|
|
156
|
-
errors.append({
|
|
157
|
-
"issue": [{
|
|
158
|
-
"severity": "error",
|
|
159
|
-
"code": "exception",
|
|
160
|
-
"diagnostics": f"Failed to parse response: {str(e)}"
|
|
161
|
-
}]
|
|
162
|
-
})
|
|
163
|
-
else:
|
|
164
|
-
# HTTP error
|
|
165
|
-
response_text = await response.get_text_async()
|
|
166
|
-
errors.append({
|
|
167
|
-
"issue": [{
|
|
168
|
-
"severity": "error",
|
|
169
|
-
"code": "exception",
|
|
170
|
-
"diagnostics": response_text or f"HTTP {response.status}"
|
|
171
|
-
}]
|
|
172
|
-
})
|
|
173
|
-
profiling["parse_response"] = time.time() - parse_response_start
|
|
174
|
-
|
|
175
|
-
except requests.exceptions.HTTPError as e:
|
|
176
|
-
raise FhirSenderException(
|
|
177
|
-
request_id=request_id,
|
|
178
|
-
url=resource_uri.url,
|
|
179
|
-
headers=headers,
|
|
180
|
-
json_data=json_payload,
|
|
181
|
-
response_text=response_text,
|
|
182
|
-
response_status_code=response_status,
|
|
183
|
-
exception=e,
|
|
184
|
-
variables=FhirClientLogger.get_variables_to_log(vars(self)),
|
|
185
|
-
message=f"HttpError: {e}",
|
|
186
|
-
elapsed_time=time.time() - merge_start_time,
|
|
187
|
-
) from e
|
|
188
|
-
except Exception as e:
|
|
189
|
-
raise FhirSenderException(
|
|
190
|
-
request_id=request_id,
|
|
191
|
-
url=resource_uri.url,
|
|
192
|
-
headers=headers,
|
|
193
|
-
json_data=json_payload,
|
|
194
|
-
response_text=response_text,
|
|
195
|
-
response_status_code=response_status,
|
|
196
|
-
exception=e,
|
|
197
|
-
variables=FhirClientLogger.get_variables_to_log(vars(self)),
|
|
198
|
-
message=f"Unknown Error: {e}",
|
|
199
|
-
elapsed_time=time.time() - merge_start_time,
|
|
200
|
-
) from e
|
|
201
|
-
|
|
202
|
-
# Convert dict responses to proper objects using fast method
|
|
203
|
-
create_objects_start = time.time()
|
|
204
|
-
response_entries: deque[BaseFhirMergeResourceResponseEntry] = deque()
|
|
205
|
-
|
|
206
|
-
for resp_dict in responses:
|
|
207
|
-
response_entries.append(
|
|
208
|
-
FhirMergeResourceResponseEntry.from_dict_without_storage(resp_dict)
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
for error_dict in errors:
|
|
212
|
-
response_entries.append(
|
|
213
|
-
FhirMergeResponseEntryError.from_dict(error_dict)
|
|
214
|
-
)
|
|
215
|
-
profiling["create_response_objects"] = time.time() - create_objects_start
|
|
216
|
-
|
|
217
|
-
profiling["total_time"] = time.time() - merge_start_time
|
|
218
|
-
|
|
219
|
-
# Log profiling information if logger is available
|
|
220
|
-
if self._logger:
|
|
221
|
-
self._logger.info(
|
|
222
|
-
f"merge_bundle_without_storage profiling: "
|
|
223
|
-
f"total={profiling['total_time']:.3f}s, "
|
|
224
|
-
f"build_url={profiling['build_url']:.3f}s, "
|
|
225
|
-
f"get_token={profiling['get_access_token']:.3f}s, "
|
|
226
|
-
f"prepare_payload={profiling['prepare_payload']:.3f}s, "
|
|
227
|
-
f"http_post={profiling['http_post']:.3f}s, "
|
|
228
|
-
f"parse_response={profiling['parse_response']:.3f}s, "
|
|
229
|
-
f"create_objects={profiling['create_response_objects']:.3f}s"
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
return FhirMergeResourceResponse(
|
|
233
|
-
request_id=request_id,
|
|
234
|
-
url=resource_uri.url,
|
|
235
|
-
responses=response_entries,
|
|
236
|
-
error=None if response_status == 200 else (response_text or f"HTTP {response_status}"),
|
|
237
|
-
access_token=self._access_token,
|
|
238
|
-
status=response_status,
|
|
239
|
-
response_text=response_text,
|
|
240
|
-
)
|
|
241
|
-
|
|
242
48
|
async def merge_bundle_async(
|
|
243
49
|
self,
|
|
244
50
|
id_: str | None,
|
|
@@ -319,8 +125,6 @@ class FhirMergeResourcesMixin(FhirClientProtocol):
|
|
|
319
125
|
access_token=self._access_token,
|
|
320
126
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
321
127
|
persistent_session=self._persistent_session,
|
|
322
|
-
use_persistent_session=self._use_persistent_session,
|
|
323
|
-
close_session_on_exit=self._close_session,
|
|
324
128
|
) as client:
|
|
325
129
|
# should we check if it exists and do a POST then?
|
|
326
130
|
response: RetryableAioHttpResponse = await client.post(
|
|
@@ -537,9 +341,7 @@ class FhirMergeResourcesMixin(FhirClientProtocol):
|
|
|
537
341
|
log_all_url_results=self._log_all_response_urls,
|
|
538
342
|
access_token=self._access_token,
|
|
539
343
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
540
|
-
close_session_on_exit=self._close_session,
|
|
541
344
|
persistent_session=self._persistent_session,
|
|
542
|
-
use_persistent_session=self._use_persistent_session,
|
|
543
345
|
) as client:
|
|
544
346
|
# should we check if it exists and do a POST then?
|
|
545
347
|
response: RetryableAioHttpResponse = await client.post(
|
|
@@ -73,8 +73,6 @@ class FhirPatchMixin(FhirClientProtocol):
|
|
|
73
73
|
access_token=self._access_token,
|
|
74
74
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
75
75
|
persistent_session=self._persistent_session,
|
|
76
|
-
use_persistent_session=self._use_persistent_session,
|
|
77
|
-
close_session_on_exit=self._close_session,
|
|
78
76
|
) as client:
|
|
79
77
|
response: RetryableAioHttpResponse = await client.patch(
|
|
80
78
|
url=full_uri.url, json=deserialized_data, headers=headers
|
|
@@ -107,8 +107,6 @@ class FhirUpdateMixin(FhirClientProtocol):
|
|
|
107
107
|
access_token=self._access_token,
|
|
108
108
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
109
109
|
persistent_session=self._persistent_session,
|
|
110
|
-
use_persistent_session=self._use_persistent_session,
|
|
111
|
-
close_session_on_exit=self._close_session,
|
|
112
110
|
) as client:
|
|
113
111
|
response = await client.put(url=full_uri.url, data=json_data, headers=headers)
|
|
114
112
|
request_id = response.response_headers.get("X-Request-ID", None)
|
|
@@ -80,7 +80,6 @@ class SimulatedGraphProcessorMixin(ABC, FhirClientProtocol):
|
|
|
80
80
|
add_cached_bundles_to_result: bool = True,
|
|
81
81
|
input_cache: RequestCache | None = None,
|
|
82
82
|
compare_hash: bool = True,
|
|
83
|
-
make_persistent_connection: bool = False,
|
|
84
83
|
) -> AsyncGenerator[FhirGetResponse, None]:
|
|
85
84
|
"""
|
|
86
85
|
Asynchronously simulate a FHIR $graph query with advanced processing capabilities.
|
|
@@ -120,7 +119,6 @@ class SimulatedGraphProcessorMixin(ABC, FhirClientProtocol):
|
|
|
120
119
|
add_cached_bundles_to_result: Optional flag to add cached bundles to result
|
|
121
120
|
input_cache: Optional cache for resource retrieval
|
|
122
121
|
compare_hash: Flag to compare resource hashes for changes
|
|
123
|
-
make_persistent_connection: Flag to make a persistent HTTP connection
|
|
124
122
|
|
|
125
123
|
Yields:
|
|
126
124
|
FhirGetResponse objects representing retrieved resources
|
|
@@ -134,17 +132,6 @@ class SimulatedGraphProcessorMixin(ABC, FhirClientProtocol):
|
|
|
134
132
|
# Parse authentication scopes for resource access control
|
|
135
133
|
scope_parser: FhirScopeParser = FhirScopeParser(scopes=auth_scopes)
|
|
136
134
|
|
|
137
|
-
persistent_session = None
|
|
138
|
-
if make_persistent_connection:
|
|
139
|
-
# Create a persistent HTTP session for reuse across all requests in this graph traversal
|
|
140
|
-
persistent_session = self.create_http_session()
|
|
141
|
-
|
|
142
|
-
# Store the origninal create_http_session method
|
|
143
|
-
original_create_http_session = self.create_http_session
|
|
144
|
-
|
|
145
|
-
# Override create_http_session to return the persistent session
|
|
146
|
-
self.create_http_session = lambda: persistent_session # type: ignore[method-assign]
|
|
147
|
-
|
|
148
135
|
# Ensure bundle resources are not separated by default
|
|
149
136
|
self.separate_bundle_resources(False)
|
|
150
137
|
|
|
@@ -279,13 +266,6 @@ class SimulatedGraphProcessorMixin(ABC, FhirClientProtocol):
|
|
|
279
266
|
# Yield the final response
|
|
280
267
|
yield full_response
|
|
281
268
|
|
|
282
|
-
if persistent_session:
|
|
283
|
-
# Clean up: close the persistent session
|
|
284
|
-
await persistent_session.close()
|
|
285
|
-
|
|
286
|
-
if make_persistent_connection:
|
|
287
|
-
self.create_http_session = original_create_http_session # type: ignore[method-assign]
|
|
288
|
-
|
|
289
269
|
# noinspection PyUnusedLocal
|
|
290
270
|
async def process_link_async_parallel_function(
|
|
291
271
|
self,
|
|
@@ -1172,7 +1152,6 @@ class SimulatedGraphProcessorMixin(ABC, FhirClientProtocol):
|
|
|
1172
1152
|
add_cached_bundles_to_result: bool = True,
|
|
1173
1153
|
input_cache: RequestCache | None = None,
|
|
1174
1154
|
compare_hash: bool = True,
|
|
1175
|
-
make_persistent_connection: bool = False,
|
|
1176
1155
|
) -> FhirGetResponse:
|
|
1177
1156
|
"""
|
|
1178
1157
|
Simulates the $graph query on the FHIR server
|
|
@@ -1195,7 +1174,6 @@ class SimulatedGraphProcessorMixin(ABC, FhirClientProtocol):
|
|
|
1195
1174
|
:param add_cached_bundles_to_result: Optional flag to add cached bundles to result
|
|
1196
1175
|
:param input_cache: Optional cache to use for input
|
|
1197
1176
|
:param compare_hash: Optional flag to compare hash of the resources
|
|
1198
|
-
:param make_persistent_connection: Whether to make the connection persistent for reuse across all requests in this graph traversal
|
|
1199
1177
|
:return: FhirGetResponse
|
|
1200
1178
|
"""
|
|
1201
1179
|
if contained:
|
|
@@ -1226,7 +1204,6 @@ class SimulatedGraphProcessorMixin(ABC, FhirClientProtocol):
|
|
|
1226
1204
|
add_cached_bundles_to_result=add_cached_bundles_to_result,
|
|
1227
1205
|
input_cache=input_cache,
|
|
1228
1206
|
compare_hash=compare_hash,
|
|
1229
|
-
make_persistent_connection=make_persistent_connection,
|
|
1230
1207
|
)
|
|
1231
1208
|
)
|
|
1232
1209
|
assert result, "No result returned from simulate_graph_async"
|
|
@@ -130,9 +130,7 @@ class RequestQueueMixin(ABC, FhirClientProtocol):
|
|
|
130
130
|
log_all_url_results=self._log_all_response_urls,
|
|
131
131
|
access_token=self._access_token,
|
|
132
132
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
133
|
-
close_session_on_exit=self._close_session,
|
|
134
133
|
persistent_session=self._persistent_session,
|
|
135
|
-
use_persistent_session=self._use_persistent_session,
|
|
136
134
|
) as client:
|
|
137
135
|
while next_url:
|
|
138
136
|
# set access token in request if present
|
|
@@ -301,9 +299,7 @@ class RequestQueueMixin(ABC, FhirClientProtocol):
|
|
|
301
299
|
log_all_url_results=self._log_all_response_urls,
|
|
302
300
|
access_token=self._access_token,
|
|
303
301
|
access_token_expiry_date=self._access_token_expiry_date,
|
|
304
|
-
close_session_on_exit=self._close_session,
|
|
305
302
|
persistent_session=self._persistent_session,
|
|
306
|
-
use_persistent_session=self._use_persistent_session,
|
|
307
303
|
) as client:
|
|
308
304
|
while next_url:
|
|
309
305
|
# set access token in request if present
|
|
@@ -75,34 +75,6 @@ class FhirMergeResourceResponseEntry(BaseFhirMergeResourceResponseEntry):
|
|
|
75
75
|
status=data.get("status"),
|
|
76
76
|
)
|
|
77
77
|
|
|
78
|
-
@classmethod
|
|
79
|
-
def from_dict_without_storage(
|
|
80
|
-
cls, data: dict[str, Any]
|
|
81
|
-
) -> "FhirMergeResourceResponseEntry":
|
|
82
|
-
"""
|
|
83
|
-
Creates a FhirMergeResourceResponseEntry from a dictionary without storage_mode overhead.
|
|
84
|
-
Uses FhirResource.construct for faster object creation.
|
|
85
|
-
|
|
86
|
-
:param data: Dictionary containing the response entry data
|
|
87
|
-
:return: FhirMergeResourceResponseEntry instance
|
|
88
|
-
"""
|
|
89
|
-
return FhirMergeResourceResponseEntry(
|
|
90
|
-
created=data.get("created"),
|
|
91
|
-
updated=data.get("updated"),
|
|
92
|
-
deleted=data.get("deleted"),
|
|
93
|
-
id_=data.get("id"),
|
|
94
|
-
uuid=data.get("uuid"),
|
|
95
|
-
resource_type=data.get("resourceType"),
|
|
96
|
-
source_assigning_authority=data.get("source_assigning_authority"),
|
|
97
|
-
resource_version=data.get("resource_version"),
|
|
98
|
-
message=data.get("message"),
|
|
99
|
-
issue=data.get("issue"),
|
|
100
|
-
error=data.get("error"),
|
|
101
|
-
token=data.get("token"),
|
|
102
|
-
resource=(FhirResource.construct(**data.get("resource")) if data.get("resource") else None),
|
|
103
|
-
status=data.get("status"),
|
|
104
|
-
)
|
|
105
|
-
|
|
106
78
|
@classmethod
|
|
107
79
|
@override
|
|
108
80
|
def from_json(
|
|
@@ -8,7 +8,7 @@ import async_timeout
|
|
|
8
8
|
from aiohttp import ClientError, ClientResponse, ClientResponseError, ClientSession
|
|
9
9
|
from multidict import MultiMapping
|
|
10
10
|
from opentelemetry import trace
|
|
11
|
-
|
|
11
|
+
import logging
|
|
12
12
|
from helix_fhir_client_sdk.function_types import (
|
|
13
13
|
RefreshTokenFunction,
|
|
14
14
|
RefreshTokenResult,
|
|
@@ -46,8 +46,6 @@ class RetryableAioHttpClient:
|
|
|
46
46
|
access_token: str | None,
|
|
47
47
|
access_token_expiry_date: datetime | None,
|
|
48
48
|
persistent_session: ClientSession | None = None,
|
|
49
|
-
use_persistent_session: bool = False,
|
|
50
|
-
close_session_on_exit: bool = True,
|
|
51
49
|
) -> None:
|
|
52
50
|
"""
|
|
53
51
|
RetryableClient provides a way to make HTTP calls with automatic retry and automatic refreshing of access tokens
|
|
@@ -73,12 +71,10 @@ class RetryableAioHttpClient:
|
|
|
73
71
|
self.log_all_url_results: bool = log_all_url_results
|
|
74
72
|
self.access_token: str | None = access_token
|
|
75
73
|
self.access_token_expiry_date: datetime | None = access_token_expiry_date
|
|
76
|
-
self.close_session_on_exit: bool = close_session_on_exit
|
|
77
74
|
self.persistent_session: ClientSession | None = persistent_session
|
|
78
|
-
self.use_persistent_session: bool = use_persistent_session
|
|
79
75
|
|
|
80
76
|
async def __aenter__(self) -> "RetryableAioHttpClient":
|
|
81
|
-
if self.
|
|
77
|
+
if self.persistent_session is not None:
|
|
82
78
|
self.session = self.persistent_session
|
|
83
79
|
else:
|
|
84
80
|
self.session = self.fn_get_session()
|
|
@@ -90,7 +86,7 @@ class RetryableAioHttpClient:
|
|
|
90
86
|
exc_val: BaseException | None,
|
|
91
87
|
exc_tb: type[BaseException] | None | None,
|
|
92
88
|
) -> None:
|
|
93
|
-
if self.session is not None
|
|
89
|
+
if not self.persistent_session and self.session is not None:
|
|
94
90
|
await self.session.close()
|
|
95
91
|
|
|
96
92
|
@staticmethod
|
|
@@ -134,6 +130,7 @@ class RetryableAioHttpClient:
|
|
|
134
130
|
if self.compress:
|
|
135
131
|
kwargs["compress"] = self.compress
|
|
136
132
|
assert self.session is not None
|
|
133
|
+
logging.info(f"Using Session ID: {id(self.session)} for URL: {url}")
|
|
137
134
|
with TRACER.start_as_current_span(FhirClientSdkOpenTelemetrySpanNames.HTTP_GET) as span:
|
|
138
135
|
span.set_attribute(
|
|
139
136
|
FhirClientSdkOpenTelemetryAttributeNames.URL,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
helix_fhir_client_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
helix_fhir_client_sdk/dictionary_parser.py,sha256=WrGkVAxMlUvVycRVrX7UZt2oP2e_Vk4-E8QibwTpHLM,3401
|
|
3
3
|
helix_fhir_client_sdk/dictionary_writer.py,sha256=V7Bx9Z69s0LRYF6Lc6Xp0d-Gj0BnAVKA1vBuwf3JORE,1486
|
|
4
|
-
helix_fhir_client_sdk/fhir_auth_mixin.py,sha256=
|
|
4
|
+
helix_fhir_client_sdk/fhir_auth_mixin.py,sha256=p2QIYrCv7ZktutY7SzYizmHADahxBddRTSCqX1EKyHc,14465
|
|
5
5
|
helix_fhir_client_sdk/fhir_bundle_appender.py,sha256=t1hs7p_vXKC9MUFyUnN9dTuDhRF-kw-kkgVFtGHv9QQ,11749
|
|
6
|
-
helix_fhir_client_sdk/fhir_client.py,sha256
|
|
7
|
-
helix_fhir_client_sdk/fhir_delete_mixin.py,sha256=
|
|
8
|
-
helix_fhir_client_sdk/fhir_merge_mixin.py,sha256=
|
|
9
|
-
helix_fhir_client_sdk/fhir_merge_resources_mixin.py,sha256=
|
|
10
|
-
helix_fhir_client_sdk/fhir_patch_mixin.py,sha256=
|
|
11
|
-
helix_fhir_client_sdk/fhir_update_mixin.py,sha256=
|
|
6
|
+
helix_fhir_client_sdk/fhir_client.py,sha256=-vaKQWKSJf4LiGP-Px-w6BlPa7N4yh_DOazM9WAvtRA,33120
|
|
7
|
+
helix_fhir_client_sdk/fhir_delete_mixin.py,sha256=1YiKddTJTUzzrRvG7WgSisXY8rfJAHPAEXTsOevrom8,6521
|
|
8
|
+
helix_fhir_client_sdk/fhir_merge_mixin.py,sha256=YTUODvc2rqXhk5_kwNMFPykm1I9_omww2WUcDExMESg,15264
|
|
9
|
+
helix_fhir_client_sdk/fhir_merge_resources_mixin.py,sha256=EOxsxOwvJ_wCbPrk7y4G55EkaDJrfUbRPZVgnt2_B7c,27671
|
|
10
|
+
helix_fhir_client_sdk/fhir_patch_mixin.py,sha256=YGcCPStoqVxWCYOaNI8vCKSFkAyRzP0YM_UWp4UKYro,5858
|
|
11
|
+
helix_fhir_client_sdk/fhir_update_mixin.py,sha256=7psQTBsGPY1izuwn3yD4MGLjLVWQjqA_15_IeaUspew,6230
|
|
12
12
|
helix_fhir_client_sdk/function_types.py,sha256=x95j6ix3Xa9b276Q741xX1jguqBuFT6EBLDw35_EoVM,3916
|
|
13
13
|
helix_fhir_client_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
helix_fhir_client_sdk/well_known_configuration.py,sha256=hwKpqZoJHkHuCEOowoXk07ywEMMhr_rcmQHNKCUEgVk,221
|
|
@@ -32,7 +32,7 @@ helix_fhir_client_sdk/graph/fhir_graph_mixin.py,sha256=z0j9FmO2bOnmzgQmczfkWC70u
|
|
|
32
32
|
helix_fhir_client_sdk/graph/graph_definition.py,sha256=FTa1GLjJ6oooAhNw7SPk-Y8duB-5WtJtnwADao-afaI,3878
|
|
33
33
|
helix_fhir_client_sdk/graph/graph_link_parameters.py,sha256=3rknHL6SBgpT2A1fr-AikEFrR_9nIJUotZ82XFzROLo,599
|
|
34
34
|
helix_fhir_client_sdk/graph/graph_target_parameters.py,sha256=fdYQpPZxDnyWyevuwDwxeTXOJoE2PgS5QhPaXpwtFcU,705
|
|
35
|
-
helix_fhir_client_sdk/graph/simulated_graph_processor_mixin.py,sha256
|
|
35
|
+
helix_fhir_client_sdk/graph/simulated_graph_processor_mixin.py,sha256=h8K4peHcoY_4_Ln4Vz54Ls87W7bXegm4SZV2s2L4cCM,60302
|
|
36
36
|
helix_fhir_client_sdk/graph/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
37
|
helix_fhir_client_sdk/graph/test/test_graph_mixin.py,sha256=LNd4LVjryVLgzWeTXMDpsbdauXl7u3LMfj9irnNfb_k,5469
|
|
38
38
|
helix_fhir_client_sdk/graph/test/test_simulate_graph_processor_mixin.py,sha256=EQDfhqJfUrP6SptXRP7ayEN7g5cZQMA00ccXzeXiSXM,46312
|
|
@@ -41,10 +41,10 @@ helix_fhir_client_sdk/open_telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
|
|
|
41
41
|
helix_fhir_client_sdk/open_telemetry/attribute_names.py,sha256=iUxm82t5-_qONL3Ld6LkzOwjuuCwcOptaJVBgCE4tps,169
|
|
42
42
|
helix_fhir_client_sdk/open_telemetry/span_names.py,sha256=Y-k29sniK5beSgkEz335eYFpybaw3K_3VU-ayxLdrW0,380
|
|
43
43
|
helix_fhir_client_sdk/queue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
44
|
-
helix_fhir_client_sdk/queue/request_queue_mixin.py,sha256=
|
|
44
|
+
helix_fhir_client_sdk/queue/request_queue_mixin.py,sha256=L5HgWWARj-JoM7v4cradNonDK1aO1BQyl2MWZknP_PY,21806
|
|
45
45
|
helix_fhir_client_sdk/responses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
46
|
helix_fhir_client_sdk/responses/bundle_expander.py,sha256=ilR5eMgciSgzsdQvKB6bHtn9jtpvn3uS-EBz-hrahzo,1065
|
|
47
|
-
helix_fhir_client_sdk/responses/fhir_client_protocol.py,sha256=
|
|
47
|
+
helix_fhir_client_sdk/responses/fhir_client_protocol.py,sha256=cKt0lNYFc5HPWZcHaaW8UFO7iHl16QmG93sbDKFJVvs,6785
|
|
48
48
|
helix_fhir_client_sdk/responses/fhir_delete_response.py,sha256=0K11vyfZ0LtL-G61NHzDqHrZgEHjMVZr00VWpWcktZA,2941
|
|
49
49
|
helix_fhir_client_sdk/responses/fhir_get_response.py,sha256=3PXvFoMZ7ix2ZzucIjY-49RL3foLR07dD57BdulyMGI,17657
|
|
50
50
|
helix_fhir_client_sdk/responses/fhir_merge_response.py,sha256=uvUjEGJgMDlAkcc5_LjgAsTFZqREQMlV79sbxUZwtwE,2862
|
|
@@ -70,7 +70,7 @@ helix_fhir_client_sdk/responses/get/test/test_get_single_response.py,sha256=cDK6
|
|
|
70
70
|
helix_fhir_client_sdk/responses/merge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
71
|
helix_fhir_client_sdk/responses/merge/base_fhir_merge_resource_response_entry.py,sha256=0PKxQc6sfO2RJka6AS4cX3U_yFnHRR0nsfgva91WrYk,3734
|
|
72
72
|
helix_fhir_client_sdk/responses/merge/fhir_merge_resource_response.py,sha256=jLHzg-mHYKYBMrAnsx_vnTaP0OCuHJoPEHODCHFxaXA,3226
|
|
73
|
-
helix_fhir_client_sdk/responses/merge/fhir_merge_resource_response_entry.py,sha256=
|
|
73
|
+
helix_fhir_client_sdk/responses/merge/fhir_merge_resource_response_entry.py,sha256=J_r92iqS8YEnfOngblAVDAys-0hRSWmj_EnIMSqm0gk,3332
|
|
74
74
|
helix_fhir_client_sdk/responses/merge/fhir_merge_response_entry_issue.py,sha256=e7yKvYqdcb45YWblQafyoK1scf62j8Ux80AOdrkQbF4,2048
|
|
75
75
|
helix_fhir_client_sdk/responses/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
76
|
helix_fhir_client_sdk/responses/test/test_bundle_expander.py,sha256=-IMu42ZcRSif8pwDWI0SsBXDI-8gRmOAsshtNhmoROM,877
|
|
@@ -104,7 +104,7 @@ helix_fhir_client_sdk/utilities/hash_util.py,sha256=YNUy7-IC_OtC0l-T45UO9UkA-_ps
|
|
|
104
104
|
helix_fhir_client_sdk/utilities/list_chunker.py,sha256=2h2k5CCFmOhICaugOx6UI-9dh4q5w1lVdF7WQLX0LCM,1456
|
|
105
105
|
helix_fhir_client_sdk/utilities/ndjson_chunk_streaming_parser.py,sha256=3TCYfWVCEpJbqRxqlSDsGnFnraO4T9bxzYdShvu6Pos,1954
|
|
106
106
|
helix_fhir_client_sdk/utilities/practitioner_generator.py,sha256=gneCAXNDNEphBY-Nc2nMQBbEWJgHcjvv3S8JQ75yiJI,3778
|
|
107
|
-
helix_fhir_client_sdk/utilities/retryable_aiohttp_client.py,sha256=
|
|
107
|
+
helix_fhir_client_sdk/utilities/retryable_aiohttp_client.py,sha256=OGWRb0ip5hHPAUHoQ9RHWdJnMERQVZvAAWPSPA4pAJ0,20997
|
|
108
108
|
helix_fhir_client_sdk/utilities/retryable_aiohttp_response.py,sha256=DvNX6WO1m2Hz6LoI5CwSPDECPd8oDsqRCVsyq_Oxf-0,3542
|
|
109
109
|
helix_fhir_client_sdk/utilities/retryable_aiohttp_url_result.py,sha256=Gdmvn6qIM2JF0YOhobQUHY41fCxvYyaths_CZs0iJfo,616
|
|
110
110
|
helix_fhir_client_sdk/utilities/url_checker.py,sha256=_JRSIvu7WNXh2OA79HJbEEiomGT-quGhAUGh44-9824,3580
|
|
@@ -130,7 +130,7 @@ helix_fhir_client_sdk/validators/async_fhir_validator.py,sha256=Bgiw5atbc5YzBYpk
|
|
|
130
130
|
helix_fhir_client_sdk/validators/fhir_validator.py,sha256=HWBldSEB9yeKIcnLcV8R-LoTzwT_OMu8SchtUUBKzys,2331
|
|
131
131
|
helix_fhir_client_sdk/validators/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
132
132
|
helix_fhir_client_sdk/validators/test/test_async_fhir_validator.py,sha256=RmSowjPUdZee5nYuYujghxWyqJ20cu7U0lJFtFT-ZBs,3285
|
|
133
|
-
helix_fhir_client_sdk-4.2.
|
|
133
|
+
helix_fhir_client_sdk-4.2.8.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
134
134
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
135
135
|
tests/logger_for_test.py,sha256=UC-7F6w6fDsUIYf37aRnvUdiUUVk8qkJEUSuO17NQnI,1525
|
|
136
136
|
tests/test_get_nested_property.py,sha256=dA7eNmPJuwzQTViORRmJkcn9RAZzxeajSxUghobHpAo,2381
|
|
@@ -209,7 +209,7 @@ tests_integration/test_emr_server_auth.py,sha256=2I4QUAspQN89uGf6JB2aVuYaBeDnRJz
|
|
|
209
209
|
tests_integration/test_firely_fhir.py,sha256=ll6-plwQrKfdrEyfbw0wLTC1jB-Qei1Mj-81tYTl5eQ,697
|
|
210
210
|
tests_integration/test_merge_vs_smart_merge_behavior.py,sha256=LrIuyxzw0YLaTjcRtG0jzy0M6xSv9qebmdBtMPDcacQ,3733
|
|
211
211
|
tests_integration/test_staging_server_graph.py,sha256=5RfMxjhdX9o4-n_ZRvze4Sm8u8NjRijRLDpqiz8qD_0,7132
|
|
212
|
-
helix_fhir_client_sdk-4.2.
|
|
213
|
-
helix_fhir_client_sdk-4.2.
|
|
214
|
-
helix_fhir_client_sdk-4.2.
|
|
215
|
-
helix_fhir_client_sdk-4.2.
|
|
212
|
+
helix_fhir_client_sdk-4.2.8.dist-info/METADATA,sha256=oR35BPFtyfxWva020v58txCvPufKY3bXlhL0RU7IYkc,3914
|
|
213
|
+
helix_fhir_client_sdk-4.2.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
214
|
+
helix_fhir_client_sdk-4.2.8.dist-info/top_level.txt,sha256=BRnDS6ceQxs-4u2jXznATObgP8G2cGAerlH0ZS4sJ6M,46
|
|
215
|
+
helix_fhir_client_sdk-4.2.8.dist-info/RECORD,,
|
|
File without changes
|
{helix_fhir_client_sdk-4.2.6.dist-info → helix_fhir_client_sdk-4.2.8.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{helix_fhir_client_sdk-4.2.6.dist-info → helix_fhir_client_sdk-4.2.8.dist-info}/top_level.txt
RENAMED
|
File without changes
|