Skip to content

Commit 890d046

Browse files
authored
Merge pull request #933 from Labelbox/ms/exports-v2-update
exports v2 task support
2 parents b3fa77b + 1df8e69 commit 890d046

File tree

3 files changed

+40
-41
lines changed

3 files changed

+40
-41
lines changed

labelbox/schema/task.py

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class Task(DbObject):
4040
status = Field.String("status")
4141
completion_percentage = Field.Float("completion_percentage")
4242
result_url = Field.String("result_url", "result")
43+
errors_url = Field.String("errors_url", "errors")
4344
type = Field.String("type")
4445
_user: Optional["User"] = None
4546

@@ -66,7 +67,9 @@ def wait_till_done(self, timeout_seconds: int = 300) -> None:
6667
check_frequency = 2 # frequency of checking, in seconds
6768
while True:
6869
if self.status != "IN_PROGRESS":
69-
if self.errors is not None:
70+
# self.errors fetches the error content.
71+
# This first condition prevents us from downloading the content for v2 exports
72+
if self.errors_url is not None or self.errors is not None:
7073
logger.warning(
7174
"There are errors present. Please look at `task.errors` for more details"
7275
)
@@ -84,21 +87,18 @@ def wait_till_done(self, timeout_seconds: int = 300) -> None:
8487
def errors(self) -> Optional[Dict[str, Any]]:
8588
""" Fetch the error associated with an import task.
8689
"""
87-
if self.type == "add-data-rows-to-batch" or self.type == "send-to-task-queue":
90+
if self.name == 'JSON Import':
91+
if self.status == "FAILED":
92+
result = self._fetch_remote_json()
93+
return result["error"]
94+
elif self.status == "COMPLETE":
95+
return self.failed_data_rows
96+
elif self.type == "export-data-rows":
97+
return self._fetch_remote_json(remote_json_field='errors_url')
98+
elif self.type == "add-data-rows-to-batch" or self.type == "send-to-task-queue":
8899
if self.status == "FAILED":
89100
# for these tasks, the error is embedded in the result itself
90101
return json.loads(self.result_url)
91-
return None
92-
93-
# TODO: We should handle error messages for export v2 tasks in the future.
94-
if self.name != 'JSON Import':
95-
return None
96-
97-
if self.status == "FAILED":
98-
result = self._fetch_remote_json()
99-
return result["error"]
100-
elif self.status == "COMPLETE":
101-
return self.failed_data_rows
102102
return None
103103

104104
@property
@@ -130,37 +130,48 @@ def failed_data_rows(self) -> Optional[Dict[str, Any]]:
130130
return None
131131

132132
@lru_cache()
133-
def _fetch_remote_json(self) -> Dict[str, Any]:
133+
def _fetch_remote_json(self,
134+
remote_json_field: Optional[str] = None
135+
) -> Dict[str, Any]:
134136
""" Function for fetching and caching the result data.
135137
"""
136138

137-
def download_result():
138-
response = requests.get(self.result_url)
139+
def download_result(remote_json_field: Optional[str], format: str):
140+
url = getattr(self, remote_json_field or 'result_url')
141+
142+
if url is None:
143+
return None
144+
145+
response = requests.get(url)
139146
response.raise_for_status()
140-
try:
147+
if format == 'json':
141148
return response.json()
142-
except Exception as e:
143-
pass
144-
try:
149+
elif format == 'ndjson':
145150
return ndjson.loads(response.text)
146-
except Exception as e:
147-
raise ValueError("Failed to parse task JSON/NDJSON result.")
151+
else:
152+
raise ValueError(
153+
"Expected the result format to be either `ndjson` or `json`."
154+
)
148155

149-
if self.name != 'JSON Import' and self.type != 'export-data-rows':
156+
if self.name == 'JSON Import':
157+
format = 'json'
158+
elif self.type == 'export-data-rows':
159+
format = 'ndjson'
160+
else:
150161
raise ValueError(
151162
"Task result is only supported for `JSON Import` and `export` tasks."
152163
" Download task.result_url manually to access the result for other tasks."
153164
)
154165

155166
if self.status != "IN_PROGRESS":
156-
return download_result()
167+
return download_result(remote_json_field, format)
157168
else:
158169
self.wait_till_done(timeout_seconds=600)
159170
if self.status == "IN_PROGRESS":
160171
raise ValueError(
161172
"Job status still in `IN_PROGRESS`. The result is not available. Call task.wait_till_done() with a larger timeout or contact support."
162173
)
163-
return download_result()
174+
return download_result(remote_json_field, format)
164175

165176
@staticmethod
166177
def get_task(client, task_id):

tests/integration/annotation_import/test_model_run.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,9 @@ def test_model_run_export_v2(model_run_with_model_run_data_rows,
173173
assert task.name == task_name
174174
task.wait_till_done()
175175
assert task.status == "COMPLETE"
176+
assert task.errors is None
176177

177-
def download_result(result_url):
178-
response = requests.get(result_url)
179-
response.raise_for_status()
180-
data = [json.loads(line) for line in response.text.splitlines()]
181-
return data
182-
183-
task_results = download_result(task.result_url)
178+
task_results = task.result
184179

185180
label_ids = [label.uid for label in configured_project.labels()]
186181
label_ids_set = set(label_ids)

tests/integration/test_project.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,9 @@ def test_project_export_v2(configured_project_with_label):
6060
assert task.name == task_name
6161
task.wait_till_done()
6262
assert task.status == "COMPLETE"
63+
assert task.errors is None
6364

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:
65+
for task_result in task.result:
7366
task_project = task_result['projects'][project.uid]
7467
task_project_label_ids_set = set(
7568
map(lambda prediction: prediction['id'], task_project['labels']))

0 commit comments

Comments
 (0)