Skip to content

Core API Reference

Core classes and functions for ccdakit.

Configuration

CDAConfig dataclass

Global configuration for C-CDA generation.

OrganizationInfo dataclass

Organization/custodian information.

configure(config)

Set global configuration.

Parameters:

Name Type Description Default
config CDAConfig

CDAConfig instance

required
Source code in ccdakit/core/config.py
def configure(config: CDAConfig) -> None:
    """
    Set global configuration.

    Args:
        config: CDAConfig instance
    """
    global _config
    _config = config

get_config()

Get current configuration.

Returns:

Type Description
CDAConfig

Current CDAConfig instance

Raises:

Type Description
RuntimeError

If not configured

Source code in ccdakit/core/config.py
def get_config() -> CDAConfig:
    """
    Get current configuration.

    Returns:
        Current CDAConfig instance

    Raises:
        RuntimeError: If not configured
    """
    if _config is None:
        raise RuntimeError("ccdakit not configured. Call configure() before generating documents.")
    return _config

reset_config()

Reset configuration (useful for testing).

Source code in ccdakit/core/config.py
def reset_config() -> None:
    """Reset configuration (useful for testing)."""
    global _config
    _config = None

Base Classes

CDAElement

Bases: ABC

Base class for all CDA elements.

All builders inherit from this class and implement the build() method.

Source code in ccdakit/core/base.py
class CDAElement(ABC):
    """
    Base class for all CDA elements.

    All builders inherit from this class and implement the build() method.
    """

    # Subclasses override with version-specific templates
    TEMPLATES: "dict[CDAVersion, List[TemplateConfig]]" = {}

    def __init__(
        self,
        version: CDAVersion = CDAVersion.R2_1,
        schema: Optional["XSDValidator"] = None,
    ) -> None:
        """
        Initialize CDA element.

        Args:
            version: C-CDA version to generate
            schema: Optional XSD validator
        """
        self.version = version
        self.schema = schema

    @abstractmethod
    def build(self) -> etree._Element:
        """
        Build and return the XML element.

        This method must be implemented by subclasses.

        Returns:
            lxml Element representing this CDA component
        """
        pass

    def to_element(self) -> etree._Element:
        """
        Build element with optional validation.

        Returns:
            lxml Element representing this CDA component

        Raises:
            etree.DocumentInvalid: If validation fails
        """
        element = self.build()

        if self.schema:
            self.schema.assert_valid(element)

        return element

    def to_string(self, pretty: bool = True, encoding: str = "unicode") -> str:
        """
        Convert to XML string.

        Args:
            pretty: Whether to pretty-print XML
            encoding: Output encoding ('unicode' or 'utf-8')

        Returns:
            XML string representation
        """
        return etree.tostring(
            self.to_element(),
            pretty_print=pretty,
            encoding=encoding,  # type: ignore
        )

    def get_templates(self) -> List[TemplateConfig]:
        """
        Get templateIds for current version.

        Returns:
            List of TemplateConfig for this version

        Raises:
            ValueError: If version not supported
        """
        if self.version not in self.TEMPLATES:
            raise ValueError(
                f"Version {self.version.value} not supported for {self.__class__.__name__}"
            )
        return self.TEMPLATES[self.version]

    def add_template_ids(self, parent: etree._Element) -> None:
        """
        Add all templateIds for current version to parent element.

        Args:
            parent: Parent element to add templateIds to
        """
        for template in self.get_templates():
            parent.append(template.to_element())

Functions

__init__(version=CDAVersion.R2_1, schema=None)

Initialize CDA element.

Parameters:

Name Type Description Default
version CDAVersion

C-CDA version to generate

R2_1
schema Optional[XSDValidator]

Optional XSD validator

None
Source code in ccdakit/core/base.py
def __init__(
    self,
    version: CDAVersion = CDAVersion.R2_1,
    schema: Optional["XSDValidator"] = None,
) -> None:
    """
    Initialize CDA element.

    Args:
        version: C-CDA version to generate
        schema: Optional XSD validator
    """
    self.version = version
    self.schema = schema

build() abstractmethod

Build and return the XML element.

This method must be implemented by subclasses.

Returns:

Type Description
_Element

lxml Element representing this CDA component

Source code in ccdakit/core/base.py
@abstractmethod
def build(self) -> etree._Element:
    """
    Build and return the XML element.

    This method must be implemented by subclasses.

    Returns:
        lxml Element representing this CDA component
    """
    pass

