helix.fhir.client.sdk 4.2.15__tar.gz → 4.2.16__tar.gz

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.
Files changed (233) hide show
  1. {helix_fhir_client_sdk-4.2.15/helix.fhir.client.sdk.egg-info → helix_fhir_client_sdk-4.2.16}/PKG-INFO +39 -2
  2. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/README.md +38 -1
  3. helix_fhir_client_sdk-4.2.16/VERSION +1 -0
  4. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16/helix.fhir.client.sdk.egg-info}/PKG-INFO +39 -2
  5. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix.fhir.client.sdk.egg-info/SOURCES.txt +1 -0
  6. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/fhir_client.py +31 -0
  7. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/fhir_delete_mixin.py +58 -43
  8. helix_fhir_client_sdk-4.2.16/helix_fhir_client_sdk/fhir_merge_mixin.py +329 -0
  9. helix_fhir_client_sdk-4.2.16/helix_fhir_client_sdk/fhir_patch_mixin.py +145 -0
  10. helix_fhir_client_sdk-4.2.16/helix_fhir_client_sdk/fhir_update_mixin.py +151 -0
  11. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/open_telemetry/attribute_names.py +3 -0
  12. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/open_telemetry/span_names.py +4 -0
  13. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/retryable_aiohttp_client.py +31 -5
  14. helix_fhir_client_sdk-4.2.16/tests/async/test_retryable_client_session_management.py +155 -0
  15. helix_fhir_client_sdk-4.2.15/VERSION +0 -1
  16. helix_fhir_client_sdk-4.2.15/helix_fhir_client_sdk/fhir_merge_mixin.py +0 -307
  17. helix_fhir_client_sdk-4.2.15/helix_fhir_client_sdk/fhir_patch_mixin.py +0 -130
  18. helix_fhir_client_sdk-4.2.15/helix_fhir_client_sdk/fhir_update_mixin.py +0 -136
  19. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/LICENSE +0 -0
  20. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/MANIFEST.in +0 -0
  21. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/Makefile +0 -0
  22. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix.fhir.client.sdk.egg-info/dependency_links.txt +0 -0
  23. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix.fhir.client.sdk.egg-info/not-zip-safe +0 -0
  24. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix.fhir.client.sdk.egg-info/requires.txt +0 -0
  25. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix.fhir.client.sdk.egg-info/top_level.txt +0 -0
  26. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/__init__.py +0 -0
  27. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/dictionary_parser.py +0 -0
  28. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/dictionary_writer.py +0 -0
  29. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/exceptions/__init__.py +0 -0
  30. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/exceptions/fhir_get_exception.py +0 -0
  31. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/exceptions/fhir_sender_exception.py +0 -0
  32. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/exceptions/fhir_validation_exception.py +0 -0
  33. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/fhir_auth_mixin.py +0 -0
  34. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/fhir_bundle_appender.py +0 -0
  35. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/fhir_merge_resources_mixin.py +0 -0
  36. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/__init__.py +0 -0
  37. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/base_filter.py +0 -0
  38. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/identifier_filter.py +0 -0
  39. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/last_updated_filter.py +0 -0
  40. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/property_filter.py +0 -0
  41. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/property_missing_filter.py +0 -0
  42. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/security_access_filter.py +0 -0
  43. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/security_owner_filter.py +0 -0
  44. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/sort_field.py +0 -0
  45. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/source_filter.py +0 -0
  46. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/filters/version_filter.py +0 -0
  47. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/function_types.py +0 -0
  48. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/__init__.py +0 -0
  49. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/fhir_graph_mixin.py +0 -0
  50. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/graph_definition.py +0 -0
  51. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/graph_link_parameters.py +0 -0
  52. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/graph_target_parameters.py +0 -0
  53. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/simulated_graph_processor_mixin.py +0 -0
  54. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/test/__init__.py +0 -0
  55. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/test/test_graph_mixin.py +0 -0
  56. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/test/test_simulate_graph_processor_mixin.py +0 -0
  57. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/graph/test/test_simulate_graph_processor_mixin_caching.py +0 -0
  58. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/open_telemetry/__init__.py +0 -0
  59. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/py.typed +0 -0
  60. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/queue/__init__.py +0 -0
  61. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/queue/request_queue_mixin.py +0 -0
  62. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/__init__.py +0 -0
  63. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/bundle_expander.py +0 -0
  64. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/fhir_client_protocol.py +0 -0
  65. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/fhir_delete_response.py +0 -0
  66. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/fhir_get_response.py +0 -0
  67. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/fhir_merge_response.py +0 -0
  68. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/fhir_response_processor.py +0 -0
  69. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/fhir_update_response.py +0 -0
  70. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/__init__.py +0 -0
  71. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/fhir_get_bundle_response.py +0 -0
  72. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/fhir_get_error_response.py +0 -0
  73. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/fhir_get_list_by_resource_type_response.py +0 -0
  74. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/fhir_get_list_response.py +0 -0
  75. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/fhir_get_response_factory.py +0 -0
  76. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/fhir_get_single_response.py +0 -0
  77. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/test/__init__.py +0 -0
  78. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/test/test_get_bundle_response.py +0 -0
  79. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/test/test_get_error_response.py +0 -0
  80. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/test/test_get_list_by_resource_type_response.py +0 -0
  81. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/test/test_get_list_response.py +0 -0
  82. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/test/test_get_response_factory.py +0 -0
  83. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get/test/test_get_single_response.py +0 -0
  84. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/get_result.py +0 -0
  85. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/merge/__init__.py +0 -0
  86. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/merge/base_fhir_merge_resource_response_entry.py +0 -0
  87. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/merge/fhir_merge_resource_response.py +0 -0
  88. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/merge/fhir_merge_resource_response_entry.py +0 -0
  89. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/merge/fhir_merge_response_entry_issue.py +0 -0
  90. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/paging_result.py +0 -0
  91. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/resource_separator.py +0 -0
  92. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/__init__.py +0 -0
  93. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/__init__.py +0 -0
  94. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/test_expand_or_separate_bundle_async.py +0 -0
  95. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/test_handle_response_200.py +0 -0
  96. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/test_handle_response_200_non_streaming.py +0 -0
  97. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/test_handle_response_200_non_streaming_separate_bundle.py +0 -0
  98. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/test_handle_response_200_streaming.py +0 -0
  99. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/test_handle_response_200_streaming_separate_bundle.py +0 -0
  100. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/test_handle_response_200_streaming_separate_bundle_ndjson.py +0 -0
  101. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/fhir_response_processor/test_handle_response_404.py +0 -0
  102. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/test_bundle_expander.py +0 -0
  103. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/test_fhir_get_response.py +0 -0
  104. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/responses/test/test_resource_separator.py +0 -0
  105. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/structures/__init__.py +0 -0
  106. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/structures/get_access_token_result.py +0 -0
  107. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/test/__init__.py +0 -0
  108. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/test/test_delete_mixin.py +0 -0
  109. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/test/test_fhir_auth_mixin.py +0 -0
  110. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/test/test_fhir_bundle_appender.py +0 -0
  111. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/test/test_merge_mixin.py +0 -0
  112. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/test/test_merge_mixin_resources.py +0 -0
  113. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/__init__.py +0 -0
  114. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/async_parallel_processor/__init__.py +0 -0
  115. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/async_parallel_processor/v1/__init__.py +0 -0
  116. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/async_parallel_processor/v1/async_parallel_processor.py +0 -0
  117. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/async_runner.py +0 -0
  118. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/cache/__init__.py +0 -0
  119. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/cache/request_cache.py +0 -0
  120. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/cache/request_cache_entry.py +0 -0
  121. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/fhir_client_logger.py +0 -0
  122. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/fhir_helper.py +0 -0
  123. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/fhir_scope_parser.py +0 -0
  124. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/fhir_scope_parser_result.py +0 -0
  125. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/fhir_server_helpers.py +0 -0
  126. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/hash_util.py +0 -0
  127. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/list_chunker.py +0 -0
  128. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/ndjson_chunk_streaming_parser.py +0 -0
  129. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/practitioner_generator.py +0 -0
  130. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/retryable_aiohttp_response.py +0 -0
  131. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/retryable_aiohttp_url_result.py +0 -0
  132. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/size_calculator/__init__.py +0 -0
  133. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/size_calculator/size_calculator.py +0 -0
  134. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/__init__.py +0 -0
  135. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/test_async_runner.py +0 -0
  136. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/test_fhir_scope_parser.py +0 -0
  137. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/test_fhir_scope_parser_can_parse_scopes.py +0 -0
  138. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/test_fhir_scope_parser_correct_allow.py +0 -0
  139. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/test_json_helpers.py +0 -0
  140. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/test_list_chunker.py +0 -0
  141. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/test_ndjson_chunk_streaming_parser.py +0 -0
  142. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/test/test_retryable_aiohttp_client.py +0 -0
  143. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/utilities/url_checker.py +0 -0
  144. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/validators/__init__.py +0 -0
  145. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/validators/async_fhir_validator.py +0 -0
  146. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/validators/fhir_validator.py +0 -0
  147. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/validators/test/__init__.py +0 -0
  148. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/validators/test/test_async_fhir_validator.py +0 -0
  149. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/helix_fhir_client_sdk/well_known_configuration.py +0 -0
  150. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/pyproject.toml +0 -0
  151. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/setup.cfg +0 -0
  152. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/setup.py +0 -0
  153. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/__init__.py +0 -0
  154. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/__init__.py +0 -0
  155. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/fhir_server/__init__.py +0 -0
  156. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/fhir_server/test_async_real_fhir_server_get_graph_large.py +0 -0
  157. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/fhir_server/test_async_real_fhir_server_get_patients_large.py +0 -0
  158. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/graph/__init__.py +0 -0
  159. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/graph/test_fhir_graph.py +0 -0
  160. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/graph/test_fhir_graph_multiple_ids.py +0 -0
  161. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/graph/test_fhir_graph_multiple_ids_in_batches.py +0 -0
  162. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/__init__.py +0 -0
  163. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_async.py +0 -0
  164. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_caching_async.py +0 -0
  165. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_caching_input_cache_async.py +0 -0
  166. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_caching_input_cache_if_modified_since_async.py +0 -0
  167. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_caching_scope_parser_async.py +0 -0
  168. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_separate_resources_async.py +0 -0
  169. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_with_errors_async.py +0 -0
  170. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_with_operation_outcomes_async.py +0 -0
  171. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph/test_fhir_simulated_graph_with_url_column_async.py +0 -0
  172. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph_practitioner/__init__.py +0 -0
  173. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph_practitioner/test_fhir_simulated_graph_multiple_practitioner_async.py +0 -0
  174. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph_practitioner/test_fhir_simulated_graph_multiple_practitioner_in_one_call_async.py +0 -0
  175. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph_practitioner/test_fhir_simulated_graph_multiple_practitioner_in_one_call_async_with_request_size.py +0 -0
  176. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph_practitioner/test_fhir_simulated_graph_practitioner_async.py +0 -0
  177. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/simulated_graph_practitioner/test_fhir_simulated_graph_practitioner_separate_resources_async.py +0 -0
  178. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_bundle/__init__.py +0 -0
  179. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_bundle/not_expanded/__init__.py +0 -0
  180. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_bundle/not_expanded/test_fhir_client_bundle_not_expanded.py +0 -0
  181. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_bundle/not_separated/__init__.py +0 -0
  182. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_bundle/not_separated/test_fhir_client_bundle_not_separated.py +0 -0
  183. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_bundle/separated/__init__.py +0 -0
  184. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_bundle/separated/test_fhir_client_bundle_separated.py +0 -0
  185. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_fetch_response_in_chunks.py +0 -0
  186. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_by_id.py +0 -0
  187. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_by_identifier_missing.py +0 -0
  188. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_delete.py +0 -0
  189. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_list.py +0 -0
  190. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_list_auth_fail.py +0 -0
  191. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_list_auth_fail_retry.py +0 -0
  192. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_list_auth_fail_retry_custom_refresh_function.py +0 -0
  193. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_list_resource_streaming.py +0 -0
  194. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_list_streaming.py +0 -0
  195. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_merge.py +0 -0
  196. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_merge_with_validate.py +0 -0
  197. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_fhir_client_patient_update.py +0 -0
  198. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_real_fhir_server_get_patients.py +0 -0
  199. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_async_real_fhir_server_get_patients_error.py +0 -0
  200. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_benchmark_compress.py +0 -0
  201. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/async/test_benchmark_merge.py +0 -0
  202. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/logger_for_test.py +0 -0
  203. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/__init__.py +0 -0
  204. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/graph/__init__.py +0 -0
  205. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/graph/test_fhir_graph.py +0 -0
  206. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_bundle/__init__.py +0 -0
  207. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_bundle/not_expanded/__init__.py +0 -0
  208. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_bundle/not_expanded/test_fhir_client_bundle_not_expanded.py +0 -0
  209. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_bundle/not_separated/__init__.py +0 -0
  210. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_bundle/not_separated/test_fhir_client_bundle_not_separated.py +0 -0
  211. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_bundle/separated/__init__.py +0 -0
  212. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_bundle/separated/test_fhir_client_bundle_separated.py +0 -0
  213. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_logs_not_contains_secret_information.py +0 -0
  214. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_patient_by_id.py +0 -0
  215. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_patient_delete.py +0 -0
  216. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_patient_list.py +0 -0
  217. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_patient_list_auth_fail.py +0 -0
  218. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_patient_list_auth_fail_retry.py +0 -0
  219. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_patient_merge.py +0 -0
  220. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_patient_update.py +0 -0
  221. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/sync/test_fhir_client_patient_update_patch.py +0 -0
  222. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/test_fhir_client_clone.py +0 -0
  223. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests/test_get_nested_property.py +0 -0
  224. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/__init__.py +0 -0
  225. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_aetna_server_auth.py +0 -0
  226. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_aetna_server_auth_aiohttp.py +0 -0
  227. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_aetna_server_auth_httpx.py +0 -0
  228. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_dev_server_auth.py +0 -0
  229. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_dev_server_no_auth.py +0 -0
  230. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_emr_server_auth.py +0 -0
  231. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_firely_fhir.py +0 -0
  232. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_merge_vs_smart_merge_behavior.py +0 -0
  233. {helix_fhir_client_sdk-4.2.15 → helix_fhir_client_sdk-4.2.16}/tests_integration/test_staging_server_graph.py +0 -0
