helix.fhir.client.sdk 4.2.15__py3-none-any.whl → 4.2.17__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.
@@ -1,14 +1,14 @@
1
1
  helix_fhir_client_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  helix_fhir_client_sdk/dictionary_parser.py,sha256=WrGkVAxMlUvVycRVrX7UZt2oP2e_Vk4-E8QibwTpHLM,3401
3
3
  helix_fhir_client_sdk/dictionary_writer.py,sha256=V7Bx9Z69s0LRYF6Lc6Xp0d-Gj0BnAVKA1vBuwf3JORE,1486
4
- helix_fhir_client_sdk/fhir_auth_mixin.py,sha256=L-_fwQbyojv6AoRUYkPSXWEsW7NRInvJ3wwYgINEtJs,14351
4
+ helix_fhir_client_sdk/fhir_auth_mixin.py,sha256=IZbqG_JtABVvN-_xxFrbupe97Hnc7cNoA2l0D3y0gf8,14549
5
5
  helix_fhir_client_sdk/fhir_bundle_appender.py,sha256=t1hs7p_vXKC9MUFyUnN9dTuDhRF-kw-kkgVFtGHv9QQ,11749
6
- helix_fhir_client_sdk/fhir_client.py,sha256=zCMK19efEE-D6aDfbi5lOBD6Hw-Wa1dWdQj_a1GCLaQ,36142
7
- helix_fhir_client_sdk/fhir_delete_mixin.py,sha256=KaBBkV771sxbqskNZbW0yNVATDaRhd5sX58AKHHai9c,6407
8
- helix_fhir_client_sdk/fhir_merge_mixin.py,sha256=5d0w_hQVJ5EB9FE8jDbgpPwgwCgmf4ZUZ-JY-Rm6zSE,15191
9
- helix_fhir_client_sdk/fhir_merge_resources_mixin.py,sha256=QO2SeZa4Co69f_2YCz0_ss2dJb4xhVMkRdzbjLIJ-iI,35799
10
- helix_fhir_client_sdk/fhir_patch_mixin.py,sha256=t_Qi-FsqNdCUnRMiliL9h09824A-OI3p9bbhM5mI-7Y,5797
11
- helix_fhir_client_sdk/fhir_update_mixin.py,sha256=XYpj0w4TokxHSh1EFqLTHvsfrsIIfwk1q2BN_iuWkXE,6173
6
+ helix_fhir_client_sdk/fhir_client.py,sha256=G6arOw76vcwSkcfAgPHLbOK-B5eWymNMRNygoKIx6FA,37262
7
+ helix_fhir_client_sdk/fhir_delete_mixin.py,sha256=1vgbbBGxXGwp1ay58Du_jWI75BjgfMKtdm5E7A0Oo7U,7738
8
+ helix_fhir_client_sdk/fhir_merge_mixin.py,sha256=ubROibX14IC8iu7CyTKV3KbO34nCJTir3oCT8Gfah_I,18124
9
+ helix_fhir_client_sdk/fhir_merge_resources_mixin.py,sha256=Jynsew9iMWTPeNJ979Dm8EB6DLsc3ddDMeywmeAU6uU,36251
10
+ helix_fhir_client_sdk/fhir_patch_mixin.py,sha256=xFn4RIjGBwnZuIV4eD8E_Yk7lRbwkW6SBHkoNqMz_mk,7360
11
+ helix_fhir_client_sdk/fhir_update_mixin.py,sha256=NQ_6_UHzlFztnH_OrChl6dicC6hR-qBBnPToqZAe_X4,7588
12
12
  helix_fhir_client_sdk/function_types.py,sha256=x95j6ix3Xa9b276Q741xX1jguqBuFT6EBLDw35_EoVM,3916
13
13
  helix_fhir_client_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  helix_fhir_client_sdk/well_known_configuration.py,sha256=hwKpqZoJHkHuCEOowoXk07ywEMMhr_rcmQHNKCUEgVk,221
@@ -38,10 +38,10 @@ helix_fhir_client_sdk/graph/test/test_graph_mixin.py,sha256=LNd4LVjryVLgzWeTXMDp
38
38
  helix_fhir_client_sdk/graph/test/test_simulate_graph_processor_mixin.py,sha256=EQDfhqJfUrP6SptXRP7ayEN7g5cZQMA00ccXzeXiSXM,46312
39
39
  helix_fhir_client_sdk/graph/test/test_simulate_graph_processor_mixin_caching.py,sha256=WFzKKHtKDcOOXjXRMKkRyJ64whoJoo9M9ST88ayvEbY,16176
40
40
  helix_fhir_client_sdk/open_telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
