Skip to content

Commit d45b10a

Browse files
v1.0.4 - bug fixes, useragent extension, endpoint quotation, pytest updates (#25)
* useragent extension, quoted endpoint, fix batch_status * bumped version * updates to model objects * fixed/extended test cases * readme updates * fixed a typo
1 parent ada216a commit d45b10a

File tree

6 files changed

+69
-28
lines changed

6 files changed

+69
-28
lines changed

README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,13 @@ __ https://docs.scale.com/reference#list-multiple-tasks
105105
Cancel Task
106106
^^^^^^^^^^^
107107

108-
Cancel a task given its id if work has not stared on the task (task status is `queued` in the UI). Check out `Scale's API documentation`__ for more information.
108+
Cancel a task given its id if work has not started on the task (task status is `Queued` in the UI). Check out `Scale's API documentation`__ for more information.
109109

110110
__ https://docs.scale.com/reference#cancel-task
111111

112112
.. code-block :: python
113113
114-
task = client.cancel_task('asdfasdfasdfasdfasdfasdf')
114+
task = client.cancel_task('30553edd0b6a93f8f05f0fee')
115115
116116
Batches
117117
_______
@@ -162,7 +162,7 @@ __ https://docs.scale.com/reference#batch-retrieval
162162

163163
.. code-block:: python
164164
165-
client.get_batch( batch_name = "batch_name_01_07_2021" )
165+
client.get_batch(batch_name = 'batch_name_01_07_2021')
166166
167167
List Batches
168168
^^^^^^^^^^^^

scaleapi/__init__.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import requests
22
import platform
3+
import urllib.parse
34

45
from .tasks import Task
56
from .batches import Batch
@@ -63,11 +64,11 @@ class Batchlist(Paginator):
6364

6465

6566
class ScaleClient(object):
66-
def __init__(self, api_key):
67+
def __init__(self, api_key, user_agent_extension=None):
6768
self.api_key = api_key
6869
self._headers = {
6970
"Content-Type": "application/json",
70-
"User-Agent": _generate_useragent()
71+
"User-Agent": _generate_useragent(user_agent_extension)
7172
}
7273

7374
def _getrequest(self, endpoint, params=None):
@@ -171,15 +172,15 @@ def create_batch(self, project, batch_name, callback):
171172
return Batch(batchdata, self)
172173

173174
def finalize_batch(self, batch_name):
174-
batchdata = self._postrequest('batches/%s/finalize' % batch_name)
175+
batchdata = self._postrequest('batches/%s/finalize' % quote_string(batch_name))
175176
return Batch(batchdata, self)
176177

177178
def batch_status(self, batch_name):
178-
batchdata = self._getrequest('batches/%s/status' % batch_name)
179-
return Batch.get_status(self)
179+
status_data = self._getrequest('batches/%s/status' % quote_string(batch_name))
180+
return status_data
180181

181182
def get_batch(self, batch_name):
182-
batchdata = self._getrequest('batches/%s' % batch_name)
183+
batchdata = self._getrequest('batches/%s' % quote_string(batch_name))
183184
return Batch(batchdata, self)
184185

185186
def list_batches(self, **kwargs):
@@ -202,7 +203,7 @@ def create_project(self, project_name, type, params):
202203
return Project(projectdata, self)
203204

204205
def get_project(self, project_name):
205-
projectdata = self._getrequest('projects/%s' % project_name)
206+
projectdata = self._getrequest('projects/%s' % quote_string(project_name))
206207
return Project(projectdata, self)
207208

208209
def projects(self):
@@ -215,19 +216,38 @@ def update_project(self, project_name, **kwargs):
215216
if key not in allowed_kwargs:
216217
raise ScaleInvalidRequest('Illegal parameter %s for ScaleClient.update_project()'
217218
% key, None)
218-
projectdata = self._postrequest('projects/%s/setParams' % project_name, payload=kwargs)
219+
projectdata = self._postrequest('projects/%s/setParams' % quote_string(project_name), payload=kwargs)
219220
return projectdata
220221

221-
def _generate_useragent():
222+
def _generate_useragent(extension=None):
222223
try:
223224
python_version = platform.python_version()
224225
os_platform = platform.platform()
225226

226-
user_agent = '%s/%s Python/%s OS/%s' % (__name__, __version__, python_version, os_platform)
227+
user_agent = " ".join(
228+
filter(
229+
None,
230+
[
231+
"{}/{}".format(__name__, __version__),
232+
"Python/{}".format(python_version),
233+
"OS/{}".format(os_platform),
234+
extension,
235+
],
236+
)
237+
)
227238
return user_agent
228-
except:
239+
240+
except Exception:
229241
return "scaleapi-python-client"
230242

243+
def quote_string(text):
244+
"""`quote_string('a bc/def')` -> `a%20bc%2Fdef`
245+
Project and Batch names can be a part of URL, which causes an error
246+
in case of a special character used. Quotation assures
247+
the right object to be retrieved from API.
248+
"""
249+
return urllib.parse.quote(text, safe="")
250+
231251
def _AddTaskTypeCreator(task_type):
232252
def create_task_wrapper(self, **kwargs):
233253
return self.create_task(task_type, **kwargs)

scaleapi/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.0.3"
1+
__version__ = "1.0.4"

scaleapi/batches.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ class Batch(object):
22
def __init__(self, param_dict, client):
33
self.param_dict = param_dict
44
self.name = param_dict['name']
5+
self.status = param_dict["status"]
6+
57
self.pending = None
68
self.completed = None
79
self.error = None
810
self.canceled = None
911
self.client = client
12+
self.get_status()
1013

1114
def __hash__(self):
1215
return hash(self.name)
@@ -18,9 +21,13 @@ def __repr__(self):
1821
return 'Batch(%s)' % self.param_dict
1922

2023
def finalize(self):
21-
return self.client._postrequest("batches/%s/finalize" % self.name)
24+
res = self.client.finalize_batch(self.name)
25+
self.status = res.status
26+
return res
2227

2328
def get_status(self):
24-
res = self.client._getrequest("batches/%s/status" % self.name)
29+
res = self.client.batch_status(self.name)
30+
self.status = res["status"]
2531
for stat in ["pending", "completed", "error", "canceled"]:
2632
setattr(self, stat, res.get(stat, 0))
33+
return res

scaleapi/projects.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ class Project(object):
22
def __init__(self, param_dict, client):
33
self.param_dict = param_dict
44
self.name = param_dict['name']
5-
self.client = client
5+
self.client = client
66

77
def __hash__(self):
88
return hash(self.name)

tests/test_client.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
import scaleapi
55
import time
66
from datetime import datetime
7+
from random import randint
78
import os
89

910
try:
1011
test_api_key = os.environ['SCALE_TEST_API_KEY']
11-
client = scaleapi.ScaleClient(test_api_key)
12+
client = scaleapi.ScaleClient(test_api_key, 'pytest')
1213
except KeyError:
1314
raise Exception("Please set the environment variable SCALE_TEST_API_KEY to run tests.")
1415

@@ -32,6 +33,7 @@ def test_categorize_ok():
3233
callback_url='http://www.example.com/callback',
3334
instruction='Is this company public or private?',
3435
attachment_type='website',
36+
force=True,
3537
attachment='http://www.google.com/',
3638
categories=['public', 'private'])
3739

