Skip to content

Commit 7287f54

Browse files
committed
fix: add maps endpoint
1 parent 9e10284 commit 7287f54

File tree

8 files changed

+111
-18
lines changed

8 files changed

+111
-18
lines changed

.helm/siibra-api-v4-worker/templates/_helpers.tpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Expand the name of the chart.
1111
{{- else -}}
1212
{{- printf "%s:%s" .Values.image.repository .Values.image.spec }}
1313
{{- end -}}
14+
{{- end -}}
1415

1516

1617
{{/*

api/common/data_handlers/core/misc.py

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
from api.common import data_decorator, get_filename, NotFound
22
from api.models.volumes.volume import MapType
33
from api.siibra_api_config import ROLE
4-
from typing import Union, Dict, Tuple
4+
from typing import Union, Dict, Tuple, List
5+
6+
def parse_maptype(maptype: Union[MapType, str]):
7+
if isinstance(maptype, MapType):
8+
assert maptype.name == maptype.value, f"str enum, expecting .name and .value to equal"
9+
return maptype.name
10+
if isinstance(maptype, str):
11+
return maptype
512

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

25-
maptype_string = None
26-
# check maptype name and value both matches
27-
if isinstance(maptype, MapType):
28-
assert maptype.name == maptype.value, f"str enum, expecting .name and .value to equal"
29-
maptype_string = maptype.name
30-
if isinstance(maptype, str):
31-
maptype_string = maptype
32+
maptype_string = parse_maptype(maptype)
3233

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

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

4344
return instance_to_model(
44-
returned_map
45+
returned_map, detail=True
4546
).dict()
4647

4748

@@ -213,4 +214,42 @@ def get_resampled_map(parcellation_id: str, space_id: str):
213214
"parcellation_id": parcellation_id,
214215
"space_id": space_id,
215216
}, indent="\t", fp=fp)
216-
return full_filename, False
217+
return full_filename, False
218+
219+
220+
@data_decorator(ROLE)
221+
def get_filtered_maps(parcellation_id: str=None, space_id: str=None, maptype: Union[MapType, str, None]=None):
222+
import siibra
223+
from api.serialization.util import instance_to_model
224+
225+
return_arr: List[siibra._parcellationmap.Map] = []
226+
for mp in siibra.maps:
227+
mp: siibra._parcellationmap.Map = mp
228+
if (
229+
parcellation_id is not None
230+
and mp.parcellation.id != parcellation_id
231+
):
232+
continue
233+
if (
234+
space_id is not None
235+
and mp.space.id != space_id
236+
):
237+
continue
238+
if (
239+
maptype is not None
240+
and mp.maptype != parse_maptype(maptype)
241+
):
242+
continue
243+
return_arr.append(mp)
244+
return [ instance_to_model(m).dict() for m in return_arr]
245+
246+
247+
@data_decorator(ROLE)
248+
def get_single_map(map_id: str):
249+
import siibra
250+
from api.serialization.util import instance_to_model
251+
for mp in siibra.maps:
252+
mp: siibra._parcellationmap.Map = mp
253+
if mp.id == map_id:
254+
return instance_to_model(mp, detail=True).dict()
255+
raise NotFound(f"map with id {map_id} not found.")

api/models/volumes/parcellationmap.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ class MapModel(_SiibraAtlasConcept):
99
species: str
1010
indices: Dict[str, List[MapIndexModel]]
1111
volumes: List[VolumeModel]
12+
parcellation: SiibraAtIdModel
13+
space: SiibraAtIdModel
14+
maptype: str
1215
# affine: List[float]
13-

api/serialization/core/_concept.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from api.models.core._concept import SiibraAtlasConcept, SiibraPublication
44

55
@serialize(AtlasConcept)
6-
def atlasconcept_to_model(concept: AtlasConcept) -> SiibraAtlasConcept:
6+
def atlasconcept_to_model(concept: AtlasConcept, **kwargs) -> SiibraAtlasConcept:
77
"""Serialize base concept.
88
99
Args:
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from api.models.volumes.parcellationmap import MapModel
2+
from api.models._commons import SiibraAtIdModel
23
from api.serialization.util import serialize, instance_to_model
34
from api.serialization.util.siibra import Map
45

56
@serialize(Map, pass_super_model=True)
6-
def map_to_model(map: Map, super_model_dict={}, **kwargs) -> MapModel:
7+
def map_to_model(map: Map, super_model_dict={}, detail=False, **kwargs) -> MapModel:
78
"""Serialize map instance
89
910
Args:
@@ -15,10 +16,13 @@ def map_to_model(map: Map, super_model_dict={}, **kwargs) -> MapModel:
1516
return MapModel(
1617
**super_model_dict,
1718
species=str(map.species),
19+
parcellation=SiibraAtIdModel(id=map.parcellation.id),
20+
space=SiibraAtIdModel(id=map.space.id),
21+
maptype=map.maptype.name,
1822
indices={
19-
regionname: instance_to_model(mapindex, **kwargs)
23+
regionname: instance_to_model(mapindex, detail=detail, **kwargs)
2024
for regionname, mapindex in map._indices.items()
21-
},
22-
volumes=[instance_to_model(v, **kwargs) for v in map.volumes],
25+
} if detail else {},
26+
volumes=[instance_to_model(v, detail=detail, **kwargs) for v in map.volumes] if detail else [],
2327
# affine=map.affine.tolist()
2428
)

api/server/volumes/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from . import parcellationmap
2+
from . import maps
23
from ..const import PrefixedRouter
34

45
prefixed_routers = (
56
PrefixedRouter(prefix="/map", router=parcellationmap.router),
7+
PrefixedRouter(prefix="/maps", router=maps.router),
68
)

api/server/volumes/maps.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from typing import Union
2+
3+
from pydantic import BaseModel
4+
from fastapi import APIRouter, HTTPException
5+
from fastapi.responses import FileResponse
6+
from fastapi_versioning import version
7+
from fastapi_pagination import Page, paginate
8+
9+
from api.models.volumes.volume import MapType
10+
from api.siibra_api_config import ROLE
11+
from api.server import FASTAPI_VERSION, cache_header
12+
from api.server.util import SapiCustomRoute
13+
from api.models.volumes.parcellationmap import MapModel
14+
from api.common import router_decorator, get_filename, logger, NotFound
15+
from api.common.data_handlers.core.misc import (
16+
get_filtered_maps,
17+
get_single_map,
18+
)
19+
20+
TAGS=["maps"]
21+
"""HTTP map tags"""
22+
23+
router = APIRouter(route_class=SapiCustomRoute, tags=TAGS)
24+
"""HTTP map router"""
25+
26+
@router.get("", response_model=Page[MapModel])
27+
@version(*FASTAPI_VERSION)
28+
@router_decorator(ROLE, func=get_filtered_maps)
29+
def filter_map(parcellation_id: str=None, space_id: str=None, map_type: Union[MapType, None]=None, *, func):
30+
"""Get a list of maps according to specification"""
31+
if func is None:
32+
raise HTTPException(500, f"func: None passsed")
33+
return paginate(func(parcellation_id, space_id, map_type))
34+
35+
36+
@router.get("/{map_id:lazy_path}", response_model=MapModel)
37+
@version(*FASTAPI_VERSION)
38+
@router_decorator(ROLE, func=get_single_map)
39+
def single_map(map_id: str, *, func):
40+
"""Get a list of maps according to specification"""
41+
if func is None:
42+
raise HTTPException(500, f"func: None passsed")
43+
return func(map_id)

api/server/volumes/parcellationmap.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@
2828
"""HTTP map router"""
2929

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

0 commit comments

Comments
 (0)