Skip to content

Commit e1ee4e2

Browse files
authored
Merge pull request #841 from Labelbox/mno/AL-4397
2 parents dbadecd + 146471f commit e1ee4e2

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

labelbox/schema/export_params.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class DataRowParams(TypedDict):
1616

1717
class ProjectExportParams(DataRowParams):
1818
project_details: Optional[bool]
19-
label_details: Optional[bool]
19+
labels: Optional[bool]
2020
performance_details: Optional[bool]
2121

2222

labelbox/schema/project.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@
1212

1313
from labelbox import utils
1414
from labelbox.exceptions import (InvalidQueryError, LabelboxError,
15-
ProcessingWaitTimeout, ResourceConflict)
15+
ProcessingWaitTimeout, ResourceConflict,
16+
ResourceNotFoundError)
1617
from labelbox.orm import query
1718
from labelbox.orm.db_object import DbObject, Deletable, Updateable
1819
from labelbox.orm.model import Entity, Field, Relationship
1920
from labelbox.pagination import PaginatedCollection
2021
from labelbox.schema.consensus_settings import ConsensusSettings
2122
from labelbox.schema.data_row import DataRow
23+
from labelbox.schema.export_params import ProjectExportParams
2224
from labelbox.schema.media_type import MediaType
2325
from labelbox.schema.queue_mode import QueueMode
2426
from labelbox.schema.resource_tag import ResourceTag
27+
from labelbox.schema.task import Task
28+
from labelbox.schema.user import User
2529

2630
if TYPE_CHECKING:
2731
from labelbox import BulkImportRequest
@@ -371,6 +375,71 @@ def _validate_datetime(string_date: str) -> bool:
371375
self.uid)
372376
time.sleep(sleep_time)
373377

378+
"""
379+
Creates a project run export task with the given params and returns the task.
380+
381+
>>> export_task = export_v2("my_export_task", filter={"media_attributes": True})
382+
383+
"""
384+
385+
def export_v2(self, task_name: str,
386+
params: Optional[ProjectExportParams]) -> Task:
387+
defaultParams: ProjectExportParams = {
388+
"attachments": False,
389+
"media_attributes": False,
390+
"metadata_fields": False,
391+
"data_row_details": False,
392+
"project_details": False,
393+
"labels": False,
394+
"performance_details": False
395+
}
396+
_params: ProjectExportParams = params if params is not None else defaultParams
397+
mutation_name = "exportDataRowsInProject"
398+
create_task_query_str = """mutation exportDataRowsInProjectPyApi($input: ExportDataRowsInProjectInput!){
399+
%s(input: $input) {taskId} }
400+
""" % (mutation_name)
401+
query_params = {
402+
"input": {
403+
"taskName": task_name,
404+
"filters": {
405+
"projectId": self.uid
406+
},
407+
"params": {
408+
"includeAttachments":
409+
_params.get('attachments', False),
410+
"includeMediaAttributes":
411+
_params.get('media_attributes', False),
412+
"includeMetadata":
413+
_params.get('metadata_fields', False),
414+
"includeDataRowDetails":
415+
_params.get('data_row_details', False),
416+
"includeProjectDetails":
417+
_params.get('project_details', False),
418+
"includeLabels":
419+
_params.get('labels', False),
420+
"includePerformanceDetails":
421+
_params.get('performance_details', False),
422+
},
423+
}
424+
}
425+
res = self.client.execute(
426+
create_task_query_str,
427+
query_params,
428+
)
429+
res = res[mutation_name]
430+
task_id = res["taskId"]
431+
user: User = self.client.get_user()
432+
tasks: List[Task] = list(
433+
user.created_tasks(where=Entity.Task.uid == task_id))
434+
# Cache user in a private variable as the relationship can't be
435+
# resolved due to server-side limitations (see Task.created_by)
436+
# for more info.
437+
if len(tasks) != 1:
438+
raise ResourceNotFoundError(Entity.Task, task_id)
439+
task: Task = tasks[0]
440+
task._user = user
441+
return task
442+
374443
def export_issues(self, status=None) -> str:
375444
""" Calls the server-side Issues exporting that
376445
returns the URL to that payload.

tests/integration/test_project.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import time
23
import os
34

@@ -41,6 +42,49 @@ def test_project(client, rand_gen):
4142
assert project not in projects
4243

4344

45+
def test_project_export_v2(configured_project_with_label):
46+
project, _, _, label = configured_project_with_label
47+
label_id = label.uid
48+
# Wait for exporter to retrieve latest labels
49+
time.sleep(10)
50+
task_name = "test_label_export_v2"
51+
52+
# TODO: Right now we don't have a way to test this
53+
include_performance_details = True
54+
task = project.export_v2(
55+
task_name,
56+
params={
57+
"include_performance_details": include_performance_details,
58+
"include_labels": True
59+
})
60+
assert task.name == task_name
61+
task.wait_till_done()
62+
assert task.status == "COMPLETE"
63+
64+
def download_result(result_url):
65+
response = requests.get(result_url)
66+
response.raise_for_status()
67+
data = [json.loads(line) for line in response.text.splitlines()]
68+
return data
69+
70+
task_results = download_result(task.result_url)
71+
72+
for task_result in task_results:
73+
assert len(task_result['errors']) == 0
74+
task_project = task_result['projects'][project.uid]
75+
task_project_label_ids_set = set(
76+
map(lambda prediction: prediction['id'], task_project['labels']))
77+
assert label_id in task_project_label_ids_set
78+
79+
# TODO: Add back in when we have a way to test this
80+
# if include_performance_details:
81+
# assert 'include_performance_details' in task_result and task_result[
82+
# 'include_performance_details'] is not None
83+
# else:
84+
# assert 'include_performance_details' not in task_result or task_result[
85+
# 'include_performance_details'] is None
86+
87+
4488
def test_update_project_resource_tags(client, rand_gen):
4589

4690
def delete_tag(tag_id: str):

0 commit comments

Comments
 (0)