ms-cql-sdk 0.1.0__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.
- ms_cql_sdk-0.1.0/.gitignore +45 -0
- ms_cql_sdk-0.1.0/LICENSE +17 -0
- ms_cql_sdk-0.1.0/PKG-INFO +185 -0
- ms_cql_sdk-0.1.0/README.md +127 -0
- ms_cql_sdk-0.1.0/pyproject.toml +137 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/__init__.py +10 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/abstractions/__init__.py +21 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/abstractions/data_source.py +27 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/abstractions/invocation.py +20 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/abstractions/operators.py +31 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/abstractions/packaging.py +14 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/abstractions/terminology.py +31 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/abstractions/type_conversion.py +16 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/api.py +80 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/cli/__init__.py +5 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/cli/commands/__init__.py +1 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/cli/commands/inspect.py +32 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/cli/commands/package.py +20 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/cli/commands/run.py +47 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/cli/commands/validate.py +28 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/cli/main.py +38 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/compiler/__init__.py +7 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/compiler/bindings.py +14 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/compiler/expression_builder.py +23 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/compiler/planner.py +37 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/compiler/type_manager.py +18 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/__init__.py +5 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/models/__init__.py +1 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/models/base.py +35 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/models/expressions.py +17 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/models/library.py +52 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/models/types.py +17 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/serialization/__init__.py +8 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/serialization/compatibility.py +45 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/serialization/json_codec.py +30 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/elm/serialization/loader.py +89 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/fhir/__init__.py +6 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/fhir/adapters.py +18 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/fhir/context.py +15 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/fhir/retrieve.py +34 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/fhir/terminology.py +18 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/fhir/type_conversion.py +18 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/invocation/__init__.py +5 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/invocation/cache.py +25 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/invocation/invoker.py +24 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/invocation/library_registry.py +38 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/invocation/toolkit.py +91 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/packaging/__init__.py +6 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/packaging/bundle_writer.py +17 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/packaging/library_package.py +53 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/packaging/manifest.py +24 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/packaging/resource_writer.py +12 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/runtime/__init__.py +1 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/runtime/comparers.py +27 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/runtime/context.py +79 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/runtime/datetime_types.py +15 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/runtime/definitions.py +13 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/runtime/intervals.py +19 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/runtime/operators.py +250 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/runtime/quantities.py +15 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/spark/__init__.py +12 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/spark/adapters.py +12 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/spark/execution.py +36 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/spark/session.py +51 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/spark/udf.py +35 -0
- ms_cql_sdk-0.1.0/src/cql_sdk/version.py +5 -0
- ms_cql_sdk-0.1.0/tests/__init__.py +0 -0
- ms_cql_sdk-0.1.0/tests/conftest.py +18 -0
- ms_cql_sdk-0.1.0/tests/fixtures/__init__.py +0 -0
- ms_cql_sdk-0.1.0/tests/fixtures/elm/__init__.py +0 -0
- ms_cql_sdk-0.1.0/tests/fixtures/elm/hello_world.py +59 -0
- ms_cql_sdk-0.1.0/tests/integration/__init__.py +0 -0
- ms_cql_sdk-0.1.0/tests/integration/test_api_end_to_end.py +10 -0
- ms_cql_sdk-0.1.0/tests/integration/test_spark_smoke.py +20 -0
- ms_cql_sdk-0.1.0/tests/unit/__init__.py +0 -0
- ms_cql_sdk-0.1.0/tests/unit/test_invocation.py +30 -0
- ms_cql_sdk-0.1.0/tests/unit/test_loader.py +14 -0
- ms_cql_sdk-0.1.0/tests/unit/test_runtime_operators.py +36 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Byte-compiled / cache
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.token
|
|
7
|
+
# Build artifacts
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
.eggs/
|
|
12
|
+
.wheels/
|
|
13
|
+
|
|
14
|
+
# Virtual envs
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
env/
|
|
18
|
+
|
|
19
|
+
# uv / pip
|
|
20
|
+
.uv/
|
|
21
|
+
pip-wheel-metadata/
|
|
22
|
+
|
|
23
|
+
# Tests / coverage
|
|
24
|
+
.pytest_cache/
|
|
25
|
+
.coverage
|
|
26
|
+
.coverage.*
|
|
27
|
+
htmlcov/
|
|
28
|
+
coverage.xml
|
|
29
|
+
.mypy_cache/
|
|
30
|
+
.ruff_cache/
|
|
31
|
+
|
|
32
|
+
# IDEs
|
|
33
|
+
.idea/
|
|
34
|
+
.vscode/
|
|
35
|
+
*.swp
|
|
36
|
+
.DS_Store
|
|
37
|
+
|
|
38
|
+
# Docs build
|
|
39
|
+
site/
|
|
40
|
+
|
|
41
|
+
# Local data
|
|
42
|
+
*.log
|
|
43
|
+
.cache/
|
|
44
|
+
.tmp/
|
|
45
|
+
.history
|
ms_cql_sdk-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026 cql-sdk authors
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ms-cql-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Modular Python CQL SDK (ELM loading, runtime, invocation, FHIR and Spark adapters).
|
|
5
|
+
Project-URL: Homepage, https://github.com/ctava-msft/azure-healthcare-digital-quality-cql-sdk
|
|
6
|
+
Project-URL: Documentation, https://github.com/ctava-msft/azure-healthcare-digital-quality-cql-sdk#readme
|
|
7
|
+
Project-URL: Source, https://github.com/ctava-msft/azure-healthcare-digital-quality-cql-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/ctava-msft/azure-healthcare-digital-quality-cql-sdk/issues
|
|
9
|
+
Author: cql-sdk authors
|
|
10
|
+
License: Apache License
|
|
11
|
+
Version 2.0, January 2004
|
|
12
|
+
http://www.apache.org/licenses/
|
|
13
|
+
|
|
14
|
+
Copyright (c) 2026 cql-sdk authors
|
|
15
|
+
|
|
16
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
17
|
+
you may not use this file except in compliance with the License.
|
|
18
|
+
You may obtain a copy of the License at
|
|
19
|
+
|
|
20
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
21
|
+
|
|
22
|
+
Unless required by applicable law or agreed to in writing, software
|
|
23
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
24
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
25
|
+
See the License for the specific language governing permissions and
|
|
26
|
+
limitations under the License.
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Keywords: cql,elm,fhir,healthcare,quality-measures
|
|
29
|
+
Classifier: Development Status :: 3 - Alpha
|
|
30
|
+
Classifier: Intended Audience :: Developers
|
|
31
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
32
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
35
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
36
|
+
Requires-Python: >=3.12
|
|
37
|
+
Requires-Dist: pydantic>=2.7
|
|
38
|
+
Requires-Dist: python-dateutil>=2.9
|
|
39
|
+
Requires-Dist: rich>=13.7
|
|
40
|
+
Requires-Dist: typer>=0.12
|
|
41
|
+
Provides-Extra: dev
|
|
42
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
43
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
44
|
+
Requires-Dist: pre-commit>=3.7; extra == 'dev'
|
|
45
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
46
|
+
Provides-Extra: docs
|
|
47
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
48
|
+
Requires-Dist: mkdocs>=1.6; extra == 'docs'
|
|
49
|
+
Provides-Extra: fhir
|
|
50
|
+
Requires-Dist: fhir-resources>=7.1; extra == 'fhir'
|
|
51
|
+
Provides-Extra: spark
|
|
52
|
+
Requires-Dist: pyspark>=3.5; extra == 'spark'
|
|
53
|
+
Provides-Extra: test
|
|
54
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'test'
|
|
55
|
+
Requires-Dist: pytest-xdist>=3.6; extra == 'test'
|
|
56
|
+
Requires-Dist: pytest>=8.2; extra == 'test'
|
|
57
|
+
Description-Content-Type: text/markdown
|
|
58
|
+
|
|
59
|
+
# cql-sdk
|
|
60
|
+
|
|
61
|
+
A modular Python SDK for working with **Clinical Quality Language (CQL)** and
|
|
62
|
+
its compiled form **ELM** (Expression Logical Model). Inspired by the layering
|
|
63
|
+
of the Firely C# CQL SDK, but designed idiomatically for Python and for modern
|
|
64
|
+
data platforms (standalone, containers, PySpark, Microsoft Fabric).
|
|
65
|
+
|
|
66
|
+
> Status: early scaffold. The architecture, public API surface and extension
|
|
67
|
+
> points are deliberately sketched so they can grow toward a fuller CQL
|
|
68
|
+
> engine without breaking consumers.
|
|
69
|
+
|
|
70
|
+
## Why this SDK
|
|
71
|
+
|
|
72
|
+
- Pure-Python core for ELM loading, runtime context, operators, invocation.
|
|
73
|
+
- Optional FHIR integration (retrieval, type conversion, terminology).
|
|
74
|
+
- Optional Spark / Microsoft Fabric integration (the *same* core package
|
|
75
|
+
runs unchanged in both environments).
|
|
76
|
+
- A Typer-based CLI for inspecting, validating, packaging and running ELM.
|
|
77
|
+
- Designed around *pre-generated ELM artifacts* as a first-class workflow —
|
|
78
|
+
no Java/CQL-to-ELM toolchain is required for normal execution.
|
|
79
|
+
|
|
80
|
+
## Package layering
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
cql_sdk
|
|
84
|
+
├── abstractions/ # Protocols / ABCs for operators, terminology, data, packaging
|
|
85
|
+
├── elm/ # ELM model + (de)serialization
|
|
86
|
+
├── runtime/ # RuntimeContext, operators, comparers, intervals, datetime
|
|
87
|
+
├── compiler/ # Expression planner, bindings, type manager
|
|
88
|
+
├── invocation/ # High-level toolkit / invoker / library registry (PUBLIC API)
|
|
89
|
+
├── fhir/ # Optional FHIR adapters
|
|
90
|
+
├── spark/ # Optional Spark / Fabric adapters
|
|
91
|
+
├── packaging/ # Library + resource packaging primitives
|
|
92
|
+
├── cli/ # Typer CLI (`cql-sdk`)
|
|
93
|
+
└── api.py # Top-level convenience facade (PUBLIC API)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The **invocation toolkit** and [`cql_sdk.api`](src/cql_sdk/api.py) are the
|
|
97
|
+
preferred entry points. Internal modules (`compiler`, low-level runtime) are
|
|
98
|
+
available but not the recommended consumption path.
|
|
99
|
+
|
|
100
|
+
## Quick start
|
|
101
|
+
|
|
102
|
+
### Install (base)
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
uv sync
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Install with optional extras
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
uv sync --extra fhir
|
|
112
|
+
uv sync --extra spark # pulls pyspark; not required for base install
|
|
113
|
+
uv sync --extra dev --extra test
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Run the local hello-world example
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
uv run python examples/hello_world/run.py
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Load ELM and invoke a definition (Python)
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from cql_sdk.api import load_library, invoke
|
|
126
|
+
|
|
127
|
+
library = load_library("examples/hello_world/HelloWorld.elm.json")
|
|
128
|
+
result = invoke(library, definition="Greeting")
|
|
129
|
+
print(result)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Use the CLI
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
uv run cql-sdk inspect examples/hello_world/HelloWorld.elm.json
|
|
136
|
+
uv run cql-sdk validate examples/hello_world/HelloWorld.elm.json
|
|
137
|
+
uv run cql-sdk run examples/hello_world/HelloWorld.elm.json --definition Greeting
|
|
138
|
+
uv run cql-sdk package examples/hello_world --output dist/packages
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Spark / Fabric usage
|
|
142
|
+
|
|
143
|
+
Spark support is *opt-in*:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
uv sync --extra spark
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from pyspark.sql import SparkSession
|
|
151
|
+
from cql_sdk.spark import SparkInvocation
|
|
152
|
+
|
|
153
|
+
spark = SparkSession.builder.getOrCreate()
|
|
154
|
+
invocation = SparkInvocation.from_elm_path(
|
|
155
|
+
"examples/hello_world/HelloWorld.elm.json", spark=spark
|
|
156
|
+
)
|
|
157
|
+
df = invocation.run(definition="Greeting")
|
|
158
|
+
df.show()
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Core modules never import `pyspark` — importing `cql_sdk.spark` is the only
|
|
162
|
+
place Spark is required.
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
uv sync --extra dev --extra test
|
|
168
|
+
uv run ruff check .
|
|
169
|
+
uv run mypy
|
|
170
|
+
uv run pytest -m "not spark"
|
|
171
|
+
uv run pytest -m spark # requires `--extra spark`
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
See [docs/development.md](docs/development.md) for more.
|
|
175
|
+
|
|
176
|
+
## Documentation
|
|
177
|
+
|
|
178
|
+
- [Architecture](docs/architecture.md)
|
|
179
|
+
- [Public API](docs/public-api.md)
|
|
180
|
+
- [Packaging](docs/packaging.md)
|
|
181
|
+
- [Development](docs/development.md)
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
Apache-2.0. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# cql-sdk
|
|
2
|
+
|
|
3
|
+
A modular Python SDK for working with **Clinical Quality Language (CQL)** and
|
|
4
|
+
its compiled form **ELM** (Expression Logical Model). Inspired by the layering
|
|
5
|
+
of the Firely C# CQL SDK, but designed idiomatically for Python and for modern
|
|
6
|
+
data platforms (standalone, containers, PySpark, Microsoft Fabric).
|
|
7
|
+
|
|
8
|
+
> Status: early scaffold. The architecture, public API surface and extension
|
|
9
|
+
> points are deliberately sketched so they can grow toward a fuller CQL
|
|
10
|
+
> engine without breaking consumers.
|
|
11
|
+
|
|
12
|
+
## Why this SDK
|
|
13
|
+
|
|
14
|
+
- Pure-Python core for ELM loading, runtime context, operators, invocation.
|
|
15
|
+
- Optional FHIR integration (retrieval, type conversion, terminology).
|
|
16
|
+
- Optional Spark / Microsoft Fabric integration (the *same* core package
|
|
17
|
+
runs unchanged in both environments).
|
|
18
|
+
- A Typer-based CLI for inspecting, validating, packaging and running ELM.
|
|
19
|
+
- Designed around *pre-generated ELM artifacts* as a first-class workflow —
|
|
20
|
+
no Java/CQL-to-ELM toolchain is required for normal execution.
|
|
21
|
+
|
|
22
|
+
## Package layering
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
cql_sdk
|
|
26
|
+
├── abstractions/ # Protocols / ABCs for operators, terminology, data, packaging
|
|
27
|
+
├── elm/ # ELM model + (de)serialization
|
|
28
|
+
├── runtime/ # RuntimeContext, operators, comparers, intervals, datetime
|
|
29
|
+
├── compiler/ # Expression planner, bindings, type manager
|
|
30
|
+
├── invocation/ # High-level toolkit / invoker / library registry (PUBLIC API)
|
|
31
|
+
├── fhir/ # Optional FHIR adapters
|
|
32
|
+
├── spark/ # Optional Spark / Fabric adapters
|
|
33
|
+
├── packaging/ # Library + resource packaging primitives
|
|
34
|
+
├── cli/ # Typer CLI (`cql-sdk`)
|
|
35
|
+
└── api.py # Top-level convenience facade (PUBLIC API)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The **invocation toolkit** and [`cql_sdk.api`](src/cql_sdk/api.py) are the
|
|
39
|
+
preferred entry points. Internal modules (`compiler`, low-level runtime) are
|
|
40
|
+
available but not the recommended consumption path.
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
### Install (base)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv sync
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Install with optional extras
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv sync --extra fhir
|
|
54
|
+
uv sync --extra spark # pulls pyspark; not required for base install
|
|
55
|
+
uv sync --extra dev --extra test
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Run the local hello-world example
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
uv run python examples/hello_world/run.py
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Load ELM and invoke a definition (Python)
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from cql_sdk.api import load_library, invoke
|
|
68
|
+
|
|
69
|
+
library = load_library("examples/hello_world/HelloWorld.elm.json")
|
|
70
|
+
result = invoke(library, definition="Greeting")
|
|
71
|
+
print(result)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Use the CLI
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv run cql-sdk inspect examples/hello_world/HelloWorld.elm.json
|
|
78
|
+
uv run cql-sdk validate examples/hello_world/HelloWorld.elm.json
|
|
79
|
+
uv run cql-sdk run examples/hello_world/HelloWorld.elm.json --definition Greeting
|
|
80
|
+
uv run cql-sdk package examples/hello_world --output dist/packages
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Spark / Fabric usage
|
|
84
|
+
|
|
85
|
+
Spark support is *opt-in*:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv sync --extra spark
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from pyspark.sql import SparkSession
|
|
93
|
+
from cql_sdk.spark import SparkInvocation
|
|
94
|
+
|
|
95
|
+
spark = SparkSession.builder.getOrCreate()
|
|
96
|
+
invocation = SparkInvocation.from_elm_path(
|
|
97
|
+
"examples/hello_world/HelloWorld.elm.json", spark=spark
|
|
98
|
+
)
|
|
99
|
+
df = invocation.run(definition="Greeting")
|
|
100
|
+
df.show()
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Core modules never import `pyspark` — importing `cql_sdk.spark` is the only
|
|
104
|
+
place Spark is required.
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv sync --extra dev --extra test
|
|
110
|
+
uv run ruff check .
|
|
111
|
+
uv run mypy
|
|
112
|
+
uv run pytest -m "not spark"
|
|
113
|
+
uv run pytest -m spark # requires `--extra spark`
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
See [docs/development.md](docs/development.md) for more.
|
|
117
|
+
|
|
118
|
+
## Documentation
|
|
119
|
+
|
|
120
|
+
- [Architecture](docs/architecture.md)
|
|
121
|
+
- [Public API](docs/public-api.md)
|
|
122
|
+
- [Packaging](docs/packaging.md)
|
|
123
|
+
- [Development](docs/development.md)
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
Apache-2.0. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ms-cql-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Modular Python CQL SDK (ELM loading, runtime, invocation, FHIR and Spark adapters)."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
requires-python = ">=3.12"
|
|
12
|
+
authors = [{ name = "cql-sdk authors" }]
|
|
13
|
+
keywords = ["cql", "elm", "fhir", "healthcare", "quality-measures"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Intended Audience :: Healthcare Industry",
|
|
18
|
+
"License :: OSI Approved :: Apache Software License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Topic :: Scientific/Engineering :: Medical Science Apps.",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"typer>=0.12",
|
|
25
|
+
"rich>=13.7",
|
|
26
|
+
"pydantic>=2.7",
|
|
27
|
+
"python-dateutil>=2.9",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
fhir = [
|
|
32
|
+
"fhir.resources>=7.1",
|
|
33
|
+
]
|
|
34
|
+
spark = [
|
|
35
|
+
"pyspark>=3.5",
|
|
36
|
+
]
|
|
37
|
+
dev = [
|
|
38
|
+
"ruff>=0.6",
|
|
39
|
+
"mypy>=1.11",
|
|
40
|
+
"build>=1.2",
|
|
41
|
+
"pre-commit>=3.7",
|
|
42
|
+
]
|
|
43
|
+
test = [
|
|
44
|
+
"pytest>=8.2",
|
|
45
|
+
"pytest-cov>=5.0",
|
|
46
|
+
"pytest-xdist>=3.6",
|
|
47
|
+
]
|
|
48
|
+
docs = [
|
|
49
|
+
"mkdocs>=1.6",
|
|
50
|
+
"mkdocs-material>=9.5",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[project.scripts]
|
|
54
|
+
cql-sdk = "cql_sdk.cli.main:app"
|
|
55
|
+
|
|
56
|
+
[project.urls]
|
|
57
|
+
Homepage = "https://github.com/ctava-msft/azure-healthcare-digital-quality-cql-sdk"
|
|
58
|
+
Documentation = "https://github.com/ctava-msft/azure-healthcare-digital-quality-cql-sdk#readme"
|
|
59
|
+
Source = "https://github.com/ctava-msft/azure-healthcare-digital-quality-cql-sdk"
|
|
60
|
+
Issues = "https://github.com/ctava-msft/azure-healthcare-digital-quality-cql-sdk/issues"
|
|
61
|
+
|
|
62
|
+
[tool.hatch.build.targets.wheel]
|
|
63
|
+
packages = ["src/cql_sdk"]
|
|
64
|
+
|
|
65
|
+
[tool.hatch.build.targets.sdist]
|
|
66
|
+
include = ["src", "tests", "README.md", "LICENSE", "pyproject.toml"]
|
|
67
|
+
|
|
68
|
+
# -------- Tooling --------
|
|
69
|
+
|
|
70
|
+
[tool.ruff]
|
|
71
|
+
line-length = 100
|
|
72
|
+
target-version = "py312"
|
|
73
|
+
src = ["src", "tests"]
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint]
|
|
76
|
+
select = [
|
|
77
|
+
"E", "F", "W", # pycodestyle + pyflakes
|
|
78
|
+
"I", # isort
|
|
79
|
+
"B", # bugbear
|
|
80
|
+
"UP", # pyupgrade
|
|
81
|
+
"SIM", # simplify
|
|
82
|
+
"RUF", # ruff rules
|
|
83
|
+
"D", # pydocstyle
|
|
84
|
+
"TID", # tidy-imports
|
|
85
|
+
]
|
|
86
|
+
ignore = [
|
|
87
|
+
"D100", "D101", "D102", "D103", "D104", "D105", "D106", "D107",
|
|
88
|
+
"D203", "D213",
|
|
89
|
+
"B008", # Typer uses call-in-default as its canonical pattern
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
[tool.ruff.lint.per-file-ignores]
|
|
93
|
+
"tests/**" = ["D", "E501"]
|
|
94
|
+
"examples/**" = ["D"]
|
|
95
|
+
"src/cql_sdk/elm/serialization/loader.py" = ["E501"]
|
|
96
|
+
"src/cql_sdk/packaging/library_package.py" = ["E501"]
|
|
97
|
+
"src/cql_sdk/spark/session.py" = ["E501"]
|
|
98
|
+
"src/cql_sdk/runtime/context.py" = ["E501"]
|
|
99
|
+
|
|
100
|
+
[tool.ruff.lint.pydocstyle]
|
|
101
|
+
convention = "google"
|
|
102
|
+
|
|
103
|
+
[tool.mypy]
|
|
104
|
+
python_version = "3.12"
|
|
105
|
+
strict = true
|
|
106
|
+
warn_unused_ignores = true
|
|
107
|
+
warn_redundant_casts = true
|
|
108
|
+
warn_unreachable = true
|
|
109
|
+
disallow_untyped_defs = true
|
|
110
|
+
no_implicit_optional = true
|
|
111
|
+
files = ["src"]
|
|
112
|
+
|
|
113
|
+
[[tool.mypy.overrides]]
|
|
114
|
+
module = ["pyspark.*", "fhir.resources.*"]
|
|
115
|
+
ignore_missing_imports = true
|
|
116
|
+
|
|
117
|
+
[tool.pytest.ini_options]
|
|
118
|
+
minversion = "8.0"
|
|
119
|
+
addopts = "-ra --strict-markers --strict-config"
|
|
120
|
+
testpaths = ["tests"]
|
|
121
|
+
markers = [
|
|
122
|
+
"unit: fast, isolated unit tests",
|
|
123
|
+
"integration: end-to-end ELM loading / invocation tests",
|
|
124
|
+
"spark: requires pyspark (install with `uv sync --extra spark`)",
|
|
125
|
+
]
|
|
126
|
+
filterwarnings = [
|
|
127
|
+
"error",
|
|
128
|
+
"ignore::DeprecationWarning:pyspark.*",
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
[tool.coverage.run]
|
|
132
|
+
branch = true
|
|
133
|
+
source = ["cql_sdk"]
|
|
134
|
+
|
|
135
|
+
[tool.coverage.report]
|
|
136
|
+
show_missing = true
|
|
137
|
+
skip_empty = true
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""cql-sdk: a modular Python SDK for CQL/ELM execution.
|
|
2
|
+
|
|
3
|
+
Public entry points live in :mod:`cql_sdk.api` and
|
|
4
|
+
:mod:`cql_sdk.invocation.toolkit`. Everything else is considered internal
|
|
5
|
+
and may evolve without notice.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from cql_sdk.version import __version__
|
|
9
|
+
|
|
10
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Abstractions: protocols and ABCs describing stable SDK seams.
|
|
2
|
+
|
|
3
|
+
Concrete implementations live under :mod:`cql_sdk.runtime`,
|
|
4
|
+
:mod:`cql_sdk.fhir`, :mod:`cql_sdk.spark`, and :mod:`cql_sdk.packaging`.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from cql_sdk.abstractions.data_source import DataSource
|
|
8
|
+
from cql_sdk.abstractions.invocation import Invoker
|
|
9
|
+
from cql_sdk.abstractions.operators import OperatorRegistry
|
|
10
|
+
from cql_sdk.abstractions.packaging import PackageWriter
|
|
11
|
+
from cql_sdk.abstractions.terminology import TerminologyProvider
|
|
12
|
+
from cql_sdk.abstractions.type_conversion import TypeConverter
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"DataSource",
|
|
16
|
+
"Invoker",
|
|
17
|
+
"OperatorRegistry",
|
|
18
|
+
"PackageWriter",
|
|
19
|
+
"TerminologyProvider",
|
|
20
|
+
"TypeConverter",
|
|
21
|
+
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Data source protocol used by retrieve-style ELM nodes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from typing import Any, Protocol, runtime_checkable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@runtime_checkable
|
|
10
|
+
class DataSource(Protocol):
|
|
11
|
+
"""Abstract source of clinical/patient data.
|
|
12
|
+
|
|
13
|
+
Implementations may be backed by in-memory FHIR bundles, file-based
|
|
14
|
+
fixtures, REST FHIR servers, or Spark DataFrames.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def retrieve(
|
|
18
|
+
self,
|
|
19
|
+
*,
|
|
20
|
+
data_type: str,
|
|
21
|
+
code_property: str | None = None,
|
|
22
|
+
codes: Iterable[Any] | None = None,
|
|
23
|
+
date_property: str | None = None,
|
|
24
|
+
date_range: Any | None = None,
|
|
25
|
+
context: Any | None = None,
|
|
26
|
+
) -> Iterable[Any]:
|
|
27
|
+
"""Retrieve resources/records matching the given criteria."""
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Invocation protocol — the top-level user-facing seam."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Protocol, runtime_checkable
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@runtime_checkable
|
|
9
|
+
class Invoker(Protocol):
|
|
10
|
+
"""Executes a named definition on a registered library."""
|
|
11
|
+
|
|
12
|
+
def invoke(
|
|
13
|
+
self,
|
|
14
|
+
*,
|
|
15
|
+
library_identifier: str,
|
|
16
|
+
definition: str,
|
|
17
|
+
parameters: dict[str, Any] | None = None,
|
|
18
|
+
context: Any | None = None,
|
|
19
|
+
) -> Any:
|
|
20
|
+
"""Evaluate ``definition`` in the given library and return its value."""
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Operator registry protocol.
|
|
2
|
+
|
|
3
|
+
An operator registry maps ELM operator/expression node *type names* to
|
|
4
|
+
executable Python callables. Keeping this behind a Protocol lets the runtime,
|
|
5
|
+
FHIR, and Spark layers swap or extend operator behavior without touching
|
|
6
|
+
core planner/invoker code.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Any, Protocol, runtime_checkable
|
|
12
|
+
|
|
13
|
+
OperatorFn = Any # Callable[[RuntimeContext, ElmNode, ...], Any] — kept loose to avoid cycles
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class OperatorRegistry(Protocol):
|
|
18
|
+
"""Maps ELM node type names to executable operator callables."""
|
|
19
|
+
|
|
20
|
+
def register(self, elm_type: str, fn: OperatorFn) -> None:
|
|
21
|
+
"""Register (or replace) an operator implementation."""
|
|
22
|
+
|
|
23
|
+
def get(self, elm_type: str) -> OperatorFn:
|
|
24
|
+
"""Return the operator callable for ``elm_type``.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
KeyError: if no operator is registered for ``elm_type``.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def has(self, elm_type: str) -> bool:
|
|
31
|
+
"""Return whether an operator is registered for ``elm_type``."""
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Packaging seam for emitting library/manifest/resource artifacts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Protocol, runtime_checkable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@runtime_checkable
|
|
10
|
+
class PackageWriter(Protocol):
|
|
11
|
+
"""Writes a logical package (ELM + resources + manifest) to disk."""
|
|
12
|
+
|
|
13
|
+
def write(self, *, output_dir: Path, manifest: Any, resources: list[Any]) -> Path:
|
|
14
|
+
"""Persist the package and return the root output path."""
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Terminology provider protocol (value sets, code systems, concepts)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Protocol, runtime_checkable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True, slots=True)
|
|
10
|
+
class Code:
|
|
11
|
+
code: str
|
|
12
|
+
system: str | None = None
|
|
13
|
+
display: str | None = None
|
|
14
|
+
version: str | None = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True, slots=True)
|
|
18
|
+
class ValueSetRef:
|
|
19
|
+
id: str
|
|
20
|
+
version: str | None = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@runtime_checkable
|
|
24
|
+
class TerminologyProvider(Protocol):
|
|
25
|
+
"""Resolves value set membership and code system lookups."""
|
|
26
|
+
|
|
27
|
+
def expand(self, value_set: ValueSetRef) -> list[Code]:
|
|
28
|
+
"""Return the expansion (list of codes) for a value set."""
|
|
29
|
+
|
|
30
|
+
def in_value_set(self, code: Code, value_set: ValueSetRef) -> bool:
|
|
31
|
+
"""Return whether ``code`` is a member of ``value_set``."""
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Type conversion seam between ELM/CQL types and host Python values."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Protocol, runtime_checkable
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@runtime_checkable
|
|
9
|
+
class TypeConverter(Protocol):
|
|
10
|
+
"""Bidirectional conversion between CQL/ELM values and Python values."""
|
|
11
|
+
|
|
12
|
+
def to_python(self, cql_value: Any, *, cql_type: str | None = None) -> Any:
|
|
13
|
+
"""Convert a CQL/ELM value to an idiomatic Python value."""
|
|
14
|
+
|
|
15
|
+
def to_cql(self, py_value: Any, *, cql_type: str | None = None) -> Any:
|
|
16
|
+
"""Convert a Python value into the representation expected by ELM."""
|