Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions .github/workflows/sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,6 @@ jobs:
export AIDBOX_LICENSE_ID="${{ secrets.AIDBOX_LICENSE_ID }}"
make test-python-sdk

- name: Repository contains actual python-sdk version
run: |
diff_result=$(git diff --exit-code --name-only examples/python/fhir_types || true)

if [ -z "$diff_result" ]; then
echo "✅ Generated SDK is identical to the one stored in repository."
else
echo "❌ Generated SDK differs from the one stored in repository."
echo "Differences:"
git diff examples/python/fhir_types
exit 1
fi

test-python-fhirpy-sdk:
runs-on: ubuntu-latest

Expand Down Expand Up @@ -138,7 +125,7 @@ jobs:
exit 1
fi

test-python-us-core-example:
test-python-r4-us-core-example:
runs-on: ubuntu-latest

steps:
Expand All @@ -155,7 +142,20 @@ jobs:
run: bun install --frozen-lockfile

- name: Run tests
run: make test-python-us-core-example
run: make test-python-r4-us-core-example

- name: Repository contains actual python-sdk version
run: |
diff_result=$(git diff --exit-code --name-only examples/python-r4-us-core/fhir_types || true)

if [ -z "$diff_result" ]; then
echo "✅ Generated SDK is identical to the one stored in repository."
else
echo "❌ Generated SDK differs from the one stored in repository."
echo "Differences:"
git diff examples/python-r4-us-core/fhir_types
exit 1
fi

