Skip to content

Commit 026d007

Browse files
author
Daniel B
authored
Merge pull request #61 from mattmanley/batch_add_tasks
Adding batch functionality for posting new tasks
2 parents 47ac6e3 + 227d3be commit 026d007

6 files changed

Lines changed: 43 additions & 9 deletions

File tree

examples/challenge_examples.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,4 @@
5858
data = json.loads(data_file.read())
5959

6060
# Printing response:
61-
print(api.add_tasks_to_challenge(data, challenge_id))
61+
print(json.dumps(api.add_tasks_to_challenge(data, challenge_id)))

maproulette/api/challenge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def reset_task_instructions(self, challenge_id):
250250
def add_tasks_to_challenge(self, data, challenge_id):
251251
"""Method to add tasks to an existing challenge
252252
253-
:param data: a geojson containing geometry of tasks to be added to a challenge
253+
:param data: a GeoJSON containing geometry of tasks to be added to a challenge
254254
:param challenge_id: the ID corresponding to the challenge that tasks will be added to
255255
:returns: the API response from the PUT request
256256
"""

maproulette/api/maproulette_server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def __check_health(self, retries=3, delay=5):
4343
return True
4444
except requests.exceptions.ConnectionError:
4545
print(f"Connection not available. Attempt {str(i+1)} out of {str(retries)}")
46+
time.sleep(delay)
4647

4748
raise ConnectionUnavailableError(
4849
message='Specified server unavailable'

maproulette/api/task.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,20 @@ def get_task_history(self, task_id):
3030
endpoint=f"/task/{task_id}/history")
3131
return response
3232

33-
def create_tasks(self, data):
34-
"""Method to create a batch of tasks
33+
def create_tasks(self, data, batch_size=5000):
34+
"""Method to create a batch of tasks using the specified batch_size.
3535
3636
:param data: a JSON input containing task details
37+
:param batch_size: the number of tasks to post per API call. The default is 5000.
38+
:type batch_size: int
3739
:returns: the API response from the POST request
3840
"""
39-
response = self.post(
40-
endpoint="/tasks",
41-
body=data)
41+
response = []
42+
for batch in self.batch_generator(input_list=data, chunk_size=batch_size):
43+
response.append(self.post(
44+
endpoint="/tasks",
45+
body=batch)
46+
)
4247
return response
4348

4449
def update_tasks(self, data):
@@ -157,3 +162,15 @@ def is_task_model(input_object):
157162
:returns: True if instance of model
158163
"""
159164
return bool(isinstance(input_object, TaskModel))
165+
166+
@staticmethod
167+
def batch_generator(input_list, chunk_size):
168+
"""Method to yield successive n-sized chunks from input_list
169+
170+
:param input_list: the list to break into chunks
171+
:param chunk_size: the number of list items to include per chunk
172+
:type chunk_size: int
173+
:returns: an iterator for the n-sized chunks of the input_list
174+
"""
175+
for i in range(0, len(input_list), chunk_size):
176+
yield input_list[i:i + chunk_size]

maproulette/models/task.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ def to_dict(self):
190190
"id": self._id,
191191
"name": self._name,
192192
"parent": self._parent,
193+
"geometries": self._geometries,
193194
"instruction": self._instruction,
194195
"location": self._location,
195196
"suggestedFix": self._suggested_fix,

tests/test_task_api.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@ def test_get_task_history(self, mock_request, api_instance=api):
2626

2727
@patch('maproulette.api.maproulette_server.requests.Session.post')
2828
def test_create_tasks(self, mock_request, api_instance=api):
29+
test_tasks = []
2930
geometries = test_geojson['features'][0]['geometry']
3031
test_task_model = maproulette.TaskModel(name='test_task',
3132
parent='12345',
3233
geometries=geometries)
34+
test_tasks.append(test_task_model.to_dict())
3335
mock_request.return_value.status_code = '200'
34-
response = api_instance.create_tasks(test_task_model)
35-
self.assertEqual(response['status'], '200')
36+
responses = api_instance.create_tasks(test_tasks)
37+
for response in responses:
38+
self.assertEqual(response['status'], '200')
3639

3740
@patch('maproulette.api.maproulette_server.requests.Session.put')
3841
def test_update_tasks(self, mock_request, api_instance=api):
@@ -88,3 +91,15 @@ def test_get_task_comments(self, mock_request, api_instance=api):
8891
mock_request.return_value.status_code = '200'
8992
response = api_instance.get_task_comments(task_id)
9093
self.assertEqual(response['status'], '200')
94+
95+
def test_batch_generator(self, api_instance=api):
96+
97+
batch_size = 10
98+
test_length = 1234
99+
test_list = [i for i in range(test_length)]
100+
running_total = 0
101+
for chunk in api_instance.batch_generator(test_list, batch_size):
102+
running_total += len(chunk)
103+
self.assertIsInstance(chunk, list)
104+
self.assertLessEqual(len(chunk), batch_size)
105+
self.assertEqual(test_length, running_total)

0 commit comments

Comments
 (0)