pysof 0.1.30__cp313-cp313-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,332 @@
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
+ __version__,
50
+ py_get_supported_fhir_versions,
51
+ py_parse_content_type,
52
+ py_run_view_definition,
53
+ py_run_view_definition_with_options,
54
+ py_validate_bundle,
55
+ py_validate_view_definition,
56
+ )
57
+
58
+ # Create Python-friendly wrapper functions
59
+ def run_view_definition(
60
+ view: dict[str, Any],
61
+ bundle: dict[str, Any],
62
+ format: str,
63
+ *,
64
+ fhir_version: str = "R4",
65
+ ) -> bytes:
66
+ """Transform FHIR Bundle data using a ViewDefinition.
67
+
68
+ Args:
69
+ view: ViewDefinition resource as a Python dictionary
70
+ bundle: FHIR Bundle resource as a Python dictionary
71
+ format: Output format ("csv", "csv_with_header", "json", "ndjson", "parquet")
72
+ fhir_version: FHIR version to use ("R4", "R4B", "R5", "R6"). Defaults to "R4"
73
+
74
+ Returns:
75
+ Transformed data in the requested format as bytes
76
+
77
+ Raises:
78
+ InvalidViewDefinitionError: ViewDefinition structure is invalid
79
+ FhirPathError: FHIRPath expression evaluation failed
80
+ SerializationError: JSON parsing/serialization failed
81
+ UnsupportedContentTypeError: Unsupported output format
82
+ CsvError: CSV generation failed
83
+ IoError: I/O operation failed
84
+ """
85
+ return py_run_view_definition(view, bundle, format, fhir_version)
86
+
87
+ def run_view_definition_with_options(
88
+ view: dict[str, Any],
89
+ bundle: dict[str, Any],
90
+ format: str,
91
+ *,
92
+ since: str | None = None,
93
+ limit: int | None = None,
94
+ page: int | None = None,
95
+ fhir_version: str = "R4",
96
+ ) -> bytes:
97
+ """Transform FHIR Bundle data using a ViewDefinition with additional options.
98
+
99
+ Args:
100
+ view: ViewDefinition resource as a Python dictionary
101
+ bundle: FHIR Bundle resource as a Python dictionary
102
+ format: Output format ("csv", "csv_with_header", "json", "ndjson", "parquet")
103
+ since: Filter resources modified after this ISO8601 datetime
104
+ limit: Limit the number of results returned
105
+ page: Page number for pagination (1-based)
106
+ fhir_version: FHIR version to use ("R4", "R4B", "R5", "R6"). Defaults to "R4"
107
+
108
+ Returns:
109
+ Transformed data in the requested format as bytes
110
+
111
+ Raises:
112
+ InvalidViewDefinitionError: ViewDefinition structure is invalid
113
+ FhirPathError: FHIRPath expression evaluation failed
114
+ SerializationError: JSON parsing/serialization failed
115
+ UnsupportedContentTypeError: Unsupported output format
116
+ CsvError: CSV generation failed
117
+ IoError: I/O operation failed
118
+ """
119
+ return py_run_view_definition_with_options(
120
+ view,
121
+ bundle,
122
+ format,
123
+ since=since,
124
+ limit=limit,
125
+ page=page,
126
+ fhir_version=fhir_version,
127
+ )
128
+
129
+ def validate_view_definition(
130
+ view: dict[str, Any], *, fhir_version: str = "R4"
131
+ ) -> bool:
132
+ """Validate a ViewDefinition structure without executing it.
133
+
134
+ Args:
135
+ view: ViewDefinition resource as a Python dictionary
136
+ fhir_version: FHIR version to use ("R4", "R4B", "R5", "R6"). Defaults to "R4"
137
+
138
+ Returns:
139
+ True if valid
140
+
141
+ Raises:
142
+ InvalidViewDefinitionError: ViewDefinition structure is invalid
143
+ SerializationError: JSON parsing failed
144
+ """
145
+ return py_validate_view_definition(view, fhir_version)
146
+
147
+ def validate_bundle(bundle: dict[str, Any], *, fhir_version: str = "R4") -> bool:
148
+ """Validate a Bundle structure without executing transformations.
149
+
150
+ Args:
151
+ bundle: FHIR Bundle resource as a Python dictionary
152
+ fhir_version: FHIR version to use ("R4", "R4B", "R5", "R6"). Defaults to "R4"
153
+
154
+ Returns:
155
+ True if valid
156
+
157
+ Raises:
158
+ SerializationError: JSON parsing failed
159
+ """
160
+ return py_validate_bundle(bundle, fhir_version)
161
+
162
+ def parse_content_type(mime_type: str) -> str:
163
+ """Parse MIME type string to format identifier.
164
+
165
+ Args:
166
+ mime_type: MIME type string (e.g., "text/csv", "application/json")
167
+
168
+ Returns:
169
+ Format identifier suitable for use with run_view_definition
170
+
171
+ Raises:
172
+ UnsupportedContentTypeError: Unknown or unsupported MIME type
173
+ """
174
+ return py_parse_content_type(mime_type)
175
+
176
+ def get_supported_fhir_versions() -> list[str]:
177
+ """Get list of supported FHIR versions compiled into this build.
178
+
179
+ Returns:
180
+ List of supported FHIR version strings
181
+ """
182
+ return py_get_supported_fhir_versions()
183
+
184
+ except ImportError as e:
185
+ # Fallback for when the Rust extension is not available
186
+ import warnings
187
+
188
+ warnings.warn(
189
+ f"Rust extension module not available: {e}. Using placeholder functions.",
190
+ ImportWarning,
191
+ stacklevel=2,
192
+ )
193
+
194
+ # Define placeholder exception classes
195
+ class SofError(Exception): # type: ignore[no-redef]
196
+ """Base exception for all pysof errors"""
197
+
198
+ pass
199
+
200
+ class InvalidViewDefinitionError(SofError): # type: ignore[no-redef]
201
+ """ViewDefinition validation errors"""
202
+
203
+ pass
204
+
205
+ class FhirPathError(SofError): # type: ignore[no-redef]
206
+ """FHIRPath expression evaluation errors"""
207
+
208
+ pass
209
+
210
+ class SerializationError(SofError): # type: ignore[no-redef]
211
+ """JSON/data serialization errors"""
212
+
213
+ pass
214
+
215
+ class UnsupportedContentTypeError(SofError): # type: ignore[no-redef]
216
+ """Unsupported output format errors"""
217
+
218
+ pass
219
+
220
+ class CsvError(SofError): # type: ignore[no-redef]
221
+ """CSV generation errors"""
222
+
223
+ pass
224
+
225
+ class IoError(SofError): # type: ignore[no-redef]
226
+ """File/IO related errors"""
227
+
228
+ pass
229
+
230
+ class InvalidSourceError(SofError): # type: ignore[no-redef]
231
+ """Invalid source parameter value"""
232
+
233
+ pass
234
+
235
+ class SourceNotFoundError(SofError): # type: ignore[no-redef]
236
+ """Source not found"""
237
+
238
+ pass
239
+
240
+ class SourceFetchError(SofError): # type: ignore[no-redef]
241
+ """Failed to fetch from source"""
242
+
243
+ pass
244
+
245
+ class SourceReadError(SofError): # type: ignore[no-redef]
246
+ """Failed to read from source"""
247
+
248
+ pass
249
+
250
+ class InvalidSourceContentError(SofError): # type: ignore[no-redef]
251
+ """Invalid content in source"""
252
+
253
+ pass
254
+
255
+ class UnsupportedSourceProtocolError(SofError): # type: ignore[no-redef]
256
+ """Unsupported source protocol"""
257
+
258
+ pass
259
+
260
+ # Define placeholder functions
261
+ def run_view_definition(
262
+ view: dict[str, Any],
263
+ bundle: dict[str, Any],
264
+ format: str,
265
+ *,
266
+ fhir_version: str = "R4",
267
+ ) -> bytes:
268
+ raise NotImplementedError("Rust extension module not available")
269
+
270
+ def run_view_definition_with_options(
271
+ view: dict[str, Any],
272
+ bundle: dict[str, Any],
273
+ format: str,
274
+ *,
275
+ since: str | None = None,
276
+ limit: int | None = None,
277
+ page: int | None = None,
278
+ fhir_version: str = "R4",
279
+ ) -> bytes:
280
+ raise NotImplementedError("Rust extension module not available")
281
+
282
+ def validate_view_definition(
283
+ view: dict[str, Any], *, fhir_version: str = "R4"
284
+ ) -> bool:
285
+ raise NotImplementedError("Rust extension module not available")
286
+
287
+ def validate_bundle(bundle: dict[str, Any], *, fhir_version: str = "R4") -> bool:
288
+ raise NotImplementedError("Rust extension module not available")
289
+
290
+ def parse_content_type(mime_type: str) -> str:
291
+ raise NotImplementedError("Rust extension module not available")
292
+
293
+ def get_supported_fhir_versions() -> list[str]:
294
+ raise NotImplementedError("Rust extension module not available")
295
+
296
+ # Set fallback version when Rust extension is not available
297
+ __version__ = "0.0.0-dev"
298
+
299
+
300
+ __all__: list[str] = [
301
+ # Core functions
302
+ "run_view_definition",
303
+ "run_view_definition_with_options",
304
+ "validate_view_definition",
305
+ "validate_bundle",
306
+ "get_supported_fhir_versions",
307
+ "parse_content_type",
308
+ # Exception classes
309
+ "SofError",
310
+ "InvalidViewDefinitionError",
311
+ "FhirPathError",
312
+ "SerializationError",
313
+ "UnsupportedContentTypeError",
314
+ "CsvError",
315
+ "IoError",
316
+ "InvalidSourceError",
317
+ "SourceNotFoundError",
318
+ "SourceFetchError",
319
+ "SourceReadError",
320
+ "InvalidSourceContentError",
321
+ "UnsupportedSourceProtocolError",
322
+ ]
323
+
324
+
325
+ def get_version() -> str:
326
+ """Return the package version."""
327
+ return str(__version__)
328
+
329
+
330
+ def get_status() -> str:
331
+ """Return the current implementation status."""
332
+ return "v1: Rust bindings available with full SOF transformation capabilities."
Binary file
pysof/_pysof.pyi ADDED
@@ -0,0 +1,49 @@
1
+ """Type stubs for the pysof Rust extension module."""
2
+
3
+ from typing import Any
4
+
5
+ # Module attributes
6
+ __version__: str
7
+
8
+ # Exception classes
9
+ class SofError(Exception): ...
10
+ class InvalidViewDefinitionError(SofError): ...
11
+ class FhirPathError(SofError): ...
12
+ class SerializationError(SofError): ...
13
+ class UnsupportedContentTypeError(SofError): ...
14
+ class CsvError(SofError): ...
15
+ class IoError(SofError): ...
16
+ class InvalidSourceError(SofError): ...
17
+ class SourceNotFoundError(SofError): ...
18
+ class SourceFetchError(SofError): ...
19
+ class SourceReadError(SofError): ...
20
+ class InvalidSourceContentError(SofError): ...
21
+ class UnsupportedSourceProtocolError(SofError): ...
22
+
23
+ # Core functions
24
+ def py_run_view_definition(
25
+ view: dict[str, Any],
26
+ bundle: dict[str, Any],
27
+ format: str,
28
+ fhir_version: str,
29
+ ) -> bytes: ...
30
+ def py_run_view_definition_with_options(
31
+ view: dict[str, Any],
32
+ bundle: dict[str, Any],
33
+ format: str,
34
+ *,
35
+ since: str | None = None,
36
+ limit: int | None = None,
37
+ page: int | None = None,
38
+ fhir_version: str = "R4",
39
+ ) -> bytes: ...
40
+ def py_validate_view_definition(
41
+ view: dict[str, Any],
42
+ fhir_version: str,
43
+ ) -> bool: ...
44
+ def py_validate_bundle(
45
+ bundle: dict[str, Any],
46
+ fhir_version: str,
47
+ ) -> bool: ...
48
+ def py_parse_content_type(mime_type: str) -> str: ...
49
+ def py_get_supported_fhir_versions() -> list[str]: ...
pysof/py.typed ADDED
File without changes
@@ -0,0 +1,543 @@
1
+ Metadata-Version: 2.4
2
+ Name: pysof
3
+ Version: 0.1.30
4
+ Classifier: Programming Language :: Python :: 3
5
+ Classifier: Programming Language :: Python :: 3.10
6
+ Classifier: Programming Language :: Python :: 3.11
7
+ Classifier: Programming Language :: Python :: 3.12
8
+ Classifier: Programming Language :: Python :: 3.13
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Healthcare Industry
14
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Summary: Python wrapper for the Helios Software SOF (SQL on FHIR) toolkit.
17
+ Keywords: SQL on FHIR,FHIR,healthcare,sof,Helios Software
18
+ Author-email: Helios Software <team@heliossoftware.com>
19
+ License: MIT
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
22
+ Project-URL: Homepage, https://github.com/HeliosSoftware/hfs/tree/main/crates/pysof
23
+ Project-URL: Repository, https://github.com/HeliosSoftware/hfs
24
+ Project-URL: Documentation, https://github.com/HeliosSoftware/hfs/tree/main/crates/pysof
25
+ Project-URL: Bug Tracker, https://github.com/HeliosSoftware/hfs/issues
26
+ Project-URL: Source, https://github.com/HeliosSoftware/hfs/tree/main/crates/pysof
27
+
28
+ # pysof - SQL on FHIR for Python
29
+
30
+ [![PyPI version](https://badge.fury.io/py/pysof.svg)](https://pypi.org/project/pysof/)
31
+ [![Python versions](https://img.shields.io/pypi/pyversions/pysof.svg)](https://pypi.org/project/pysof/)
32
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
33
+ [![Downloads](https://pepy.tech/badge/pysof)](https://pepy.tech/project/pysof)
34
+
35
+ **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/).
36
+
37
+ 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.
38
+
39
+ ## ✨ Key Features
40
+
41
+ - 🚀 **High Performance**: Native Rust implementation with minimal Python overhead
42
+ - 📊 **Multiple Output Formats**: CSV, JSON, NDJSON, and Parquet
43
+ - 🔄 **Parallel Processing**: Automatic multithreading with 5-7x speedup on multi-core systems
44
+ - 🌐 **Multi-Version FHIR**: Supports R4, R4B, R5, and R6 (based on build features)
45
+ - 🎯 **Type-Safe**: Leverages Rust's type safety with a Pythonic interface
46
+ - ⚡ **GIL-Free**: Python GIL released during processing for true parallelism
47
+
48
+ ## 🎯 Why pysof?
49
+
50
+ Working with FHIR data in Python just got faster. **pysof** lets you:
51
+
52
+ - **Transform complex FHIR resources** into clean, analyzable tables without writing custom parsers
53
+ - **Process large datasets efficiently** with automatic parallel processing and Rust-level performance
54
+ - **Use standard SQL on FHIR ViewDefinitions** for portable, maintainable data transformations
55
+ - **Export to multiple formats** (CSV, JSON, NDJSON, Parquet) for analytics, ML, or reporting workflows
56
+
57
+ Perfect for healthcare data engineers, researchers, and developers building FHIR-based analytics pipelines.
58
+
59
+ ## 🔗 Quick Links
60
+
61
+ - 📦 **[PyPI Package](https://pypi.org/project/pysof/)**
62
+ - 📚 **[Documentation](https://github.com/HeliosSoftware/hfs/tree/main/crates/pysof)**
63
+ - 🐛 **[Issue Tracker](https://github.com/HeliosSoftware/hfs/issues)**
64
+ - 💻 **[Source Code](https://github.com/HeliosSoftware/hfs)**
65
+ - 📋 **[GitHub Releases](https://github.com/HeliosSoftware/hfs/releases)**
66
+
67
+ ## 📥 Installation
68
+
69
+ ### From PyPI (Recommended)
70
+
71
+ ```bash
72
+ pip install pysof
73
+ ```
74
+
75
+ **Supported Platforms:**
76
+ - **Linux**: x86_64 (glibc and musl)
77
+ - **Windows**: x86_64 (MSVC)
78
+ - **macOS**: AArch64 (Apple Silicon)
79
+ - **Python**: 3.10, 3.11, 3.12, 3.13
80
+
81
+ ### From GitHub Releases
82
+
83
+ Download pre-built wheels from the [releases page](https://github.com/HeliosSoftware/hfs/releases):
84
+
85
+ ```bash
86
+ pip install pysof-*.whl
87
+ ```
88
+
89
+ ## 🚀 Quick Start
90
+
91
+ Transform FHIR patient data to CSV in just a few lines:
92
+
93
+ ```python
94
+ import pysof
95
+
96
+ # Define what data to extract
97
+ view_definition = {
98
+ "resourceType": "ViewDefinition",
99
+ "id": "patient-demographics",
100
+ "name": "PatientDemographics",
101
+ "status": "active",
102
+ "resource": "Patient",
103
+ "select": [{
104
+ "column": [
105
+ {"name": "id", "path": "id"},
106
+ {"name": "family_name", "path": "name.family"},
107
+ {"name": "given_name", "path": "name.given.first()"},
108
+ {"name": "gender", "path": "gender"},
109
+ {"name": "birth_date", "path": "birthDate"}
110
+ ]
111
+ }]
112
+ }
113
+
114
+ # Sample FHIR Bundle
115
+ bundle = {
116
+ "resourceType": "Bundle",
117
+ "type": "collection",
118
+ "entry": [{
119
+ "resource": {
120
+ "resourceType": "Patient",
121
+ "id": "patient-1",
122
+ "name": [{"family": "Doe", "given": ["John"]}],
123
+ "gender": "male",
124
+ "birthDate": "1990-01-01"
125
+ }
126
+ }]
127
+ }
128
+
129
+ # Transform to CSV
130
+ csv_output = pysof.run_view_definition(view_definition, bundle, "csv")
131
+ print(csv_output.decode('utf-8'))
132
+ # Output:
133
+ # id,family_name,given_name,gender,birth_date
134
+ # patient-1,Doe,John,male,1990-01-01
135
+ ```
136
+
137
+ ## 📖 Usage
138
+
139
+ ### Multiple Output Formats
140
+
141
+ ```python
142
+ import pysof
143
+ import json
144
+
145
+ # Transform to different formats
146
+ csv_result = pysof.run_view_definition(view_definition, bundle, "csv")
147
+ json_result = pysof.run_view_definition(view_definition, bundle, "json")
148
+ ndjson_result = pysof.run_view_definition(view_definition, bundle, "ndjson")
149
+ parquet_result = pysof.run_view_definition(view_definition, bundle, "parquet")
150
+
151
+ print("CSV Output:")
152
+ print(csv_result.decode('utf-8'))
153
+
154
+ print("\nJSON Output:")
155
+ data = json.loads(json_result.decode('utf-8'))
156
+ print(json.dumps(data, indent=2))
157
+ ```
158
+
159
+ ### Advanced Options
160
+
161
+ ```python
162
+ import pysof
163
+
164
+ # Transform with pagination and filtering
165
+ result = pysof.run_view_definition_with_options(
166
+ view_definition,
167
+ bundle,
168
+ "json",
169
+ limit=10, # Limit results
170
+ page=1, # Page number
171
+ since="2023-01-01T00:00:00Z", # Filter by modification date
172
+ fhir_version="R4" # Specify FHIR version
173
+ )
174
+ ```
175
+
176
+ ### Utility Functions
177
+
178
+ ```python
179
+ import pysof
180
+
181
+ # Validate structures
182
+ is_valid_view = pysof.validate_view_definition(view_definition)
183
+ is_valid_bundle = pysof.validate_bundle(bundle)
184
+
185
+ # Parse content types
186
+ format_str = pysof.parse_content_type("text/csv") # Returns "csv_with_header"
187
+
188
+ # Check supported FHIR versions
189
+ versions = pysof.get_supported_fhir_versions() # Returns ["R4"] or more
190
+ print(f"Supported FHIR versions: {versions}")
191
+
192
+ # Package info
193
+ print(f"Version: {pysof.get_version()}")
194
+ print(pysof.get_status())
195
+ ```
196
+
197
+ ### Error Handling
198
+
199
+ ```python
200
+ import pysof
201
+
202
+ try:
203
+ result = pysof.run_view_definition(view_definition, bundle, "json")
204
+ except pysof.InvalidViewDefinitionError as e:
205
+ print(f"ViewDefinition validation error: {e}")
206
+ except pysof.SerializationError as e:
207
+ print(f"JSON parsing error: {e}")
208
+ except pysof.UnsupportedContentTypeError as e:
209
+ print(f"Unsupported format: {e}")
210
+ except pysof.SofError as e:
211
+ print(f"General SOF error: {e}")
212
+ ```
213
+
214
+ ## ⚡ Performance
215
+
216
+ ### Automatic Parallel Processing
217
+
218
+ pysof automatically processes FHIR resources in parallel using rayon:
219
+
220
+ - **5-7x speedup** on typical workloads with multi-core CPUs
221
+ - **Zero configuration** - parallelization is always enabled
222
+ - **Python GIL released** during processing for true parallel execution
223
+
224
+ ### Controlling Thread Count
225
+
226
+ Set the `RAYON_NUM_THREADS` environment variable before importing pysof:
227
+
228
+ ```python
229
+ import os
230
+ os.environ['RAYON_NUM_THREADS'] = '4' # Must be set before first import
231
+
232
+ import pysof
233
+ result = pysof.run_view_definition(view_definition, bundle, "json")
234
+ ```
235
+
236
+ Or from the command line:
237
+
238
+ ```bash
239
+ # Linux/Mac
240
+ RAYON_NUM_THREADS=4 python my_script.py
241
+
242
+ # Windows PowerShell
243
+ $env:RAYON_NUM_THREADS=4
244
+ python my_script.py
245
+ ```
246
+
247
+ **Performance Tips:**
248
+ - Use all available cores for large datasets (default behavior)
249
+ - Limit threads on shared systems to avoid resource contention
250
+ - Reduce thread count if memory-constrained
251
+
252
+ ## 📋 Supported Features
253
+
254
+ ### Output Formats
255
+
256
+ | Format | Description | Output |
257
+ |--------|-------------|--------|
258
+ | `csv` | CSV with headers | Comma-separated values with header row |
259
+ | `json` | JSON array | Array of objects, one per result row |
260
+ | `ndjson` | Newline-delimited JSON | One JSON object per line |
261
+ | `parquet` | Parquet format | Columnar binary format for analytics |
262
+
263
+ ### FHIR Versions
264
+
265
+ - **R4** (default, always available)
266
+ - **R4B** (if compiled with R4B feature)
267
+ - **R5** (if compiled with R5 feature)
268
+ - **R6** (if compiled with R6 feature)
269
+
270
+ Use `pysof.get_supported_fhir_versions()` to check available versions in your build.
271
+
272
+ ---
273
+
274
+ ## 🔧 Development
275
+
276
+ ### Requirements
277
+
278
+ - Python 3.10 or later (3.10, 3.11, 3.12, 3.13 supported)
279
+ - uv (package and environment manager)
280
+ - Rust toolchain (for building from source)
281
+
282
+ > **Note**: This crate is excluded from the default workspace build. When running `cargo build` from the repository root, `pysof` will not be built automatically.
283
+
284
+ ### Building from Source
285
+
286
+ ### Building with Cargo
287
+
288
+ This crate is excluded from the default workspace build to allow building the core Rust components without Python. To build it explicitly:
289
+
290
+ ```bash
291
+ # Your current directory MUST be the pysof crate:
292
+ cd crates/pysof
293
+
294
+ # From the pysof folder
295
+ cargo build
296
+
297
+ # Or build with specific FHIR version features
298
+ cargo build -p pysof --features R4,R5
299
+ ```
300
+
301
+ ### Building with Maturin (Recommended)
302
+
303
+ For Python development, it's recommended to use `maturin` via `uv`:
304
+
305
+ ```bash
306
+ # From repo root
307
+ cd crates/pysof
308
+
309
+ # Create a venv with your preferred Python version (3.10+)
310
+ uv venv --python 3.11 # or 3.10, 3.12, 3.13
311
+
312
+ # Install the project dev dependencies
313
+ uv sync --group dev
314
+
315
+ # Build and install the Rust extension into the venv
316
+ uv run maturin develop --release
317
+
318
+ # Build distributable artifacts
319
+ uv run maturin build --release -o dist # wheels
320
+ uv run maturin sdist -o dist # source distribution
321
+
322
+ # Sanity checks
323
+ uv run python -c "import pysof; print(pysof.__version__); print(pysof.get_status()); print(pysof.get_supported_fhir_versions())"
324
+ ```
325
+
326
+ ### Installing from Source
327
+
328
+ Requires Rust toolchain:
329
+
330
+ ```bash
331
+ # Install directly
332
+ pip install -e .
333
+
334
+ # Or build wheel locally
335
+ maturin build --release --out dist
336
+ pip install dist/*.whl
337
+ ```
338
+
339
+ ### Testing
340
+
341
+ The project has separate test suites for Python and Rust components:
342
+
343
+ #### Python Tests
344
+
345
+ Run the comprehensive Python test suite:
346
+
347
+ ```bash
348
+ # Run all Python tests
349
+ uv run pytest python-tests/
350
+
351
+ # Run specific test files
352
+ uv run pytest python-tests/test_core_functions.py -v
353
+ uv run pytest python-tests/test_content_types.py -v
354
+ uv run pytest python-tests/test_import.py -v
355
+
356
+ # Run with coverage
357
+ uv run pytest python-tests/ --cov=pysof --cov-report=html
358
+
359
+ # Run tests with detailed output
360
+ uv run pytest python-tests/ -v --tb=short
361
+ ```
362
+
363
+ #### Rust Tests
364
+
365
+ Run the Rust unit and integration tests:
366
+
367
+ ```bash
368
+ # Run all Rust tests
369
+ cargo test
370
+
371
+ # Run unit tests only
372
+ cargo test --test lib_tests
373
+
374
+ # Run integration tests only
375
+ cargo test --test integration
376
+
377
+ # Run with verbose output
378
+ cargo test -- --nocapture
379
+ ```
380
+
381
+ ## Configuring FHIR Version Support
382
+
383
+ By default, pysof is compiled with **R4 support only**. You can configure which FHIR versions are available by modifying the feature compilation settings.
384
+
385
+ ### Change Default FHIR Version
386
+
387
+ To change from R4 to another version (e.g., R5):
388
+
389
+ 1. **Edit `crates/pysof/Cargo.toml`**:
390
+ ```toml
391
+ [features]
392
+ default = ["R5"] # Changed from ["R4"]
393
+ R4 = ["helios-sof/R4", "helios-fhir/R4"]
394
+ R4B = ["helios-sof/R4B", "helios-fhir/R4B"]
395
+ R5 = ["helios-sof/R5", "helios-fhir/R5"]
396
+ R6 = ["helios-sof/R6", "helios-fhir/R6"]
397
+ ```
398
+
399
+ 2. **Rebuild the extension**:
400
+ ```bash
401
+ cd crates/pysof
402
+ uv run maturin develop --release
403
+ ```
404
+
405
+ 3. **Verify the change**:
406
+ ```bash
407
+ uv run python -c "
408
+ import pysof
409
+ versions = pysof.get_supported_fhir_versions()
410
+ print('Supported FHIR versions:', versions)
411
+ "
412
+ ```
413
+ This should now show `['R5']` instead of `['R4']`.
414
+
415
+ ### Enable Multiple FHIR Versions
416
+
417
+ To support multiple FHIR versions simultaneously:
418
+
419
+ 1. **Edit `crates/pysof/Cargo.toml`**:
420
+ ```toml
421
+ [features]
422
+ default = ["R4", "R5"] # Enable both R4 and R5
423
+ # Or enable all versions:
424
+ # default = ["R4", "R4B", "R5", "R6"]
425
+ ```
426
+
427
+ 2. **Rebuild and verify**:
428
+ ```bash
429
+ uv run maturin develop --release
430
+ uv run python -c "import pysof; print(pysof.get_supported_fhir_versions())"
431
+ ```
432
+ This should show `['R4', 'R5']` (or all enabled versions).
433
+
434
+ 3. **Use specific versions in code**:
435
+ ```python
436
+ import pysof
437
+
438
+ # Use R4 explicitly
439
+ result_r4 = pysof.run_view_definition(view, bundle, "json", fhir_version="R4")
440
+
441
+ # Use R5 explicitly
442
+ result_r5 = pysof.run_view_definition(view, bundle, "json", fhir_version="R5")
443
+ ```
444
+
445
+ ### Build with Specific Features (Without Changing Default)
446
+
447
+ To temporarily build with different features without modifying `Cargo.toml`:
448
+
449
+ ```bash
450
+ # Build with only R5
451
+ cargo build --features R5 --no-default-features
452
+
453
+ # Build with R4 and R6
454
+ cargo build --features R4,R6 --no-default-features
455
+
456
+ # With maturin
457
+ uv run --with maturin -- maturin develop --release --cargo-extra-args="--features R5 --no-default-features"
458
+ ```
459
+
460
+ ### Testing After Version Changes
461
+
462
+ After changing FHIR version support, run the test suite to ensure compatibility:
463
+
464
+ ```bash
465
+ # Run all tests
466
+ uv run pytest
467
+
468
+ # Run FHIR version-specific tests
469
+ uv run pytest tests/test_fhir_versions.py -v
470
+
471
+ # Test with your new default version
472
+ uv run python -c "
473
+ import pysof
474
+
475
+ # Test with default version (should be your new default)
476
+ view = {'resourceType': 'ViewDefinition', 'id': 'test', 'name': 'Test', 'status': 'active', 'resource': 'Patient', 'select': [{'column': [{'name': 'id', 'path': 'id'}]}]}
477
+ bundle = {'resourceType': 'Bundle', 'type': 'collection', 'entry': [{'resource': {'resourceType': 'Patient', 'id': 'test'}}]}
478
+
479
+ result = pysof.run_view_definition(view, bundle, 'json')
480
+ print('Default version test successful:', len(result), 'bytes')
481
+ "
482
+ ```
483
+
484
+ ## Project layout
485
+
486
+ ```
487
+ crates/pysof/
488
+ ├─ pyproject.toml # PEP 621 metadata, Python >=3.8, uv-compatible
489
+ ├─ README.md
490
+ ├─ src/
491
+ │ ├─ pysof/
492
+ │ │ └─ __init__.py # Python package root
493
+ │ └─ lib.rs # Rust PyO3 bindings
494
+ ├─ tests/ # Rust tests (17 tests)
495
+ │ ├─ lib_tests.rs # Unit tests for core library functions
496
+ │ ├─ integration.rs # Integration tests for component interactions
497
+ │ └─ integration/ # Organized integration test modules
498
+ │ ├─ mod.rs
499
+ │ ├─ content_types.rs
500
+ │ ├─ error_handling.rs
501
+ │ └─ fhir_versions.rs
502
+ ├─ python-tests/ # Python test suite (58 tests)
503
+ │ ├─ __init__.py
504
+ │ ├─ test_core_functions.py
505
+ │ ├─ test_content_types.py
506
+ │ ├─ test_fhir_versions.py
507
+ │ ├─ test_import.py
508
+ │ └─ test_package_metadata.py
509
+ └─ Cargo.toml # Rust crate metadata
510
+ ```
511
+
512
+ ## 📄 License
513
+
514
+ MIT License - See [LICENSE.md](../../LICENSE.md) for details.
515
+
516
+ Copyright (c) 2025 Helios Software
517
+
518
+ ## 🤝 Contributing
519
+
520
+ Contributions are welcome! Please see our [Contributing Guidelines](../../CONTRIBUTING.md) for details.
521
+
522
+ ### Reporting Issues
523
+
524
+ - **Bug Reports**: [GitHub Issues](https://github.com/HeliosSoftware/hfs/issues)
525
+ - **Security Issues**: Email team@heliossoftware.com
526
+
527
+ ### Development Setup
528
+
529
+ See the [Development](#-development) section above for instructions on setting up your development environment.
530
+
531
+ ## 🙏 Acknowledgments
532
+
533
+ Built with:
534
+ - [PyO3](https://pyo3.rs/) - Rust bindings for Python
535
+ - [maturin](https://www.maturin.rs/) - Build system for Rust Python extensions
536
+ - [helios-sof](../sof) - Core SQL-on-FHIR implementation in Rust
537
+
538
+ Part of the [Helios FHIR Server](https://github.com/HeliosSoftware/hfs) project.
539
+
540
+ ---
541
+
542
+ **Made with ❤️ by [Helios Software](https://heliossoftware.com)**
543
+
@@ -0,0 +1,7 @@
1
+ pysof-0.1.30.dist-info/METADATA,sha256=V_PAZrpkd6gUajiPKoy-p0YFJnO7KFbRUhv_6ORE1-g,16671
2
+ pysof-0.1.30.dist-info/WHEEL,sha256=N98zsR-csMcExBUgwG16bkVqfvUmGS-bae3JTmaVPLE,97
3
+ pysof/__init__.py,sha256=oP9_yZjTGOivf7h_yzYSg-fjWJiFIO4HRQu3J_wtwOk,11018
4
+ pysof/_pysof.cp313-win_amd64.pyd,sha256=rh-HNWYAYIcbW9YEIwDUrz-TIqZlRc1cnB5ynLF7_Aw,87629312
5
+ pysof/_pysof.pyi,sha256=YO6fyyNum9C7eNKd5DSbU3M1Y-_O38a5R7IF1Wsda-M,1409
6
+ pysof/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ pysof-0.1.30.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.10.1)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win_amd64