Skip to content

api.models

This module is a collection of pydantic models, which siibra instances will serialize into.

This is a deliberate design decision, since this could provide the type hinting with the least amount of dependency.

Processes import from this module must not require siibra installed.

_commons

ConfigBaseModel

ConfigBaseModel

Source code in api/models/_commons.py
class ConfigBaseModel(_BaseModel):
    """ConfigBaseModel"""

    _type: ClassVar[str] = None
    type: Optional[str] = Field(..., alias="@type")

    def __init__(__pydantic_self__, **data) -> None:
        kwargs = {}
        if "type" not in data:
            kwargs["type"] = __pydantic_self__.__class__._type
        super().__init__(**data, **kwargs)

    def __init_subclass__(cls, type: str=None) -> None:
        """On init subclass, configure _type accordingly.

        The type should always following the following pattern:

        ```
        siibra-{siibra_python_version}/{generic}/{specific}/{specific+1}...
        ```

        Similar to [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types)
        This can allow clients to decide on which level of specificity to stop on parsing the data.

        Additionally, fastapi response model type infer is not perfect. 

        e.g.

        ```python
        class B(BaseModel): pass
        class A(B): pass
        response_model = Union[A, B]
        ```

        Fastapi will reduce the above will be reduced to `B`.

        To circumvent the problem, all super classes must start with `_`. 

        Since we cannot directly control openminds, we ignore openminds types.

        Args:
            type: type of the new class

        Raises:
            AssertionError: if a super class does not start with `_`
            AssertionError: if a super class does not subclass ABC
        """

        if cls.__name__ not in ignore_cls:
            for mro_cls in cls.__mro__[1:]:

                # FIXME fastapi does some weird thing when start uvcorn
                if mro_cls.__name__ == cls.__name__:
                    continue

                if mro_cls is ConfigBaseModel:
                    break
                assert mro_cls.__name__[0] == "_", f"{cls.__name__!r} init subclass failure, {mro_cls.__name__!r} is illegal. Subclassed model MUST starts with underscore. Otherwise pydantic may confuse which model to use to serialize."
                assert issubclass(mro_cls, ABC), f"{cls.__name__!r} init subclass failure, {mro_cls.__name__!r} must be subclassed from ABC."

        if type:
            if cls._type is None:
                cls._type = f"siibra-{SIIBRA_PYTHON_VERSION}"
            cls._type = f"{cls._type}/{type}"

        return super().__init_subclass__()

__init_subclass__(type=None)

On init subclass, configure _type accordingly.

The type should always following the following pattern:

siibra-{siibra_python_version}/{generic}/{specific}/{specific+1}...

Similar to MIME types This can allow clients to decide on which level of specificity to stop on parsing the data.

Additionally, fastapi response model type infer is not perfect.

e.g.

class B(BaseModel): pass
class A(B): pass
response_model = Union[A, B]

Fastapi will reduce the above will be reduced to B.

To circumvent the problem, all super classes must start with _.

Since we cannot directly control openminds, we ignore openminds types.

Parameters:

Name Type Description Default
type str

type of the new class

None

Raises:

Type Description
AssertionError

if a super class does not start with _

AssertionError

if a super class does not subclass ABC

Source code in api/models/_commons.py
def __init_subclass__(cls, type: str=None) -> None:
    """On init subclass, configure _type accordingly.

    The type should always following the following pattern:

    ```
    siibra-{siibra_python_version}/{generic}/{specific}/{specific+1}...
    ```

    Similar to [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types)
    This can allow clients to decide on which level of specificity to stop on parsing the data.

    Additionally, fastapi response model type infer is not perfect. 

    e.g.

    ```python
    class B(BaseModel): pass
    class A(B): pass
    response_model = Union[A, B]
    ```

    Fastapi will reduce the above will be reduced to `B`.

    To circumvent the problem, all super classes must start with `_`. 

    Since we cannot directly control openminds, we ignore openminds types.

    Args:
        type: type of the new class

    Raises:
        AssertionError: if a super class does not start with `_`
        AssertionError: if a super class does not subclass ABC
    """

    if cls.__name__ not in ignore_cls:
        for mro_cls in cls.__mro__[1:]:

            # FIXME fastapi does some weird thing when start uvcorn
            if mro_cls.__name__ == cls.__name__:
                continue

            if mro_cls is ConfigBaseModel:
                break
            assert mro_cls.__name__[0] == "_", f"{cls.__name__!r} init subclass failure, {mro_cls.__name__!r} is illegal. Subclassed model MUST starts with underscore. Otherwise pydantic may confuse which model to use to serialize."
            assert issubclass(mro_cls, ABC), f"{cls.__name__!r} init subclass failure, {mro_cls.__name__!r} must be subclassed from ABC."

    if type:
        if cls._type is None:
            cls._type = f"siibra-{SIIBRA_PYTHON_VERSION}"
        cls._type = f"{cls._type}/{type}"

    return super().__init_subclass__()

