Skip to content

Commit 6183869

Browse files
authored
Merge pull request #117 from Labelbox/ms/upload-instructions
upload instructions
2 parents eded4ee + 466c5a5 commit 6183869

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

labelbox/schema/project.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,69 @@ def export_labels(self, timeout_seconds=60):
173173
self.uid)
174174
time.sleep(sleep_time)
175175

176+
def upsert_instructions(self, instructions_file: str):
177+
"""
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.
183+
184+
Raises:
185+
ValueError:
186+
* project must be setup
187+
* instructions file must end with one of ".text", ".txt", ".pdf", ".html"
188+
"""
189+
190+
if self.setup_complete is None:
191+
raise ValueError(
192+
"Cannot attach instructions to a project that has not been set up."
193+
)
194+
195+
frontend = self.labeling_frontend()
196+
frontendId = frontend.uid
197+
198+
if frontend.name != "Editor":
199+
logger.warn(
200+
f"This function has only been tested to work with the Editor front end. Found %s",
201+
frontend.name)
202+
203+
supported_instruction_formats = (".text", ".txt", ".pdf", ".html")
204+
if not instructions_file.endswith(supported_instruction_formats):
205+
raise ValueError(
206+
f"instructions_file must end with one of {supported_instruction_formats}. Found {instructions_file}"
207+
)
208+
209+
lfo = list(self.labeling_frontend_options())[-1]
210+
instructions_url = self.client.upload_file(instructions_file)
211+
customization_options = json.loads(lfo.customization_options)
212+
customization_options['projectInstructions'] = instructions_url
213+
option_id = lfo.uid
214+
215+
self.client.execute(
216+
"""mutation UpdateFrontendWithExistingOptionsPyApi (
217+
$frontendId: ID!,
218+
$optionsId: ID!,
219+
$name: String!,
220+
$description: String!,
221+
$customizationOptions: String!
222+
) {
223+
updateLabelingFrontend(
224+
where: {id: $frontendId},
225+
data: {name: $name, description: $description}
226+
) {id}
227+
updateLabelingFrontendOptions(
228+
where: {id: $optionsId},
229+
data: {customizationOptions: $customizationOptions}
230+
) {id}
231+
}""", {
232+
"frontendId": frontendId,
233+
"optionsId": option_id,
234+
"name": frontend.name,
235+
"description": "Video, image, and text annotation",
236+
"customizationOptions": json.dumps(customization_options)
237+
})
238+
176239
def labeler_performance(self):
177240
""" Returns the labeler performances for this Project.
178241

tests/integration/test_project.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import pytest
2+
import json
3+
import requests
24

3-
from labelbox import Project
5+
from labelbox import Project, LabelingFrontend
46
from labelbox.exceptions import InvalidQueryError
57

68

@@ -64,3 +66,29 @@ def test_extend_reservations(project):
6466
assert project.extend_reservations("ReviewQueue") == 0
6567
with pytest.raises(InvalidQueryError):
6668
project.extend_reservations("InvalidQueueType")
69+
70+
71+
def test_attach_instructions(client, project):
72+
with pytest.raises(ValueError) as execinfo:
73+
project.upsert_instructions('/tmp/instructions.txt')
74+
assert str(
75+
execinfo.value
76+
) == "Cannot attach instructions to a project that has not been set up."
77+
78+
editor = list(
79+
client.get_labeling_frontends(
80+
where=LabelingFrontend.name == "editor"))[0]
81+
empty_ontology = {"tools": [], "classifications": []}
82+
project.setup(editor, empty_ontology)
83+
84+
with open('/tmp/instructions.txt', 'w') as file:
85+
file.write("some instructions...")
86+
87+
project.upsert_instructions('/tmp/instructions.txt')
88+
assert json.loads(
89+
list(project.labeling_frontend_options())
90+
[-1].customization_options).get('projectInstructions') is not None
91+
92+
with pytest.raises(ValueError) as execinfo:
93+
project.upsert_instructions('/tmp/file.invalid_file_extension')
94+
assert "instructions_file must end with one of" in str(execinfo.value)

0 commit comments

Comments
 (0)