Skip to content

Commit b7f5459

Browse files
author
Matt Sokoloff
committed
instruction upload works and is tested
1 parent 3b5ad31 commit b7f5459

File tree

2 files changed

+69
-25
lines changed

2 files changed

+69
-25
lines changed

labelbox/schema/project.py

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -175,37 +175,65 @@ def export_labels(self, timeout_seconds=60):
175175

176176
def attach_instructions(self, instructions_file: str):
177177
"""
178-
- Upload a set of instructions for labeling
178+
* Uploads instructions to the UI. Running more than once will replace the instructions
179+
180+
Args:
181+
instructions_file (str): Path to a local file.
182+
* Must be either a pdf, text, or html file.
179183
184+
Raises ValueError:
185+
* project must be setup
186+
* instructions file must be one of ".text", ".txt", ".pdf", ".html"
180187
"""
188+
181189
if self.setup_complete is None:
182-
raise Exception("Cannot attach instructions to a project that has not been setup.")
190+
raise ValueError(
191+
"Cannot attach instructions to a project that has not been setup."
192+
)
193+
194+
frontend = self.labeling_frontend()
195+
frontendId = frontend.uid
196+
197+
if frontend.name != "Editor":
198+
logger.warn(
199+
f"This function has only been tested to work with the Editor front end. Found {frontend.name}"
200+
)
201+
202+
supported_instruction_formats = (".text", ".txt", ".pdf", ".html")
203+
if not instructions_file.endswith(supported_instruction_formats):
204+
raise ValueError(
205+
f"instructions_file must end with one of {supported_instruction_formats}. Found {instructions_file}"
206+
)
183207

184-
assert self.setup_complete is not None #Change this to an actual exception...
185-
#Assert that the editor type is the editor..
186-
instructions_url = self.client.upload_file(instructions_file)
187208
lfo = list(self.labeling_frontend_options())[-1]
209+
instructions_url = self.client.upload_file(instructions_file)
188210
customization_options = json.loads(lfo.customization_options)
189211
customization_options['projectInstructions'] = instructions_url
190212
option_id = lfo.uid
191-
frontendId = self.labeling_frontend().uid
192-
args = {"frontendId": frontendId,
193-
"name": "Editor", #Probably only compatible with the regular editor..
213+
214+
self.client.execute(
215+
"""mutation UpdateFrontendWithExistingOptionsPyApi (
216+
$frontendId: ID!,
217+
$optionsId: ID!,
218+
$name: String!,
219+
$description: String!,
220+
$customizationOptions: String!
221+
) {
222+
updateLabelingFrontend(
223+
where: {id: $frontendId},
224+
data: {name: $name, description: $description}
225+
) {id}
226+
updateLabelingFrontendOptions(
227+
where: {id: $optionsId},
228+
data: {customizationOptions: $customizationOptions}
229+
) {id}
230+
}""", {
231+
"frontendId": frontendId,
232+
"name": frontend.name,
194233
"description": "Video, image, and text annotation",
195234
"optionsId": option_id,
196235
"customizationOptions": json.dumps(customization_options)
197-
}
198-
return self.client.execute("""
199-
mutation UpdateFrontendWithExistingOptions($frontendId: ID!, $optionsId: ID!, $name: String!, $description: String!, $customizationOptions: String!) {
200-
updateLabelingFrontend(where: {id: $frontendId}, data: {name: $name, description: $description}) {
201-
id
202-
}
203-
updateLabelingFrontendOptions(where: {id: $optionsId}, data: {customizationOptions: $customizationOptions}) {
204-
id
205-
}
206-
}
207-
""", args)
208-
236+
})
209237

210238
def labeler_performance(self):
211239
""" Returns the labeler performances for this Project.

tests/integration/test_project.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import pytest
2+
import json
23

3-
from labelbox import Project
4+
from labelbox import Project, LabelingFrontend
45
from labelbox.exceptions import InvalidQueryError
5-
import json
66

77

88
def test_project(client, rand_gen):
@@ -67,7 +67,23 @@ def test_extend_reservations(project):
6767
project.extend_reservations("InvalidQueueType")
6868

6969

70+
def test_attach_instructions(client, project):
71+
with pytest.raises(ValueError):
72+
project.attach_instructions('/tmp/instructions.txt')
73+
74+
editor = list(
75+
client.get_labeling_frontends(
76+
where=LabelingFrontend.name == "editor"))[0]
77+
empty_ontology = {"tools": [], "classifications": []}
78+
project.setup(editor, empty_ontology)
79+
80+
with open('/tmp/instructions.txt', 'w') as file:
81+
file.write("some instructions...")
82+
83+
project.attach_instructions('/tmp/instructions.txt')
84+
assert json.loads(
85+
list(project.labeling_frontend_options())
86+
[-1].customization_options).get('projectInstructions') is not None
7087

71-
def test_attach_instructions(setup_project):
72-
setup_project.attach_labeling_instructions("http://www.africau.edu/images/default/sample.pdf")
73-
assert json.loads(list(setup_project.labeling_frontend_options())[-1].customization_options).get('projectInstructions') is not None
88+
with pytest.raises(ValueError):
89+
project.attach_instructions('/tmp/file.invalid_file_extension')

0 commit comments

Comments
 (0)