phenoml 0.0.1__py3-none-any.whl → 0.0.5__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 phenoml might be problematic. Click here for more details.

Files changed (86) hide show
  1. phenoml/agent/__init__.py +10 -12
  2. phenoml/agent/client.py +172 -65
  3. phenoml/agent/prompts/client.py +60 -60
  4. phenoml/agent/prompts/raw_client.py +134 -134
  5. phenoml/agent/raw_client.py +236 -69
  6. phenoml/agent/types/__init__.py +10 -12
  7. phenoml/agent/types/agent_create_request.py +53 -0
  8. phenoml/agent/types/agent_create_request_provider.py +1 -9
  9. phenoml/agent/types/agent_get_chat_messages_request_order.py +5 -0
  10. phenoml/agent/types/agent_get_chat_messages_response.py +22 -0
  11. phenoml/agent/types/agent_template.py +6 -4
  12. phenoml/agent/types/agent_template_provider.py +1 -9
  13. phenoml/agent/types/chat_message_template.py +72 -0
  14. phenoml/agent/types/chat_session_template.py +67 -0
  15. phenoml/client.py +6 -0
  16. phenoml/core/client_wrapper.py +2 -2
  17. phenoml/fhir/__init__.py +36 -0
  18. phenoml/fhir/client.py +970 -0
  19. phenoml/fhir/errors/__init__.py +10 -0
  20. phenoml/fhir/errors/bad_request_error.py +10 -0
  21. phenoml/fhir/errors/internal_server_error.py +10 -0
  22. phenoml/fhir/errors/not_found_error.py +10 -0
  23. phenoml/fhir/errors/unauthorized_error.py +10 -0
  24. phenoml/fhir/raw_client.py +1385 -0
  25. phenoml/fhir/types/__init__.py +29 -0
  26. phenoml/{agent/types/chat_fhir_client_config.py → fhir/types/error_response.py} +11 -6
  27. phenoml/fhir/types/fhir_bundle.py +43 -0
  28. phenoml/fhir/types/fhir_bundle_entry_item.py +34 -0
  29. phenoml/fhir/types/fhir_bundle_entry_item_request.py +25 -0
  30. phenoml/fhir/types/fhir_bundle_entry_item_request_method.py +5 -0
  31. phenoml/fhir/types/fhir_bundle_entry_item_response.py +24 -0
  32. phenoml/fhir/types/fhir_patch_request_body_item.py +36 -0
  33. phenoml/fhir/types/fhir_patch_request_body_item_op.py +7 -0
  34. phenoml/fhir/types/fhir_resource.py +40 -0
  35. phenoml/fhir/types/fhir_resource_meta.py +28 -0
  36. phenoml/fhir/types/fhir_search_response.py +8 -0
  37. phenoml/fhir_provider/__init__.py +43 -0
  38. phenoml/fhir_provider/client.py +731 -0
  39. phenoml/fhir_provider/errors/__init__.py +11 -0
  40. phenoml/fhir_provider/errors/bad_request_error.py +10 -0
  41. phenoml/fhir_provider/errors/forbidden_error.py +10 -0
  42. phenoml/fhir_provider/errors/internal_server_error.py +10 -0
  43. phenoml/fhir_provider/errors/not_found_error.py +10 -0
  44. phenoml/fhir_provider/errors/unauthorized_error.py +10 -0
  45. phenoml/fhir_provider/raw_client.py +1445 -0
  46. phenoml/fhir_provider/types/__init__.py +35 -0
  47. phenoml/fhir_provider/types/auth_method.py +7 -0
  48. phenoml/fhir_provider/types/fhir_provider_auth_config.py +53 -0
  49. phenoml/fhir_provider/types/fhir_provider_delete_response.py +20 -0
  50. phenoml/fhir_provider/types/fhir_provider_list_response.py +22 -0
  51. phenoml/fhir_provider/types/fhir_provider_remove_auth_config_response.py +22 -0
  52. phenoml/fhir_provider/types/fhir_provider_response.py +22 -0
  53. phenoml/fhir_provider/types/fhir_provider_set_active_auth_config_response.py +22 -0
  54. phenoml/fhir_provider/types/fhir_provider_template.py +66 -0
  55. phenoml/fhir_provider/types/fhir_query_response.py +27 -0
  56. phenoml/fhir_provider/types/fhir_query_response_data.py +5 -0
  57. phenoml/fhir_provider/types/json_web_key.py +51 -0
  58. phenoml/fhir_provider/types/provider.py +8 -0
  59. phenoml/fhir_provider/types/service_account_key.py +35 -0
  60. phenoml/fhir_provider/types/smart_configuration.py +46 -0
  61. phenoml/tools/__init__.py +12 -8
  62. phenoml/tools/client.py +27 -60
  63. phenoml/tools/mcp_server/__init__.py +7 -0
  64. phenoml/tools/mcp_server/client.py +336 -0
  65. phenoml/tools/mcp_server/raw_client.py +641 -0
  66. phenoml/tools/mcp_server/tools/__init__.py +4 -0
  67. phenoml/tools/mcp_server/tools/client.py +358 -0
  68. phenoml/tools/mcp_server/tools/raw_client.py +656 -0
  69. phenoml/tools/raw_client.py +18 -67
  70. phenoml/tools/types/__init__.py +10 -8
  71. phenoml/{agent/types/agent_fhir_config.py → tools/types/mcp_server_response.py} +8 -6
  72. phenoml/tools/types/mcp_server_response_data.py +51 -0
  73. phenoml/tools/types/mcp_server_tool_call_response.py +37 -0
  74. phenoml/tools/types/{fhir_client_config.py → mcp_server_tool_response.py} +8 -6
  75. phenoml/tools/types/mcp_server_tool_response_data.py +61 -0
  76. {phenoml-0.0.1.dist-info → phenoml-0.0.5.dist-info}/METADATA +1 -1
  77. {phenoml-0.0.1.dist-info → phenoml-0.0.5.dist-info}/RECORD +79 -29
  78. phenoml/agent/types/agent_create_request_provider_item.py +0 -7
  79. phenoml/agent/types/agent_template_provider_item.py +0 -5
  80. phenoml/agent/types/agent_update_request_provider.py +0 -13
  81. phenoml/agent/types/agent_update_request_provider_item.py +0 -7
  82. phenoml/tools/types/cohort_request_provider.py +0 -5
  83. phenoml/tools/types/lang2fhir_and_create_request_provider.py +0 -7
  84. phenoml/tools/types/lang2fhir_and_search_request_provider.py +0 -7
  85. {phenoml-0.0.1.dist-info → phenoml-0.0.5.dist-info}/LICENSE +0 -0
  86. {phenoml-0.0.1.dist-info → phenoml-0.0.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,1385 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+ from json.decoder import JSONDecodeError
5
+
6
+ from ..core.api_error import ApiError
7
+ from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
8
+ from ..core.http_response import AsyncHttpResponse, HttpResponse
9
+ from ..core.jsonable_encoder import jsonable_encoder
10
+ from ..core.pydantic_utilities import parse_obj_as
11
+ from ..core.request_options import RequestOptions
12
+ from ..core.serialization import convert_and_respect_annotation_metadata
13
+ from .errors.bad_request_error import BadRequestError
14
+ from .errors.internal_server_error import InternalServerError
15
+ from .errors.not_found_error import NotFoundError
16
+ from .errors.unauthorized_error import UnauthorizedError
17
+ from .types.fhir_bundle import FhirBundle
18
+ from .types.fhir_bundle_entry_item import FhirBundleEntryItem
19
+ from .types.fhir_patch_request_body_item import FhirPatchRequestBodyItem
20
+ from .types.fhir_resource import FhirResource
21
+ from .types.fhir_resource_meta import FhirResourceMeta
22
+ from .types.fhir_search_response import FhirSearchResponse
23
+
24
+ # this is used as the default value for optional parameters
25
+ OMIT = typing.cast(typing.Any, ...)
26
+
27
+
28
+ class RawFhirClient:
29
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
30
+ self._client_wrapper = client_wrapper
31
+
32
+ def search(
33
+ self,
34
+ fhir_provider_id: str,
35
+ fhir_path: str,
36
+ *,
37
+ query_parameters: typing.Optional[typing.Dict[str, typing.Optional[str]]] = None,
38
+ phenoml_on_behalf_of: typing.Optional[str] = None,
39
+ request_options: typing.Optional[RequestOptions] = None,
40
+ ) -> HttpResponse[FhirSearchResponse]:
41
+ """
42
+ Retrieves FHIR resources from the specified provider. Supports both individual resource retrieval and search operations based on the FHIR path and query parameters.
43
+
44
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
45
+
46
+ Parameters
47
+ ----------
48
+ fhir_provider_id : str
49
+ The ID of the FHIR provider to use. Can be either:
50
+ - A UUID representing the provider ID
51
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
52
+
53
+ fhir_path : str
54
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
55
+ Examples:
56
+ - "Patient" (for resource type operations)
57
+ - "Patient/123" (for specific resource operations)
58
+ - "Patient/123/_history" (for history operations)
59
+
60
+ query_parameters : typing.Optional[typing.Dict[str, typing.Optional[str]]]
61
+ FHIR-compliant query parameters for search operations. Supports standard FHIR search parameters including:
62
+ - Resource-specific search parameters (e.g., name for Patient, status for Observation)
63
+ - Common search parameters (_id, _lastUpdated, _tag, _profile, _security, _text, _content, _filter)
64
+ - Result parameters (_count, _offset, _sort, _include, _revinclude, _summary, _elements)
65
+ - Search prefixes for dates, numbers, quantities (eq, ne, gt, ge, lt, le, sa, eb, ap)
66
+
67
+ phenoml_on_behalf_of : typing.Optional[str]
68
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
69
+
70
+ request_options : typing.Optional[RequestOptions]
71
+ Request-specific configuration.
72
+
73
+ Returns
74
+ -------
75
+ HttpResponse[FhirSearchResponse]
76
+ Successfully retrieved FHIR resource(s)
77
+ """
78
+ _response = self._client_wrapper.httpx_client.request(
79
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
80
+ method="GET",
81
+ params={
82
+ "query_parameters": query_parameters,
83
+ },
84
+ headers={
85
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
86
+ },
87
+ request_options=request_options,
88
+ )
89
+ try:
90
+ if 200 <= _response.status_code < 300:
91
+ _data = typing.cast(
92
+ FhirSearchResponse,
93
+ parse_obj_as(
94
+ type_=FhirSearchResponse, # type: ignore
95
+ object_=_response.json(),
96
+ ),
97
+ )
98
+ return HttpResponse(response=_response, data=_data)
99
+ if _response.status_code == 400:
100
+ raise BadRequestError(
101
+ headers=dict(_response.headers),
102
+ body=typing.cast(
103
+ typing.Optional[typing.Any],
104
+ parse_obj_as(
105
+ type_=typing.Optional[typing.Any], # type: ignore
106
+ object_=_response.json(),
107
+ ),
108
+ ),
109
+ )
110
+ if _response.status_code == 401:
111
+ raise UnauthorizedError(
112
+ headers=dict(_response.headers),
113
+ body=typing.cast(
114
+ typing.Optional[typing.Any],
115
+ parse_obj_as(
116
+ type_=typing.Optional[typing.Any], # type: ignore
117
+ object_=_response.json(),
118
+ ),
119
+ ),
120
+ )
121
+ if _response.status_code == 404:
122
+ raise NotFoundError(
123
+ headers=dict(_response.headers),
124
+ body=typing.cast(
125
+ typing.Optional[typing.Any],
126
+ parse_obj_as(
127
+ type_=typing.Optional[typing.Any], # type: ignore
128
+ object_=_response.json(),
129
+ ),
130
+ ),
131
+ )
132
+ if _response.status_code == 500:
133
+ raise InternalServerError(
134
+ headers=dict(_response.headers),
135
+ body=typing.cast(
136
+ typing.Optional[typing.Any],
137
+ parse_obj_as(
138
+ type_=typing.Optional[typing.Any], # type: ignore
139
+ object_=_response.json(),
140
+ ),
141
+ ),
142
+ )
143
+ _response_json = _response.json()
144
+ except JSONDecodeError:
145
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
146
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
147
+
148
+ def create(
149
+ self,
150
+ fhir_provider_id: str,
151
+ fhir_path: str,
152
+ *,
153
+ resource_type: str,
154
+ phenoml_on_behalf_of: typing.Optional[str] = None,
155
+ id: typing.Optional[str] = OMIT,
156
+ meta: typing.Optional[FhirResourceMeta] = OMIT,
157
+ request_options: typing.Optional[RequestOptions] = None,
158
+ ) -> HttpResponse[FhirResource]:
159
+ """
160
+ Creates a new FHIR resource on the specified provider. The request body should contain a valid FHIR resource in JSON format.
161
+
162
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
163
+
164
+ Parameters
165
+ ----------
166
+ fhir_provider_id : str
167
+ The ID of the FHIR provider to use. Can be either:
168
+ - A UUID representing the provider ID
169
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
170
+
171
+ fhir_path : str
172
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
173
+ Examples:
174
+ - "Patient" (for resource type operations)
175
+ - "Patient/123" (for specific resource operations)
176
+ - "Patient/123/_history" (for history operations)
177
+
178
+ resource_type : str
179
+ The type of FHIR resource (e.g., Patient, Observation, etc.)
180
+
181
+ phenoml_on_behalf_of : typing.Optional[str]
182
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
183
+
184
+ id : typing.Optional[str]
185
+ Logical ID of the resource
186
+
187
+ meta : typing.Optional[FhirResourceMeta]
188
+ Metadata about the resource
189
+
190
+ request_options : typing.Optional[RequestOptions]
191
+ Request-specific configuration.
192
+
193
+ Returns
194
+ -------
195
+ HttpResponse[FhirResource]
196
+ Resource created successfully
197
+ """
198
+ _response = self._client_wrapper.httpx_client.request(
199
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
200
+ method="POST",
201
+ json={
202
+ "resourceType": resource_type,
203
+ "id": id,
204
+ "meta": convert_and_respect_annotation_metadata(
205
+ object_=meta, annotation=FhirResourceMeta, direction="write"
206
+ ),
207
+ },
208
+ headers={
209
+ "content-type": "application/fhir+json",
210
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
211
+ },
212
+ request_options=request_options,
213
+ omit=OMIT,
214
+ )
215
+ try:
216
+ if 200 <= _response.status_code < 300:
217
+ _data = typing.cast(
218
+ FhirResource,
219
+ parse_obj_as(
220
+ type_=FhirResource, # type: ignore
221
+ object_=_response.json(),
222
+ ),
223
+ )
224
+ return HttpResponse(response=_response, data=_data)
225
+ if _response.status_code == 400:
226
+ raise BadRequestError(
227
+ headers=dict(_response.headers),
228
+ body=typing.cast(
229
+ typing.Optional[typing.Any],
230
+ parse_obj_as(
231
+ type_=typing.Optional[typing.Any], # type: ignore
232
+ object_=_response.json(),
233
+ ),
234
+ ),
235
+ )
236
+ if _response.status_code == 401:
237
+ raise UnauthorizedError(
238
+ headers=dict(_response.headers),
239
+ body=typing.cast(
240
+ typing.Optional[typing.Any],
241
+ parse_obj_as(
242
+ type_=typing.Optional[typing.Any], # type: ignore
243
+ object_=_response.json(),
244
+ ),
245
+ ),
246
+ )
247
+ if _response.status_code == 500:
248
+ raise InternalServerError(
249
+ headers=dict(_response.headers),
250
+ body=typing.cast(
251
+ typing.Optional[typing.Any],
252
+ parse_obj_as(
253
+ type_=typing.Optional[typing.Any], # type: ignore
254
+ object_=_response.json(),
255
+ ),
256
+ ),
257
+ )
258
+ _response_json = _response.json()
259
+ except JSONDecodeError:
260
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
261
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
262
+
263
+ def upsert(
264
+ self,
265
+ fhir_provider_id: str,
266
+ fhir_path: str,
267
+ *,
268
+ resource_type: str,
269
+ phenoml_on_behalf_of: typing.Optional[str] = None,
270
+ id: typing.Optional[str] = OMIT,
271
+ meta: typing.Optional[FhirResourceMeta] = OMIT,
272
+ request_options: typing.Optional[RequestOptions] = None,
273
+ ) -> HttpResponse[FhirResource]:
274
+ """
275
+ Creates or updates a FHIR resource on the specified provider. If the resource exists, it will be updated; otherwise, it will be created.
276
+
277
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
278
+
279
+ Parameters
280
+ ----------
281
+ fhir_provider_id : str
282
+ The ID of the FHIR provider to use. Can be either:
283
+ - A UUID representing the provider ID
284
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
285
+
286
+ fhir_path : str
287
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
288
+ Examples:
289
+ - "Patient" (for resource type operations)
290
+ - "Patient/123" (for specific resource operations)
291
+ - "Patient/123/_history" (for history operations)
292
+
293
+ resource_type : str
294
+ The type of FHIR resource (e.g., Patient, Observation, etc.)
295
+
296
+ phenoml_on_behalf_of : typing.Optional[str]
297
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
298
+
299
+ id : typing.Optional[str]
300
+ Logical ID of the resource
301
+
302
+ meta : typing.Optional[FhirResourceMeta]
303
+ Metadata about the resource
304
+
305
+ request_options : typing.Optional[RequestOptions]
306
+ Request-specific configuration.
307
+
308
+ Returns
309
+ -------
310
+ HttpResponse[FhirResource]
311
+ Resource upserted successfully
312
+ """
313
+ _response = self._client_wrapper.httpx_client.request(
314
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
315
+ method="PUT",
316
+ json={
317
+ "resourceType": resource_type,
318
+ "id": id,
319
+ "meta": convert_and_respect_annotation_metadata(
320
+ object_=meta, annotation=FhirResourceMeta, direction="write"
321
+ ),
322
+ },
323
+ headers={
324
+ "content-type": "application/fhir+json",
325
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
326
+ },
327
+ request_options=request_options,
328
+ omit=OMIT,
329
+ )
330
+ try:
331
+ if 200 <= _response.status_code < 300:
332
+ _data = typing.cast(
333
+ FhirResource,
334
+ parse_obj_as(
335
+ type_=FhirResource, # type: ignore
336
+ object_=_response.json(),
337
+ ),
338
+ )
339
+ return HttpResponse(response=_response, data=_data)
340
+ if _response.status_code == 400:
341
+ raise BadRequestError(
342
+ headers=dict(_response.headers),
343
+ body=typing.cast(
344
+ typing.Optional[typing.Any],
345
+ parse_obj_as(
346
+ type_=typing.Optional[typing.Any], # type: ignore
347
+ object_=_response.json(),
348
+ ),
349
+ ),
350
+ )
351
+ if _response.status_code == 401:
352
+ raise UnauthorizedError(
353
+ headers=dict(_response.headers),
354
+ body=typing.cast(
355
+ typing.Optional[typing.Any],
356
+ parse_obj_as(
357
+ type_=typing.Optional[typing.Any], # type: ignore
358
+ object_=_response.json(),
359
+ ),
360
+ ),
361
+ )
362
+ if _response.status_code == 500:
363
+ raise InternalServerError(
364
+ headers=dict(_response.headers),
365
+ body=typing.cast(
366
+ typing.Optional[typing.Any],
367
+ parse_obj_as(
368
+ type_=typing.Optional[typing.Any], # type: ignore
369
+ object_=_response.json(),
370
+ ),
371
+ ),
372
+ )
373
+ _response_json = _response.json()
374
+ except JSONDecodeError:
375
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
376
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
377
+
378
+ def delete(
379
+ self,
380
+ fhir_provider_id: str,
381
+ fhir_path: str,
382
+ *,
383
+ phenoml_on_behalf_of: typing.Optional[str] = None,
384
+ request_options: typing.Optional[RequestOptions] = None,
385
+ ) -> HttpResponse[typing.Dict[str, typing.Optional[typing.Any]]]:
386
+ """
387
+ Deletes a FHIR resource from the specified provider.
388
+
389
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
390
+
391
+ Parameters
392
+ ----------
393
+ fhir_provider_id : str
394
+ The ID of the FHIR provider to use. Can be either:
395
+ - A UUID representing the provider ID
396
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
397
+
398
+ fhir_path : str
399
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
400
+ Examples:
401
+ - "Patient" (for resource type operations)
402
+ - "Patient/123" (for specific resource operations)
403
+ - "Patient/123/_history" (for history operations)
404
+
405
+ phenoml_on_behalf_of : typing.Optional[str]
406
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
407
+
408
+ request_options : typing.Optional[RequestOptions]
409
+ Request-specific configuration.
410
+
411
+ Returns
412
+ -------
413
+ HttpResponse[typing.Dict[str, typing.Optional[typing.Any]]]
414
+ Resource deleted successfully
415
+ """
416
+ _response = self._client_wrapper.httpx_client.request(
417
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
418
+ method="DELETE",
419
+ headers={
420
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
421
+ },
422
+ request_options=request_options,
423
+ )
424
+ try:
425
+ if 200 <= _response.status_code < 300:
426
+ _data = typing.cast(
427
+ typing.Dict[str, typing.Optional[typing.Any]],
428
+ parse_obj_as(
429
+ type_=typing.Dict[str, typing.Optional[typing.Any]], # type: ignore
430
+ object_=_response.json(),
431
+ ),
432
+ )
433
+ return HttpResponse(response=_response, data=_data)
434
+ if _response.status_code == 400:
435
+ raise BadRequestError(
436
+ headers=dict(_response.headers),
437
+ body=typing.cast(
438
+ typing.Optional[typing.Any],
439
+ parse_obj_as(
440
+ type_=typing.Optional[typing.Any], # type: ignore
441
+ object_=_response.json(),
442
+ ),
443
+ ),
444
+ )
445
+ if _response.status_code == 401:
446
+ raise UnauthorizedError(
447
+ headers=dict(_response.headers),
448
+ body=typing.cast(
449
+ typing.Optional[typing.Any],
450
+ parse_obj_as(
451
+ type_=typing.Optional[typing.Any], # type: ignore
452
+ object_=_response.json(),
453
+ ),
454
+ ),
455
+ )
456
+ if _response.status_code == 404:
457
+ raise NotFoundError(
458
+ headers=dict(_response.headers),
459
+ body=typing.cast(
460
+ typing.Optional[typing.Any],
461
+ parse_obj_as(
462
+ type_=typing.Optional[typing.Any], # type: ignore
463
+ object_=_response.json(),
464
+ ),
465
+ ),
466
+ )
467
+ if _response.status_code == 500:
468
+ raise InternalServerError(
469
+ headers=dict(_response.headers),
470
+ body=typing.cast(
471
+ typing.Optional[typing.Any],
472
+ parse_obj_as(
473
+ type_=typing.Optional[typing.Any], # type: ignore
474
+ object_=_response.json(),
475
+ ),
476
+ ),
477
+ )
478
+ _response_json = _response.json()
479
+ except JSONDecodeError:
480
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
481
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
482
+
483
+ def patch(
484
+ self,
485
+ fhir_provider_id: str,
486
+ fhir_path: str,
487
+ *,
488
+ request: typing.Sequence[FhirPatchRequestBodyItem],
489
+ phenoml_on_behalf_of: typing.Optional[str] = None,
490
+ request_options: typing.Optional[RequestOptions] = None,
491
+ ) -> HttpResponse[FhirResource]:
492
+ """
493
+ Partially updates a FHIR resource on the specified provider using JSON Patch operations as defined in RFC 6902.
494
+
495
+ The request body should contain an array of JSON Patch operations. Each operation specifies:
496
+ - `op`: The operation type (add, remove, replace, move, copy, test)
497
+ - `path`: JSON Pointer to the target location in the resource
498
+ - `value`: The value to use (required for add, replace, and test operations)
499
+
500
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
501
+
502
+ Parameters
503
+ ----------
504
+ fhir_provider_id : str
505
+ The ID of the FHIR provider to use. Can be either:
506
+ - A UUID representing the provider ID
507
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
508
+
509
+ fhir_path : str
510
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
511
+ Examples:
512
+ - "Patient" (for resource type operations)
513
+ - "Patient/123" (for specific resource operations)
514
+ - "Patient/123/_history" (for history operations)
515
+
516
+ request : typing.Sequence[FhirPatchRequestBodyItem]
517
+
518
+ phenoml_on_behalf_of : typing.Optional[str]
519
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
520
+
521
+ request_options : typing.Optional[RequestOptions]
522
+ Request-specific configuration.
523
+
524
+ Returns
525
+ -------
526
+ HttpResponse[FhirResource]
527
+ Resource patched successfully
528
+ """
529
+ _response = self._client_wrapper.httpx_client.request(
530
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
531
+ method="PATCH",
532
+ json=convert_and_respect_annotation_metadata(
533
+ object_=request, annotation=typing.Sequence[FhirPatchRequestBodyItem], direction="write"
534
+ ),
535
+ headers={
536
+ "content-type": "application/json-patch+json",
537
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
538
+ },
539
+ request_options=request_options,
540
+ omit=OMIT,
541
+ )
542
+ try:
543
+ if 200 <= _response.status_code < 300:
544
+ _data = typing.cast(
545
+ FhirResource,
546
+ parse_obj_as(
547
+ type_=FhirResource, # type: ignore
548
+ object_=_response.json(),
549
+ ),
550
+ )
551
+ return HttpResponse(response=_response, data=_data)
552
+ if _response.status_code == 400:
553
+ raise BadRequestError(
554
+ headers=dict(_response.headers),
555
+ body=typing.cast(
556
+ typing.Optional[typing.Any],
557
+ parse_obj_as(
558
+ type_=typing.Optional[typing.Any], # type: ignore
559
+ object_=_response.json(),
560
+ ),
561
+ ),
562
+ )
563
+ if _response.status_code == 401:
564
+ raise UnauthorizedError(
565
+ headers=dict(_response.headers),
566
+ body=typing.cast(
567
+ typing.Optional[typing.Any],
568
+ parse_obj_as(
569
+ type_=typing.Optional[typing.Any], # type: ignore
570
+ object_=_response.json(),
571
+ ),
572
+ ),
573
+ )
574
+ if _response.status_code == 404:
575
+ raise NotFoundError(
576
+ headers=dict(_response.headers),
577
+ body=typing.cast(
578
+ typing.Optional[typing.Any],
579
+ parse_obj_as(
580
+ type_=typing.Optional[typing.Any], # type: ignore
581
+ object_=_response.json(),
582
+ ),
583
+ ),
584
+ )
585
+ if _response.status_code == 500:
586
+ raise InternalServerError(
587
+ headers=dict(_response.headers),
588
+ body=typing.cast(
589
+ typing.Optional[typing.Any],
590
+ parse_obj_as(
591
+ type_=typing.Optional[typing.Any], # type: ignore
592
+ object_=_response.json(),
593
+ ),
594
+ ),
595
+ )
596
+ _response_json = _response.json()
597
+ except JSONDecodeError:
598
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
599
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
600
+
601
+ def execute_bundle(
602
+ self,
603
+ fhir_provider_id: str,
604
+ *,
605
+ entry: typing.Sequence[FhirBundleEntryItem],
606
+ phenoml_on_behalf_of: typing.Optional[str] = None,
607
+ total: typing.Optional[int] = OMIT,
608
+ request_options: typing.Optional[RequestOptions] = None,
609
+ ) -> HttpResponse[FhirBundle]:
610
+ """
611
+ Executes a FHIR Bundle transaction or batch operation on the specified provider. This allows multiple FHIR resources to be processed in a single request.
612
+
613
+ The request body should contain a valid FHIR Bundle resource with transaction or batch type.
614
+
615
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
616
+
617
+ Parameters
618
+ ----------
619
+ fhir_provider_id : str
620
+ The ID of the FHIR provider to use. Can be either:
621
+ - A UUID representing the provider ID
622
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
623
+
624
+ entry : typing.Sequence[FhirBundleEntryItem]
625
+ Array of bundle entries containing resources or operation results
626
+
627
+ phenoml_on_behalf_of : typing.Optional[str]
628
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
629
+
630
+ total : typing.Optional[int]
631
+ Total number of resources that match the search criteria.
632
+ Optional field as not all FHIR servers include it (e.g., Medplum).
633
+
634
+ request_options : typing.Optional[RequestOptions]
635
+ Request-specific configuration.
636
+
637
+ Returns
638
+ -------
639
+ HttpResponse[FhirBundle]
640
+ Bundle executed successfully
641
+ """
642
+ _response = self._client_wrapper.httpx_client.request(
643
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir",
644
+ method="POST",
645
+ json={
646
+ "total": total,
647
+ "entry": convert_and_respect_annotation_metadata(
648
+ object_=entry, annotation=typing.Sequence[FhirBundleEntryItem], direction="write"
649
+ ),
650
+ "resourceType": "Bundle",
651
+ },
652
+ headers={
653
+ "content-type": "application/fhir+json",
654
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
655
+ },
656
+ request_options=request_options,
657
+ omit=OMIT,
658
+ )
659
+ try:
660
+ if 200 <= _response.status_code < 300:
661
+ _data = typing.cast(
662
+ FhirBundle,
663
+ parse_obj_as(
664
+ type_=FhirBundle, # type: ignore
665
+ object_=_response.json(),
666
+ ),
667
+ )
668
+ return HttpResponse(response=_response, data=_data)
669
+ if _response.status_code == 400:
670
+ raise BadRequestError(
671
+ headers=dict(_response.headers),
672
+ body=typing.cast(
673
+ typing.Optional[typing.Any],
674
+ parse_obj_as(
675
+ type_=typing.Optional[typing.Any], # type: ignore
676
+ object_=_response.json(),
677
+ ),
678
+ ),
679
+ )
680
+ if _response.status_code == 401:
681
+ raise UnauthorizedError(
682
+ headers=dict(_response.headers),
683
+ body=typing.cast(
684
+ typing.Optional[typing.Any],
685
+ parse_obj_as(
686
+ type_=typing.Optional[typing.Any], # type: ignore
687
+ object_=_response.json(),
688
+ ),
689
+ ),
690
+ )
691
+ if _response.status_code == 500:
692
+ raise InternalServerError(
693
+ headers=dict(_response.headers),
694
+ body=typing.cast(
695
+ typing.Optional[typing.Any],
696
+ parse_obj_as(
697
+ type_=typing.Optional[typing.Any], # type: ignore
698
+ object_=_response.json(),
699
+ ),
700
+ ),
701
+ )
702
+ _response_json = _response.json()
703
+ except JSONDecodeError:
704
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
705
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
706
+
707
+
708
+ class AsyncRawFhirClient:
709
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
710
+ self._client_wrapper = client_wrapper
711
+
712
+ async def search(
713
+ self,
714
+ fhir_provider_id: str,
715
+ fhir_path: str,
716
+ *,
717
+ query_parameters: typing.Optional[typing.Dict[str, typing.Optional[str]]] = None,
718
+ phenoml_on_behalf_of: typing.Optional[str] = None,
719
+ request_options: typing.Optional[RequestOptions] = None,
720
+ ) -> AsyncHttpResponse[FhirSearchResponse]:
721
+ """
722
+ Retrieves FHIR resources from the specified provider. Supports both individual resource retrieval and search operations based on the FHIR path and query parameters.
723
+
724
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
725
+
726
+ Parameters
727
+ ----------
728
+ fhir_provider_id : str
729
+ The ID of the FHIR provider to use. Can be either:
730
+ - A UUID representing the provider ID
731
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
732
+
733
+ fhir_path : str
734
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
735
+ Examples:
736
+ - "Patient" (for resource type operations)
737
+ - "Patient/123" (for specific resource operations)
738
+ - "Patient/123/_history" (for history operations)
739
+
740
+ query_parameters : typing.Optional[typing.Dict[str, typing.Optional[str]]]
741
+ FHIR-compliant query parameters for search operations. Supports standard FHIR search parameters including:
742
+ - Resource-specific search parameters (e.g., name for Patient, status for Observation)
743
+ - Common search parameters (_id, _lastUpdated, _tag, _profile, _security, _text, _content, _filter)
744
+ - Result parameters (_count, _offset, _sort, _include, _revinclude, _summary, _elements)
745
+ - Search prefixes for dates, numbers, quantities (eq, ne, gt, ge, lt, le, sa, eb, ap)
746
+
747
+ phenoml_on_behalf_of : typing.Optional[str]
748
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
749
+
750
+ request_options : typing.Optional[RequestOptions]
751
+ Request-specific configuration.
752
+
753
+ Returns
754
+ -------
755
+ AsyncHttpResponse[FhirSearchResponse]
756
+ Successfully retrieved FHIR resource(s)
757
+ """
758
+ _response = await self._client_wrapper.httpx_client.request(
759
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
760
+ method="GET",
761
+ params={
762
+ "query_parameters": query_parameters,
763
+ },
764
+ headers={
765
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
766
+ },
767
+ request_options=request_options,
768
+ )
769
+ try:
770
+ if 200 <= _response.status_code < 300:
771
+ _data = typing.cast(
772
+ FhirSearchResponse,
773
+ parse_obj_as(
774
+ type_=FhirSearchResponse, # type: ignore
775
+ object_=_response.json(),
776
+ ),
777
+ )
778
+ return AsyncHttpResponse(response=_response, data=_data)
779
+ if _response.status_code == 400:
780
+ raise BadRequestError(
781
+ headers=dict(_response.headers),
782
+ body=typing.cast(
783
+ typing.Optional[typing.Any],
784
+ parse_obj_as(
785
+ type_=typing.Optional[typing.Any], # type: ignore
786
+ object_=_response.json(),
787
+ ),
788
+ ),
789
+ )
790
+ if _response.status_code == 401:
791
+ raise UnauthorizedError(
792
+ headers=dict(_response.headers),
793
+ body=typing.cast(
794
+ typing.Optional[typing.Any],
795
+ parse_obj_as(
796
+ type_=typing.Optional[typing.Any], # type: ignore
797
+ object_=_response.json(),
798
+ ),
799
+ ),
800
+ )
801
+ if _response.status_code == 404:
802
+ raise NotFoundError(
803
+ headers=dict(_response.headers),
804
+ body=typing.cast(
805
+ typing.Optional[typing.Any],
806
+ parse_obj_as(
807
+ type_=typing.Optional[typing.Any], # type: ignore
808
+ object_=_response.json(),
809
+ ),
810
+ ),
811
+ )
812
+ if _response.status_code == 500:
813
+ raise InternalServerError(
814
+ headers=dict(_response.headers),
815
+ body=typing.cast(
816
+ typing.Optional[typing.Any],
817
+ parse_obj_as(
818
+ type_=typing.Optional[typing.Any], # type: ignore
819
+ object_=_response.json(),
820
+ ),
821
+ ),
822
+ )
823
+ _response_json = _response.json()
824
+ except JSONDecodeError:
825
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
826
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
827
+
828
+ async def create(
829
+ self,
830
+ fhir_provider_id: str,
831
+ fhir_path: str,
832
+ *,
833
+ resource_type: str,
834
+ phenoml_on_behalf_of: typing.Optional[str] = None,
835
+ id: typing.Optional[str] = OMIT,
836
+ meta: typing.Optional[FhirResourceMeta] = OMIT,
837
+ request_options: typing.Optional[RequestOptions] = None,
838
+ ) -> AsyncHttpResponse[FhirResource]:
839
+ """
840
+ Creates a new FHIR resource on the specified provider. The request body should contain a valid FHIR resource in JSON format.
841
+
842
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
843
+
844
+ Parameters
845
+ ----------
846
+ fhir_provider_id : str
847
+ The ID of the FHIR provider to use. Can be either:
848
+ - A UUID representing the provider ID
849
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
850
+
851
+ fhir_path : str
852
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
853
+ Examples:
854
+ - "Patient" (for resource type operations)
855
+ - "Patient/123" (for specific resource operations)
856
+ - "Patient/123/_history" (for history operations)
857
+
858
+ resource_type : str
859
+ The type of FHIR resource (e.g., Patient, Observation, etc.)
860
+
861
+ phenoml_on_behalf_of : typing.Optional[str]
862
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
863
+
864
+ id : typing.Optional[str]
865
+ Logical ID of the resource
866
+
867
+ meta : typing.Optional[FhirResourceMeta]
868
+ Metadata about the resource
869
+
870
+ request_options : typing.Optional[RequestOptions]
871
+ Request-specific configuration.
872
+
873
+ Returns
874
+ -------
875
+ AsyncHttpResponse[FhirResource]
876
+ Resource created successfully
877
+ """
878
+ _response = await self._client_wrapper.httpx_client.request(
879
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
880
+ method="POST",
881
+ json={
882
+ "resourceType": resource_type,
883
+ "id": id,
884
+ "meta": convert_and_respect_annotation_metadata(
885
+ object_=meta, annotation=FhirResourceMeta, direction="write"
886
+ ),
887
+ },
888
+ headers={
889
+ "content-type": "application/fhir+json",
890
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
891
+ },
892
+ request_options=request_options,
893
+ omit=OMIT,
894
+ )
895
+ try:
896
+ if 200 <= _response.status_code < 300:
897
+ _data = typing.cast(
898
+ FhirResource,
899
+ parse_obj_as(
900
+ type_=FhirResource, # type: ignore
901
+ object_=_response.json(),
902
+ ),
903
+ )
904
+ return AsyncHttpResponse(response=_response, data=_data)
905
+ if _response.status_code == 400:
906
+ raise BadRequestError(
907
+ headers=dict(_response.headers),
908
+ body=typing.cast(
909
+ typing.Optional[typing.Any],
910
+ parse_obj_as(
911
+ type_=typing.Optional[typing.Any], # type: ignore
912
+ object_=_response.json(),
913
+ ),
914
+ ),
915
+ )
916
+ if _response.status_code == 401:
917
+ raise UnauthorizedError(
918
+ headers=dict(_response.headers),
919
+ body=typing.cast(
920
+ typing.Optional[typing.Any],
921
+ parse_obj_as(
922
+ type_=typing.Optional[typing.Any], # type: ignore
923
+ object_=_response.json(),
924
+ ),
925
+ ),
926
+ )
927
+ if _response.status_code == 500:
928
+ raise InternalServerError(
929
+ headers=dict(_response.headers),
930
+ body=typing.cast(
931
+ typing.Optional[typing.Any],
932
+ parse_obj_as(
933
+ type_=typing.Optional[typing.Any], # type: ignore
934
+ object_=_response.json(),
935
+ ),
936
+ ),
937
+ )
938
+ _response_json = _response.json()
939
+ except JSONDecodeError:
940
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
941
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
942
+
943
+ async def upsert(
944
+ self,
945
+ fhir_provider_id: str,
946
+ fhir_path: str,
947
+ *,
948
+ resource_type: str,
949
+ phenoml_on_behalf_of: typing.Optional[str] = None,
950
+ id: typing.Optional[str] = OMIT,
951
+ meta: typing.Optional[FhirResourceMeta] = OMIT,
952
+ request_options: typing.Optional[RequestOptions] = None,
953
+ ) -> AsyncHttpResponse[FhirResource]:
954
+ """
955
+ Creates or updates a FHIR resource on the specified provider. If the resource exists, it will be updated; otherwise, it will be created.
956
+
957
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
958
+
959
+ Parameters
960
+ ----------
961
+ fhir_provider_id : str
962
+ The ID of the FHIR provider to use. Can be either:
963
+ - A UUID representing the provider ID
964
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
965
+
966
+ fhir_path : str
967
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
968
+ Examples:
969
+ - "Patient" (for resource type operations)
970
+ - "Patient/123" (for specific resource operations)
971
+ - "Patient/123/_history" (for history operations)
972
+
973
+ resource_type : str
974
+ The type of FHIR resource (e.g., Patient, Observation, etc.)
975
+
976
+ phenoml_on_behalf_of : typing.Optional[str]
977
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
978
+
979
+ id : typing.Optional[str]
980
+ Logical ID of the resource
981
+
982
+ meta : typing.Optional[FhirResourceMeta]
983
+ Metadata about the resource
984
+
985
+ request_options : typing.Optional[RequestOptions]
986
+ Request-specific configuration.
987
+
988
+ Returns
989
+ -------
990
+ AsyncHttpResponse[FhirResource]
991
+ Resource upserted successfully
992
+ """
993
+ _response = await self._client_wrapper.httpx_client.request(
994
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
995
+ method="PUT",
996
+ json={
997
+ "resourceType": resource_type,
998
+ "id": id,
999
+ "meta": convert_and_respect_annotation_metadata(
1000
+ object_=meta, annotation=FhirResourceMeta, direction="write"
1001
+ ),
1002
+ },
1003
+ headers={
1004
+ "content-type": "application/fhir+json",
1005
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
1006
+ },
1007
+ request_options=request_options,
1008
+ omit=OMIT,
1009
+ )
1010
+ try:
1011
+ if 200 <= _response.status_code < 300:
1012
+ _data = typing.cast(
1013
+ FhirResource,
1014
+ parse_obj_as(
1015
+ type_=FhirResource, # type: ignore
1016
+ object_=_response.json(),
1017
+ ),
1018
+ )
1019
+ return AsyncHttpResponse(response=_response, data=_data)
1020
+ if _response.status_code == 400:
1021
+ raise BadRequestError(
1022
+ headers=dict(_response.headers),
1023
+ body=typing.cast(
1024
+ typing.Optional[typing.Any],
1025
+ parse_obj_as(
1026
+ type_=typing.Optional[typing.Any], # type: ignore
1027
+ object_=_response.json(),
1028
+ ),
1029
+ ),
1030
+ )
1031
+ if _response.status_code == 401:
1032
+ raise UnauthorizedError(
1033
+ headers=dict(_response.headers),
1034
+ body=typing.cast(
1035
+ typing.Optional[typing.Any],
1036
+ parse_obj_as(
1037
+ type_=typing.Optional[typing.Any], # type: ignore
1038
+ object_=_response.json(),
1039
+ ),
1040
+ ),
1041
+ )
1042
+ if _response.status_code == 500:
1043
+ raise InternalServerError(
1044
+ headers=dict(_response.headers),
1045
+ body=typing.cast(
1046
+ typing.Optional[typing.Any],
1047
+ parse_obj_as(
1048
+ type_=typing.Optional[typing.Any], # type: ignore
1049
+ object_=_response.json(),
1050
+ ),
1051
+ ),
1052
+ )
1053
+ _response_json = _response.json()
1054
+ except JSONDecodeError:
1055
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1056
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1057
+
1058
+ async def delete(
1059
+ self,
1060
+ fhir_provider_id: str,
1061
+ fhir_path: str,
1062
+ *,
1063
+ phenoml_on_behalf_of: typing.Optional[str] = None,
1064
+ request_options: typing.Optional[RequestOptions] = None,
1065
+ ) -> AsyncHttpResponse[typing.Dict[str, typing.Optional[typing.Any]]]:
1066
+ """
1067
+ Deletes a FHIR resource from the specified provider.
1068
+
1069
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
1070
+
1071
+ Parameters
1072
+ ----------
1073
+ fhir_provider_id : str
1074
+ The ID of the FHIR provider to use. Can be either:
1075
+ - A UUID representing the provider ID
1076
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
1077
+
1078
+ fhir_path : str
1079
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
1080
+ Examples:
1081
+ - "Patient" (for resource type operations)
1082
+ - "Patient/123" (for specific resource operations)
1083
+ - "Patient/123/_history" (for history operations)
1084
+
1085
+ phenoml_on_behalf_of : typing.Optional[str]
1086
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
1087
+
1088
+ request_options : typing.Optional[RequestOptions]
1089
+ Request-specific configuration.
1090
+
1091
+ Returns
1092
+ -------
1093
+ AsyncHttpResponse[typing.Dict[str, typing.Optional[typing.Any]]]
1094
+ Resource deleted successfully
1095
+ """
1096
+ _response = await self._client_wrapper.httpx_client.request(
1097
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
1098
+ method="DELETE",
1099
+ headers={
1100
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
1101
+ },
1102
+ request_options=request_options,
1103
+ )
1104
+ try:
1105
+ if 200 <= _response.status_code < 300:
1106
+ _data = typing.cast(
1107
+ typing.Dict[str, typing.Optional[typing.Any]],
1108
+ parse_obj_as(
1109
+ type_=typing.Dict[str, typing.Optional[typing.Any]], # type: ignore
1110
+ object_=_response.json(),
1111
+ ),
1112
+ )
1113
+ return AsyncHttpResponse(response=_response, data=_data)
1114
+ if _response.status_code == 400:
1115
+ raise BadRequestError(
1116
+ headers=dict(_response.headers),
1117
+ body=typing.cast(
1118
+ typing.Optional[typing.Any],
1119
+ parse_obj_as(
1120
+ type_=typing.Optional[typing.Any], # type: ignore
1121
+ object_=_response.json(),
1122
+ ),
1123
+ ),
1124
+ )
1125
+ if _response.status_code == 401:
1126
+ raise UnauthorizedError(
1127
+ headers=dict(_response.headers),
1128
+ body=typing.cast(
1129
+ typing.Optional[typing.Any],
1130
+ parse_obj_as(
1131
+ type_=typing.Optional[typing.Any], # type: ignore
1132
+ object_=_response.json(),
1133
+ ),
1134
+ ),
1135
+ )
1136
+ if _response.status_code == 404:
1137
+ raise NotFoundError(
1138
+ headers=dict(_response.headers),
1139
+ body=typing.cast(
1140
+ typing.Optional[typing.Any],
1141
+ parse_obj_as(
1142
+ type_=typing.Optional[typing.Any], # type: ignore
1143
+ object_=_response.json(),
1144
+ ),
1145
+ ),
1146
+ )
1147
+ if _response.status_code == 500:
1148
+ raise InternalServerError(
1149
+ headers=dict(_response.headers),
1150
+ body=typing.cast(
1151
+ typing.Optional[typing.Any],
1152
+ parse_obj_as(
1153
+ type_=typing.Optional[typing.Any], # type: ignore
1154
+ object_=_response.json(),
1155
+ ),
1156
+ ),
1157
+ )
1158
+ _response_json = _response.json()
1159
+ except JSONDecodeError:
1160
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1161
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1162
+
1163
+ async def patch(
1164
+ self,
1165
+ fhir_provider_id: str,
1166
+ fhir_path: str,
1167
+ *,
1168
+ request: typing.Sequence[FhirPatchRequestBodyItem],
1169
+ phenoml_on_behalf_of: typing.Optional[str] = None,
1170
+ request_options: typing.Optional[RequestOptions] = None,
1171
+ ) -> AsyncHttpResponse[FhirResource]:
1172
+ """
1173
+ Partially updates a FHIR resource on the specified provider using JSON Patch operations as defined in RFC 6902.
1174
+
1175
+ The request body should contain an array of JSON Patch operations. Each operation specifies:
1176
+ - `op`: The operation type (add, remove, replace, move, copy, test)
1177
+ - `path`: JSON Pointer to the target location in the resource
1178
+ - `value`: The value to use (required for add, replace, and test operations)
1179
+
1180
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
1181
+
1182
+ Parameters
1183
+ ----------
1184
+ fhir_provider_id : str
1185
+ The ID of the FHIR provider to use. Can be either:
1186
+ - A UUID representing the provider ID
1187
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
1188
+
1189
+ fhir_path : str
1190
+ The FHIR resource path to operate on. This follows FHIR RESTful API conventions.
1191
+ Examples:
1192
+ - "Patient" (for resource type operations)
1193
+ - "Patient/123" (for specific resource operations)
1194
+ - "Patient/123/_history" (for history operations)
1195
+
1196
+ request : typing.Sequence[FhirPatchRequestBodyItem]
1197
+
1198
+ phenoml_on_behalf_of : typing.Optional[str]
1199
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
1200
+
1201
+ request_options : typing.Optional[RequestOptions]
1202
+ Request-specific configuration.
1203
+
1204
+ Returns
1205
+ -------
1206
+ AsyncHttpResponse[FhirResource]
1207
+ Resource patched successfully
1208
+ """
1209
+ _response = await self._client_wrapper.httpx_client.request(
1210
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir/{jsonable_encoder(fhir_path)}",
1211
+ method="PATCH",
1212
+ json=convert_and_respect_annotation_metadata(
1213
+ object_=request, annotation=typing.Sequence[FhirPatchRequestBodyItem], direction="write"
1214
+ ),
1215
+ headers={
1216
+ "content-type": "application/json-patch+json",
1217
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
1218
+ },
1219
+ request_options=request_options,
1220
+ omit=OMIT,
1221
+ )
1222
+ try:
1223
+ if 200 <= _response.status_code < 300:
1224
+ _data = typing.cast(
1225
+ FhirResource,
1226
+ parse_obj_as(
1227
+ type_=FhirResource, # type: ignore
1228
+ object_=_response.json(),
1229
+ ),
1230
+ )
1231
+ return AsyncHttpResponse(response=_response, data=_data)
1232
+ if _response.status_code == 400:
1233
+ raise BadRequestError(
1234
+ headers=dict(_response.headers),
1235
+ body=typing.cast(
1236
+ typing.Optional[typing.Any],
1237
+ parse_obj_as(
1238
+ type_=typing.Optional[typing.Any], # type: ignore
1239
+ object_=_response.json(),
1240
+ ),
1241
+ ),
1242
+ )
1243
+ if _response.status_code == 401:
1244
+ raise UnauthorizedError(
1245
+ headers=dict(_response.headers),
1246
+ body=typing.cast(
1247
+ typing.Optional[typing.Any],
1248
+ parse_obj_as(
1249
+ type_=typing.Optional[typing.Any], # type: ignore
1250
+ object_=_response.json(),
1251
+ ),
1252
+ ),
1253
+ )
1254
+ if _response.status_code == 404:
1255
+ raise NotFoundError(
1256
+ headers=dict(_response.headers),
1257
+ body=typing.cast(
1258
+ typing.Optional[typing.Any],
1259
+ parse_obj_as(
1260
+ type_=typing.Optional[typing.Any], # type: ignore
1261
+ object_=_response.json(),
1262
+ ),
1263
+ ),
1264
+ )
1265
+ if _response.status_code == 500:
1266
+ raise InternalServerError(
1267
+ headers=dict(_response.headers),
1268
+ body=typing.cast(
1269
+ typing.Optional[typing.Any],
1270
+ parse_obj_as(
1271
+ type_=typing.Optional[typing.Any], # type: ignore
1272
+ object_=_response.json(),
1273
+ ),
1274
+ ),
1275
+ )
1276
+ _response_json = _response.json()
1277
+ except JSONDecodeError:
1278
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1279
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
1280
+
1281
+ async def execute_bundle(
1282
+ self,
1283
+ fhir_provider_id: str,
1284
+ *,
1285
+ entry: typing.Sequence[FhirBundleEntryItem],
1286
+ phenoml_on_behalf_of: typing.Optional[str] = None,
1287
+ total: typing.Optional[int] = OMIT,
1288
+ request_options: typing.Optional[RequestOptions] = None,
1289
+ ) -> AsyncHttpResponse[FhirBundle]:
1290
+ """
1291
+ Executes a FHIR Bundle transaction or batch operation on the specified provider. This allows multiple FHIR resources to be processed in a single request.
1292
+
1293
+ The request body should contain a valid FHIR Bundle resource with transaction or batch type.
1294
+
1295
+ The request is proxied to the configured FHIR server with appropriate authentication headers.
1296
+
1297
+ Parameters
1298
+ ----------
1299
+ fhir_provider_id : str
1300
+ The ID of the FHIR provider to use. Can be either:
1301
+ - A UUID representing the provider ID
1302
+ - A provider name (legacy support - will just use the most recently updated provider with this name)
1303
+
1304
+ entry : typing.Sequence[FhirBundleEntryItem]
1305
+ Array of bundle entries containing resources or operation results
1306
+
1307
+ phenoml_on_behalf_of : typing.Optional[str]
1308
+ Optional header for on-behalf-of authentication. Used when making requests on behalf of another user or entity.
1309
+
1310
+ total : typing.Optional[int]
1311
+ Total number of resources that match the search criteria.
1312
+ Optional field as not all FHIR servers include it (e.g., Medplum).
1313
+
1314
+ request_options : typing.Optional[RequestOptions]
1315
+ Request-specific configuration.
1316
+
1317
+ Returns
1318
+ -------
1319
+ AsyncHttpResponse[FhirBundle]
1320
+ Bundle executed successfully
1321
+ """
1322
+ _response = await self._client_wrapper.httpx_client.request(
1323
+ f"fhir-provider/{jsonable_encoder(fhir_provider_id)}/fhir",
1324
+ method="POST",
1325
+ json={
1326
+ "total": total,
1327
+ "entry": convert_and_respect_annotation_metadata(
1328
+ object_=entry, annotation=typing.Sequence[FhirBundleEntryItem], direction="write"
1329
+ ),
1330
+ "resourceType": "Bundle",
1331
+ },
1332
+ headers={
1333
+ "content-type": "application/fhir+json",
1334
+ "X-Phenoml-On-Behalf-Of": str(phenoml_on_behalf_of) if phenoml_on_behalf_of is not None else None,
1335
+ },
1336
+ request_options=request_options,
1337
+ omit=OMIT,
1338
+ )
1339
+ try:
1340
+ if 200 <= _response.status_code < 300:
1341
+ _data = typing.cast(
1342
+ FhirBundle,
1343
+ parse_obj_as(
1344
+ type_=FhirBundle, # type: ignore
1345
+ object_=_response.json(),
1346
+ ),
1347
+ )
1348
+ return AsyncHttpResponse(response=_response, data=_data)
1349
+ if _response.status_code == 400:
1350
+ raise BadRequestError(
1351
+ headers=dict(_response.headers),
1352
+ body=typing.cast(
1353
+ typing.Optional[typing.Any],
1354
+ parse_obj_as(
1355
+ type_=typing.Optional[typing.Any], # type: ignore
1356
+ object_=_response.json(),
1357
+ ),
1358
+ ),
1359
+ )
1360
+ if _response.status_code == 401:
1361
+ raise UnauthorizedError(
1362
+ headers=dict(_response.headers),
1363
+ body=typing.cast(
1364
+ typing.Optional[typing.Any],
1365
+ parse_obj_as(
1366
+ type_=typing.Optional[typing.Any], # type: ignore
1367
+ object_=_response.json(),
1368
+ ),
1369
+ ),
1370
+ )
1371
+ if _response.status_code == 500:
1372
+ raise InternalServerError(
1373
+ headers=dict(_response.headers),
1374
+ body=typing.cast(
1375
+ typing.Optional[typing.Any],
1376
+ parse_obj_as(
1377
+ type_=typing.Optional[typing.Any], # type: ignore
1378
+ object_=_response.json(),
1379
+ ),
1380
+ ),
1381
+ )
1382
+ _response_json = _response.json()
1383
+ except JSONDecodeError:
1384
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
1385
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)