test-typescript-custom-packages-example:
runs-on: ubuntu-latest
Expand Down
79 changes: 26 additions & 53 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ VERSION = $(shell cat package.json | grep version | sed -E 's/ *"version": "//'
test-on-the-fly-example test-on-the-fly-norge-r4 test-on-the-fly-kbv-r4 test-on-the-fly-ccda \
test-typescript-r4-us-core-example test-typescript-custom-packages-example \
test-mustache-java-r4-example \
test-csharp-sdk generate-python-sdk generate-python-sdk-fhirpy generate-python-us-core-sdk \
python-test-setup python-fhirpy-test-setup python-us-core-test-setup \
test-python-sdk test-python-fhirpy-sdk test-python-us-core-example
test-csharp-sdk generate-python-r4-us-core-sdk generate-python-sdk-fhirpy \
python-r4-us-core-test-setup python-fhirpy-test-setup \
test-python-sdk test-python-fhirpy-sdk test-python-r4-us-core-example

all: test test-multi-package test-typescript-r4-us-core-example test-typescript-custom-packages-example lint-unsafe test-all-example-generation

Expand Down Expand Up @@ -56,9 +56,8 @@ test-all-example-generation: test-other-example-generation
bun run examples/csharp/generate.ts
bun run examples/typescript-custom-packages/generate.ts
bun run examples/mustache/mustache-java-r4-gen.ts
bun run examples/python-r4/generate.ts
bun run examples/python-r4-us-core/generate.ts
bun run examples/python-fhirpy/generate.ts
bun run examples/python-us-core/generate.ts
bun run examples/typescript-r4-us-core/generate.ts

test-other-example-generation: test-on-the-fly-example
Expand Down Expand Up @@ -102,25 +101,20 @@ test-csharp-sdk: typecheck prepare-aidbox-runme
cd examples/csharp && dotnet test

PYTHON=python3.13
PYTHON_EXAMPLE=./examples/python-r4
PYTHON_R4_US_CORE_EXAMPLE=./examples/python-r4-us-core
PYTHON_FHIRPY_EXAMPLE=./examples/python-fhirpy
PYTHON_US_CORE_EXAMPLE=./examples/python-us-core

generate-python-sdk:
$(TYPECHECK) --project examples/python-r4/tsconfig.json
bun run examples/python-r4/generate.ts
generate-python-r4-us-core-sdk:
$(TYPECHECK) --project examples/python-r4-us-core/tsconfig.json
bun run examples/python-r4-us-core/generate.ts

generate-python-sdk-fhirpy:
$(TYPECHECK) --project examples/python-fhirpy/tsconfig.json
bun run examples/python-fhirpy/generate.ts

generate-python-us-core-sdk:
$(TYPECHECK) --project examples/python-us-core/tsconfig.json
bun run examples/python-us-core/generate.ts

python-test-setup:
@if [ ! -d "$(PYTHON_EXAMPLE)/venv" ]; then \
cd $(PYTHON_EXAMPLE) && \
python-r4-us-core-test-setup:
@if [ ! -d "$(PYTHON_R4_US_CORE_EXAMPLE)/venv" ]; then \
cd $(PYTHON_R4_US_CORE_EXAMPLE) && \
$(PYTHON) -m venv venv && \
. venv/bin/activate && \
pip install -r fhir_types/requirements.txt; \
Expand All @@ -135,44 +129,23 @@ python-fhirpy-test-setup:
pip install fhirpy; \
fi

python-us-core-test-setup:
@if [ ! -d "$(PYTHON_US_CORE_EXAMPLE)/venv" ]; then \
cd $(PYTHON_US_CORE_EXAMPLE) && \
$(PYTHON) -m venv venv && \
. venv/bin/activate && \
pip install -r fhir_types/requirements.txt; \
fi

test-python-sdk: typecheck prepare-aidbox-runme generate-python-sdk python-test-setup
# Run mypy in strict mode
cd $(PYTHON_EXAMPLE) && \
. venv/bin/activate && \
mypy --strict .

cd $(PYTHON_EXAMPLE) && \
. venv/bin/activate && \
python -m pytest test_sdk.py -v
# Offline: mypy + profile/bundle/extension tests (no Aidbox required).
test-python-r4-us-core-example: typecheck generate-python-r4-us-core-sdk python-r4-us-core-test-setup
cd $(PYTHON_R4_US_CORE_EXAMPLE) && \
. venv/bin/activate && \
mypy .

cd $(PYTHON_EXAMPLE) && \
. venv/bin/activate && \
python -m pytest test_raw_extension.py -v
cd $(PYTHON_R4_US_CORE_EXAMPLE) && \
. venv/bin/activate && \
python -m pytest --ignore=test_sdk.py -v

cd $(PYTHON_EXAMPLE) && \
. venv/bin/activate && \
python -m pytest test_bundle.py -v
# Live SDK client tests via client.py (require Aidbox).
test-python-sdk: typecheck prepare-aidbox-runme generate-python-r4-us-core-sdk python-r4-us-core-test-setup
cd $(PYTHON_R4_US_CORE_EXAMPLE) && \
. venv/bin/activate && \
python -m pytest test_sdk.py -v
Comment thread
ryukzak marked this conversation as resolved.

test-python-fhirpy-sdk: typecheck prepare-aidbox-runme generate-python-sdk-fhirpy python-fhirpy-test-setup
# Run mypy in strict mode
cd $(PYTHON_FHIRPY_EXAMPLE) && \
. venv/bin/activate && \
mypy --strict .

# Profile tests are offline (no Aidbox required).
test-python-us-core-example: typecheck generate-python-us-core-sdk python-us-core-test-setup
cd $(PYTHON_US_CORE_EXAMPLE) && \
. venv/bin/activate && \
mypy --config-file mypy.ini .

cd $(PYTHON_US_CORE_EXAMPLE) && \
. venv/bin/activate && \
python -m pytest -v
. venv/bin/activate && \
mypy .
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ See the [examples/](examples/) directory for working demonstrations:

- **[typescript-r4-us-core/](examples/typescript-r4-us-core/)** - FHIR R4 core + US Core type generation with resource creation, profiles, and extensions
- **[on-the-fly/ccda/](examples/on-the-fly/ccda/)** - C-CDA on FHIR type generation (logical models, generated on the fly)
- **[python/](examples/python/)** - Python/Pydantic model generation with simple requests-based client
- **[python-r4-us-core/](examples/python-r4-us-core/)** - Python/Pydantic models for FHIR R4 core + US Core profiles, with a requests-based client
- **[python-fhirpy/](examples/python-fhirpy/)** - Python/Pydantic model generation with fhirpy async client
- **[csharp/](examples/csharp/)** - C# class generation with namespace configuration
- **[mustache/](examples/mustache/)** - Java generation with Mustache templates and post-generation hooks
Expand Down
9 changes: 4 additions & 5 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ This directory contains working examples demonstrating the capabilities of Atomi

### Python Generation

- **[python/](python/)** - Python/Pydantic model generation with simple requests-based client
- `generate.ts` - Generates Python models with configurable field formats
- Supports `snake_case` or `camelCase` field naming
- Configurable extra field validation
- Client implementation example: [python/client.py](python/client.py)
- **[python-r4-us-core/](python-r4-us-core/)** - Python/Pydantic models for FHIR R4 core + US Core profiles
- `generate.ts` - Generates R4 models and US Core profiles in one tree; configurable `snake_case`/`camelCase` field naming and extra-field validation
- US Core profile classes (Patient, blood pressure, body weight) with typed accessors and race/ethnicity/birth-sex extensions
- Simple `requests`-based FHIR client ([python-r4-us-core/client.py](python-r4-us-core/client.py)), exercised by `test_sdk.py`

- **[python-fhirpy/](python-fhirpy/)** - Python/Pydantic models with fhirpy async client
- `generate.ts` - Generates Python models with fhirpy integration
Expand Down
1 change: 1 addition & 0 deletions examples/python-fhirpy/mypy.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[mypy]
python_version = 3.13
strict = True
disallow_untyped_defs = False
disallow_incomplete_defs = False
check_untyped_defs = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ __pycache__
.mypy_cache
venv
/.venv/
fhir_types/type-schemas/
Original file line number Diff line number Diff line change
@@ -1,28 +1,41 @@
# Python Example
# Python Example — FHIR R4 Core + US Core

FHIR R4 type generation with Pydantic models, configurable field formats, and validation.
Python/Pydantic model generation for FHIR R4 core **and** US Core profiles, with
configurable field formats, validation, and a simple `requests`-based FHIR client.

A single `generate.ts` pulls US Core 8.0.1 (which depends on R4 core) plus a local
`ExampleTypedBundle` StructureDefinition, so one `fhir_types/` tree contains the base
R4 models/profiles (`hl7_fhir_r4_core`), the US Core profiles (`hl7_fhir_us_core`), and
the local typed-bundle profile (`example_folder_structures`).

## Overview

This example demonstrates how to generate Python/Pydantic models from the FHIR R4 specification using the Atomic EHR Codegen toolkit. It includes:
This example demonstrates how to generate Python/Pydantic models using the Atomic EHR
Codegen toolkit. It includes:

- Full FHIR R4 resource type definitions as Pydantic models
- FHIR R4 resource type definitions as Pydantic models, plus base R4 profiles (bodyweight)
- US Core profiles (Patient, blood pressure, body weight) with typed accessors and race/ethnicity/birth-sex extensions
- Automatic validation and serialization
- Configurable field naming conventions (snake_case or camelCase)
- Integration with Python type checking and IDE support
- Virtual environment setup
- Simple FHIR server client example using `requests`
- Integration with Python type checking (mypy) and IDE support
- A simple FHIR server client example using `requests` (`client.py`, exercised by `test_sdk.py`)

For an example using the `fhirpy` async client library, see [python-fhirpy/](../python-fhirpy/).

## Tests

- `test_profile_*.py` — US Core profile API (offline: no server required)
- `test_bundle.py` / `test_raw_extension.py` — generic Bundle and extension handling (offline)
- `test_sdk.py` — live CRUD against a FHIR server via `client.py` (requires Aidbox)

## Setup

### Python Environment

1. Create virtual environment:

```bash
cd examples/python
cd examples/python-r4-us-core
python3 -m venv venv

# On macOS/Linux:
Expand All @@ -48,10 +61,10 @@ python --version # Should be 3.10 or higher
To generate Python/Pydantic types for FHIR R4:

```bash
bun run examples/python/generate.ts
bun run examples/python-r4-us-core/generate.ts
```

This will output to `./examples/python/fhir_types/`
This will output to `./examples/python-r4-us-core/fhir_types/`

## Configuration

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@
- `http://hl7.org/fhir/StructureDefinition/Appointment`
- `http://hl7.org/fhir/StructureDefinition/AppointmentResponse`
- `http://hl7.org/fhir/StructureDefinition/AuditEvent`
- `http://hl7.org/fhir/StructureDefinition/BackboneElement`
- `http://hl7.org/fhir/StructureDefinition/Basic`
- `http://hl7.org/fhir/StructureDefinition/Binary`
- `http://hl7.org/fhir/StructureDefinition/BiologicallyDerivedProduct`
- `http://hl7.org/fhir/StructureDefinition/BodyStructure`
- `http://hl7.org/fhir/StructureDefinition/Bundle`
- `http://hl7.org/fhir/StructureDefinition/CapabilityStatement`
- `http://hl7.org/fhir/StructureDefinition/CarePlan`
- `http://hl7.org/fhir/StructureDefinition/CareTeam`
Expand Down Expand Up @@ -78,7 +80,9 @@
- `http://hl7.org/fhir/StructureDefinition/DiagnosticReport-geneticsReferences`
- `http://hl7.org/fhir/StructureDefinition/DocumentManifest`
- `http://hl7.org/fhir/StructureDefinition/DocumentReference`
- `http://hl7.org/fhir/StructureDefinition/DomainResource`
- `http://hl7.org/fhir/StructureDefinition/EffectEvidenceSynthesis`
- `http://hl7.org/fhir/StructureDefinition/Element`
- `http://hl7.org/fhir/StructureDefinition/ElementDefinition`
- `http://hl7.org/fhir/StructureDefinition/Encounter`
- `http://hl7.org/fhir/StructureDefinition/Endpoint`
Expand Down Expand Up @@ -137,12 +141,14 @@
- `http://hl7.org/fhir/StructureDefinition/MoneyQuantity`
- `http://hl7.org/fhir/StructureDefinition/NamingSystem`
- `http://hl7.org/fhir/StructureDefinition/NutritionOrder`
- `http://hl7.org/fhir/StructureDefinition/Observation`
- `http://hl7.org/fhir/StructureDefinition/ObservationDefinition`
- `http://hl7.org/fhir/StructureDefinition/OperationDefinition`
- `http://hl7.org/fhir/StructureDefinition/OperationOutcome`
- `http://hl7.org/fhir/StructureDefinition/Organization`
- `http://hl7.org/fhir/StructureDefinition/OrganizationAffiliation`
- `http://hl7.org/fhir/StructureDefinition/Parameters`
- `http://hl7.org/fhir/StructureDefinition/Patient`
- `http://hl7.org/fhir/StructureDefinition/PaymentNotice`
- `http://hl7.org/fhir/StructureDefinition/PaymentReconciliation`
- `http://hl7.org/fhir/StructureDefinition/Person`
Expand Down Expand Up @@ -2581,9 +2587,6 @@
- `urn:fhir:binding:InvestigationGroupType`
- `urn:fhir:binding:InvoicePriceComponentType`
- `urn:fhir:binding:InvoiceStatus`
- `urn:fhir:binding:IssueDetails`
- `urn:fhir:binding:IssueSeverity`
- `urn:fhir:binding:IssueType`
- `urn:fhir:binding:ItemDescriptionLanguage`
- `urn:fhir:binding:Jurisdiction`
- `urn:fhir:binding:LDLCodes`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from fhir_types.hl7_fhir_r4_core.observation import (
Observation, ObservationComponent, ObservationReferenceRange
)
from fhir_types.hl7_fhir_r4_core.operation_outcome import OperationOutcome, OperationOutcomeIssue
from fhir_types.hl7_fhir_r4_core.organization import Organization, OrganizationContact
from fhir_types.hl7_fhir_r4_core.patient import (
Patient, PatientCommunication, PatientContact, PatientLink
Expand Down Expand Up @@ -55,6 +56,8 @@
Observation.model_rebuild()
ObservationComponent.model_rebuild()
ObservationReferenceRange.model_rebuild()
OperationOutcome.model_rebuild()
OperationOutcomeIssue.model_rebuild()
Organization.model_rebuild()
OrganizationContact.model_rebuild()
ParameterDefinition.model_rebuild()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
Observation, ObservationComponent, ObservationReferenceRange
)
from fhir_types.hl7_fhir_r4_core.operation_outcome import OperationOutcome, OperationOutcomeIssue
from fhir_types.hl7_fhir_r4_core.organization import Organization, OrganizationContact
from fhir_types.hl7_fhir_r4_core.patient import (
Patient, PatientCommunication, PatientContact, PatientLink
)
Expand Down Expand Up @@ -58,6 +59,8 @@
'ObservationReferenceRange',
'OperationOutcome',
'OperationOutcomeIssue',
'Organization',
'OrganizationContact',
'ParameterDefinition',
'Patient',
'PatientCommunication',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# WARNING: This file is autogenerated by @atomic-ehr/codegen.
# GitHub: https://github.com/atomic-ehr/codegen
# Any manual changes made to this file may be overwritten.

from .extension_birth_place import BirthPlaceExtension
from .extension_birth_time import BirthTimeExtension
from .extension_nationality import NationalityExtension
from .observation_observation_bodyweight import ObservationBodyweightProfile
from .observation_observation_vitalsigns import ObservationVitalsignsProfile
from .extension_own_prefix import OwnPrefixExtension

__all__ = [
'BirthPlaceExtension',
'BirthTimeExtension',
'NationalityExtension',
'ObservationBodyweightProfile',
'ObservationVitalsignsProfile',
'OwnPrefixExtension',
]
Loading
Loading