pysof 0.2.0__tar.gz → 0.2.3__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 (352) hide show
  1. {pysof-0.2.0 → pysof-0.2.3}/Cargo.toml +6 -2
  2. {pysof-0.2.0 → pysof-0.2.3}/PKG-INFO +78 -11
  3. {pysof-0.2.0/crates/pysof → pysof-0.2.3}/README.md +77 -10
  4. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/Cargo.toml +3 -3
  5. pysof-0.2.3/crates/fhir/src/compartment/loader.rs +178 -0
  6. pysof-0.2.3/crates/fhir/src/compartment/mod.rs +15 -0
  7. pysof-0.2.3/crates/fhir/src/compartment_expressions/r6.rs +711 -0
  8. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/lib.rs +120 -0
  9. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/r4.rs +267 -677
  10. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/r4b.rs +271 -681
  11. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/r5.rs +269 -679
  12. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/r6.rs +38881 -45996
  13. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/search/errors.rs +26 -0
  14. pysof-0.2.3/crates/fhir/src/search/loader.rs +1309 -0
  15. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/search/mod.rs +1 -1
  16. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/search/registry.rs +376 -11
  17. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir-macro/Cargo.toml +1 -1
  18. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir-macro/src/lib.rs +188 -290
  19. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/Cargo.toml +7 -2
  20. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/README.md +26 -6
  21. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/boundary_functions.rs +172 -11
  22. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/cli.rs +2 -2
  23. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/evaluator.rs +259 -71
  24. pysof-0.2.3/crates/fhirpath/src/functions.rs +711 -0
  25. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/handlers.rs +2 -0
  26. pysof-0.2.3/crates/fhirpath/src/lib.rs +766 -0
  27. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/parser.rs +1 -1
  28. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/polymorphic_access.rs +612 -86
  29. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/server.rs +15 -11
  30. pysof-0.2.3/crates/fhirpath/src/terminology_client.rs +1014 -0
  31. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/terminology_functions.rs +28 -5
  32. pysof-0.2.3/crates/fhirpath/tests/builtin_functions_evaluator_tests.rs +66 -0
  33. pysof-0.2.3/crates/fhirpath/tests/cli_version_test.rs +17 -0
  34. pysof-0.2.3/crates/fhirpath/tests/common/known_failures.rs +333 -0
  35. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/common/mod.rs +2 -0
  36. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/common/runner.rs +4 -1
  37. pysof-0.2.3/crates/fhirpath/tests/data/r4/rust-known-failures.json +5 -0
  38. pysof-0.2.3/crates/fhirpath/tests/data/r5/known-test-failures.json +71 -0
  39. pysof-0.2.3/crates/fhirpath/tests/data/r5/rust-known-failures.json +56 -0
  40. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/tests-fhir-r5.xml +47 -0
  41. pysof-0.2.3/crates/fhirpath/tests/environment_variables_tests.rs +72 -0
  42. pysof-0.2.3/crates/fhirpath/tests/external_constants_tests.rs +150 -0
  43. pysof-0.2.3/crates/fhirpath/tests/parse_expression_diagnostics_tests.rs +72 -0
  44. pysof-0.2.3/crates/fhirpath/tests/parse_expression_spanned_tests.rs +58 -0
  45. pysof-0.2.3/crates/fhirpath/tests/polymorphic_version_tests.rs +162 -0
  46. pysof-0.2.3/crates/fhirpath/tests/primitive_extension_tests.rs +567 -0
  47. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/r4_tests.rs +161 -164
  48. pysof-0.2.3/crates/fhirpath/tests/r5_tests.rs +601 -0
  49. pysof-0.2.3/crates/fhirpath/tests/terminology_config_tests.rs +174 -0
  50. pysof-0.2.3/crates/fhirpath/tests/valueless_primitive_tests.rs +118 -0
  51. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath-support/src/lib.rs +90 -1
  52. pysof-0.2.3/crates/observability/Cargo.toml +63 -0
  53. pysof-0.2.3/crates/observability/src/dashboard.rs +1105 -0
  54. pysof-0.2.3/crates/observability/src/dashboard_counters.rs +2311 -0
  55. pysof-0.2.3/crates/observability/src/dashboard_metrics.rs +231 -0
  56. pysof-0.2.3/crates/observability/src/lib.rs +56 -0
  57. pysof-0.2.3/crates/observability/src/metrics.rs +107 -0
  58. pysof-0.2.3/crates/observability/src/middleware.rs +315 -0
  59. pysof-0.2.3/crates/observability/src/mode.rs +188 -0
  60. pysof-0.2.3/crates/observability/src/reqlog.rs +404 -0
  61. pysof-0.2.3/crates/observability/src/subscriptions.rs +126 -0
  62. pysof-0.2.3/crates/observability/src/telemetry.rs +166 -0
  63. pysof-0.2.3/crates/observability/src/uptime.rs +56 -0
  64. pysof-0.2.3/crates/observability/tests/middleware.rs +65 -0
  65. pysof-0.2.3/crates/observability/tests/middleware_full.rs +36 -0
  66. pysof-0.2.3/crates/observability/tests/middleware_off.rs +36 -0
  67. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/.gitignore +5 -0
  68. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/Cargo.toml +6 -2
  69. {pysof-0.2.0 → pysof-0.2.3/crates/pysof}/README.md +77 -10
  70. pysof-0.2.3/crates/pysof/build.rs +13 -0
  71. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/python-tests/test_core_functions.py +13 -5
  72. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/python-tests/test_error_handling.py +6 -5
  73. pysof-0.2.3/crates/pysof/python-tests/test_json_string_input.py +116 -0
  74. pysof-0.2.3/crates/pysof/python-tests/test_ndjson_exports.py +85 -0
  75. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/python-tests/test_package_metadata.py +2 -2
  76. pysof-0.2.3/crates/pysof/python-tests/test_remote_resolve.py +141 -0
  77. pysof-0.2.3/crates/pysof/python-tests/test_threading.py +108 -0
  78. pysof-0.2.3/crates/pysof/scripts/bench_threading.py +192 -0
  79. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/src/lib.rs +407 -247
  80. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/src/pysof/__init__.py +218 -18
  81. pysof-0.2.3/crates/pysof/src/pysof/_pysof.pyi +120 -0
  82. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/integration/content_types.rs +66 -65
  83. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/integration.rs +2 -1
  84. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/lib_coverage_tests.rs +3 -1
  85. {pysof-0.2.0 → pysof-0.2.3}/crates/serde-support/Cargo.toml +4 -0
  86. {pysof-0.2.0 → pysof-0.2.3}/crates/serde-support/src/lib.rs +179 -0
  87. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/Cargo.toml +23 -4
  88. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/README.md +84 -43
  89. pysof-0.2.3/crates/sof/scripts/bench_arrow_client.py +126 -0
  90. pysof-0.2.0/crates/sof/src/server.rs → pysof-0.2.3/crates/sof/src/app.rs +60 -313
  91. pysof-0.2.3/crates/sof/src/canonical.rs +80 -0
  92. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/cli.rs +114 -25
  93. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/error.rs +42 -1
  94. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/handlers.rs +380 -198
  95. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/lib.rs +1098 -262
  96. pysof-0.2.3/crates/sof/src/lint/tests.rs +1917 -0
  97. pysof-0.2.3/crates/sof/src/lint.rs +2017 -0
  98. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/models.rs +75 -40
  99. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/params.rs +120 -40
  100. pysof-0.2.3/crates/sof/src/reference_collector.rs +185 -0
  101. pysof-0.2.3/crates/sof/src/remote_fetch.rs +369 -0
  102. pysof-0.2.3/crates/sof/src/remote_resolver.rs +856 -0
  103. pysof-0.2.3/crates/sof/src/server.rs +252 -0
  104. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/sqlquery/bind.rs +71 -0
  105. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/sqlquery/engine.rs +311 -19
  106. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/sqlquery/library.rs +68 -10
  107. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/sqlquery/mod.rs +22 -1
  108. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/sqlquery/params.rs +33 -45
  109. pysof-0.2.3/crates/sof/src/sqlquery/scan.rs +524 -0
  110. pysof-0.2.3/crates/sof/tests/common/mod.rs +11 -0
  111. pysof-0.2.3/crates/sof/tests/resolve_remote_tests.rs +417 -0
  112. pysof-0.2.3/crates/sof/tests/resolve_tests.rs +304 -0
  113. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/run_foreach_tests.rs +10 -4
  114. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/server_tests.rs +415 -191
  115. pysof-0.2.3/crates/sof/tests/sql-on-fhir/README.md +66 -0
  116. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/constant_types.json +12 -9
  117. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fhirpath.json +5 -0
  118. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fn_boundary.json +3 -2
  119. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fn_extension.json +1 -2
  120. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fn_reference_keys.json +2 -0
  121. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/repeat.json +4 -1
  122. pysof-0.2.3/crates/sof/tests/sql-on-fhir/tests/row_index.json +700 -0
  123. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/where.json +4 -0
  124. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/sql_on_fhir_tests.rs +38 -40
  125. pysof-0.2.3/crates/sof/tests/test_arrow_ipc_export.rs +249 -0
  126. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_base64_binary_constant.rs +5 -3
  127. pysof-0.2.3/crates/sof/tests/test_cli_version.rs +17 -0
  128. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_format_parameter_body.rs +14 -23
  129. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_header_parameter_body.rs +19 -28
  130. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_limit_parameter_body.rs +12 -12
  131. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_parameter_validation.rs +3 -3
  132. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_patient_reference_formats.rs +37 -8
  133. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_query_parameter_combinations.rs +74 -32
  134. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_run_operation_parameters.rs +2 -2
  135. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_runner_integration.rs +100 -20
  136. {pysof-0.2.0 → pysof-0.2.3}/pyproject.toml +1 -1
  137. {pysof-0.2.0 → pysof-0.2.3}/src/lib.rs +407 -247
  138. {pysof-0.2.0 → pysof-0.2.3}/src/pysof/__init__.py +218 -18
  139. pysof-0.2.3/src/pysof/_pysof.pyi +120 -0
  140. pysof-0.2.0/crates/fhir/src/compartment_expressions/r6.rs +0 -743
  141. pysof-0.2.0/crates/fhir/src/search/loader.rs +0 -729
  142. pysof-0.2.0/crates/fhirpath/src/lib.rs +0 -385
  143. pysof-0.2.0/crates/fhirpath/src/terminology_client.rs +0 -545
  144. pysof-0.2.0/crates/fhirpath/tests/data/r5/known-test-failures.json +0 -66
  145. pysof-0.2.0/crates/fhirpath/tests/primitive_extension_tests.rs +0 -199
  146. pysof-0.2.0/crates/fhirpath/tests/r5_tests.rs +0 -396
  147. pysof-0.2.0/crates/pysof/multithreading_example.py +0 -100
  148. pysof-0.2.0/crates/pysof/src/pysof/_pysof.pyi +0 -49
  149. pysof-0.2.0/crates/pysof/test_multithreading.py +0 -125
  150. pysof-0.2.0/crates/sof/tests/common/mod.rs +0 -749
  151. pysof-0.2.0/src/pysof/_pysof.cpython-311-darwin.so +0 -4
  152. pysof-0.2.0/src/pysof/_pysof.pyi +0 -49
  153. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/README.md +0 -0
  154. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/build.rs +0 -0
  155. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/compartment_expressions/mod.rs +0 -0
  156. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/compartment_expressions/r4.rs +0 -0
  157. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/compartment_expressions/r4b.rs +0 -0
  158. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/compartment_expressions/r5.rs +0 -0
  159. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/parameters.rs +0 -0
  160. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/r6.rs.template +0 -0
  161. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/src/search/types.rs +0 -0
  162. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/tests/integer_string_integration.rs +0 -0
  163. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/tests/simple_null_test.rs +0 -0
  164. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir/tests/test_contained_stack.rs +0 -0
  165. {pysof-0.2.0 → pysof-0.2.3}/crates/fhir-macro/README.md +0 -0
  166. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/PRECISION_LIMITATION.md +0 -0
  167. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/benches/cli_benches.rs +0 -0
  168. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/benches/evaluator_benches.rs +0 -0
  169. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/benches/parser_benches.rs +0 -0
  170. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/benches/server_benches.rs +0 -0
  171. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/examples/test_ucum.rs +0 -0
  172. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/grammar/fhirpath.g4 +0 -0
  173. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/server-api.md +0 -0
  174. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/aggregate_function.rs +0 -0
  175. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/aggregate_math_functions.rs +0 -0
  176. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/bin/fhirpath-cli.rs +0 -0
  177. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/bin/fhirpath-server.rs +0 -0
  178. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/boolean_functions.rs +0 -0
  179. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/collection_functions.rs +0 -0
  180. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/collection_navigation.rs +0 -0
  181. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/contains_function.rs +0 -0
  182. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/conversion_functions.rs +0 -0
  183. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/date_operation.rs +0 -0
  184. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/datetime_impl.rs +0 -0
  185. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/debug_trace.rs +0 -0
  186. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/distinct_functions.rs +0 -0
  187. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/error.rs +0 -0
  188. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/extension_function.rs +0 -0
  189. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/fhir_type_hierarchy.rs +0 -0
  190. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/format_functions.rs +0 -0
  191. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/interval_functions.rs +0 -0
  192. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/json_utils.rs +0 -0
  193. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/long_conversion.rs +0 -0
  194. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/models.rs +0 -0
  195. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/not_function.rs +0 -0
  196. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/parse_debug.rs +0 -0
  197. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/reference_key_functions.rs +0 -0
  198. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/repeat_all_function.rs +0 -0
  199. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/repeat_function.rs +0 -0
  200. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/resolve_function.rs +0 -0
  201. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/resource_type.rs +0 -0
  202. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/set_operations.rs +0 -0
  203. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/subset_functions.rs +0 -0
  204. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/trace_function.rs +0 -0
  205. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/type_function.rs +0 -0
  206. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/type_inference.rs +0 -0
  207. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/src/ucum.rs +0 -0
  208. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/all_function_tests.rs +0 -0
  209. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/boundary_debug_tests.rs +0 -0
  210. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/boundary_function_integration_tests.rs +0 -0
  211. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/comment_test.rs +0 -0
  212. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/common/context.rs +0 -0
  213. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/common/parser.rs +0 -0
  214. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/context_trace_test.rs +0 -0
  215. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/input/observation-example.json +0 -0
  216. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/input/observation-example.xml +0 -0
  217. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/input/patient-example.json +0 -0
  218. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/input/patient-example.xml +0 -0
  219. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/input/questionnaire-example.json +0 -0
  220. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/input/questionnaire-example.xml +0 -0
  221. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/input/valueset-example-expansion.json +0 -0
  222. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/input/valueset-example-expansion.xml +0 -0
  223. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r4/tests-fhir-r4.xml +0 -0
  224. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/appointment-examplereq.json +0 -0
  225. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/ccda.json +0 -0
  226. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/codesystem-example.json +0 -0
  227. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/conceptmap-example.json +0 -0
  228. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/diagnosticreport-eric.json +0 -0
  229. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/explanationofbenefit-example.json +0 -0
  230. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/observation-example.json +0 -0
  231. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/observation-example.xml +0 -0
  232. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/parameters-example-types.json +0 -0
  233. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/patient-container-example.json +0 -0
  234. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/patient-example-name.json +0 -0
  235. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/patient-example-period.json +0 -0
  236. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/patient-example.json +0 -0
  237. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/patient-name-extensions.json +0 -0
  238. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/questionnaire-example.json +0 -0
  239. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/r5/input/valueset-example-expansion.json +0 -0
  240. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/data/testSchema.xsd +0 -0
  241. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/date_operation_tests.rs +0 -0
  242. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/datetime_boundary_tests.rs +0 -0
  243. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/debug_datetime_boundary.rs +0 -0
  244. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/debug_string_boundary_tests.rs +0 -0
  245. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/define_variable_test.rs +0 -0
  246. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/enhanced_variable_tests.rs +0 -0
  247. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/evaluator_tests.rs +0 -0
  248. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/extension_tests.rs +0 -0
  249. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/fhir_boundary_tests.rs +0 -0
  250. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/http_compression.rs +0 -0
  251. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/is_as_method_tests.rs +0 -0
  252. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/join_function_test.rs +0 -0
  253. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/oftype_datetime_tests.rs +0 -0
  254. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/parse_debug_test.rs +0 -0
  255. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/parser_tests.rs +0 -0
  256. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/polymorphic_r4_tests.rs +0 -0
  257. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/polymorphic_tests.rs +0 -0
  258. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/precision_tests.rs +0 -0
  259. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/reference_key_debug.rs +0 -0
  260. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/test_boundary_zero.rs +0 -0
  261. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/trace_api_test.rs +0 -0
  262. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/trace_tests.rs +0 -0
  263. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/tree_navigation_tests.rs +0 -0
  264. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/truncate_tests.rs +0 -0
  265. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/type_operation_tests.rs +0 -0
  266. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/type_preservation_integration_test.rs +0 -0
  267. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/type_reflection_tests.rs +0 -0
  268. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/unicode_scalar_value_tests.rs +0 -0
  269. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/uri_type_test.rs +0 -0
  270. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath/tests/uuid_type_preservation_test.rs +0 -0
  271. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath-support/Cargo.toml +0 -0
  272. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath-support/README.md +0 -0
  273. {pysof-0.2.0 → pysof-0.2.3}/crates/fhirpath-support/src/type_info.rs +0 -0
  274. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/Cargo.lock +0 -0
  275. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/Makefile +0 -0
  276. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/PYPI_CHECKLIST.md +0 -0
  277. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/WHEEL_BUILDING.md +0 -0
  278. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/python-tests/__init__.py +0 -0
  279. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/python-tests/test_content_types.py +0 -0
  280. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/python-tests/test_fhir_versions.py +0 -0
  281. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/python-tests/test_import.py +0 -0
  282. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/python-tests/test_source_errors.py +0 -0
  283. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/scripts/build-wheels.py +0 -0
  284. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/src/pysof/py.typed +0 -0
  285. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/integration/error_handling.rs +0 -0
  286. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/integration/fhir_versions.rs +0 -0
  287. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/integration/mod.rs +0 -0
  288. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/lib_tests.rs +0 -0
  289. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/multithreading_integration.rs +0 -0
  290. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/tests/threading_test.rs +0 -0
  291. {pysof-0.2.0 → pysof-0.2.3}/crates/pysof/uv.lock +0 -0
  292. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/benches/parallel_processing_bench.rs +0 -0
  293. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/compartment.rs +0 -0
  294. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/constants.rs +0 -0
  295. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/data_source.rs +0 -0
  296. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/fhir_format.rs +0 -0
  297. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/mod.rs +0 -0
  298. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/parquet_schema.rs +0 -0
  299. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/parquet_zip.rs +0 -0
  300. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/sqlquery/output.rs +0 -0
  301. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/src/traits.rs +0 -0
  302. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_boolean_test.rs +0 -0
  303. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_column_ordering.rs +0 -0
  304. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_datetime_instant_constants.rs +0 -0
  305. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_datetime_type_info.rs +0 -0
  306. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_enum_conversion.rs +0 -0
  307. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_evaluation_result_conversion.rs +0 -0
  308. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_extension_function.rs +0 -0
  309. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_extension_macro_fix.rs +0 -0
  310. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_extension_simple.rs +0 -0
  311. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_fhir_resource_structure.rs +0 -0
  312. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_foreach_combinations.rs +0 -0
  313. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_inequality.rs +0 -0
  314. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_instant_constant.rs +0 -0
  315. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_instant_type_info.rs +0 -0
  316. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_raw_resource.rs +0 -0
  317. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/debug_reference_key_types.rs +0 -0
  318. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/extension_debug_test.rs +0 -0
  319. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/foreach_test.rs +0 -0
  320. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/multiselect_test.rs +0 -0
  321. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/basic.json +0 -0
  322. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/collection.json +0 -0
  323. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/combinations.json +0 -0
  324. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/constant.json +0 -0
  325. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fhirpath_numbers.json +0 -0
  326. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fn_empty.json +0 -0
  327. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fn_first.json +0 -0
  328. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fn_join.json +0 -0
  329. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/fn_oftype.json +0 -0
  330. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/foreach.json +0 -0
  331. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/logic.json +0 -0
  332. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/union.json +0 -0
  333. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/validate.json +0 -0
  334. {pysof-0.2.0/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.3/crates/sof/tests/sql-on-fhir}/tests/view_resource.json +0 -0
  335. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_boolean_constant_debug.rs +0 -0
  336. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_boolean_constant_debug2.rs +0 -0
  337. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_boolean_constant_debug3.rs +0 -0
  338. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_boolean_validation.rs +0 -0
  339. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_chunked_processing.rs +0 -0
  340. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_cli_file_source.rs +0 -0
  341. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_csv_quote_handling.rs +0 -0
  342. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_extension_fix_verification.rs +0 -0
  343. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_extension_value_access.rs +0 -0
  344. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_ndjson_input.rs +0 -0
  345. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_parallel_working.rs +0 -0
  346. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_parquet_export.rs +0 -0
  347. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_parquet_large_dataset.rs +0 -0
  348. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_parquet_server_options.rs +0 -0
  349. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_shortened_format_names.rs +0 -0
  350. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_where_clause_validation.rs +0 -0
  351. {pysof-0.2.0 → pysof-0.2.3}/crates/sof/tests/test_x_ndjson_support.rs +0 -0
  352. {pysof-0.2.0 → pysof-0.2.3}/src/pysof/py.typed +0 -0
