1
1
"""FastAPI endpoint functions for the `/labwareOffsets` endpoints."""
2
2
3
3
4
+ from datetime import datetime
4
5
import textwrap
5
6
from typing import Annotated , Literal
6
7
7
8
import fastapi
8
- from opentrons .protocol_engine import LabwareOffset , LabwareOffsetCreate
9
+ from opentrons .protocol_engine import LabwareOffset , LabwareOffsetCreate , ModuleModel
10
+ from opentrons .types import DeckSlotName
9
11
12
+ from robot_server .labware_offsets .models import LabwareOffsetNotFound
13
+ from robot_server .service .dependencies import get_current_time , get_unique_id
10
14
from robot_server .service .json_api .request import RequestModel
11
15
from robot_server .service .json_api .response import (
16
+ MultiBodyMeta ,
12
17
PydanticResponse ,
13
18
SimpleBody ,
14
19
SimpleEmptyBody ,
15
20
SimpleMultiBody ,
16
21
)
17
22
23
+ from .store import LabwareOffsetNotFoundError , LabwareOffsetStore
24
+ from .fastapi_dependencies import get_labware_offset_store
25
+
18
26
19
27
router = fastapi .APIRouter (prefix = "/labwareOffsets" )
20
28
31
39
To do that, you must add the offset to a run, through the `/runs` endpoints.
32
40
"""
33
41
),
42
+ status_code = 201 ,
34
43
)
35
- def post_labware_offset ( # noqa: D103
36
- new_offset : Annotated [RequestModel [LabwareOffsetCreate ], fastapi .Body ()]
37
- ) -> PydanticResponse [SimpleEmptyBody ]:
38
- raise NotImplementedError ()
44
+ async def post_labware_offset ( # noqa: D103
45
+ store : Annotated [LabwareOffsetStore , fastapi .Depends (get_labware_offset_store )],
46
+ new_offset_id : Annotated [str , fastapi .Depends (get_unique_id )],
47
+ new_offset_created_at : Annotated [datetime , fastapi .Depends (get_current_time )],
48
+ request_body : Annotated [RequestModel [LabwareOffsetCreate ], fastapi .Body ()],
49
+ ) -> PydanticResponse [SimpleBody [LabwareOffset ]]:
50
+ new_offset = LabwareOffset .construct (
51
+ id = new_offset_id ,
52
+ createdAt = new_offset_created_at ,
53
+ definitionUri = request_body .data .definitionUri ,
54
+ location = request_body .data .location ,
55
+ vector = request_body .data .vector ,
56
+ )
57
+ store .add (new_offset )
58
+ return await PydanticResponse .create (
59
+ content = SimpleBody .construct (data = new_offset ),
60
+ status_code = 201 ,
61
+ )
39
62
40
63
41
64
@PydanticResponse .wrap_route (
@@ -48,7 +71,8 @@ def post_labware_offset( # noqa: D103
48
71
" Results are returned in order from oldest to newest."
49
72
),
50
73
)
51
- def get_labware_offsets ( # noqa: D103
74
+ async def get_labware_offsets ( # noqa: D103
75
+ store : Annotated [LabwareOffsetStore , fastapi .Depends (get_labware_offset_store )],
52
76
id : Annotated [
53
77
str | None ,
54
78
fastapi .Query (description = "Filter for exact matches on the `id` field." ),
@@ -64,23 +88,23 @@ def get_labware_offsets( # noqa: D103
64
88
),
65
89
] = None ,
66
90
location_slot_name : Annotated [
67
- str | None ,
91
+ DeckSlotName | None ,
68
92
fastapi .Query (
69
- alias = "location.slotName " ,
93
+ alias = "locationSlotName " ,
70
94
description = "Filter for exact matches on the `location.slotName` field." ,
71
95
),
72
96
] = None ,
73
97
location_module_model : Annotated [
74
- str | None ,
98
+ ModuleModel | None ,
75
99
fastapi .Query (
76
- alias = "location.moduleModel " ,
100
+ alias = "locationModuleModel " ,
77
101
description = "Filter for exact matches on the `location.moduleModel` field." ,
78
102
),
79
103
] = None ,
80
104
location_definition_uri : Annotated [
81
105
str | None ,
82
106
fastapi .Query (
83
- alias = "location.definitionUri " ,
107
+ alias = "locationDefinitionUri " ,
84
108
description = (
85
109
"Filter for exact matches on the `location.definitionUri` field."
86
110
" (Not to be confused with just `definitionUri`.)"
@@ -104,7 +128,32 @@ def get_labware_offsets( # noqa: D103
104
128
),
105
129
] = "unlimited" ,
106
130
) -> PydanticResponse [SimpleMultiBody [LabwareOffset ]]:
107
- raise NotImplementedError ()
131
+ if cursor not in (0 , None ) or page_length != "unlimited" :
132
+ # todo(mm, 2024-12-06): Support this when LabwareOffsetStore supports it.
133
+ raise NotImplementedError (
134
+ "Pagination not currently supported on this endpoint."
135
+ )
136
+
137
+ result_data = store .search (
138
+ id_filter = id ,
139
+ definition_uri_filter = definition_uri ,
140
+ location_slot_name_filter = location_slot_name ,
141
+ location_definition_uri_filter = location_definition_uri ,
142
+ location_module_model_filter = location_module_model ,
143
+ )
144
+
145
+ meta = MultiBodyMeta .construct (
146
+ # todo(mm, 2024-12-06): Update this when pagination is supported.
147
+ cursor = 0 ,
148
+ totalLength = len (result_data ),
149
+ )
150
+
151
+ return await PydanticResponse .create (
152
+ SimpleMultiBody [LabwareOffset ].construct (
153
+ data = result_data ,
154
+ meta = meta ,
155
+ )
156
+ )
108
157
109
158
110
159
@PydanticResponse .wrap_route (
@@ -113,19 +162,28 @@ def get_labware_offsets( # noqa: D103
113
162
summary = "Delete a single labware offset" ,
114
163
description = "Delete a single labware offset. The deleted offset is returned." ,
115
164
)
116
- def delete_labware_offset ( # noqa: D103
165
+ async def delete_labware_offset ( # noqa: D103
166
+ store : Annotated [LabwareOffsetStore , fastapi .Depends (get_labware_offset_store )],
117
167
id : Annotated [
118
168
str ,
119
169
fastapi .Path (description = "The `id` field of the offset to delete." ),
120
170
],
121
171
) -> PydanticResponse [SimpleBody [LabwareOffset ]]:
122
- raise NotImplementedError ()
172
+ try :
173
+ deleted_offset = store .delete (offset_id = id )
174
+ except LabwareOffsetNotFoundError as e :
175
+ raise LabwareOffsetNotFound .build (bad_offset_id = e .bad_offset_id ).as_error (404 )
176
+ else :
177
+ return await PydanticResponse .create (SimpleBody .construct (data = deleted_offset ))
123
178
124
179
125
180
@PydanticResponse .wrap_route (
126
181
router .delete ,
127
182
path = "" ,
128
183
summary = "Delete all labware offsets" ,
129
184
)
130
- def delete_all_labware_offsets () -> PydanticResponse [SimpleEmptyBody ]: # noqa: D103
131
- raise NotImplementedError ()
185
+ async def delete_all_labware_offsets ( # noqa: D103
186
+ store : Annotated [LabwareOffsetStore , fastapi .Depends (get_labware_offset_store )]
187
+ ) -> PydanticResponse [SimpleEmptyBody ]:
188
+ store .delete_all ()
189
+ return await PydanticResponse .create (SimpleEmptyBody .construct ())
0 commit comments