@@ -172,6 +174,7 @@ def test_audiotranscription_ok():
172174
task = client.create_audiotranscription_task(
173175
callback_url='http://www.example.com/callback',
174176
attachment_type='audio',
177+
instruction='Listen to the audio file and transcript.',
175178
attachment='https://storage.googleapis.com/deepmind-media/pixie/knowing-what-to-say/second-list/speaker-3.wav',
176179
verbatim=False,
177180
phrases=['avocado', 'stone']
@@ -202,14 +205,13 @@ def test_cancel():
202205
def test_task_retrieval():
203206
task = make_a_task()
204207
task2 = client.fetch_task(task.id)
205-
assert task.status == 'pending'
206208
assert task2.status == 'completed'
207209
assert task2.id == task.id
208210
assert task2.callback_url == task.callback_url
209211
assert task2.instruction == task.instruction
210212
assert task2.attachment_type == task.attachment_type
211-
assert task2.attachments == task.attachments
212-
assert task2.choices == task.choices
213+
assert task2.attachment == task.attachment
214+
assert task2.geometries == task.geometries
213215
assert task2.metadata == task.metadata
214216
assert task2.type == task.type
215217
assert task2.created_at == task.created_at
@@ -242,18 +244,30 @@ def test_tasks_invalid():
242244
def create_a_batch():
243245
return client.create_batch(
244246
callback = "http://www.example.com/callback",
245-
batch_name = "kitten_labeling_2020-07",
246-
project = "kitten_labeling"
247+
batch_name = "scaleapi-python-sdk-" + str(randint(0, 99999)),
248+
project = "scaleapi-python-sdk"
247249
)
248250

249251
def test_finalize_batch():
250252
batch = create_a_batch()
251-
client.finalize_batch(batch.name)
253+
batch = client.finalize_batch(batch.name)
254+
assert batch.status == 'in_progress'
252255

253-
def get_batch_status():
256+
batch2 = create_a_batch()
257+
batch2.finalize()
258+
assert batch2.status == 'in_progress'
259+
260+
def test_get_batch_status():
254261
batch = create_a_batch()
255262
client.batch_status(batch.name)
263+
assert batch.status == 'staging'
264+
265+
batch.finalize()
266+
batch.get_status() # Test status update
267+
assert batch.status == 'in_progress'
256268

257-
def get_batch():
269+
def test_get_batch():
258270
batch = create_a_batch()
259-
client.get_batch(batch.name)
271+
batch2 = client.get_batch(batch.name)
272+
assert batch.name == batch2.name
273+
assert batch2.status == 'staging'

0 commit comments

Comments
 (0)