Skip to content

FHIR Model Factory

Main class and utilities for dynamically constructing FHIR resource models.

ConstructionMode

Path: fhircraft.fhir.resources.factory.ConstructionMode

Bases: str, Enum

Mode for constructing FHIR resource models.

Attributes:

Name Type Description
SNAPSHOT

Build from complete snapshot definition

DIFFERENTIAL

Build from differential definition (inherits from base)

AUTO

Automatically detect based on available elements (default)

ModelT module-attribute

ModelT = TypeVar('ModelT', bound='BaseModel')

ResourceFactory

Path: fhircraft.fhir.resources.factory.ResourceFactory

ResourceFactory(repository: Optional[CompositeStructureDefinitionRepository] = None, internet_enabled: bool = True, enable_packages: bool = True, registry_base_url: Optional[str] = None, timeout: float = 30.0)

Factory for constructing Pydantic models from FHIR StructureDefinitions.

The ResourceFactory provides functionality to
  • Load StructureDefinitions from various sources (files, directories, dictionaries)
  • Load FHIR packages from package registries
  • Construct Pydantic models from StructureDefinitions
  • Cache constructed models for performance
  • Manage internet access and package registry configuration

Parameters:

Name Type Description Default
repository Optional[CompositeStructureDefinitionRepository]

Custom repository to use. If None, creates a default CompositeStructureDefinitionRepository

None
internet_enabled bool

Whether to enable internet access for downloading definitions

True
enable_packages bool

Whether to enable FHIR package support

True
registry_base_url Optional[str]

Base URL for the FHIR package registry

None
timeout float

Request timeout in seconds for package downloads

30.0

Classes:

Name Description
FactoryConfig

Represents the configuration for the Factory class.

Methods:

Name Description
configure_repository

Configure the factory repository with various sources.

disable_internet_access

Toggle offline mode (disable internet access) to avoid external requests.

enable_internet_access

Toggle online mode (enable internet access) to allow external requests.

load_definitions_from_directory

Load FHIR structure definitions from the specified directory.

load_definitions_from_files

Loads resource definitions from the specified file paths into the repository.

load_definitions_from_list

Loads resource definitions into the repository from a list of definition dictionaries.

load_package

Load a FHIR package and return loaded structure definitions.

get_loaded_packages

Get dictionary of loaded FHIR packages (name -> version).

has_package

Check if a package is loaded.

remove_package

Remove a loaded package.

set_registry_base_url

Set the FHIR package registry base URL.

clear_package_cache

Clear the package cache.

resolve_structure_definition

Resolve structure definition using the repository.

construct_resource_model

Constructs a Pydantic model based on the provided FHIR structure definition.

clear_cache

Clears the factory cache.

Attributes:

Name Type Description
in_snapshot_mode bool

Check if the factory is in snapshot construction mode.

in_differential_mode bool

Check if the factory is in differential construction mode.

Source code in fhircraft/fhir/resources/factory.py
def __init__(
    self,
    repository: Optional[CompositeStructureDefinitionRepository] = None,
    internet_enabled: bool = True,
    enable_packages: bool = True,
    registry_base_url: Optional[str] = None,
    timeout: float = 30.0,
):
    """Initialize the ResourceFactory.

    Args:
        repository: Custom repository to use. If None, creates a default CompositeStructureDefinitionRepository
        internet_enabled: Whether to enable internet access for downloading definitions
        enable_packages: Whether to enable FHIR package support
        registry_base_url: Base URL for the FHIR package registry
        timeout: Request timeout in seconds for package downloads
    """
    if repository is None:
        self.repository = CompositeStructureDefinitionRepository(
            internet_enabled=internet_enabled,
            enable_packages=enable_packages,
            registry_base_url=registry_base_url,
            timeout=timeout,
        )
    else:
        self.repository = repository

    self.construction_cache: Dict[str, type[BaseModel]] = {}
    self.paths_in_processing: set[str] = set()
    self.local_cache: Dict[str, type[BaseModel]] = {}
    self.Config: ResourceFactory.FactoryConfig

in_snapshot_mode property

in_snapshot_mode: bool

Check if the factory is in snapshot construction mode.

in_differential_mode property

in_differential_mode: bool

Check if the factory is in differential construction mode.

FactoryConfig

Path: fhircraft.fhir.resources.factory.ResourceFactory.FactoryConfig

Represents the configuration for the Factory class.

Attributes:

Name Type Description

Parameters:

Name Type Description Default
FHIR_release str
required
FHIR_version str
required
construction_mode ConstructionMode
<ConstructionMode.AUTO: 'auto'>

configure_repository

configure_repository(directory: Optional[Union[str, Path]] = None, files: Optional[List[Union[str, Path]]] = None, definitions: Optional[List[Dict[str, Any]]] = None, packages: Optional[List[Union[str, Tuple[str, str]]]] = None, internet_enabled: bool = True, registry_base_url: Optional[str] = None) -> None

Configure the factory repository with various sources.

Parameters:

Name Type Description Default
directory Optional[Union[str, Path]]

Directory containing structure definition files

None
files Optional[List[Union[str, Path]]]

List of individual structure definition files to load

None
definitions Optional[List[Dict[str, Any]]]

List of structure definition dictionaries to load

None
packages Optional[List[Union[str, Tuple[str, str]]]]

List of FHIR packages to load. Each can be a package name (string) or a tuple of (package_name, version)

None
internet_enabled bool

Whether to enable internet access

True
registry_base_url Optional[str]

Base URL for the package registry

None
Source code in fhircraft/fhir/resources/factory.py
def configure_repository(
    self,
    directory: Optional[Union[str, Path]] = None,
    files: Optional[List[Union[str, Path]]] = None,
    definitions: Optional[List[Dict[str, Any]]] = None,
    packages: Optional[List[Union[str, Tuple[str, str]]]] = None,
    internet_enabled: bool = True,
    registry_base_url: Optional[str] = None,
) -> None:
    """Configure the factory repository with various sources.

    Args:
        directory: Directory containing structure definition files
        files: List of individual structure definition files to load
        definitions: List of structure definition dictionaries to load
        packages: List of FHIR packages to load. Each can be a package name (string)
                 or a tuple of (package_name, version)
        internet_enabled: Whether to enable internet access
        registry_base_url: Base URL for the package registry
    """
    self.repository.set_internet_enabled(internet_enabled)

    if registry_base_url and hasattr(self.repository, "set_registry_base_url"):
        self.repository.set_registry_base_url(registry_base_url)

    if directory:
        self.load_definitions_from_directory(directory)

    if files:
        self.load_definitions_from_files(*files)

    if definitions:
        self.load_definitions_from_list(*definitions)

    if packages:
        for package in packages:
            if isinstance(package, str):
                self.load_package(package)
            elif isinstance(package, tuple) and len(package) == 2:
                self.load_package(package[0], package[1])
            else:
                raise ValueError(f"Invalid package specification: {package}")

