dtlpy 1.114.17__py3-none-any.whl → 1.116.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dtlpy/__init__.py +491 -491
- dtlpy/__version__.py +1 -1
- dtlpy/assets/__init__.py +26 -26
- dtlpy/assets/code_server/config.yaml +2 -2
- dtlpy/assets/code_server/installation.sh +24 -24
- dtlpy/assets/code_server/launch.json +13 -13
- dtlpy/assets/code_server/settings.json +2 -2
- dtlpy/assets/main.py +53 -53
- dtlpy/assets/main_partial.py +18 -18
- dtlpy/assets/mock.json +11 -11
- dtlpy/assets/model_adapter.py +83 -83
- dtlpy/assets/package.json +61 -61
- dtlpy/assets/package_catalog.json +29 -29
- dtlpy/assets/package_gitignore +307 -307
- dtlpy/assets/service_runners/__init__.py +33 -33
- dtlpy/assets/service_runners/converter.py +96 -96
- dtlpy/assets/service_runners/multi_method.py +49 -49
- dtlpy/assets/service_runners/multi_method_annotation.py +54 -54
- dtlpy/assets/service_runners/multi_method_dataset.py +55 -55
- dtlpy/assets/service_runners/multi_method_item.py +52 -52
- dtlpy/assets/service_runners/multi_method_json.py +52 -52
- dtlpy/assets/service_runners/single_method.py +37 -37
- dtlpy/assets/service_runners/single_method_annotation.py +43 -43
- dtlpy/assets/service_runners/single_method_dataset.py +43 -43
- dtlpy/assets/service_runners/single_method_item.py +41 -41
- dtlpy/assets/service_runners/single_method_json.py +42 -42
- dtlpy/assets/service_runners/single_method_multi_input.py +45 -45
- dtlpy/assets/voc_annotation_template.xml +23 -23
- dtlpy/caches/base_cache.py +32 -32
- dtlpy/caches/cache.py +473 -473
- dtlpy/caches/dl_cache.py +201 -201
- dtlpy/caches/filesystem_cache.py +89 -89
- dtlpy/caches/redis_cache.py +84 -84
- dtlpy/dlp/__init__.py +20 -20
- dtlpy/dlp/cli_utilities.py +367 -367
- dtlpy/dlp/command_executor.py +764 -764
- dtlpy/dlp/dlp +1 -1
- dtlpy/dlp/dlp.bat +1 -1
- dtlpy/dlp/dlp.py +128 -128
- dtlpy/dlp/parser.py +651 -651
- dtlpy/entities/__init__.py +83 -83
- dtlpy/entities/analytic.py +347 -311
- dtlpy/entities/annotation.py +1879 -1879
- dtlpy/entities/annotation_collection.py +699 -699
- dtlpy/entities/annotation_definitions/__init__.py +20 -20
- dtlpy/entities/annotation_definitions/base_annotation_definition.py +100 -100
- dtlpy/entities/annotation_definitions/box.py +195 -195
- dtlpy/entities/annotation_definitions/classification.py +67 -67
- dtlpy/entities/annotation_definitions/comparison.py +72 -72
- dtlpy/entities/annotation_definitions/cube.py +204 -204
- dtlpy/entities/annotation_definitions/cube_3d.py +149 -149
- dtlpy/entities/annotation_definitions/description.py +32 -32
- dtlpy/entities/annotation_definitions/ellipse.py +124 -124
- dtlpy/entities/annotation_definitions/free_text.py +62 -62
- dtlpy/entities/annotation_definitions/gis.py +69 -69
- dtlpy/entities/annotation_definitions/note.py +139 -139
- dtlpy/entities/annotation_definitions/point.py +117 -117
- dtlpy/entities/annotation_definitions/polygon.py +182 -182
- dtlpy/entities/annotation_definitions/polyline.py +111 -111
- dtlpy/entities/annotation_definitions/pose.py +92 -92
- dtlpy/entities/annotation_definitions/ref_image.py +86 -86
- dtlpy/entities/annotation_definitions/segmentation.py +240 -240
- dtlpy/entities/annotation_definitions/subtitle.py +34 -34
- dtlpy/entities/annotation_definitions/text.py +85 -85
- dtlpy/entities/annotation_definitions/undefined_annotation.py +74 -74
- dtlpy/entities/app.py +220 -220
- dtlpy/entities/app_module.py +107 -107
- dtlpy/entities/artifact.py +174 -174
- dtlpy/entities/assignment.py +399 -399
- dtlpy/entities/base_entity.py +214 -214
- dtlpy/entities/bot.py +113 -113
- dtlpy/entities/codebase.py +292 -296
- dtlpy/entities/collection.py +38 -38
- dtlpy/entities/command.py +169 -169
- dtlpy/entities/compute.py +449 -442
- dtlpy/entities/dataset.py +1299 -1285
- dtlpy/entities/directory_tree.py +44 -44
- dtlpy/entities/dpk.py +470 -470
- dtlpy/entities/driver.py +235 -223
- dtlpy/entities/execution.py +397 -397
- dtlpy/entities/feature.py +124 -124
- dtlpy/entities/feature_set.py +145 -145
- dtlpy/entities/filters.py +798 -645
- dtlpy/entities/gis_item.py +107 -107
- dtlpy/entities/integration.py +184 -184
- dtlpy/entities/item.py +959 -953
- dtlpy/entities/label.py +123 -123
- dtlpy/entities/links.py +85 -85
- dtlpy/entities/message.py +175 -175
- dtlpy/entities/model.py +684 -684
- dtlpy/entities/node.py +1005 -1005
- dtlpy/entities/ontology.py +810 -803
- dtlpy/entities/organization.py +287 -287
- dtlpy/entities/package.py +657 -657
- dtlpy/entities/package_defaults.py +5 -5
- dtlpy/entities/package_function.py +185 -185
- dtlpy/entities/package_module.py +113 -113
- dtlpy/entities/package_slot.py +118 -118
- dtlpy/entities/paged_entities.py +299 -299
- dtlpy/entities/pipeline.py +624 -624
- dtlpy/entities/pipeline_execution.py +279 -279
- dtlpy/entities/project.py +394 -394
- dtlpy/entities/prompt_item.py +505 -499
- dtlpy/entities/recipe.py +301 -301
- dtlpy/entities/reflect_dict.py +102 -102
- dtlpy/entities/resource_execution.py +138 -138
- dtlpy/entities/service.py +963 -958
- dtlpy/entities/service_driver.py +117 -117
- dtlpy/entities/setting.py +294 -294
- dtlpy/entities/task.py +495 -495
- dtlpy/entities/time_series.py +143 -143
- dtlpy/entities/trigger.py +426 -426
- dtlpy/entities/user.py +118 -118
- dtlpy/entities/webhook.py +124 -124
- dtlpy/examples/__init__.py +19 -19
- dtlpy/examples/add_labels.py +135 -135
- dtlpy/examples/add_metadata_to_item.py +21 -21
- dtlpy/examples/annotate_items_using_model.py +65 -65
- dtlpy/examples/annotate_video_using_model_and_tracker.py +75 -75
- dtlpy/examples/annotations_convert_to_voc.py +9 -9
- dtlpy/examples/annotations_convert_to_yolo.py +9 -9
- dtlpy/examples/convert_annotation_types.py +51 -51
- dtlpy/examples/converter.py +143 -143
- dtlpy/examples/copy_annotations.py +22 -22
- dtlpy/examples/copy_folder.py +31 -31
- dtlpy/examples/create_annotations.py +51 -51
- dtlpy/examples/create_video_annotations.py +83 -83
- dtlpy/examples/delete_annotations.py +26 -26
- dtlpy/examples/filters.py +113 -113
- dtlpy/examples/move_item.py +23 -23
- dtlpy/examples/play_video_annotation.py +13 -13
- dtlpy/examples/show_item_and_mask.py +53 -53
- dtlpy/examples/triggers.py +49 -49
- dtlpy/examples/upload_batch_of_items.py +20 -20
- dtlpy/examples/upload_items_and_custom_format_annotations.py +55 -55
- dtlpy/examples/upload_items_with_modalities.py +43 -43
- dtlpy/examples/upload_segmentation_annotations_from_mask_image.py +44 -44
- dtlpy/examples/upload_yolo_format_annotations.py +70 -70
- dtlpy/exceptions.py +125 -125
- dtlpy/miscellaneous/__init__.py +20 -20
- dtlpy/miscellaneous/dict_differ.py +95 -95
- dtlpy/miscellaneous/git_utils.py +217 -217
- dtlpy/miscellaneous/json_utils.py +14 -14
- dtlpy/miscellaneous/list_print.py +105 -105
- dtlpy/miscellaneous/zipping.py +130 -130
- dtlpy/ml/__init__.py +20 -20
- dtlpy/ml/base_feature_extractor_adapter.py +27 -27
- dtlpy/ml/base_model_adapter.py +1257 -1086
- dtlpy/ml/metrics.py +461 -461
- dtlpy/ml/predictions_utils.py +274 -274
- dtlpy/ml/summary_writer.py +57 -57
- dtlpy/ml/train_utils.py +60 -60
- dtlpy/new_instance.py +252 -252
- dtlpy/repositories/__init__.py +56 -56
- dtlpy/repositories/analytics.py +85 -85
- dtlpy/repositories/annotations.py +916 -916
- dtlpy/repositories/apps.py +383 -383
- dtlpy/repositories/artifacts.py +452 -452
- dtlpy/repositories/assignments.py +599 -599
- dtlpy/repositories/bots.py +213 -213
- dtlpy/repositories/codebases.py +559 -559
- dtlpy/repositories/collections.py +332 -332
- dtlpy/repositories/commands.py +152 -158
- dtlpy/repositories/compositions.py +61 -61
- dtlpy/repositories/computes.py +439 -435
- dtlpy/repositories/datasets.py +1504 -1291
- dtlpy/repositories/downloader.py +976 -903
- dtlpy/repositories/dpks.py +433 -433
- dtlpy/repositories/drivers.py +482 -470
- dtlpy/repositories/executions.py +815 -817
- dtlpy/repositories/feature_sets.py +226 -226
- dtlpy/repositories/features.py +255 -238
- dtlpy/repositories/integrations.py +484 -484
- dtlpy/repositories/items.py +912 -909
- dtlpy/repositories/messages.py +94 -94
- dtlpy/repositories/models.py +1000 -988
- dtlpy/repositories/nodes.py +80 -80
- dtlpy/repositories/ontologies.py +511 -511
- dtlpy/repositories/organizations.py +525 -525
- dtlpy/repositories/packages.py +1941 -1941
- dtlpy/repositories/pipeline_executions.py +451 -451
- dtlpy/repositories/pipelines.py +640 -640
- dtlpy/repositories/projects.py +539 -539
- dtlpy/repositories/recipes.py +419 -399
- dtlpy/repositories/resource_executions.py +137 -137
- dtlpy/repositories/schema.py +120 -120
- dtlpy/repositories/service_drivers.py +213 -213
- dtlpy/repositories/services.py +1704 -1704
- dtlpy/repositories/settings.py +339 -339
- dtlpy/repositories/tasks.py +1477 -1477
- dtlpy/repositories/times_series.py +278 -278
- dtlpy/repositories/triggers.py +536 -536
- dtlpy/repositories/upload_element.py +257 -257
- dtlpy/repositories/uploader.py +661 -651
- dtlpy/repositories/webhooks.py +249 -249
- dtlpy/services/__init__.py +22 -22
- dtlpy/services/aihttp_retry.py +131 -131
- dtlpy/services/api_client.py +1785 -1782
- dtlpy/services/api_reference.py +40 -40
- dtlpy/services/async_utils.py +133 -133
- dtlpy/services/calls_counter.py +44 -44
- dtlpy/services/check_sdk.py +68 -68
- dtlpy/services/cookie.py +115 -115
- dtlpy/services/create_logger.py +156 -156
- dtlpy/services/events.py +84 -84
- dtlpy/services/logins.py +235 -235
- dtlpy/services/reporter.py +256 -256
- dtlpy/services/service_defaults.py +91 -91
- dtlpy/utilities/__init__.py +20 -20
- dtlpy/utilities/annotations/__init__.py +16 -16
- dtlpy/utilities/annotations/annotation_converters.py +269 -269
- dtlpy/utilities/base_package_runner.py +285 -264
- dtlpy/utilities/converter.py +1650 -1650
- dtlpy/utilities/dataset_generators/__init__.py +1 -1
- dtlpy/utilities/dataset_generators/dataset_generator.py +670 -670
- dtlpy/utilities/dataset_generators/dataset_generator_tensorflow.py +23 -23
- dtlpy/utilities/dataset_generators/dataset_generator_torch.py +21 -21
- dtlpy/utilities/local_development/__init__.py +1 -1
- dtlpy/utilities/local_development/local_session.py +179 -179
- dtlpy/utilities/reports/__init__.py +2 -2
- dtlpy/utilities/reports/figures.py +343 -343
- dtlpy/utilities/reports/report.py +71 -71
- dtlpy/utilities/videos/__init__.py +17 -17
- dtlpy/utilities/videos/video_player.py +598 -598
- dtlpy/utilities/videos/videos.py +470 -470
- {dtlpy-1.114.17.data → dtlpy-1.116.6.data}/scripts/dlp +1 -1
- dtlpy-1.116.6.data/scripts/dlp.bat +2 -0
- {dtlpy-1.114.17.data → dtlpy-1.116.6.data}/scripts/dlp.py +128 -128
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/METADATA +186 -183
- dtlpy-1.116.6.dist-info/RECORD +239 -0
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/WHEEL +1 -1
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/licenses/LICENSE +200 -200
- tests/features/environment.py +551 -551
- dtlpy/assets/__pycache__/__init__.cpython-310.pyc +0 -0
- dtlpy-1.114.17.data/scripts/dlp.bat +0 -2
- dtlpy-1.114.17.dist-info/RECORD +0 -240
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.114.17.dist-info → dtlpy-1.116.6.dist-info}/top_level.txt +0 -0
|
@@ -1,599 +1,599 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
from .. import exceptions, miscellaneous, entities, repositories, _api_reference
|
|
4
|
-
from ..services.api_client import ApiClient
|
|
5
|
-
|
|
6
|
-
logger = logging.getLogger(name='dtlpy')
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Assignments:
|
|
10
|
-
"""
|
|
11
|
-
Assignments Repository
|
|
12
|
-
|
|
13
|
-
The Assignments class allows users to manage assignments and their properties.
|
|
14
|
-
Read more about `Task Assignment <https://developers.dataloop.ai/tutorials/task_workflows/create_a_task/chapter/>`_ in our Developers documentation.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
def __init__(self,
|
|
18
|
-
client_api: ApiClient,
|
|
19
|
-
project: entities.Project = None,
|
|
20
|
-
task: entities.Task = None,
|
|
21
|
-
dataset: entities.Dataset = None,
|
|
22
|
-
project_id=None):
|
|
23
|
-
self._client_api = client_api
|
|
24
|
-
self._project = project
|
|
25
|
-
self._dataset = dataset
|
|
26
|
-
self._task = task
|
|
27
|
-
|
|
28
|
-
self._project_id = project_id
|
|
29
|
-
if self._project_id is None and self._project is not None:
|
|
30
|
-
self._project_id = self._project.id
|
|
31
|
-
|
|
32
|
-
############
|
|
33
|
-
# entities #
|
|
34
|
-
############
|
|
35
|
-
@property
|
|
36
|
-
def task(self) -> entities.Task:
|
|
37
|
-
if self._task is None:
|
|
38
|
-
raise exceptions.PlatformException(
|
|
39
|
-
error='2001',
|
|
40
|
-
message='Missing "task". need to set an Task entity or use task.assignments repository')
|
|
41
|
-
assert isinstance(self._task, entities.Task)
|
|
42
|
-
return self._task
|
|
43
|
-
|
|
44
|
-
@task.setter
|
|
45
|
-
def task(self, task: entities.Task):
|
|
46
|
-
if not isinstance(task, entities.Task):
|
|
47
|
-
raise ValueError('Must input a valid Task entity')
|
|
48
|
-
self._task = task
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def project_id(self):
|
|
52
|
-
if self._project_id is not None:
|
|
53
|
-
return self._project_id
|
|
54
|
-
elif self._project is not None:
|
|
55
|
-
return self._project.id
|
|
56
|
-
else:
|
|
57
|
-
return None
|
|
58
|
-
|
|
59
|
-
@property
|
|
60
|
-
def project(self) -> entities.Project:
|
|
61
|
-
if self._project is None:
|
|
62
|
-
raise exceptions.PlatformException(
|
|
63
|
-
error='2001',
|
|
64
|
-
message='Missing "project". need to set a Project entity or use project.assignments repository')
|
|
65
|
-
assert isinstance(self._project, entities.Project)
|
|
66
|
-
return self._project
|
|
67
|
-
|
|
68
|
-
@project.setter
|
|
69
|
-
def project(self, project: entities.Project):
|
|
70
|
-
if not isinstance(project, entities.Project):
|
|
71
|
-
raise ValueError('Must input a valid Project entity')
|
|
72
|
-
self._project = project
|
|
73
|
-
|
|
74
|
-
###########
|
|
75
|
-
# methods #
|
|
76
|
-
###########
|
|
77
|
-
def list(self,
|
|
78
|
-
project_ids: list = None,
|
|
79
|
-
status: str = None,
|
|
80
|
-
assignment_name: str = None,
|
|
81
|
-
assignee_id: str = None,
|
|
82
|
-
pages_size: int = None,
|
|
83
|
-
page_offset: int = None,
|
|
84
|
-
task_id: int = None
|
|
85
|
-
) -> miscellaneous.List[entities.Assignment]:
|
|
86
|
-
"""
|
|
87
|
-
Get Assignment list to be able to use it in your code.
|
|
88
|
-
|
|
89
|
-
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
90
|
-
|
|
91
|
-
:param list project_ids: search assignment by given list of project ids
|
|
92
|
-
:param str status: search assignment by a given task status
|
|
93
|
-
:param str assignment_name: search assignment by a given assignment name
|
|
94
|
-
:param str assignee_id: the user email that assignee the assignment to it
|
|
95
|
-
:param int pages_size: pages size of the output generator
|
|
96
|
-
:param int page_offset: page offset of the output generator
|
|
97
|
-
:param str task_id: search assignment by given task id
|
|
98
|
-
:return: List of Assignment objects
|
|
99
|
-
:rtype: miscellaneous.List[dtlpy.entities.assignment.Assignment]
|
|
100
|
-
|
|
101
|
-
**Example**:
|
|
102
|
-
|
|
103
|
-
.. code-block:: python
|
|
104
|
-
|
|
105
|
-
assignments = task.assignments.list(status='complete', assignee_id='user@dataloop.ai', pages_size=100, page_offset=0)
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
# url
|
|
109
|
-
url = '/assignments'
|
|
110
|
-
|
|
111
|
-
query = list()
|
|
112
|
-
if project_ids is not None:
|
|
113
|
-
if not isinstance(project_ids, list):
|
|
114
|
-
project_ids = [project_ids]
|
|
115
|
-
elif self._project_id is not None:
|
|
116
|
-
project_ids = [self._project_id]
|
|
117
|
-
elif self._project is not None:
|
|
118
|
-
project_ids = [self._project.id]
|
|
119
|
-
else:
|
|
120
|
-
raise exceptions.PlatformException(error='400', message='Must provide project')
|
|
121
|
-
|
|
122
|
-
project_ids = ','.join(project_ids)
|
|
123
|
-
query.append('projects={}'.format(project_ids))
|
|
124
|
-
|
|
125
|
-
if status is not None:
|
|
126
|
-
query.append('status={}'.format(status))
|
|
127
|
-
if assignment_name is not None:
|
|
128
|
-
query.append('name={}'.format(assignment_name))
|
|
129
|
-
if assignee_id is not None:
|
|
130
|
-
query.append('annotator={}'.format(assignee_id))
|
|
131
|
-
if pages_size is not None:
|
|
132
|
-
query.append('pageSize={}'.format(pages_size))
|
|
133
|
-
if pages_size is None:
|
|
134
|
-
query.append('pageSize={}'.format(500))
|
|
135
|
-
if page_offset is not None:
|
|
136
|
-
query.append('pageOffset={}'.format(page_offset))
|
|
137
|
-
|
|
138
|
-
if task_id is None and self._task is not None:
|
|
139
|
-
task_id = self._task.id
|
|
140
|
-
if task_id is not None:
|
|
141
|
-
query.append('taskId={}'.format(task_id))
|
|
142
|
-
|
|
143
|
-
if len(query) > 0:
|
|
144
|
-
query_string = '&'.join(query)
|
|
145
|
-
url = '{}?{}'.format(url, query_string)
|
|
146
|
-
|
|
147
|
-
success, response = self._client_api.gen_request(req_type='get',
|
|
148
|
-
path=url)
|
|
149
|
-
if success:
|
|
150
|
-
assignments = miscellaneous.List(
|
|
151
|
-
[entities.Assignment.from_json(client_api=self._client_api,
|
|
152
|
-
_json=_json, project=self._project, dataset=self._dataset,
|
|
153
|
-
task=self._task)
|
|
154
|
-
for _json in response.json()['items']])
|
|
155
|
-
else:
|
|
156
|
-
logger.error('Platform error getting assignments')
|
|
157
|
-
raise exceptions.PlatformException(response)
|
|
158
|
-
return assignments
|
|
159
|
-
|
|
160
|
-
@_api_reference.add(path='/assignments/{id}', method='get')
|
|
161
|
-
def get(self,
|
|
162
|
-
assignment_name: str = None,
|
|
163
|
-
assignment_id: str = None):
|
|
164
|
-
"""
|
|
165
|
-
Get Assignment object to use it in your code.
|
|
166
|
-
|
|
167
|
-
:param str assignment_name: optional - search by name
|
|
168
|
-
:param str assignment_id: optional - search by id
|
|
169
|
-
:return: Assignment object
|
|
170
|
-
:rtype: dtlpy.entities.assignment.Assignment
|
|
171
|
-
|
|
172
|
-
**Example**:
|
|
173
|
-
|
|
174
|
-
.. code-block:: python
|
|
175
|
-
|
|
176
|
-
assignment = task.assignments.get(assignment_id='assignment_id')
|
|
177
|
-
"""
|
|
178
|
-
|
|
179
|
-
if assignment_id is not None:
|
|
180
|
-
url = '/assignments/{}'.format(assignment_id)
|
|
181
|
-
success, response = self._client_api.gen_request(req_type='get',
|
|
182
|
-
path=url)
|
|
183
|
-
if not success:
|
|
184
|
-
raise exceptions.PlatformException('404', 'Assignment not found')
|
|
185
|
-
else:
|
|
186
|
-
assignment = entities.Assignment.from_json(_json=response.json(),
|
|
187
|
-
client_api=self._client_api,
|
|
188
|
-
project=self._project,
|
|
189
|
-
dataset=self._dataset,
|
|
190
|
-
task=self._task)
|
|
191
|
-
# verify input assignment name is same as the given id
|
|
192
|
-
if assignment_name is not None and assignment.name != assignment_name:
|
|
193
|
-
logger.warning(
|
|
194
|
-
"Mismatch found in assignments.get: assignment_name is different then assignment.name: "
|
|
195
|
-
"{!r} != {!r}".format(
|
|
196
|
-
assignment_name,
|
|
197
|
-
assignment.name))
|
|
198
|
-
elif assignment_name is not None:
|
|
199
|
-
assignments = [assignment for assignment in self.list() if assignment.name == assignment_name]
|
|
200
|
-
if len(assignments) == 0:
|
|
201
|
-
raise exceptions.PlatformException('404', 'Assignment not found')
|
|
202
|
-
elif len(assignments) > 1:
|
|
203
|
-
raise exceptions.PlatformException('404',
|
|
204
|
-
'More than one assignment exist with the same name: {}'.format(
|
|
205
|
-
assignment_name))
|
|
206
|
-
else:
|
|
207
|
-
assignment = assignments[0]
|
|
208
|
-
else:
|
|
209
|
-
raise exceptions.PlatformException('400', 'Must provide either assignment name or assignment id')
|
|
210
|
-
|
|
211
|
-
assert isinstance(assignment, entities.Assignment)
|
|
212
|
-
return assignment
|
|
213
|
-
|
|
214
|
-
@property
|
|
215
|
-
def platform_url(self):
|
|
216
|
-
if self.task.id is None or self.project_id is None:
|
|
217
|
-
raise ValueError("must have project and task")
|
|
218
|
-
|
|
219
|
-
return self._client_api._get_resource_url(
|
|
220
|
-
"projects/{}/tasks/{}/assignments".format(self.project_id, self.task.id))
|
|
221
|
-
|
|
222
|
-
def open_in_web(self,
|
|
223
|
-
assignment_name: str = None,
|
|
224
|
-
assignment_id: str = None,
|
|
225
|
-
assignment: str = None):
|
|
226
|
-
"""
|
|
227
|
-
Open the assignment in the platform.
|
|
228
|
-
|
|
229
|
-
**Prerequisites**: All users.
|
|
230
|
-
|
|
231
|
-
:param str assignment_name: the name of the assignment
|
|
232
|
-
:param str assignment_id: the Id of the assignment
|
|
233
|
-
:param dtlpy.entities.assignment.Assignment assignment: assignment object
|
|
234
|
-
|
|
235
|
-
**Example**:
|
|
236
|
-
|
|
237
|
-
.. code-block:: python
|
|
238
|
-
|
|
239
|
-
task.assignments.open_in_web(assignment_id='assignment_id')
|
|
240
|
-
"""
|
|
241
|
-
if assignment_name is not None:
|
|
242
|
-
assignment = self.get(assignment_name=assignment_name)
|
|
243
|
-
if assignment is not None:
|
|
244
|
-
assignment.open_in_web()
|
|
245
|
-
elif assignment_id is not None:
|
|
246
|
-
self._client_api._open_in_web(url=self.platform_url + '/' + str(assignment_id))
|
|
247
|
-
else:
|
|
248
|
-
self._client_api._open_in_web(url=self.platform_url)
|
|
249
|
-
|
|
250
|
-
@_api_reference.add(path='/assignments/{id}/reassign', method='post')
|
|
251
|
-
def reassign(self,
|
|
252
|
-
assignee_id: str,
|
|
253
|
-
assignment: entities.Assignment = None,
|
|
254
|
-
assignment_id: str = None,
|
|
255
|
-
task: entities.Task = None,
|
|
256
|
-
task_id: str = None,
|
|
257
|
-
wait: bool = True):
|
|
258
|
-
"""
|
|
259
|
-
Reassign an assignment.
|
|
260
|
-
|
|
261
|
-
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
262
|
-
|
|
263
|
-
:param str assignee_id: the email of the user that want to assign the assignment
|
|
264
|
-
:param dtlpy.entities.assignment.Assignment assignment: assignment object
|
|
265
|
-
:param assignment_id: the Id of the assignment
|
|
266
|
-
:param dtlpy.entities.task.Task task: task object
|
|
267
|
-
:param str task_id: the Id of the task that include the assignment
|
|
268
|
-
:param bool wait: wait until reassign assignment finish
|
|
269
|
-
:return: Assignment object
|
|
270
|
-
:rtype: dtlpy.entities.assignment.Assignment
|
|
271
|
-
|
|
272
|
-
**Example**:
|
|
273
|
-
|
|
274
|
-
.. code-block:: python
|
|
275
|
-
|
|
276
|
-
assignment = task.assignments.reassign(assignee_ids='annotator1@dataloop.ai')
|
|
277
|
-
"""
|
|
278
|
-
if assignment_id is None and assignment is None:
|
|
279
|
-
raise exceptions.PlatformException('400', 'Must provide either assignment or assignment_id')
|
|
280
|
-
elif assignment_id is None:
|
|
281
|
-
assignment_id = assignment.id
|
|
282
|
-
|
|
283
|
-
if task_id is None and task is None:
|
|
284
|
-
raise exceptions.PlatformException('400', 'Must provide either task or task_id')
|
|
285
|
-
elif task_id is None:
|
|
286
|
-
task_id = task.id
|
|
287
|
-
|
|
288
|
-
url = '/assignments/{}/reassign'.format(assignment_id)
|
|
289
|
-
|
|
290
|
-
payload = {
|
|
291
|
-
'taskId': task_id,
|
|
292
|
-
'annotator': assignee_id,
|
|
293
|
-
'asynced': wait
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
297
|
-
path=url,
|
|
298
|
-
json_req=payload)
|
|
299
|
-
if success:
|
|
300
|
-
command = entities.Command.from_json(_json=response.json(),
|
|
301
|
-
client_api=self._client_api)
|
|
302
|
-
if not wait:
|
|
303
|
-
return command
|
|
304
|
-
command = command.wait(timeout=0)
|
|
305
|
-
if 'toAssignment' not in command.spec:
|
|
306
|
-
raise exceptions.PlatformException(error='400',
|
|
307
|
-
message="'toAssignment' key is missing in command response: {}"
|
|
308
|
-
.format(response))
|
|
309
|
-
return self.get(assignment_id=command.spec['toAssignment'])
|
|
310
|
-
else:
|
|
311
|
-
raise exceptions.PlatformException(response)
|
|
312
|
-
|
|
313
|
-
@_api_reference.add(path='/assignments/{id}/redistribute', method='post')
|
|
314
|
-
def redistribute(self,
|
|
315
|
-
workload: entities.Workload,
|
|
316
|
-
assignment: entities.Assignment = None,
|
|
317
|
-
assignment_id: str = None,
|
|
318
|
-
task: entities.Task = None,
|
|
319
|
-
task_id: str = None,
|
|
320
|
-
wait: bool = True):
|
|
321
|
-
"""
|
|
322
|
-
Redistribute an assignment.
|
|
323
|
-
|
|
324
|
-
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
325
|
-
|
|
326
|
-
**Example**:
|
|
327
|
-
|
|
328
|
-
:param dtlpy.entities.assignment.Workload workload: list of WorkloadUnit objects. Customize distribution (percentage) between the task assignees. For example: [dl.WorkloadUnit(annotator@hi.com, 80), dl.WorkloadUnit(annotator2@hi.com, 20)]
|
|
329
|
-
:param dtlpy.entities.assignment.Assignment assignment: assignment object
|
|
330
|
-
:param str assignment_id: the Id of the assignment
|
|
331
|
-
:param dtlpy.entities.task.Task task: the task object that include the assignment
|
|
332
|
-
:param str task_id: the Id of the task that include the assignment
|
|
333
|
-
:param bool wait: wait until redistribute assignment finish
|
|
334
|
-
:return: Assignment object
|
|
335
|
-
:rtype: dtlpy.entities.assignment.Assignment assignment
|
|
336
|
-
|
|
337
|
-
.. code-block:: python
|
|
338
|
-
|
|
339
|
-
assignment = task.assignments.redistribute(workload=dl.Workload([dl.WorkloadUnit(assignee_id="annotator1@dataloop.ai", load=50),
|
|
340
|
-
dl.WorkloadUnit(assignee_id="annotator2@dataloop.ai", load=50)]))
|
|
341
|
-
"""
|
|
342
|
-
if assignment_id is None and assignment is None:
|
|
343
|
-
raise exceptions.PlatformException('400', 'Must provide either assignment or assignment_id')
|
|
344
|
-
elif assignment_id is None:
|
|
345
|
-
assignment_id = assignment.id
|
|
346
|
-
|
|
347
|
-
if task_id is None and task is None:
|
|
348
|
-
raise exceptions.PlatformException('400', 'Must provide either task or task_id')
|
|
349
|
-
elif task_id is None:
|
|
350
|
-
task_id = task.id
|
|
351
|
-
|
|
352
|
-
url = '/assignments/{}/redistribute'.format(assignment_id)
|
|
353
|
-
|
|
354
|
-
payload = {
|
|
355
|
-
'taskId': task_id,
|
|
356
|
-
'workload': workload.to_json(),
|
|
357
|
-
'asynced': wait
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if self._task is None:
|
|
361
|
-
self._task = self.get(assignment_id=assignment_id).task
|
|
362
|
-
if task is None:
|
|
363
|
-
task = self._task
|
|
364
|
-
|
|
365
|
-
success, response = self._client_api.gen_request(req_type='post',
|
|
366
|
-
path=url,
|
|
367
|
-
json_req=payload)
|
|
368
|
-
if success:
|
|
369
|
-
command = entities.Command.from_json(_json=response.json(),
|
|
370
|
-
client_api=self._client_api)
|
|
371
|
-
if not wait:
|
|
372
|
-
return command
|
|
373
|
-
command = command.wait(timeout=0)
|
|
374
|
-
if 'workload' not in command.spec:
|
|
375
|
-
raise exceptions.PlatformException(error='400',
|
|
376
|
-
message="workload key is missing in command response: {}"
|
|
377
|
-
.format(response))
|
|
378
|
-
|
|
379
|
-
task_assignments = task.assignments.list()
|
|
380
|
-
workers = list()
|
|
381
|
-
for worker in workload:
|
|
382
|
-
workers.append(worker.assignee_id.lower())
|
|
383
|
-
|
|
384
|
-
redistributed_assignments = list()
|
|
385
|
-
for ass in task_assignments:
|
|
386
|
-
if ass.annotator in workers:
|
|
387
|
-
redistributed_assignments.append(ass)
|
|
388
|
-
workers.remove(ass.annotator)
|
|
389
|
-
if not workers:
|
|
390
|
-
break
|
|
391
|
-
|
|
392
|
-
return miscellaneous.List(redistributed_assignments)
|
|
393
|
-
else:
|
|
394
|
-
raise exceptions.PlatformException(response)
|
|
395
|
-
|
|
396
|
-
@_api_reference.add(path='/assignments/{id}', method='patch')
|
|
397
|
-
def update(self,
|
|
398
|
-
assignment: entities.Assignment = None,
|
|
399
|
-
system_metadata: bool = False
|
|
400
|
-
) -> entities.Assignment:
|
|
401
|
-
"""
|
|
402
|
-
Update an assignment.
|
|
403
|
-
|
|
404
|
-
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
405
|
-
|
|
406
|
-
:param dtlpy.entities.assignment.Assignment assignment assignment: assignment entity
|
|
407
|
-
:param bool system_metadata: True, if you want to change metadata system
|
|
408
|
-
:return: Assignment object
|
|
409
|
-
:rtype: dtlpy.entities.assignment.Assignment assignment
|
|
410
|
-
|
|
411
|
-
**Example**:
|
|
412
|
-
|
|
413
|
-
.. code-block:: python
|
|
414
|
-
|
|
415
|
-
assignment = task.assignments.update(assignment='assignment_entity', system_metadata=False)
|
|
416
|
-
"""
|
|
417
|
-
url = '/assignments/{}'.format(assignment.id)
|
|
418
|
-
|
|
419
|
-
if system_metadata:
|
|
420
|
-
url += '?system=true'
|
|
421
|
-
|
|
422
|
-
success, response = self._client_api.gen_request(req_type='patch',
|
|
423
|
-
path=url,
|
|
424
|
-
json_req=assignment.to_json())
|
|
425
|
-
if success:
|
|
426
|
-
return entities.Assignment.from_json(_json=response.json(),
|
|
427
|
-
client_api=self._client_api, project=self._project,
|
|
428
|
-
dataset=self._dataset, task=self._task)
|
|
429
|
-
else:
|
|
430
|
-
raise exceptions.PlatformException(response)
|
|
431
|
-
|
|
432
|
-
def create(self,
|
|
433
|
-
assignee_id: str,
|
|
434
|
-
task: entities.Task = None,
|
|
435
|
-
filters: entities.Filters = None,
|
|
436
|
-
items: list = None) -> entities.Assignment:
|
|
437
|
-
"""
|
|
438
|
-
Create a new assignment.
|
|
439
|
-
|
|
440
|
-
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
441
|
-
|
|
442
|
-
:param str assignee_id: the email of the user that want to assign the assignment
|
|
443
|
-
:param dtlpy.entities.task.Task task: the task object that include the assignment
|
|
444
|
-
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
445
|
-
:param list items: list of items (item Id or objects) to insert to the assignment
|
|
446
|
-
:return: Assignment object
|
|
447
|
-
:rtype: dtlpy.entities.assignment.Assignment assignment
|
|
448
|
-
|
|
449
|
-
**Example**:
|
|
450
|
-
|
|
451
|
-
.. code-block:: python
|
|
452
|
-
|
|
453
|
-
assignment = task.assignments.create(assignee_id='annotator1@dataloop.ai')
|
|
454
|
-
"""
|
|
455
|
-
return self._create_in_task(assignee_id=assignee_id, task=task, filters=filters, items=items)
|
|
456
|
-
|
|
457
|
-
def _create_in_task(self, assignee_id, task, filters=None, items=None) -> entities.Assignment:
|
|
458
|
-
|
|
459
|
-
if task is None:
|
|
460
|
-
if self._task is None:
|
|
461
|
-
raise exceptions.PlatformException('400', 'Must provide task')
|
|
462
|
-
task = self._task
|
|
463
|
-
|
|
464
|
-
assignments_before = [ass.id for ass in task.assignments.list()]
|
|
465
|
-
|
|
466
|
-
if filters is None and items is None:
|
|
467
|
-
raise exceptions.PlatformException('400', 'Must provide either filters or items list')
|
|
468
|
-
|
|
469
|
-
workload = entities.Workload.generate(assignee_ids=[assignee_id])
|
|
470
|
-
task = task.add_items(filters=filters, items=items, workload=workload, limit=None)
|
|
471
|
-
assignments = [ass for ass in task.assignments.list() if ass.id not in assignments_before]
|
|
472
|
-
|
|
473
|
-
if len(assignments) < 1:
|
|
474
|
-
raise exceptions.PlatformException('Error creating an assignment, '
|
|
475
|
-
'Please use task.add_items() to perform this action')
|
|
476
|
-
|
|
477
|
-
return assignments[0]
|
|
478
|
-
|
|
479
|
-
def __item_operations(self, dataset: entities.Dataset,
|
|
480
|
-
op, assignment_id=None, assignment_name=None, filters=None, items=None):
|
|
481
|
-
if assignment_id is None and assignment_name is None:
|
|
482
|
-
raise exceptions.PlatformException('400', 'Must provide either assignment name or assignment id')
|
|
483
|
-
elif assignment_id is None:
|
|
484
|
-
assignment_id = self.get(assignment_name=assignment_name).id
|
|
485
|
-
|
|
486
|
-
try:
|
|
487
|
-
if filters is None and items is None:
|
|
488
|
-
raise exceptions.PlatformException('400', 'Must provide either filters or items list')
|
|
489
|
-
|
|
490
|
-
if filters is None:
|
|
491
|
-
if not isinstance(items, list):
|
|
492
|
-
items = [items]
|
|
493
|
-
filters = entities.Filters(field='id',
|
|
494
|
-
values=[item.id for item in items],
|
|
495
|
-
operator=entities.FiltersOperations.IN,
|
|
496
|
-
use_defaults=False)
|
|
497
|
-
|
|
498
|
-
filters._ref_assignment = True
|
|
499
|
-
filters._ref_assignment_id = assignment_id
|
|
500
|
-
filters._ref_op = op
|
|
501
|
-
|
|
502
|
-
return dataset.items.update(filters=filters)
|
|
503
|
-
finally:
|
|
504
|
-
if filters is not None:
|
|
505
|
-
filters._nullify_refs()
|
|
506
|
-
|
|
507
|
-
def get_items(self,
|
|
508
|
-
assignment: entities.Assignment = None,
|
|
509
|
-
assignment_id=None,
|
|
510
|
-
assignment_name=None,
|
|
511
|
-
dataset=None,
|
|
512
|
-
filters=None
|
|
513
|
-
) -> entities.PagedEntities:
|
|
514
|
-
"""
|
|
515
|
-
Get all the items in the assignment.
|
|
516
|
-
|
|
517
|
-
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
518
|
-
|
|
519
|
-
:param dtlpy.entities.assignment.Assignment assignment: assignment object
|
|
520
|
-
:param assignment_id: the Id of the assignment
|
|
521
|
-
:param str assignment_name: the name of the assignment
|
|
522
|
-
:param dtlpy.entities.dataset.Dataset dataset: dataset object, the dataset that refer to the assignment
|
|
523
|
-
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
524
|
-
:return: pages of the items
|
|
525
|
-
:rtype: dtlpy.entities.paged_entities.PagedEntities
|
|
526
|
-
|
|
527
|
-
**Example**:
|
|
528
|
-
|
|
529
|
-
.. code-block:: python
|
|
530
|
-
|
|
531
|
-
items = task.assignments.get_items(assignment_id='assignment_id')
|
|
532
|
-
"""
|
|
533
|
-
if assignment is None and assignment_id is None and assignment_name is None:
|
|
534
|
-
raise exceptions.PlatformException('400',
|
|
535
|
-
'Please provide either assignment, assignment_id or assignment_name')
|
|
536
|
-
|
|
537
|
-
if assignment_id is None:
|
|
538
|
-
if assignment is None:
|
|
539
|
-
assignment = self.get(assignment_name=assignment_name)
|
|
540
|
-
assignment_id = assignment.id
|
|
541
|
-
|
|
542
|
-
if dataset is None and self._dataset is None:
|
|
543
|
-
if assignment is None:
|
|
544
|
-
assignment = self.get(assignment_id=assignment_id, assignment_name=assignment_name)
|
|
545
|
-
if assignment.dataset_id is None:
|
|
546
|
-
raise exceptions.PlatformException('400', 'Please provide a dataset entity')
|
|
547
|
-
dataset = repositories.Datasets(client_api=self._client_api, project=self._project).get(
|
|
548
|
-
dataset_id=assignment.dataset_id)
|
|
549
|
-
elif dataset is None:
|
|
550
|
-
dataset = self._dataset
|
|
551
|
-
|
|
552
|
-
if filters is None:
|
|
553
|
-
filters = entities.Filters(use_defaults=False)
|
|
554
|
-
filters.add(field='metadata.system.refs.id', values=[assignment_id], operator=entities.FiltersOperations.IN)
|
|
555
|
-
|
|
556
|
-
return dataset.items.list(filters=filters)
|
|
557
|
-
|
|
558
|
-
def set_status(self,
|
|
559
|
-
status: str,
|
|
560
|
-
operation: str,
|
|
561
|
-
item_id: str,
|
|
562
|
-
assignment_id: str
|
|
563
|
-
) -> bool:
|
|
564
|
-
"""
|
|
565
|
-
Set item status within assignment.
|
|
566
|
-
|
|
567
|
-
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
568
|
-
|
|
569
|
-
:param str status: string the describes the status
|
|
570
|
-
:param str operation: the status action need 'create' or 'delete'
|
|
571
|
-
:param str item_id: item id that want to set his status
|
|
572
|
-
:param assignment_id: the Id of the assignment
|
|
573
|
-
:return: True id success
|
|
574
|
-
:rtype: bool
|
|
575
|
-
|
|
576
|
-
**Example**:
|
|
577
|
-
|
|
578
|
-
.. code-block:: python
|
|
579
|
-
|
|
580
|
-
success = task.assignments.set_status(assignment_id='assignment_id',
|
|
581
|
-
status='complete',
|
|
582
|
-
operation='created',
|
|
583
|
-
item_id='item_id')
|
|
584
|
-
"""
|
|
585
|
-
url = '/assignments/{assignment_id}/items/{item_id}/status'.format(assignment_id=assignment_id, item_id=item_id)
|
|
586
|
-
payload = {
|
|
587
|
-
'operation': operation,
|
|
588
|
-
'status': status
|
|
589
|
-
}
|
|
590
|
-
success, response = self._client_api.gen_request(
|
|
591
|
-
req_type='post',
|
|
592
|
-
path=url,
|
|
593
|
-
json_req=payload
|
|
594
|
-
)
|
|
595
|
-
|
|
596
|
-
if not success:
|
|
597
|
-
raise exceptions.PlatformException(response)
|
|
598
|
-
|
|
599
|
-
return True
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from .. import exceptions, miscellaneous, entities, repositories, _api_reference
|
|
4
|
+
from ..services.api_client import ApiClient
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(name='dtlpy')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Assignments:
|
|
10
|
+
"""
|
|
11
|
+
Assignments Repository
|
|
12
|
+
|
|
13
|
+
The Assignments class allows users to manage assignments and their properties.
|
|
14
|
+
Read more about `Task Assignment <https://developers.dataloop.ai/tutorials/task_workflows/create_a_task/chapter/>`_ in our Developers documentation.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self,
|
|
18
|
+
client_api: ApiClient,
|
|
19
|
+
project: entities.Project = None,
|
|
20
|
+
task: entities.Task = None,
|
|
21
|
+
dataset: entities.Dataset = None,
|
|
22
|
+
project_id=None):
|
|
23
|
+
self._client_api = client_api
|
|
24
|
+
self._project = project
|
|
25
|
+
self._dataset = dataset
|
|
26
|
+
self._task = task
|
|
27
|
+
|
|
28
|
+
self._project_id = project_id
|
|
29
|
+
if self._project_id is None and self._project is not None:
|
|
30
|
+
self._project_id = self._project.id
|
|
31
|
+
|
|
32
|
+
############
|
|
33
|
+
# entities #
|
|
34
|
+
############
|
|
35
|
+
@property
|
|
36
|
+
def task(self) -> entities.Task:
|
|
37
|
+
if self._task is None:
|
|
38
|
+
raise exceptions.PlatformException(
|
|
39
|
+
error='2001',
|
|
40
|
+
message='Missing "task". need to set an Task entity or use task.assignments repository')
|
|
41
|
+
assert isinstance(self._task, entities.Task)
|
|
42
|
+
return self._task
|
|
43
|
+
|
|
44
|
+
@task.setter
|
|
45
|
+
def task(self, task: entities.Task):
|
|
46
|
+
if not isinstance(task, entities.Task):
|
|
47
|
+
raise ValueError('Must input a valid Task entity')
|
|
48
|
+
self._task = task
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def project_id(self):
|
|
52
|
+
if self._project_id is not None:
|
|
53
|
+
return self._project_id
|
|
54
|
+
elif self._project is not None:
|
|
55
|
+
return self._project.id
|
|
56
|
+
else:
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def project(self) -> entities.Project:
|
|
61
|
+
if self._project is None:
|
|
62
|
+
raise exceptions.PlatformException(
|
|
63
|
+
error='2001',
|
|
64
|
+
message='Missing "project". need to set a Project entity or use project.assignments repository')
|
|
65
|
+
assert isinstance(self._project, entities.Project)
|
|
66
|
+
return self._project
|
|
67
|
+
|
|
68
|
+
@project.setter
|
|
69
|
+
def project(self, project: entities.Project):
|
|
70
|
+
if not isinstance(project, entities.Project):
|
|
71
|
+
raise ValueError('Must input a valid Project entity')
|
|
72
|
+
self._project = project
|
|
73
|
+
|
|
74
|
+
###########
|
|
75
|
+
# methods #
|
|
76
|
+
###########
|
|
77
|
+
def list(self,
|
|
78
|
+
project_ids: list = None,
|
|
79
|
+
status: str = None,
|
|
80
|
+
assignment_name: str = None,
|
|
81
|
+
assignee_id: str = None,
|
|
82
|
+
pages_size: int = None,
|
|
83
|
+
page_offset: int = None,
|
|
84
|
+
task_id: int = None
|
|
85
|
+
) -> miscellaneous.List[entities.Assignment]:
|
|
86
|
+
"""
|
|
87
|
+
Get Assignment list to be able to use it in your code.
|
|
88
|
+
|
|
89
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
90
|
+
|
|
91
|
+
:param list project_ids: search assignment by given list of project ids
|
|
92
|
+
:param str status: search assignment by a given task status
|
|
93
|
+
:param str assignment_name: search assignment by a given assignment name
|
|
94
|
+
:param str assignee_id: the user email that assignee the assignment to it
|
|
95
|
+
:param int pages_size: pages size of the output generator
|
|
96
|
+
:param int page_offset: page offset of the output generator
|
|
97
|
+
:param str task_id: search assignment by given task id
|
|
98
|
+
:return: List of Assignment objects
|
|
99
|
+
:rtype: miscellaneous.List[dtlpy.entities.assignment.Assignment]
|
|
100
|
+
|
|
101
|
+
**Example**:
|
|
102
|
+
|
|
103
|
+
.. code-block:: python
|
|
104
|
+
|
|
105
|
+
assignments = task.assignments.list(status='complete', assignee_id='user@dataloop.ai', pages_size=100, page_offset=0)
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
# url
|
|
109
|
+
url = '/assignments'
|
|
110
|
+
|
|
111
|
+
query = list()
|
|
112
|
+
if project_ids is not None:
|
|
113
|
+
if not isinstance(project_ids, list):
|
|
114
|
+
project_ids = [project_ids]
|
|
115
|
+
elif self._project_id is not None:
|
|
116
|
+
project_ids = [self._project_id]
|
|
117
|
+
elif self._project is not None:
|
|
118
|
+
project_ids = [self._project.id]
|
|
119
|
+
else:
|
|
120
|
+
raise exceptions.PlatformException(error='400', message='Must provide project')
|
|
121
|
+
|
|
122
|
+
project_ids = ','.join(project_ids)
|
|
123
|
+
query.append('projects={}'.format(project_ids))
|
|
124
|
+
|
|
125
|
+
if status is not None:
|
|
126
|
+
query.append('status={}'.format(status))
|
|
127
|
+
if assignment_name is not None:
|
|
128
|
+
query.append('name={}'.format(assignment_name))
|
|
129
|
+
if assignee_id is not None:
|
|
130
|
+
query.append('annotator={}'.format(assignee_id))
|
|
131
|
+
if pages_size is not None:
|
|
132
|
+
query.append('pageSize={}'.format(pages_size))
|
|
133
|
+
if pages_size is None:
|
|
134
|
+
query.append('pageSize={}'.format(500))
|
|
135
|
+
if page_offset is not None:
|
|
136
|
+
query.append('pageOffset={}'.format(page_offset))
|
|
137
|
+
|
|
138
|
+
if task_id is None and self._task is not None:
|
|
139
|
+
task_id = self._task.id
|
|
140
|
+
if task_id is not None:
|
|
141
|
+
query.append('taskId={}'.format(task_id))
|
|
142
|
+
|
|
143
|
+
if len(query) > 0:
|
|
144
|
+
query_string = '&'.join(query)
|
|
145
|
+
url = '{}?{}'.format(url, query_string)
|
|
146
|
+
|
|
147
|
+
success, response = self._client_api.gen_request(req_type='get',
|
|
148
|
+
path=url)
|
|
149
|
+
if success:
|
|
150
|
+
assignments = miscellaneous.List(
|
|
151
|
+
[entities.Assignment.from_json(client_api=self._client_api,
|
|
152
|
+
_json=_json, project=self._project, dataset=self._dataset,
|
|
153
|
+
task=self._task)
|
|
154
|
+
for _json in response.json()['items']])
|
|
155
|
+
else:
|
|
156
|
+
logger.error('Platform error getting assignments')
|
|
157
|
+
raise exceptions.PlatformException(response)
|
|
158
|
+
return assignments
|
|
159
|
+
|
|
160
|
+
@_api_reference.add(path='/assignments/{id}', method='get')
|
|
161
|
+
def get(self,
|
|
162
|
+
assignment_name: str = None,
|
|
163
|
+
assignment_id: str = None):
|
|
164
|
+
"""
|
|
165
|
+
Get Assignment object to use it in your code.
|
|
166
|
+
|
|
167
|
+
:param str assignment_name: optional - search by name
|
|
168
|
+
:param str assignment_id: optional - search by id
|
|
169
|
+
:return: Assignment object
|
|
170
|
+
:rtype: dtlpy.entities.assignment.Assignment
|
|
171
|
+
|
|
172
|
+
**Example**:
|
|
173
|
+
|
|
174
|
+
.. code-block:: python
|
|
175
|
+
|
|
176
|
+
assignment = task.assignments.get(assignment_id='assignment_id')
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
if assignment_id is not None:
|
|
180
|
+
url = '/assignments/{}'.format(assignment_id)
|
|
181
|
+
success, response = self._client_api.gen_request(req_type='get',
|
|
182
|
+
path=url)
|
|
183
|
+
if not success:
|
|
184
|
+
raise exceptions.PlatformException('404', 'Assignment not found')
|
|
185
|
+
else:
|
|
186
|
+
assignment = entities.Assignment.from_json(_json=response.json(),
|
|
187
|
+
client_api=self._client_api,
|
|
188
|
+
project=self._project,
|
|
189
|
+
dataset=self._dataset,
|
|
190
|
+
task=self._task)
|
|
191
|
+
# verify input assignment name is same as the given id
|
|
192
|
+
if assignment_name is not None and assignment.name != assignment_name:
|
|
193
|
+
logger.warning(
|
|
194
|
+
"Mismatch found in assignments.get: assignment_name is different then assignment.name: "
|
|
195
|
+
"{!r} != {!r}".format(
|
|
196
|
+
assignment_name,
|
|
197
|
+
assignment.name))
|
|
198
|
+
elif assignment_name is not None:
|
|
199
|
+
assignments = [assignment for assignment in self.list() if assignment.name == assignment_name]
|
|
200
|
+
if len(assignments) == 0:
|
|
201
|
+
raise exceptions.PlatformException('404', 'Assignment not found')
|
|
202
|
+
elif len(assignments) > 1:
|
|
203
|
+
raise exceptions.PlatformException('404',
|
|
204
|
+
'More than one assignment exist with the same name: {}'.format(
|
|
205
|
+
assignment_name))
|
|
206
|
+
else:
|
|
207
|
+
assignment = assignments[0]
|
|
208
|
+
else:
|
|
209
|
+
raise exceptions.PlatformException('400', 'Must provide either assignment name or assignment id')
|
|
210
|
+
|
|
211
|
+
assert isinstance(assignment, entities.Assignment)
|
|
212
|
+
return assignment
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def platform_url(self):
|
|
216
|
+
if self.task.id is None or self.project_id is None:
|
|
217
|
+
raise ValueError("must have project and task")
|
|
218
|
+
|
|
219
|
+
return self._client_api._get_resource_url(
|
|
220
|
+
"projects/{}/tasks/{}/assignments".format(self.project_id, self.task.id))
|
|
221
|
+
|
|
222
|
+
def open_in_web(self,
|
|
223
|
+
assignment_name: str = None,
|
|
224
|
+
assignment_id: str = None,
|
|
225
|
+
assignment: str = None):
|
|
226
|
+
"""
|
|
227
|
+
Open the assignment in the platform.
|
|
228
|
+
|
|
229
|
+
**Prerequisites**: All users.
|
|
230
|
+
|
|
231
|
+
:param str assignment_name: the name of the assignment
|
|
232
|
+
:param str assignment_id: the Id of the assignment
|
|
233
|
+
:param dtlpy.entities.assignment.Assignment assignment: assignment object
|
|
234
|
+
|
|
235
|
+
**Example**:
|
|
236
|
+
|
|
237
|
+
.. code-block:: python
|
|
238
|
+
|
|
239
|
+
task.assignments.open_in_web(assignment_id='assignment_id')
|
|
240
|
+
"""
|
|
241
|
+
if assignment_name is not None:
|
|
242
|
+
assignment = self.get(assignment_name=assignment_name)
|
|
243
|
+
if assignment is not None:
|
|
244
|
+
assignment.open_in_web()
|
|
245
|
+
elif assignment_id is not None:
|
|
246
|
+
self._client_api._open_in_web(url=self.platform_url + '/' + str(assignment_id))
|
|
247
|
+
else:
|
|
248
|
+
self._client_api._open_in_web(url=self.platform_url)
|
|
249
|
+
|
|
250
|
+
@_api_reference.add(path='/assignments/{id}/reassign', method='post')
|
|
251
|
+
def reassign(self,
|
|
252
|
+
assignee_id: str,
|
|
253
|
+
assignment: entities.Assignment = None,
|
|
254
|
+
assignment_id: str = None,
|
|
255
|
+
task: entities.Task = None,
|
|
256
|
+
task_id: str = None,
|
|
257
|
+
wait: bool = True):
|
|
258
|
+
"""
|
|
259
|
+
Reassign an assignment.
|
|
260
|
+
|
|
261
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
262
|
+
|
|
263
|
+
:param str assignee_id: the email of the user that want to assign the assignment
|
|
264
|
+
:param dtlpy.entities.assignment.Assignment assignment: assignment object
|
|
265
|
+
:param assignment_id: the Id of the assignment
|
|
266
|
+
:param dtlpy.entities.task.Task task: task object
|
|
267
|
+
:param str task_id: the Id of the task that include the assignment
|
|
268
|
+
:param bool wait: wait until reassign assignment finish
|
|
269
|
+
:return: Assignment object
|
|
270
|
+
:rtype: dtlpy.entities.assignment.Assignment
|
|
271
|
+
|
|
272
|
+
**Example**:
|
|
273
|
+
|
|
274
|
+
.. code-block:: python
|
|
275
|
+
|
|
276
|
+
assignment = task.assignments.reassign(assignee_ids='annotator1@dataloop.ai')
|
|
277
|
+
"""
|
|
278
|
+
if assignment_id is None and assignment is None:
|
|
279
|
+
raise exceptions.PlatformException('400', 'Must provide either assignment or assignment_id')
|
|
280
|
+
elif assignment_id is None:
|
|
281
|
+
assignment_id = assignment.id
|
|
282
|
+
|
|
283
|
+
if task_id is None and task is None:
|
|
284
|
+
raise exceptions.PlatformException('400', 'Must provide either task or task_id')
|
|
285
|
+
elif task_id is None:
|
|
286
|
+
task_id = task.id
|
|
287
|
+
|
|
288
|
+
url = '/assignments/{}/reassign'.format(assignment_id)
|
|
289
|
+
|
|
290
|
+
payload = {
|
|
291
|
+
'taskId': task_id,
|
|
292
|
+
'annotator': assignee_id,
|
|
293
|
+
'asynced': wait
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
297
|
+
path=url,
|
|
298
|
+
json_req=payload)
|
|
299
|
+
if success:
|
|
300
|
+
command = entities.Command.from_json(_json=response.json(),
|
|
301
|
+
client_api=self._client_api)
|
|
302
|
+
if not wait:
|
|
303
|
+
return command
|
|
304
|
+
command = command.wait(timeout=0)
|
|
305
|
+
if 'toAssignment' not in command.spec:
|
|
306
|
+
raise exceptions.PlatformException(error='400',
|
|
307
|
+
message="'toAssignment' key is missing in command response: {}"
|
|
308
|
+
.format(response))
|
|
309
|
+
return self.get(assignment_id=command.spec['toAssignment'])
|
|
310
|
+
else:
|
|
311
|
+
raise exceptions.PlatformException(response)
|
|
312
|
+
|
|
313
|
+
@_api_reference.add(path='/assignments/{id}/redistribute', method='post')
|
|
314
|
+
def redistribute(self,
|
|
315
|
+
workload: entities.Workload,
|
|
316
|
+
assignment: entities.Assignment = None,
|
|
317
|
+
assignment_id: str = None,
|
|
318
|
+
task: entities.Task = None,
|
|
319
|
+
task_id: str = None,
|
|
320
|
+
wait: bool = True):
|
|
321
|
+
"""
|
|
322
|
+
Redistribute an assignment.
|
|
323
|
+
|
|
324
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
325
|
+
|
|
326
|
+
**Example**:
|
|
327
|
+
|
|
328
|
+
:param dtlpy.entities.assignment.Workload workload: list of WorkloadUnit objects. Customize distribution (percentage) between the task assignees. For example: [dl.WorkloadUnit(annotator@hi.com, 80), dl.WorkloadUnit(annotator2@hi.com, 20)]
|
|
329
|
+
:param dtlpy.entities.assignment.Assignment assignment: assignment object
|
|
330
|
+
:param str assignment_id: the Id of the assignment
|
|
331
|
+
:param dtlpy.entities.task.Task task: the task object that include the assignment
|
|
332
|
+
:param str task_id: the Id of the task that include the assignment
|
|
333
|
+
:param bool wait: wait until redistribute assignment finish
|
|
334
|
+
:return: Assignment object
|
|
335
|
+
:rtype: dtlpy.entities.assignment.Assignment assignment
|
|
336
|
+
|
|
337
|
+
.. code-block:: python
|
|
338
|
+
|
|
339
|
+
assignment = task.assignments.redistribute(workload=dl.Workload([dl.WorkloadUnit(assignee_id="annotator1@dataloop.ai", load=50),
|
|
340
|
+
dl.WorkloadUnit(assignee_id="annotator2@dataloop.ai", load=50)]))
|
|
341
|
+
"""
|
|
342
|
+
if assignment_id is None and assignment is None:
|
|
343
|
+
raise exceptions.PlatformException('400', 'Must provide either assignment or assignment_id')
|
|
344
|
+
elif assignment_id is None:
|
|
345
|
+
assignment_id = assignment.id
|
|
346
|
+
|
|
347
|
+
if task_id is None and task is None:
|
|
348
|
+
raise exceptions.PlatformException('400', 'Must provide either task or task_id')
|
|
349
|
+
elif task_id is None:
|
|
350
|
+
task_id = task.id
|
|
351
|
+
|
|
352
|
+
url = '/assignments/{}/redistribute'.format(assignment_id)
|
|
353
|
+
|
|
354
|
+
payload = {
|
|
355
|
+
'taskId': task_id,
|
|
356
|
+
'workload': workload.to_json(),
|
|
357
|
+
'asynced': wait
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if self._task is None:
|
|
361
|
+
self._task = self.get(assignment_id=assignment_id).task
|
|
362
|
+
if task is None:
|
|
363
|
+
task = self._task
|
|
364
|
+
|
|
365
|
+
success, response = self._client_api.gen_request(req_type='post',
|
|
366
|
+
path=url,
|
|
367
|
+
json_req=payload)
|
|
368
|
+
if success:
|
|
369
|
+
command = entities.Command.from_json(_json=response.json(),
|
|
370
|
+
client_api=self._client_api)
|
|
371
|
+
if not wait:
|
|
372
|
+
return command
|
|
373
|
+
command = command.wait(timeout=0)
|
|
374
|
+
if 'workload' not in command.spec:
|
|
375
|
+
raise exceptions.PlatformException(error='400',
|
|
376
|
+
message="workload key is missing in command response: {}"
|
|
377
|
+
.format(response))
|
|
378
|
+
|
|
379
|
+
task_assignments = task.assignments.list()
|
|
380
|
+
workers = list()
|
|
381
|
+
for worker in workload:
|
|
382
|
+
workers.append(worker.assignee_id.lower())
|
|
383
|
+
|
|
384
|
+
redistributed_assignments = list()
|
|
385
|
+
for ass in task_assignments:
|
|
386
|
+
if ass.annotator in workers:
|
|
387
|
+
redistributed_assignments.append(ass)
|
|
388
|
+
workers.remove(ass.annotator)
|
|
389
|
+
if not workers:
|
|
390
|
+
break
|
|
391
|
+
|
|
392
|
+
return miscellaneous.List(redistributed_assignments)
|
|
393
|
+
else:
|
|
394
|
+
raise exceptions.PlatformException(response)
|
|
395
|
+
|
|
396
|
+
@_api_reference.add(path='/assignments/{id}', method='patch')
|
|
397
|
+
def update(self,
|
|
398
|
+
assignment: entities.Assignment = None,
|
|
399
|
+
system_metadata: bool = False
|
|
400
|
+
) -> entities.Assignment:
|
|
401
|
+
"""
|
|
402
|
+
Update an assignment.
|
|
403
|
+
|
|
404
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
405
|
+
|
|
406
|
+
:param dtlpy.entities.assignment.Assignment assignment assignment: assignment entity
|
|
407
|
+
:param bool system_metadata: True, if you want to change metadata system
|
|
408
|
+
:return: Assignment object
|
|
409
|
+
:rtype: dtlpy.entities.assignment.Assignment assignment
|
|
410
|
+
|
|
411
|
+
**Example**:
|
|
412
|
+
|
|
413
|
+
.. code-block:: python
|
|
414
|
+
|
|
415
|
+
assignment = task.assignments.update(assignment='assignment_entity', system_metadata=False)
|
|
416
|
+
"""
|
|
417
|
+
url = '/assignments/{}'.format(assignment.id)
|
|
418
|
+
|
|
419
|
+
if system_metadata:
|
|
420
|
+
url += '?system=true'
|
|
421
|
+
|
|
422
|
+
success, response = self._client_api.gen_request(req_type='patch',
|
|
423
|
+
path=url,
|
|
424
|
+
json_req=assignment.to_json())
|
|
425
|
+
if success:
|
|
426
|
+
return entities.Assignment.from_json(_json=response.json(),
|
|
427
|
+
client_api=self._client_api, project=self._project,
|
|
428
|
+
dataset=self._dataset, task=self._task)
|
|
429
|
+
else:
|
|
430
|
+
raise exceptions.PlatformException(response)
|
|
431
|
+
|
|
432
|
+
def create(self,
|
|
433
|
+
assignee_id: str,
|
|
434
|
+
task: entities.Task = None,
|
|
435
|
+
filters: entities.Filters = None,
|
|
436
|
+
items: list = None) -> entities.Assignment:
|
|
437
|
+
"""
|
|
438
|
+
Create a new assignment.
|
|
439
|
+
|
|
440
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
441
|
+
|
|
442
|
+
:param str assignee_id: the email of the user that want to assign the assignment
|
|
443
|
+
:param dtlpy.entities.task.Task task: the task object that include the assignment
|
|
444
|
+
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
445
|
+
:param list items: list of items (item Id or objects) to insert to the assignment
|
|
446
|
+
:return: Assignment object
|
|
447
|
+
:rtype: dtlpy.entities.assignment.Assignment assignment
|
|
448
|
+
|
|
449
|
+
**Example**:
|
|
450
|
+
|
|
451
|
+
.. code-block:: python
|
|
452
|
+
|
|
453
|
+
assignment = task.assignments.create(assignee_id='annotator1@dataloop.ai')
|
|
454
|
+
"""
|
|
455
|
+
return self._create_in_task(assignee_id=assignee_id, task=task, filters=filters, items=items)
|
|
456
|
+
|
|
457
|
+
def _create_in_task(self, assignee_id, task, filters=None, items=None) -> entities.Assignment:
|
|
458
|
+
|
|
459
|
+
if task is None:
|
|
460
|
+
if self._task is None:
|
|
461
|
+
raise exceptions.PlatformException('400', 'Must provide task')
|
|
462
|
+
task = self._task
|
|
463
|
+
|
|
464
|
+
assignments_before = [ass.id for ass in task.assignments.list()]
|
|
465
|
+
|
|
466
|
+
if filters is None and items is None:
|
|
467
|
+
raise exceptions.PlatformException('400', 'Must provide either filters or items list')
|
|
468
|
+
|
|
469
|
+
workload = entities.Workload.generate(assignee_ids=[assignee_id])
|
|
470
|
+
task = task.add_items(filters=filters, items=items, workload=workload, limit=None)
|
|
471
|
+
assignments = [ass for ass in task.assignments.list() if ass.id not in assignments_before]
|
|
472
|
+
|
|
473
|
+
if len(assignments) < 1:
|
|
474
|
+
raise exceptions.PlatformException('Error creating an assignment, '
|
|
475
|
+
'Please use task.add_items() to perform this action')
|
|
476
|
+
|
|
477
|
+
return assignments[0]
|
|
478
|
+
|
|
479
|
+
def __item_operations(self, dataset: entities.Dataset,
|
|
480
|
+
op, assignment_id=None, assignment_name=None, filters=None, items=None):
|
|
481
|
+
if assignment_id is None and assignment_name is None:
|
|
482
|
+
raise exceptions.PlatformException('400', 'Must provide either assignment name or assignment id')
|
|
483
|
+
elif assignment_id is None:
|
|
484
|
+
assignment_id = self.get(assignment_name=assignment_name).id
|
|
485
|
+
|
|
486
|
+
try:
|
|
487
|
+
if filters is None and items is None:
|
|
488
|
+
raise exceptions.PlatformException('400', 'Must provide either filters or items list')
|
|
489
|
+
|
|
490
|
+
if filters is None:
|
|
491
|
+
if not isinstance(items, list):
|
|
492
|
+
items = [items]
|
|
493
|
+
filters = entities.Filters(field='id',
|
|
494
|
+
values=[item.id for item in items],
|
|
495
|
+
operator=entities.FiltersOperations.IN,
|
|
496
|
+
use_defaults=False)
|
|
497
|
+
|
|
498
|
+
filters._ref_assignment = True
|
|
499
|
+
filters._ref_assignment_id = assignment_id
|
|
500
|
+
filters._ref_op = op
|
|
501
|
+
|
|
502
|
+
return dataset.items.update(filters=filters)
|
|
503
|
+
finally:
|
|
504
|
+
if filters is not None:
|
|
505
|
+
filters._nullify_refs()
|
|
506
|
+
|
|
507
|
+
def get_items(self,
|
|
508
|
+
assignment: entities.Assignment = None,
|
|
509
|
+
assignment_id=None,
|
|
510
|
+
assignment_name=None,
|
|
511
|
+
dataset=None,
|
|
512
|
+
filters=None
|
|
513
|
+
) -> entities.PagedEntities:
|
|
514
|
+
"""
|
|
515
|
+
Get all the items in the assignment.
|
|
516
|
+
|
|
517
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
518
|
+
|
|
519
|
+
:param dtlpy.entities.assignment.Assignment assignment: assignment object
|
|
520
|
+
:param assignment_id: the Id of the assignment
|
|
521
|
+
:param str assignment_name: the name of the assignment
|
|
522
|
+
:param dtlpy.entities.dataset.Dataset dataset: dataset object, the dataset that refer to the assignment
|
|
523
|
+
:param dtlpy.entities.filters.Filters filters: Filters entity or a dictionary containing filters parameters
|
|
524
|
+
:return: pages of the items
|
|
525
|
+
:rtype: dtlpy.entities.paged_entities.PagedEntities
|
|
526
|
+
|
|
527
|
+
**Example**:
|
|
528
|
+
|
|
529
|
+
.. code-block:: python
|
|
530
|
+
|
|
531
|
+
items = task.assignments.get_items(assignment_id='assignment_id')
|
|
532
|
+
"""
|
|
533
|
+
if assignment is None and assignment_id is None and assignment_name is None:
|
|
534
|
+
raise exceptions.PlatformException('400',
|
|
535
|
+
'Please provide either assignment, assignment_id or assignment_name')
|
|
536
|
+
|
|
537
|
+
if assignment_id is None:
|
|
538
|
+
if assignment is None:
|
|
539
|
+
assignment = self.get(assignment_name=assignment_name)
|
|
540
|
+
assignment_id = assignment.id
|
|
541
|
+
|
|
542
|
+
if dataset is None and self._dataset is None:
|
|
543
|
+
if assignment is None:
|
|
544
|
+
assignment = self.get(assignment_id=assignment_id, assignment_name=assignment_name)
|
|
545
|
+
if assignment.dataset_id is None:
|
|
546
|
+
raise exceptions.PlatformException('400', 'Please provide a dataset entity')
|
|
547
|
+
dataset = repositories.Datasets(client_api=self._client_api, project=self._project).get(
|
|
548
|
+
dataset_id=assignment.dataset_id)
|
|
549
|
+
elif dataset is None:
|
|
550
|
+
dataset = self._dataset
|
|
551
|
+
|
|
552
|
+
if filters is None:
|
|
553
|
+
filters = entities.Filters(use_defaults=False)
|
|
554
|
+
filters.add(field='metadata.system.refs.id', values=[assignment_id], operator=entities.FiltersOperations.IN)
|
|
555
|
+
|
|
556
|
+
return dataset.items.list(filters=filters)
|
|
557
|
+
|
|
558
|
+
def set_status(self,
|
|
559
|
+
status: str,
|
|
560
|
+
operation: str,
|
|
561
|
+
item_id: str,
|
|
562
|
+
assignment_id: str
|
|
563
|
+
) -> bool:
|
|
564
|
+
"""
|
|
565
|
+
Set item status within assignment.
|
|
566
|
+
|
|
567
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned as *owner* of the annotation task.
|
|
568
|
+
|
|
569
|
+
:param str status: string the describes the status
|
|
570
|
+
:param str operation: the status action need 'create' or 'delete'
|
|
571
|
+
:param str item_id: item id that want to set his status
|
|
572
|
+
:param assignment_id: the Id of the assignment
|
|
573
|
+
:return: True id success
|
|
574
|
+
:rtype: bool
|
|
575
|
+
|
|
576
|
+
**Example**:
|
|
577
|
+
|
|
578
|
+
.. code-block:: python
|
|
579
|
+
|
|
580
|
+
success = task.assignments.set_status(assignment_id='assignment_id',
|
|
581
|
+
status='complete',
|
|
582
|
+
operation='created',
|
|
583
|
+
item_id='item_id')
|
|
584
|
+
"""
|
|
585
|
+
url = '/assignments/{assignment_id}/items/{item_id}/status'.format(assignment_id=assignment_id, item_id=item_id)
|
|
586
|
+
payload = {
|
|
587
|
+
'operation': operation,
|
|
588
|
+
'status': status
|
|
589
|
+
}
|
|
590
|
+
success, response = self._client_api.gen_request(
|
|
591
|
+
req_type='post',
|
|
592
|
+
path=url,
|
|
593
|
+
json_req=payload
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
if not success:
|
|
597
|
+
raise exceptions.PlatformException(response)
|
|
598
|
+
|
|
599
|
+
return True
|