DataFrameModel

DataFrameModel

Source code in api/models/_commons.py
class DataFrameModel(ConfigBaseModel):
    """DataFrameModel"""
    index: List[Any]
    columns: List[Any]
    ndim: int
    data: Optional[
        # to prepare for ndim > 2, maybe we should consider using generic ndim list?
        List[List[
            # probably easier than introducing a dependency to a more generalist module
            Any
            # Optional[Union[float, str, List[float], ParcellationEntityVersionModel]]
        ]]
    ]

MapIndexModel

MapIndexModel

Source code in api/models/_commons.py
class MapIndexModel(ConfigBaseModel):
    """MapIndexModel"""
    volume: int
    label: Optional[int]
    fragment: Optional[str]

SeriesModel

SeriesModel

Source code in api/models/_commons.py
class SeriesModel(ConfigBaseModel):
    """SeriesModel"""
    name: Optional[str]
    dtype: str
    index: List[Union[str, int, float]]
    data: List[float]

TaskIdResp

TaskIdResp

Source code in api/models/_commons.py
class TaskIdResp(BaseModel):
    """TaskIdResp"""
    task_id: str
    status: Optional[
        Union[
            Literal['SUCCESS'],
            Literal['PENDING'],
        ]
    ]

_retrieval

datasets

EbrainsDatasetModel

EbrainsDatasetModel

Source code in api/models/_retrieval/datasets.py
class EbrainsDatasetModel(ConfigBaseModel):
    """EbrainsDatasetModel"""
    id: str = Field(..., alias="@id")
    name: str
    urls: List[EbrainsDsUrl]
    description: Optional[str]
    contributors: List[EbrainsDsPerson]
    ebrains_page: Optional[str]
    custodians:  List[EbrainsDsPerson]

EbrainsDsPerson

EbrainsDsPerson

Source code in api/models/_retrieval/datasets.py
class EbrainsDsPerson(ConfigBaseModel):
    """EbrainsDsPerson"""
    id: str = Field(..., alias="@id")
    schema_shortname: Optional[str] = Field(..., alias="schema.org/shortName")
    identifier: str
    shortName: str
    name: str

EbrainsDsUrl

EbrainsDsUrl

Source code in api/models/_retrieval/datasets.py
7
8
9
class EbrainsDsUrl(ConfigBaseModel):
    """EbrainsDsUrl"""
    url: str

core

_concept

SiibraAtlasConcept

SiibraAtlasConcept

Source code in api/models/core/_concept.py
class SiibraAtlasConcept(_SiibraAtlasConcept):
    """SiibraAtlasConcept"""
    pass

atlas

SiibraAtlasModel

SiibraAtlasModel

Source code in api/models/core/atlas.py
class SiibraAtlasModel(ConfigBaseModel, type="atlas"):
    """SiibraAtlasModel"""
    id: str = Field(..., alias="@id")
    name: str
    spaces: List[SiibraAtIdModel]
    parcellations: List[SiibraAtIdModel]
    species: str

SpeciesModel

SpeciesModel

Source code in api/models/core/atlas.py
class SpeciesModel(_SpeciesModel):
    """SpeciesModel"""
    kg_v1_id: str = Field(..., alias="kgV1Id")

parcellation

SiibraParcellationModel

SiibraParcellationModel

Source code in api/models/core/parcellation.py
class SiibraParcellationModel(ConfigBaseModel, type="parcellation"):
    """SiibraParcellationModel"""
    id: str = Field(..., alias="@id")
    type: str = Field(..., alias="@type")
    name: str
    modality: Optional[str]
    datasets: List[EbrainsDatasetModel]
    brain_atlas_versions: List[BrainAtlasVersionModel] = Field(..., alias="brainAtlasVersions")
    version: Optional[SiibraParcellationVersionModel]
    shortname: Optional[str]

SiibraParcellationVersionModel

SiibraParcellationVersionModel

Source code in api/models/core/parcellation.py
class SiibraParcellationVersionModel(ConfigBaseModel, type="parcellation_version"):
    """SiibraParcellationVersionModel"""
    name: str
    deprecated: Optional[bool]
    prev: Optional[SiibraAtIdModel]
    next: Optional[SiibraAtIdModel]