disable_internet_access

disable_internet_access() -> None

Toggle offline mode (disable internet access) to avoid external requests.

Source code in fhircraft/fhir/resources/factory.py
def disable_internet_access(self) -> None:
    """Toggle offline mode (disable internet access) to avoid external requests."""
    self.repository.set_internet_enabled(False)

enable_internet_access

enable_internet_access() -> None

Toggle online mode (enable internet access) to allow external requests.

Source code in fhircraft/fhir/resources/factory.py
def enable_internet_access(self) -> None:
    """Toggle online mode (enable internet access) to allow external requests."""
    self.repository.set_internet_enabled(True)

load_definitions_from_directory

load_definitions_from_directory(directory_path: Union[str, Path]) -> None

Load FHIR structure definitions from the specified directory.

This method attempts to load structure definitions into the repository from the given directory path. If the underlying repository supports loading from a directory (i.e., implements load_from_directory), the method delegates the loading process to it. Otherwise, a NotImplementedError is raised.

Parameters:

Name Type Description Default
directory_path Union[str, Path]

The path to the directory containing structure definitions.

required

Raises:

Type Description
NotImplementedError

If the repository does not support loading from a directory.

Source code in fhircraft/fhir/resources/factory.py
def load_definitions_from_directory(self, directory_path: Union[str, Path]) -> None:
    """
    Load FHIR structure definitions from the specified directory.

    This method attempts to load structure definitions into the repository from the given directory path.
    If the underlying repository supports loading from a directory (i.e., implements `load_from_directory`),
    the method delegates the loading process to it. Otherwise, a NotImplementedError is raised.

    Args:
        directory_path (Union[str, Path]): The path to the directory containing structure definitions.

    Raises:
        NotImplementedError: If the repository does not support loading from a directory.
    """
    """Load structure definitions from a directory."""
    if hasattr(self.repository, "load_from_directory"):
        self.repository.load_from_directory(directory_path)
    else:
        raise NotImplementedError(
            "Repository does not support loading from directory"
        )

load_definitions_from_files

load_definitions_from_files(*file_paths: Union[str, Path]) -> None

Loads resource definitions from the specified file paths into the repository.

This method delegates the loading process to the repository's load_from_files method, if it exists. If the repository does not support loading from files, a NotImplementedError is raised.

Parameters:

Name Type Description Default
*file_paths Union[str, Path]

One or more file paths from which to load resource definitions.

()

Raises:

Type Description
NotImplementedError

If the repository does not support loading from files.

Source code in fhircraft/fhir/resources/factory.py
def load_definitions_from_files(self, *file_paths: Union[str, Path]) -> None:
    """
    Loads resource definitions from the specified file paths into the repository.

    This method delegates the loading process to the repository's `load_from_files` method,
    if it exists. If the repository does not support loading from files, a NotImplementedError is raised.

    Args:
        *file_paths (Union[str, Path]): One or more file paths from which to load resource definitions.

    Raises:
        NotImplementedError: If the repository does not support loading from files.
    """
    if hasattr(self.repository, "load_from_files"):
        self.repository.load_from_files(*file_paths)
    else:
        raise NotImplementedError("Repository does not support loading from files")

load_definitions_from_list

load_definitions_from_list(*definitions: Dict[str, Any]) -> None

Loads resource definitions into the repository from a list of definition dictionaries.

This method forwards the provided definitions to the repository's load_from_definitions method if it exists. If the repository does not support loading from definitions, a NotImplementedError is raised.

Parameters:

Name Type Description Default
*definitions Dict[str, Any]

One or more resource definition dictionaries to load.

()

Raises:

Type Description
NotImplementedError

If the repository does not support loading from definitions.

Source code in fhircraft/fhir/resources/factory.py
def load_definitions_from_list(self, *definitions: Dict[str, Any]) -> None:
    """
    Loads resource definitions into the repository from a list of definition dictionaries.

    This method forwards the provided definitions to the repository's `load_from_definitions`
    method if it exists. If the repository does not support loading from definitions,
    a NotImplementedError is raised.

    Args:
        *definitions (Dict[str, Any]): One or more resource definition dictionaries to load.

    Raises:
        NotImplementedError: If the repository does not support loading from definitions.
    """
    if hasattr(self.repository, "load_from_definitions"):
        self.repository.load_from_definitions(*definitions)
    else:
        raise NotImplementedError(
            "Repository does not support loading from definitions"
        )

load_package

load_package(package_name: str, version: Optional[str] = None) -> None

Load a FHIR package and return loaded structure definitions.

Parameters:

Name Type Description Default
package_name str

Name of the package (e.g., "hl7.fhir.us.core")

required
version Optional[str]

Version of the package (defaults to latest)

None

Returns:

Type Description
None

List of StructureDefinition objects that were loaded

Raises:

Type Description
RuntimeError

If package support is not enabled in the repository

Source code in fhircraft/fhir/resources/factory.py
def load_package(self, package_name: str, version: Optional[str] = None) -> None:
    """Load a FHIR package and return loaded structure definitions.

    Args:
        package_name: Name of the package (e.g., "hl7.fhir.us.core")
        version: Version of the package (defaults to latest)

    Returns:
        List of StructureDefinition objects that were loaded

    Raises:
        RuntimeError: If package support is not enabled in the repository
    """
    if hasattr(self.repository, "load_package"):
        self.repository.load_package(package_name, version)
    else:
        raise NotImplementedError("Repository does not support package loading")

get_loaded_packages

get_loaded_packages() -> Dict[str, str]

Get dictionary of loaded FHIR packages (name -> version).

Returns:

Type Description
Dict[str, str]

Dictionary mapping package names to their loaded versions