to_element()

Build element with optional validation.

Returns:

Type Description
_Element

lxml Element representing this CDA component

Raises:

Type Description
DocumentInvalid

If validation fails

Source code in ccdakit/core/base.py
def to_element(self) -> etree._Element:
    """
    Build element with optional validation.

    Returns:
        lxml Element representing this CDA component

    Raises:
        etree.DocumentInvalid: If validation fails
    """
    element = self.build()

    if self.schema:
        self.schema.assert_valid(element)

    return element

to_string(pretty=True, encoding='unicode')

Convert to XML string.

Parameters:

Name Type Description Default
pretty bool

Whether to pretty-print XML

True
encoding str

Output encoding ('unicode' or 'utf-8')

'unicode'

Returns:

Type Description
str

XML string representation

Source code in ccdakit/core/base.py
def to_string(self, pretty: bool = True, encoding: str = "unicode") -> str:
    """
    Convert to XML string.

    Args:
        pretty: Whether to pretty-print XML
        encoding: Output encoding ('unicode' or 'utf-8')

    Returns:
        XML string representation
    """
    return etree.tostring(
        self.to_element(),
        pretty_print=pretty,
        encoding=encoding,  # type: ignore
    )

get_templates()

Get templateIds for current version.

Returns:

Type Description
List[TemplateConfig]

List of TemplateConfig for this version

Raises:

Type Description
ValueError

If version not supported

Source code in ccdakit/core/base.py
def get_templates(self) -> List[TemplateConfig]:
    """
    Get templateIds for current version.

    Returns:
        List of TemplateConfig for this version

    Raises:
        ValueError: If version not supported
    """
    if self.version not in self.TEMPLATES:
        raise ValueError(
            f"Version {self.version.value} not supported for {self.__class__.__name__}"
        )
    return self.TEMPLATES[self.version]

add_template_ids(parent)

Add all templateIds for current version to parent element.

Parameters:

Name Type Description Default
parent _Element

Parent element to add templateIds to

required
Source code in ccdakit/core/base.py
def add_template_ids(self, parent: etree._Element) -> None:
    """
    Add all templateIds for current version to parent element.

    Args:
        parent: Parent element to add templateIds to
    """
    for template in self.get_templates():
        parent.append(template.to_element())

CDAVersion

Bases: Enum

Supported C-CDA versions.

Source code in ccdakit/core/base.py
class CDAVersion(Enum):
    """Supported C-CDA versions."""

    R1_1 = "1.1"
    R2_0 = "2.0"
    R2_1 = "2.1"
    R3_0 = "3.0"  # Planned

TemplateConfig

Template identifier configuration.

Source code in ccdakit/core/base.py
class TemplateConfig:
    """Template identifier configuration."""

    # CDA namespace for element creation
    NS = "urn:hl7-org:v3"

    def __init__(
        self,
        root: str,
        extension: Optional[str] = None,
        description: Optional[str] = None,
    ) -> None:
        """
        Initialize template configuration.

        Args:
            root: Template OID
            extension: Version extension (e.g., '2015-08-01')
            description: Human-readable description
        """
        self.root = root
        self.extension = extension
        self.description = description

    def to_element(self) -> etree._Element:
        """
        Convert to templateId XML element.

        Returns:
            lxml Element for templateId
        """
        elem = etree.Element(f"{{{self.NS}}}templateId", root=self.root)
        if self.extension:
            elem.set("extension", self.extension)
        return elem

Functions

__init__(root, extension=None, description=None)

Initialize template configuration.

Parameters:

Name Type Description Default
root str

Template OID

required
extension Optional[str]

Version extension (e.g., '2015-08-01')

None
description Optional[str]

Human-readable description

None
Source code in ccdakit/core/base.py
def __init__(
    self,
    root: str,
    extension: Optional[str] = None,
    description: Optional[str] = None,
) -> None:
    """
    Initialize template configuration.

    Args:
        root: Template OID
        extension: Version extension (e.g., '2015-08-01')
        description: Human-readable description
    """
    self.root = root
    self.extension = extension
    self.description = description

to_element()

Convert to templateId XML element.

Returns:

Type Description
_Element

lxml Element for templateId

Source code in ccdakit/core/base.py
def to_element(self) -> etree._Element:
    """
    Convert to templateId XML element.

    Returns:
        lxml Element for templateId
    """
    elem = etree.Element(f"{{{self.NS}}}templateId", root=self.root)
    if self.extension:
        elem.set("extension", self.extension)
    return elem