region

ParcellationEntityVersionModel

ParcellationEntityVersionModel

Source code in api/models/core/region.py
class ParcellationEntityVersionModel(_ParcellationEntityVersionModel, ConfigBaseModel, type="region"):
    """ParcellationEntityVersionModel"""
    pass

Qualification

Qualification

Exactly match to Qualification in siibra.core.relation_quantification.Quantification

Source code in api/models/core/region.py
class Qualification(str, Enum):
    """Qualification

    Exactly match to Qualification in siibra.core.relation_quantification.Quantification"""
    EXACT = "EXACT"
    OVERLAPS = "OVERLAPS"
    CONTAINED = "CONTAINED"
    CONTAINS = "CONTAINS"
    APPROXIMATE = "APPROXIMATE"
    HOMOLOGOUS = "HOMOLOGOUS"
    OTHER_VERSION = "OTHER_VERSION"

space

CommonCoordinateSpaceModel

CommonCoordinateSpaceModel

Source code in api/models/core/space.py
class CommonCoordinateSpaceModel(_CommonCoordinateSpaceModel, ConfigBaseModel, type="space"):
    """CommonCoordinateSpaceModel"""
    default_image: Optional[List[VolumeModel]] = Field(
        None,
        alias='defaultImage',
        description='Two or three dimensional image that particluarly represents a specific coordinate space. Overriden by Siibra API to use as VolumeModel',
        min_items=1,
        title='defaultImage',
    )
    datasets: Optional[List[EbrainsDatasetModel]] = Field(
        None,
        alias="datasets",
    )

features

_basetypes

cortical_profiles

SiibraCorticalProfileModel

SiibraCorticalProfileModel

Source code in api/models/features/_basetypes/cortical_profiles.py
4
5
6
7
8
class SiibraCorticalProfileModel(_SiibraTabularModel, type="cortical_profile"):
    """SiibraCorticalProfileModel"""
    unit: Optional[str]
    boundary_positions: Dict[str, float]
    boundaries_mapped: bool

feature

FeatureModel

FeatureModel

Source code in api/models/features/_basetypes/feature.py
class FeatureModel(_FeatureModel):
    """FeatureModel"""
    pass
_FeatureModel

AbstractBaseModel

see api.models._commons.ConfigBaseModel

Source code in api/models/features/_basetypes/feature.py
class _FeatureModel(ConfigBaseModel, ABC, type="feature"):
    """AbstractBaseModel

    see [api.models._commons.ConfigBaseModel][]"""

    id: str
    modality: Optional[str] # ebrains dataset do not have modality populated
    category: str
    description: str
    name: str
    datasets: List[EbrainsDatasetModel]
    anchor: Optional[SiibraAnchorModel]

regional_connectivity

SiibraRegionalConnectivityModel

SiibraRegionalConnectivityModel

Source code in api/models/features/_basetypes/regional_connectivity.py
5
6
7
8
9
class SiibraRegionalConnectivityModel(_FeatureModel, type="regional_connectivity"):
    """SiibraRegionalConnectivityModel"""
    cohort: str
    subjects: List[str]
    matrices: Optional[Dict[str, DataFrameModel]]

tabular

SiibraTabularModel

SiibraTabularModel

Source code in api/models/features/_basetypes/tabular.py
class SiibraTabularModel(_SiibraTabularModel):
    """SiibraTabularModel"""
    pass
_SiibraTabularModel

AbstractBaseModel

see api.models._commons.ConfigBaseModel

Source code in api/models/features/_basetypes/tabular.py
class _SiibraTabularModel(_FeatureModel, ABC, type="tabular"):
    """AbstractBaseModel

    see [api.models._commons.ConfigBaseModel][]"""
    data: Optional[DataFrameModel]

volume_of_interest

SiibraVoiModel

SiibraVoiModel

Source code in api/models/features/_basetypes/volume_of_interest.py
5
6
7
8
class SiibraVoiModel(_FeatureModel, type="volume_of_interest"):
    """SiibraVoiModel"""
    volume: VolumeModel
    boundingbox: BoundingBoxModel

anchor

SiibraAnatomicalAssignmentModel

SiibraAnatomicalAssignmentModel

Source code in api/models/features/anchor.py
class SiibraAnatomicalAssignmentModel(ConfigBaseModel, type="anatomical_assignment"):
    """SiibraAnatomicalAssignmentModel"""
    qualification: str
    query_structure: Union[LocationModel, ParcellationEntityVersionModel, SiibraParcellationModel]
    assigned_structure: Union[LocationModel, ParcellationEntityVersionModel, SiibraParcellationModel]
    explanation: str