- helix_fhir_client_sdk/open_telemetry/attribute_names.py,sha256=iUxm82t5-_qONL3Ld6LkzOwjuuCwcOptaJVBgCE4tps,169
42
- helix_fhir_client_sdk/open_telemetry/span_names.py,sha256=Y-k29sniK5beSgkEz335eYFpybaw3K_3VU-ayxLdrW0,380
41
+ helix_fhir_client_sdk/open_telemetry/attribute_names.py,sha256=mcPcgpaRe-hZDmPu8gLQo51E_-rllAk2OXMC9uK6EmM,328
42
+ helix_fhir_client_sdk/open_telemetry/span_names.py,sha256=sEuzUXxE9pSoAZti2YVifBqbo3r4SLTPlIUW4F2EuP0,548
43
43
  helix_fhir_client_sdk/queue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
- helix_fhir_client_sdk/queue/request_queue_mixin.py,sha256=Q5ZyadT2nMX6TATsiy0FLXzzCpTbVjN0Gh-B_F0RGCk,21684
44
+ helix_fhir_client_sdk/queue/request_queue_mixin.py,sha256=5Oc5lE-9Mu8R6gBcu6a3HUEvWllIzbF2OFXCTD6W2h8,21890
45
45
  helix_fhir_client_sdk/responses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  helix_fhir_client_sdk/responses/bundle_expander.py,sha256=ilR5eMgciSgzsdQvKB6bHtn9jtpvn3uS-EBz-hrahzo,1065
47
47
  helix_fhir_client_sdk/responses/fhir_client_protocol.py,sha256=IWM7LNQ1ZbgaySLGqpCwWAKyArT5HgBdNhkmSEivNMo,7100
@@ -104,7 +104,7 @@ helix_fhir_client_sdk/utilities/hash_util.py,sha256=YNUy7-IC_OtC0l-T45UO9UkA-_ps
104
104
  helix_fhir_client_sdk/utilities/list_chunker.py,sha256=2h2k5CCFmOhICaugOx6UI-9dh4q5w1lVdF7WQLX0LCM,1456
105
105
  helix_fhir_client_sdk/utilities/ndjson_chunk_streaming_parser.py,sha256=3TCYfWVCEpJbqRxqlSDsGnFnraO4T9bxzYdShvu6Pos,1954
106
106
  helix_fhir_client_sdk/utilities/practitioner_generator.py,sha256=gneCAXNDNEphBY-Nc2nMQBbEWJgHcjvv3S8JQ75yiJI,3778
107
- helix_fhir_client_sdk/utilities/retryable_aiohttp_client.py,sha256=Gb_-EcJRpNlMr5Ma2VlJY51jMCGiU-embiA1V6WMR9s,20617
107
+ helix_fhir_client_sdk/utilities/retryable_aiohttp_client.py,sha256=ytM4wSpxVLrAp30QtCWnu6SpPac4-Gzwv8d86GmtFgk,22827
108
108
  helix_fhir_client_sdk/utilities/retryable_aiohttp_response.py,sha256=DvNX6WO1m2Hz6LoI5CwSPDECPd8oDsqRCVsyq_Oxf-0,3542
109
109
  helix_fhir_client_sdk/utilities/retryable_aiohttp_url_result.py,sha256=Gdmvn6qIM2JF0YOhobQUHY41fCxvYyaths_CZs0iJfo,616
110
110
  helix_fhir_client_sdk/utilities/url_checker.py,sha256=_JRSIvu7WNXh2OA79HJbEEiomGT-quGhAUGh44-9824,3580
@@ -126,11 +126,11 @@ helix_fhir_client_sdk/utilities/test/test_list_chunker.py,sha256=n9J9UZqdluCp2AH
126
126
  helix_fhir_client_sdk/utilities/test/test_ndjson_chunk_streaming_parser.py,sha256=scwktyIIHSRKpw_GTHI4Uj0SsKy3OY4Yf5v5rZGBZXk,5343
127
127
  helix_fhir_client_sdk/utilities/test/test_retryable_aiohttp_client.py,sha256=EeYiYktiLUDTvp5jpJWi7-Qyip4gmI55BJzEhbLpGiE,19121
128
128
  helix_fhir_client_sdk/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
129
- helix_fhir_client_sdk/validators/async_fhir_validator.py,sha256=Bgiw5atbc5YzBYpkV68oJYFz0uaXZzEg2rgORTH_6PM,3676
129
+ helix_fhir_client_sdk/validators/async_fhir_validator.py,sha256=i1BC98hZF6JhMQQzolEAuxQXCP4CMiRewiuQ1ufe0yQ,3879
130
130
  helix_fhir_client_sdk/validators/fhir_validator.py,sha256=HWBldSEB9yeKIcnLcV8R-LoTzwT_OMu8SchtUUBKzys,2331
131
131
  helix_fhir_client_sdk/validators/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