Source code in fhircraft/fhir/resources/factory.py
def get_loaded_packages(self) -> Dict[str, str]:
    """Get dictionary of loaded FHIR packages (name -> version).

    Returns:
        Dictionary mapping package names to their loaded versions
    """
    if hasattr(self.repository, "get_loaded_packages"):
        return self.repository.get_loaded_packages()
    else:
        return {}

has_package

has_package(package_name: str, version: Optional[str] = None) -> bool

Check if a package is loaded.

Parameters:

Name Type Description Default
package_name str

Name of the package

required
version Optional[str]

Version of the package (if None, checks any version)

None

Returns:

Type Description
bool

True if package is loaded

Source code in fhircraft/fhir/resources/factory.py
def has_package(self, package_name: str, version: Optional[str] = None) -> bool:
    """Check if a package is loaded.

    Args:
        package_name (str): Name of the package
        version (Optional[str]): Version of the package (if None, checks any version)

    Returns:
        True if package is loaded
    """
    if hasattr(self.repository, "has_package"):
        return self.repository.has_package(package_name, version)
    else:
        return False

remove_package

remove_package(package_name: str, version: Optional[str] = None) -> None

Remove a loaded package.

Parameters:

Name Type Description Default
package_name str

Name of the package

required
version Optional[str]

Version of the package (if None, removes all versions)

None
Source code in fhircraft/fhir/resources/factory.py
def remove_package(self, package_name: str, version: Optional[str] = None) -> None:
    """Remove a loaded package.

    Args:
        package_name (str): Name of the package
        version (Optional[str]): Version of the package (if None, removes all versions)
    """
    if hasattr(self.repository, "remove_package"):
        self.repository.remove_package(package_name, version)

set_registry_base_url

set_registry_base_url(base_url: str) -> None

Set the FHIR package registry base URL.

Parameters:

Name Type Description Default
base_url str

The base URL for the package registry

required

Raises:

Type Description
RuntimeError

If package support is not enabled in the repository

Source code in fhircraft/fhir/resources/factory.py
def set_registry_base_url(self, base_url: str) -> None:
    """Set the FHIR package registry base URL.

    Args:
        base_url (str): The base URL for the package registry

    Raises:
        RuntimeError: If package support is not enabled in the repository
    """
    if hasattr(self.repository, "set_registry_base_url"):
        self.repository.set_registry_base_url(base_url)
    else:
        raise NotImplementedError(
            "Repository does not support package registry configuration"
        )

clear_package_cache

clear_package_cache() -> None

Clear the package cache.

Source code in fhircraft/fhir/resources/factory.py
def clear_package_cache(self) -> None:
    """Clear the package cache."""
    if hasattr(self.repository, "clear_package_cache"):
        self.repository.clear_package_cache()

resolve_structure_definition

resolve_structure_definition(canonical_url: str, version: str | None = None) -> StructureDefinition | StructureDefinition | StructureDefinition

Resolve structure definition using the repository.

Source code in fhircraft/fhir/resources/factory.py
def resolve_structure_definition(
    self, canonical_url: str, version: str | None = None
) -> R4_StructureDefinition | R4B_StructureDefinition | R5_StructureDefinition:
    """Resolve structure definition using the repository."""
    if structure_def := self.repository.get(canonical_url, version):
        return structure_def
    raise ValueError(f"Could not resolve structure definition: {canonical_url}")

construct_resource_model

construct_resource_model(canonical_url: str | None = None, structure_definition: str | dict | StructureDefinition | StructureDefinition | StructureDefinition | None = None, base_model: type[ModelT] | None = None, mode: ConstructionMode | str = AUTO, mixins: Sequence[type] | None = None, fhir_release: Literal['DSTU2', 'STU3', 'R4', 'R4B', 'R5', 'R6'] | None = None) -> type[ModelT | BaseModel]

Constructs a Pydantic model based on the provided FHIR structure definition.

Parameters:

Name Type Description Default
canonical_url str | None

The FHIR resource's or profile's canonical URL from which to download the StructureDefinition.

None
structure_definition str | dict | StructureDefinition | StructureDefinition | StructureDefinition | None

The FHIR StructureDefinition to build the model from specified as a filename or as a dictionary.

None
base_model type[ModelT] | None

Optional base model to inherit from (overrides baseDefinition in differential mode).

None
mode ConstructionMode | str

Construction mode (SNAPSHOT, DIFFERENTIAL, or AUTO). Defaults to AUTO which auto-detects.

AUTO
mixins Sequence[type] | None

Optional sequence of mixin classes to include in the model.

None
fhir_release Literal['DSTU2', 'STU3', 'R4', 'R4B', 'R5', 'R6'] | None

Optional FHIR release version ("DSTU2", "STU3", "R4", "R4B", "R5", "R6") to use for model construction.

None

Returns:

Type Description
type[ModelT | BaseModel]

The constructed Pydantic model representing the FHIR resource.

