Skip to content

Commit ef633e7

Browse files
author
8ashar
authored
[RSDK-3634] Implement data.proto APIs that Add/Remove Tags (#334)
1 parent fb56da4 commit ef633e7

File tree

2 files changed

+114
-26
lines changed

2 files changed

+114
-26
lines changed

src/viam/app/client.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
from grpclib.client import Channel
1+
from typing import Mapping
22
from typing_extensions import Self
33

4+
from grpclib.client import Channel
5+
46
from viam import logging
57
from viam.app.data.client import DataClient
68
from viam.rpc.dial import DialOptions, _dial_app, _get_access_token
@@ -9,11 +11,13 @@
911

1012

1113
class AppClient:
12-
"""gRPC client for all communication and interaction with app.
14+
"""
15+
gRPC client for all communication and interaction with app.
1316
1417
Use create() to instantiate an AppClient::
1518
1619
AppClient.create(...)
20+
1721
"""
1822

1923
@classmethod
@@ -34,12 +38,17 @@ async def create(cls, dial_options: DialOptions) -> Self:
3438
return self
3539

3640
_channel: Channel
37-
_metadata: str
41+
_metadata: Mapping[str, str]
3842
_closed: bool = False
3943

4044
@property
4145
def data_client(self) -> DataClient:
4246
return DataClient(self._channel, self._metadata)
4347

44-
async def close(self):
45-
raise NotImplementedError()
48+
def close(self):
49+
if self._closed:
50+
LOGGER.debug("AppClient is already closed")
51+
return
52+
LOGGER.debug("Closing gRPC channel to app")
53+
self._channel.close()
54+
self._closed = True

src/viam/app/data/client.py

Lines changed: 100 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44

55
from viam import logging
66
from viam.proto.app.data import (
7+
AddTagsToBinaryDataByIDsRequest,
8+
AddTagsToBinaryDataByIDsResponse,
9+
AddTagsToBinaryDataByFilterRequest,
10+
AddTagsToBinaryDataByFilterResponse,
11+
RemoveTagsFromBinaryDataByIDsRequest,
12+
RemoveTagsFromBinaryDataByIDsResponse,
13+
RemoveTagsFromBinaryDataByFilterRequest,
14+
RemoveTagsFromBinaryDataByFilterResponse,
15+
TagsByFilterRequest,
16+
TagsByFilterResponse,
17+
BoundingBoxLabelsByFilterRequest,
18+
BoundingBoxLabelsByFilterResponse,
719
BinaryDataByFilterRequest,
820
BinaryDataByFilterResponse,
921
BinaryDataByIDsRequest,
@@ -29,10 +41,10 @@
2941
class DataClient:
3042
"""gRPC client for uploading and retreiving data from app
3143
32-
Constructor is used by AppClient to instantiate relevant service stubs. Calls to DataClient methods should be made through AppClient.
44+
Constructor is used by AppClient to instantiate relevant service stubs. Calls to DataClient methods should be made through AppClient
3345
"""
3446

35-
def __init__(self, channel: Channel, metadata: str):
47+
def __init__(self, channel: Channel, metadata: Mapping[str, str]):
3648
"""
3749
Create a data client that establishes a connection to app.
3850
@@ -46,7 +58,7 @@ def __init__(self, channel: Channel, metadata: str):
4658

4759
_data_client: DataServiceStub
4860
_data_sync_client: DataSyncServiceStub
49-
_metadata: str
61+
_metadata: Mapping[str, str]
5062

5163
async def tabular_data_by_filter(
5264
self,
@@ -186,36 +198,103 @@ async def delete_binary_data_by_ids(self, binary_ids: List[BinaryID]) -> None:
186198
request = DeleteBinaryDataByIDsRequest(binary_ids=binary_ids)
187199
_: DeleteBinaryDataByIDsResponse = await self._data_client.DeleteBinaryDataByIDs(request, metadata=self._metadata)
188200

189-
async def add_tags_to_binary_data_by_binary_ids(self, binary_ids: Optional[List[str]], tags: Optional[List[str]]) -> None:
190-
raise NotImplementedError()
201+
async def add_tags_to_binary_data_by_ids(self, tags: List[str], binary_ids: List[BinaryID]) -> None:
202+
"""Add tags to binary data using BinaryIDs
191203
192-
async def add_tags_to_binary_data_by_filter(self, filter: Optional[Filter], tags: Optional[List[str]]) -> None:
193-
raise NotImplementedError()
204+
Args:
205+
tags (List[str]): List of tags to add to specified binary data. Must be non-empty
206+
binary_ids (List[viam.app.proto.BinaryID]): List of BinaryIDs specifying binary data to tag. Must be non-empty
194207
195-
async def remove_tags_from_binary_data_by_binary_ids(self, binary_ids: Optional[List[str]], tags: Optional[List[str]]) -> None:
196-
raise NotImplementedError()
208+
Raises:
209+
GRPCError: if no binary_ids or tags are provided
210+
"""
211+
request = AddTagsToBinaryDataByIDsRequest(binary_ids=binary_ids, tags=tags)
212+
_: AddTagsToBinaryDataByIDsResponse = await self._data_client.AddTagsToBinaryDataByIDs(request, metadata=self._metadata)
197213

198-
async def remove_tags_from_binary_data_by_filter(self, filter: Optional[Filter], tags: Optional[List[str]]) -> None:
199-
raise NotImplementedError()
214+
async def add_tags_to_binary_data_by_filter(self, tags: List[str], filter: Optional[Filter] = None) -> None:
215+
"""Add tags to binary data using a filter
200216
201-
async def tags_by_filter(self, filter: Optional[Filter]) -> List[str]:
202-
raise NotImplementedError()
217+
Args:
218+
tags (List[str]): List of tags to add to specified binary data. Must be non-empty
219+
filter (viam.app.proto.Filter): Filter specifying binary data to tag. If no filter is provided, all data will be tagged
220+
221+
Raises:
222+
GRPCError: if no tags are provided
223+
"""
224+
filter = filter if filter else Filter()
225+
request = AddTagsToBinaryDataByFilterRequest(filter=filter, tags=tags)
226+
_: AddTagsToBinaryDataByFilterResponse = await self._data_client.AddTagsToBinaryDataByFilter(request, metadata=self._metadata)
227+
228+
async def remove_tags_from_binary_data_by_ids(self, tags: List[str], binary_ids: List[BinaryID]) -> None:
229+
"""Remove tags from binary data using BinaryIDs
230+
231+
Args:
232+
tags (List[str]): List of tags to remove from specified binary data. Must be non-empty
233+
file_ids (List[str]): List of BinaryIDs specifying binary data to untag. Must be non-empty
234+
235+
Raises:
236+
GRPCError: if no binary_ids or tags are provided
237+
"""
238+
request = RemoveTagsFromBinaryDataByIDsRequest(binary_ids=binary_ids, tags=tags)
239+
_: RemoveTagsFromBinaryDataByIDsResponse = await self._data_client.RemoveTagsFromBinaryDataByIDs(request, metadata=self._metadata)
240+
241+
async def remove_tags_from_binary_data_by_filter(self, tags: List[str], filter: Optional[Filter] = None) -> None:
242+
"""Remove tags from binary data using a filter
203243
204-
# to be defined and implemented last
244+
Args:
245+
tags (List[str]): List of tags to remove from specified binary data
246+
filter (viam.app.proto.Filter): Filter specifying binary data to untag. If no filter is provided, all data will be tagged
247+
248+
Raises:
249+
GRPCError: if no tags are provided
250+
"""
251+
filter = filter if filter else Filter()
252+
request = RemoveTagsFromBinaryDataByFilterRequest(filter=filter, tags=tags)
253+
_: RemoveTagsFromBinaryDataByFilterResponse = await self._data_client.RemoveTagsFromBinaryDataByFilter(
254+
request,
255+
metadata=self._metadata
256+
)
257+
258+
async def tags_by_filter(self, filter: Optional[Filter] = None) -> List[str]:
259+
"""Get a list of tags using a filter
260+
261+
Args:
262+
filter (viam.app.proto.Filter): Filter specifying data to retreive from. If no filter is provided, all data tags will return
263+
264+
Returns:
265+
List[str]: The list of tags
266+
"""
267+
filter = filter if filter else Filter()
268+
request = TagsByFilterRequest(filter=filter)
269+
response: TagsByFilterResponse = await self._data_client.TagsByFilter(request, metadata=self._metadata)
270+
return response.tags
271+
272+
# later
205273
async def add_bounding_box_to_image_by_id(self):
206274
raise NotImplementedError()
207275

208-
# to be defined and implemented last
276+
# later
209277
async def remove_bounding_box_from_image_by_id(self):
210278
raise NotImplementedError()
211279

212-
async def bounding_box_labels_by_filter(self, filter: Optional[Filter]) -> List[str]:
213-
raise NotImplementedError()
280+
async def bounding_box_labels_by_filter(self, filter: Optional[Filter] = None) -> List[str]:
281+
"""Get a list of bounding box labels using a filter
282+
283+
Args:
284+
filter (viam.app.proto.Filter): Filter specifying data to retreive from. If no filter is provided, all labels will return
285+
286+
Returns:
287+
List[str]: The list of bounding box labels
288+
"""
289+
filter = filter if filter else Filter()
290+
request = BoundingBoxLabelsByFilterRequest(filter=filter)
291+
response: BoundingBoxLabelsByFilterResponse = await self._data_client.BoundingBoxLabelsByFilter(request, metadata=self._metadata)
292+
return response.labels
214293

215-
# TODO (RSDK-3637): confirm arguments
216-
async def data_capture_upload(self, metadata: Optional[UploadMetadata], sensor_contents: Optional[List[SensorData]]) -> None:
294+
# TODO(RSDK-3637): Implement
295+
async def data_capture_upload(self, metadata: UploadMetadata , sensor_contents: Optional[List[SensorData]] = None) -> None:
217296
raise NotImplementedError()
218297

219-
# TODO (RSDK-3637): confirm arguments
220-
async def file_upload(self, metadata: Optional[UploadMetadata], file_contents: Optional[FileData]) -> None:
298+
# TODO(RSDK-3637): Implement
299+
async def file_upload(self, metadata: UploadMetadata, file_contents: Optional[FileData]) -> None:
221300
raise NotImplementedError()

0 commit comments

Comments
 (0)