132
  helix_fhir_client_sdk/validators/test/test_async_fhir_validator.py,sha256=RmSowjPUdZee5nYuYujghxWyqJ20cu7U0lJFtFT-ZBs,3285
133
- helix_fhir_client_sdk-4.2.15.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
133
+ helix_fhir_client_sdk-4.2.17.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
134
134
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
135
135
  tests/logger_for_test.py,sha256=UC-7F6w6fDsUIYf37aRnvUdiUUVk8qkJEUSuO17NQnI,1525
136
136
  tests/test_fhir_client_clone.py,sha256=c5y1rWJ32nBSUnK1FfyymY005dNowd4Nf1xrbuQolNk,5368
@@ -153,6 +153,7 @@ tests/async/test_async_real_fhir_server_get_patients.py,sha256=0oMnUJg1KEspJ5_4e
153
153
  tests/async/test_async_real_fhir_server_get_patients_error.py,sha256=_s7chLogAg0yKgGpsq1o9_dDHBrzGaRWBAo8agFTN6U,1914
154
154
  tests/async/test_benchmark_compress.py,sha256=q1gDG7qXvof-3uVAqJlZAW7uO8cR0vEeDfzl-iwIEtY,16470
155
155
  tests/async/test_benchmark_merge.py,sha256=ME0Pow_IXpIaVGWvq3ii7dGltXcz-3DGxz2gGF4LmYQ,19830
156
+ tests/async/test_retryable_client_session_management.py,sha256=h6zTQCICbuz3NpShJc63V9yY_Aur9Fho16-LFDcb4oQ,5658
156
157
  tests/async/fhir_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
157
158
  tests/async/fhir_server/test_async_real_fhir_server_get_graph_large.py,sha256=fM2MPF47nDF2Qwj2AkdTZ2CfvgUYGN4AVIS253KC9MQ,9430
158
159
  tests/async/fhir_server/test_async_real_fhir_server_get_patients_large.py,sha256=rXRF8E8Al7XANCmef1d_WqxSA9TVQjVC7B41OZaEQlY,5583
@@ -212,7 +213,7 @@ tests_integration/test_emr_server_auth.py,sha256=2I4QUAspQN89uGf6JB2aVuYaBeDnRJz
212
213
  tests_integration/test_firely_fhir.py,sha256=ll6-plwQrKfdrEyfbw0wLTC1jB-Qei1Mj-81tYTl5eQ,697
213
214
  tests_integration/test_merge_vs_smart_merge_behavior.py,sha256=LrIuyxzw0YLaTjcRtG0jzy0M6xSv9qebmdBtMPDcacQ,3733
214
215
  tests_integration/test_staging_server_graph.py,sha256=5RfMxjhdX9o4-n_ZRvze4Sm8u8NjRijRLDpqiz8qD_0,7132