Validation

ValidationResult dataclass

Result of validation with errors, warnings, and info.

Source code in ccdakit/core/validation.py
@dataclass
class ValidationResult:
    """Result of validation with errors, warnings, and info."""

    errors: list[ValidationIssue] = field(default_factory=list)
    warnings: list[ValidationIssue] = field(default_factory=list)
    infos: list[ValidationIssue] = field(default_factory=list)

    @property
    def is_valid(self) -> bool:
        """Check if validation passed (no errors)."""
        return len(self.errors) == 0

    @property
    def has_warnings(self) -> bool:
        """Check if there are warnings."""
        return len(self.warnings) > 0

    @property
    def all_issues(self) -> list[ValidationIssue]:
        """Get all issues in order: errors, warnings, infos."""
        return self.errors + self.warnings + self.infos

    def raise_if_invalid(self) -> None:
        """
        Raise ValidationError if validation failed.

        Raises:
            ValidationError: If there are any errors
        """
        if not self.is_valid:
            raise ValidationError(self)

    def to_dict(self) -> dict:
        """Convert to dictionary for JSON serialization."""

        def issue_to_dict(issue: ValidationIssue) -> dict:
            """Convert a single issue to dict, including parsed data if available."""
            result = {
                "message": str(issue),
                "raw_message": issue.message,
            }
            # Only add parsed data if it exists (Schematron validation has it, XSD doesn't)
            if hasattr(issue, "parsed_data") and issue.parsed_data:
                result["parsed"] = issue.parsed_data
            return result

        return {
            "is_valid": self.is_valid,
            "error_count": len(self.errors),
            "warning_count": len(self.warnings),
            "info_count": len(self.infos),
            "errors": [issue_to_dict(e) for e in self.errors],
            "warnings": [issue_to_dict(w) for w in self.warnings],
            "infos": [issue_to_dict(i) for i in self.infos],
        }

    def __str__(self) -> str:
        """String representation of validation result."""
        lines = [
            f"Validation {'PASSED' if self.is_valid else 'FAILED'}",
            f"Errors: {len(self.errors)}, Warnings: {len(self.warnings)}, Info: {len(self.infos)}",
        ]

        if self.errors:
            lines.append("\nErrors:")
            lines.extend(f"  - {e}" for e in self.errors)

        if self.warnings:
            lines.append("\nWarnings:")
            lines.extend(f"  - {w}" for w in self.warnings)

        return "\n".join(lines)

Attributes

is_valid property

Check if validation passed (no errors).

has_warnings property

Check if there are warnings.

all_issues property

Get all issues in order: errors, warnings, infos.

Functions

raise_if_invalid()

Raise ValidationError if validation failed.

Raises:

Type Description
ValidationError

If there are any errors

Source code in ccdakit/core/validation.py
def raise_if_invalid(self) -> None:
    """
    Raise ValidationError if validation failed.

    Raises:
        ValidationError: If there are any errors
    """
    if not self.is_valid:
        raise ValidationError(self)

to_dict()

Convert to dictionary for JSON serialization.

Source code in ccdakit/core/validation.py
def to_dict(self) -> dict:
    """Convert to dictionary for JSON serialization."""

    def issue_to_dict(issue: ValidationIssue) -> dict:
        """Convert a single issue to dict, including parsed data if available."""
        result = {
            "message": str(issue),
            "raw_message": issue.message,
        }
        # Only add parsed data if it exists (Schematron validation has it, XSD doesn't)
        if hasattr(issue, "parsed_data") and issue.parsed_data:
            result["parsed"] = issue.parsed_data
        return result

    return {
        "is_valid": self.is_valid,
        "error_count": len(self.errors),
        "warning_count": len(self.warnings),
        "info_count": len(self.infos),
        "errors": [issue_to_dict(e) for e in self.errors],
        "warnings": [issue_to_dict(w) for w in self.warnings],
        "infos": [issue_to_dict(i) for i in self.infos],
    }

__str__()

String representation of validation result.

