diff --git a/src/entitysdk/models/__init__.py b/src/entitysdk/models/__init__.py index 8990317d..3e6bcddd 100644 --- a/src/entitysdk/models/__init__.py +++ b/src/entitysdk/models/__init__.py @@ -5,8 +5,10 @@ from entitysdk.models.brain_location import BrainLocation from entitysdk.models.brain_region import BrainRegion from entitysdk.models.contribution import Contribution, Role +from entitysdk.models.emodel import EModel from entitysdk.models.ion_channel_model import IonChannelModel, NeuronBlock, UseIon from entitysdk.models.license import License +from entitysdk.models.memodel import MEModel from entitysdk.models.morphology import ReconstructionMorphology from entitysdk.models.mtype import MTypeClass from entitysdk.models.taxonomy import Species, Strain, Taxonomy @@ -16,8 +18,10 @@ "BrainLocation", "BrainRegion", "Contribution", + "EModel", "IonChannelModel", "License", + "MEModel", "MTypeClass", "NeuronBlock", "Organization", diff --git a/src/entitysdk/models/emodel.py b/src/entitysdk/models/emodel.py new file mode 100644 index 00000000..04a7ec28 --- /dev/null +++ b/src/entitysdk/models/emodel.py @@ -0,0 +1,89 @@ +"""Electrical cell model.""" + +from typing import Annotated + +from pydantic import Field + +from entitysdk.models.contribution import Contribution +from entitysdk.models.entity import Entity +from entitysdk.models.etype import ETypeClass +from entitysdk.models.ion_channel_model import IonChannelModel +from entitysdk.models.morphology import ( + BrainRegion, + License, + ReconstructionMorphology, + Species, + Strain, +) +from entitysdk.models.mtype import MTypeClass + + +class EModel(Entity): + """Electrical cell model.""" + + species: Annotated[ + Species, + Field(description="The species for which the emodel applies."), + ] + strain: Annotated[ + Strain | None, + Field(description="The specific strain of the species, if applicable."), + ] = None + brain_region: Annotated[ + BrainRegion, + Field(description="The brain region where the emodel is used or applies."), + ] + license: Annotated[ + License | None, + Field(description="License under which the emodel is distributed."), + ] = None + contributions: Annotated[ + list[Contribution] | None, + Field(description="List of contributions related to this emodel."), + ] = None + iteration: Annotated[ + str, + Field( + description="The iteration of the emodel used during optimisation.", + examples="1372346", + ), + ] + score: Annotated[ + float, + Field( + description="The score of the emodel gotten during validation.", + examples=54.0, + ), + ] + seed: Annotated[ + int, + Field( + description="The RNG seed used during optimisation.", + examples=13, + ), + ] + exemplar_morphology: Annotated[ + ReconstructionMorphology | None, + Field( + description="The morphology used during optimisation.", + ), + ] = None + etypes: Annotated[ + list[ETypeClass] | None, + Field( + description="The etype classes of the emodel.", + ), + ] = None + mtypes: Annotated[ + list[MTypeClass] | None, + Field( + description="The mtype classes of the emodel.", + ), + ] = None + ion_channel_models: Annotated[ + list[IonChannelModel] | None, + Field( + description="List of ion channel models.", + ), + ] = None + legacy_id: list[str] | None = None diff --git a/src/entitysdk/models/etype.py b/src/entitysdk/models/etype.py new file mode 100644 index 00000000..6b47d079 --- /dev/null +++ b/src/entitysdk/models/etype.py @@ -0,0 +1,28 @@ +"""EType classification models.""" + +from typing import Annotated + +from pydantic import Field + +from entitysdk.models.core import Identifiable + + +class ETypeClass(Identifiable): + """EType model class.""" + + pref_label: Annotated[ + str, + Field( + description="The preferred label of the etype class.", + ), + ] + definition: Annotated[ + str, + Field( + description="The definition of the etype class.", + ), + ] + alt_label: Annotated[ + str | None, + Field(description="The alternative label of th etype class."), + ] diff --git a/src/entitysdk/models/memodel.py b/src/entitysdk/models/memodel.py new file mode 100644 index 00000000..1d1a72f8 --- /dev/null +++ b/src/entitysdk/models/memodel.py @@ -0,0 +1,96 @@ +"""Simulatable neuron model.""" + +from typing import Annotated + +from pydantic import Field + +from entitysdk.models.contribution import Contribution +from entitysdk.models.emodel import EModel +from entitysdk.models.entity import Entity +from entitysdk.models.etype import ETypeClass +from entitysdk.models.morphology import ( + BrainRegion, + License, + ReconstructionMorphology, + Species, + Strain, +) +from entitysdk.models.mtype import MTypeClass +from entitysdk.typedef import ValidationStatus + + +class MEModel(Entity): + """Simulatable neuron model.""" + + species: Annotated[ + Species, + Field(description="The species for which the memodel applies."), + ] + strain: Annotated[ + Strain | None, + Field(description="The specific strain of the species, if applicable."), + ] = None + brain_region: Annotated[ + BrainRegion, + Field(description="The brain region where the memodel is used or applies."), + ] + license: Annotated[ + License | None, + Field(description="License under which the memodel is distributed."), + ] = None + contributions: Annotated[ + list[Contribution] | None, + Field(description="List of contributions related to this memodel."), + ] = None + iteration: Annotated[ + str | None, + Field( + description="The iteration of the memodel used during optimisation.", + examples="1372346", + ), + ] = None + validation_status: Annotated[ + ValidationStatus, + Field( + description="The validation status of the memodel.", + ), + ] + holding_current: Annotated[ + float, + Field( + description="The holding current of the memodel.", + examples=0.0, + ), + ] = 0.0 + threshold_current: Annotated[ + float, + Field( + description="The threshold current of the memodel.", + examples=0.1, + ), + ] = 0.1 + morphology: Annotated[ + ReconstructionMorphology, + Field( + description="The morphology of the memodel.", + ), + ] + emodel: Annotated[ + EModel, + Field( + description="The emodel of the memodel.", + ), + ] + etypes: Annotated[ + list[ETypeClass] | None, + Field( + description="The etype classes of the memodel.", + ), + ] = None + mtypes: Annotated[ + list[MTypeClass] | None, + Field( + description="The mtype classes of the memodel.", + ), + ] = None + legacy_id: list[str] | None = None diff --git a/src/entitysdk/models/morphology.py b/src/entitysdk/models/morphology.py index 3ee42ae6..727a893e 100644 --- a/src/entitysdk/models/morphology.py +++ b/src/entitysdk/models/morphology.py @@ -22,17 +22,17 @@ class ReconstructionMorphology(Entity): ), ] = None brain_region: Annotated[ - BrainRegion, + BrainRegion | None, Field( description="The region of the brain where the morphology is located.", ), - ] + ] = None species: Annotated[ - Species, + Species | None, Field( description="The species of the morphology.", ), - ] + ] = None strain: Annotated[ Strain | None, Field( diff --git a/src/entitysdk/route.py b/src/entitysdk/route.py index dd953613..893e3f7d 100644 --- a/src/entitysdk/route.py +++ b/src/entitysdk/route.py @@ -22,6 +22,8 @@ "Taxonomy": "taxonomy", "IonChannelModel": "ion-channel-model", "Ion": "ion", + "EModel": "emodel", + "MEModel": "memodel", } diff --git a/src/entitysdk/typedef.py b/src/entitysdk/typedef.py index 3ea7063f..119b79a6 100644 --- a/src/entitysdk/typedef.py +++ b/src/entitysdk/typedef.py @@ -1,7 +1,7 @@ """Type definitions.""" import uuid -from enum import StrEnum +from enum import StrEnum, auto ID = uuid.UUID @@ -11,3 +11,13 @@ class DeploymentEnvironment(StrEnum): staging = "staging" production = "production" + + +class ValidationStatus(StrEnum): + """Validation status.""" + + created = auto() + initialized = auto() + running = auto() + done = auto() + error = auto() diff --git a/tests/integration/test_searching.py b/tests/integration/test_searching.py index 443ab2a2..6ab22f37 100644 --- a/tests/integration/test_searching.py +++ b/tests/integration/test_searching.py @@ -2,8 +2,10 @@ from entitysdk.models import ( Contribution, + EModel, IonChannelModel, License, + MEModel, MTypeClass, Organization, Person, @@ -27,6 +29,8 @@ Species, Strain, Organization, + EModel, + MEModel, ], ) def test_is_searchable(entity_type, client):