215
- helix_fhir_client_sdk-4.2.15.dist-info/METADATA,sha256=7L_vOwYcAkZTKkAtwRolmGQbB7X90cN9EuuwiwBTo24,5845
216
- helix_fhir_client_sdk-4.2.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
217
- helix_fhir_client_sdk-4.2.15.dist-info/top_level.txt,sha256=BRnDS6ceQxs-4u2jXznATObgP8G2cGAerlH0ZS4sJ6M,46
218
- helix_fhir_client_sdk-4.2.15.dist-info/RECORD,,
216
+ helix_fhir_client_sdk-4.2.17.dist-info/METADATA,sha256=KP-b2VyDF8N0VPOshkF_8j7Du3oQgQlhCO5jCU8hHZg,7210
217
+ helix_fhir_client_sdk-4.2.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
218
+ helix_fhir_client_sdk-4.2.17.dist-info/top_level.txt,sha256=BRnDS6ceQxs-4u2jXznATObgP8G2cGAerlH0ZS4sJ6M,46
219
+ helix_fhir_client_sdk-4.2.17.dist-info/RECORD,,
@@ -0,0 +1,159 @@
1
+ """
2
+ Tests for RetryableAioHttpClient session lifecycle management.
3
+
4
+ This module tests that sessions are properly closed or kept open depending on
5
+ whether they were created internally or provided by the user.
6
+ """
7
+
8
+ import aiohttp
9
+ import pytest
10
+
11
+ from helix_fhir_client_sdk.utilities.retryable_aiohttp_client import RetryableAioHttpClient
12
+
13
+
14
+ @pytest.mark.asyncio
15
+ async def test_internal_session_is_closed_after_exit() -> None:
16
+ """Test that internally created sessions are closed when context exits"""
17
+ client = RetryableAioHttpClient(
18
+ retries=1,
19
+ refresh_token_func=None,
20
+ tracer_request_func=None,
21
+ fn_get_session=None, # No custom factory - SDK will create session
22
+ use_data_streaming=False,
23
+ access_token=None,
24
+ access_token_expiry_date=None,
25
+ )
26
+
27
+ async with client:
28
+ # Session should be created
29
+ assert client.session is not None
30
+ assert not client.session.closed
31
+ session_ref = client.session
32
+
33
+ # After exiting context, the internal session should be closed
34
+ assert session_ref.closed
35
+
36
+
37
+ @pytest.mark.asyncio
38
+ async def test_user_provided_session_is_not_closed_after_exit() -> None:
39
+ """Test that user-provided sessions are NOT closed when context exits"""
40
+ # User creates their own session
41
+ user_session = aiohttp.ClientSession()
42
+
43
+ try:
44
+ # Provide a factory that returns the user's session
45
+ # Set caller_managed_session=True so SDK will NOT close the session
46
+ client = RetryableAioHttpClient(
47
+ retries=1,
48
+ refresh_token_func=None,
49
+ tracer_request_func=None,
50
+ fn_get_session=lambda: user_session, # User provides a custom factory
51
+ caller_managed_session=True, # User manages session lifecycle
52
+ use_data_streaming=False,
53
+ access_token=None,
54
+ access_token_expiry_date=None,
55
+ )
56
+
57
+ async with client:
58
+ # Session should be the user's session
59
+ assert client.session is user_session
60
+ assert not client.session.closed
61
+
62
+ # After exiting context, the user's session should still be open
63
+ # because caller_managed_session=True (caller manages session lifecycle)
64
+ assert not user_session.closed
65
+
66
+ finally:
67
+ # User closes their own session
68
+ await user_session.close()
69
+ assert user_session.closed
70
+
71
+
72
+ @pytest.mark.asyncio
73
+ async def test_multiple_clients_can_share_user_session() -> None:
74
+ """Test that multiple RetryableAioHttpClient instances can share the same user session"""
75
+ # User creates a persistent session
76
+ shared_session = aiohttp.ClientSession()
77
+
78
+ try:
79
+ # Multiple clients share the same session
80
+ async with RetryableAioHttpClient(
81
+ retries=1,
82
+ refresh_token_func=None,
83
+ tracer_request_func=None,
84
+ fn_get_session=lambda: shared_session,
85
+ caller_managed_session=True, # User manages session lifecycle
86
+ use_data_streaming=False,
87
+ access_token=None,
88
+ access_token_expiry_date=None,
89
+ ) as client1:
90
+ assert client1.session is shared_session
91
+ assert not shared_session.closed
92
+
93
+ # Session should still be open after the first client exits
94
+ assert not shared_session.closed
95
+
96
+ # The second client can reuse the same session
97
+ async with RetryableAioHttpClient(
98
+ retries=1,
99
+ refresh_token_func=None,
100
+ tracer_request_func=None,
101
+ fn_get_session=lambda: shared_session,
102
+ caller_managed_session=True, # User manages session lifecycle
103
+ use_data_streaming=False,
104
+ access_token=None,
105
+ access_token_expiry_date=None,
106
+ ) as client2:
107
+ assert client2.session is shared_session
108
+ assert not shared_session.closed
109
+
110
+ # Session should still be open after the second client exits
111
+ assert not shared_session.closed
112
+
113
+ finally:
114
+ # User closes the shared session when done
115
+ await shared_session.close()
116
+ assert shared_session.closed
117
+
118
+
119
+ @pytest.mark.asyncio
120
+ async def test_user_can_recreate_closed_session_via_factory() -> None:
121
+ """Test that a user's factory can be called multiple times if session gets closed"""
122
+ call_count = 0
123
+
124
+ def session_factory() -> aiohttp.ClientSession:
125
+ nonlocal call_count
126
+ call_count += 1
127
+ return aiohttp.ClientSession()
128
+
129
+ created_sessions = []
130
+
131
+ try:
132
+ # First client call
133
+ async with RetryableAioHttpClient(
134
+ retries=1,
135
+ refresh_token_func=None,
136
+ tracer_request_func=None,
137
+ fn_get_session=session_factory,
138
+ caller_managed_session=True, # User manages session lifecycle
139
+ use_data_streaming=False,
140
+ access_token=None,
141
+ access_token_expiry_date=None,
142
+ ) as client1:
143
+ assert client1.session is not None
144
+ created_sessions.append(client1.session)
145
+ assert call_count == 1 # Factory called once in __aenter__
146
+
147
+ # SDK doesn't close session (caller_managed_session=True)
148
+ assert created_sessions[0] is not None
149
+ assert not created_sessions[0].closed
150
+
151
+ # User could manually close and recreate via factory if needed
152
+ # (This demonstrates the pattern, though in practice the factory
153
+ # would handle closed session detection)
154
+
155
+ finally:
156
+ # Clean up all created sessions
157
+ for session in created_sessions:
158
+ if session is not None and not session.closed:
159
+ await session.close()