Skip to content

Commit

Permalink
fix: add maps endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
xgui3783 committed Dec 10, 2024
1 parent 9e10284 commit 7287f54
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 18 deletions.
1 change: 1 addition & 0 deletions .helm/siibra-api-v4-worker/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Expand the name of the chart.
{{- else -}}
{{- printf "%s:%s" .Values.image.repository .Values.image.spec }}
{{- end -}}
{{- end -}}


{{/*
Expand Down
59 changes: 49 additions & 10 deletions api/common/data_handlers/core/misc.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
from api.common import data_decorator, get_filename, NotFound
from api.models.volumes.volume import MapType
from api.siibra_api_config import ROLE
from typing import Union, Dict, Tuple
from typing import Union, Dict, Tuple, List

def parse_maptype(maptype: Union[MapType, str]):
if isinstance(maptype, MapType):
assert maptype.name == maptype.value, f"str enum, expecting .name and .value to equal"
return maptype.name
if isinstance(maptype, str):
return maptype

@data_decorator(ROLE)
def get_map(parcellation_id: str, space_id: str, maptype: Union[MapType, str]) -> Dict:
Expand All @@ -22,13 +29,7 @@ def get_map(parcellation_id: str, space_id: str, maptype: Union[MapType, str]) -
import siibra
from api.serialization.util import instance_to_model

maptype_string = None
# check maptype name and value both matches
if isinstance(maptype, MapType):
assert maptype.name == maptype.value, f"str enum, expecting .name and .value to equal"
maptype_string = maptype.name
if isinstance(maptype, str):
maptype_string = maptype
maptype_string = parse_maptype(maptype)

assert maptype_string is not None, f"maptype is neither MapType nor str"

Expand All @@ -41,7 +42,7 @@ def get_map(parcellation_id: str, space_id: str, maptype: Union[MapType, str]) -
raise NotFound

return instance_to_model(
returned_map
returned_map, detail=True
).dict()


Expand Down Expand Up @@ -213,4 +214,42 @@ def get_resampled_map(parcellation_id: str, space_id: str):
"parcellation_id": parcellation_id,
"space_id": space_id,
}, indent="\t", fp=fp)
return full_filename, False
return full_filename, False


@data_decorator(ROLE)
def get_filtered_maps(parcellation_id: str=None, space_id: str=None, maptype: Union[MapType, str, None]=None):
import siibra
from api.serialization.util import instance_to_model

return_arr: List[siibra._parcellationmap.Map] = []
for mp in siibra.maps:
mp: siibra._parcellationmap.Map = mp
if (
parcellation_id is not None
and mp.parcellation.id != parcellation_id
):
continue
if (
space_id is not None
and mp.space.id != space_id
):
continue
if (
maptype is not None
and mp.maptype != parse_maptype(maptype)
):
continue
return_arr.append(mp)
return [ instance_to_model(m).dict() for m in return_arr]


@data_decorator(ROLE)
def get_single_map(map_id: str):
import siibra
from api.serialization.util import instance_to_model
for mp in siibra.maps:
mp: siibra._parcellationmap.Map = mp
if mp.id == map_id:
return instance_to_model(mp, detail=True).dict()
raise NotFound(f"map with id {map_id} not found.")
4 changes: 3 additions & 1 deletion api/models/volumes/parcellationmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ class MapModel(_SiibraAtlasConcept):
species: str
indices: Dict[str, List[MapIndexModel]]
volumes: List[VolumeModel]
parcellation: SiibraAtIdModel
space: SiibraAtIdModel
maptype: str
# affine: List[float]

2 changes: 1 addition & 1 deletion api/serialization/core/_concept.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from api.models.core._concept import SiibraAtlasConcept, SiibraPublication

@serialize(AtlasConcept)
def atlasconcept_to_model(concept: AtlasConcept) -> SiibraAtlasConcept:
def atlasconcept_to_model(concept: AtlasConcept, **kwargs) -> SiibraAtlasConcept:
"""Serialize base concept.
Args:
Expand Down
12 changes: 8 additions & 4 deletions api/serialization/volumes/parcellationmap.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from api.models.volumes.parcellationmap import MapModel
from api.models._commons import SiibraAtIdModel
from api.serialization.util import serialize, instance_to_model
from api.serialization.util.siibra import Map

@serialize(Map, pass_super_model=True)
def map_to_model(map: Map, super_model_dict={}, **kwargs) -> MapModel:
def map_to_model(map: Map, super_model_dict={}, detail=False, **kwargs) -> MapModel:
"""Serialize map instance
Args:
Expand All @@ -15,10 +16,13 @@ def map_to_model(map: Map, super_model_dict={}, **kwargs) -> MapModel:
return MapModel(
**super_model_dict,
species=str(map.species),
parcellation=SiibraAtIdModel(id=map.parcellation.id),
space=SiibraAtIdModel(id=map.space.id),
maptype=map.maptype.name,
indices={
regionname: instance_to_model(mapindex, **kwargs)
regionname: instance_to_model(mapindex, detail=detail, **kwargs)
for regionname, mapindex in map._indices.items()
},
volumes=[instance_to_model(v, **kwargs) for v in map.volumes],
} if detail else {},
volumes=[instance_to_model(v, detail=detail, **kwargs) for v in map.volumes] if detail else [],
# affine=map.affine.tolist()
)
2 changes: 2 additions & 0 deletions api/server/volumes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from . import parcellationmap
from . import maps
from ..const import PrefixedRouter

prefixed_routers = (
PrefixedRouter(prefix="/map", router=parcellationmap.router),
PrefixedRouter(prefix="/maps", router=maps.router),
)
43 changes: 43 additions & 0 deletions api/server/volumes/maps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from typing import Union

from pydantic import BaseModel
from fastapi import APIRouter, HTTPException
from fastapi.responses import FileResponse
from fastapi_versioning import version
from fastapi_pagination import Page, paginate

from api.models.volumes.volume import MapType
from api.siibra_api_config import ROLE
from api.server import FASTAPI_VERSION, cache_header
from api.server.util import SapiCustomRoute
from api.models.volumes.parcellationmap import MapModel
from api.common import router_decorator, get_filename, logger, NotFound
from api.common.data_handlers.core.misc import (
get_filtered_maps,
get_single_map,
)

TAGS=["maps"]
"""HTTP map tags"""

router = APIRouter(route_class=SapiCustomRoute, tags=TAGS)
"""HTTP map router"""

@router.get("", response_model=Page[MapModel])
@version(*FASTAPI_VERSION)
@router_decorator(ROLE, func=get_filtered_maps)
def filter_map(parcellation_id: str=None, space_id: str=None, map_type: Union[MapType, None]=None, *, func):
"""Get a list of maps according to specification"""
if func is None:
raise HTTPException(500, f"func: None passsed")
return paginate(func(parcellation_id, space_id, map_type))


@router.get("/{map_id:lazy_path}", response_model=MapModel)
@version(*FASTAPI_VERSION)
@router_decorator(ROLE, func=get_single_map)
def single_map(map_id: str, *, func):
"""Get a list of maps according to specification"""
if func is None:
raise HTTPException(500, f"func: None passsed")
return func(map_id)
6 changes: 4 additions & 2 deletions api/server/volumes/parcellationmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@
"""HTTP map router"""

# still use the old worker. New worker not stable (?)
@router.get("", response_model=MapModel)
@router.get("", response_model=MapModel, deprecated=True)
@version(*FASTAPI_VERSION)
@router_decorator(ROLE, func=old_get_map)
def get_siibra_map(parcellation_id: str, space_id: str, map_type: MapType, name: str= "", *, func):
"""Get map according to specification"""
"""Get map according to specification.
Deprecated. use /maps/{map_id} instead."""
if func is None:
raise HTTPException(500, f"func: None passsed")
return func(parcellation_id, space_id, map_type)
Expand Down

0 comments on commit 7287f54

Please sign in to comment.