Skip to content

Commit 41a6448

Browse files
author
Richard Sun
committed
[QQC-1484] Review feedback
1 parent 86112a4 commit 41a6448

File tree

6 files changed

+67
-91
lines changed

6 files changed

+67
-91
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
## Added
55
* All imports are available via `import labelbox as lb` and `import labelbox.types as lb_types`.
66
* Attachment_name support to create_attachment()
7+
* New method `Project.task_queues()` to obtain the task queues for a project.
8+
* New method `Project.move_data_rows_to_task_queue()` for moving data rows to a specified task queue.
79

810
## Changed
911
* `LabelImport.create_from_objects()`, `MALPredictionImport.create_from_objects()`, `MEAPredictionImport.create_from_objects()`, `Project.upload_annotations()`, `ModelRun.add_predictions()` now support Python Types for annotations.

docs/source/index.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ Task
118118
:members:
119119
:show-inheritance:
120120

121+
Task Queue
122+
---------------------------
123+
.. automodule:: labelbox.schema.task_queue
124+
:members:
125+
:show-inheritance:
126+
121127
User
122128
---------------------------
123129

labelbox/schema/project.py

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -796,9 +796,10 @@ def _create_batch_async(self,
796796

797797
task_id = res['taskId']
798798

799-
status = self._wait_for_task(task_id)
800-
if status != "COMPLETE":
801-
raise LabelboxError(f"Batch was not created successfully.")
799+
task = self._wait_for_task(task_id)
800+
if task.status != "COMPLETE":
801+
raise LabelboxError(f"Batch was not created successfully: " +
802+
json.dumps(task.errors))
802803

803804
# obtain batch entity to return
804805
get_batch_str = """query %s($projectId: ID!, $batchId: ID!) {
@@ -1133,8 +1134,8 @@ def task_queues(self) -> List[TaskQueue]:
11331134
for field_values in task_queue_values
11341135
]
11351136

1136-
def move_data_rows_to_task(self, data_row_ids: List[str],
1137-
task_queue_id: str):
1137+
def move_data_rows_to_task_queue(self, data_row_ids: List[str],
1138+
task_queue_id: str):
11381139
"""
11391140
11401141
Moves data rows to the specified task queue.
@@ -1172,34 +1173,16 @@ def move_data_rows_to_task(self, data_row_ids: List[str],
11721173
timeout=180.0,
11731174
experimental=True)["project"][method]["taskId"]
11741175

1175-
status = self._wait_for_task(task_id)
1176-
if status != "COMPLETE":
1177-
raise LabelboxError(f"Data rows were not moved successfully")
1176+
task = self._wait_for_task(task_id)
1177+
if task.status != "COMPLETE":
1178+
raise LabelboxError(f"Data rows were not moved successfully: " +
1179+
json.dumps(task.errors))
11781180

1179-
def _wait_for_task(self, task_id: str):
1180-
timeout_seconds = 600
1181-
sleep_time = 2
1182-
get_task_query_str = """query %s($taskId: ID!) {
1183-
task(where: {id: $taskId}) {
1184-
status
1185-
}
1186-
}
1187-
""" % "getTaskPyApi"
1181+
def _wait_for_task(self, task_id: str) -> Task:
1182+
task = Task.get_task(self.client, task_id)
1183+
task.wait_till_done()
11881184

1189-
while True:
1190-
task_status = self.client.execute(
1191-
get_task_query_str, {'taskId': task_id},
1192-
experimental=True)['task']['status']
1193-
1194-
if task_status == "IN_PROGRESS":
1195-
timeout_seconds -= sleep_time
1196-
if timeout_seconds <= 0:
1197-
raise LabelboxError(
1198-
f"Timed out while waiting for task to be completed.")
1199-
time.sleep(sleep_time)
1200-
continue
1201-
1202-
return task_status
1185+
return task
12031186

12041187
def upload_annotations(
12051188
self,

labelbox/schema/task.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from labelbox.exceptions import ResourceNotFoundError
88
from labelbox.orm.db_object import DbObject
9-
from labelbox.orm.model import Field, Relationship
9+
from labelbox.orm.model import Field, Relationship, Entity
1010

1111
if TYPE_CHECKING:
1212
from labelbox import User
@@ -55,7 +55,7 @@ def refresh(self) -> None:
5555
for field in self.fields():
5656
setattr(self, field.name, getattr(tasks[0], field.name))
5757

58-
def wait_till_done(self, timeout_seconds=300) -> None:
58+
def wait_till_done(self, timeout_seconds: int = 300) -> None:
5959
""" Waits until the task is completed. Periodically queries the server
6060
to update the task attributes.
6161
@@ -153,3 +153,17 @@ def download_result():
153153
"Job status still in `IN_PROGRESS`. The result is not available. Call task.wait_till_done() with a larger timeout or contact support."
154154
)
155155
return download_result()
156+
157+
@staticmethod
158+
def get_task(client, task_id):
159+
user: User = client.get_user()
160+
tasks: List[Task] = list(
161+
user.created_tasks(where=Entity.Task.uid == task_id))
162+
# Cache user in a private variable as the relationship can't be
163+
# resolved due to server-side limitations (see Task.created_by)
164+
# for more info.
165+
if len(tasks) != 1:
166+
raise ResourceNotFoundError(Entity.Task, {task_id: task_id})
167+
task: Task = tasks[0]
168+
task._user = user
169+
return task

tests/integration/conftest.py

Lines changed: 28 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -311,47 +311,9 @@ def configured_project_with_label(client, rand_gen, image_url, project, dataset,
311311
One label is already created and yielded when using fixture
312312
"""
313313
project.datasets.connect(dataset)
314-
editor = list(
315-
project.client.get_labeling_frontends(
316-
where=LabelingFrontend.name == "editor"))[0]
317-
318-
ontology_builder = OntologyBuilder(tools=[
319-
Tool(tool=Tool.Type.BBOX, name="test-bbox-class"),
320-
])
321-
project.setup(editor, ontology_builder.asdict())
322-
# TODO: ontology may not be synchronous after setup. remove sleep when api is more consistent
323-
time.sleep(2)
324-
325-
ontology = ontology_builder.from_project(project)
326-
predictions = [{
327-
"uuid": str(uuid.uuid4()),
328-
"schemaId": ontology.tools[0].feature_schema_id,
329-
"dataRow": {
330-
"id": datarow.uid
331-
},
332-
"bbox": {
333-
"top": 20,
334-
"left": 20,
335-
"height": 50,
336-
"width": 50
337-
}
338-
}]
339-
340-
def create_label():
341-
""" Ad-hoc function to create a LabelImport
342-
Creates a LabelImport task which will create a label
343-
"""
344-
upload_task = LabelImport.create_from_objects(
345-
client, project.uid, f'label-import-{uuid.uuid4()}', predictions)
346-
upload_task.wait_until_done(sleep_time_seconds=5)
347-
assert upload_task.state == AnnotationImportState.FINISHED, "Label Import did not finish"
348-
assert len(
349-
upload_task.errors
350-
) == 0, f"Label Import {upload_task.name} failed with errors {upload_task.errors}"
351314

352-
project.create_label = create_label
353-
project.create_label()
354-
label = wait_for_label_processing(project)[0]
315+
ontology = _setup_ontology(project)
316+
label = _create_label(project, datarow, ontology, wait_for_label_processing)
355317

356318
yield [project, dataset, datarow, label]
357319

@@ -370,18 +332,18 @@ def configured_batch_project_with_label(client, rand_gen, image_url,
370332
"""
371333
data_rows = [dr.uid for dr in list(dataset.data_rows())]
372334
batch_project.create_batch("test-batch", data_rows)
373-
editor = list(
374-
batch_project.client.get_labeling_frontends(
375-
where=LabelingFrontend.name == "editor"))[0]
376335

377-
ontology_builder = OntologyBuilder(tools=[
378-
Tool(tool=Tool.Type.BBOX, name="test-bbox-class"),
379-
])
380-
batch_project.setup(editor, ontology_builder.asdict())
381-
# TODO: ontology may not be synchronous after setup. remove sleep when api is more consistent
382-
time.sleep(2)
336+
ontology = _setup_ontology(batch_project)
337+
label = _create_label(batch_project, datarow, ontology,
338+
wait_for_label_processing)
339+
340+
yield [batch_project, dataset, datarow, label]
341+
342+
for label in batch_project.labels():
343+
label.delete()
383344

384-
ontology = ontology_builder.from_project(batch_project)
345+
346+
def _create_label(project, datarow, ontology, wait_for_label_processing):
385347
predictions = [{
386348
"uuid": str(uuid.uuid4()),
387349
"schemaId": ontology.tools[0].feature_schema_id,
@@ -401,22 +363,31 @@ def create_label():
401363
Creates a LabelImport task which will create a label
402364
"""
403365
upload_task = LabelImport.create_from_objects(
404-
client, batch_project.uid, f'label-import-{uuid.uuid4()}',
366+
project.client, project.uid, f'label-import-{uuid.uuid4()}',
405367
predictions)
406368
upload_task.wait_until_done(sleep_time_seconds=5)
407369
assert upload_task.state == AnnotationImportState.FINISHED, "Label Import did not finish"
408370
assert len(
409371
upload_task.errors
410372
) == 0, f"Label Import {upload_task.name} failed with errors {upload_task.errors}"
411373

412-
batch_project.create_label = create_label
413-
batch_project.create_label()
414-
label = wait_for_label_processing(batch_project)[0]
374+
project.create_label = create_label
375+
project.create_label()
376+
label = wait_for_label_processing(project)[0]
377+
return label
415378

416-
yield [batch_project, dataset, datarow, label]
417379

418-
for label in batch_project.labels():
419-
label.delete()
380+
def _setup_ontology(project):
381+
editor = list(
382+
project.client.get_labeling_frontends(
383+
where=LabelingFrontend.name == "editor"))[0]
384+
ontology_builder = OntologyBuilder(tools=[
385+
Tool(tool=Tool.Type.BBOX, name="test-bbox-class"),
386+
])
387+
project.setup(editor, ontology_builder.asdict())
388+
# TODO: ontology may not be synchronous after setup. remove sleep when api is more consistent
389+
time.sleep(2)
390+
return ontology_builder.from_project(project)
420391

421392

422393
@pytest.fixture

tests/integration/test_task_queue.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def test_move_to_task(configured_batch_project_with_label: Project):
1717

1818
review_queue = next(
1919
tq for tq in task_queues if tq.queue_type == "MANUAL_REVIEW_QUEUE")
20-
project.move_data_rows_to_task([data_row.uid], review_queue.uid)
20+
project.move_data_rows_to_task_queue([data_row.uid], review_queue.uid)
2121

2222
timeout_seconds = 30
2323
sleep_time = 2

0 commit comments

Comments
 (0)