@@ -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
 
@@ -75,9 +75,46 @@ response: Optional[FhirGetResponse] = await FhirGetResponse.from_async_generator
75
75
  ```
76
76
 
77
77
  # Data Streaming
78
- 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.
78
+ 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.
79
79
  The data will be streamed in AsyncGenerators as described above.
80
80
 
81
+ # Persistent Sessions (Connection Reuse)
82
+ By default, the SDK creates a new HTTP session for each request. For better performance (~4× faster),
83
+ you can use persistent sessions to reuse connections across multiple requests.
84
+
85
+ **Important**: When you provide a custom session factory using `use_http_session()`, YOU are responsible
86
+ for managing the session lifecycle, including closing it when done. The SDK will NOT automatically close
87
+ user-provided sessions.
88
+
89
+ ```python
90
+ import aiohttp
91
+ from helix_fhir_client_sdk.fhir_client import FhirClient
92
+
93
+ # Create a persistent session for connection reuse
94
+ session = aiohttp.ClientSession()
95
+
96
+ try:
97
+ # Configure FhirClient to use persistent session
98
+ fhir_client = (
99
+ FhirClient()
100
+ .url("https://fhir.example.com")
101
+ .resource("Patient")
102
+ .use_http_session(lambda: session) # User provides session factory
103
+ )
104
+
105
+ # Multiple requests reuse the same connection (~4× performance boost)
106
+ response1 = await fhir_client.get_async()
107
+ response2 = await fhir_client.clone().resource("Observation").get_async()
108
+
109
+ finally:
110
+ # User must close the session when done
111
+ await session.close()
112
+ ```
113
+
114
+ **Session Lifecycle Rules**:
115
+ - **No custom factory** (default): SDK creates and closes the session automatically
116
+ - **Custom factory provided**: User is responsible for closing the session
117
+
81
118
  # Storage Compression
82
119
  The FHIR client SDK supports two types of compression:
83
120
 
@@ -0,0 +1 @@
1
+ 4.2.16
@@ -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
 
@@ -166,6 +166,7 @@ tests/async/test_async_real_fhir_server_get_patients.py
166
166
  tests/async/test_async_real_fhir_server_get_patients_error.py
167
167
  tests/async/test_benchmark_compress.py
168
168
  tests/async/test_benchmark_merge.py
169
+ tests/async/test_retryable_client_session_management.py
169
170
  tests/async/fhir_server/__init__.py
170
171
  tests/async/fhir_server/test_async_real_fhir_server_get_graph_large.py
171
172
  tests/async/fhir_server/test_async_real_fhir_server_get_patients_large.py
@@ -488,6 +488,37 @@ class FhirClient(
488
488
  implementation. This allows for custom session management, connection pooling,
489
489
  or persistent session support.
490
490
 
491
+ **Important**: When you provide a custom session factory, YOU are responsible
492
+ for managing the session lifecycle, including closing it when done. The SDK
493
+ will NOT automatically close user-provided sessions.
494
+
495
+ Example with a persistent session for connection reuse (~4× performance boost):
496
+
497
+ .. code-block:: python
498
+
499
+ import aiohttp
500
+ from helix_fhir_client_sdk.fhir_client import FhirClient
501
+
502
+ # Create persistent session
503
+ session = aiohttp.ClientSession()
504
+
505
+ try:
506
+ # Configure FhirClient to use persistent session
507
+ fhir_client = (
508
+ FhirClient()
509
+ .url("http://fhir.example.com")
510
+ .resource("Patient")
511
+ .use_http_session(lambda: session) # User provides session
512
+ )
513
+
514
+ # Multiple requests reuse the same connection
515
+ response1 = await fhir_client.get_async()
516
+ response2 = await fhir_client.clone().resource("Observation").get_async()
517
+
518
+ finally:
519
+ # User must close the session when done
520
+ await session.close()
521
+
491
522
  :param fn_create_http_session: callable that returns a ClientSession, or None to use default
492
523
  """
493
524
  self._fn_create_http_session = fn_create_http_session
@@ -1,7 +1,11 @@
1
1
  import json
2
2
 
3
3
  from furl import furl
4
+ from opentelemetry import trace
5
+ from opentelemetry.trace import Status, StatusCode
4
6
 
7
+ from helix_fhir_client_sdk.open_telemetry.attribute_names import FhirClientSdkOpenTelemetryAttributeNames
8
+ from helix_fhir_client_sdk.open_telemetry.span_names import FhirClientSdkOpenTelemetrySpanNames
5
9
  from helix_fhir_client_sdk.responses.fhir_client_protocol import FhirClientProtocol
6
10
  from helix_fhir_client_sdk.responses.fhir_delete_response import FhirDeleteResponse
7
11
  from helix_fhir_client_sdk.structures.get_access_token_result import (
@@ -15,6 +19,8 @@ from helix_fhir_client_sdk.utilities.retryable_aiohttp_response import (
15
19
  RetryableAioHttpResponse,
16
20
  )
17
21
 
22
+ TRACER = trace.get_tracer(__name__)
23
+
18
24
 
19
25
  class FhirDeleteMixin(FhirClientProtocol):
20
26
  async def delete_async(self) -> FhirDeleteResponse:
@@ -29,50 +35,59 @@ class FhirDeleteMixin(FhirClientProtocol):
29
35
  raise ValueError("delete requires the ID of FHIR object to delete")
30
36
  if not self._resource:
31
37
  raise ValueError("delete requires a FHIR resource type")
32
- full_uri: furl = furl(self._url)
33
- full_uri /= self._resource
34
- full_uri /= id_list
35
- # setup retry
36
- # set up headers
37
- headers: dict[str, str] = {}
38
- headers.update(self._additional_request_headers)
39
- self._internal_logger.debug(f"Request headers: {headers}")
40
-
41
- access_token_result: GetAccessTokenResult = await self.get_access_token_async()
42
- access_token: str | None = access_token_result.access_token
43
- # set access token in request if present
44
- if access_token:
45
- headers["Authorization"] = f"Bearer {access_token}"
46
-
47
- async with RetryableAioHttpClient(
48
- fn_get_session=lambda: self.create_http_session(),
49
- refresh_token_func=self._refresh_token_function,
50
- retries=self._retry_count,
51
- exclude_status_codes_from_retry=self._exclude_status_codes_from_retry,
52
- use_data_streaming=self._use_data_streaming,
53
- compress=False,
54
- throw_exception_on_error=self._throw_exception_on_error,
55
- log_all_url_results=self._log_all_response_urls,
56
- access_token=self._access_token,
57
- access_token_expiry_date=self._access_token_expiry_date,
58
- tracer_request_func=self._trace_request_function,
59
- ) as client:
60
- response: RetryableAioHttpResponse = await client.delete(url=full_uri.tostr(), headers=headers)
61
- request_id = response.response_headers.get("X-Request-ID", None)
62
- self._internal_logger.debug(f"X-Request-ID={request_id}")
63
- if response.status == 200:
64
- if self._logger:
65
- self._logger.info(f"Successfully deleted: {full_uri}")
66
38
 
67
- return FhirDeleteResponse(
68
- request_id=request_id,
69
- url=full_uri.tostr(),
70
- responses=await response.get_text_async(),
71
- error=f"{response.status}" if not response.status == 200 else None,
72
- access_token=access_token,
73
- status=response.status,
74
- resource_type=self._resource,
75
- )
39
+ with TRACER.start_as_current_span(FhirClientSdkOpenTelemetrySpanNames.DELETE) as span:
40
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.URL, self._url or "")
41
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.RESOURCE, self._resource or "")
42
+ try:
43
+ full_uri: furl = furl(self._url)
44
+ full_uri /= self._resource
45
+ full_uri /= id_list
46
+ # setup retry
47
+ # set up headers
48
+ headers: dict[str, str] = {}
49
+ headers.update(self._additional_request_headers)
50
+ self._internal_logger.debug(f"Request headers: {headers}")
51
+
52
+ access_token_result: GetAccessTokenResult = await self.get_access_token_async()
53
+ access_token: str | None = access_token_result.access_token
54
+ # set access token in request if present
55
+ if access_token:
56
+ headers["Authorization"] = f"Bearer {access_token}"
57
+
58
+ async with RetryableAioHttpClient(
59
+ fn_get_session=lambda: self.create_http_session(),
60
+ refresh_token_func=self._refresh_token_function,
61
+ retries=self._retry_count,
62
+ exclude_status_codes_from_retry=self._exclude_status_codes_from_retry,
63
+ use_data_streaming=self._use_data_streaming,
64
+ compress=False,
65
+ throw_exception_on_error=self._throw_exception_on_error,
66
+ log_all_url_results=self._log_all_response_urls,
67
+ access_token=self._access_token,
68
+ access_token_expiry_date=self._access_token_expiry_date,
69
+ tracer_request_func=self._trace_request_function,
70
+ ) as client:
71
+ response: RetryableAioHttpResponse = await client.delete(url=full_uri.tostr(), headers=headers)
72
+ request_id = response.response_headers.get("X-Request-ID", None)
73
+ self._internal_logger.debug(f"X-Request-ID={request_id}")
74
+ if response.status == 200:
75
+ if self._logger:
76
+ self._logger.info(f"Successfully deleted: {full_uri}")
77
+
78
+ return FhirDeleteResponse(
79
+ request_id=request_id,
80
+ url=full_uri.tostr(),
81
+ responses=await response.get_text_async(),
82
+ error=f"{response.status}" if not response.status == 200 else None,
83
+ access_token=access_token,
84
+ status=response.status,
85
+ resource_type=self._resource,
86
+ )
87
+ except Exception as e:
88
+ span.record_exception(e)
89
+ span.set_status(Status(StatusCode.ERROR, str(e)))
90
+ raise
76
91
 
77
92
  def delete(self) -> FhirDeleteResponse:
78
93
  """
@@ -0,0 +1,329 @@
1
+ import json
2
+ import time
3
+ from collections.abc import AsyncGenerator, Generator
4
+ from typing import (
5
+ Any,
6
+ cast,
7
+ )
8
+
9
+ import requests
10
+ from furl import furl
11
+ from opentelemetry import trace
12
+ from opentelemetry.trace import Status, StatusCode
13
+
14
+ from helix_fhir_client_sdk.dictionary_writer import convert_dict_to_str
15
+ from helix_fhir_client_sdk.exceptions.fhir_sender_exception import FhirSenderException
16
+ from helix_fhir_client_sdk.exceptions.fhir_validation_exception import (
17
+ FhirValidationException,
18
+ )
19
+ from helix_fhir_client_sdk.open_telemetry.attribute_names import FhirClientSdkOpenTelemetryAttributeNames
20
+ from helix_fhir_client_sdk.open_telemetry.span_names import FhirClientSdkOpenTelemetrySpanNames
21
+ from helix_fhir_client_sdk.responses.fhir_client_protocol import FhirClientProtocol
22
+ from helix_fhir_client_sdk.responses.fhir_merge_response import FhirMergeResponse
23
+ from helix_fhir_client_sdk.structures.get_access_token_result import (
24
+ GetAccessTokenResult,
25
+ )
26
+ from helix_fhir_client_sdk.utilities.async_runner import AsyncRunner
27
+ from helix_fhir_client_sdk.utilities.fhir_client_logger import FhirClientLogger
28
+ from helix_fhir_client_sdk.utilities.list_chunker import ListChunker
29
+ from helix_fhir_client_sdk.utilities.retryable_aiohttp_client import (
30
+ RetryableAioHttpClient,
31
+ )
32
+ from helix_fhir_client_sdk.utilities.retryable_aiohttp_response import (
33
+ RetryableAioHttpResponse,
34
+ )
35
+ from helix_fhir_client_sdk.validators.async_fhir_validator import AsyncFhirValidator
36
+
37
+ TRACER = trace.get_tracer(__name__)
38
+
39
+
40
+ class FhirMergeMixin(FhirClientProtocol):
41
+ async def validate_content(
42
+ self,
43
+ *,
44
+ errors: list[dict[str, Any]],
45
+ resource_json_list_incoming: list[dict[str, Any]],
46
+ ) -> list[dict[str, Any]]:
47
+ resource_json_list_clean: list[dict[str, Any]] = []
48
+ assert self._validation_server_url
49
+ # if there is only resource then just validate that individually
50
+ if len(resource_json_list_incoming) == 1:
51
+ resource_json: dict[str, Any] = resource_json_list_incoming[0]
52
+ try:
53
+ access_token_result: GetAccessTokenResult = await self.get_access_token_async()
54
+ access_token: str | None = access_token_result.access_token
55
+
56
+ await AsyncFhirValidator.validate_fhir_resource(
57
+ fn_get_session=lambda: self.create_http_session(),
58
+ json_data=json.dumps(resource_json),
59
+ resource_name=cast(str | None, resource_json.get("resourceType")) or self._resource or "",
60
+ validation_server_url=self._validation_server_url,
61
+ access_token=access_token,
62
+ )
63
+ resource_json_list_clean.append(resource_json)
64
+ except FhirValidationException as e:
65
+ errors.append(
66
+ {
67
+ "id": (resource_json.get("id") if resource_json.get("id") else None),
68
+ "resourceType": resource_json.get("resourceType"),
69
+ "issue": e.issue,
70
+ }
71
+ )
72
+ else:
73
+ for resource_json in resource_json_list_incoming:
74
+ try:
75
+ access_token_result1: GetAccessTokenResult = await self.get_access_token_async()
76
+ access_token1: str | None = access_token_result1.access_token
77
+ await AsyncFhirValidator.validate_fhir_resource(
78
+ fn_get_session=lambda: self.create_http_session(),
79
+ json_data=json.dumps(resource_json),
80
+ resource_name=resource_json.get("resourceType") or self._resource or "",
81
+ validation_server_url=self._validation_server_url,
82
+ access_token=access_token1,
83
+ )
84
+ resource_json_list_clean.append(resource_json)
85
+ except FhirValidationException as e:
86
+ errors.append(
87
+ {
88
+ "id": resource_json.get("id"),
89
+ "resourceType": resource_json.get("resourceType"),
90
+ "issue": e.issue,
91
+ }
92
+ )
93
+ return resource_json_list_clean
94
+
95
+ async def merge_async(
96
+ self,
97
+ *,
98
+ id_: str | None = None,
99
+ json_data_list: list[str],
100
+ batch_size: int | None = None,
101
+ ) -> AsyncGenerator[FhirMergeResponse, None]:
102
+ """
103
+ Calls $merge function on FHIR server
104
+
105
+
106
+ :param json_data_list: list of resources to send
107
+ :param id_: id of the resource to merge
108
+ :param batch_size: size of each batch
109
+ :return: response
110
+ """
111
+ assert self._url, "No FHIR server url was set"
112
+ assert isinstance(json_data_list, list), "This function requires a list"
113
+
114
+ with TRACER.start_as_current_span(FhirClientSdkOpenTelemetrySpanNames.MERGE) as span:
115
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.URL, self._url or "")
116
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.RESOURCE, self._resource or "")
117
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.BATCH_SIZE, batch_size or 0)
118
+ span.set_attribute(FhirClientSdkOpenTelemetryAttributeNames.JSON_DATA_COUNT, len(json_data_list))
119
+ try:
120
+ self._internal_logger.debug(
121
+ f"Calling $merge on {self._url} with client_id={self._client_id} and scopes={self._auth_scopes}"
122
+ )
123
+ instance_variables_text = convert_dict_to_str(FhirClientLogger.get_variables_to_log(vars(self)))
124
+ if self._internal_logger:
125
+ self._internal_logger.info(f"parameters: {instance_variables_text}")
126
+ else:
127
+ self._internal_logger.info(f"LOGLEVEL (InternalLogger): {self._log_level}")
128
+ self._internal_logger.info(f"parameters: {instance_variables_text}")
129
+
130
+ request_id: str | None = None
131
+ response_status: int | None = None
132
+ full_uri: furl = furl(self._url)
133
+ assert self._resource
134
+ full_uri /= self._resource
135
+ headers = {"Content-Type": "application/fhir+json"}
136
+ headers.update(self._additional_request_headers)
137
+ self._internal_logger.debug(f"Request headers: {headers}")
138
+
139
+ responses: list[dict[str, Any]] = []
140
+ start_time: float = time.time()
141
+ # set access token in request if present
142
+ access_token_result: GetAccessTokenResult = await self.get_access_token_async()
143
+ access_token: str | None = access_token_result.access_token
144
+ if access_token:
145
+ headers["Authorization"] = f"Bearer {access_token}"
146
+
147
+ try:
148
+ resource_json_list_incoming: list[dict[str, Any]] = [
149
+ json.loads(json_data) for json_data in json_data_list
150
+ ]
151
+ resource_json_list_clean: list[dict[str, Any]]
152
+ errors: list[dict[str, Any]] = []
153
+ if self._validation_server_url:
154
+ resource_json_list_clean = await self.validate_content(
155
+ errors=errors,
156
+ resource_json_list_incoming=resource_json_list_incoming,
157
+ )
158
+ else:
159
+ resource_json_list_clean = resource_json_list_incoming
160
+
161
+ if len(resource_json_list_clean) > 0:
162
+ chunks: Generator[list[dict[str, Any]], None, None] = ListChunker.divide_into_chunks(
163
+ resource_json_list_clean, chunk_size=batch_size
164
+ )
165
+ chunk: list[dict[str, Any]]
166
+ for chunk in chunks:
167
+ resource_uri: furl = full_uri.copy()
168
+ # if there is only item in the list then send it instead of having it in a list
169
+ json_payload: str = json.dumps(chunk[0]) if len(chunk) == 1 else json.dumps(chunk)
170
+ # json_payload_bytes: str = json_payload
171
+ obj_id = id_ or 1 # TODO: remove this once the node fhir accepts merge without a parameter
172
+ assert obj_id
173
+
174
+ if obj_id is not None and str(obj_id).strip():
175
+ resource_uri.path.segments.append(str(obj_id))
176
+ # Always append $merge
177
+ resource_uri.path.segments.append("$merge")
178
+
179
+ # Conditionally add the query parameter
180
+ if self._smart_merge is False:
181
+ resource_uri.add({"smartMerge": "false"})
182
+
183
+ response_text: str | None = None
184
+ try:
185
+ async with RetryableAioHttpClient(
186
+ fn_get_session=lambda: self.create_http_session(),
187
+ refresh_token_func=self._refresh_token_function,
188
+ tracer_request_func=self._trace_request_function,
189
+ retries=self._retry_count,
190
+ exclude_status_codes_from_retry=self._exclude_status_codes_from_retry,
191
+ use_data_streaming=self._use_data_streaming,
192
+ send_data_as_chunked=self._send_data_as_chunked,
193
+ compress=self._compress,
194
+ throw_exception_on_error=self._throw_exception_on_error,
195
+ log_all_url_results=self._log_all_response_urls,
196
+ access_token=self._access_token,
197
+ access_token_expiry_date=self._access_token_expiry_date,
198
+ ) as client:
199
+ # should we check if it exists and do a POST then?
200
+ response: RetryableAioHttpResponse = await client.post(
201
+ url=resource_uri.url,
202
+ data=json_payload,
203
+ headers=headers,
204
+ )
205
+ response_status = response.status
206
+ request_id = response.response_headers.get("X-Request-ID", None)
207
+ self._internal_logger.debug(f"X-Request-ID={request_id}")
208
+ if response and response.status == 200:
209
+ response_text = await response.get_text_async()
210
+ if response_text:
211
+ try:
212
+ raw_response: list[dict[str, Any]] | dict[str, Any] = json.loads(
213
+ response_text
214
+ )
215
+ if isinstance(raw_response, list):
216
+ responses = raw_response
217
+ else:
218
+ responses = [raw_response]
219
+ except ValueError as e:
220
+ responses = [{"issue": str(e)}]
221
+ else:
222
+ responses = []
223
+ yield FhirMergeResponse(
224
+ request_id=request_id,
225
+ url=resource_uri.url,
226
+ responses=responses + errors,
227
+ error=(json.dumps(responses + errors) if response_status != 200 else None),
228
+ access_token=self._access_token,
229
+ status=response_status if response_status else 500,
230
+ json_data=json_payload,
231
+ )
232
+ else: # other HTTP errors
233
+ self._internal_logger.info(
234
+ f"POST response for {resource_uri.url}: {response.status}"
235
+ )
236
+ response_text = await response.get_text_async()
237
+ yield FhirMergeResponse(
238
+ request_id=request_id,
239
+ url=resource_uri.url or self._url or "",
240
+ json_data=json_payload,
241
+ responses=[
242
+ {
243
+ "issue": [
244
+ {
245
+ "severity": "error",
246
+ "code": "exception",
247
+ "diagnostics": response_text,
248
+ }
249
+ ]
250
+ }
251
+ ],
252
+ error=(json.dumps(response_text) if response_text else None),
253
+ access_token=self._access_token,
254
+ status=response.status if response.status else 500,
255
+ )
256
+ except requests.exceptions.HTTPError as e:
257
+ raise FhirSenderException(
258
+ request_id=request_id,
259
+ url=resource_uri.url,
260
+ headers=headers,
261
+ json_data=json_payload,
262
+ response_text=response_text,
263
+ response_status_code=response_status,
264
+ exception=e,
265
+ variables=FhirClientLogger.get_variables_to_log(vars(self)),
266
+ message=f"HttpError: {e}",
267
+ elapsed_time=time.time() - start_time,
268
+ ) from e
269
+ except Exception as e:
270
+ raise FhirSenderException(
271
+ request_id=request_id,
272
+ url=resource_uri.url,
273
+ headers=headers,
274
+ json_data=json_payload,
275
+ response_text=response_text,
276
+ response_status_code=response_status,
277
+ exception=e,
278
+ variables=FhirClientLogger.get_variables_to_log(vars(self)),
279
+ message=f"Unknown Error: {e}",
280
+ elapsed_time=time.time() - start_time,
281
+ ) from e
282
+ else:
283
+ json_payload = json.dumps(json_data_list)
284
+ yield FhirMergeResponse(
285
+ request_id=request_id,
286
+ url=full_uri.url,
287
+ responses=responses + errors,
288
+ error=(json.dumps(responses + errors) if response_status != 200 else None),
289
+ access_token=self._access_token,
290
+ status=response_status if response_status else 500,
291
+ json_data=json_payload,
292
+ )
293
+ except AssertionError as e:
294
+ if self._logger:
295
+ self._logger.error(
296
+ Exception(
297
+ f"Assertion: FHIR send failed: {str(e)} for resource: {json_data_list}. "
298
+ + f"variables={convert_dict_to_str(FhirClientLogger.get_variables_to_log(vars(self)))}"
299
+ )
300
+ )
301
+ raise e
302
+ except Exception as e:
303
+ span.record_exception(e)
304
+ span.set_status(Status(StatusCode.ERROR, str(e)))
305
+ raise
306
+
307
+ def merge(
308
+ self,
309
+ *,
310
+ id_: str | None = None,
311
+ json_data_list: list[str],
312
+ batch_size: int | None = None,
313
+ ) -> FhirMergeResponse | None:
314
+ """
315
+ Calls $merge function on FHIR server
316
+
317
+
318
+ :param json_data_list: list of resources to send
319
+ :param batch_size: size of each batch
320
+ :param id_: id of the resource to merge
321
+ :return: response
322
+ """
323
+
324
+ result: FhirMergeResponse | None = AsyncRunner.run(
325
+ FhirMergeResponse.from_async_generator(
326
+ self.merge_async(id_=id_, json_data_list=json_data_list, batch_size=batch_size)
327
+ )
328
+ )
329
+ return result