Source code in fhircraft/fhir/resources/factory.py
def construct_resource_model(
    self,
    canonical_url: str | None = None,
    structure_definition: (
        str
        | dict
        | R4_StructureDefinition
        | R4B_StructureDefinition
        | R5_StructureDefinition
        | None
    ) = None,
    base_model: type[ModelT] | None = None,
    mode: ConstructionMode | str = ConstructionMode.AUTO,
    mixins: Sequence[type] | None = None,
    fhir_release: Literal["DSTU2", "STU3", "R4", "R4B", "R5", "R6"] | None = None,
) -> type[ModelT | BaseModel]:
    """
    Constructs a Pydantic model based on the provided FHIR structure definition.

    Args:
        canonical_url: The FHIR resource's or profile's canonical URL from which to download the StructureDefinition.
        structure_definition: The FHIR StructureDefinition to build the model from specified as a filename or as a dictionary.
        base_model: Optional base model to inherit from (overrides baseDefinition in differential mode).
        mode: Construction mode (SNAPSHOT, DIFFERENTIAL, or AUTO). Defaults to AUTO which auto-detects.
        mixins: Optional sequence of mixin classes to include in the model.
        fhir_release: Optional FHIR release version ("DSTU2", "STU3", "R4", "R4B", "R5", "R6") to use for model construction.

    Returns:
        The constructed Pydantic model representing the FHIR resource.
    """
    # If the model has been constructed before, return the cached model
    if canonical_url and canonical_url in self.construction_cache:
        return self.construction_cache[canonical_url]
    self.paths_in_processing: set[str] = set()
    self.local_cache: Dict[str, type[BaseModel]] = dict()

    # Resolve the FHIR structure definition
    _structure_definition = None
    if isinstance(
        structure_definition,
        (R4_StructureDefinition, R4B_StructureDefinition, R5_StructureDefinition),
    ):
        self.repository.add(structure_definition)
        _structure_definition = structure_definition
    elif isinstance(structure_definition, str):
        _structure_definition = self.repository.load_from_files(
            Path(structure_definition)
        )
    elif isinstance(structure_definition, dict):
        self.repository.load_from_definitions(structure_definition)
        _structure_definition = self.repository.get(
            structure_definition.get("url", "")
        )
    elif canonical_url:
        _structure_definition = self.resolve_structure_definition(canonical_url)
    if not _structure_definition:
        raise ValueError(
            "No StructureDefinition provided or downloaded. Please provide a valid StructureDefinition."
        )
    if not _structure_definition.name:
        raise ValueError("StructureDefinition must have a valid name.")

    # Detect the appropriate construction mode
    resolved_mode = self._detect_construction_mode(_structure_definition, mode)
    sanitized_name = self._sanitize_structure_definition_name(
        _structure_definition.name
    )

    if not _structure_definition.fhirVersion:
        if not fhir_release:
            raise ValueError(
                "StructureDefinition does not specify FHIR version. Please provide 'fhirVersion' in the structure definition."
            )
    else:
        if fhir_release and fhir_release != get_FHIR_release_from_version(
            _structure_definition.fhirVersion
        ):
            raise ValueError(
                "Provided fhir_release does not match StructureDefinition's fhirVersion."
            )
        else:
            fhir_release = get_FHIR_release_from_version(
                _structure_definition.fhirVersion
            )
    self.Config = self.FactoryConfig(
        FHIR_release=fhir_release,
        FHIR_version=_structure_definition.fhirVersion or "",
        construction_mode=resolved_mode,
    )

    # Determine the base model and StructureDefinition to inherit from
    _base_structure_definition = None
    # For DIFFERENTIAL mode, we must resolve the base definition
    if resolved_mode == ConstructionMode.DIFFERENTIAL:
        if base_canonical_url := _structure_definition.baseDefinition:
            # Resolve and store the base StructureDefinition for snapshot merging
            try:
                _base_structure_definition = self.resolve_structure_definition(
                    base_canonical_url, version=structure_definition.fhirVersion  # type: ignore
                )
            except Exception as e:
                # Base StructureDefinition not in repository
                # It may have been constructed inline - we'll construct without snapshot merging
                pass
            base = self._resolve_and_construct_base_model(
                base_canonical_url, _structure_definition
            )
            resolved_base_sd = self.repository.get(base_canonical_url)
            # Use resolved StructureDefinition if we didn't get it from repository
            if not _base_structure_definition and resolved_base_sd:
                _base_structure_definition = resolved_base_sd
        else:
            warnings.warn(
                f"DIFFERENTIAL mode for '{_structure_definition.name}' but no baseDefinition specified. "
                "Using FHIRBaseModel as base."
            )
            base = FHIRBaseModel
    # For SNAPSHOT mode, check if there's a baseDefinition to inherit from
    elif base_canonical_url := _structure_definition.baseDefinition:
        if not (base := self.construction_cache.get(base_canonical_url)):
            try:
                base = self._resolve_FHIR_type(base_canonical_url)
                assert inspect.isclass(base) and issubclass(base, FHIRBaseModel)
            except:
                base = FHIRBaseModel
    else:
        base = FHIRBaseModel

    # Select element source based on mode
    if resolved_mode == ConstructionMode.DIFFERENTIAL:
        if not _structure_definition.differential:
            raise ValueError(
                f"StructureDefinition '{_structure_definition.name}' has no differential element."
            )
        elements = _structure_definition.differential.element
        # Merge differential elements with base snapshot BEFORE building tree
        if _base_structure_definition and elements:
            elements = self._merge_differential_elements_with_base_snapshot(
                elements, _base_structure_definition
            )
    else:  # SNAPSHOT
        if not _structure_definition.snapshot:
            raise ValueError(
                f"StructureDefinition '{_structure_definition.name}' has no snapshot element."
            )
        elements = _structure_definition.snapshot.element
    if not elements:
        raise ValueError(
            f"StructureDefinition {'differential' if resolved_mode == ConstructionMode.DIFFERENTIAL else 'snapshot'} '{_structure_definition.name}' has no elements to process."
        )
    # Pre-process the elements into a tree structure to simplify model construction later
    nodes = self._build_element_tree_structure(elements)
    assert (
        len(nodes) == 1
    ), f"StructureDefinition {resolved_mode.value} must have exactly one root element."
    root_node = nodes[0]
    resource_type = _structure_definition.type
    # Configure the factory for the current FHIR environment
    if not _structure_definition.fhirVersion:
        warnings.warn(
            "StructureDefinition does not specify FHIR version, defaulting to 4.3.0."
        )

    # Process the FHIR resource's elements & constraints into Pydantic fields & validators
    fields, validators, properties = (
        self._process_FHIR_structure_into_Pydantic_components(
            root_node,
            resource_name=sanitized_name,
            base=base,
        )
    )
    # Process resource-level constraints
    if root_node.definition:
        for constraint in root_node.definition.constraint or []:
            validators.add_model_constraint_validator(constraint)

    # If the resource has metadata, prefill the information
    if "meta" in fields or "meta" in getattr(base, "model_fields", {}):
        Meta = get_complex_FHIR_type(
            "Meta", self.Config.FHIR_release if self.Config else "4.3.0"
        )
        fields["meta"] = (
            Optional[Meta],
            Field(
                title="Meta",
                description="Metadata about the resource.",
                default=Meta(
                    profile=[_structure_definition.url],
                ),
            ),
        )

    # Construct the Pydantic model representing the FHIR resource
    model = self._construct_model_with_properties(
        sanitized_name,
        fields=fields,
        base=(base, *mixins) if mixins else (base,),
        validators=validators.get_all(),
        properties=properties,
        docstring=_structure_definition.description,
    )

    # Set structural model metadata
    if issubclass(model, FHIRBaseModel):
        # Set the FHIR release version for the model and canonical URL
        model._fhir_release = self.Config.FHIR_release
        model._canonical_url = _structure_definition.url or None
        # Set the kind, type, canonical URL, and abstract status for the model
        if _structure_definition.kind:
            model._kind = FhirBaseModelKind(_structure_definition.kind)
        else:
            model._kind = FhirBaseModelKind.LOGICAL
        if resource_type:
            model._type = resource_type
        else:
            model._type = _structure_definition.type or _structure_definition.name
        if _structure_definition.abstract is not None:
            model._abstract = bool(_structure_definition.abstract)
        elif (
            base and issubclass(base, FHIRBaseModel) and base._abstract is not None
        ):
            model._abstract = base._abstract
        else:
            model._abstract = False

    # Add the current model to the cache
    self.construction_cache[str(_structure_definition.url)] = model
    return model