@@ -17,13 +17,17 @@ crate-type = ["cdylib"]
17
17
 
18
18
  [dependencies]
19
19
  pyo3 = { version = ">=0.29", features = ["extension-module", "generate-import-lib"] }
20
- helios-sof = { path = "../sof", version = "0.2.0", default-features = false }
21
- helios-fhir = { path = "../fhir", version = "0.2.0", default-features = false }
20
+ helios-sof = { path = "../sof", version = "0.2.3", default-features = false }
21
+ helios-fhir = { path = "../fhir", version = "0.2.3", default-features = false }
22
22
  serde = { workspace = true }
23
23
  serde_json = { workspace = true }
24
24
  chrono = { version = "0.4", features = ["serde"] }
25
25
  pythonize = "0.29"
26
26
  csv = "1.3"
27
+ # Drives helios-sof's async remote-resolve functions from the synchronous
28
+ # PyO3 entry points via a current-thread runtime.
29
+ tokio = { version = "1", default-features = false, features = ["rt", "net", "time"] }
30
+ mimalloc = "0.1.52"
27
31
 
28
32
  [features]
29
33
  default = ["R4"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pysof
3
- Version: 0.2.0
3
+ Version: 0.2.3
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.10
6
6
  Classifier: Programming Language :: Python :: 3.11
@@ -34,7 +34,7 @@ Project-URL: Source, https://github.com/HeliosSoftware/hfs/tree/main/crates/pyso
34
34
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
35
35
  [![Downloads](https://pepy.tech/badge/pysof)](https://pepy.tech/project/pysof)
36
36
 
37
- **High-performance FHIR data transformation for Python.** Transform FHIR resources into tabular formats (CSV, JSON, Parquet) using declarative ViewDefinitions from the [SQL on FHIR specification](https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/).
37
+ **High-performance FHIR data transformation for Python.** Transform FHIR resources into tabular formats (CSV, JSON, Parquet) using declarative ViewDefinitions from the [SQL on FHIR specification](http://hl7.org/fhir/uv/sql-on-fhir/).
38
38
 
39
39
  Built in Rust for speed, exposed to Python with a simple, Pythonic API. Part of the [Helios FHIR Server](https://github.com/HeliosSoftware/hfs) project.
40
40
 
@@ -46,7 +46,8 @@ Built in Rust for speed, exposed to Python with a simple, Pythonic API. Part of
46
46
  - 📦 **Streaming Support**: Memory-efficient chunked processing for large NDJSON files
47
47
  - 🌐 **Multi-Version FHIR**: Supports R4, R4B, R5, and R6 (based on build features)
48
48
  - 🎯 **Type-Safe**: Leverages Rust's type safety with a Pythonic interface
49
- - ⚡ **GIL-Free**: Python GIL released during processing for true parallelism
49
+ - ⚡ **GIL-Friendly**: the GIL is released during parsing and processing, so other Python threads stay responsive
50
+ - 📨 **Flexible Input**: ViewDefinitions and Bundles as Python dicts or pre-serialized JSON (`str`/`bytes`)
50
51
 
51
52
  ## 🎯 Why pysof?
52
53
 
@@ -176,6 +177,44 @@ result = pysof.run_view_definition_with_options(
176
177
  )
177
178
  ```
178
179
 
180
+ ### Remote `resolve()` (Trusted Servers)
181
+
182
+ `resolve()` dereferences references against the input bundle by default. You can
183
+ optionally let it fetch references that point at **explicitly trusted** FHIR
184
+ servers and fold them into the resolution pool before rows are generated. This is
185
+ **off by default** and gated by a strict allowlist (matching scheme + host + port
186
+ + path-prefix; private/loopback addresses are blocked unless opted in).
187
+
188
+ ```python
189
+ import pysof
190
+
191
+ config = pysof.RemoteResolveConfig(
192
+ ["https://fhir.example.org/r4"], # trusted base URLs (allowlist)
193
+ max_fetches=256, # per-run/-stream fetch cap
194
+ max_depth=1, # chained-reference rounds
195
+ allow_private_addresses=False, # allow internal LBs (e.g. Traefik) by hostname
196
+ bearer_tokens={"fhir.example.org": "TOKEN"}, # optional per-host auth
197
+ )
198
+
199
+ # Or build it from SOF_RESOLVE_* environment variables:
200
+ # config = pysof.RemoteResolveConfig.from_env()
201
+
202
+ result = pysof.run_view_definition_remote(
203
+ view_definition, bundle, "json", config, fhir_version="R4"
204
+ )
205
+
206
+ # Streaming NDJSON with remote resolve() (one shared cache across chunks):
207
+ stats = pysof.process_ndjson_to_file_remote(
208
+ view_definition, "input.ndjson", "output.json", "ndjson", config, chunk_size=1000
209
+ )
210
+ ```
211
+
212
+ When `config.is_active()` is `False` (disabled or empty allowlist) these behave
213
+ exactly like their non-remote counterparts. Enabling remote resolution makes
214
+ output depend on remote server state at run time. See the
215
+ [SQL-on-FHIR guide](../../book/src/ch06-sql-on-fhir.md) for the full security
216
+ model and configuration reference.
217
+
179
218
  ### Utility Functions
180
219
 
181
220
  ```python
@@ -276,18 +315,46 @@ pysof automatically processes FHIR resources in parallel using rayon:
276
315
  - **5-7x speedup** on typical batch workloads with multi-core CPUs
277
316
  - **Streaming benefits**: `ChunkedProcessor` and `process_ndjson_to_file` also use parallel processing
278
317
  - **Zero configuration** - parallelization is always enabled
279
- - **Python GIL released** during processing for true parallel execution
318
+ - **Python GIL released** during parsing and processing, so other Python threads stay responsive
319
+
320
+ Because each call already fans out across all cores via rayon's shared thread
321
+ pool, running pysof from multiple Python threads does **not** multiply
322
+ throughput — one call can saturate the machine. Use Python threads for
323
+ concurrency (overlapping I/O, serving requests), not to speed up transforms.
324
+
325
+ ### Pass Pre-Serialized JSON for Maximum Speed
326
+
327
+ If your data is already JSON text (from a file, an HTTP body, a database), pass
328
+ the `str` or `bytes` directly instead of `json.loads`-ing it first:
329
+
330
+ ```python
331
+ view_json: str = load_view_definition_text()
332
+ bundle_json: bytes = fetch_bundle_bytes()
333
+
334
+ result = pysof.run_view_definition(view_json, bundle_json, "csv")
335
+ ```
336
+
337
+ This skips the Python-dict conversion entirely and parses the JSON with the
338
+ GIL released — measured 20-27% faster per call on large bundles, with GIL hold
339
+ time dropping from tens of milliseconds to microseconds.
280
340
 
281
341
  ### Performance Benchmarks
282
342
 
283
- | Mode | Dataset | Time | Memory | Notes |
284
- |------|---------|------|--------|-------|
285
- | **Batch** | 10k Patients | ~2.7s | 1.6 GB | All resources in memory |
286
- | **Streaming** | 10k Patients | ~0.9s | 45 MB | 35x less memory, 2.9x faster |
287
- | **Batch** | 93k Encounters | ~4s | 3.9 GB | All resources in memory |
288
- | **Streaming** | 93k Encounters | ~2.8s | 25 MB | 155x less memory, 1.4x faster |
343
+ Measured with `scripts/bench_threading.py` (a 7-column Patient ViewDefinition;
344
+ Windows 11, 12 logical CPUs, Python 3.11, release build with mimalloc):
345
+
346
+ | Path | Dataset | Throughput |
347
+ |------|---------|-----------|
348
+ | **Batch** (dict input) | 2,000-patient bundle | ~28k patients/sec |
349
+ | **Batch** (JSON `str` input) | 2,000-patient bundle | ~31k patients/sec |
350
+ | **Streaming** (`process_ndjson_to_file`) | 5,000-patient NDJSON | ~31k patients/sec |
351
+
352
+ Numbers vary with hardware and ViewDefinition complexity — re-run
353
+ `scripts/bench_threading.py` on your target machine.
289
354
 
290
- Streaming mode (`ChunkedProcessor`, `process_ndjson_to_file`) is recommended for large NDJSON files.
355
+ Streaming mode (`ChunkedProcessor`, `process_ndjson_to_file`) keeps memory
356
+ bounded by `chunk_size` regardless of input size, so it is recommended for
357
+ large NDJSON files; batch mode holds the whole bundle and result in memory.
291
358
 
292
359
  ### Controlling Thread Count (RAYON_NUM_THREADS)
293
360
 
@@ -5,7 +5,7 @@
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![Downloads](https://pepy.tech/badge/pysof)](https://pepy.tech/project/pysof)
7
7
 
8
- **High-performance FHIR data transformation for Python.** Transform FHIR resources into tabular formats (CSV, JSON, Parquet) using declarative ViewDefinitions from the [SQL on FHIR specification](https://build.fhir.org/ig/FHIR/sql-on-fhir-v2/).
8
+ **High-performance FHIR data transformation for Python.** Transform FHIR resources into tabular formats (CSV, JSON, Parquet) using declarative ViewDefinitions from the [SQL on FHIR specification](http://hl7.org/fhir/uv/sql-on-fhir/).
9
9
 
10
10
  Built in Rust for speed, exposed to Python with a simple, Pythonic API. Part of the [Helios FHIR Server](https://github.com/HeliosSoftware/hfs) project.
11
11
 
@@ -17,7 +17,8 @@ Built in Rust for speed, exposed to Python with a simple, Pythonic API. Part of
17
17
  - 📦 **Streaming Support**: Memory-efficient chunked processing for large NDJSON files
18
18
  - 🌐 **Multi-Version FHIR**: Supports R4, R4B, R5, and R6 (based on build features)
19
19
  - 🎯 **Type-Safe**: Leverages Rust's type safety with a Pythonic interface
20
- - ⚡ **GIL-Free**: Python GIL released during processing for true parallelism
20
+ - ⚡ **GIL-Friendly**: the GIL is released during parsing and processing, so other Python threads stay responsive
21
+ - 📨 **Flexible Input**: ViewDefinitions and Bundles as Python dicts or pre-serialized JSON (`str`/`bytes`)
21
22
 
22
23
  ## 🎯 Why pysof?
23
24
 
@@ -147,6 +148,44 @@ result = pysof.run_view_definition_with_options(
147
148
  )
148
149
  ```
149
150
 
151
+ ### Remote `resolve()` (Trusted Servers)
152
+
153
+ `resolve()` dereferences references against the input bundle by default. You can
154
+ optionally let it fetch references that point at **explicitly trusted** FHIR
155
+ servers and fold them into the resolution pool before rows are generated. This is
156
+ **off by default** and gated by a strict allowlist (matching scheme + host + port
157
+ + path-prefix; private/loopback addresses are blocked unless opted in).
158
+
159
+ ```python
160
+ import pysof
161
+
162
+ config = pysof.RemoteResolveConfig(
163
+ ["https://fhir.example.org/r4"], # trusted base URLs (allowlist)
164
+ max_fetches=256, # per-run/-stream fetch cap
165
+ max_depth=1, # chained-reference rounds
166
+ allow_private_addresses=False, # allow internal LBs (e.g. Traefik) by hostname
167
+ bearer_tokens={"fhir.example.org": "TOKEN"}, # optional per-host auth
168
+ )
169
+
170
+ # Or build it from SOF_RESOLVE_* environment variables:
171
+ # config = pysof.RemoteResolveConfig.from_env()
172
+
173
+ result = pysof.run_view_definition_remote(
174
+ view_definition, bundle, "json", config, fhir_version="R4"
175
+ )
176
+
177
+ # Streaming NDJSON with remote resolve() (one shared cache across chunks):
178
+ stats = pysof.process_ndjson_to_file_remote(
179
+ view_definition, "input.ndjson", "output.json", "ndjson", config, chunk_size=1000
180
+ )
181
+ ```
182
+
183
+ When `config.is_active()` is `False` (disabled or empty allowlist) these behave
184
+ exactly like their non-remote counterparts. Enabling remote resolution makes
185
+ output depend on remote server state at run time. See the
186
+ [SQL-on-FHIR guide](../../book/src/ch06-sql-on-fhir.md) for the full security
187
+ model and configuration reference.
188
+
150
189
  ### Utility Functions
151
190
 
152
191
  ```python
@@ -247,18 +286,46 @@ pysof automatically processes FHIR resources in parallel using rayon:
247
286
  - **5-7x speedup** on typical batch workloads with multi-core CPUs
248
287
  - **Streaming benefits**: `ChunkedProcessor` and `process_ndjson_to_file` also use parallel processing
249
288
  - **Zero configuration** - parallelization is always enabled
250
- - **Python GIL released** during processing for true parallel execution
289
+ - **Python GIL released** during parsing and processing, so other Python threads stay responsive
290
+
291
+ Because each call already fans out across all cores via rayon's shared thread
292
+ pool, running pysof from multiple Python threads does **not** multiply
293
+ throughput — one call can saturate the machine. Use Python threads for
294
+ concurrency (overlapping I/O, serving requests), not to speed up transforms.
295
+
296
+ ### Pass Pre-Serialized JSON for Maximum Speed
297
+
298
+ If your data is already JSON text (from a file, an HTTP body, a database), pass
299
+ the `str` or `bytes` directly instead of `json.loads`-ing it first:
300
+
301
+ ```python
302
+ view_json: str = load_view_definition_text()
303
+ bundle_json: bytes = fetch_bundle_bytes()
304
+
305
+ result = pysof.run_view_definition(view_json, bundle_json, "csv")
306
+ ```
307
+
308
+ This skips the Python-dict conversion entirely and parses the JSON with the
309
+ GIL released — measured 20-27% faster per call on large bundles, with GIL hold
310
+ time dropping from tens of milliseconds to microseconds.
251
311
 
252
312
  ### Performance Benchmarks
253
313
 
254
- | Mode | Dataset | Time | Memory | Notes |
255
- |------|---------|------|--------|-------|
256
- | **Batch** | 10k Patients | ~2.7s | 1.6 GB | All resources in memory |
257
- | **Streaming** | 10k Patients | ~0.9s | 45 MB | 35x less memory, 2.9x faster |
258
- | **Batch** | 93k Encounters | ~4s | 3.9 GB | All resources in memory |
259
- | **Streaming** | 93k Encounters | ~2.8s | 25 MB | 155x less memory, 1.4x faster |
314
+ Measured with `scripts/bench_threading.py` (a 7-column Patient ViewDefinition;
315
+ Windows 11, 12 logical CPUs, Python 3.11, release build with mimalloc):
316
+
317
+ | Path | Dataset | Throughput |
318
+ |------|---------|-----------|
319
+ | **Batch** (dict input) | 2,000-patient bundle | ~28k patients/sec |
320
+ | **Batch** (JSON `str` input) | 2,000-patient bundle | ~31k patients/sec |
321
+ | **Streaming** (`process_ndjson_to_file`) | 5,000-patient NDJSON | ~31k patients/sec |
322
+
323
+ Numbers vary with hardware and ViewDefinition complexity — re-run
324
+ `scripts/bench_threading.py` on your target machine.
260
325
 
261
- Streaming mode (`ChunkedProcessor`, `process_ndjson_to_file`) is recommended for large NDJSON files.
326
+ Streaming mode (`ChunkedProcessor`, `process_ndjson_to_file`) keeps memory
327
+ bounded by `chunk_size` regardless of input size, so it is recommended for
328
+ large NDJSON files; batch mode holds the whole bundle and result in memory.
262
329
 
263
330
  ### Controlling Thread Count (RAYON_NUM_THREADS)
264
331
 
@@ -24,9 +24,9 @@ xml = ["helios-serde-support/xml"]
24
24
  serde = { workspace = true }
25
25
  serde_json = { workspace = true, features = ["raw_value"] }
26
26
  clap = { version = "4.0", features = ["derive"] }
27
- helios-fhir-macro = { path = "../fhir-macro", version = "0.2.0" }
28
- helios-serde-support = { path = "../serde-support", version = "0.2.0" }
29
- helios-fhirpath-support = { path = "../fhirpath-support", version = "0.2.0" }
27
+ helios-fhir-macro = { path = "../fhir-macro", version = "0.2.3" }
28
+ helios-serde-support = { path = "../serde-support", version = "0.2.3" }
29
+ helios-fhirpath-support = { path = "../fhirpath-support", version = "0.2.3" }
30
30
  time = "0.3"
31
31
  chrono = { workspace = true }
32
32
  # Re-add serde-with-arbitrary-precision, keep macros
@@ -0,0 +1,178 @@
1
+ //! CompartmentDefinition loader.
2
+ //!
3
+ //! Reads the FHIR spec `CompartmentDefinition` resources from the data
4
+ //! directory, as stored-shape JSON ready to seed into storage. This is the
5
+ //! compartment analogue of
6
+ //! [`SearchParameterLoader::load_spec_resources`](crate::search::loader::SearchParameterLoader::load_spec_resources):
7
+ //! the server seeds these into primary storage at startup so
8
+ //! `GET /CompartmentDefinition` and the web UI read the same definitions the
9
+ //! codegen'd membership table (`crate::get_compartment_params`) is built from.
10
+
11
+ use std::path::Path;
12
+
13
+ use serde_json::Value;
14
+
15
+ use crate::FhirVersion;
16
+ use crate::search::errors::LoaderError;
17
+
18
+ /// Loader for CompartmentDefinition spec resources.
19
+ pub struct CompartmentDefinitionLoader {
20
+ fhir_version: FhirVersion,
21
+ }
22
+
23
+ impl CompartmentDefinitionLoader {
24
+ /// Creates a new loader for the specified FHIR version.
25
+ pub fn new(fhir_version: FhirVersion) -> Self {
26
+ Self { fhir_version }
27
+ }
28
+
29
+ /// Returns the FHIR version.
30
+ pub fn version(&self) -> FhirVersion {
31
+ self.fhir_version
32
+ }
33
+
34
+ /// Returns the spec bundle filename for the configured FHIR version.
35
+ ///
36
+ /// Mirrors the `compartment-definitions-{version}.json` bundles shipped
37
+ /// under the data directory, alongside `search-parameters-{version}.json`.
38
+ #[allow(unreachable_patterns)]
39
+ pub fn spec_filename(&self) -> &'static str {
40
+ match self.fhir_version {
41
+ #[cfg(feature = "R4")]
42
+ FhirVersion::R4 => "compartment-definitions-r4.json",
43
+ #[cfg(feature = "R4B")]
44
+ FhirVersion::R4B => "compartment-definitions-r4b.json",
45
+ #[cfg(feature = "R5")]
46
+ FhirVersion::R5 => "compartment-definitions-r5.json",
47
+ #[cfg(feature = "R6")]
48
+ FhirVersion::R6 => "compartment-definitions-r6.json",
49
+ _ => "compartment-definitions-r4.json",
50
+ }
51
+ }
52
+
53
+ /// Returns the raw CompartmentDefinition resources from the spec bundle,
54
+ /// as stored-shape JSON.
55
+ ///
56
+ /// The seeding companion the server hands to storage: each entry carries
57
+ /// its bundle id (`patient`, `encounter`, …), so re-seeding is idempotent
58
+ /// via `create`'s `AlreadyExists`.
59
+ pub fn load_spec_resources(&self, data_dir: &Path) -> Result<Vec<Value>, LoaderError> {
60
+ let path = data_dir.join(self.spec_filename());
61
+ let content =
62
+ std::fs::read_to_string(&path).map_err(|e| LoaderError::ConfigLoadFailed {
63
+ path: path.display().to_string(),
64
+ message: e.to_string(),
65
+ })?;
66
+ let json: Value =
67
+ serde_json::from_str(&content).map_err(|e| LoaderError::ConfigLoadFailed {
68
+ path: path.display().to_string(),
69
+ message: format!("Invalid JSON: {}", e),
70
+ })?;
71
+
72
+ let mut resources = Vec::new();
73
+ if let Some(entries) = json.get("entry").and_then(|e| e.as_array()) {
74
+ for entry in entries {
75
+ if let Some(resource) = entry.get("resource")
76
+ && resource.get("resourceType").and_then(|t| t.as_str())
77
+ == Some("CompartmentDefinition")
78
+ {
79
+ resources.push(resource.clone());
80
+ }
81
+ }
82
+ }
83
+ Ok(resources)
84
+ }
85
+ }
86
+
87
+ #[cfg(test)]
88
+ mod tests {
89
+ use super::*;
90
+ use std::path::PathBuf;
91
+
92
+ /// Repo-root `data/` directory, from this crate's manifest dir.
93
+ fn workspace_data_dir() -> PathBuf {
94
+ PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../data")
95
+ }
96
+
97
+ #[cfg(feature = "R4")]
98
+ #[test]
99
+ fn loads_r4_compartment_definitions() {
100
+ let loader = CompartmentDefinitionLoader::new(FhirVersion::R4);
101
+ let resources = loader.load_spec_resources(&workspace_data_dir()).unwrap();
102
+ // Device, Encounter, Patient, Practitioner, RelatedPerson (questionnaire
103
+ // has no code and is excluded from the bundle).
104
+ assert_eq!(resources.len(), 5);
105
+ assert!(
106
+ resources
107
+ .iter()
108
+ .all(|r| r["resourceType"] == "CompartmentDefinition")
109
+ );
110
+ assert!(resources.iter().any(|r| r["code"] == "Patient"));
111
+ assert!(
112
+ resources
113
+ .iter()
114
+ .all(|r| r.get("id").and_then(|i| i.as_str()).is_some())
115
+ );
116
+ }
117
+
118
+ #[test]
119
+ fn missing_dir_errors() {
120
+ let loader = CompartmentDefinitionLoader::new(FhirVersion::default_enabled());
121
+ assert!(
122
+ loader
123
+ .load_spec_resources(Path::new("/nonexistent/data/dir"))
124
+ .is_err()
125
+ );
126
+ }
127
+
128
+ /// The shipped `data/compartment-definitions-*.json` bundles must say
129
+ /// exactly what the codegen'd `get_compartment_params` table says — every
130
+ /// `(compartment, resource)` slot, every version. This is the guard against
131
+ /// the seeded copies drifting from `crates/fhir-gen/resources/`.
132
+ fn assert_parity(version: FhirVersion) {
133
+ let loader = CompartmentDefinitionLoader::new(version);
134
+ let defs = loader.load_spec_resources(&workspace_data_dir()).unwrap();
135
+ assert!(!defs.is_empty(), "{version:?} bundle is empty");
136
+ for def in &defs {
137
+ let code = def["code"].as_str().unwrap();
138
+ for resource in def["resource"].as_array().unwrap() {
139
+ let rtype = resource["code"].as_str().unwrap();
140
+ let params: Vec<&str> = resource
141
+ .get("param")
142
+ .and_then(|p| p.as_array())
143
+ .map(|a| a.iter().filter_map(|v| v.as_str()).collect())
144
+ .unwrap_or_default();
145
+ let runtime = crate::get_compartment_params(version, code, rtype);
146
+ assert_eq!(
147
+ runtime,
148
+ params.as_slice(),
149
+ "{version:?} compartment {code} / {rtype}"
150
+ );
151
+ }
152
+ }
153
+ }
154
+
155
+ #[cfg(feature = "R4")]
156
+ #[test]
157
+ fn r4_bundle_matches_codegen_table() {
158
+ assert_parity(FhirVersion::R4);
159
+ }
160
+
161
+ #[cfg(feature = "R4B")]
162
+ #[test]
163
+ fn r4b_bundle_matches_codegen_table() {
164
+ assert_parity(FhirVersion::R4B);
165
+ }
166
+
167
+ #[cfg(feature = "R5")]
168
+ #[test]
169
+ fn r5_bundle_matches_codegen_table() {
170
+ assert_parity(FhirVersion::R5);
171
+ }
172
+
173
+ #[cfg(feature = "R6")]
174
+ #[test]
175
+ fn r6_bundle_matches_codegen_table() {
176
+ assert_parity(FhirVersion::R6);
177
+ }
178
+ }
@@ -0,0 +1,15 @@
1
+ //! FHIR CompartmentDefinition spec data.
2
+ //!
3
+ //! Companion to [`crate::search`]: where SearchParameters drive search
4
+ //! resolution, CompartmentDefinitions describe the compartment membership the
5
+ //! REST compartment-search handler enforces (via the codegen'd
6
+ //! [`crate::get_compartment_params`] table). This module only *loads* the spec
7
+ //! resources so the server can seed them into storage — the source of truth the
8
+ //! `GET /CompartmentDefinition` route and the web UI read from. Membership
9
+ //! itself stays codegen-driven.
10
+ //!
11
+ //! - [`loader`] – [`CompartmentDefinitionLoader`] for reading the spec bundle.
12
+
13
+ pub mod loader;
14
+
15
+ pub use loader::CompartmentDefinitionLoader;