helix.fhir.client.sdk 4.2.15__py3-none-any.whl → 4.2.16__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.
@@ -2,8 +2,12 @@ import json
2
2
  import time
3
3
 
4
4
  from furl import furl
5
+ from opentelemetry import trace
6
+ from opentelemetry.trace import Status, StatusCode
5
7
 
6
8
  from helix_fhir_client_sdk.exceptions.fhir_sender_exception import FhirSenderException
9
+ from helix_fhir_client_sdk.open_telemetry.attribute_names import FhirClientSdkOpenTelemetryAttributeNames
10
+ from helix_fhir_client_sdk.open_telemetry.span_names import FhirClientSdkOpenTelemetrySpanNames
7
11
  from helix_fhir_client_sdk.responses.fhir_client_protocol import FhirClientProtocol
8
12
  from helix_fhir_client_sdk.responses.fhir_update_response import FhirUpdateResponse
9
13
  from helix_fhir_client_sdk.structures.get_access_token_result import (
@@ -18,6 +22,8 @@ from helix_fhir_client_sdk.utilities.retryable_aiohttp_response import (
18
22
  RetryableAioHttpResponse,
19
23
  )
20
24
 
25
+ TRACER = trace.get_tracer(__name__)
26
+
21
27
 
22
28
  class FhirPatchMixin(FhirClientProtocol):
23
29
  async def send_patch_request_async(self, data: str) -> FhirUpdateResponse:
@@ -33,93 +39,102 @@ class FhirPatchMixin(FhirClientProtocol):
33
39
  raise ValueError("update should have only one id")
34
40
  if not self._resource:
35
41
  raise ValueError("update requires a FHIR resource type")
36
- self._internal_logger.debug(
37
- f"Calling patch method on {self._url} with client_id={self._client_id} and scopes={self._auth_scopes}"
38
- )
39
- full_uri: furl = furl(self._url)
40
- full_uri /= self._resource
41
- full_uri /= self._id
42
- request_id: str | None = None
43
42
 
44
- start_time: float = time.time()
43
+ with TRACER.start_as_current_span(FhirClientSdkOpenTelemetrySpanNames.PATCH) as span:
44
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.URL, self._url or "")
45
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.RESOURCE, self._resource or "")
46
+ try:
47
+ self._internal_logger.debug(
48
+ f"Calling patch method on {self._url} with client_id={self._client_id} and scopes={self._auth_scopes}"
49
+ )
50
+ full_uri: furl = furl(self._url)
51
+ full_uri /= self._resource
52
+ full_uri /= self._id
53
+ request_id: str | None = None
45
54
 
46
- # Set up headers
47
- headers = {"Content-Type": "application/json-patch+json"}
48
- headers.update(self._additional_request_headers)
49
- self._internal_logger.debug(f"Request headers: {headers}")
50
- access_token_result: GetAccessTokenResult = await self.get_access_token_async()
51
- access_token: str | None = access_token_result.access_token
52
- # set access token in request if present
53
- if access_token:
54
- headers["Authorization"] = f"Bearer {access_token}"
55
+ start_time: float = time.time()
55
56
 
56
- response_text: str | None = None
57
- response_status: int | None = None
57
+ # Set up headers
58
+ headers = {"Content-Type": "application/json-patch+json"}
59
+ headers.update(self._additional_request_headers)
60
+ self._internal_logger.debug(f"Request headers: {headers}")
61
+ access_token_result: GetAccessTokenResult = await self.get_access_token_async()
62
+ access_token: str | None = access_token_result.access_token
63
+ # set access token in request if present
64
+ if access_token:
65
+ headers["Authorization"] = f"Bearer {access_token}"
58
66
 