clear_cache

clear_cache()

Clears the factory cache.

Source code in fhircraft/fhir/resources/factory.py
def clear_cache(self):
    """
    Clears the factory cache.
    """
    self.construction_cache = {}
    self.local_cache = {}

ResourceFactoryValidators

Path: fhircraft.fhir.resources.factory.ResourceFactoryValidators

Container for resource-level validators.

Methods:

Name Description
add_model_constraint_validator

Adds a model constraint validator based on the provided constraint.

add_element_constraint_validator

Adds a validator for a specific element constraint to the validators dictionary.

add_slicing_validator

Adds a validator to ensure that slicing rules are followed for sliced elements.

add_type_choice_validator

Adds a validator to ensure that the field's value matches one of the allowed types.

add_model_constraint_validator

Adds a model constraint validator based on the provided constraint.

Parameters:

Name Type Description Default
constraint dict

The constraint details including expression, human-readable description, key, and severity.

required
Source code in fhircraft/fhir/resources/factory.py
def add_model_constraint_validator(
    self,
    constraint: (
        R4_ElementDefinitionConstraint
        | R4B_ElementDefinitionConstraint
        | R5_ElementDefinitionConstraint
    ),
):
    """
    Adds a model constraint validator based on the provided constraint.

    Args:
        constraint (dict): The constraint details including expression, human-readable description, key, and severity.
    """
    if (
        not constraint.key
        or not constraint.expression
        or not constraint.human
        or not constraint.key
        or not constraint.severity
    ):
        raise ValueError(
            "Constraint must have key, expression, human, and severity."
        )
    # Construct function name for validator
    constraint_name = constraint.key.replace("-", "_")
    validator_name = f"FHIR_{constraint_name}_constraint_model_validator"
    # Add the current field to the list of validated fields
    if constraint.expression:
        self._validators[validator_name] = model_validator(mode="after")(
            partial(
                fhir_validators.validate_model_constraint,
                expression=constraint.expression,
                human=constraint.human,
                key=constraint.key,
                severity=constraint.severity,
            )
        )

add_element_constraint_validator

add_element_constraint_validator(field: str, constraint: ElementDefinitionConstraint | ElementDefinitionConstraint | ElementDefinitionConstraint, base: Any)

Adds a validator for a specific element constraint to the validators dictionary.

Parameters:

Name Type Description Default
field str

The field to validate.

required
constraint dict

The details of the constraint including expression, human-readable description, key, and severity.

required
base Any

The base model to check for existing validators.

required
Source code in fhircraft/fhir/resources/factory.py
def add_element_constraint_validator(
    self,
    field: str,
    constraint: (
        R4_ElementDefinitionConstraint
        | R4B_ElementDefinitionConstraint
        | R5_ElementDefinitionConstraint
    ),
    base: Any,
):
    """
    Adds a validator for a specific element constraint to the validators dictionary.

    Args:
        field (str): The field to validate.
        constraint (dict): The details of the constraint including expression, human-readable description, key, and severity.
        base (Any): The base model to check for existing validators.
    """
    if (
        not constraint.key
        or not constraint.expression
        or not constraint.human
        or not constraint.key
        or not constraint.severity
    ):
        raise ValueError(
            "Constraint must have key, expression, human, and severity."
        )
    # Construct function name for validator
    constraint_name = constraint.key.replace("-", "_")
    validator_name = f"FHIR_{constraint_name}_constraint_validator"
    # If base model has a validator with the same name, modify the validator name to avoid conflicts
    if base and validator_name in base.__pydantic_decorators__.field_validators:
        validator_name = f"{base.__name__}_diff_{validator_name}"
    # Check if validator has already been constructed for another field
    validate_fields = [field]
    # Get the list of fields already being validated by this constraint
    if validator_name in self._validators:
        validator = self._validators.get(validator_name)
        if validator:
            validate_fields.extend(validator.keywords.get("elements", []))
    # Add the current field to the list of validated fields
    if constraint.expression:
        self._validators[validator_name] = model_validator(mode="after")(
            partial(
                fhir_validators.validate_element_constraint,
                elements=validate_fields,
                expression=constraint.expression,
                human=constraint.human,
                key=constraint.key,
                severity=constraint.severity,
            )
        )

add_slicing_validator

add_slicing_validator(field: str)

Adds a validator to ensure that slicing rules are followed for sliced elements.

Source code in fhircraft/fhir/resources/factory.py
def add_slicing_validator(self, field: str):
    """
    Adds a validator to ensure that slicing rules are followed for sliced elements.
    """
    self._validators[f"{field}_slicing_cardinality_validator"] = field_validator(
        field, mode="after"
    )(
        partial(
            fhir_validators.validate_slicing_cardinalities,
            field_name=field,
        )
    )

add_type_choice_validator

add_type_choice_validator(field: str, allowed_types: List[Union[str, type]], forbidden_types: List[Union[str, type]], required: bool = False)

Adds a validator to ensure that the field's value matches one of the allowed types.

Parameters:

Name Type Description Default
field str

The field to validate.

required
allowed_types List[Union[str, type]]

List of allowed types for the field.

required
required bool

Whether the field is required. Defaults to False.

False
Source code in fhircraft/fhir/resources/factory.py
def add_type_choice_validator(
    self,
    field: str,
    allowed_types: List[Union[str, type]],
    forbidden_types: List[Union[str, type]],
    required: bool = False,
):
    """
    Adds a validator to ensure that the field's value matches one of the allowed types.

    Args:
        field (str): The field to validate.
        allowed_types (List[Union[str, type]]): List of allowed types for the field.
        required (bool): Whether the field is required. Defaults to `False`.
    """
    self._validators[f"{field}_type_choice_validator"] = model_validator(
        mode="after"
    )(
        partial(
            fhir_validators.validate_type_choice_element,
            field_types=allowed_types,
            field_name_base=field,
            required=required,
            non_allowed_types=forbidden_types,
        )
    )