SiibraAnchorModel

SiibraAnchorModel

Source code in api/models/features/anchor.py
class SiibraAnchorModel(ConfigBaseModel, type="anchor"):
    """SiibraAnchorModel"""
    location: Optional[Union[LocationModel, CoordinatePointModel]]
    regions: List[SiibraRegionAssignmentQual]
    last_match_description: str=""
    last_match_result: List[SiibraAnatomicalAssignmentModel]=Field(default_factory=list)

SiibraRegionAssignmentQual

SiibraRegionAssignmentModel

Source code in api/models/features/anchor.py
class SiibraRegionAssignmentQual(ConfigBaseModel):
    """
    SiibraRegionAssignmentModel
    """
    region: ParcellationEntityVersionModel
    qualification: str

locations

boundingbox

BoundingBoxModel

BoundingBoxModel

Source code in api/models/locations/boundingbox.py
class BoundingBoxModel(_LocationModel, type="bbox"):
    """BoundingBoxModel"""
    center: CoordinatePointModel
    minpoint: CoordinatePointModel
    maxpoint: CoordinatePointModel
    shape: List[float]
    is_planar: bool = Field(..., alias="isPlanar")

location

LocationModel

LocationModel

Source code in api/models/locations/location.py
class LocationModel(_LocationModel):
    """LocationModel"""
    pass

point

CoordinatePointModel

CoordinatePointModel

Source code in api/models/locations/point.py
7
8
9
class CoordinatePointModel(_CoordinatePointModel, ConfigBaseModel, type="point"):
    """CoordinatePointModel"""
    pass

util

numpyarray

NpArrayDataModel

deprecated

NpArrayDataModel

Source code in api/models/util/numpyarray.py
class NpArrayDataModel(ConfigBaseModel):
    """deprecated

    NpArrayDataModel"""

    content_type: str = Field("application/octet-stream")
    content_encoding: str = Field("gzip; base64")
    x_width: int = Field(..., alias="x-width")
    x_height: int = Field(..., alias="x-height")
    x_channel: int = Field(..., alias="x-channel")
    dtype: str
    content: str

    def __init__(self, np_data=None, **data) -> None:
        import numpy as np
        import base64
        import gzip

        if np_data is None:
            return super().__init__(**data)

        # try to avoid 64 bit any number
        supported_dtype = [
            np.dtype("uint8"),
            np.dtype("int32"),
            np.dtype("float32"),
        ]
        assert type(np_data) is np.ndarray, f"expect input to be numpy array"
        assert np_data.dtype in supported_dtype, f"can only serialize {','.join([str(dtype) for dtype in supported_dtype])} for now"
        assert len(np_data.shape) <= 3, f"can only deal np array with up to 3 dimension"

        x_channel = 1 if len(np_data.shape) < 3 else np_data.shape[2]
        x_width = np_data.shape[0]
        x_height = 1 if len(np_data.shape) < 2 else np_data.shape[1]
        dtype = str(np_data.dtype)
        content = base64.b64encode(gzip.compress(np_data.tobytes(order="F")))

        super().__init__(
            x_width=x_width,
            x_height=x_height,
            dtype=dtype,
            content=content,
            x_channel=x_channel,
        )

volumes

parcellationmap

MapModel

MapModel

Source code in api/models/volumes/parcellationmap.py
class MapModel(_SiibraAtlasConcept):
    """MapModel"""
    species: str
    indices: Dict[str, List[MapIndexModel]]
    volumes: List[VolumeModel]

volume

MapType

MapType

Exact match to MapType in siibra, to avoid dependency on siibra

Source code in api/models/volumes/volume.py
class MapType(str, Enum):
    """MapType

    Exact match to MapType in siibra, to avoid dependency on siibra"""
    LABELLED = "LABELLED"
    STATISTICAL = "STATISTICAL"

VolumeModel

VolumeModel

Source code in api/models/volumes/volume.py
class VolumeModel(ConfigBaseModel):
    """VolumeModel"""
    name: str
    formats: List[str]

    provides_mesh: bool = Field(..., alias="providesMesh")
    provides_image: bool = Field(..., alias="providesImage")

    fragments: Dict[str, List[str]]
    variant: Optional[str]

    provided_volumes: Dict[str, Union[str, Dict[str, str]]] = Field(..., alias="providedVolumes")

    space: SiibraAtIdModel

    datasets: List[EbrainsDatasetModel]