59
- try:
60
- deserialized_data = json.loads(data)
61
- # actually make the request
62
- async with RetryableAioHttpClient(
63
- fn_get_session=lambda: self.create_http_session(),
64
- refresh_token_func=self._refresh_token_function,
65
- tracer_request_func=self._trace_request_function,
66
- retries=self._retry_count,
67
- exclude_status_codes_from_retry=self._exclude_status_codes_from_retry,
68
- use_data_streaming=self._use_data_streaming,
69
- send_data_as_chunked=self._send_data_as_chunked,
70
- compress=self._compress,
71
- throw_exception_on_error=self._throw_exception_on_error,
72
- log_all_url_results=self._log_all_response_urls,
73
- access_token=self._access_token,
74
- access_token_expiry_date=self._access_token_expiry_date,
75
- ) as client:
76
- response: RetryableAioHttpResponse = await client.patch(
77
- url=full_uri.url, json=deserialized_data, headers=headers
78
- )
79
- response_status = response.status
80
- response_text = await response.get_text_async()
81
- request_id = response.response_headers.get("X-Request-ID", None)
82
- self._internal_logger.debug(f"X-Request-ID={request_id}")
67
+ response_text: str | None = None
68
+ response_status: int | None = None
83
69
 
84
- if response_status == 200:
85
- if self._logger:
86
- self._logger.info(f"Successfully updated: {full_uri}")
87
- elif response_status == 404:
88
- if self._logger:
89
- self._logger.info(f"Request resource was not found: {full_uri}")
70
+ try:
71
+ deserialized_data = json.loads(data)
72
+ # actually make the request
73
+ async with RetryableAioHttpClient(
74
+ fn_get_session=lambda: self.create_http_session(),
75
+ refresh_token_func=self._refresh_token_function,
76
+ tracer_request_func=self._trace_request_function,
77
+ retries=self._retry_count,
78
+ exclude_status_codes_from_retry=self._exclude_status_codes_from_retry,
79
+ use_data_streaming=self._use_data_streaming,
80
+ send_data_as_chunked=self._send_data_as_chunked,
81
+ compress=self._compress,
82
+ throw_exception_on_error=self._throw_exception_on_error,
83
+ log_all_url_results=self._log_all_response_urls,
84
+ access_token=self._access_token,
85
+ access_token_expiry_date=self._access_token_expiry_date,
86
+ ) as client:
87
+ response: RetryableAioHttpResponse = await client.patch(
88
+ url=full_uri.url, json=deserialized_data, headers=headers
89
+ )
90
+ response_status = response.status
91
+ response_text = await response.get_text_async()
92
+ request_id = response.response_headers.get("X-Request-ID", None)
93
+ self._internal_logger.debug(f"X-Request-ID={request_id}")
94
+
95
+ if response_status == 200:
96
+ if self._logger:
97
+ self._logger.info(f"Successfully updated: {full_uri}")
98
+ elif response_status == 404:
99
+ if self._logger:
100
+ self._logger.info(f"Request resource was not found: {full_uri}")
101
+ else:
102
+ # other HTTP errors
103
+ self._internal_logger.info(f"PATCH response for {full_uri.url}: {response_status}")
104
+ except Exception as e:
105
+ raise FhirSenderException(
106
+ request_id=request_id,
107
+ url=full_uri.url,
108
+ headers=headers,
109
+ json_data=data,
110
+ response_text=response_text,
111
+ response_status_code=response_status,
112
+ exception=e,
113
+ variables=FhirClientLogger.get_variables_to_log(vars(self)),
114
+ message=f"Error: {e}",
115
+ elapsed_time=time.time() - start_time,
116
+ ) from e
117
+ # check if response is json
118
+ if response_text:
119
+ try:
120
+ responses = json.loads(response_text)
121
+ except ValueError as e:
122
+ responses = {"issue": str(e)}
90
123
  else:
