Skip to content

Commit f1082da

Browse files
authored
Add ability to create an item with a certain group, and group lookup (#91)
1 parent df8611b commit f1082da

3 files changed

Lines changed: 116 additions & 7 deletions

File tree

src/datalab_api/__init__.py

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ def create_item(
127127
item_type: str = "samples",
128128
item_data: dict[str, Any] | None = None,
129129
collection_id: str | None = None,
130+
collection_ids: str | Iterable[str] | None = None, # alias for collection_id
131+
group_ids: str | Iterable[str] | None = None,
130132
) -> dict[str, Any]:
131133
"""Create an item with a given ID and item data.
132134
@@ -135,7 +137,9 @@ def create_item(
135137
item_type: The type of item to create, e.g., 'samples', 'cells'.
136138
item_data: The data for the item.
137139
collection_id: The ID of the collection to add the item to (optional).
138-
If such a collection does not exist, one will be made.
140+
If such a collection does not exist, one will be made. Deprecated in favor of `collection_ids`.
141+
collection_ids: The ID or IDs of the collection(s) to add the item to (optional).
142+
group_ids: The ID or IDs of the group(s) to share the item with (optional).
139143
140144
"""
141145
new_item = {}
@@ -147,13 +151,34 @@ def create_item(
147151
new_item.pop("item_id")
148152

149153
if collection_id is not None:
150-
try:
151-
collection_immutable_id = self.get_collection(collection_id)[0]["immutable_id"]
152-
except (RuntimeError, DatalabAPIError):
153-
self.create_collection(collection_id)
154-
collection_immutable_id = self.get_collection(collection_id)[0]["immutable_id"]
154+
warnings.warn(
155+
DeprecationWarning(
156+
"`collection_id` is deprecated, please use `collection_ids` instead."
157+
)
158+
)
159+
if collection_ids is None:
160+
collection_ids = [collection_id]
161+
162+
if collection_ids:
155163
new_item["collections"] = new_item.get("collections", [])
156-
new_item["collections"].append({"immutable_id": collection_immutable_id})
164+
for collection_id in collection_ids:
165+
try:
166+
collection_immutable_id = self.get_collection(collection_id)[0]["immutable_id"]
167+
except (RuntimeError, DatalabAPIError):
168+
self.create_collection(collection_id)
169+
collection_immutable_id = self.get_collection(collection_id)[0]["immutable_id"]
170+
new_item["collections"].append({"immutable_id": collection_immutable_id})
171+
172+
if group_ids:
173+
# For now, we have to use the search groups endpoint
174+
# until we add a get group by id endpoint that is locked down per user
175+
new_item["groups"] = new_item.get("groups", [])
176+
for group_id in group_ids:
177+
try:
178+
group_immutable_id = self.get_group(group_id)["immutable_id"]
179+
new_item["groups"].append({"immutable_id": group_immutable_id})
180+
except (RuntimeError, DatalabAPIError):
181+
pass
157182

158183
create_item_url = f"{self.datalab_api_url}/new-sample/"
159184
created_item = self._post(
@@ -435,6 +460,32 @@ def get_collection(self, collection_id: str) -> tuple[dict[str, Any], list[dict[
435460
collection = self._get(collection_url)
436461
return collection["data"], collection["child_items"]
437462

463+
def get_group(self, group_id: str) -> dict[str, Any]:
464+
"""Get a group with a given ID.
465+
466+
Uses the search groups endpoint under the hood,
467+
so will only find groups that the user has access
468+
to and that match the query.
469+
470+
Parameters:
471+
group_id: The human-readable ID of the group to search for.
472+
473+
Returns:
474+
A dictionary of group data for the group with the given ID.
475+
476+
Raises:
477+
DatalabAPIError: If no group with the given ID is found.
478+
479+
"""
480+
group_url = f"{self.datalab_api_url}/search/groups?query={group_id}"
481+
group_resp = self._get(group_url)
482+
matching_groups = group_resp["data"]
483+
if matching_groups:
484+
matching_groups = [g for g in matching_groups if g.get("group_id") == group_id]
485+
return matching_groups[0]
486+
487+
raise DatalabAPIError(f"No group found with ID {group_id!r}")
488+
438489
def create_collection(
439490
self, collection_id: str, collection_data: dict | None = None
440491
) -> dict[str, Any]:

tests/conftest.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,51 @@ def mocked_api(
6565
500, json={"message": "('type',)", "title": "KeyError"}
6666
)
6767

68+
fake_group_search_api = respx_mock.get(
69+
"/search/groups?query=test_group", name="search-groups"
70+
)
71+
fake_group_search_api.return_value = Response(
72+
200,
73+
json={
74+
"data": [
75+
{
76+
"description": "test",
77+
"display_name": "Test",
78+
"group_id": "test2",
79+
"immutable_id": "6949ca813a5a8985defeb403",
80+
"last_modified": None,
81+
"managers": [],
82+
"members": None,
83+
"relationships": None,
84+
"type": "groups",
85+
},
86+
{
87+
"description": "test",
88+
"display_name": "testtest",
89+
"group_id": "test-test",
90+
"immutable_id": "696011270060765fbbeb868b",
91+
"last_modified": None,
92+
"managers": [],
93+
"members": None,
94+
"relationships": None,
95+
"type": "groups",
96+
},
97+
{
98+
"description": "Add longer description",
99+
"display_name": "Test group",
100+
"group_id": "test_group",
101+
"immutable_id": "67d0b01e03000cdc75134dbd",
102+
"last_modified": None,
103+
"managers": [],
104+
"members": None,
105+
"relationships": None,
106+
"type": "groups",
107+
},
108+
],
109+
"status": "success",
110+
},
111+
)
112+
68113
yield respx_mock
69114

70115

tests/test_client.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,16 @@ def test_collection_get(fake_api_url, mocked_api):
5858

5959
collection, children = client.get_collection("test_collection", display=True)
6060
assert mocked_api["collection-test_collection"].called
61+
62+
63+
@respx.mock
64+
def test_group_get(fake_api_url, mocked_api):
65+
with DatalabClient("https://api.datalab.industries") as client:
66+
assert mocked_api["api"].called
67+
assert mocked_api["info"].called
68+
assert mocked_api["info-blocks"].called
69+
70+
group = client.get_group("test_group", display=True)
71+
assert mocked_api["search-groups"].called
72+
assert group["immutable_id"] == "67d0b01e03000cdc75134dbd"
73+
assert group["group_id"] == "test_group"

0 commit comments

Comments
 (0)