pysof 0.1.2__cp311-cp311-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pysof/__init__.py ADDED
@@ -0,0 +1,330 @@
1
+ """pysof: Python wrapper for the Helios SOF (SQL on FHIR) toolkit.
2
+
3
+ This package provides Python bindings for the Rust `sof` crate, enabling
4
+ transformation of FHIR resources into tabular data using ViewDefinitions.
5
+
6
+ Public API:
7
+ run_view_definition: Transform FHIR data using ViewDefinition
8
+ run_view_definition_with_options: Transform with filtering/pagination
9
+ validate_view_definition: Pre-validate ViewDefinition structure
10
+ validate_bundle: Pre-validate Bundle structure
11
+ get_supported_fhir_versions: List available FHIR versions
12
+ parse_content_type: Parse MIME types to format strings
13
+
14
+ Exception hierarchy:
15
+ SofError: Base exception for all pysof errors
16
+ InvalidViewDefinitionError: ViewDefinition validation errors
17
+ FhirPathError: FHIRPath expression evaluation errors
18
+ SerializationError: JSON/data serialization errors
19
+ UnsupportedContentTypeError: Unsupported output format errors
20
+ CsvError: CSV generation errors
21
+ IoError: File/IO related errors
22
+ InvalidSourceError: Invalid source parameter value
23
+ SourceNotFoundError: Source not found
24
+ SourceFetchError: Failed to fetch from source
25
+ SourceReadError: Failed to read from source
26
+ InvalidSourceContentError: Invalid content in source
27
+ UnsupportedSourceProtocolError: Unsupported source protocol
28
+ """
29
+
30
+ from typing import Any, cast
31
+
32
+ try:
33
+ # Import the Rust extension module
34
+ from pysof._pysof import (
35
+ CsvError,
36
+ FhirPathError,
37
+ InvalidSourceContentError,
38
+ InvalidSourceError,
39
+ InvalidViewDefinitionError,
40
+ IoError,
41
+ SerializationError,
42
+ # Exception classes
43
+ SofError,
44
+ SourceFetchError,
45
+ SourceNotFoundError,
46
+ SourceReadError,
47
+ UnsupportedContentTypeError,
48
+ UnsupportedSourceProtocolError,
49
+ py_get_supported_fhir_versions,
50
+ py_parse_content_type,
51
+ py_run_view_definition,
52
+ py_run_view_definition_with_options,
53
+ py_validate_bundle,
54
+ py_validate_view_definition,
55
+ )
56
+
57
+ # Create Python-friendly wrapper functions
58
+ def run_view_definition(
59
+ view: dict[str, Any],
60
+ bundle: dict[str, Any],
61
+ format: str,
62
+ *,
63
+ fhir_version: str = "R4",
64
+ ) -> bytes:
65
+ """Transform FHIR Bundle data using a ViewDefinition.
66
+
67
+ Args:
68
+ view: ViewDefinition resource as a Python dictionary
69
+ bundle: FHIR Bundle resource as a Python dictionary
70
+ format: Output format ("csv", "csv_with_header", "json", "ndjson", "parquet")
71
+ fhir_version: FHIR version to use ("R4", "R4B", "R5", "R6"). Defaults to "R4"
72
+
73
+ Returns:
74
+ Transformed data in the requested format as bytes
75
+
76
+ Raises:
77
+ InvalidViewDefinitionError: ViewDefinition structure is invalid
78
+ FhirPathError: FHIRPath expression evaluation failed
79
+ SerializationError: JSON parsing/serialization failed
80
+ UnsupportedContentTypeError: Unsupported output format
81
+ CsvError: CSV generation failed
82
+ IoError: I/O operation failed
83
+ """
84
+ return py_run_view_definition(view, bundle, format, fhir_version)
85
+
86
+ def run_view_definition_with_options(
87
+ view: dict[str, Any],
88
+ bundle: dict[str, Any],
89
+ format: str,
90
+ *,
91
+ since: str | None = None,
92
+ limit: int | None = None,
93
+ page: int | None = None,
94
+ fhir_version: str = "R4",
95
+ ) -> bytes:
96
+ """Transform FHIR Bundle data using a ViewDefinition with additional options.
97
+
98
+ Args:
99
+ view: ViewDefinition resource as a Python dictionary
100
+ bundle: FHIR Bundle resource as a Python dictionary
101
+ format: Output format ("csv", "csv_with_header", "json", "ndjson", "parquet")
102
+ since: Filter resources modified after this ISO8601 datetime
103
+ limit: Limit the number of results returned
104
+ page: Page number for pagination (1-based)
105
+ fhir_version: FHIR version to use ("R4", "R4B", "R5", "R6"). Defaults to "R4"
106
+
107
+ Returns:
108
+ Transformed data in the requested format as bytes
109
+
110
+ Raises:
111
+ InvalidViewDefinitionError: ViewDefinition structure is invalid
112
+ FhirPathError: FHIRPath expression evaluation failed
113
+ SerializationError: JSON parsing/serialization failed
114
+ UnsupportedContentTypeError: Unsupported output format
115
+ CsvError: CSV generation failed
116
+ IoError: I/O operation failed
117
+ """
118
+ return py_run_view_definition_with_options(
119
+ view,
120
+ bundle,
121
+ format,
122
+ since=since,
123
+ limit=limit,
124
+ page=page,
125
+ fhir_version=fhir_version,
126
+ )
127
+
128
+ def validate_view_definition(
129
+ view: dict[str, Any], *, fhir_version: str = "R4"
130
+ ) -> bool:
131
+ """Validate a ViewDefinition structure without executing it.
132
+
133
+ Args:
134
+ view: ViewDefinition resource as a Python dictionary
135
+ fhir_version: FHIR version to use ("R4", "R4B", "R5", "R6"). Defaults to "R4"
136
+
137
+ Returns:
138
+ True if valid
139
+
140
+ Raises:
141
+ InvalidViewDefinitionError: ViewDefinition structure is invalid
142
+ SerializationError: JSON parsing failed
143
+ """
144
+ return py_validate_view_definition(view, fhir_version)
145
+
146
+ def validate_bundle(bundle: dict[str, Any], *, fhir_version: str = "R4") -> bool:
147
+ """Validate a Bundle structure without executing transformations.
148
+
149
+ Args:
150
+ bundle: FHIR Bundle resource as a Python dictionary
151
+ fhir_version: FHIR version to use ("R4", "R4B", "R5", "R6"). Defaults to "R4"
152
+
153
+ Returns:
154
+ True if valid
155
+
156
+ Raises:
157
+ SerializationError: JSON parsing failed
158
+ """
159
+ return py_validate_bundle(bundle, fhir_version)
160
+
161
+ def parse_content_type(mime_type: str) -> str:
162
+ """Parse MIME type string to format identifier.
163
+
164
+ Args:
165
+ mime_type: MIME type string (e.g., "text/csv", "application/json")
166
+
167
+ Returns:
168
+ Format identifier suitable for use with run_view_definition
169
+
170
+ Raises:
171
+ UnsupportedContentTypeError: Unknown or unsupported MIME type
172
+ """
173
+ return py_parse_content_type(mime_type)
174
+
175
+ def get_supported_fhir_versions() -> list[str]:
176
+ """Get list of supported FHIR versions compiled into this build.
177
+
178
+ Returns:
179
+ List of supported FHIR version strings
180
+ """
181
+ return py_get_supported_fhir_versions()
182
+
183
+ except ImportError as e:
184
+ # Fallback for when the Rust extension is not available
185
+ import warnings
186
+
187
+ warnings.warn(
188
+ f"Rust extension module not available: {e}. Using placeholder functions.",
189
+ ImportWarning,
190
+ stacklevel=2,
191
+ )
192
+
193
+ # Define placeholder exception classes
194
+ class SofError(Exception): # type: ignore[no-redef]
195
+ """Base exception for all pysof errors"""
196
+
197
+ pass
198
+
199
+ class InvalidViewDefinitionError(SofError): # type: ignore[no-redef]
200
+ """ViewDefinition validation errors"""
201
+
202
+ pass
203
+
204
+ class FhirPathError(SofError): # type: ignore[no-redef]
205
+ """FHIRPath expression evaluation errors"""
206
+
207
+ pass
208
+
209
+ class SerializationError(SofError): # type: ignore[no-redef]
210
+ """JSON/data serialization errors"""
211
+
212
+ pass
213
+
214
+ class UnsupportedContentTypeError(SofError): # type: ignore[no-redef]
215
+ """Unsupported output format errors"""
216
+
217
+ pass
218
+
219
+ class CsvError(SofError): # type: ignore[no-redef]
220
+ """CSV generation errors"""
221
+
222
+ pass
223
+
224
+ class IoError(SofError): # type: ignore[no-redef]
225
+ """File/IO related errors"""
226
+
227
+ pass
228
+
229
+ class InvalidSourceError(SofError): # type: ignore[no-redef]
230
+ """Invalid source parameter value"""
231
+
232
+ pass
233
+
234
+ class SourceNotFoundError(SofError): # type: ignore[no-redef]
235
+ """Source not found"""
236
+
237
+ pass
238
+
239
+ class SourceFetchError(SofError): # type: ignore[no-redef]
240
+ """Failed to fetch from source"""
241
+
242
+ pass
243
+
244
+ class SourceReadError(SofError): # type: ignore[no-redef]
245
+ """Failed to read from source"""
246
+
247
+ pass
248
+
249
+ class InvalidSourceContentError(SofError): # type: ignore[no-redef]
250
+ """Invalid content in source"""
251
+
252
+ pass
253
+
254
+ class UnsupportedSourceProtocolError(SofError): # type: ignore[no-redef]
255
+ """Unsupported source protocol"""
256
+
257
+ pass
258
+
259
+ # Define placeholder functions
260
+ def run_view_definition(
261
+ view: dict[str, Any],
262
+ bundle: dict[str, Any],
263
+ format: str,
264
+ *,
265
+ fhir_version: str = "R4",
266
+ ) -> bytes:
267
+ raise NotImplementedError("Rust extension module not available")
268
+
269
+ def run_view_definition_with_options(
270
+ view: dict[str, Any],
271
+ bundle: dict[str, Any],
272
+ format: str,
273
+ *,
274
+ since: str | None = None,
275
+ limit: int | None = None,
276
+ page: int | None = None,
277
+ fhir_version: str = "R4",
278
+ ) -> bytes:
279
+ raise NotImplementedError("Rust extension module not available")
280
+
281
+ def validate_view_definition(
282
+ view: dict[str, Any], *, fhir_version: str = "R4"
283
+ ) -> bool:
284
+ raise NotImplementedError("Rust extension module not available")
285
+
286
+ def validate_bundle(bundle: dict[str, Any], *, fhir_version: str = "R4") -> bool:
287
+ raise NotImplementedError("Rust extension module not available")
288
+
289
+ def parse_content_type(mime_type: str) -> str:
290
+ raise NotImplementedError("Rust extension module not available")
291
+
292
+ def get_supported_fhir_versions() -> list[str]:
293
+ raise NotImplementedError("Rust extension module not available")
294
+
295
+
296
+ __all__: list[str] = [
297
+ # Core functions
298
+ "run_view_definition",
299
+ "run_view_definition_with_options",
300
+ "validate_view_definition",
301
+ "validate_bundle",
302
+ "get_supported_fhir_versions",
303
+ "parse_content_type",
304
+ # Exception classes
305
+ "SofError",
306
+ "InvalidViewDefinitionError",
307
+ "FhirPathError",
308
+ "SerializationError",
309
+ "UnsupportedContentTypeError",
310
+ "CsvError",
311
+ "IoError",
312
+ "InvalidSourceError",
313
+ "SourceNotFoundError",
314
+ "SourceFetchError",
315
+ "SourceReadError",
316
+ "InvalidSourceContentError",
317
+ "UnsupportedSourceProtocolError",
318
+ ]
319
+
320
+ __version__ = "0.1.0"
321
+
322
+
323
+ def get_version() -> str:
324
+ """Return the package version."""
325
+ return __version__
326
+
327
+
328
+ def get_status() -> str:
329
+ """Return the current implementation status."""
330
+ return "v1: Rust bindings available with full SOF transformation capabilities."
Binary file
pysof/_pysof.pyi ADDED
@@ -0,0 +1,46 @@
1
+ """Type stubs for the pysof Rust extension module."""
2
+
3
+ from typing import Any
4
+
5
+ # Exception classes
6
+ class SofError(Exception): ...
7
+ class InvalidViewDefinitionError(SofError): ...
8
+ class FhirPathError(SofError): ...
9
+ class SerializationError(SofError): ...
10
+ class UnsupportedContentTypeError(SofError): ...
11
+ class CsvError(SofError): ...
12
+ class IoError(SofError): ...
13
+ class InvalidSourceError(SofError): ...
14
+ class SourceNotFoundError(SofError): ...
15
+ class SourceFetchError(SofError): ...
16
+ class SourceReadError(SofError): ...
17
+ class InvalidSourceContentError(SofError): ...
18
+ class UnsupportedSourceProtocolError(SofError): ...
19
+
20
+ # Core functions
21
+ def py_run_view_definition(
22
+ view: dict[str, Any],
23
+ bundle: dict[str, Any],
24
+ format: str,
25
+ fhir_version: str,
26
+ ) -> bytes: ...
27
+ def py_run_view_definition_with_options(
28
+ view: dict[str, Any],
29
+ bundle: dict[str, Any],
30
+ format: str,
31
+ *,
32
+ since: str | None = None,
33
+ limit: int | None = None,
34
+ page: int | None = None,
35
+ fhir_version: str = "R4",
36
+ ) -> bytes: ...
37
+ def py_validate_view_definition(
38
+ view: dict[str, Any],
39
+ fhir_version: str,
40
+ ) -> bool: ...
41
+ def py_validate_bundle(
42
+ bundle: dict[str, Any],
43
+ fhir_version: str,
44
+ ) -> bool: ...
45
+ def py_parse_content_type(mime_type: str) -> str: ...
46
+ def py_get_supported_fhir_versions() -> list[str]: ...
pysof/py.typed ADDED
File without changes
@@ -0,0 +1,552 @@
1
+ Metadata-Version: 2.4
2
+ Name: pysof
3
+ Version: 0.1.2
4
+ Classifier: Programming Language :: Python :: 3
5
+ Classifier: Programming Language :: Python :: 3.11
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Operating System :: OS Independent
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Healthcare Industry
11
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
12
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
+ Summary: Python wrapper for the Helios SOF (SQL on FHIR) toolkit.
14
+ Keywords: SQL on FHIR,FHIR,healthcare,sof,helios
15
+ Author-email: Helios Team <team@heliossoftware.com>
16
+ License: MIT
17
+ Requires-Python: >=3.11, <3.12
18
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
19
+
20
+ # pysof
21
+
22
+ Python wrapper for the Helios SOF (SQL on FHIR) toolkit.
23
+
24
+ This package provides Python bindings for the Rust `helios-sof` library via PyO3 and maturin. Use `uv` to manage the environment and run builds.
25
+
26
+ > **Note**: This crate is excluded from the default workspace build via workspace default-members. When running `cargo build` from the repository root, `pysof` will not be built automatically. Build it explicitly when needed.
27
+
28
+ ## Requirements
29
+
30
+ - Python 3.11
31
+ - uv (package and environment manager)
32
+
33
+ ## Building the Crate
34
+
35
+ ### Building with Cargo
36
+
37
+ This crate is excluded from the default workspace build to allow building the core Rust components without Python. To build it explicitly:
38
+
39
+ ```bash
40
+ # Your current directory MUST be the pysof crate:
41
+ cd crates/pysof
42
+
43
+ # From the pysof folder
44
+ cargo build
45
+
46
+ # Or build with specific FHIR version features
47
+ cargo build -p pysof --features R4,R5
48
+ ```
49
+
50
+ ### Building with Maturin (Recommended)
51
+
52
+ For Python development, it's recommended to use `maturin` via `uv`:
53
+
54
+ ```bash
55
+ # From repo root
56
+ cd crates/pysof
57
+
58
+ # Ensure Python 3.11 is available and create a venv
59
+ uv venv --python 3.11
60
+
61
+ # Install the project dev dependencies
62
+ uv sync --group dev
63
+
64
+ # Build and install the Rust extension into the venv
65
+ uv run maturin develop --release
66
+
67
+ # Build distributable artifacts
68
+ uv run maturin build --release -o dist # wheels
69
+ uv run maturin sdist -o dist # source distribution
70
+
71
+ # Sanity checks
72
+ uv run python -c "import pysof; print(pysof.__version__); print(pysof.get_status()); print(pysof.get_supported_fhir_versions())"
73
+ ```
74
+
75
+ ## Installation
76
+
77
+ ### From PyPI (Recommended)
78
+
79
+ ```bash
80
+ pip install pysof
81
+ ```
82
+
83
+ ### From Source
84
+
85
+ ```bash
86
+ # Install from source (requires Rust toolchain)
87
+ pip install -e .
88
+
89
+ # Or build wheel locally
90
+ maturin build --release --out dist
91
+ pip install dist/*.whl
92
+ ```
93
+
94
+ ### From GitHub Releases
95
+
96
+ Download the appropriate wheel for your platform from the [releases page](https://github.com/HeliosSoftware/hfs/releases) and install:
97
+
98
+ ```bash
99
+ pip install pysof-*.whl
100
+ ```
101
+
102
+ ### Supported Platforms
103
+
104
+ - **Linux**: x86_64 (glibc and musl)
105
+ - **Windows**: x86_64 (MSVC)
106
+ - **macOS**: AArch64 (x86_64 is not supported)
107
+ - **Python**: 3.11 only
108
+
109
+ For detailed information about wheel building and distribution, see [WHEEL_BUILDING.md](WHEEL_BUILDING.md).
110
+
111
+ ## Testing
112
+
113
+ The project has separate test suites for Python and Rust components:
114
+
115
+ ### Python Tests
116
+
117
+ Run the comprehensive Python test suite:
118
+
119
+ ```bash
120
+ # Run all Python tests
121
+ uv run pytest python-tests/
122
+
123
+ # Run specific test files
124
+ uv run pytest python-tests/test_core_functions.py -v
125
+ uv run pytest python-tests/test_content_types.py -v
126
+ uv run pytest python-tests/test_import.py -v
127
+
128
+ # Run with coverage
129
+ uv run pytest python-tests/ --cov=pysof --cov-report=html
130
+
131
+ # Run tests with detailed output
132
+ uv run pytest python-tests/ -v --tb=short
133
+ ```
134
+
135
+ Current Python test coverage:
136
+ - **58 total tests** across 5 test files
137
+ - Core API functions (19 tests)
138
+ - Content type support (14 tests)
139
+ - FHIR version support (16 tests)
140
+ - Package structure and imports (6 tests)
141
+ - Package metadata (3 tests)
142
+
143
+ ### Rust Tests
144
+
145
+ Run the Rust unit and integration tests:
146
+
147
+ ```bash
148
+ # Run all Rust tests
149
+ cargo test
150
+
151
+ # Run unit tests only
152
+ cargo test --test lib_tests
153
+
154
+ # Run integration tests only
155
+ cargo test --test integration
156
+
157
+ # Run with verbose output
158
+ cargo test -- --nocapture
159
+ ```
160
+
161
+ Current Rust test coverage:
162
+ - **17 total tests** across 2 test files
163
+ - Unit tests: 14 tests covering core library functions
164
+ - Integration tests: 3 tests covering component interactions
165
+
166
+ ## Usage
167
+
168
+ ### Basic Example
169
+
170
+ ```python
171
+ import pysof
172
+ import json
173
+
174
+ # Sample ViewDefinition for extracting patient data
175
+ view_definition = {
176
+ "resourceType": "ViewDefinition",
177
+ "id": "patient-demographics",
178
+ "name": "PatientDemographics",
179
+ "status": "active",
180
+ "resource": "Patient",
181
+ "select": [
182
+ {
183
+ "column": [
184
+ {"name": "id", "path": "id"},
185
+ {"name": "family_name", "path": "name.family"},
186
+ {"name": "given_name", "path": "name.given.first()"},
187
+ {"name": "gender", "path": "gender"},
188
+ {"name": "birth_date", "path": "birthDate"}
189
+ ]
190
+ }
191
+ ]
192
+ }
193
+
194
+ # Sample FHIR Bundle with patient data
195
+ bundle = {
196
+ "resourceType": "Bundle",
197
+ "type": "collection",
198
+ "entry": [
199
+ {
200
+ "resource": {
201
+ "resourceType": "Patient",
202
+ "id": "patient-1",
203
+ "name": [{"family": "Doe", "given": ["John"]}],
204
+ "gender": "male",
205
+ "birthDate": "1990-01-01"
206
+ }
207
+ },
208
+ {
209
+ "resource": {
210
+ "resourceType": "Patient",
211
+ "id": "patient-2",
212
+ "name": [{"family": "Smith", "given": ["Jane"]}],
213
+ "gender": "female",
214
+ "birthDate": "1985-05-15"
215
+ }
216
+ }
217
+ ]
218
+ }
219
+
220
+ # Transform to different formats
221
+ csv_result = pysof.run_view_definition(view_definition, bundle, "csv")
222
+ json_result = pysof.run_view_definition(view_definition, bundle, "json")
223
+ ndjson_result = pysof.run_view_definition(view_definition, bundle, "ndjson")
224
+ parquet_result = pysof.run_view_definition(view_definition, bundle, "parquet")
225
+
226
+ print("CSV Output:")
227
+ print(csv_result.decode('utf-8'))
228
+
229
+ print("\nJSON Output:")
230
+ data = json.loads(json_result.decode('utf-8'))
231
+ print(json.dumps(data, indent=2))
232
+
233
+ print("\nParquet Output (binary):")
234
+ print(f"Parquet data: {len(parquet_result)} bytes")
235
+ ```
236
+
237
+ ### Advanced Usage with Options
238
+
239
+ ```python
240
+ import pysof
241
+ from datetime import datetime
242
+
243
+ # Transform with pagination and filtering
244
+ result = pysof.run_view_definition_with_options(
245
+ view_definition,
246
+ bundle,
247
+ "json",
248
+ limit=10, # Limit to 10 results
249
+ page=1, # First page
250
+ since="2023-01-01T00:00:00Z", # Filter by modification date
251
+ fhir_version="R4" # Specify FHIR version
252
+ )
253
+ ```
254
+
255
+ ### Utility Functions
256
+
257
+ ```python
258
+ import pysof
259
+
260
+ # Validate structures before processing
261
+ is_valid_view = pysof.validate_view_definition(view_definition)
262
+ is_valid_bundle = pysof.validate_bundle(bundle)
263
+
264
+ # Parse content types
265
+ format_str = pysof.parse_content_type("text/csv") # Returns "csv_with_header"
266
+ format_str = pysof.parse_content_type("application/json") # Returns "json"
267
+
268
+ # Check supported FHIR versions
269
+ versions = pysof.get_supported_fhir_versions() # Returns ["R4"] (or more based on build)
270
+ print(f"Supported FHIR versions: {versions}")
271
+
272
+ # Check package status
273
+ print(pysof.get_status()) # Shows current implementation status
274
+ print(f"Version: {pysof.get_version()}")
275
+ ```
276
+
277
+ ### Error Handling
278
+
279
+ ```python
280
+ import pysof
281
+
282
+ try:
283
+ result = pysof.run_view_definition(view_definition, bundle, "json")
284
+ except pysof.InvalidViewDefinitionError as e:
285
+ print(f"ViewDefinition validation error: {e}")
286
+ except pysof.SerializationError as e:
287
+ print(f"JSON parsing error: {e}")
288
+ except pysof.UnsupportedContentTypeError as e:
289
+ print(f"Unsupported format: {e}")
290
+ except pysof.SofError as e:
291
+ print(f"General SOF error: {e}")
292
+ ```
293
+
294
+ ### Key Features
295
+
296
+ - **Performance**: Efficient processing of large FHIR Bundles using Rust
297
+ - **Parallel Processing**: Automatic multithreading of FHIR resources using rayon (5-7x speedup on multi-core systems)
298
+ - **GIL Release**: Python GIL is released during Rust execution for better performance
299
+ - **Multiple Formats**: Support for CSV, JSON, NDJSON, and Parquet outputs
300
+ - **FHIR Versions**: Support for R4, R4B, R5, and R6 (depending on build features)
301
+
302
+ ### Available Options
303
+
304
+ The `run_view_definition_with_options()` function accepts the following parameters:
305
+
306
+ - **limit**: Limit the number of results returned
307
+ - **page**: Page number for pagination (1-based)
308
+ - **since**: Filter resources modified after this ISO8601 datetime
309
+ - **fhir_version**: FHIR version to use ("R4", "R4B", "R5", "R6")
310
+
311
+ ### Supported Content Types
312
+
313
+ | Format | Description | Output |
314
+ |--------|-------------|---------|
315
+ | `csv` | CSV with headers | Comma-separated values with header row |
316
+ | `json` | JSON array | Array of objects, one per result row |
317
+ | `ndjson` | Newline-delimited JSON | One JSON object per line |
318
+ | `parquet` | Parquet format | Columnar binary format optimized for analytics |
319
+
320
+ ### Supported FHIR Versions
321
+
322
+ - **R4** (default, always available)
323
+ - **R4B** (if compiled with R4B feature)
324
+ - **R5** (if compiled with R5 feature)
325
+ - **R6** (if compiled with R6 feature)
326
+
327
+ Use `pysof.get_supported_fhir_versions()` to check what's available in your build.
328
+
329
+ ### Usage Notes
330
+
331
+ - The basic `run_view_definition()` function is suitable for simple use cases
332
+ - Use `run_view_definition_with_options()` for pagination, filtering, and other advanced features
333
+ - All heavy processing happens in Rust code; Python GIL is properly released for optimal performance
334
+
335
+ ## Multithreading and Performance
336
+
337
+ ### Automatic Parallel Processing
338
+
339
+ pysof automatically processes FHIR resources in parallel using rayon, providing significant performance improvements on multi-core systems:
340
+
341
+ - **5-7x speedup** for typical workloads on modern CPUs
342
+ - **Zero configuration required** - parallelization is always enabled
343
+ - **Python GIL released** during processing for true parallel execution
344
+
345
+ ### Controlling Thread Count
346
+
347
+ By default, pysof uses all available CPU cores. You can control the thread count using the `RAYON_NUM_THREADS` environment variable:
348
+
349
+ ```python
350
+ import os
351
+ import pysof
352
+
353
+ # Set thread count BEFORE first use (must be set before rayon initializes)
354
+ os.environ['RAYON_NUM_THREADS'] = '4'
355
+
356
+ # Now all operations will use 4 threads
357
+ result = pysof.run_view_definition(view_definition, bundle, "json")
358
+ ```
359
+
360
+ Or from the command line:
361
+
362
+ ```bash
363
+ # Linux/Mac
364
+ RAYON_NUM_THREADS=4 python my_script.py
365
+
366
+ # Windows (cmd)
367
+ set RAYON_NUM_THREADS=4
368
+ python my_script.py
369
+
370
+ # Windows (PowerShell)
371
+ $env:RAYON_NUM_THREADS=4
372
+ python my_script.py
373
+ ```
374
+
375
+ **Important**: The environment variable must be set before rayon initializes its global thread pool (typically on first use of pysof). Once initialized, the thread count cannot be changed for that process.
376
+
377
+ ### Performance Tips
378
+
379
+ - **Large datasets**: Use all available cores (default behavior)
380
+ - **Shared systems**: Limit threads to avoid resource contention (`RAYON_NUM_THREADS=4`)
381
+ - **Memory constrained**: Reduce thread count to lower memory usage
382
+ - **Benchmarking**: Test different thread counts to find optimal performance for your workload
383
+
384
+ ## Configuring FHIR Version Support
385
+
386
+ By default, pysof is compiled with **R4 support only**. You can configure which FHIR versions are available by modifying the feature compilation settings.
387
+
388
+ ### Change Default FHIR Version
389
+
390
+ To change from R4 to another version (e.g., R5):
391
+
392
+ 1. **Edit `crates/pysof/Cargo.toml`**:
393
+ ```toml
394
+ [features]
395
+ default = ["R5"] # Changed from ["R4"]
396
+ R4 = ["helios-sof/R4", "helios-fhir/R4"]
397
+ R4B = ["helios-sof/R4B", "helios-fhir/R4B"]
398
+ R5 = ["helios-sof/R5", "helios-fhir/R5"]
399
+ R6 = ["helios-sof/R6", "helios-fhir/R6"]
400
+ ```
401
+
402
+ 2. **Rebuild the extension**:
403
+ ```bash
404
+ cd crates/pysof
405
+ uv run maturin develop --release
406
+ ```
407
+
408
+ 3. **Verify the change**:
409
+ ```bash
410
+ uv run python -c "
411
+ import pysof
412
+ versions = pysof.get_supported_fhir_versions()
413
+ print('Supported FHIR versions:', versions)
414
+ "
415
+ ```
416
+ This should now show `['R5']` instead of `['R4']`.
417
+
418
+ ### Enable Multiple FHIR Versions
419
+
420
+ To support multiple FHIR versions simultaneously:
421
+
422
+ 1. **Edit `crates/pysof/Cargo.toml`**:
423
+ ```toml
424
+ [features]
425
+ default = ["R4", "R5"] # Enable both R4 and R5
426
+ # Or enable all versions:
427
+ # default = ["R4", "R4B", "R5", "R6"]
428
+ ```
429
+
430
+ 2. **Rebuild and verify**:
431
+ ```bash
432
+ uv run maturin develop --release
433
+ uv run python -c "import pysof; print(pysof.get_supported_fhir_versions())"
434
+ ```
435
+ This should show `['R4', 'R5']` (or all enabled versions).
436
+
437
+ 3. **Use specific versions in code**:
438
+ ```python
439
+ import pysof
440
+
441
+ # Use R4 explicitly
442
+ result_r4 = pysof.run_view_definition(view, bundle, "json", fhir_version="R4")
443
+
444
+ # Use R5 explicitly
445
+ result_r5 = pysof.run_view_definition(view, bundle, "json", fhir_version="R5")
446
+ ```
447
+
448
+ ### Build with Specific Features (Without Changing Default)
449
+
450
+ To temporarily build with different features without modifying `Cargo.toml`:
451
+
452
+ ```bash
453
+ # Build with only R5
454
+ cargo build --features R5 --no-default-features
455
+
456
+ # Build with R4 and R6
457
+ cargo build --features R4,R6 --no-default-features
458
+
459
+ # With maturin
460
+ uv run --with maturin -- maturin develop --release --cargo-extra-args="--features R5 --no-default-features"
461
+ ```
462
+
463
+ ### Testing After Version Changes
464
+
465
+ After changing FHIR version support, run the test suite to ensure compatibility:
466
+
467
+ ```bash
468
+ # Run all tests
469
+ uv run pytest
470
+
471
+ # Run FHIR version-specific tests
472
+ uv run pytest tests/test_fhir_versions.py -v
473
+
474
+ # Test with your new default version
475
+ uv run python -c "
476
+ import pysof
477
+
478
+ # Test with default version (should be your new default)
479
+ view = {'resourceType': 'ViewDefinition', 'id': 'test', 'name': 'Test', 'status': 'active', 'resource': 'Patient', 'select': [{'column': [{'name': 'id', 'path': 'id'}]}]}
480
+ bundle = {'resourceType': 'Bundle', 'type': 'collection', 'entry': [{'resource': {'resourceType': 'Patient', 'id': 'test'}}]}
481
+
482
+ result = pysof.run_view_definition(view, bundle, 'json')
483
+ print('Default version test successful:', len(result), 'bytes')
484
+ "
485
+ ```
486
+
487
+ ### Important Considerations
488
+
489
+ 1. **Dependency Requirements**: Ensure the underlying `helios-sof` and `helios-fhir` crates support the features you want to enable
490
+ 2. **Binary Size**: Enabling multiple FHIR versions increases the compiled binary size significantly
491
+ 3. **Memory Usage**: Multiple versions require more memory at runtime
492
+ 4. **Testing**: Always run your test suite after changing version support
493
+ 5. **Documentation**: Update any project documentation that mentions specific FHIR versions
494
+ 6. **CI/CD**: Update build scripts and CI workflows if they depend on specific versions
495
+
496
+ ### Version Compatibility Matrix
497
+
498
+ | FHIR Version | Feature Flag | Status | Notes |
499
+ |--------------|--------------|---------|-------|
500
+ | R4 | `R4` | ✅ Stable | Default, always recommended |
501
+ | R4B | `R4B` | ✅ Stable | Minor updates to R4 |
502
+ | R5 | `R5` | ✅ Stable | Current latest stable version |
503
+ | R6 | `R6` | ⚠️ Preview | May have limited support |
504
+
505
+ ### Common Configuration Examples
506
+
507
+ ```toml
508
+ # Production: Single version for minimal size
509
+ default = ["R4"]
510
+
511
+ # Development: Multiple versions for testing
512
+ default = ["R4", "R5"]
513
+
514
+ # Bleeding edge: Latest versions only
515
+ default = ["R5", "R6"]
516
+
517
+ # Maximum compatibility: All versions (not recommended for production)
518
+ default = ["R4", "R4B", "R5", "R6"]
519
+ ```
520
+
521
+ ## Project layout
522
+
523
+ ```
524
+ crates/pysof/
525
+ ├─ pyproject.toml # PEP 621 metadata, Python >=3.11, uv-compatible
526
+ ├─ README.md
527
+ ├─ src/
528
+ │ ├─ pysof/
529
+ │ │ └─ __init__.py # Python package root
530
+ │ └─ lib.rs # Rust PyO3 bindings
531
+ ├─ tests/ # Rust tests (17 tests)
532
+ │ ├─ lib_tests.rs # Unit tests for core library functions
533
+ │ ├─ integration.rs # Integration tests for component interactions
534
+ │ └─ integration/ # Organized integration test modules
535
+ │ ├─ mod.rs
536
+ │ ├─ content_types.rs
537
+ │ ├─ error_handling.rs
538
+ │ └─ fhir_versions.rs
539
+ ├─ python-tests/ # Python test suite (58 tests)
540
+ │ ├─ __init__.py
541
+ │ ├─ test_core_functions.py
542
+ │ ├─ test_content_types.py
543
+ │ ├─ test_fhir_versions.py
544
+ │ ├─ test_import.py
545
+ │ └─ test_package_metadata.py
546
+ └─ Cargo.toml # Rust crate metadata
547
+ ```
548
+
549
+ ## License
550
+
551
+ This package inherits the license from the repository root.
552
+
@@ -0,0 +1,7 @@
1
+ pysof-0.1.2.dist-info/METADATA,sha256=Z4lDuie6T4gehChRpWivscQPrGiGvJkz5dH_9R-T97E,17006
2
+ pysof-0.1.2.dist-info/WHEEL,sha256=XthGvlhx1v097WptSw_sEjm7LbRsMyYW6bZuLs4TDpg,96
3
+ pysof/__init__.py,sha256=s_PWzd0kLvPqAj5CTnmlEvqv1e76jZr8VutJD6Nch3k,10918
4
+ pysof/_pysof.cp311-win_amd64.pyd,sha256=eAEZDbBx5Li1xUHDV94HAXPds2CCoHe8r4fvJe1CR4o,87613952
5
+ pysof/_pysof.pyi,sha256=2ibUgIuek1UJOWOoKxulIF7_mqX0TovvtpJWzTKH144,1368
6
+ pysof/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ pysof-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.9.5)
3
+ Root-Is-Purelib: false
4
+ Tag: cp311-cp311-win_amd64