91
- # other HTTP errors
92
- self._internal_logger.info(f"PATCH response for {full_uri.url}: {response_status}")
93
- except Exception as e:
94
- raise FhirSenderException(
95
- request_id=request_id,
96
- url=full_uri.url,
97
- headers=headers,
98
- json_data=data,
99
- response_text=response_text,
100
- response_status_code=response_status,
101
- exception=e,
102
- variables=FhirClientLogger.get_variables_to_log(vars(self)),
103
- message=f"Error: {e}",
104
- elapsed_time=time.time() - start_time,
105
- ) from e
106
- # check if response is json
107
- if response_text:
108
- try:
109
- responses = json.loads(response_text)
110
- except ValueError as e:
111
- responses = {"issue": str(e)}
112
- else:
113
- responses = {}
114
- return FhirUpdateResponse(
115
- request_id=request_id,
116
- url=full_uri.tostr(),
117
- responses=json.dumps(responses),
118
- error=json.dumps(responses),
119
- access_token=access_token,
120
- status=response_status if response_status else 500,
121
- resource_type=self._resource,
122
- )
124
+ responses = {}
125
+ return FhirUpdateResponse(
126
+ request_id=request_id,
127
+ url=full_uri.tostr(),
128
+ responses=json.dumps(responses),
129
+ error=json.dumps(responses),
130
+ access_token=access_token,
131
+ status=response_status if response_status else 500,
132
+ resource_type=self._resource,
133
+ )
134
+ except Exception as e:
135
+ span.record_exception(e)
136
+ span.set_status(Status(StatusCode.ERROR, str(e)))
137
+ raise
123
138
 
124
139
  def send_patch_request(self, data: str) -> FhirUpdateResponse:
125
140
  """
@@ -3,7 +3,11 @@ from collections.abc import AsyncGenerator
3
3
  from compressedfhir.fhir.fhir_resource import FhirResource
4
4
  from compressedfhir.fhir.fhir_resource_list import FhirResourceList
5
5
  from furl import furl
6
+ from opentelemetry import trace
7
+ from opentelemetry.trace import Status, StatusCode
6
8
 
9
+ from helix_fhir_client_sdk.open_telemetry.attribute_names import FhirClientSdkOpenTelemetryAttributeNames
10
+ from helix_fhir_client_sdk.open_telemetry.span_names import FhirClientSdkOpenTelemetrySpanNames
7
11
  from helix_fhir_client_sdk.responses.fhir_client_protocol import FhirClientProtocol
8
12
  from helix_fhir_client_sdk.responses.fhir_update_response import FhirUpdateResponse
9
13
  from helix_fhir_client_sdk.structures.get_access_token_result import (
@@ -15,6 +19,8 @@ from helix_fhir_client_sdk.utilities.retryable_aiohttp_client import (
15
19
  )
16
20
  from helix_fhir_client_sdk.validators.async_fhir_validator import AsyncFhirValidator
17
21
 
22
+ TRACER = trace.get_tracer(__name__)
23
+
18
24
 
19
25
  class FhirUpdateMixin(FhirClientProtocol):
20
26
  async def update_single_resource_async(self, *, resource: FhirResource) -> FhirUpdateResponse:
@@ -69,60 +75,69 @@ class FhirUpdateMixin(FhirClientProtocol):
69
75
  raise ValueError("update should have only one id")
70
76
  if not self._resource:
71
77
  raise ValueError("update requires a FHIR resource type")
72
- full_uri: furl = furl(self._url)
73
- full_uri /= self._resource
74
- full_uri /= id_ or self._id
75
- # set up headers
76
- headers = {"Content-Type": "application/fhir+json"}
77
- headers.update(self._additional_request_headers)
78
- self._internal_logger.debug(f"Request headers: {headers}")
79
-
80
- access_token_result: GetAccessTokenResult = await self.get_access_token_async()
81
- access_token: str | None = access_token_result.access_token
82
- # set access token in request if present
83
- if access_token:
84
- headers["Authorization"] = f"Bearer {access_token}"
85
-
86
- if self._validation_server_url:
87
- await AsyncFhirValidator.validate_fhir_resource(
88
- fn_get_session=lambda: self.create_http_session(),
89
- json_data=json_data,
90
- resource_name=self._resource,
91
- validation_server_url=self._validation_server_url,
92
- access_token=access_token,
93
- )
94
-
95
- # actually make the request
96
- async with RetryableAioHttpClient(
97
- fn_get_session=lambda: self.create_http_session(),
98
- refresh_token_func=self._refresh_token_function,
99
- tracer_request_func=self._trace_request_function,
100
- retries=self._retry_count,
101
- exclude_status_codes_from_retry=self._exclude_status_codes_from_retry,
102
- use_data_streaming=self._use_data_streaming,
103
- send_data_as_chunked=self._send_data_as_chunked,
104
- compress=self._compress,
105
- throw_exception_on_error=self._throw_exception_on_error,
106
- log_all_url_results=self._log_all_response_urls,
107
- access_token=self._access_token,
108
- access_token_expiry_date=self._access_token_expiry_date,
109
- ) as client:
110
- response = await client.put(url=full_uri.url, data=json_data, headers=headers)
111
- request_id = response.response_headers.get("X-Request-ID", None)
112
- self._internal_logger.debug(f"X-Request-ID={request_id}")
113
- if response.status == 200:
114
- if self._logger:
115
- self._logger.info(f"Successfully updated: {full_uri}")
116
-
117
- return FhirUpdateResponse(
118
- request_id=request_id,
119
- url=full_uri.tostr(),
120
- responses=await response.get_text_async(),
121
- error=f"{response.status}" if not response.status == 200 else None,
122
- access_token=access_token,
123
- status=response.status,
124
- resource_type=self._resource,
125
- )
78
+
79
+ with TRACER.start_as_current_span(FhirClientSdkOpenTelemetrySpanNames.UPDATE) as span:
80
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.URL, self._url or "")
81
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.RESOURCE, self._resource or "")
82
+ try:
83
+ full_uri: furl = furl(self._url)
84
+ full_uri /= self._resource
85
+ full_uri /= id_ or self._id
86
+ # set up headers
87
+ headers = {"Content-Type": "application/fhir+json"}
88
+ headers.update(self._additional_request_headers)
89
+ self._internal_logger.debug(f"Request headers: {headers}")
90
+
91
+ access_token_result: GetAccessTokenResult = await self.get_access_token_async()
92
+ access_token: str | None = access_token_result.access_token
93
+ # set access token in request if present
94
+ if access_token:
95
+ headers["Authorization"] = f"Bearer {access_token}"
96
+
97
+ if self._validation_server_url:
98
+ await AsyncFhirValidator.validate_fhir_resource(
99
+ fn_get_session=lambda: self.create_http_session(),
100
+ json_data=json_data,
101
+ resource_name=self._resource,
102
+ validation_server_url=self._validation_server_url,
103
+ access_token=access_token,
104
+ )
105
+
106
+ # actually make the request
107
+ async with RetryableAioHttpClient(
108
+ fn_get_session=lambda: self.create_http_session(),
109
+ refresh_token_func=self._refresh_token_function,
110
+ tracer_request_func=self._trace_request_function,
111
+ retries=self._retry_count,
112
+ exclude_status_codes_from_retry=self._exclude_status_codes_from_retry,
113
+ use_data_streaming=self._use_data_streaming,
114
+ send_data_as_chunked=self._send_data_as_chunked,
115
+ compress=self._compress,
116
+ throw_exception_on_error=self._throw_exception_on_error,
117
+ log_all_url_results=self._log_all_response_urls,
118
+ access_token=self._access_token,
119
+ access_token_expiry_date=self._access_token_expiry_date,
120
+ ) as client:
121
+ response = await client.put(url=full_uri.url, data=json_data, headers=headers)
122
+ request_id = response.response_headers.get("X-Request-ID", None)
123
+ self._internal_logger.debug(f"X-Request-ID={request_id}")
124
+ if response.status == 200:
125
+ if self._logger:
126
+ self._logger.info(f"Successfully updated: {full_uri}")
127
+
128
+ return FhirUpdateResponse(
129
+ request_id=request_id,
130
+ url=full_uri.tostr(),
131
+ responses=await response.get_text_async(),
132
+ error=f"{response.status}" if not response.status == 200 else None,
133
+ access_token=access_token,
134
+ status=response.status,
135
+ resource_type=self._resource,
136
+ )
137
+ except Exception as e:
138
+ span.record_exception(e)
139
+ span.set_status(Status(StatusCode.ERROR, str(e)))
140
+ raise
126
141
 
127
142
  def update(self, json_data: str) -> FhirUpdateResponse:
128
143
  """