SlicedModelT module-attribute

SlicedModelT = TypeVar('SlicedModelT', bound='FHIRSliceModel')

StructureNode

Path: fhircraft.fhir.resources.factory.StructureNode

Bases: BaseModel

A node in the ElementDefinition tree structure.

Parameters:

Name Type Description Default
id str | None
None
path str | None
None
node_label str
required
children Dict[str, StructureNode]

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

<class 'dict'>
slices Dict[str, StructureNode]

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

<class 'dict'>
root StructureNode | None
None
definition ElementDefinition | ElementDefinition | ElementDefinition | None
None

construct_resource_model module-attribute

construct_resource_model = construct_resource_model

factory module-attribute

factory = ResourceFactory()

T module-attribute

T = TypeVar('T', bound=BaseModel)

get_type_choice_value_by_base

get_type_choice_value_by_base(instance: BaseModel, base: str) -> Any

Retrieve the value of a type-choice field in an instance based on the field name starting with a specific base string.

Parameters:

Name Type Description Default
instance object

The instance object to retrieve the value from.

required
base str

The base string that the field name should start with.

required

Returns:

Name Type Description
value Any

The value of the first field found in the instance that starts with the specified base string, or None if no such field exists or the value is None.

Source code in fhircraft/fhir/resources/validators.py
def get_type_choice_value_by_base(instance: BaseModel, base: str) -> Any:
    """
    Retrieve the value of a type-choice field in an instance based on the field
    name starting with a specific base string.

    Args:
        instance (object): The instance object to retrieve the value from.
        base (str): The base string that the field name should start with.

    Returns:
        value (Any): The value of the first field found in the instance that starts with the specified base string,
                    or `None` if no such field exists or the value is `None`.
    """
    for field in instance.__class__.model_fields:
        if field.startswith(base):
            value = getattr(instance, field)
            if value is not None:
                return value

validate_FHIR_element_fixed_value

validate_FHIR_element_fixed_value(cls: Any, element: Union[FHIRBaseModel, List[FHIRBaseModel], Any], constant: Union[FHIRBaseModel, List[FHIRBaseModel], Any]) -> Any

Validate the FHIR element against a specified constant value and return the element if it fulfills the constant.

Parameters:

Name Type Description Default
cls Any

Placeholder for an argument that is not used in the function.

required
element Union[FHIRBaseModel, List[FHIRBaseModel]]

The FHIR element to validate against the constant.

required
constant Union[FHIRBaseModel, List[FHIRBaseModel]]

The constant value to validate the element against.

required

Returns:

Type Description
Any

Union[FHIRBaseModel, List[FHIRBaseModel]]: The validated FHIR element.

Raises:

Type Description
AssertionError

If the element does not fulfill the specified constant.

Source code in fhircraft/fhir/resources/validators.py
def validate_FHIR_element_fixed_value(
    cls: Any,
    element: Union["FHIRBaseModel", List["FHIRBaseModel"], Any],
    constant: Union["FHIRBaseModel", List["FHIRBaseModel"], Any],
) -> Any:
    """
    Validate the FHIR element against a specified constant value and return the element if it fulfills the constant.

    Args:
        cls (Any): Placeholder for an argument that is not used in the function.
        element (Union[FHIRBaseModel, List[FHIRBaseModel]]): The FHIR element to validate against the constant.
        constant (Union[FHIRBaseModel, List[FHIRBaseModel]]): The constant value to validate the element against.

    Returns:
        Union[FHIRBaseModel, List[FHIRBaseModel]]: The validated FHIR element.

    Raises:
        AssertionError: If the element does not fulfill the specified constant.
    """
    from fhircraft.fhir.resources.base import FHIRBaseModel

    if isinstance(constant, list):
        constant = constant[0]
    _element = element[0] if isinstance(element, list) else element
    if isinstance(_element, FHIRBaseModel):
        assert (
            constant.model_dump() == _element.model_dump()
        ), f"Value does not fulfill constant:\n{constant.model_dump_json(indent=2)}"
    elif isinstance(_element, dict) and isinstance(constant, dict):
        assert constant == _element, f"Value does not fulfill constant: {constant}"
    else:
        assert constant == _element, f"Value does not fulfill constant: {constant}"
    return element

validate_FHIR_element_pattern

validate_FHIR_element_pattern(cls: Any, element: Union[FHIRBaseModel, List[FHIRBaseModel], Any], pattern: Union[FHIRBaseModel, List[FHIRBaseModel], Any]) -> Any

Validate the FHIR element against a specified pattern and return the element if it fulfills the pattern.

Parameters:

Name Type Description Default
cls Any

Placeholder for an argument that is not used in the function.

required
element Union[FHIRBaseModel, List[FHIRBaseModel]]

The FHIR element to validate against the pattern.

required
pattern Union[FHIRBaseModel, List[FHIRBaseModel]]

The pattern to validate the element against.

required

Returns:

Type Description
Any

Union[FHIRBaseModel, List[FHIRBaseModel]]: The validated FHIR element.

Raises:

Type Description
AssertionError

If the element does not fulfill the specified pattern.

Source code in fhircraft/fhir/resources/validators.py
def validate_FHIR_element_pattern(
    cls: Any,
    element: Union["FHIRBaseModel", List["FHIRBaseModel"], Any],
    pattern: Union["FHIRBaseModel", List["FHIRBaseModel"], Any],
) -> Any:
    """
    Validate the FHIR element against a specified pattern and return the element if it fulfills the pattern.

    Args:
        cls (Any): Placeholder for an argument that is not used in the function.
        element (Union[FHIRBaseModel, List[FHIRBaseModel]]): The FHIR element to validate against the pattern.
        pattern (Union[FHIRBaseModel, List[FHIRBaseModel]]): The pattern to validate the element against.

    Returns:
        Union[FHIRBaseModel, List[FHIRBaseModel]]: The validated FHIR element.

    Raises:
        AssertionError: If the element does not fulfill the specified pattern.
    """
    from fhircraft.fhir.resources.base import FHIRBaseModel

    if isinstance(pattern, list):
        pattern = pattern[0]
    _element = element[0] if isinstance(element, list) else element
    if isinstance(_element, FHIRBaseModel):
        assert (
            merge_dicts(_element.model_dump(), pattern.model_dump())
            == _element.model_dump()
        ), f"Value does not fulfill pattern:\n{pattern.model_dump_json(indent=2)}"
    elif isinstance(_element, dict) and isinstance(pattern, dict):
        assert (
            merge_dicts(_element, pattern) == _element
        ), f"Value does not fulfill pattern: {pattern}"
    else:
        assert _element == pattern, f"Value does not fulfill pattern: {pattern}"
    return element

