Skip to content

Commit 045fdce

Browse files
committed
added bulk creation of links
1 parent d773da2 commit 045fdce

4 files changed

Lines changed: 124 additions & 5 deletions

File tree

ayon_api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
delete_link_type,
276276
make_sure_link_type_exists,
277277
create_link,
278+
create_links,
278279
delete_link,
279280
get_entities_links,
280281
get_folders_links,
@@ -594,6 +595,7 @@
594595
"delete_link_type",
595596
"make_sure_link_type_exists",
596597
"create_link",
598+
"create_links",
597599
"delete_link",
598600
"get_entities_links",
599601
"get_folders_links",

ayon_api/_api.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
BackgroundOperationTask,
5454
LinkDirection,
5555
CreateLinkData,
56+
CreateLinkResponseData,
5657
EventFilter,
5758
EventStatus,
5859
EnrollEventData,
@@ -7504,7 +7505,7 @@ def create_link(
75047505
output_type: str,
75057506
link_name: Optional[str] = None,
75067507
data: Optional[dict[str, Any]] = None,
7507-
) -> CreateLinkData:
7508+
) -> CreateLinkResponseData:
75087509
"""Create link between 2 entities.
75097510
75107511
Link has a type which must already exists on a project.
@@ -7527,7 +7528,7 @@ def create_link(
75277528
with the link.
75287529
75297530
Returns:
7530-
CreateLinkData: Information about link.
7531+
CreateLinkResponseData: Information about link.
75317532
75327533
Raises:
75337534
HTTPRequestError: Server error happened.
@@ -7546,6 +7547,38 @@ def create_link(
75467547
)
75477548

75487549

7550+
def create_links(
7551+
project_name: str,
7552+
links: list[dict[str, Any]],
7553+
) -> None:
7554+
"""Create multiple links in a single request.
7555+
7556+
Example of link data::
7557+
[
7558+
{
7559+
"input": "59a212c0d2e211eda0e20242ac120001",
7560+
"output": "59a212c0d2e211eda0e20242ac120002",
7561+
"linkType": "reference|folder|folder",
7562+
"name": "my_link",
7563+
"data": {"key": "value"}
7564+
}
7565+
]
7566+
7567+
Args:
7568+
project_name (str): Project where links are created.
7569+
links (list[dict[str, Any]]): List of link data.
7570+
7571+
Raises:
7572+
ValueError: Link data is invalid.
7573+
7574+
"""
7575+
con = get_server_api_connection()
7576+
return con.create_links(
7577+
project_name=project_name,
7578+
links=links,
7579+
)
7580+
7581+
75497582
def delete_link(
75507583
project_name: str,
75517584
link_id: str,

ayon_api/_api_helpers/links.py

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def create_link(
200200
output_type: str,
201201
link_name: Optional[str] = None,
202202
data: Optional[dict[str, Any]] = None,
203-
) -> CreateLinkData:
203+
) -> CreateLinkResponseData:
204204
"""Create link between 2 entities.
205205
206206
Link has a type which must already exists on a project.
@@ -223,7 +223,7 @@ def create_link(
223223
with the link.
224224
225225
Returns:
226-
CreateLinkData: Information about link.
226+
CreateLinkResponseData: Information about link.
227227
228228
Raises:
229229
HTTPRequestError: Server error happened.
@@ -249,6 +249,59 @@ def create_link(
249249
response.raise_for_status()
250250
return response.data
251251

252+
def create_links(
253+
self,
254+
project_name: str,
255+
links: list[dict[str, Any]],
256+
) -> None:
257+
"""Create multiple links in a single request.
258+
259+
Example of link data::
260+
[
261+
{
262+
"input": "59a212c0d2e211eda0e20242ac120001",
263+
"output": "59a212c0d2e211eda0e20242ac120002",
264+
"linkType": "reference|folder|folder",
265+
"name": "my_link",
266+
"data": {"key": "value"}
267+
}
268+
]
269+
270+
Args:
271+
project_name (str): Project where links are created.
272+
links (list[dict[str, Any]]): List of link data.
273+
274+
Raises:
275+
ValueError: Link data is invalid.
276+
277+
"""
278+
if not links:
279+
return
280+
281+
for link in links:
282+
self._validate_link_data(link)
283+
284+
if self.get_server_version_tuple() < (1, 15, 8):
285+
for link in links:
286+
link_type, in_type, out_type = link["linkType"].split("|")
287+
self.create_link(
288+
project_name,
289+
link_type,
290+
link["input"],
291+
in_type,
292+
link["output"],
293+
out_type,
294+
link_name=link.get("name") or None,
295+
data=link.get("data") or None,
296+
)
297+
return
298+
299+
response = self.post(
300+
f"projects/{project_name}/links/bulk",
301+
links=links
302+
)
303+
response.raise_for_status()
304+
252305
def delete_link(self, project_name: str, link_id: str) -> None:
253306
"""Remove link by id.
254307
@@ -619,6 +672,29 @@ def get_representation_links(
619672
project_name, [representation_id], link_types, link_direction
620673
)[representation_id]
621674

675+
def _validate_link_data(self, link_data: dict[str, Any]) -> None:
676+
"""Validate link data before sending to server.
677+
678+
Args:
679+
link_data (dict[str, Any]): Link data to validate.
680+
681+
Raises:
682+
ValueError: Link data is invalid.
683+
684+
"""
685+
required_keys = {"input", "output", "linkType"}
686+
missing_keys = required_keys - link_data.keys()
687+
if missing_keys:
688+
mk = ", ".join((f"'{key}'" for key in missing_keys))
689+
raise ValueError(f"Missing required keys in link data {mk}")
690+
691+
link_type_parts = link_data["linkType"].split("|")
692+
if len(link_type_parts) != 3:
693+
raise ValueError(
694+
f"Invalid linkType format: {link_data['linkType']}. "
695+
"Expected format: 'link_type|input_type|output_type'"
696+
)
697+
622698
def _prepare_link_filters(
623699
self,
624700
filters: dict[str, Any],

ayon_api/typing.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,18 @@ class BackgroundOperationTask(TypedDict):
127127
LinkDirection = Literal["in", "out"]
128128

129129

130-
class CreateLinkData(TypedDict):
130+
class CreateLinkResponseData(TypedDict):
131131
id: str
132132

133133

134+
class CreateLinkData(TypedDict):
135+
input: str
136+
output: str
137+
linkType: str
138+
data: dict[str, Any] | None = None
139+
name: str | None = None
140+
141+
134142
class AttributeEnumItemDict(TypedDict):
135143
value: str | int | float | bool
136144
label: str

0 commit comments

Comments
 (0)