@@ -2,3 +2,6 @@ class FhirClientSdkOpenTelemetryAttributeNames:
2
2
  """Constants for OpenTelemetry attribute names used in the FHIR Client SDK."""
3
3
 
4
4
  URL: str = "fhir.client_sdk.url"
5
+ RESOURCE: str = "fhir.client_sdk.resource"
6
+ JSON_DATA_COUNT: str = "fhir.client_sdk.json_data.count"
7
+ BATCH_SIZE: str = "fhir.client_sdk.batch.size"
@@ -6,3 +6,7 @@ class FhirClientSdkOpenTelemetrySpanNames:
6
6
  GET_ACCESS_TOKEN: str = "fhir.client_sdk.access_token.get"
7
7
  HTTP_GET: str = "fhir.client_sdk.http.get"
8
8
  HANDLE_RESPONSE: str = "fhir.client_sdk.handle_response"
9
+ DELETE: str = "fhir.client_sdk.delete"
10
+ UPDATE: str = "fhir.client_sdk.update"
11
+ PATCH: str = "fhir.client_sdk.patch"
12
+ MERGE: str = "fhir.client_sdk.merge"
@@ -47,8 +47,30 @@ class RetryableAioHttpClient:
47
47
  access_token_expiry_date: datetime | None,
48
48
  ) -> None:
49
49
  """
50
- RetryableClient provides a way to make HTTP calls with automatic retry and automatic refreshing of access tokens
50
+ RetryableClient provides a way to make HTTP calls with automatic retry and automatic refreshing of access tokens.
51
51
 
52
+ Session Lifecycle Management:
53
+ - If fn_get_session is None (default): The SDK creates and manages the session lifecycle.
54
+ The session will be automatically closed when exiting the context manager.
55
+ - If fn_get_session is provided: The caller is responsible for managing the session lifecycle.
56
+ The SDK will NOT close the session - the caller must close it themselves.
57
+
58
+ :param retries: Number of retry attempts for failed requests
59
+ :param timeout_in_seconds: Timeout for HTTP requests
60
+ :param backoff_factor: Factor for exponential backoff between retries
61
+ :param retry_status_codes: HTTP status codes that trigger a retry
62
+ :param refresh_token_func: Function to refresh authentication tokens
63
+ :param tracer_request_func: Function to trace/log requests
64
+ :param fn_get_session: Optional callable that returns a ClientSession. If provided,
65
+ the caller is responsible for closing the session.
66
+ :param exclude_status_codes_from_retry: Status codes to exclude from retry logic
67
+ :param use_data_streaming: Whether to stream response data
68
+ :param compress: Whether to compress request data
69
+ :param send_data_as_chunked: Whether to use chunked transfer encoding
70
+ :param throw_exception_on_error: Whether to raise exceptions on HTTP errors
71
+ :param log_all_url_results: Whether to log all URL results
72
+ :param access_token: Access token for authentication
73
+ :param access_token_expiry_date: Expiry date of the access token
52
74
  """
53
75
  self.retries: int = retries
54
76
  self.timeout_in_seconds: float | None = timeout_in_seconds
@@ -58,6 +80,8 @@ class RetryableAioHttpClient:
58
80
  )
59
81
  self.refresh_token_func_async: RefreshTokenFunction | None = refresh_token_func
60
82
  self.trace_function_async: TraceRequestFunction | None = tracer_request_func
83
+ # Automatically determine if a session is caller-managed based on whether fn_get_session is provided
84
+ self._caller_managed_session: bool = fn_get_session is not None
61
85
  self.fn_get_session: Callable[[], ClientSession] = (
62
86
  fn_get_session if fn_get_session is not None else lambda: ClientSession()
63
87
  )
@@ -81,7 +105,9 @@ class RetryableAioHttpClient:
81
105
  exc_val: BaseException | None,
82
106
  exc_tb: type[BaseException] | None | None,
83
107
  ) -> None:
84
- if self.session is not None:
108
+ # Only close the session if SDK created it (fn_get_session was not provided)
109
+ # If the caller provided fn_get_session, they are responsible for closing the session
110
+ if not self._caller_managed_session and self.session is not None:
85
111
  await self.session.close()
86
112
 
87
113
  @staticmethod
@@ -115,7 +141,7 @@ class RetryableAioHttpClient:
115
141
  try:
116
142
  if headers:
117
143
  kwargs["headers"] = headers
118
- # if there is no data then remove from kwargs so as not to confuse aiohttp
144
+ # if there is no data, then remove from kwargs so as not to confuse aiohttp
119
145
  if "data" in kwargs and kwargs["data"] is None:
120
146
  del kwargs["data"]
121
147
  # compression and chunked can only be enabled if there is content sent
@@ -399,7 +425,7 @@ class RetryableAioHttpClient:
399
425
  if retry_after_text:
400
426
  # noinspection PyBroadException
401
427
  try:
402
- if retry_after_text.isnumeric(): # it is number of seconds
428
+ if retry_after_text.isnumeric(): # it is a number of seconds
403
429
  await asyncio.sleep(int(retry_after_text))
404
430
  else:
405
431
  wait_till: datetime = datetime.strptime(retry_after_text, "%a, %d %b %Y %H:%M:%S GMT")
@@ -413,7 +439,7 @@ class RetryableAioHttpClient:
413
439
  if time_diff > 0:
414
440
  await asyncio.sleep(time_diff)
415
441
  except Exception:
416
- # if there was some exception parsing the Retry-After header, sleep for 60 seconds
442
+ # if there was some exception, parsing the Retry-After header, sleep for 60 seconds
417
443
  await asyncio.sleep(60)
418
444
  else:
419
445
  await asyncio.sleep(60)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: helix.fhir.client.sdk
3
- Version: 4.2.15
3
+ Version: 4.2.16
4
4
  Summary: helix.fhir.client.sdk
5
5
  Home-page: https://github.com/icanbwell/helix.fhir.client.sdk
6
6
  Author: Imran Qureshi