Source code in ccdakit/core/validation.py
def __str__(self) -> str:
    """String representation of validation result."""
    lines = [
        f"Validation {'PASSED' if self.is_valid else 'FAILED'}",
        f"Errors: {len(self.errors)}, Warnings: {len(self.warnings)}, Info: {len(self.infos)}",
    ]

    if self.errors:
        lines.append("\nErrors:")
        lines.extend(f"  - {e}" for e in self.errors)

    if self.warnings:
        lines.append("\nWarnings:")
        lines.extend(f"  - {w}" for w in self.warnings)

    return "\n".join(lines)

ValidationIssue dataclass

A validation issue (error, warning, or info).

Source code in ccdakit/core/validation.py
@dataclass
class ValidationIssue:
    """A validation issue (error, warning, or info)."""

    level: ValidationLevel
    message: str
    location: str | None = None  # XPath or description
    code: str | None = None  # Error code for categorization
    parsed_data: dict[str, Any] | None = None  # Parsed error data for enhanced display

    def __str__(self) -> str:
        """String representation of issue."""
        location_str = f" at {self.location}" if self.location else ""
        code_str = f" [{self.code}]" if self.code else ""
        return f"{self.level.value.upper()}{location_str}: {self.message}{code_str}"

Functions

__str__()

String representation of issue.

Source code in ccdakit/core/validation.py
def __str__(self) -> str:
    """String representation of issue."""
    location_str = f" at {self.location}" if self.location else ""
    code_str = f" [{self.code}]" if self.code else ""
    return f"{self.level.value.upper()}{location_str}: {self.message}{code_str}"

ValidationLevel

Bases: Enum

Validation severity levels.

Source code in ccdakit/core/validation.py
class ValidationLevel(Enum):
    """Validation severity levels."""

    ERROR = "error"
    WARNING = "warning"
    INFO = "info"

ValidationError

Bases: Exception

Exception raised when validation fails.

Source code in ccdakit/core/validation.py
class ValidationError(Exception):
    """Exception raised when validation fails."""

    def __init__(self, result: ValidationResult) -> None:
        """
        Initialize with validation result.

        Args:
            result: ValidationResult containing errors
        """
        self.result = result
        super().__init__(str(result))

Functions

__init__(result)

Initialize with validation result.

Parameters:

Name Type Description Default
result ValidationResult

ValidationResult containing errors

required
Source code in ccdakit/core/validation.py
def __init__(self, result: ValidationResult) -> None:
    """
    Initialize with validation result.

    Args:
        result: ValidationResult containing errors
    """
    self.result = result
    super().__init__(str(result))

Null Flavors

NullFlavor

Bases: Enum

Standard HL7 null flavors.

Used when data is missing or not applicable.

Source code in ccdakit/core/null_flavor.py
class NullFlavor(Enum):
    """
    Standard HL7 null flavors.

    Used when data is missing or not applicable.
    """

    # No information
    NI = "NI"  # No information
    INV = "INV"  # Invalid
    DER = "DER"  # Derived
    OTH = "OTH"  # Other
    NINF = "NINF"  # Negative infinity
    PINF = "PINF"  # Positive infinity

    # Unknown
    UNK = "UNK"  # Unknown
    ASKU = "ASKU"  # Asked but unknown
    NAV = "NAV"  # Temporarily unavailable
    NASK = "NASK"  # Not asked

    # Masked
    MSK = "MSK"  # Masked

    # Not applicable
    NA = "NA"  # Not applicable
    NAVU = "NAVU"  # Not available

get_null_flavor_for_missing(asked=False)

Get appropriate null flavor for missing data.

Parameters:

Name Type Description Default
asked bool

Whether the data was asked for but not provided

False

Returns:

Type Description
NullFlavor

Appropriate NullFlavor

Source code in ccdakit/core/null_flavor.py
def get_null_flavor_for_missing(asked: bool = False) -> NullFlavor:
    """
    Get appropriate null flavor for missing data.

    Args:
        asked: Whether the data was asked for but not provided

    Returns:
        Appropriate NullFlavor
    """
    return NullFlavor.ASKU if asked else NullFlavor.UNK

is_null_flavor(value)

Check if a string is a valid null flavor code.

Parameters:

Name Type Description Default
value Optional[str]

String to check

required

Returns:

Type Description
bool

True if value is a null flavor code

Source code in ccdakit/core/null_flavor.py
def is_null_flavor(value: Optional[str]) -> bool:
    """
    Check if a string is a valid null flavor code.

    Args:
        value: String to check

    Returns:
        True if value is a null flavor code
    """
    if value is None:
        return False
    try:
        NullFlavor(value)
        return True
    except ValueError:
        return False