Skip to content

Commit 1d73b19

Browse files
committed
Add tomogram search map endpoints
1 parent 26576eb commit 1d73b19

File tree

11 files changed

+98
-68
lines changed

11 files changed

+98
-68
lines changed

database/data.sql

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,7 +2347,7 @@ CREATE TABLE `ContainerInspection` (
23472347
CONSTRAINT `ContainerInspection_fk2` FOREIGN KEY (`inspectionTypeId`) REFERENCES `InspectionType` (`inspectionTypeId`) ON DELETE NO ACTION ON UPDATE NO ACTION,
23482348
CONSTRAINT `ContainerInspection_fk3` FOREIGN KEY (`imagerId`) REFERENCES `Imager` (`imagerId`) ON DELETE NO ACTION ON UPDATE NO ACTION,
23492349
CONSTRAINT `ContainerInspection_fk4` FOREIGN KEY (`scheduleComponentid`) REFERENCES `ScheduleComponent` (`scheduleComponentId`)
2350-
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
2350+
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
23512351
/*!40101 SET character_set_client = @saved_cs_client */;
23522352

23532353
--
@@ -2357,7 +2357,8 @@ CREATE TABLE `ContainerInspection` (
23572357
LOCK TABLES `ContainerInspection` WRITE;
23582358
/*!40000 ALTER TABLE `ContainerInspection` DISABLE KEYS */;
23592359
INSERT INTO `ContainerInspection` VALUES
2360-
(4,34874,1,NULL,NULL,'2018-08-07 15:20:00',NULL,'Completed',99,NULL,'2018-08-07 12:08:00','2018-08-07 15:36:00');
2360+
(4,34874,1,NULL,NULL,'2018-08-07 15:20:00',NULL,'Completed',99,NULL,'2018-08-07 12:08:00','2018-08-07 15:36:00'),
2361+
(5,34874,1,NULL,NULL,'2018-08-07 15:20:00',NULL,'Completed',99,NULL,'2018-08-07 12:08:00','2018-08-07 15:36:00');
23612362
/*!40000 ALTER TABLE `ContainerInspection` ENABLE KEYS */;
23622363
UNLOCK TABLES;
23632364

@@ -2950,7 +2951,7 @@ CREATE TABLE `DataCollection` (
29502951
CONSTRAINT `DataCollection_ibfk_6` FOREIGN KEY (`startPositionId`) REFERENCES `MotorPosition` (`motorPositionId`),
29512952
CONSTRAINT `DataCollection_ibfk_7` FOREIGN KEY (`endPositionId`) REFERENCES `MotorPosition` (`motorPositionId`),
29522953
CONSTRAINT `DataCollection_ibfk_8` FOREIGN KEY (`blSubSampleId`) REFERENCES `BLSubSample` (`blSubSampleId`)
2953-
) ENGINE=InnoDB AUTO_INCREMENT=6018040 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
2954+
) ENGINE=InnoDB AUTO_INCREMENT=6018043 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
29542955
/*!40101 SET character_set_client = @saved_cs_client */;
29552956

29562957
--
@@ -3070,7 +3071,7 @@ CREATE TABLE `DataCollectionGroup` (
30703071
CONSTRAINT `DataCollectionGroup_ibfk_1` FOREIGN KEY (`blSampleId`) REFERENCES `BLSample` (`blSampleId`) ON DELETE CASCADE ON UPDATE CASCADE,
30713072
CONSTRAINT `DataCollectionGroup_ibfk_2` FOREIGN KEY (`sessionId`) REFERENCES `BLSession` (`sessionId`) ON DELETE CASCADE ON UPDATE CASCADE,
30723073
CONSTRAINT `DataCollectionGroup_ibfk_4` FOREIGN KEY (`experimentTypeId`) REFERENCES `ExperimentType` (`experimentTypeId`)
3073-
) ENGINE=InnoDB AUTO_INCREMENT=5441293 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci COMMENT='a dataCollectionGroup is a group of dataCollection for a spe';
3074+
) ENGINE=InnoDB AUTO_INCREMENT=5441296 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci COMMENT='a dataCollectionGroup is a group of dataCollection for a spe';
30743075
/*!40101 SET character_set_client = @saved_cs_client */;
30753076