@@ -111,9 +111,46 @@ response: Optional[FhirGetResponse] = await FhirGetResponse.from_async_generator
111
111
  ```
112
112
 
113
113
  # Data Streaming
114
- 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.
114
+ 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 is received.
115
115
  The data will be streamed in AsyncGenerators as described above.
116
116
 
117
+ # Persistent Sessions (Connection Reuse)
118
+ By default, the SDK creates a new HTTP session for each request. For better performance (~4× faster),
119
+ you can use persistent sessions to reuse connections across multiple requests.
120
+
121
+ **Important**: When you provide a custom session factory using `use_http_session()`, YOU are responsible
122
+ for managing the session lifecycle, including closing it when done. The SDK will NOT automatically close
123
+ user-provided sessions.
124
+
125
+ ```python
126
+ import aiohttp
127
+ from helix_fhir_client_sdk.fhir_client import FhirClient
128
+
129
+ # Create a persistent session for connection reuse
130
+ session = aiohttp.ClientSession()
131
+
132
+ try:
133
+ # Configure FhirClient to use persistent session
134
+ fhir_client = (
135
+ FhirClient()
136
+ .url("https://fhir.example.com")
137
+ .resource("Patient")
138
+ .use_http_session(lambda: session) # User provides session factory
139
+ )
140
+
141
+ # Multiple requests reuse the same connection (~4× performance boost)
142
+ response1 = await fhir_client.get_async()
143
+ response2 = await fhir_client.clone().resource("Observation").get_async()
144
+
145
+ finally:
146
+ # User must close the session when done
147
+ await session.close()
148
+ ```
149
+
150
+ **Session Lifecycle Rules**:
151
+ - **No custom factory** (default): SDK creates and closes the session automatically
152
+ - **Custom factory provided**: User is responsible for closing the session
153
+
117
154
  # Storage Compression
118
155
  The FHIR client SDK supports two types of compression:
119
156
 
@@ -3,12 +3,12 @@ helix_fhir_client_sdk/dictionary_parser.py,sha256=WrGkVAxMlUvVycRVrX7UZt2oP2e_Vk
3
3
  helix_fhir_client_sdk/dictionary_writer.py,sha256=V7Bx9Z69s0LRYF6Lc6Xp0d-Gj0BnAVKA1vBuwf3JORE,1486
4
4
  helix_fhir_client_sdk/fhir_auth_mixin.py,sha256=L-_fwQbyojv6AoRUYkPSXWEsW7NRInvJ3wwYgINEtJs,14351
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=zCMK19efEE-D6aDfbi5lOBD6Hw-Wa1dWdQj_a1GCLaQ,36142
7
- helix_fhir_client_sdk/fhir_delete_mixin.py,sha256=KaBBkV771sxbqskNZbW0yNVATDaRhd5sX58AKHHai9c,6407
8
- helix_fhir_client_sdk/fhir_merge_mixin.py,sha256=5d0w_hQVJ5EB9FE8jDbgpPwgwCgmf4ZUZ-JY-Rm6zSE,15191
6
+ helix_fhir_client_sdk/fhir_client.py,sha256=dHfkruJZ1uPM4cmKcnn4HqI0BCDP3IwIqXSLvCu4IsY,37346
7
+ helix_fhir_client_sdk/fhir_delete_mixin.py,sha256=IRcJ5AJ7yrsc1HbjqYW5-jAcIEwG__9nEqwbvvC8qJ0,7532
8
+ helix_fhir_client_sdk/fhir_merge_mixin.py,sha256=h2lvpLDs5nvt9F1bcpd110LFuFXI2HW-uKrUs5TbW7I,17783
9
9
  helix_fhir_client_sdk/fhir_merge_resources_mixin.py,sha256=QO2SeZa4Co69f_2YCz0_ss2dJb4xhVMkRdzbjLIJ-iI,35799
10
- helix_fhir_client_sdk/fhir_patch_mixin.py,sha256=t_Qi-FsqNdCUnRMiliL9h09824A-OI3p9bbhM5mI-7Y,5797
11
- helix_fhir_client_sdk/fhir_update_mixin.py,sha256=XYpj0w4TokxHSh1EFqLTHvsfrsIIfwk1q2BN_iuWkXE,6173
10
+ helix_fhir_client_sdk/fhir_patch_mixin.py,sha256=QLTsqhFLGi4gC_qQblnCA4skdiLw8h4QRlzvaeyFkl4,7249
11
+ helix_fhir_client_sdk/fhir_update_mixin.py,sha256=_Yx9yg809N8EXY07XlwHxSJLp-xIzpNg5erL92LOeww,7370
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
@@ -38,8 +38,8 @@ helix_fhir_client_sdk/graph/test/test_graph_mixin.py,sha256=LNd4LVjryVLgzWeTXMDp
38
38
  helix_fhir_client_sdk/graph/test/test_simulate_graph_processor_mixin.py,sha256=EQDfhqJfUrP6SptXRP7ayEN7g5cZQMA00ccXzeXiSXM,46312
39
39
  helix_fhir_client_sdk/graph/test/test_simulate_graph_processor_mixin_caching.py,sha256=WFzKKHtKDcOOXjXRMKkRyJ64whoJoo9M9ST88ayvEbY,16176
40
40
  helix_fhir_client_sdk/open_telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- helix_fhir_client_sdk/open_telemetry/attribute_names.py,sha256=iUxm82t5-_qONL3Ld6LkzOwjuuCwcOptaJVBgCE4tps,169
42
- helix_fhir_client_sdk/open_telemetry/span_names.py,sha256=Y-k29sniK5beSgkEz335eYFpybaw3K_3VU-ayxLdrW0,380
41
+ helix_fhir_client_sdk/open_telemetry/attribute_names.py,sha256=mcPcgpaRe-hZDmPu8gLQo51E_-rllAk2OXMC9uK6EmM,328
42
+ helix_fhir_client_sdk/open_telemetry/span_names.py,sha256=sEuzUXxE9pSoAZti2YVifBqbo3r4SLTPlIUW4F2EuP0,548
43
43
  helix_fhir_client_sdk/queue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  helix_fhir_client_sdk/queue/request_queue_mixin.py,sha256=Q5ZyadT2nMX6TATsiy0FLXzzCpTbVjN0Gh-B_F0RGCk,21684
45
45
  helix_fhir_client_sdk/responses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -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=Gb_-EcJRpNlMr5Ma2VlJY51jMCGiU-embiA1V6WMR9s,20617
107
+ helix_fhir_client_sdk/utilities/retryable_aiohttp_client.py,sha256=8DdzqTmIY1hWlxmEXOxycBpa72wTo-vsAtcLO4hpnmQ,22605
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.15.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
133
+ helix_fhir_client_sdk-4.2.16.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_fhir_client_clone.py,sha256=c5y1rWJ32nBSUnK1FfyymY005dNowd4Nf1xrbuQolNk,5368
@@ -153,6 +153,7 @@ tests/async/test_async_real_fhir_server_get_patients.py,sha256=0oMnUJg1KEspJ5_4e
153
153
  tests/async/test_async_real_fhir_server_get_patients_error.py,sha256=_s7chLogAg0yKgGpsq1o9_dDHBrzGaRWBAo8agFTN6U,1914
154
154
  tests/async/test_benchmark_compress.py,sha256=q1gDG7qXvof-3uVAqJlZAW7uO8cR0vEeDfzl-iwIEtY,16470
155
155
  tests/async/test_benchmark_merge.py,sha256=ME0Pow_IXpIaVGWvq3ii7dGltXcz-3DGxz2gGF4LmYQ,19830
156
+ tests/async/test_retryable_client_session_management.py,sha256=cOAE0wGkh3cv0AS187nujeial3gGEu1VlOJ5b9-LaCI,5360
156
157
  tests/async/fhir_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
157
158
  tests/async/fhir_server/test_async_real_fhir_server_get_graph_large.py,sha256=fM2MPF47nDF2Qwj2AkdTZ2CfvgUYGN4AVIS253KC9MQ,9430
158
159
  tests/async/fhir_server/test_async_real_fhir_server_get_patients_large.py,sha256=rXRF8E8Al7XANCmef1d_WqxSA9TVQjVC7B41OZaEQlY,5583
@@ -212,7 +213,7 @@ tests_integration/test_emr_server_auth.py,sha256=2I4QUAspQN89uGf6JB2aVuYaBeDnRJz
212
213
  tests_integration/test_firely_fhir.py,sha256=ll6-plwQrKfdrEyfbw0wLTC1jB-Qei1Mj-81tYTl5eQ,697
213
214
  tests_integration/test_merge_vs_smart_merge_behavior.py,sha256=LrIuyxzw0YLaTjcRtG0jzy0M6xSv9qebmdBtMPDcacQ,3733
214
215
  tests_integration/test_staging_server_graph.py,sha256=5RfMxjhdX9o4-n_ZRvze4Sm8u8NjRijRLDpqiz8qD_0,7132
215
- helix_fhir_client_sdk-4.2.15.dist-info/METADATA,sha256=7L_vOwYcAkZTKkAtwRolmGQbB7X90cN9EuuwiwBTo24,5845
216
- helix_fhir_client_sdk-4.2.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
217
- helix_fhir_client_sdk-4.2.15.dist-info/top_level.txt,sha256=BRnDS6ceQxs-4u2jXznATObgP8G2cGAerlH0ZS4sJ6M,46
218
- helix_fhir_client_sdk-4.2.15.dist-info/RECORD,,
216
+ helix_fhir_client_sdk-4.2.16.dist-info/METADATA,sha256=AHcaKMqC3ICIbjD_Fr8CXs8MxOXLzdyh3A76J-SVYMk,7210
217
+ helix_fhir_client_sdk-4.2.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
218
+ helix_fhir_client_sdk-4.2.16.dist-info/top_level.txt,sha256=BRnDS6ceQxs-4u2jXznATObgP8G2cGAerlH0ZS4sJ6M,46
219
+ helix_fhir_client_sdk-4.2.16.dist-info/RECORD,,