oehrpy
Docs: Templates & Builders

Templates, OPT Parsing & Composition Builders

Clinical data in openEHR is shaped by templates. oehrpy reads Operational Templates (OPT 1.4 XML) to extract their metadata, generates builder skeletons from them, and provides template builders that produce ready-to-post FLAT compositions with paths taken from the Web Template.

OPT Parser & Builder Generator

oehrpy provides tools for working with OPT (Operational Template) files. OPT files are XML documents that define constraints on openEHR archetypes for specific clinical use cases. With oehrpy, you can parse OPT files to extract template metadata (template ID, concept, archetypes) and generate builder class skeletons.

ADR-0005: FLAT paths cannot be reliably derived from OPT XML. The BuilderGenerator produces metadata-only class skeletons — no FLAT path strings. Use the Web Template JSON from the CDR for accurate FLAT paths. See ADR-0005 for details.

Parsing OPT Files

Use the parse_opt() function to parse an OPT file and extract template metadata:

from oehrpy.templates import parse_opt

# Parse an OPT file
template = parse_opt("path/to/vital_signs.opt")

# Access template metadata
print(f"Template ID: {template.template_id}")
print(f"Concept: {template.concept}")
print(f"Language: {template.language}")

# List all observations in the template
for obs in template.list_observations():
    print(f"  - {obs.name} ({obs.archetype_id})")

# List all entry types (OBSERVATION, EVALUATION, etc.)
entries = template.list_entries()
print(f"Found {len(entries)} entries")

Template Definition

The parsed TemplateDefinition provides access to:

Generating Builder Skeletons

Generate metadata-only class skeletons from OPT files. The generated code includes template ID, concept, and discovered archetypes, but not FLAT path strings (see ADR-0005):

from oehrpy.templates import generate_builder_from_opt

# Generate a builder skeleton (metadata only, no FLAT paths)
code = generate_builder_from_opt("vital_signs.opt")

# Save to file
generate_builder_from_opt(
    "vital_signs.opt",
    output_path="my_project/builders/vital_signs_skeleton.py"
)

# Use a custom class name
generate_builder_from_opt(
    "vital_signs.opt",
    output_path="vital_signs_skeleton.py",
    class_name="MyVitalSignsBuilder"
)

The generated skeleton must be supplemented with FLAT paths from the Web Template JSON. Fetch it after uploading the OPT to a CDR:

async with EHRBaseClient(...) as client:
    # Fetch Web Template (cached automatically)
    wt = await client.get_web_template("IDCR - Vital Signs Encounter.v1")
    # wt["tree"] contains the authoritative FLAT path segments

Web Template as FLAT Path Source

The Web Template JSON is the sole authoritative source for FLAT path derivation (ADR-0005). The EHRBaseClient provides cached fetching:

async with EHRBaseClient(...) as client:
    # Fetch with Accept: application/openehr.wt+json (cached in memory)
    wt = await client.get_web_template("IDCR - Vital Signs Encounter.v1")

    # Force refresh from CDR
    wt = await client.get_web_template("IDCR - Vital Signs Encounter.v1", use_cache=False)

    # Clear cache
    client.clear_web_template_cache()

Complete Workflow Example

Here's a complete example using the pre-built VitalSignsBuilder (which has FLAT paths sourced from the Web Template):

from oehrpy.templates import VitalSignsBuilder

# Create the builder (FLAT paths sourced from Web Template)
builder = VitalSignsBuilder(composer_name="Dr. Smith")

# Add clinical observations (type-safe with IDE autocomplete!)
builder.add_blood_pressure(systolic=120, diastolic=80)
builder.add_pulse(rate=72)
builder.add_temperature(magnitude=37.2)
builder.add_respiration(rate=16)
builder.add_oxygen_saturation(spo2=98)

# Build FLAT format data
flat_data = builder.build()

# Submit to EHRBase
async with EHRBaseClient(...) as client:
    result = await client.create_composition(
        ehr_id=ehr_id,
        template_id=builder.template_id,
        composition=flat_data,
        format="FLAT"
    )

Note: Pre-built builders like VitalSignsBuilder have FLAT paths verified against the Web Template from EHRBase. The BuilderGenerator produces metadata-only skeletons that need FLAT paths added manually from the Web Template.

Template Builders

Template builders provide a high-level API for creating compositions. FLAT paths in pre-built builders are sourced from the Web Template JSON (ADR-0005).

Vital Signs Builder

from oehrpy.templates import VitalSignsBuilder

# Create a vital signs composition
builder = VitalSignsBuilder(composer_name="Dr. Smith")

# Add measurements
builder.add_blood_pressure(systolic=120, diastolic=80)
builder.add_pulse(rate=72)
builder.add_temperature(37.2)
builder.add_respiration(rate=16)
builder.add_oxygen_saturation(spo2=98)

# Build FLAT format for EHRBase
flat_data = builder.build()
# {
#   "ctx/language": "en",
#   "ctx/territory": "US",
#   "vital_signs/blood_pressure:0/any_event:0/systolic|magnitude": 120,
#   ...
# }

Creating Custom Builders

You can create your own template builders for custom archetypes:

from oehrpy.serialization import FlatBuilder

class CustomTemplateBuilder:
    def __init__(self, composer_name: str):
        self.builder = FlatBuilder()
        self.builder.context(
            language="en",
            territory="US",
            composer_name=composer_name
        )

    def add_observation(self, value: float, unit: str):
        self.builder.set_quantity(
            "template/observation/value",
            value,
            unit
        )
        return self

    def build(self):
        return self.builder.build()