30763077
--
@@ -5429,7 +5430,7 @@ CREATE TABLE `ProcessingJob` (
54295430
PRIMARY KEY (`processingJobId`),
54305431
KEY `ProcessingJob_ibfk1` (`dataCollectionId`),
54315432
CONSTRAINT `ProcessingJob_ibfk1` FOREIGN KEY (`dataCollectionId`) REFERENCES `DataCollection` (`dataCollectionId`)
5432-
) ENGINE=InnoDB AUTO_INCREMENT=3990 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci COMMENT='From this we get both job times and lag times';
5433+
) ENGINE=InnoDB AUTO_INCREMENT=4017 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci COMMENT='From this we get both job times and lag times';
54335434
/*!40101 SET character_set_client = @saved_cs_client */;
54345435

54355436
--
@@ -5524,7 +5525,7 @@ CREATE TABLE `ProcessingJobParameter` (
55245525
KEY `ProcessingJobParameter_ibfk1` (`processingJobId`),
55255526
KEY `ProcessingJobParameter_idx_paramKey_procJobId` (`parameterKey`,`processingJobId`),
55265527
CONSTRAINT `ProcessingJobParameter_ibfk1` FOREIGN KEY (`processingJobId`) REFERENCES `ProcessingJob` (`processingJobId`)
5527-
) ENGINE=InnoDB AUTO_INCREMENT=27355 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
5528+
) ENGINE=InnoDB AUTO_INCREMENT=27655 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
55285529
/*!40101 SET character_set_client = @saved_cs_client */;
55295530