validate_FHIR_model_fixed_value

validate_FHIR_model_fixed_value(model: Union[FHIRBaseModel, List[FHIRBaseModel], Any], constant: Union[FHIRBaseModel, List[FHIRBaseModel], Any]) -> Any

Validate the FHIR model against a specified constant value and return the model if it fulfills the constant.

Parameters:

Name Type Description Default
model Union[FHIRBaseModel, List[FHIRBaseModel]]

The FHIR model to validate against the constant.

required
constant Union[FHIRBaseModel, List[FHIRBaseModel]]

The constant value to validate the model against.

required

Returns:

Type Description
Any

Union[FHIRBaseModel, List[FHIRBaseModel]]: The validated FHIR element.

Raises:

Type Description
AssertionError

If the element does not fulfill the specified constant.

Source code in fhircraft/fhir/resources/validators.py
def validate_FHIR_model_fixed_value(
    model: Union["FHIRBaseModel", List["FHIRBaseModel"], Any],
    constant: Union["FHIRBaseModel", List["FHIRBaseModel"], Any],
) -> Any:
    """
    Validate the FHIR model against a specified constant value and return the model if it fulfills the constant.

    Args:
        model (Union[FHIRBaseModel, List[FHIRBaseModel]]): The FHIR model to validate against the constant.
        constant (Union[FHIRBaseModel, List[FHIRBaseModel]]): The constant value to validate the model against.

    Returns:
        Union[FHIRBaseModel, List[FHIRBaseModel]]: The validated FHIR element.

    Raises:
        AssertionError: If the element does not fulfill the specified constant.
    """
    return validate_FHIR_element_fixed_value(cls=None, element=model, constant=constant)

validate_FHIR_model_pattern

validate_FHIR_model_pattern(model: Union[FHIRBaseModel, List[FHIRBaseModel], Any], pattern: Union[FHIRBaseModel, List[FHIRBaseModel], Any]) -> Any

Validate the FHIR model against a specified pattern and return the model if it fulfills the pattern.

Parameters:

Name Type Description Default
model Union[FHIRBaseModel, List[FHIRBaseModel]]

The FHIR model to validate against the pattern.

required
pattern Union[FHIRBaseModel, List[FHIRBaseModel]]

The pattern to validate the model against.

required

Returns:

Type Description
Any

Union[FHIRBaseModel, List[FHIRBaseModel]]: The validated FHIR model.

Raises:

Type Description
AssertionError

If the model does not fulfill the specified pattern.

Source code in fhircraft/fhir/resources/validators.py
def validate_FHIR_model_pattern(
    model: Union["FHIRBaseModel", List["FHIRBaseModel"], Any],
    pattern: Union["FHIRBaseModel", List["FHIRBaseModel"], Any],
) -> Any:
    """
    Validate the FHIR model against a specified pattern and return the model if it fulfills the pattern.

    Args:
        model (Union[FHIRBaseModel, List[FHIRBaseModel]]): The FHIR model to validate against the pattern.
        pattern (Union[FHIRBaseModel, List[FHIRBaseModel]]): The pattern to validate the model against.

    Returns:
        Union[FHIRBaseModel, List[FHIRBaseModel]]: The validated FHIR model.

    Raises:
        AssertionError: If the model does not fulfill the specified pattern.
    """
    return validate_FHIR_element_pattern(cls=None, element=model, pattern=pattern)

validate_element_constraint

validate_element_constraint(instance: T, elements: Sequence[str], expression: str, human: str, key: str, severity: str) -> T

Validates a FHIR element constraint based on a FHIRPath expression.

Parameters:

Name Type Description Default
instance T

The instance to be validated.

required
elements Sequence[str]

The elements to be validated.

required
expression str

The FHIRPath expression to evaluate.

required
human str

A human-readable description of the constraint.

required
key str

The key associated with the constraint.

required
severity str

The severity level of the constraint ('warning' or 'error').

required

Returns:

Name Type Description
Any T

The validated value.

Raises:

Type Description
AssertionError

If the validation fails and severity is not warning.

Warning

If the validation fails and severity is warning.

Source code in fhircraft/fhir/resources/validators.py
def validate_element_constraint(
    instance: T,
    elements: Sequence[str],
    expression: str,
    human: str,
    key: str,
    severity: str,
) -> T:
    """
    Validates a FHIR element constraint based on a FHIRPath expression.

    Args:
        instance (T): The instance to be validated.
        elements (Sequence[str]): The elements to be validated.
        expression (str): The FHIRPath expression to evaluate.
        human (str): A human-readable description of the constraint.
        key (str): The key associated with the constraint.
        severity (str): The severity level of the constraint ('warning' or 'error').

    Returns:
        Any: The validated value.

    Raises:
        AssertionError: If the validation fails and severity is not `warning`.
        Warning: If the validation fails and severity is `warning`.
    """
    values = {}

    def _get_path_value(obj: Any, element_path: str, current_path: str = "") -> None:
        """
        Recursively extract values from nested object paths, handling lists correctly.

        Args:
            obj: Current object to traverse
            element_path: Remaining path to traverse (dot-separated)
            current_path: Path traversed so far (for error reporting)
        """
        if not element_path:
            # We've reached the end of the path
            values[current_path] = obj
            return

        parts = element_path.split(".", 1)
        current_attr = parts[0]
        remaining_path = parts[1] if len(parts) > 1 else ""

        # Build the new current path
        new_current_path = (
            f"{current_path}.{current_attr}" if current_path else current_attr
        )

        # Get the attribute value
        current_value = getattr(obj, current_attr, None) if obj is not None else None

        if current_value is None:
            # Attribute doesn't exist or is None
            values[
                (
                    new_current_path
                    if not remaining_path
                    else f"{new_current_path}.{remaining_path}"
                )
            ] = None
            return

        if isinstance(current_value, list):
            if not remaining_path:
                # We want the list itself
                values[new_current_path] = current_value
            else:
                # We need to traverse into each item in the list
                for idx, item in enumerate(current_value):
                    item_path = f"{new_current_path}[{idx}]"
                    _get_path_value(item, remaining_path, item_path)
        else:
            if not remaining_path:
                # We want this value
                values[new_current_path] = current_value
            else:
                # Continue traversing
                _get_path_value(current_value, remaining_path, new_current_path)

    for element_path in elements:
        _get_path_value(instance, element_path)

    for path, value in values.items():
        _validate_FHIR_element_constraint(
            value, instance, expression, human, key, severity, element=path
        )
    return instance

