1111from ..exceptions import SABaseException
1212from .images import (
1313 delete_image , get_image_annotations , get_image_bytes , get_image_metadata ,
14- set_image_annotation_status , upload_annotations_from_json_to_image
14+ search_images , set_image_annotation_status ,
15+ upload_annotations_from_json_to_image
1516)
1617from .projects import (
1718 __create_image , _get_project_image_quality_in_editor ,
@@ -126,7 +127,8 @@ def copy_image(
126127 image_name ,
127128 destination_project ,
128129 include_annotations = False ,
129- copy_annotation_status = False
130+ copy_annotation_status = False ,
131+ copy_pin = False
130132):
131133 """Copy image to a project. The image's project is the same as destination
132134 project then the name will be changed to <image_name>_(<num>).<image_ext>,
@@ -142,6 +144,8 @@ def copy_image(
142144 :type include_annotations: bool
143145 :param copy_annotation_status: enables annotations status copy
144146 :type copy_annotation_status: bool
147+ :param copy_pin: enables image pin status copy
148+ :type copy_pin: bool
145149 """
146150 if not isinstance (source_project , dict ):
147151 source_project = get_project_metadata (source_project )
@@ -190,6 +194,8 @@ def copy_image(
190194 destination_project , new_name ,
191195 annotation_status_int_to_str (img_metadata ["annotation_status" ])
192196 )
197+ if copy_pin :
198+ pin_image (destination_project , new_name , img_metadata ["is_pinned" ])
193199
194200 logger .info (
195201 "Copied image %s/%s to %s/%s." , source_project ["name" ], image_name ,
@@ -201,8 +207,9 @@ def move_image(
201207 source_project ,
202208 image_name ,
203209 destination_project ,
204- include_annotations = False ,
205- copy_annotation_status = False
210+ include_annotations = True ,
211+ copy_annotation_status = True ,
212+ copy_pin = True
206213):
207214 """Move image from source_project to destination_project. source_project
208215 and destination_project cannot be the same.
@@ -217,6 +224,8 @@ def move_image(
217224 :type include_annotations: bool
218225 :param copy_annotation_status: enables annotations status copy
219226 :type copy_annotation_status: bool
227+ :param copy_pin: enables image pin status copy
228+ :type copy_pin: bool
220229 """
221230 if not isinstance (source_project , dict ):
222231 source_project = get_project_metadata (source_project )
@@ -228,7 +237,86 @@ def move_image(
228237 )
229238 copy_image (
230239 source_project , image_name , destination_project , include_annotations ,
231- copy_annotation_status
240+ copy_annotation_status , copy_pin
232241 )
233242 delete_image (source_project , image_name )
234243 logger .info ("Deleted image %s/%s." , source_project ["name" ], image_name )
244+
245+
246+ def pin_image (project , image_name , pin = True ):
247+ """Pins (or unpins) image
248+
249+ :param project: project name or metadata of the project
250+ :type project: str or dict
251+ :param image_name: image name
252+ :type image: str
253+ :param pin: sets to pin if True, else unpins image
254+ :type pin: bool
255+ """
256+ if not isinstance (project , dict ):
257+ project = get_project_metadata (project )
258+ img_metadata = get_image_metadata (project , image_name )
259+ team_id , project_id , image_id = project ["team_id" ], project [
260+ "id" ], img_metadata ["id" ]
261+ params = {"team_id" : team_id , "project_id" : project_id }
262+ json_req = {"is_pinned" : int (pin )}
263+ response = _api .send_request (
264+ req_type = 'PUT' ,
265+ path = f'/image/{ image_id } ' ,
266+ params = params ,
267+ json_req = json_req
268+ )
269+ if not response .ok :
270+ raise SABaseException (
271+ response .status_code , "Couldn't pin image " + response .text
272+ )
273+
274+
275+ def assign_images (project , image_names , user ):
276+ """Assigns images to a user. The assignment role, QA or Annotator, will
277+ be deduced from the user's role in the project. With SDK, the user can be
278+ assigned to a role in the project with the share_project function.
279+
280+ :param project: project name or metadata of the project
281+ :type project: str or dict
282+ :param image_names: list of image names to assign
283+ :type image_names: list of str
284+ :param user: user email
285+ :type user: str
286+ """
287+ logger .info ("Assign %s images to user %s" , len (image_names ), user )
288+ if len (image_names ) == 0 :
289+ return
290+ if not isinstance (project , dict ):
291+ project = get_project_metadata (project )
292+ folder_id = None
293+ images = search_images (project , return_metadata = True )
294+ image_dict = {}
295+ for image in images :
296+ image_dict [image ["name" ]] = image ["id" ]
297+ if folder_id is None :
298+ folder_id = image ["folder_id" ]
299+ elif folder_id != image ["folder_id" ]:
300+ raise SABaseException (0 , "Folders not implemented yet" )
301+
302+ image_ids = []
303+ for image_name in image_names :
304+ image_ids .append (image_dict [image_name ])
305+ team_id , project_id = project ["team_id" ], project ["id" ]
306+ params = {
307+ "team_id" : team_id ,
308+ "project_id" : project_id ,
309+ "folder_id" : folder_id
310+ }
311+ json_req = {"user_id" : user , "image_ids" : image_ids }
312+ response = _api .send_request (
313+ req_type = 'POST' ,
314+ path = '/images/assign' ,
315+ params = params ,
316+ json_req = json_req
317+ )
318+ if not response .ok :
319+ raise SABaseException (
320+ response .status_code , "Couldn't assign images " + response .text
321+ )
322+ # print(response.json())
0 commit comments