Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5f62ee7
py: fhirpy: add client test
ryukzak Dec 17, 2025
0bfef03
py: fhirpy: add client test
ryukzak Dec 17, 2025
7cf3031
Merge remote-tracking branch 'origin/fhirpy-client' into fhirpy-client
MikhailArtemyev Dec 19, 2025
a881e09
py: fhirpy: fixed fhirpy client
MikhailArtemyev Dec 19, 2025
c57d602
py: fhirpy: direct usage of AsyncFHIRClient
MikhailArtemyev Dec 22, 2025
9990bc2
py: fhirpy: extended fhirpy client support
MikhailArtemyev Dec 23, 2025
07f9cbb
py: changed example for supporting fhirpy client
MikhailArtemyev Dec 23, 2025
1097371
minor format fix
MikhailArtemyev Dec 23, 2025
2721421
py: replaced fhirpy example with a common client example
MikhailArtemyev Dec 26, 2025
e3af334
py: renamed FHIRBase into FhirBaseModel
MikhailArtemyev Dec 26, 2025
ac8e693
py: renamed FhirBaseModel into FhirpyBaseModel
MikhailArtemyev Jan 5, 2026
b5b3eee
py: fhirpy: added comments to fhirpy_client.py
MikhailArtemyev Jan 5, 2026
f1bea26
ci: py: added a ci step for fhirpy generator
MikhailArtemyev Jan 5, 2026
cd79e9e
minor format fix
MikhailArtemyev Jan 5, 2026
65f50eb
Merge branch 'main' into fhirpy-client-2
MikhailArtemyev Jan 13, 2026
b491851
py: fixed failing test
MikhailArtemyev Jan 14, 2026
219e383
py: separated simple Python and FHIRPy examples into different direct…
MikhailArtemyev Jan 22, 2026
7a6208a
chore: retrigger CI
MikhailArtemyev Jan 22, 2026
9a669fc
Merge branch 'main' into fhirpy-client-2
MikhailArtemyev Jan 28, 2026
f6fc413
py: fixed generate.ts
MikhailArtemyev Jan 28, 2026
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
49 changes: 45 additions & 4 deletions .github/workflows/sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ jobs:

strategy:
matrix:
bun-version: [latest]
python-version: ["3.13"]
bun-version: [ latest ]
python-version: [ "3.13" ]

steps:
- uses: actions/checkout@v4
Expand All @@ -140,14 +140,55 @@ jobs:

- name: Repository contains actual python-sdk version
run: |
diff_result=$(git diff --exit-code --name-only examples/python/generated || true)
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-test:
runs-on: ubuntu-latest

strategy:
matrix:
bun-version: [ latest ]
python-version: [ "3.13" ]

steps:
- uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: ${{ matrix.bun-version }}

- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Test Python fhirpy SDK
run: |
export AIDBOX_LICENSE_ID="${{ secrets.AIDBOX_LICENSE_ID }}"
make test-python-fhirpy-sdk