validate_model_constraint

validate_model_constraint(instance: T, expression: str, human: str, key: str, severity: str) -> T

Validates a FHIR model constraint based on a FHIRPath expression.

Parameters:

Name Type Description Default
instance T

Instance of the model to be validated.

required
expression str

The FHIRPath expression to evaluate.

required
human str

A human-readable description of the constraint.

required
key str

The key associated with the constraint.

required
severity str

The severity level of the constraint ('warning' or 'error').

required

Returns:

Name Type Description
instance type[T]

The validated model instance.

Raises:

Type Description
AssertionError

If the validation fails and severity is not warning.

Warning

If the validation fails and severity is warning.

Source code in fhircraft/fhir/resources/validators.py
def validate_model_constraint(
    instance: T, expression: str, human: str, key: str, severity: str
) -> T:
    """
    Validates a FHIR model constraint based on a FHIRPath expression.

    Args:
        instance (T): Instance of the model to be validated.
        expression (str): The FHIRPath expression to evaluate.
        human (str): A human-readable description of the constraint.
        key (str): The key associated with the constraint.
        severity (str): The severity level of the constraint ('warning' or 'error').

    Returns:
        instance (type[T]): The validated model instance.

    Raises:
        AssertionError: If the validation fails and severity is not `warning`.
        Warning: If the validation fails and severity is `warning`.
    """
    return _validate_FHIR_element_constraint(
        instance, instance, expression, human, key, severity
    )

validate_slicing_cardinalities

validate_slicing_cardinalities(cls: Any, values: List[Any] | None, field_name: str) -> List[FHIRSliceModel] | None

Validates the cardinalities of FHIR slices for a specific field within a FHIR resource.

Parameters:

Name Type Description Default
cls Any

The Pydantic FHIR model class.

required
values List[Any]

List of values for the field.

required
field_name str

The name of the field to validate.

required

Returns:

Type Description
List[FHIRSliceModel] | None

List[FHIRSliceModel]: The validated list of values.

Raises:

Type Description
AssertionError

If cardinality constraints are violated for any slice.

Source code in fhircraft/fhir/resources/validators.py
def validate_slicing_cardinalities(
    cls: Any, values: List[Any] | None, field_name: str
) -> List["FHIRSliceModel"] | None:
    """
    Validates the cardinalities of FHIR slices for a specific field within a FHIR resource.

    Args:
        cls (Any): The Pydantic FHIR model class.
        values (List[Any]): List of values for the field.
        field_name (str): The name of the field to validate.

    Returns:
        List[FHIRSliceModel]: The validated list of values.

    Raises:
        AssertionError: If cardinality constraints are violated for any slice.
    """
    from fhircraft.fhir.resources.base import FHIRSliceModel

    if values is None:
        return values
    slices = get_all_models_from_field(
        cls.model_fields[field_name], issubclass_of=FHIRSliceModel
    )
    for slice in slices:
        slice_instances_count = sum([isinstance(value, slice) for value in values])
        assert (
            slice_instances_count >= slice.min_cardinality
        ), f"Slice '{slice.__name__}' for field '{field_name}' violates its min. cardinality. \
                Requires min. cardinality of {slice.min_cardinality}, but got {slice_instances_count}"
        assert (
            slice_instances_count <= slice.max_cardinality
        ), f"Slice '{slice.__name__}' for field '{field_name}' violates its max. cardinality. \
                Requires max. cardinality of {slice.max_cardinality}, but got {slice_instances_count}"
    return values

validate_type_choice_element

validate_type_choice_element(instance: T, field_types: List[Any], field_name_base: str, required: bool = False, non_allowed_types: List[Any] | None = None) -> T

Validate the type choice element for a given instance.

Parameters:

Name Type Description Default
instance T

The instance to validate.

required
field_types List[Any]

List of field types to check.

required
field_name_base str

Base name of the field.

required
required bool

Whether the type choice element is required.

False
non_allowed_types List[Any] | None

List of types that are not allowed for this element (for negative checks).

None

Returns:

Name Type Description
T T

The validated instance.

Raises:

Type Description
AssertionError

If more than one value is set for the type choice element or if a non-allowed type is set.

Source code in fhircraft/fhir/resources/validators.py
def validate_type_choice_element(
    instance: T,
    field_types: List[Any],
    field_name_base: str,
    required: bool = False,
    non_allowed_types: List[Any] | None = None,
) -> T:
    """
    Validate the type choice element for a given instance.

    Args:
        instance (T): The instance to validate.
        field_types (List[Any]): List of field types to check.
        field_name_base (str): Base name of the field.
        required (bool): Whether the type choice element is required.
        non_allowed_types (List[Any] | None): List of types that are not allowed for this element (for negative checks).

    Returns:
        T: The validated instance.

    Raises:
        AssertionError: If more than one value is set for the type choice element or if a non-allowed type is set.
    """
    types_set_count = sum(
        (
            getattr(
                instance,
                (
                    field_name_base
                    + (
                        field_type
                        if isinstance(field_type, str)
                        else field_type.__name__
                    )
                ),
                None,
            )
        )
        is not None
        for field_type in field_types
    )
    assert (
        types_set_count <= 1
    ), f"Type choice element {field_name_base}[x] can only have one value set."
    assert not required or (
        required and types_set_count > 0
    ), f"Type choice element {field_name_base}[x] must have one value set. Got {types_set_count}."

    # Check that non-allowed types are not set
    if non_allowed_types:
        for non_allowed_type in non_allowed_types:
            field_name = field_name_base + (
                non_allowed_type
                if isinstance(non_allowed_type, str)
                else non_allowed_type.__name__
            )
            value = getattr(instance, field_name, None)
            assert (
                value is None
            ), f"Type choice element {field_name_base}[x] cannot use non-allowed type '{non_allowed_type}'. "

    return instance