55305531
--
@@ -7825,8 +7826,8 @@ INSERT INTO `Tomogram` VALUES
78257826
(3,6017409,56986678,'aligned_file_fri_aretomo.mrc',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/dls','test.png','test.png','test.png','test.png','test.png','2023-01-19 14:15:44',NULL,NULL,NULL,NULL),
78267827
(4,6017411,56986679,'aligned_file_fri_aretomo.mrc','/dls/m02/data/align_output/Position_1_9_stack.mrc',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/dls','test.png','test.png','test.png','test.png','test.png','2023-01-19 14:15:44',NULL,NULL,NULL,NULL),
78277828
(5,6017411,56986800,'aligned_file_fri_aretomo.mrc','/dls/m02/data/align_output/Position_1_9_stack.mrc',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/dls','test.png','test.png','test.png','test.png','test.png','2023-01-19 14:15:44',NULL,NULL,NULL,NULL),
7828-
(6,6017408,56986676,'aligned_file_fri_aretomo.mrc','/dls/m02/data/align_output/Position_1_9_stack.mrc',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/dls','test.png','test.png','test.png','test.png','test.png','2023-01-19 14:15:44',NULL,NULL,NULL,NULL),
7829-
(7,6017408,56986676,'aligned_file_fri_aretomo.mrc','/dls/m02/data/align_output/Position_1_9_stack.mrc',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/dls','test.png','test.png','test.png','test.png','test.png','2023-01-19 14:15:44',NULL,NULL,NULL,NULL),
7829+
(6,6017408,56986676,'aligned_file_fri_aretomo.mrc','/dls/m02/data/align_output/Position_1_9_stack.mrc',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/dls','test.png','test.png','test.png','test.png','test.png','2023-01-19 14:15:44',NULL,1,NULL,NULL),
7830+
(7,6017408,56986676,'aligned_file_fri_aretomo.mrc','/dls/m02/data/align_output/Position_1_9_stack.mrc',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/dls','test.png','test.png','test.png','test.png','test.png','2023-01-19 14:15:44',NULL,1,NULL,NULL),
78307831
(8,6017413,56986801,'aligned_file_fri_aretomo.mrc','/dls/m02/data/align_output/Position_1_9_stack.mrc',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/dls','test.png','test.png','test.png','test.png','test.png','2023-01-19 14:15:44',1.2,NULL,NULL,NULL);
78317832
/*!40000 ALTER TABLE `Tomogram` ENABLE KEYS */;
78327833
UNLOCK TABLES;
@@ -8441,4 +8442,4 @@ UNLOCK TABLES;
84418442
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
84428443
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
84438444

8444-
-- Dump completed on 2025-07-09 10:50:48
8445+
-- Dump completed on 2025-07-25 11:49:47

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ dependencies = [
2525
"pydantic[email]~=2.11.5",
2626
"fpdf2~=2.8.3",
2727
"types-requests",
28-
"lims-utils~=0.4.6"
28+
"lims-utils~=0.4.7"
2929
]
3030
dynamic = ["version"]
3131
license.file = "LICENSE"

src/pato/crud/collections.py

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
ProcessingJobResponse,
4444
TomogramFullResponse,
4545
)
46-
from ..utils.database import db
46+
from ..utils.database import db, unravel
4747
from ..utils.generic import MovieType, check_session_active, parse_count, validate_path
4848
from ..utils.pika import PikaPublisher
4949

@@ -64,9 +64,7 @@
6464

6565
def _generate_proc_job_params(proc_job_id: int | Column[int], params: dict):
6666
return [
67-
ProcessingJobParameter(
68-
processingJobId=proc_job_id, parameterKey=key, parameterValue=value
69-
)
67+
ProcessingJobParameter(processingJobId=proc_job_id, parameterKey=key, parameterValue=value)
7068
for (key, value) in params.items()
7169
]
7270

@@ -104,8 +102,7 @@ def get_data_collection_attachments(
104102
def get_data_collection_attachment(collection_id: int, attachment_id: int):
105103
attachment_path = db.session.scalar(
106104
select(DataCollectionFileAttachment.fileFullPath).filter(
107-
DataCollectionFileAttachment.dataCollectionFileAttachmentId
108-
== attachment_id,
105+
DataCollectionFileAttachment.dataCollectionFileAttachmentId == attachment_id,
109106
DataCollectionFileAttachment.dataCollectionId == collection_id,
110107
)
111108
)
@@ -119,9 +116,7 @@ def get_data_collection_attachment(collection_id: int, attachment_id: int):
119116
return attachment_path
120117

121118

122-
def get_tomograms(
123-
limit: int, page: int, collectionId: int
124-
) -> Paged[TomogramFullResponse]:
119+
def get_tomograms(limit: int, page: int, collectionId: int) -> Paged[TomogramFullResponse]:
125120
query = (
126121
select(
127122
Tomogram,
@@ -152,9 +147,7 @@ def get_motion_correction(limit: int, page: int, collectionId: int) -> Paged[Ful
152147
return db.paginate(query, limit, page, slow_count=True)
153148

154149

155-
def initiate_reprocessing_tomogram(
156-
params: TomogramReprocessingParameters, collectionId: int
157-
):
150+
def initiate_reprocessing_tomogram(params: TomogramReprocessingParameters, collectionId: int):
158151
_validate_session_active(collectionId)
159152

160153
motion_correction_records = db.session.execute(
@@ -170,9 +163,7 @@ def initiate_reprocessing_tomogram(
170163
for record in motion_correction_records:
171164
# Users can modify the file name, and we cannot control where exactly the tilt
172165
# angle ends up, so we have to manually extract them from each file
173-
tilt_angle_regex = re.match(
174-
r".*_([-]?[0-9]+\.[0-9]+)_.*", record.micrographFullPath
175-
)
166+
tilt_angle_regex = re.match(r".*_([-]?[0-9]+\.[0-9]+)_.*", record.micrographFullPath)
176167

177168
if tilt_angle_regex is None:
178169
raise HTTPException(
@@ -313,9 +304,7 @@ def initiate_reprocessing_spa(params: SPAReprocessingParameters, collectionId: i
313304
db.session.add(new_job)
314305
db.session.flush()
315306

316-
db.session.bulk_save_objects(
317-
_generate_proc_job_params(new_job.processingJobId, full_params)
318-
)
307+
db.session.bulk_save_objects(_generate_proc_job_params(new_job.processingJobId, full_params))
319308
db.session.commit()
320309

321310
message = {"parameters": {"ispyb_process": new_job.processingJobId}}
@@ -356,8 +345,7 @@ def _with_ctf_joins(query: Select, collectionId: int):
356345
.join(CTF, CTF.motionCorrectionId == MotionCorrection.motionCorrectionId)
357346
.join(
358347
ParticlePicker,
359-
ParticlePicker.firstMotionCorrectionId
360-
== MotionCorrection.motionCorrectionId,
348+
ParticlePicker.firstMotionCorrectionId == MotionCorrection.motionCorrectionId,
361349
)
362350
)
363351

@@ -416,9 +404,7 @@ def get_particle_count_per_resolution(collectionId: int) -> ItemList[DataPoint]:
416404
@validate_path
417405
def get_central_slice(collection_id: int, movie_type: MovieType = None) -> str:
418406
tomogram_id = db.session.scalar(
419-
select(Tomogram.tomogramId)
420-
.filter(Tomogram.dataCollectionId == collection_id)
421-
.limit(1)
407+
select(Tomogram.tomogramId).filter(Tomogram.dataCollectionId == collection_id).limit(1)
422408
)
423409

424410
if tomogram_id is None:
@@ -428,3 +414,29 @@ def get_central_slice(collection_id: int, movie_type: MovieType = None) -> str:
428414
)
429415

430416
return get_slice_path(tomogram_id, movie_type)
417+
418+
419+
def get_data_collection(collection_id: int):
420+
# Since we need the index to be able to paginate the tomogram page properly, we need to obtain the ordinality
421+
# of the data collection in the set. This is quicker than finding the index in the front end, as 1/6th of data
422+
# collection groups have over 100 data collections.
423+
base_sub_query = (
424+
select(
425+
func.row_number().over(order_by=DataCollection.dataCollectionId).label("index"),
426+
*unravel(DataCollection),
427+
)
428+
.select_from(DataCollectionGroup)
429+
.join(DataCollection)
430+
.filter(
431+
DataCollectionGroup.dataCollectionGroupId
432+
== select(DataCollection.dataCollectionGroupId)
433+
.filter(DataCollection.dataCollectionId == collection_id)
434+
.scalar_subquery()
435+
)
436+
.group_by(DataCollection.dataCollectionId)
437+
.order_by(DataCollection.dataCollectionId)
438+
).subquery()
439+
440+
query = select(base_sub_query).filter(base_sub_query.c.dataCollectionId == collection_id)
441+
442+
return db.session.execute(query).one()

src/pato/crud/grid_squares.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
MotionCorrection,
66
Movie,
77
ParticlePicker,
8+
Tomogram,
89
)
910
from sqlalchemy import distinct, func, select
1011
from sqlalchemy.sql.functions import coalesce
@@ -23,7 +24,7 @@ def get_foil_holes(grid_square_id: int, page: int, limit: int):
2324
# Astigmatism can be negative if short/long axis get mixed up when calculating
2425
# astigmatism from defocus. It is also inserted in the database in angstroms,
2526
# when we want to return it in nm.
26-
(func.abs(func.avg(CTF.astigmatism))/10).label("astigmatism"),
27+
(func.abs(func.avg(CTF.astigmatism)) / 10).label("astigmatism"),
2728
func.avg(CTF.estimatedResolution).label("resolution"),
2829
func.avg(ParticlePicker.numberOfParticles).label("particleCount"),
2930
func.count(distinct(Movie.movieId)).label("movieCount"),
@@ -39,14 +40,13 @@ def get_foil_holes(grid_square_id: int, page: int, limit: int):
3940
CTF,
4041
CTF.motionCorrectionId == MotionCorrection.motionCorrectionId,
4142
isouter=True,
42-
).join(
43+
)
44+
.join(
4345
ParticlePicker,
44-
ParticlePicker.firstMotionCorrectionId
45-
== MotionCorrection.motionCorrectionId,
46+
ParticlePicker.firstMotionCorrectionId == MotionCorrection.motionCorrectionId,
4647
isouter=True,
47-
).group_by(
48-
FoilHole.foilHoleId
4948
)
49+
.group_by(FoilHole.foilHoleId)
5050
)
5151

5252
return db.paginate(query=query, limit=limit, page=page, slow_count=True)
@@ -55,7 +55,11 @@ def get_foil_holes(grid_square_id: int, page: int, limit: int):
5555
@validate_path
5656
def get_grid_square_image(grid_square_id: int):
5757
return db.session.scalar(
58-
select(GridSquare.gridSquareImage).filter(
59-
GridSquare.gridSquareId == grid_square_id
60-
)
58+
select(GridSquare.gridSquareImage).filter(GridSquare.gridSquareId == grid_square_id)
6159
)
60+
61+
62+
def get_tomograms(grid_square_id: int, limit: int, page: int):
63+
query = select(Tomogram).filter(Tomogram.gridSquareId == grid_square_id)
64+
65+
return db.paginate(query, limit, page, slow_count=False, scalar=False)

src/pato/crud/tomograms.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,13 @@ def _prepend_denoise(
4343
if len(split_file) != 3:
4444
raise HTTPException(status_code=500, detail="Unexpected filename")
4545

46-
denoised_prefix = (
47-
".denoised" if movie_type == "denoised" else f".denoised_{movie_type}"
48-
)
46+
denoised_prefix = ".denoised" if movie_type == "denoised" else f".denoised_{movie_type}"
4947

5048
return split_file[0] + denoised_prefix + "".join(split_file[1:3])
5149

5250

5351
@validate_path
54-
def _get_movie(
55-
tomogramId: int, movie_type: MovieType, image_type: Literal["thumbnail", "movie"]
56-
):
52+
def _get_movie(tomogramId: int, movie_type: MovieType, image_type: Literal["thumbnail", "movie"]):
5753
if movie_type:
5854
# If movie_Type is defined, this means that this is not the standard noisy tomogram we're looking for
5955
base_path = db.session.scalar(
@@ -71,9 +67,7 @@ def _get_movie(
7167
if movie_type == "picked":
7268
raise HTTPException(status_code=404, detail="No picked tomogram found")
7369

74-
column = (
75-
Tomogram.tomogramMovie if image_type == "movie" else Tomogram.centralSliceImage
76-
)
70+
column = Tomogram.tomogramMovie if image_type == "movie" else Tomogram.centralSliceImage
7771
base_path = _get_generic_tomogram_file(tomogramId, column)
7872
return _prepend_denoise(base_path, image_type, movie_type)
7973

src/pato/models/response.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,9 @@ class SessionResponse(OrmBaseModel):
7575
collectionGroups: Optional[int] = None
7676
dataCollectionGroupId: Optional[int] = None
7777

78+
7879
class DataCollectionGroupSummaryResponse(OrmBaseModel):
79-
dataCollectionGroupId: int = Field(
80-
..., lt=1e9, description="Data Collection Group ID"
81-
)
80+
dataCollectionGroupId: int = Field(..., lt=1e9, description="Data Collection Group ID")
8281
sessionId: int = Field(..., lt=1e9, description="Session ID")
8382
experimentType: Optional[str] = None
8483
atlasId: Optional[int] = None
@@ -147,23 +146,15 @@ class MotionCorrection(OrmBaseModel):
147146
motionCorrectionId: int
148147
dataCollectionId: Optional[int] = None
149148
autoProcProgramId: Optional[int] = None
150-
imageNumber: Optional[int] = Field(
151-
None, title="Movie number, sequential in time 1-n"
152-
)
149+
imageNumber: Optional[int] = Field(None, title="Movie number, sequential in time 1-n")
153150
firstFrame: Optional[int] = Field(None, title="First frame of movie used")
154151
lastFrame: Optional[int] = Field(None, title="Last frame of movie used")
155152
dosePerFrame: Optional[float] = Field(None, title="Dose per frame")
156153
doseWeight: Optional[float] = Field(None, title="Dose weight")
157154
totalMotion: Optional[float] = Field(None, title="Total motion")
158-
averageMotionPerFrame: Optional[float] = Field(
159-
None, title="Average motion per frame"
160-
)
161-
driftPlotFullPath: Optional[str] = Field(
162-
None, max_length=255, title="Path to drift plot"
163-
)
164-
micrographFullPath: Optional[str] = Field(
165-
None, max_length=255, title="Path to micrograph"
166-
)
155+
averageMotionPerFrame: Optional[float] = Field(None, title="Average motion per frame")
156+
driftPlotFullPath: Optional[str] = Field(None, max_length=255, title="Path to drift plot")
157+
micrographFullPath: Optional[str] = Field(None, max_length=255, title="Path to micrograph")
167158
micrographSnapshotFullPath: Optional[str] = Field(
168159
None, max_length=255, title="Path to micrograph"
169160
)
@@ -257,12 +248,15 @@ class ProcessingJobResponse(OrmBaseModel):
257248

258249

259250
class TomogramResponse(OrmBaseModel):
251+
dataCollectionId: int
260252
tomogramId: int
261253
volumeFile: Optional[str] = Field(None, max_length=255)
262254
stackFile: Optional[str] = Field(None, max_length=255)
263255
sizeX: Optional[int] = None
264256
sizeY: Optional[int] = None
265257
sizeZ: Optional[int] = None
258+
pixelLocationX: Optional[int] = None
259+
pixelLocationY: Optional[int] = None
266260
pixelSpacing: Optional[float] = None
267261
residualErrorMean: Optional[float] = None
268262
residualErrorSD: Optional[float] = None

src/pato/routes/collections.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ..crud import collection_report as report_crud
77
from ..crud import collections as crud
88
from ..crud import generic
9-
from ..models.collections import DataCollectionFileAttachmentOut
9+
from ..models.collections import BaseDataCollectionOut, DataCollectionFileAttachmentOut
1010
from ..models.reprocessing import (
1111
SPAReprocessingParameters,
1212
TomogramReprocessingParameters,
@@ -28,6 +28,12 @@
2828
prefix="/dataCollections",
2929
)
3030

31+
@router.get("/{collectionId}", response_model=BaseDataCollectionOut)
32+
def get_data_collection(
33+
collectionId: int = Depends(auth)
34+
):
35+
"""Get data collection"""
36+
return crud.get_data_collection(collection_id=collectionId)
3137

3238
@router.get("/{collectionId}/tomograms", response_model=Paged[TomogramFullResponse])
3339
def get_tomograms(

src/pato/routes/grid_squares.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from ..auth import Permissions
66
from ..crud import grid_squares as crud
7-
from ..models.response import FoilHole
7+
from ..models.response import FoilHole, TomogramResponse
88

99
router = APIRouter(
1010
tags=["Grid Squares"],
@@ -21,6 +21,14 @@ def get_foil_holes(
2121
return crud.get_foil_holes(grid_square_id=gridSquareId, **page)
2222

2323

24+
@router.get("/{gridSquareId}/tomograms", response_model=Paged[TomogramResponse])
25+
def get_tomograms(
26+
gridSquareId: int = Depends(Permissions.grid_square),
27+
page: dict[str, int] = Depends(pagination),
28+
):
29+
"""Get tomograms in a search map"""
30+
return crud.get_tomograms(grid_square_id=gridSquareId, **page)
31+
2432
@router.get("/{gridSquareId}/image", response_class=FileResponse)
2533
def get_grid_square_image(gridSquareId: int = Depends(Permissions.grid_square)):
2634
"""Get image of grid square"""

tests/collections/test_get.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
def test_get(mock_permissions, client):
2+
"""Get data collection"""
3+
resp = client.get("/dataCollections/6017412")
4+
assert resp.status_code == 200
5+
assert resp.json()["index"] == 2

0 commit comments

Comments
 (0)