pysof 0.2.1__tar.gz → 0.2.4__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.
- {pysof-0.2.1 → pysof-0.2.4}/Cargo.toml +3 -2
- {pysof-0.2.1 → pysof-0.2.4}/PKG-INFO +40 -11
- {pysof-0.2.1/crates/pysof → pysof-0.2.4}/README.md +39 -10
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/Cargo.toml +3 -3
- pysof-0.2.4/crates/fhir/src/compartment/loader.rs +178 -0
- pysof-0.2.4/crates/fhir/src/compartment/mod.rs +15 -0
- pysof-0.2.4/crates/fhir/src/compartment_expressions/r6.rs +711 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/lib.rs +120 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/r4.rs +277 -677
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/r4b.rs +281 -681
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/r5.rs +279 -679
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/r6.rs +38891 -45996
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/search/errors.rs +26 -0
- pysof-0.2.4/crates/fhir/src/search/loader.rs +1360 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/search/mod.rs +1 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/search/registry.rs +376 -11
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir-macro/Cargo.toml +1 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir-macro/src/lib.rs +188 -290
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/Cargo.toml +7 -2
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/README.md +26 -6
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/boundary_functions.rs +172 -11
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/cli.rs +2 -2
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/evaluator.rs +240 -71
- pysof-0.2.4/crates/fhirpath/src/functions.rs +711 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/handlers.rs +2 -0
- pysof-0.2.4/crates/fhirpath/src/lib.rs +872 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/not_function.rs +2 -3
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/parser.rs +1 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/polymorphic_access.rs +612 -86
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/reference_key_functions.rs +77 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/server.rs +24 -13
- pysof-0.2.4/crates/fhirpath/src/terminology_client.rs +1014 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/terminology_functions.rs +28 -5
- pysof-0.2.4/crates/fhirpath/tests/builtin_functions_evaluator_tests.rs +66 -0
- pysof-0.2.4/crates/fhirpath/tests/cli_version_test.rs +17 -0
- pysof-0.2.4/crates/fhirpath/tests/common/known_failures.rs +333 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/common/mod.rs +2 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/common/runner.rs +4 -1
- pysof-0.2.4/crates/fhirpath/tests/data/r4/rust-known-failures.json +5 -0
- pysof-0.2.4/crates/fhirpath/tests/data/r5/known-test-failures.json +71 -0
- pysof-0.2.4/crates/fhirpath/tests/data/r5/rust-known-failures.json +56 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/tests-fhir-r5.xml +47 -0
- pysof-0.2.4/crates/fhirpath/tests/environment_variables_tests.rs +72 -0
- pysof-0.2.4/crates/fhirpath/tests/external_constants_tests.rs +150 -0
- pysof-0.2.4/crates/fhirpath/tests/nesting_depth.rs +56 -0
- pysof-0.2.4/crates/fhirpath/tests/parse_expression_diagnostics_tests.rs +72 -0
- pysof-0.2.4/crates/fhirpath/tests/parse_expression_spanned_tests.rs +58 -0
- pysof-0.2.4/crates/fhirpath/tests/polymorphic_version_tests.rs +162 -0
- pysof-0.2.4/crates/fhirpath/tests/primitive_extension_tests.rs +567 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/r4_tests.rs +161 -164
- pysof-0.2.4/crates/fhirpath/tests/r5_tests.rs +601 -0
- pysof-0.2.4/crates/fhirpath/tests/terminology_config_tests.rs +174 -0
- pysof-0.2.4/crates/fhirpath/tests/valueless_primitive_tests.rs +118 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath-support/src/lib.rs +90 -1
- pysof-0.2.4/crates/observability/Cargo.toml +64 -0
- pysof-0.2.4/crates/observability/src/composite_metrics.rs +101 -0
- pysof-0.2.4/crates/observability/src/dashboard.rs +1105 -0
- pysof-0.2.4/crates/observability/src/dashboard_counters.rs +2311 -0
- pysof-0.2.4/crates/observability/src/dashboard_metrics.rs +231 -0
- pysof-0.2.4/crates/observability/src/lib.rs +67 -0
- pysof-0.2.4/crates/observability/src/metrics.rs +107 -0
- pysof-0.2.4/crates/observability/src/middleware.rs +315 -0
- pysof-0.2.4/crates/observability/src/mode.rs +188 -0
- pysof-0.2.4/crates/observability/src/reqlog.rs +404 -0
- pysof-0.2.4/crates/observability/src/shutdown.rs +96 -0
- pysof-0.2.4/crates/observability/src/subscriptions.rs +126 -0
- pysof-0.2.4/crates/observability/src/telemetry.rs +166 -0
- pysof-0.2.4/crates/observability/src/uptime.rs +56 -0
- pysof-0.2.4/crates/observability/tests/middleware.rs +65 -0
- pysof-0.2.4/crates/observability/tests/middleware_full.rs +36 -0
- pysof-0.2.4/crates/observability/tests/middleware_off.rs +36 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/.gitignore +5 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/Cargo.toml +3 -2
- {pysof-0.2.1 → pysof-0.2.4/crates/pysof}/README.md +39 -10
- pysof-0.2.4/crates/pysof/build.rs +13 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/test_core_functions.py +13 -5
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/test_error_handling.py +6 -5
- pysof-0.2.4/crates/pysof/python-tests/test_json_string_input.py +116 -0
- pysof-0.2.4/crates/pysof/python-tests/test_ndjson_exports.py +85 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/test_package_metadata.py +2 -2
- pysof-0.2.4/crates/pysof/python-tests/test_threading.py +108 -0
- pysof-0.2.4/crates/pysof/scripts/bench_threading.py +192 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/src/lib.rs +145 -316
- {pysof-0.2.1 → pysof-0.2.4/crates/pysof}/src/pysof/__init__.py +96 -27
- {pysof-0.2.1 → pysof-0.2.4/crates/pysof}/src/pysof/_pysof.pyi +38 -9
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/integration/content_types.rs +66 -65
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/integration.rs +2 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/lib_coverage_tests.rs +3 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/uv.lock +1 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/serde-support/Cargo.toml +4 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/serde-support/src/lib.rs +179 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/Cargo.toml +21 -12
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/README.md +84 -43
- pysof-0.2.4/crates/sof/scripts/bench_arrow_client.py +126 -0
- pysof-0.2.1/crates/sof/src/server.rs → pysof-0.2.4/crates/sof/src/app.rs +60 -313
- pysof-0.2.4/crates/sof/src/canonical.rs +80 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/cli.rs +23 -8
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/error.rs +42 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/handlers.rs +404 -193
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/lib.rs +769 -222
- pysof-0.2.4/crates/sof/src/lint/tests.rs +1918 -0
- pysof-0.2.4/crates/sof/src/lint.rs +2026 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/models.rs +75 -40
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/params.rs +120 -40
- pysof-0.2.4/crates/sof/src/server.rs +259 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/sqlquery/bind.rs +71 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/sqlquery/engine.rs +311 -19
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/sqlquery/library.rs +68 -10
- pysof-0.2.4/crates/sof/src/sqlquery/mod.rs +166 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/sqlquery/params.rs +33 -45
- pysof-0.2.4/crates/sof/src/sqlquery/scan.rs +524 -0
- pysof-0.2.4/crates/sof/tests/common/mod.rs +11 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/run_foreach_tests.rs +1 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/server_tests.rs +415 -191
- pysof-0.2.4/crates/sof/tests/spec_examples.rs +220 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/README.md +22 -3
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-CodeSystemHierarchy.json +43 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-ConditionFlat.json +72 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-EncounterFlat.json +76 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-PatientAddresses.json +40 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-PatientAndContactAddressUnion.json +62 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-PatientDemographics.json +36 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-PatientNamesWithIndex.json +41 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-QuestionnaireResponseItems.json +71 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-ShareablePatientDemographics.json +51 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/ViewDefinition-UsCoreBloodPressures.json +88 -0
- pysof-0.2.4/crates/sof/tests/sql-on-fhir/examples/test-bundle.json +9 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/repeat.json +2 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/sql_on_fhir_tests.rs +17 -37
- pysof-0.2.4/crates/sof/tests/test_arrow_ipc_export.rs +249 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_base64_binary_constant.rs +1 -1
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_chunked_processing.rs +35 -0
- pysof-0.2.4/crates/sof/tests/test_cli_version.rs +17 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_format_parameter_body.rs +14 -23
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_header_parameter_body.rs +19 -28
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_limit_parameter_body.rs +12 -12
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_parameter_validation.rs +3 -3
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_patient_reference_formats.rs +37 -8
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_query_parameter_combinations.rs +74 -32
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_run_operation_parameters.rs +2 -2
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_runner_integration.rs +78 -13
- {pysof-0.2.1 → pysof-0.2.4}/pyproject.toml +1 -1
- {pysof-0.2.1 → pysof-0.2.4}/src/lib.rs +145 -316
- {pysof-0.2.1/crates/pysof → pysof-0.2.4}/src/pysof/__init__.py +96 -27
- pysof-0.2.4/src/pysof/_pysof.cpython-314-x86_64-linux-gnu.so +4 -0
- {pysof-0.2.1/crates/pysof → pysof-0.2.4}/src/pysof/_pysof.pyi +38 -9
- pysof-0.2.1/crates/fhir/src/compartment_expressions/r6.rs +0 -743
- pysof-0.2.1/crates/fhir/src/search/loader.rs +0 -729
- pysof-0.2.1/crates/fhirpath/src/lib.rs +0 -385
- pysof-0.2.1/crates/fhirpath/src/terminology_client.rs +0 -545
- pysof-0.2.1/crates/fhirpath/tests/data/r5/known-test-failures.json +0 -66
- pysof-0.2.1/crates/fhirpath/tests/primitive_extension_tests.rs +0 -199
- pysof-0.2.1/crates/fhirpath/tests/r5_tests.rs +0 -396
- pysof-0.2.1/crates/pysof/multithreading_example.py +0 -100
- pysof-0.2.1/crates/pysof/test_multithreading.py +0 -125
- pysof-0.2.1/crates/sof/src/sqlquery/mod.rs +0 -63
- pysof-0.2.1/crates/sof/tests/common/mod.rs +0 -749
- pysof-0.2.1/src/pysof/_pysof.cpython-311-darwin.so +0 -4
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/README.md +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/build.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/compartment_expressions/mod.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/compartment_expressions/r4.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/compartment_expressions/r4b.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/compartment_expressions/r5.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/parameters.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/r6.rs.template +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/src/search/types.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/tests/integer_string_integration.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/tests/simple_null_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir/tests/test_contained_stack.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhir-macro/README.md +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/PRECISION_LIMITATION.md +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/benches/cli_benches.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/benches/evaluator_benches.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/benches/parser_benches.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/benches/server_benches.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/examples/test_ucum.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/grammar/fhirpath.g4 +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/server-api.md +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/aggregate_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/aggregate_math_functions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/bin/fhirpath-cli.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/bin/fhirpath-server.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/boolean_functions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/collection_functions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/collection_navigation.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/contains_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/conversion_functions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/date_operation.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/datetime_impl.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/debug_trace.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/distinct_functions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/error.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/extension_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/fhir_type_hierarchy.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/format_functions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/interval_functions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/json_utils.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/long_conversion.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/models.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/parse_debug.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/repeat_all_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/repeat_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/resolve_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/resource_type.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/set_operations.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/subset_functions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/trace_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/type_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/type_inference.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/src/ucum.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/all_function_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/boundary_debug_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/boundary_function_integration_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/comment_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/common/context.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/common/parser.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/context_trace_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/input/observation-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/input/observation-example.xml +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/input/patient-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/input/patient-example.xml +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/input/questionnaire-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/input/questionnaire-example.xml +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/input/valueset-example-expansion.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/input/valueset-example-expansion.xml +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r4/tests-fhir-r4.xml +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/appointment-examplereq.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/ccda.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/codesystem-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/conceptmap-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/diagnosticreport-eric.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/explanationofbenefit-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/observation-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/observation-example.xml +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/parameters-example-types.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/patient-container-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/patient-example-name.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/patient-example-period.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/patient-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/patient-name-extensions.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/questionnaire-example.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/r5/input/valueset-example-expansion.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/data/testSchema.xsd +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/date_operation_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/datetime_boundary_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/debug_datetime_boundary.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/debug_string_boundary_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/define_variable_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/enhanced_variable_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/evaluator_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/extension_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/fhir_boundary_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/http_compression.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/is_as_method_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/join_function_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/oftype_datetime_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/parse_debug_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/parser_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/polymorphic_r4_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/polymorphic_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/precision_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/reference_key_debug.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/test_boundary_zero.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/trace_api_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/trace_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/tree_navigation_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/truncate_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/type_operation_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/type_preservation_integration_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/type_reflection_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/unicode_scalar_value_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/uri_type_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath/tests/uuid_type_preservation_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath-support/Cargo.toml +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath-support/README.md +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/fhirpath-support/src/type_info.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/Cargo.lock +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/Makefile +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/PYPI_CHECKLIST.md +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/WHEEL_BUILDING.md +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/__init__.py +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/test_content_types.py +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/test_fhir_versions.py +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/test_import.py +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/test_remote_resolve.py +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/python-tests/test_source_errors.py +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/scripts/build-wheels.py +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/src/pysof/py.typed +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/integration/error_handling.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/integration/fhir_versions.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/integration/mod.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/lib_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/multithreading_integration.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/pysof/tests/threading_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/benches/parallel_processing_bench.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/compartment.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/constants.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/data_source.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/fhir_format.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/mod.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/parquet_schema.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/parquet_zip.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/reference_collector.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/remote_fetch.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/remote_resolver.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/sqlquery/output.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/src/traits.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_boolean_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_column_ordering.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_datetime_instant_constants.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_datetime_type_info.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_enum_conversion.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_evaluation_result_conversion.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_extension_function.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_extension_macro_fix.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_extension_simple.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_fhir_resource_structure.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_foreach_combinations.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_inequality.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_instant_constant.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_instant_type_info.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_raw_resource.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/debug_reference_key_types.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/extension_debug_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/foreach_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/multiselect_test.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/resolve_remote_tests.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/resolve_tests.rs +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/basic.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/collection.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/combinations.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/constant.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/constant_types.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fhirpath.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fhirpath_numbers.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fn_boundary.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fn_empty.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fn_extension.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fn_first.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fn_join.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fn_oftype.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/fn_reference_keys.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/foreach.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/logic.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/row_index.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/union.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/validate.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/view_resource.json +0 -0
- {pysof-0.2.1/crates/sof/tests/sql-on-fhir-v2 → pysof-0.2.4/crates/sof/tests/sql-on-fhir}/tests/where.json +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_boolean_constant_debug.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_boolean_constant_debug2.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_boolean_constant_debug3.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_boolean_validation.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_cli_file_source.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_csv_quote_handling.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_extension_fix_verification.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_extension_value_access.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_ndjson_input.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_parallel_working.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_parquet_export.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_parquet_large_dataset.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_parquet_server_options.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_shortened_format_names.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_where_clause_validation.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/crates/sof/tests/test_x_ndjson_support.rs +0 -0
- {pysof-0.2.1 → pysof-0.2.4}/src/pysof/py.typed +0 -0
|
@@ -17,8 +17,8 @@ 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.
|
|
21
|
-
helios-fhir = { path = "../fhir", version = "0.2.
|
|
20
|
+
helios-sof = { path = "../sof", version = "0.2.4", default-features = false }
|
|
21
|
+
helios-fhir = { path = "../fhir", version = "0.2.4", default-features = false }
|
|
22
22
|
serde = { workspace = true }
|
|
23
23
|
serde_json = { workspace = true }
|
|
24
24
|
chrono = { version = "0.4", features = ["serde"] }
|
|
@@ -27,6 +27,7 @@ csv = "1.3"
|
|
|
27
27
|
# Drives helios-sof's async remote-resolve functions from the synchronous
|
|
28
28
|
# PyO3 entry points via a current-thread runtime.
|
|
29
29
|
tokio = { version = "1", default-features = false, features = ["rt", "net", "time"] }
|
|
30
|
+
mimalloc = "0.1.52"
|
|
30
31
|
|
|
31
32
|
[features]
|
|
32
33
|
default = ["R4"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pysof
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
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
|
[](https://opensource.org/licenses/MIT)
|
|
35
35
|
[](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](
|
|
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-
|
|
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
|
|
|
@@ -314,18 +315,46 @@ pysof automatically processes FHIR resources in parallel using rayon:
|
|
|
314
315
|
- **5-7x speedup** on typical batch workloads with multi-core CPUs
|
|
315
316
|
- **Streaming benefits**: `ChunkedProcessor` and `process_ndjson_to_file` also use parallel processing
|
|
316
317
|
- **Zero configuration** - parallelization is always enabled
|
|
317
|
-
- **Python GIL released** during processing
|
|
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.
|
|
318
340
|
|
|
319
341
|
### Performance Benchmarks
|
|
320
342
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
|
325
|
-
|
|
326
|
-
| **
|
|
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.
|
|
327
354
|
|
|
328
|
-
Streaming mode (`ChunkedProcessor`, `process_ndjson_to_file`)
|
|
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.
|
|
329
358
|
|
|
330
359
|
### Controlling Thread Count (RAYON_NUM_THREADS)
|
|
331
360
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](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](
|
|
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-
|
|
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
|
|
|
@@ -285,18 +286,46 @@ pysof automatically processes FHIR resources in parallel using rayon:
|
|
|
285
286
|
- **5-7x speedup** on typical batch workloads with multi-core CPUs
|
|
286
287
|
- **Streaming benefits**: `ChunkedProcessor` and `process_ndjson_to_file` also use parallel processing
|
|
287
288
|
- **Zero configuration** - parallelization is always enabled
|
|
288
|
-
- **Python GIL released** during processing
|
|
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.
|
|
289
311
|
|
|
290
312
|
### Performance Benchmarks
|
|
291
313
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
|
296
|
-
|
|
297
|
-
| **
|
|
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.
|
|
298
325
|
|
|
299
|
-
Streaming mode (`ChunkedProcessor`, `process_ndjson_to_file`)
|
|
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.
|
|
300
329
|
|
|
301
330
|
### Controlling Thread Count (RAYON_NUM_THREADS)
|
|
302
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.
|
|
28
|
-
helios-serde-support = { path = "../serde-support", version = "0.2.
|
|
29
|
-
helios-fhirpath-support = { path = "../fhirpath-support", version = "0.2.
|
|
27
|
+
helios-fhir-macro = { path = "../fhir-macro", version = "0.2.4" }
|
|
28
|
+
helios-serde-support = { path = "../serde-support", version = "0.2.4" }
|
|
29
|
+
helios-fhirpath-support = { path = "../fhirpath-support", version = "0.2.4" }
|
|
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;
|