@@ -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 ],
0 commit comments