- name: Repository contains actual python-fhirpy-sdk version
run: |
diff_result=$(git diff --exit-code --name-only examples/python-fhirpy/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/generated
git diff examples/python-fhirpy/fhir_types
exit 1
fi

Expand Down
43 changes: 33 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ test-all-example-generation:
bun run examples/local-package-folder/generate.ts
bun run examples/mustache/mustache-java-r4-gen.ts
bun run examples/python/generate.ts
bun run examples/python-fhirpy/generate.ts
bun run examples/typescript-ccda/generate.ts
bun run examples/typescript-r4/generate.ts
bun run examples/typescript-sql-on-fhir/generate.ts
Expand Down Expand Up @@ -81,27 +82,49 @@ test-csharp-sdk: typecheck format prepare-aidbox-runme lint
cd examples/csharp && dotnet test

PYTHON=python3.13
PYTHON_SDK_EXAMPLE=./examples/python
PYTHON_EXAMPLE=./examples/python
PYTHON_FHIRPY_EXAMPLE=./examples/python-fhirpy

test-python-sdk: typecheck format prepare-aidbox-runme lint
generate-python-sdk:
$(TYPECHECK) --project examples/python/tsconfig.json
bun run examples/python/generate.ts

@if [ ! -d "$(PYTHON_SDK_EXAMPLE)/venv" ]; then \
cd $(PYTHON_SDK_EXAMPLE) && \
generate-python-sdk-fhirpy:
Comment thread
MikhailArtemyev marked this conversation as resolved.
$(TYPECHECK) --project examples/python-fhirpy/tsconfig.json
bun run examples/python-fhirpy/generate.ts

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

# Run mypy in strict mode
cd $(PYTHON_SDK_EXAMPLE) && \
python-fhirpy-test-setup:
@if [ ! -d "$(PYTHON_FHIRPY_EXAMPLE)/venv" ]; then \
cd $(PYTHON_FHIRPY_EXAMPLE) && \
$(PYTHON) -m venv venv && \
. venv/bin/activate && \
mypy --strict .
pip install -r fhir_types/requirements.txt && \
pip install fhirpy; \
fi

cd $(PYTHON_SDK_EXAMPLE) && \
. venv/bin/activate && \
python -m pytest test_sdk.py -v
test-python-sdk: typecheck format prepare-aidbox-runme lint 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

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

release:
echo Push tag for $(VERSION)
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ See the [examples/](examples/) directory for working demonstrations:
- **[typescript-r4/](examples/typescript-r4/)** - FHIR R4 type generation with resource creation demo and profile usage
- **[typescript-ccda/](examples/typescript-ccda/)** - C-CDA on FHIR type generation
- **[typescript-sql-on-fhir/](examples/typescript-sql-on-fhir/)** - SQL on FHIR ViewDefinition with tree shaking
- **[python/](examples/python/)** - Python/Pydantic model generation with configurable field formats
- **[python/](examples/python/)** - Python/Pydantic model generation with simple 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
- **[local-package-folder/](examples/local-package-folder/)** - Loading unpublished local FHIR packages
Expand Down
32 changes: 32 additions & 0 deletions assets/api/writer-generator/python/fhirpy_base_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from typing import Any, Union, Optional, Iterator, Tuple, Dict
from pydantic import BaseModel, Field
from typing import Protocol


class ResourceProtocol(Protocol):
resourceType: Any
id: Union[str, None]


class FhirpyBaseModel(BaseModel):
"""
This class satisfies ResourceProtocol
"""
resource_type: str = Field(alias="resourceType")
id: Optional[str] = Field(None, alias="id")

@property
def resourceType(self) -> str:
return self.resource_type

@resourceType.setter
def resourceType(self, value: str) -> None:
self.resource_type = value

def __iter__(self) -> Iterator[Tuple[str, Any]]: # type: ignore[override]
data = self.model_dump(mode='json', by_alias=True, exclude_none=True)
return iter(data.items())

def serialize(self) -> Dict[str, Any]:
"""Serialize to dict (compatible with fhirpy's serialize method)"""
return self.model_dump(mode='json', by_alias=True, exclude_none=True)
9 changes: 7 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ This directory contains working examples demonstrating the capabilities of Atomi

### Multi-Language Generation

- **[python/](python/)** - Python/Pydantic model 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: [examples/python/client.py](examples/python/client.py).
- Client implementation example: [python/client.py](python/client.py)

- **[python-fhirpy/](python-fhirpy/)** - Python/Pydantic models with fhirpy async client
- `generate.ts` - Generates Python models with fhirpy integration
- Uses `fhirpyClient: true` for async FHIR client support
- Client implementation example: [python-fhirpy/client.py](python-fhirpy/client.py)


- **[csharp/](csharp/)** - C# class generation
Expand Down
4 changes: 4 additions & 0 deletions examples/python-fhirpy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.pytest_cache
__pycache__
.mypy_cache
venv
147 changes: 147 additions & 0 deletions examples/python-fhirpy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Python fhirpy Example

FHIR R4 type generation with Pydantic models integrated with the [fhirpy](https://github.com/beda-software/fhir-py) async client library.

## Overview

This example demonstrates how to use generated Python/Pydantic models with the `fhirpy` async FHIR client. It includes:

- Full FHIR R4 resource type definitions as Pydantic models
- Integration with `fhirpy` AsyncFHIRClient
- Automatic validation and serialization
- Async/await patterns for FHIR operations

For a simpler example using `requests`, see [python-simple/](../python-simple/).

## Setup

### Python Environment

1. Create virtual environment:

```bash
cd examples/python-fhirpy
python3 -m venv venv

# On macOS/Linux:
source venv/bin/activate
# On Windows:
venv\Scripts\activate
```

2. Install Python dependencies:

```bash
pip install -r fhir_types/requirements.txt
pip install fhirpy
```

3. Check Python version:

```bash
python --version # Should be 3.10 or higher
```

## Generating Types

To generate Python/Pydantic types for FHIR R4 with fhirpy support:

```bash
bun run examples/python-fhirpy/generate.ts
```

This will output to `./examples/python-fhirpy/fhir_types/`

## Configuration

Edit `generate.ts` to customize:

```typescript
.python({
allowExtraFields: false, // Reject unknown fields in models
fieldFormat: "snake_case", // or "camelCase"
fhirpyClient: true // Enable fhirpy integration
})
```

The `fhirpyClient: true` option generates models that inherit from a base class compatible with fhirpy's client API.

## Using with fhirpy

### Basic Usage

```python
import asyncio
from fhirpy import AsyncFHIRClient
from fhir_types.hl7_fhir_r4_core import HumanName
from fhir_types.hl7_fhir_r4_core.patient import Patient

async def main():
client = AsyncFHIRClient(
"http://localhost:8080/fhir",
authorization="Basic <token>",
)

# Create a patient using typed models
patient = Patient(
name=[HumanName(given=["John"], family="Doe")],
gender="male",
birthDate="1980-01-01",
)

# Use fhirpy's client API with the typed model
created = await client.create(patient)
print(f"Created patient: {created.id}")

# Search for patients
patients = await client.resources("Patient").fetch()
for pat in patients:
print(f"Found: {pat.get('name', [{}])[0].get('family', 'N/A')}")

asyncio.run(main())
```

### Resource API

```python
from fhir_types.hl7_fhir_r4_core.organization import Organization

organization = Organization(
name="My Organization",
active=True
)

# Use fhirpy's resource API
org_resource = await client.resource(
"Organization",
**organization.model_dump(exclude_none=True)
).save()

print(f"Created organization: {org_resource.id}")
```

## Type Checking

### MyPy Integration

Verify type safety with MyPy:

```bash
pip install mypy
mypy fhir_types/
```

## Running the Demo

Start a FHIR server (e.g., using the docker-compose in examples/), then run:

```bash
python client.py
```

## Next Steps

- See [python-simple/](../python-simple/) for basic requests-based example
- See [examples/](../) overview for other language examples
- Check [../../CLAUDE.md](../../CLAUDE.md) for architecture details
- Learn more about [fhirpy](https://github.com/beda-software/fhir-py)
Loading