dtlpy 1.114.13__py3-none-any.whl → 1.114.14__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 +4 -1
- dtlpy/__version__.py +1 -1
- dtlpy/assets/__pycache__/{__init__.cpython-38.pyc → __init__.cpython-310.pyc} +0 -0
- dtlpy/entities/__init__.py +1 -1
- dtlpy/entities/driver.py +3 -2
- dtlpy/entities/filters.py +165 -161
- dtlpy/entities/model.py +14 -24
- dtlpy/entities/paged_entities.py +14 -5
- dtlpy/entities/pipeline.py +31 -0
- dtlpy/entities/task.py +4 -0
- dtlpy/ml/base_model_adapter.py +208 -67
- dtlpy/new_instance.py +1 -1
- dtlpy/repositories/downloader.py +18 -10
- dtlpy/repositories/dpks.py +1 -1
- dtlpy/repositories/drivers.py +293 -81
- dtlpy/repositories/models.py +137 -26
- dtlpy/repositories/pipeline_executions.py +14 -11
- dtlpy/repositories/pipelines.py +179 -181
- dtlpy/repositories/tasks.py +711 -359
- {dtlpy-1.114.13.dist-info → dtlpy-1.114.14.dist-info}/METADATA +14 -3
- {dtlpy-1.114.13.dist-info → dtlpy-1.114.14.dist-info}/RECORD +28 -28
- {dtlpy-1.114.13.dist-info → dtlpy-1.114.14.dist-info}/WHEEL +1 -1
- {dtlpy-1.114.13.data → dtlpy-1.114.14.data}/scripts/dlp +0 -0
- {dtlpy-1.114.13.data → dtlpy-1.114.14.data}/scripts/dlp.bat +0 -0
- {dtlpy-1.114.13.data → dtlpy-1.114.14.data}/scripts/dlp.py +0 -0
- {dtlpy-1.114.13.dist-info → dtlpy-1.114.14.dist-info}/entry_points.txt +0 -0
- {dtlpy-1.114.13.dist-info → dtlpy-1.114.14.dist-info/licenses}/LICENSE +0 -0
- {dtlpy-1.114.13.dist-info → dtlpy-1.114.14.dist-info}/top_level.txt +0 -0
dtlpy/repositories/tasks.py
CHANGED
|
@@ -7,8 +7,8 @@ import warnings
|
|
|
7
7
|
from .. import exceptions, miscellaneous, entities, repositories, _api_reference
|
|
8
8
|
from ..services.api_client import ApiClient
|
|
9
9
|
|
|
10
|
-
logger = logging.getLogger(name=
|
|
11
|
-
URL_PATH =
|
|
10
|
+
logger = logging.getLogger(name="dtlpy")
|
|
11
|
+
URL_PATH = "/annotationtasks"
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class Tasks:
|
|
@@ -19,23 +19,17 @@ class Tasks:
|
|
|
19
19
|
For more information, read in our developers' documentation about `Creating Tasks <https://developers.dataloop.ai/tutorials/task_workflows/create_a_task/chapter/>`_, and `Redistributing and Reassigning Tasks <https://developers.dataloop.ai/tutorials/task_workflows/redistributing_and_reassigning_a_task/chapter/>`_.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
def __init__(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
client_api: ApiClient,
|
|
25
|
+
project: entities.Project = None,
|
|
26
|
+
dataset: entities.Dataset = None,
|
|
27
|
+
project_id: str = None,
|
|
28
|
+
):
|
|
27
29
|
self._client_api = client_api
|
|
28
30
|
self._project = project
|
|
29
31
|
self._dataset = dataset
|
|
30
32
|
self._assignments = None
|
|
31
|
-
if project_id is None:
|
|
32
|
-
if self._project is not None:
|
|
33
|
-
project_id = self._project.id
|
|
34
|
-
elif self._dataset is not None:
|
|
35
|
-
if self._dataset._project is not None:
|
|
36
|
-
project_id = self._dataset._project.id
|
|
37
|
-
elif isinstance(self._dataset.projects, list) and len(self._dataset.projects) > 0:
|
|
38
|
-
project_id = self._dataset.projects[0]
|
|
39
33
|
self._project_id = project_id
|
|
40
34
|
|
|
41
35
|
############
|
|
@@ -43,32 +37,38 @@ class Tasks:
|
|
|
43
37
|
############
|
|
44
38
|
@property
|
|
45
39
|
def project(self) -> entities.Project:
|
|
46
|
-
if self._project is None:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
if self._project is None and self._project_id is None:
|
|
41
|
+
if self._dataset is None:
|
|
42
|
+
raise exceptions.PlatformException(
|
|
43
|
+
error="2001",
|
|
44
|
+
message='Missing "project". need to set a Project entity or use project.tasks repository',
|
|
45
|
+
)
|
|
46
|
+
else:
|
|
47
|
+
self._project = self._dataset.project
|
|
48
|
+
self._project_id = self._project.id
|
|
49
|
+
if self._project is None and self._project_id is not None:
|
|
50
|
+
self._project = self._client_api.projects.get(project_id=self._project_id)
|
|
51
51
|
return self._project
|
|
52
52
|
|
|
53
53
|
@project.setter
|
|
54
54
|
def project(self, project: entities.Project):
|
|
55
55
|
if not isinstance(project, entities.Project):
|
|
56
|
-
raise ValueError(
|
|
56
|
+
raise ValueError("Must input a valid Project entity")
|
|
57
57
|
self._project = project
|
|
58
58
|
|
|
59
59
|
@property
|
|
60
60
|
def dataset(self) -> entities.Dataset:
|
|
61
61
|
if self._dataset is None:
|
|
62
62
|
raise exceptions.PlatformException(
|
|
63
|
-
error=
|
|
64
|
-
|
|
63
|
+
error="2001", message='Missing "dataset". need to set a Dataset entity or use dataset.tasks repository'
|
|
64
|
+
)
|
|
65
65
|
assert isinstance(self._dataset, entities.Dataset)
|
|
66
66
|
return self._dataset
|
|
67
67
|
|
|
68
68
|
@dataset.setter
|
|
69
69
|
def dataset(self, dataset: entities.Dataset):
|
|
70
70
|
if not isinstance(dataset, entities.Dataset):
|
|
71
|
-
raise ValueError(
|
|
71
|
+
raise ValueError("Must input a valid Dataset entity")
|
|
72
72
|
self._dataset = dataset
|
|
73
73
|
|
|
74
74
|
@property
|
|
@@ -79,18 +79,13 @@ class Tasks:
|
|
|
79
79
|
return self._assignments
|
|
80
80
|
|
|
81
81
|
def _build_entities_from_response(self, response_items) -> miscellaneous.List[entities.Task]:
|
|
82
|
-
pool = self._client_api.thread_pools(pool_name=
|
|
82
|
+
pool = self._client_api.thread_pools(pool_name="entity.create")
|
|
83
83
|
jobs = [None for _ in range(len(response_items))]
|
|
84
84
|
|
|
85
85
|
for i_task, task in enumerate(response_items):
|
|
86
86
|
jobs[i_task] = pool.submit(
|
|
87
87
|
entities.Task._protected_from_json,
|
|
88
|
-
**{
|
|
89
|
-
'client_api': self._client_api,
|
|
90
|
-
'_json': task,
|
|
91
|
-
'project': self._project,
|
|
92
|
-
'dataset': self._dataset
|
|
93
|
-
}
|
|
88
|
+
**{"client_api": self._client_api, "_json": task, "project": self._project, "dataset": self._dataset},
|
|
94
89
|
)
|
|
95
90
|
|
|
96
91
|
# get all results
|
|
@@ -102,14 +97,10 @@ class Tasks:
|
|
|
102
97
|
return tasks
|
|
103
98
|
|
|
104
99
|
def _list(self, filters: entities.Filters):
|
|
105
|
-
url =
|
|
100
|
+
url = "{}/query".format(URL_PATH)
|
|
106
101
|
query = filters.prepare()
|
|
107
|
-
query[
|
|
108
|
-
success, response = self._client_api.gen_request(
|
|
109
|
-
req_type='post',
|
|
110
|
-
path=url,
|
|
111
|
-
json_req=filters.prepare()
|
|
112
|
-
)
|
|
102
|
+
query["context"] = dict(projectIds=[self._project_id])
|
|
103
|
+
success, response = self._client_api.gen_request(req_type="post", path=url, json_req=filters.prepare())
|
|
113
104
|
|
|
114
105
|
if not success:
|
|
115
106
|
raise exceptions.PlatformException(response)
|
|
@@ -136,7 +127,7 @@ class Tasks:
|
|
|
136
127
|
if self._project_id is not None:
|
|
137
128
|
project_ids = self._project_id
|
|
138
129
|
else:
|
|
139
|
-
raise exceptions.PlatformException(
|
|
130
|
+
raise exceptions.PlatformException("400", "Please provide param project_ids")
|
|
140
131
|
|
|
141
132
|
if not isinstance(project_ids, list):
|
|
142
133
|
project_ids = [project_ids]
|
|
@@ -145,45 +136,47 @@ class Tasks:
|
|
|
145
136
|
filters = entities.Filters(resource=entities.FiltersResource.TASK)
|
|
146
137
|
else:
|
|
147
138
|
if not isinstance(filters, entities.Filters):
|
|
148
|
-
raise exceptions.PlatformException(
|
|
139
|
+
raise exceptions.PlatformException("400", "Unknown filters type")
|
|
149
140
|
if filters.resource != entities.FiltersResource.TASK:
|
|
150
|
-
raise exceptions.PlatformException(
|
|
141
|
+
raise exceptions.PlatformException("400", "Filter resource must be task")
|
|
151
142
|
|
|
152
143
|
if filters.context is None:
|
|
153
|
-
filters.context = {
|
|
144
|
+
filters.context = {"projectIds": project_ids}
|
|
154
145
|
|
|
155
146
|
if self._project_id is not None:
|
|
156
|
-
filters.add(field=
|
|
147
|
+
filters.add(field="projectId", values=self._project_id)
|
|
157
148
|
|
|
158
149
|
if self._dataset is not None:
|
|
159
|
-
filters.add(field=
|
|
160
|
-
|
|
161
|
-
paged = entities.PagedEntities(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
150
|
+
filters.add(field="datasetId", values=self._dataset.id)
|
|
151
|
+
|
|
152
|
+
paged = entities.PagedEntities(
|
|
153
|
+
items_repository=self,
|
|
154
|
+
filters=filters,
|
|
155
|
+
page_offset=filters.page,
|
|
156
|
+
page_size=filters.page_size,
|
|
157
|
+
project_id=self._project_id,
|
|
158
|
+
client_api=self._client_api,
|
|
159
|
+
)
|
|
167
160
|
paged.get_page()
|
|
168
161
|
return paged
|
|
169
162
|
|
|
170
163
|
###########
|
|
171
164
|
# methods #
|
|
172
165
|
###########
|
|
173
|
-
@_api_reference.add(path=
|
|
166
|
+
@_api_reference.add(path="/annotationtasks/query", method="post")
|
|
174
167
|
def list(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
168
|
+
self,
|
|
169
|
+
project_ids=None,
|
|
170
|
+
status=None,
|
|
171
|
+
task_name=None,
|
|
172
|
+
pages_size=None,
|
|
173
|
+
page_offset=None,
|
|
174
|
+
recipe=None,
|
|
175
|
+
creator=None,
|
|
176
|
+
assignments=None,
|
|
177
|
+
min_date=None,
|
|
178
|
+
max_date=None,
|
|
179
|
+
filters: entities.Filters = None,
|
|
187
180
|
) -> Union[miscellaneous.List[entities.Task], entities.PagedEntities]:
|
|
188
181
|
"""
|
|
189
182
|
List all tasks.
|
|
@@ -210,7 +203,7 @@ class Tasks:
|
|
|
210
203
|
dataset.tasks.list(project_ids='project_ids',pages_size=100, page_offset=0)
|
|
211
204
|
"""
|
|
212
205
|
# url
|
|
213
|
-
url = URL_PATH +
|
|
206
|
+
url = URL_PATH + "/query"
|
|
214
207
|
|
|
215
208
|
if filters is None:
|
|
216
209
|
filters = entities.Filters(use_defaults=False, resource=entities.FiltersResource.TASK)
|
|
@@ -218,7 +211,7 @@ class Tasks:
|
|
|
218
211
|
return self.query(filters=filters, project_ids=project_ids)
|
|
219
212
|
|
|
220
213
|
if self._dataset is not None:
|
|
221
|
-
filters.add(field=
|
|
214
|
+
filters.add(field="datasetId", values=self._dataset.id)
|
|
222
215
|
|
|
223
216
|
if project_ids is not None:
|
|
224
217
|
if not isinstance(project_ids, list):
|
|
@@ -226,7 +219,7 @@ class Tasks:
|
|
|
226
219
|
elif self._project_id is not None:
|
|
227
220
|
project_ids = [self._project_id]
|
|
228
221
|
else:
|
|
229
|
-
raise (
|
|
222
|
+
raise exceptions.PlatformException("400", "Must provide project")
|
|
230
223
|
filters.context = {"projectIds": project_ids}
|
|
231
224
|
|
|
232
225
|
if assignments is not None:
|
|
@@ -234,12 +227,13 @@ class Tasks:
|
|
|
234
227
|
assignments = [assignments]
|
|
235
228
|
assignments = [
|
|
236
229
|
assignments_entity.id if isinstance(assignments_entity, entities.Assignment) else assignments_entity
|
|
237
|
-
for assignments_entity in assignments
|
|
238
|
-
|
|
230
|
+
for assignments_entity in assignments
|
|
231
|
+
]
|
|
232
|
+
filters.add(field="assignmentIds", values=assignments, operator=entities.FiltersOperations.IN)
|
|
239
233
|
if status is not None:
|
|
240
|
-
filters.add(field=
|
|
234
|
+
filters.add(field="status", values=status)
|
|
241
235
|
if task_name is not None:
|
|
242
|
-
filters.add(field=
|
|
236
|
+
filters.add(field="name", values=task_name)
|
|
243
237
|
if pages_size is not None:
|
|
244
238
|
filters.page_size = pages_size
|
|
245
239
|
if pages_size is None:
|
|
@@ -249,31 +243,35 @@ class Tasks:
|
|
|
249
243
|
if recipe is not None:
|
|
250
244
|
if not isinstance(recipe, list):
|
|
251
245
|
recipe = [recipe]
|
|
252
|
-
recipe = [
|
|
253
|
-
|
|
254
|
-
|
|
246
|
+
recipe = [
|
|
247
|
+
recipe_entity.id if isinstance(recipe_entity, entities.Recipe) else recipe_entity
|
|
248
|
+
for recipe_entity in recipe
|
|
249
|
+
]
|
|
250
|
+
filters.add(field="recipeId", values=recipe, operator=entities.FiltersOperations.IN)
|
|
255
251
|
if creator is not None:
|
|
256
|
-
filters.add(field=
|
|
252
|
+
filters.add(field="creator", values=creator)
|
|
257
253
|
if min_date is not None:
|
|
258
|
-
filters.add(field=
|
|
254
|
+
filters.add(field="dueDate", values=min_date, operator=entities.FiltersOperations.GREATER_THAN)
|
|
259
255
|
if max_date is not None:
|
|
260
|
-
filters.add(field=
|
|
256
|
+
filters.add(field="dueDate", values=max_date, operator=entities.FiltersOperations.LESS_THAN)
|
|
261
257
|
|
|
262
|
-
success, response = self._client_api.gen_request(req_type=
|
|
263
|
-
path=url,
|
|
264
|
-
json_req=filters.prepare())
|
|
258
|
+
success, response = self._client_api.gen_request(req_type="post", path=url, json_req=filters.prepare())
|
|
265
259
|
if success:
|
|
266
260
|
tasks = miscellaneous.List(
|
|
267
|
-
[
|
|
268
|
-
|
|
269
|
-
|
|
261
|
+
[
|
|
262
|
+
entities.Task.from_json(
|
|
263
|
+
client_api=self._client_api, _json=_json, project=self._project, dataset=self._dataset
|
|
264
|
+
)
|
|
265
|
+
for _json in response.json()["items"]
|
|
266
|
+
]
|
|
267
|
+
)
|
|
270
268
|
else:
|
|
271
|
-
logger.error(
|
|
269
|
+
logger.error("Platform error getting annotation task")
|
|
272
270
|
raise exceptions.PlatformException(response)
|
|
273
271
|
|
|
274
272
|
return tasks
|
|
275
273
|
|
|
276
|
-
@_api_reference.add(path=
|
|
274
|
+
@_api_reference.add(path="/annotationtasks/{id}", method="get")
|
|
277
275
|
def get(self, task_name=None, task_id=None) -> entities.Task:
|
|
278
276
|
"""
|
|
279
277
|
Get a Task object to use in your code.
|
|
@@ -296,48 +294,43 @@ class Tasks:
|
|
|
296
294
|
url = URL_PATH
|
|
297
295
|
|
|
298
296
|
if task_id is not None:
|
|
299
|
-
url =
|
|
300
|
-
success, response = self._client_api.gen_request(req_type=
|
|
301
|
-
path=url)
|
|
297
|
+
url = "{}/{}".format(url, task_id)
|
|
298
|
+
success, response = self._client_api.gen_request(req_type="get", path=url)
|
|
302
299
|
if not success:
|
|
303
300
|
raise exceptions.PlatformException(response)
|
|
304
301
|
else:
|
|
305
|
-
task = entities.Task.from_json(
|
|
306
|
-
|
|
307
|
-
|
|
302
|
+
task = entities.Task.from_json(
|
|
303
|
+
_json=response.json(), client_api=self._client_api, project=self._project, dataset=self._dataset
|
|
304
|
+
)
|
|
308
305
|
# verify input task name is same as the given id
|
|
309
306
|
if task_name is not None and task.name != task_name:
|
|
310
307
|
logger.warning(
|
|
311
308
|
"Mismatch found in tasks.get: task_name is different then task.name:"
|
|
312
|
-
" {!r} != {!r}".format(
|
|
313
|
-
|
|
314
|
-
task.name))
|
|
309
|
+
" {!r} != {!r}".format(task_name, task.name)
|
|
310
|
+
)
|
|
315
311
|
elif task_name is not None:
|
|
316
|
-
tasks = self.list(
|
|
317
|
-
|
|
318
|
-
|
|
312
|
+
tasks = self.list(
|
|
313
|
+
filters=entities.Filters(field="name", values=task_name, resource=entities.FiltersResource.TASK)
|
|
314
|
+
)
|
|
319
315
|
if tasks.items_count == 0:
|
|
320
|
-
raise exceptions.PlatformException(
|
|
316
|
+
raise exceptions.PlatformException("404", "Annotation task not found")
|
|
321
317
|
elif tasks.items_count > 1:
|
|
322
|
-
raise exceptions.PlatformException(
|
|
323
|
-
|
|
324
|
-
|
|
318
|
+
raise exceptions.PlatformException(
|
|
319
|
+
"404", f"More than one Annotation task exist with the same name: {task_name}"
|
|
320
|
+
)
|
|
325
321
|
else:
|
|
326
322
|
task = tasks[0][0]
|
|
327
323
|
else:
|
|
328
|
-
raise exceptions.PlatformException(
|
|
324
|
+
raise exceptions.PlatformException("400", "Must provide either Annotation task name or Annotation task id")
|
|
329
325
|
|
|
330
326
|
assert isinstance(task, entities.Task)
|
|
331
327
|
return task
|
|
332
328
|
|
|
333
329
|
@property
|
|
334
330
|
def platform_url(self):
|
|
335
|
-
return self._client_api._get_resource_url("projects/{
|
|
331
|
+
return self._client_api._get_resource_url(f"projects/{self.project.id}/tasks")
|
|
336
332
|
|
|
337
|
-
def open_in_web(self,
|
|
338
|
-
task_name: str = None,
|
|
339
|
-
task_id: str = None,
|
|
340
|
-
task: entities.Task = None):
|
|
333
|
+
def open_in_web(self, task_name: str = None, task_id: str = None, task: entities.Task = None):
|
|
341
334
|
"""
|
|
342
335
|
Open the task in the web platform.
|
|
343
336
|
|
|
@@ -358,16 +351,12 @@ class Tasks:
|
|
|
358
351
|
if task is not None:
|
|
359
352
|
task.open_in_web()
|
|
360
353
|
elif task_id is not None:
|
|
361
|
-
self._client_api._open_in_web(url=self.platform_url +
|
|
354
|
+
self._client_api._open_in_web(url=self.platform_url + "/" + str(task_id))
|
|
362
355
|
else:
|
|
363
356
|
self._client_api._open_in_web(url=self.platform_url)
|
|
364
357
|
|
|
365
|
-
@_api_reference.add(path=
|
|
366
|
-
def delete(self,
|
|
367
|
-
task: entities.Task = None,
|
|
368
|
-
task_name: str = None,
|
|
369
|
-
task_id: str = None,
|
|
370
|
-
wait: bool = True):
|
|
358
|
+
@_api_reference.add(path="/annotationtasks/{id}", method="delete")
|
|
359
|
+
def delete(self, task: entities.Task = None, task_name: str = None, task_id: str = None, wait: bool = True):
|
|
371
360
|
"""
|
|
372
361
|
Delete the Task.
|
|
373
362
|
|
|
@@ -389,38 +378,32 @@ class Tasks:
|
|
|
389
378
|
if task_id is None:
|
|
390
379
|
if task is None:
|
|
391
380
|
if task_name is None:
|
|
392
|
-
raise exceptions.PlatformException(
|
|
393
|
-
|
|
394
|
-
|
|
381
|
+
raise exceptions.PlatformException(
|
|
382
|
+
"400", "Must provide either annotation task, " "annotation task name or annotation task id"
|
|
383
|
+
)
|
|
395
384
|
else:
|
|
396
385
|
task = self.get(task_name=task_name)
|
|
397
386
|
task_id = task.id
|
|
398
387
|
|
|
399
388
|
url = URL_PATH
|
|
400
|
-
url =
|
|
401
|
-
success, response = self._client_api.gen_request(req_type=
|
|
402
|
-
path=url,
|
|
403
|
-
json_req={'asynced': wait})
|
|
389
|
+
url = f"{url}/{task_id}"
|
|
390
|
+
success, response = self._client_api.gen_request(req_type="delete", path=url, json_req={"asynced": wait})
|
|
404
391
|
|
|
405
392
|
if not success:
|
|
406
393
|
raise exceptions.PlatformException(response)
|
|
407
394
|
response_json = response.json()
|
|
408
|
-
command = entities.Command.from_json(_json=response_json,
|
|
409
|
-
client_api=self._client_api)
|
|
395
|
+
command = entities.Command.from_json(_json=response_json, client_api=self._client_api)
|
|
410
396
|
if not wait:
|
|
411
397
|
return command
|
|
412
398
|
command = command.wait(timeout=0)
|
|
413
|
-
if
|
|
414
|
-
raise exceptions.PlatformException(
|
|
415
|
-
|
|
416
|
-
|
|
399
|
+
if "deleteTaskId" not in command.spec:
|
|
400
|
+
raise exceptions.PlatformException(
|
|
401
|
+
error="400", message="deleteTaskId key is missing in command response: {}".format(response)
|
|
402
|
+
)
|
|
417
403
|
return True
|
|
418
404
|
|
|
419
|
-
@_api_reference.add(path=
|
|
420
|
-
def update(self,
|
|
421
|
-
task: entities.Task = None,
|
|
422
|
-
system_metadata=False
|
|
423
|
-
) -> entities.Task:
|
|
405
|
+
@_api_reference.add(path="/annotationtasks/{id}", method="patch")
|
|
406
|
+
def update(self, task: entities.Task = None, system_metadata=False) -> entities.Task:
|
|
424
407
|
"""
|
|
425
408
|
Update a Task.
|
|
426
409
|
|
|
@@ -438,17 +421,19 @@ class Tasks:
|
|
|
438
421
|
dataset.tasks.update(task='task_entity')
|
|
439
422
|
"""
|
|
440
423
|
url = URL_PATH
|
|
441
|
-
url =
|
|
424
|
+
url = f"{url}/{task.id}"
|
|
442
425
|
|
|
443
426
|
if system_metadata:
|
|
444
|
-
warnings.warn(
|
|
427
|
+
warnings.warn(
|
|
428
|
+
"Task system metadata updates are not permitted. Please store custom metadata in 'task.metadata['user']' instead.",
|
|
429
|
+
DeprecationWarning,
|
|
430
|
+
)
|
|
445
431
|
|
|
446
|
-
success, response = self._client_api.gen_request(req_type=
|
|
447
|
-
path=url,
|
|
448
|
-
json_req=task.to_json())
|
|
432
|
+
success, response = self._client_api.gen_request(req_type="patch", path=url, json_req=task.to_json())
|
|
449
433
|
if success:
|
|
450
|
-
return entities.Task.from_json(
|
|
451
|
-
|
|
434
|
+
return entities.Task.from_json(
|
|
435
|
+
_json=response.json(), client_api=self._client_api, project=self._project, dataset=self._dataset
|
|
436
|
+
)
|
|
452
437
|
else:
|
|
453
438
|
raise exceptions.PlatformException(response)
|
|
454
439
|
|
|
@@ -550,45 +535,450 @@ class Tasks:
|
|
|
550
535
|
priority=priority
|
|
551
536
|
)
|
|
552
537
|
|
|
538
|
+
def create_honeypot_task(
|
|
539
|
+
self,
|
|
540
|
+
name: str,
|
|
541
|
+
dataset: entities.Dataset = None,
|
|
542
|
+
due_date: float = None,
|
|
543
|
+
filters: entities.Filters = None,
|
|
544
|
+
owner: str = None,
|
|
545
|
+
recipe_id: str = None,
|
|
546
|
+
assignee_ids: List[str] = None,
|
|
547
|
+
workload=None,
|
|
548
|
+
available_actions=None,
|
|
549
|
+
priority=entities.TaskPriority.MEDIUM,
|
|
550
|
+
consensus_percentage=None,
|
|
551
|
+
consensus_assignees=None,
|
|
552
|
+
scoring=True,
|
|
553
|
+
limit=None,
|
|
554
|
+
wait=True,
|
|
555
|
+
enforce_video_conversion=True,
|
|
556
|
+
) -> entities.Task:
|
|
557
|
+
"""
|
|
558
|
+
Create a new Consensus Task.
|
|
559
|
+
|
|
560
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned to be *owner* of the annotation task.
|
|
561
|
+
|
|
562
|
+
:param str name: the name of the task
|
|
563
|
+
:param entities.Dataset dataset: dataset object, the dataset that refer to the task
|
|
564
|
+
:param float due_date: date by which the task should be finished; for example, due_date=datetime.datetime(day=1, month=1, year=2029).timestamp()
|
|
565
|
+
:param entities.Filters filters: dl.Filters entity to filter items for the task
|
|
566
|
+
:param str owner: task owner. Provide user email
|
|
567
|
+
:param str recipe_id: recipe id for the task
|
|
568
|
+
:param list assignee_ids: list the task assignees (contributors) that should be working on the task. Provide a list of users' emails
|
|
569
|
+
:param workload: list of WorkloadUnit objects. Customize distribution (percentage) between the task assignees
|
|
570
|
+
:param list available_actions: list of available actions (statuses) that will be available for the task items
|
|
571
|
+
:param entities.TaskPriority priority: priority of the task options in entities.TaskPriority
|
|
572
|
+
:param str consensus_task_type: consensus task type - "consensus", "qualification", or "honeypot"
|
|
573
|
+
:param int consensus_percentage: percentage of items to be copied to multiple annotators (consensus items)
|
|
574
|
+
:param int consensus_assignees: the number of different annotators per item (number of copies per item)
|
|
575
|
+
:param bool scoring: create a scoring app in project
|
|
576
|
+
:param int limit: the limit items that the task can include
|
|
577
|
+
:param bool wait: wait until create task finish
|
|
578
|
+
:param bool enforce_video_conversion: Enforce WEBM conversion on video items for frame-accurate annotations
|
|
579
|
+
:return: Task object
|
|
580
|
+
:rtype: dtlpy.entities.task.Task
|
|
581
|
+
|
|
582
|
+
**Example**:
|
|
583
|
+
|
|
584
|
+
.. code-block:: python
|
|
585
|
+
|
|
586
|
+
# Create a consensus task
|
|
587
|
+
dataset.tasks.create_consensus_task(name='my_consensus_task',
|
|
588
|
+
assignee_ids=['annotator1@dataloop.ai', 'annotator2@dataloop.ai'],
|
|
589
|
+
consensus_percentage=66,
|
|
590
|
+
consensus_assignees=2)
|
|
591
|
+
"""
|
|
592
|
+
return self.create_consensus_task(
|
|
593
|
+
name=name,
|
|
594
|
+
dataset=dataset,
|
|
595
|
+
due_date=due_date,
|
|
596
|
+
filters=filters,
|
|
597
|
+
owner=owner,
|
|
598
|
+
recipe_id=recipe_id,
|
|
599
|
+
assignee_ids=assignee_ids,
|
|
600
|
+
workload=workload,
|
|
601
|
+
available_actions=available_actions,
|
|
602
|
+
priority=priority,
|
|
603
|
+
consensus_task_type=entities.ConsensusTaskType.HONEYPOT,
|
|
604
|
+
consensus_percentage=consensus_percentage,
|
|
605
|
+
consensus_assignees=consensus_assignees,
|
|
606
|
+
scoring=scoring,
|
|
607
|
+
limit=limit,
|
|
608
|
+
wait=wait,
|
|
609
|
+
enforce_video_conversion=enforce_video_conversion,
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
def create_qualification_task(
|
|
613
|
+
self,
|
|
614
|
+
name: str,
|
|
615
|
+
dataset: entities.Dataset = None,
|
|
616
|
+
due_date: float = None,
|
|
617
|
+
filters: entities.Filters = None,
|
|
618
|
+
owner: str = None,
|
|
619
|
+
recipe_id: str = None,
|
|
620
|
+
assignee_ids: List[str] = None,
|
|
621
|
+
workload=None,
|
|
622
|
+
available_actions=None,
|
|
623
|
+
priority=entities.TaskPriority.MEDIUM,
|
|
624
|
+
consensus_percentage=None,
|
|
625
|
+
consensus_assignees=None,
|
|
626
|
+
limit=None,
|
|
627
|
+
wait=True,
|
|
628
|
+
enforce_video_conversion=True,
|
|
629
|
+
) -> entities.Task:
|
|
630
|
+
"""
|
|
631
|
+
Create a new Qualification Task.
|
|
632
|
+
"""
|
|
633
|
+
return self.create_consensus_task(
|
|
634
|
+
name=name,
|
|
635
|
+
dataset=dataset,
|
|
636
|
+
due_date=due_date,
|
|
637
|
+
filters=filters,
|
|
638
|
+
owner=owner,
|
|
639
|
+
recipe_id=recipe_id,
|
|
640
|
+
assignee_ids=assignee_ids,
|
|
641
|
+
workload=workload,
|
|
642
|
+
available_actions=available_actions,
|
|
643
|
+
priority=priority,
|
|
644
|
+
consensus_task_type=entities.ConsensusTaskType.QUALIFICATION,
|
|
645
|
+
consensus_percentage=consensus_percentage,
|
|
646
|
+
consensus_assignees=consensus_assignees,
|
|
647
|
+
scoring=True,
|
|
648
|
+
limit=limit,
|
|
649
|
+
wait=wait,
|
|
650
|
+
enforce_video_conversion=enforce_video_conversion,
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
def create_consensus_task(
|
|
654
|
+
self,
|
|
655
|
+
name: str,
|
|
656
|
+
dataset: entities.Dataset = None,
|
|
657
|
+
due_date: float = None,
|
|
658
|
+
filters: entities.Filters = None,
|
|
659
|
+
owner: str = None,
|
|
660
|
+
recipe_id: str = None,
|
|
661
|
+
assignee_ids: List[str] = None,
|
|
662
|
+
workload=None,
|
|
663
|
+
available_actions=None,
|
|
664
|
+
priority=entities.TaskPriority.MEDIUM,
|
|
665
|
+
metadata=None,
|
|
666
|
+
consensus_task_type: entities.ConsensusTaskType = entities.ConsensusTaskType.CONSENSUS,
|
|
667
|
+
consensus_percentage=None,
|
|
668
|
+
consensus_assignees=None,
|
|
669
|
+
scoring=True,
|
|
670
|
+
limit=None,
|
|
671
|
+
wait=True,
|
|
672
|
+
enforce_video_conversion=True,
|
|
673
|
+
) -> entities.Task:
|
|
674
|
+
"""
|
|
675
|
+
Create a new Consensus Task.
|
|
676
|
+
|
|
677
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned to be *owner* of the annotation task.
|
|
678
|
+
|
|
679
|
+
:param str name: the name of the task
|
|
680
|
+
:param entities.Dataset dataset: dataset object, the dataset that refer to the task
|
|
681
|
+
:param float due_date: date by which the task should be finished; for example, due_date=datetime.datetime(day=1, month=1, year=2029).timestamp()
|
|
682
|
+
:param entities.Filters filters: dl.Filters entity to filter items for the task
|
|
683
|
+
:param str owner: task owner. Provide user email
|
|
684
|
+
:param str recipe_id: recipe id for the task
|
|
685
|
+
:param list assignee_ids: list the task assignees (contributors) that should be working on the task. Provide a list of users' emails
|
|
686
|
+
:param workload: list of WorkloadUnit objects. Customize distribution (percentage) between the task assignees
|
|
687
|
+
:param list available_actions: list of available actions (statuses) that will be available for the task items
|
|
688
|
+
:param entities.TaskPriority priority: priority of the task options in entities.TaskPriority
|
|
689
|
+
:param dict metadata: metadata for the task
|
|
690
|
+
:param str consensus_task_type: consensus task type - "consensus", "qualification", or "honeypot"
|
|
691
|
+
:param int consensus_percentage: percentage of items to be copied to multiple annotators (consensus items)
|
|
692
|
+
:param int consensus_assignees: the number of different annotators per item (number of copies per item)
|
|
693
|
+
:param bool scoring: create a scoring app in project
|
|
694
|
+
:param int limit: the limit items that the task can include
|
|
695
|
+
:param bool wait: wait until create task finish
|
|
696
|
+
:param bool enforce_video_conversion: Enforce WEBM conversion on video items for frame-accurate annotations
|
|
697
|
+
:return: Task object
|
|
698
|
+
:rtype: dtlpy.entities.task.Task
|
|
699
|
+
|
|
700
|
+
**Example**:
|
|
701
|
+
|
|
702
|
+
.. code-block:: python
|
|
703
|
+
|
|
704
|
+
# Create a consensus task
|
|
705
|
+
dataset.tasks.create_consensus_task(name='my_consensus_task',
|
|
706
|
+
assignee_ids=['annotator1@dataloop.ai', 'annotator2@dataloop.ai'],
|
|
707
|
+
consensus_percentage=66,
|
|
708
|
+
consensus_assignees=2)
|
|
709
|
+
"""
|
|
710
|
+
|
|
711
|
+
if dataset is None:
|
|
712
|
+
dataset = self.dataset
|
|
713
|
+
|
|
714
|
+
if due_date is None:
|
|
715
|
+
due_date = (datetime.datetime.now() + datetime.timedelta(days=7)).timestamp()
|
|
716
|
+
|
|
717
|
+
if filters is None:
|
|
718
|
+
filters = entities.Filters()
|
|
719
|
+
|
|
720
|
+
if owner is None:
|
|
721
|
+
owner = self._client_api.info()["user_email"]
|
|
722
|
+
|
|
723
|
+
if recipe_id is None:
|
|
724
|
+
recipe_id = dataset.get_recipe_ids()[0]
|
|
725
|
+
|
|
726
|
+
if workload is None and assignee_ids is not None:
|
|
727
|
+
workload = entities.Workload.generate(assignee_ids=assignee_ids)
|
|
728
|
+
|
|
729
|
+
# Handle metadata for consensus tasks
|
|
730
|
+
if metadata is None:
|
|
731
|
+
metadata = {}
|
|
732
|
+
if "system" not in metadata:
|
|
733
|
+
metadata["system"] = {}
|
|
734
|
+
if assignee_ids is not None:
|
|
735
|
+
metadata["system"]["allowedAssignees"] = assignee_ids
|
|
736
|
+
if consensus_task_type is not None:
|
|
737
|
+
metadata["system"]["consensusTaskType"] = consensus_task_type
|
|
738
|
+
metadata = self._add_task_metadata_params(
|
|
739
|
+
metadata=metadata, input_value=consensus_percentage, input_name="consensusPercentage"
|
|
740
|
+
)
|
|
741
|
+
metadata = self._add_task_metadata_params(
|
|
742
|
+
metadata=metadata, input_value=consensus_assignees, input_name="consensusAssignees"
|
|
743
|
+
)
|
|
744
|
+
metadata = self._add_task_metadata_params(metadata=metadata, input_value=scoring, input_name="scoring")
|
|
745
|
+
|
|
746
|
+
# Create payload for consensus task
|
|
747
|
+
payload = {
|
|
748
|
+
"name": name,
|
|
749
|
+
"query": "{}".format(json.dumps(filters.prepare()).replace("'", '"')),
|
|
750
|
+
"taskOwner": owner,
|
|
751
|
+
"spec": {"type": "annotation"},
|
|
752
|
+
"datasetId": dataset.id,
|
|
753
|
+
"projectId": self.project.id,
|
|
754
|
+
"assignmentIds": [],
|
|
755
|
+
"recipeId": recipe_id,
|
|
756
|
+
"dueDate": due_date * 1000,
|
|
757
|
+
"asynced": wait,
|
|
758
|
+
"priority": priority,
|
|
759
|
+
"percentage": True,
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
# Add workload if provided
|
|
763
|
+
if workload:
|
|
764
|
+
payload["workload"] = workload.to_json()
|
|
765
|
+
|
|
766
|
+
# Add limit if provided
|
|
767
|
+
if limit:
|
|
768
|
+
payload["limit"] = limit
|
|
769
|
+
|
|
770
|
+
# Add available actions if provided
|
|
771
|
+
if available_actions is not None:
|
|
772
|
+
payload["availableActions"] = [action.to_json() for action in available_actions]
|
|
773
|
+
|
|
774
|
+
# Handle video conversion
|
|
775
|
+
if not enforce_video_conversion:
|
|
776
|
+
payload["disableWebm"] = not enforce_video_conversion
|
|
777
|
+
|
|
778
|
+
# Handle metadata for consensus tasks
|
|
779
|
+
if metadata is not None:
|
|
780
|
+
payload["metadata"] = metadata
|
|
781
|
+
|
|
782
|
+
return self._create_task(payload, wait=wait)
|
|
783
|
+
|
|
553
784
|
def _add_task_metadata_params(self, metadata, input_value, input_name):
|
|
554
785
|
if input_value is not None and not isinstance(input_value, int):
|
|
555
|
-
raise exceptions.PlatformException(error=
|
|
556
|
-
message="{} must be a numbers".format(input_name))
|
|
786
|
+
raise exceptions.PlatformException(error="400", message=f"{input_name} must be a numbers")
|
|
557
787
|
if input_value is not None:
|
|
558
|
-
metadata[
|
|
788
|
+
metadata["system"][input_name] = input_value
|
|
559
789
|
return metadata
|
|
560
790
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
791
|
+
def create_labeling_task(
|
|
792
|
+
self,
|
|
793
|
+
name: str,
|
|
794
|
+
dataset: entities.Dataset = None,
|
|
795
|
+
due_date: float = None,
|
|
796
|
+
filters: entities.Filters = None,
|
|
797
|
+
owner: str = None,
|
|
798
|
+
recipe_id: str = None,
|
|
799
|
+
assignee_ids: List[str] = None,
|
|
800
|
+
workload=None,
|
|
801
|
+
available_actions=None,
|
|
802
|
+
priority=entities.TaskPriority.MEDIUM,
|
|
803
|
+
metadata=None,
|
|
804
|
+
batch_size=None,
|
|
805
|
+
max_batch_workload=None,
|
|
806
|
+
allowed_assignees=None,
|
|
807
|
+
limit=None,
|
|
808
|
+
wait=True,
|
|
809
|
+
enforce_video_conversion=True,
|
|
810
|
+
) -> entities.Task:
|
|
811
|
+
"""
|
|
812
|
+
Create a new Annotation Task (Distribution or Pulling).
|
|
813
|
+
|
|
814
|
+
**Prerequisites**: You must be in the role of an *owner*, *developer*, or *annotation manager* who has been assigned to be *owner* of the annotation task.
|
|
815
|
+
|
|
816
|
+
:param str name: the name of the task
|
|
817
|
+
:param entities.Dataset dataset: dataset object, the dataset that refer to the task
|
|
818
|
+
:param float due_date: date by which the task should be finished; for example, due_date=datetime.datetime(day=1, month=1, year=2029).timestamp()
|
|
819
|
+
:param entities.Filters filters: dl.Filters entity to filter items for the task
|
|
820
|
+
:param str owner: task owner. Provide user email
|
|
821
|
+
:param str recipe_id: recipe id for the task
|
|
822
|
+
:param list assignee_ids: list the task assignees (contributors) that should be working on the task. Provide a list of users' emails
|
|
823
|
+
:param workload: list of WorkloadUnit objects. Customize distribution (percentage) between the task assignees
|
|
824
|
+
:param list available_actions: list of available actions (statuses) that will be available for the task items
|
|
825
|
+
:param entities.TaskPriority priority: priority of the task options in entities.TaskPriority
|
|
826
|
+
:param dict metadata: metadata for the task
|
|
827
|
+
:param int batch_size: Pulling batch size (items), use with pulling allocation method. Restrictions - Min 3, max 100
|
|
828
|
+
:param int max_batch_workload: Max items in assignment, use with pulling allocation method. Restrictions - Min batchSize + 2, max batchSize * 2
|
|
829
|
+
:param list allowed_assignees: list the task assignees (contributors) that should be working on the task. Provide a list of users' emails
|
|
830
|
+
:param int limit: the limit items that the task can include
|
|
831
|
+
:param bool wait: wait until create task finish
|
|
832
|
+
:param bool enforce_video_conversion: Enforce WEBM conversion on video items for frame-accurate annotations
|
|
833
|
+
:return: Task object
|
|
834
|
+
:rtype: dtlpy.entities.task.Task
|
|
835
|
+
|
|
836
|
+
**Example**:
|
|
837
|
+
|
|
838
|
+
.. code-block:: python
|
|
839
|
+
|
|
840
|
+
# Create a distribution task
|
|
841
|
+
dataset.tasks.create_labeling(name='my_distribution_task',
|
|
842
|
+
assignee_ids=['annotator1@dataloop.ai', 'annotator2@dataloop.ai'])
|
|
843
|
+
|
|
844
|
+
# Create a pulling task
|
|
845
|
+
dataset.tasks.create_labeling(name='my_pulling_task',
|
|
846
|
+
assignee_ids=['annotator1@dataloop.ai', 'annotator2@dataloop.ai'],
|
|
847
|
+
batch_size=5,
|
|
848
|
+
max_batch_workload=7)
|
|
849
|
+
"""
|
|
850
|
+
|
|
851
|
+
if dataset is None:
|
|
852
|
+
dataset = self.dataset
|
|
853
|
+
|
|
854
|
+
if due_date is None:
|
|
855
|
+
due_date = (datetime.datetime.now() + datetime.timedelta(days=7)).timestamp()
|
|
856
|
+
|
|
857
|
+
if filters is None:
|
|
858
|
+
filters = entities.Filters()
|
|
859
|
+
|
|
860
|
+
if owner is None:
|
|
861
|
+
owner = self._client_api.info()["user_email"]
|
|
862
|
+
|
|
863
|
+
if recipe_id is None:
|
|
864
|
+
recipe_id = dataset.get_recipe_ids()[0]
|
|
865
|
+
|
|
866
|
+
if workload is None and assignee_ids is not None:
|
|
867
|
+
workload = entities.Workload.generate(assignee_ids=assignee_ids)
|
|
868
|
+
|
|
869
|
+
if metadata is None:
|
|
870
|
+
metadata = {}
|
|
871
|
+
if any([batch_size, max_batch_workload]):
|
|
872
|
+
if "system" not in metadata:
|
|
873
|
+
metadata["system"] = {}
|
|
874
|
+
if allowed_assignees is not None or assignee_ids is not None:
|
|
875
|
+
metadata["system"]["allowedAssignees"] = allowed_assignees if allowed_assignees else assignee_ids
|
|
876
|
+
metadata = self._add_task_metadata_params(metadata=metadata, input_value=batch_size, input_name="batchSize")
|
|
877
|
+
metadata = self._add_task_metadata_params(
|
|
878
|
+
metadata=metadata, input_value=max_batch_workload, input_name="maxBatchWorkload"
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
# Create payload for annotation task
|
|
882
|
+
payload = {
|
|
883
|
+
"name": name,
|
|
884
|
+
"query": "{}".format(json.dumps(filters.prepare()).replace("'", '"')),
|
|
885
|
+
"taskOwner": owner,
|
|
886
|
+
"spec": {"type": "annotation"},
|
|
887
|
+
"datasetId": dataset.id,
|
|
888
|
+
"projectId": self.project.id,
|
|
889
|
+
"assignmentIds": [],
|
|
890
|
+
"recipeId": recipe_id,
|
|
891
|
+
"dueDate": due_date * 1000,
|
|
892
|
+
"asynced": wait,
|
|
893
|
+
"priority": priority,
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
# Add workload if provided
|
|
897
|
+
if workload:
|
|
898
|
+
payload["workload"] = workload.to_json()
|
|
899
|
+
|
|
900
|
+
# Add limit if provided
|
|
901
|
+
if limit:
|
|
902
|
+
payload["limit"] = limit
|
|
903
|
+
|
|
904
|
+
# Add available actions if provided
|
|
905
|
+
if available_actions is not None:
|
|
906
|
+
payload["availableActions"] = [action.to_json() for action in available_actions]
|
|
907
|
+
|
|
908
|
+
# Handle video conversion
|
|
909
|
+
if not enforce_video_conversion:
|
|
910
|
+
payload["disableWebm"] = not enforce_video_conversion
|
|
911
|
+
|
|
912
|
+
# Handle metadata for pulling tasks
|
|
913
|
+
if metadata is not None:
|
|
914
|
+
payload["metadata"] = metadata
|
|
915
|
+
|
|
916
|
+
return self._create_task(payload, wait=wait)
|
|
917
|
+
|
|
918
|
+
def _create_task(self, payload: dict, wait: bool = True) -> entities.Task:
|
|
919
|
+
"""
|
|
920
|
+
Private function to create a task from a prepared payload.
|
|
921
|
+
|
|
922
|
+
:param dict payload: the prepared payload for task creation
|
|
923
|
+
:param bool wait: whether to wait for task creation to complete
|
|
924
|
+
:return: created Task object
|
|
925
|
+
:rtype: dtlpy.entities.task.Task
|
|
926
|
+
"""
|
|
927
|
+
success, response = self._client_api.gen_request(req_type="post", path=URL_PATH, json_req=payload)
|
|
928
|
+
if success:
|
|
929
|
+
response_json = response.json()
|
|
930
|
+
if payload.get("checkIfExist") is not None and "name" in response_json:
|
|
931
|
+
return entities.Task.from_json(
|
|
932
|
+
_json=response.json(), client_api=self._client_api, project=self._project, dataset=self._dataset
|
|
933
|
+
)
|
|
934
|
+
|
|
935
|
+
command = entities.Command.from_json(_json=response_json, client_api=self._client_api)
|
|
936
|
+
if not wait:
|
|
937
|
+
return command
|
|
938
|
+
command = command.wait(timeout=0)
|
|
939
|
+
if "createTaskPayload" not in command.spec:
|
|
940
|
+
raise exceptions.PlatformException(
|
|
941
|
+
error="400", message="createTaskPayload key is missing in command response: {}".format(response)
|
|
942
|
+
)
|
|
943
|
+
task = self.get(task_id=command.spec["createdTaskId"])
|
|
944
|
+
else:
|
|
945
|
+
raise exceptions.PlatformException(response)
|
|
946
|
+
|
|
947
|
+
assert isinstance(task, entities.Task)
|
|
948
|
+
return task
|
|
949
|
+
|
|
950
|
+
@_api_reference.add(path="/annotationtasks", method="post")
|
|
951
|
+
def create(
|
|
952
|
+
self,
|
|
953
|
+
task_name, # all
|
|
954
|
+
due_date=None, # all
|
|
955
|
+
assignee_ids=None, # all
|
|
956
|
+
workload=None,
|
|
957
|
+
dataset=None, # all
|
|
958
|
+
task_owner=None, # all
|
|
959
|
+
task_type="annotation", # distribution / pulling /
|
|
960
|
+
task_parent_id=None, # qa from task
|
|
961
|
+
project_id=None, # all
|
|
962
|
+
recipe_id=None, # all
|
|
963
|
+
assignments_ids=None, # Check
|
|
964
|
+
metadata=None, # all
|
|
965
|
+
filters=None, # all
|
|
966
|
+
items=None, # deprecate
|
|
967
|
+
query=None, # deprecate
|
|
968
|
+
available_actions=None, # all
|
|
969
|
+
wait=True, # all
|
|
970
|
+
check_if_exist: entities.Filters = False, # all
|
|
971
|
+
limit=None, # all
|
|
972
|
+
batch_size=None, # Pulling
|
|
973
|
+
max_batch_workload=None, # Pulling
|
|
974
|
+
allowed_assignees=None, # pulling - check distribution
|
|
975
|
+
priority=entities.TaskPriority.MEDIUM, # all
|
|
976
|
+
consensus_task_type=None, # qualification / honeypot / consensus
|
|
977
|
+
consensus_percentage=None, # qualification / honeypot / consensus
|
|
978
|
+
consensus_assignees=None, # qualification / honeypot / consensus Check qualifications
|
|
979
|
+
scoring=True, # quality task
|
|
980
|
+
enforce_video_conversion=True, # all
|
|
981
|
+
) -> entities.Task:
|
|
592
982
|
"""
|
|
593
983
|
Create a new Task (Annotation or QA).
|
|
594
984
|
|
|
@@ -636,7 +1026,7 @@ class Tasks:
|
|
|
636
1026
|
"""
|
|
637
1027
|
|
|
638
1028
|
if dataset is None and self._dataset is None:
|
|
639
|
-
raise exceptions.PlatformException(
|
|
1029
|
+
raise exceptions.PlatformException("400", "Please provide param dataset")
|
|
640
1030
|
if due_date is None:
|
|
641
1031
|
due_date = (datetime.datetime.now() + datetime.timedelta(days=7)).timestamp()
|
|
642
1032
|
if query is None:
|
|
@@ -653,11 +1043,13 @@ class Tasks:
|
|
|
653
1043
|
elif isinstance(items, entities.Item):
|
|
654
1044
|
item_list.append(items)
|
|
655
1045
|
else:
|
|
656
|
-
raise exceptions.PlatformException(
|
|
657
|
-
query = entities.Filters(
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
1046
|
+
raise exceptions.PlatformException("400", "Unknown items type")
|
|
1047
|
+
query = entities.Filters(
|
|
1048
|
+
field="id",
|
|
1049
|
+
values=[item.id for item in item_list],
|
|
1050
|
+
operator=entities.FiltersOperations.IN,
|
|
1051
|
+
use_defaults=False,
|
|
1052
|
+
).prepare()
|
|
661
1053
|
else:
|
|
662
1054
|
query = filters.prepare()
|
|
663
1055
|
|
|
@@ -665,9 +1057,9 @@ class Tasks:
|
|
|
665
1057
|
dataset = self._dataset
|
|
666
1058
|
|
|
667
1059
|
if task_owner is None:
|
|
668
|
-
task_owner = self._client_api.info()[
|
|
1060
|
+
task_owner = self._client_api.info()["user_email"]
|
|
669
1061
|
|
|
670
|
-
if task_type not in [
|
|
1062
|
+
if task_type not in ["annotation", "qa"]:
|
|
671
1063
|
raise ValueError('task_type must be one of: "annotation", "qa". got: {}'.format(task_type))
|
|
672
1064
|
|
|
673
1065
|
if recipe_id is None:
|
|
@@ -677,7 +1069,7 @@ class Tasks:
|
|
|
677
1069
|
if self._project_id is not None:
|
|
678
1070
|
project_id = self._project_id
|
|
679
1071
|
else:
|
|
680
|
-
raise exceptions.PlatformException(
|
|
1072
|
+
raise exceptions.PlatformException("400", "Must provide a project id")
|
|
681
1073
|
|
|
682
1074
|
if workload is None and assignee_ids is not None:
|
|
683
1075
|
workload = entities.Workload.generate(assignee_ids=assignee_ids)
|
|
@@ -685,124 +1077,95 @@ class Tasks:
|
|
|
685
1077
|
if assignments_ids is None:
|
|
686
1078
|
assignments_ids = list()
|
|
687
1079
|
|
|
688
|
-
payload = {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
1080
|
+
payload = {
|
|
1081
|
+
"name": task_name,
|
|
1082
|
+
"query": "{}".format(json.dumps(query).replace("'", '"')),
|
|
1083
|
+
"taskOwner": task_owner,
|
|
1084
|
+
"spec": {"type": task_type},
|
|
1085
|
+
"datasetId": dataset.id,
|
|
1086
|
+
"projectId": project_id,
|
|
1087
|
+
"assignmentIds": assignments_ids,
|
|
1088
|
+
"recipeId": recipe_id,
|
|
1089
|
+
"dueDate": due_date * 1000,
|
|
1090
|
+
"asynced": wait,
|
|
1091
|
+
"priority": priority,
|
|
1092
|
+
}
|
|
700
1093
|
|
|
701
1094
|
if check_if_exist:
|
|
702
1095
|
if check_if_exist.resource != entities.FiltersResource.TASK:
|
|
703
1096
|
raise exceptions.PlatformException(
|
|
704
|
-
|
|
1097
|
+
"407",
|
|
1098
|
+
"Filter resource for check_if_exist param must be {}, got {}".format(
|
|
705
1099
|
entities.FiltersResource.TASK, check_if_exist.resource
|
|
706
|
-
)
|
|
1100
|
+
),
|
|
707
1101
|
)
|
|
708
|
-
payload[
|
|
1102
|
+
payload["checkIfExist"] = {"query": check_if_exist.prepare()}
|
|
709
1103
|
|
|
710
1104
|
if workload:
|
|
711
|
-
payload[
|
|
1105
|
+
payload["workload"] = workload.to_json()
|
|
712
1106
|
|
|
713
1107
|
if limit:
|
|
714
|
-
payload[
|
|
1108
|
+
payload["limit"] = limit
|
|
715
1109
|
|
|
716
1110
|
if available_actions is not None:
|
|
717
|
-
payload[
|
|
1111
|
+
payload["availableActions"] = [action.to_json() for action in available_actions]
|
|
718
1112
|
|
|
719
1113
|
if task_parent_id is not None:
|
|
720
|
-
payload[
|
|
1114
|
+
payload["spec"]["parentTaskId"] = task_parent_id
|
|
721
1115
|
|
|
722
1116
|
if not enforce_video_conversion:
|
|
723
|
-
payload[
|
|
1117
|
+
payload["disableWebm"] = not enforce_video_conversion
|
|
724
1118
|
|
|
725
1119
|
is_pulling = any([batch_size, max_batch_workload])
|
|
726
1120
|
is_consensus = any([consensus_percentage, consensus_assignees, consensus_task_type])
|
|
727
1121
|
if is_pulling and is_consensus:
|
|
728
|
-
raise exceptions.PlatformException(error=
|
|
729
|
-
message="Consensus can not work as a pulling task")
|
|
1122
|
+
raise exceptions.PlatformException(error="400", message="Consensus can not work as a pulling task")
|
|
730
1123
|
if any([is_pulling, is_consensus]):
|
|
731
1124
|
if metadata is None:
|
|
732
1125
|
metadata = {}
|
|
733
|
-
if
|
|
734
|
-
metadata[
|
|
1126
|
+
if "system" not in metadata:
|
|
1127
|
+
metadata["system"] = {}
|
|
735
1128
|
if allowed_assignees is not None or assignee_ids is not None:
|
|
736
|
-
metadata[
|
|
1129
|
+
metadata["system"]["allowedAssignees"] = allowed_assignees if allowed_assignees else assignee_ids
|
|
737
1130
|
if consensus_task_type is not None:
|
|
738
|
-
metadata[
|
|
739
|
-
metadata = self._add_task_metadata_params(metadata=metadata,
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
input_name='consensusAssignees')
|
|
751
|
-
metadata = self._add_task_metadata_params(metadata=metadata,
|
|
752
|
-
input_value=scoring,
|
|
753
|
-
input_name='scoring')
|
|
1131
|
+
metadata["system"]["consensusTaskType"] = consensus_task_type
|
|
1132
|
+
metadata = self._add_task_metadata_params(metadata=metadata, input_value=batch_size, input_name="batchSize")
|
|
1133
|
+
metadata = self._add_task_metadata_params(
|
|
1134
|
+
metadata=metadata, input_value=max_batch_workload, input_name="maxBatchWorkload"
|
|
1135
|
+
)
|
|
1136
|
+
metadata = self._add_task_metadata_params(
|
|
1137
|
+
metadata=metadata, input_value=consensus_percentage, input_name="consensusPercentage"
|
|
1138
|
+
)
|
|
1139
|
+
metadata = self._add_task_metadata_params(
|
|
1140
|
+
metadata=metadata, input_value=consensus_assignees, input_name="consensusAssignees"
|
|
1141
|
+
)
|
|
1142
|
+
metadata = self._add_task_metadata_params(metadata=metadata, input_value=scoring, input_name="scoring")
|
|
754
1143
|
|
|
755
1144
|
if metadata is not None:
|
|
756
|
-
payload[
|
|
1145
|
+
payload["metadata"] = metadata
|
|
757
1146
|
|
|
758
|
-
|
|
759
|
-
path=URL_PATH,
|
|
760
|
-
json_req=payload)
|
|
761
|
-
if success:
|
|
762
|
-
|
|
763
|
-
response_json = response.json()
|
|
764
|
-
if check_if_exist is not None and 'name' in response_json:
|
|
765
|
-
return entities.Task.from_json(
|
|
766
|
-
_json=response.json(),
|
|
767
|
-
client_api=self._client_api,
|
|
768
|
-
project=self._project,
|
|
769
|
-
dataset=self._dataset
|
|
770
|
-
)
|
|
771
|
-
|
|
772
|
-
command = entities.Command.from_json(_json=response_json,
|
|
773
|
-
client_api=self._client_api)
|
|
774
|
-
if not wait:
|
|
775
|
-
return command
|
|
776
|
-
command = command.wait(timeout=0)
|
|
777
|
-
if 'createTaskPayload' not in command.spec:
|
|
778
|
-
raise exceptions.PlatformException(error='400',
|
|
779
|
-
message="createTaskPayload key is missing in command response: {}"
|
|
780
|
-
.format(response))
|
|
781
|
-
task = self.get(task_id=command.spec['createdTaskId'])
|
|
782
|
-
else:
|
|
783
|
-
raise exceptions.PlatformException(response)
|
|
784
|
-
|
|
785
|
-
assert isinstance(task, entities.Task)
|
|
786
|
-
return task
|
|
1147
|
+
return self._create_task(payload, wait=wait)
|
|
787
1148
|
|
|
788
1149
|
def __item_operations(self, dataset: entities.Dataset, op, task=None, task_id=None, filters=None, items=None):
|
|
789
1150
|
|
|
790
1151
|
if task is None and task_id is None:
|
|
791
|
-
raise exceptions.PlatformException(
|
|
1152
|
+
raise exceptions.PlatformException("400", "Must provide either task or task id")
|
|
792
1153
|
elif task_id is None:
|
|
793
1154
|
task_id = task.id
|
|
794
1155
|
|
|
795
1156
|
try:
|
|
796
1157
|
if filters is None and items is None:
|
|
797
|
-
raise exceptions.PlatformException(
|
|
1158
|
+
raise exceptions.PlatformException("400", "Must provide either filters or items list")
|
|
798
1159
|
|
|
799
1160
|
if filters is None:
|
|
800
|
-
filters = entities.Filters(
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
1161
|
+
filters = entities.Filters(
|
|
1162
|
+
field="id",
|
|
1163
|
+
values=[item.id for item in items],
|
|
1164
|
+
operator=entities.FiltersOperations.IN,
|
|
1165
|
+
use_defaults=False,
|
|
1166
|
+
)
|
|
804
1167
|
|
|
805
|
-
if op ==
|
|
1168
|
+
if op == "delete":
|
|
806
1169
|
if task is None:
|
|
807
1170
|
task = self.get(task_id=task_id)
|
|
808
1171
|
assignment_ids = task.assignmentIds
|
|
@@ -817,17 +1180,19 @@ class Tasks:
|
|
|
817
1180
|
if filters is not None:
|
|
818
1181
|
filters._nullify_refs()
|
|
819
1182
|
|
|
820
|
-
@_api_reference.add(path=
|
|
821
|
-
def add_items(
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1183
|
+
@_api_reference.add(path="/annotationtasks/{id}/addToTask", method="post")
|
|
1184
|
+
def add_items(
|
|
1185
|
+
self,
|
|
1186
|
+
task: entities.Task = None,
|
|
1187
|
+
task_id=None,
|
|
1188
|
+
filters: entities.Filters = None,
|
|
1189
|
+
items=None,
|
|
1190
|
+
assignee_ids=None,
|
|
1191
|
+
query=None,
|
|
1192
|
+
workload=None,
|
|
1193
|
+
limit=None,
|
|
1194
|
+
wait=True,
|
|
1195
|
+
) -> entities.Task:
|
|
831
1196
|
"""
|
|
832
1197
|
Add items to a Task.
|
|
833
1198
|
|
|
@@ -853,19 +1218,21 @@ class Tasks:
|
|
|
853
1218
|
items = [items])
|
|
854
1219
|
"""
|
|
855
1220
|
if filters is None and items is None and query is None:
|
|
856
|
-
raise exceptions.PlatformException(
|
|
1221
|
+
raise exceptions.PlatformException("400", "Must provide either filters, query or items list")
|
|
857
1222
|
|
|
858
1223
|
if task is None and task_id is None:
|
|
859
|
-
raise exceptions.PlatformException(
|
|
1224
|
+
raise exceptions.PlatformException("400", "Must provide either task or task_id")
|
|
860
1225
|
|
|
861
1226
|
if query is None:
|
|
862
1227
|
if filters is None:
|
|
863
1228
|
if not isinstance(items, list):
|
|
864
1229
|
items = [items]
|
|
865
|
-
filters = entities.Filters(
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1230
|
+
filters = entities.Filters(
|
|
1231
|
+
field="id",
|
|
1232
|
+
values=[item.id for item in items],
|
|
1233
|
+
operator=entities.FiltersOperations.IN,
|
|
1234
|
+
use_defaults=False,
|
|
1235
|
+
)
|
|
869
1236
|
query = filters.prepare()
|
|
870
1237
|
|
|
871
1238
|
if workload is None and assignee_ids is not None:
|
|
@@ -874,39 +1241,34 @@ class Tasks:
|
|
|
874
1241
|
if task_id is None:
|
|
875
1242
|
task_id = task.id
|
|
876
1243
|
|
|
877
|
-
payload = {
|
|
878
|
-
"query": "{}".format(json.dumps(query).replace("'", '"')),
|
|
879
|
-
}
|
|
1244
|
+
payload = {"query": "{}".format(json.dumps(query).replace("'", '"'))}
|
|
880
1245
|
|
|
881
1246
|
if workload is not None:
|
|
882
1247
|
payload["workload"] = workload.to_json()
|
|
883
1248
|
|
|
884
1249
|
if limit is not None:
|
|
885
|
-
payload[
|
|
1250
|
+
payload["limit"] = limit
|
|
886
1251
|
|
|
887
|
-
payload[
|
|
1252
|
+
payload["asynced"] = wait
|
|
888
1253
|
|
|
889
|
-
url =
|
|
1254
|
+
url = "{}/{}/addToTask".format(URL_PATH, task_id)
|
|
890
1255
|
|
|
891
|
-
success, response = self._client_api.gen_request(req_type=
|
|
892
|
-
path=url,
|
|
893
|
-
json_req=payload)
|
|
1256
|
+
success, response = self._client_api.gen_request(req_type="post", path=url, json_req=payload)
|
|
894
1257
|
|
|
895
1258
|
if success:
|
|
896
|
-
command = entities.Command.from_json(_json=response.json(),
|
|
897
|
-
client_api=self._client_api)
|
|
1259
|
+
command = entities.Command.from_json(_json=response.json(), client_api=self._client_api)
|
|
898
1260
|
if not wait:
|
|
899
1261
|
return command
|
|
900
1262
|
backoff_factor = 2
|
|
901
|
-
if command.type ==
|
|
1263
|
+
if command.type == "BulkAddToTaskSetting":
|
|
902
1264
|
backoff_factor = 8
|
|
903
1265
|
command = command.wait(timeout=0, backoff_factor=backoff_factor)
|
|
904
1266
|
if task is None:
|
|
905
1267
|
task = self.get(task_id=task_id)
|
|
906
|
-
if
|
|
907
|
-
raise exceptions.PlatformException(
|
|
908
|
-
|
|
909
|
-
|
|
1268
|
+
if "addToTaskPayload" not in command.spec:
|
|
1269
|
+
raise exceptions.PlatformException(
|
|
1270
|
+
error="400", message="addToTaskPayload key is missing in command response: {}".format(response)
|
|
1271
|
+
)
|
|
910
1272
|
else:
|
|
911
1273
|
raise exceptions.PlatformException(response)
|
|
912
1274
|
|
|
@@ -914,13 +1276,15 @@ class Tasks:
|
|
|
914
1276
|
return task
|
|
915
1277
|
|
|
916
1278
|
# @_api_reference.add(path='/annotationtasks/{id}/removeFromTask', method='post')
|
|
917
|
-
def remove_items(
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1279
|
+
def remove_items(
|
|
1280
|
+
self,
|
|
1281
|
+
task: entities.Task = None,
|
|
1282
|
+
task_id=None,
|
|
1283
|
+
filters: entities.Filters = None,
|
|
1284
|
+
query=None,
|
|
1285
|
+
items=None,
|
|
1286
|
+
wait=True,
|
|
1287
|
+
):
|
|
924
1288
|
"""
|
|
925
1289
|
remove items from Task.
|
|
926
1290
|
|
|
@@ -944,55 +1308,55 @@ class Tasks:
|
|
|
944
1308
|
|
|
945
1309
|
"""
|
|
946
1310
|
if filters is None and items is None and query is None:
|
|
947
|
-
raise exceptions.PlatformException(
|
|
1311
|
+
raise exceptions.PlatformException("400", "Must provide either filters, query or items list")
|
|
948
1312
|
|
|
949
1313
|
if task is None and task_id is None:
|
|
950
|
-
raise exceptions.PlatformException(
|
|
1314
|
+
raise exceptions.PlatformException("400", "Must provide either task or task_id")
|
|
951
1315
|
|
|
952
1316
|
if query is None:
|
|
953
1317
|
if filters is None:
|
|
954
1318
|
if not isinstance(items, list):
|
|
955
1319
|
items = [items]
|
|
956
|
-
filters = entities.Filters(
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1320
|
+
filters = entities.Filters(
|
|
1321
|
+
field="id",
|
|
1322
|
+
values=[item.id for item in items],
|
|
1323
|
+
operator=entities.FiltersOperations.IN,
|
|
1324
|
+
use_defaults=False,
|
|
1325
|
+
)
|
|
960
1326
|
query = filters.prepare()
|
|
961
1327
|
|
|
962
1328
|
if task_id is None:
|
|
963
1329
|
task_id = task.id
|
|
964
1330
|
|
|
965
|
-
payload = {"query": "{}".format(json.dumps(query).replace("'", '"')),
|
|
1331
|
+
payload = {"query": "{}".format(json.dumps(query).replace("'", '"')), "asynced": wait}
|
|
966
1332
|
|
|
967
|
-
url =
|
|
1333
|
+
url = "{}/{}/removeFromTask".format(URL_PATH, task_id)
|
|
968
1334
|
|
|
969
|
-
success, response = self._client_api.gen_request(req_type=
|
|
970
|
-
path=url,
|
|
971
|
-
json_req=payload)
|
|
1335
|
+
success, response = self._client_api.gen_request(req_type="post", path=url, json_req=payload)
|
|
972
1336
|
|
|
973
1337
|
if success:
|
|
974
|
-
command = entities.Command.from_json(_json=response.json(),
|
|
975
|
-
client_api=self._client_api)
|
|
1338
|
+
command = entities.Command.from_json(_json=response.json(), client_api=self._client_api)
|
|
976
1339
|
if not wait:
|
|
977
1340
|
return command
|
|
978
1341
|
command = command.wait(timeout=0)
|
|
979
1342
|
|
|
980
|
-
if
|
|
981
|
-
raise exceptions.PlatformException(
|
|
982
|
-
|
|
983
|
-
|
|
1343
|
+
if "removeFromTaskId" not in command.spec:
|
|
1344
|
+
raise exceptions.PlatformException(
|
|
1345
|
+
error="400", message="removeFromTaskId key is missing in command response: {}".format(response)
|
|
1346
|
+
)
|
|
984
1347
|
else:
|
|
985
1348
|
raise exceptions.PlatformException(response)
|
|
986
1349
|
return True
|
|
987
1350
|
|
|
988
|
-
def get_items(
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1351
|
+
def get_items(
|
|
1352
|
+
self,
|
|
1353
|
+
task_id: str = None,
|
|
1354
|
+
task_name: str = None,
|
|
1355
|
+
dataset: entities.Dataset = None,
|
|
1356
|
+
filters: entities.Filters = None,
|
|
1357
|
+
get_consensus_items: bool = False,
|
|
1358
|
+
task: entities.Task = None,
|
|
1359
|
+
) -> entities.PagedEntities:
|
|
996
1360
|
"""
|
|
997
1361
|
Get the task items to use in your code.
|
|
998
1362
|
|
|
@@ -1016,7 +1380,7 @@ class Tasks:
|
|
|
1016
1380
|
dataset.tasks.get_items(task_id= 'task_id')
|
|
1017
1381
|
"""
|
|
1018
1382
|
if task is None and task_id is None and task_name is None:
|
|
1019
|
-
raise exceptions.PlatformException(
|
|
1383
|
+
raise exceptions.PlatformException("400", "Please provide either task_id or task_name")
|
|
1020
1384
|
|
|
1021
1385
|
if task_id is None:
|
|
1022
1386
|
if task is None:
|
|
@@ -1024,22 +1388,22 @@ class Tasks:
|
|
|
1024
1388
|
task_id = task.id
|
|
1025
1389
|
|
|
1026
1390
|
if dataset is None and self._dataset is None:
|
|
1027
|
-
raise exceptions.PlatformException(
|
|
1391
|
+
raise exceptions.PlatformException("400", "Please provide a dataset entity")
|
|
1028
1392
|
if dataset is None:
|
|
1029
1393
|
dataset = self._dataset
|
|
1030
1394
|
|
|
1031
1395
|
if filters is None:
|
|
1032
1396
|
filters = entities.Filters(use_defaults=False)
|
|
1033
|
-
filters.add(field=
|
|
1397
|
+
filters.add(field="metadata.system.refs.id", values=[task_id], operator=entities.FiltersOperations.IN)
|
|
1034
1398
|
|
|
1035
1399
|
if not get_consensus_items:
|
|
1036
1400
|
if task is None:
|
|
1037
1401
|
task = self.get(task_id=task_id)
|
|
1038
|
-
if task.metadata.get(
|
|
1402
|
+
if task.metadata.get("system", dict()).get("consensusAssignmentId", None):
|
|
1039
1403
|
filters.add(
|
|
1040
|
-
field=
|
|
1041
|
-
values=task.metadata[
|
|
1042
|
-
operator=entities.FiltersOperations.NOT_EQUAL
|
|
1404
|
+
field="metadata.system.refs.id",
|
|
1405
|
+
values=task.metadata["system"]["consensusAssignmentId"],
|
|
1406
|
+
operator=entities.FiltersOperations.NOT_EQUAL,
|
|
1043
1407
|
)
|
|
1044
1408
|
|
|
1045
1409
|
return dataset.items.list(filters=filters)
|
|
@@ -1063,34 +1427,27 @@ class Tasks:
|
|
|
1063
1427
|
|
|
1064
1428
|
dataset.tasks.set_status(task_id= 'task_id', status='complete', operation='create')
|
|
1065
1429
|
"""
|
|
1066
|
-
url =
|
|
1430
|
+
url = "/assignments/items/tasks/{task_id}/status".format(task_id=task_id)
|
|
1067
1431
|
payload = {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
'operation': operation,
|
|
1071
|
-
'returnLastStatus': True,
|
|
1072
|
-
'status': status
|
|
1073
|
-
}
|
|
1432
|
+
"itemIds": item_ids,
|
|
1433
|
+
"statusPayload": {"operation": operation, "returnLastStatus": True, "status": status},
|
|
1074
1434
|
}
|
|
1075
1435
|
|
|
1076
|
-
success, response = self._client_api.gen_request(
|
|
1077
|
-
req_type='post',
|
|
1078
|
-
path=url,
|
|
1079
|
-
json_req=payload
|
|
1080
|
-
)
|
|
1436
|
+
success, response = self._client_api.gen_request(req_type="post", path=url, json_req=payload)
|
|
1081
1437
|
|
|
1082
1438
|
if not success:
|
|
1083
1439
|
raise exceptions.PlatformException(response)
|
|
1084
1440
|
if response.json() is not None:
|
|
1085
1441
|
updated_items = set(response.json().keys())
|
|
1086
|
-
log_msg =
|
|
1442
|
+
log_msg = "Items status was updated successfully."
|
|
1087
1443
|
if len(updated_items) != len(item_ids):
|
|
1088
1444
|
failed_items = set(item_ids).difference(updated_items)
|
|
1089
|
-
log_msg =
|
|
1090
|
-
success_count=len(updated_items), failed_items=failed_items
|
|
1445
|
+
log_msg = "{success_count} out of TOTAL items were updated. The following items failed to update: {failed_items}".format(
|
|
1446
|
+
success_count=len(updated_items), failed_items=failed_items
|
|
1447
|
+
)
|
|
1091
1448
|
logger.info(msg=log_msg)
|
|
1092
1449
|
return True
|
|
1093
|
-
|
|
1450
|
+
|
|
1094
1451
|
def task_scores(self, task_id: str = None, page_offset: int = 0, page_size: int = 100):
|
|
1095
1452
|
"""
|
|
1096
1453
|
Get all entities scores in a task.
|
|
@@ -1107,19 +1464,14 @@ class Tasks:
|
|
|
1107
1464
|
dataset.tasks.task_scores(task_id= 'task_id')
|
|
1108
1465
|
"""
|
|
1109
1466
|
if task_id is None:
|
|
1110
|
-
raise exceptions.PlatformException(
|
|
1111
|
-
|
|
1112
|
-
url =
|
|
1113
|
-
task_id=task_id,
|
|
1114
|
-
page_offset=page_offset,
|
|
1115
|
-
page_size=page_size
|
|
1116
|
-
)
|
|
1117
|
-
success, response = self._client_api.gen_request(
|
|
1118
|
-
req_type='get',
|
|
1119
|
-
path=url
|
|
1467
|
+
raise exceptions.PlatformException("400", "Please provide task_id")
|
|
1468
|
+
|
|
1469
|
+
url = "/scores/tasks/{task_id}?page={page_offset}&pageSize={page_size}".format(
|
|
1470
|
+
task_id=task_id, page_offset=page_offset, page_size=page_size
|
|
1120
1471
|
)
|
|
1472
|
+
success, response = self._client_api.gen_request(req_type="get", path=url)
|
|
1121
1473
|
|
|
1122
1474
|
if success:
|
|
1123
1475
|
return response.json()
|
|
1124
1476
|
else:
|
|
1125
|
-
raise exceptions.PlatformException(response)
|
|
1477
|
+
raise exceptions.PlatformException(response)
|