Skip to content

Commit 2176c1e

Browse files
authored
Merge pull request #57 from CABLE-LSM/56-update-code-to-match-new-api-spec
56 update code to match new api spec
2 parents 13a5841 + 276d261 commit 2176c1e

File tree

7 files changed

+527
-361
lines changed

7 files changed

+527
-361
lines changed

meorg_client/cli.py

+25-18
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,9 @@ def list_endpoints():
109109

110110
@click.command("upload")
111111
@click.argument("file_path", nargs=-1)
112+
@click.argument("id")
112113
@click.option("-n", default=1, help="Number of threads for parallel uploads.")
113-
@click.option(
114-
"--attach_to",
115-
default=None,
116-
help="Supply a model output id to immediately attach the file to.",
117-
)
118-
def file_upload(file_path, n: int = 1, attach_to=None):
114+
def file_upload(file_path, id, n: int = 1):
119115
"""
120116
Upload a file to the server.
121117
@@ -130,19 +126,15 @@ def file_upload(file_path, n: int = 1, attach_to=None):
130126
client.upload_files,
131127
files=list(file_path),
132128
n=n,
133-
attach_to=attach_to,
129+
id=id,
134130
progress=True,
135131
)
136132

137133
for response in responses:
138134

139-
# For singular case
140-
if n == 1:
141-
response = response[0]
142-
143135
files = response.get("data").get("files")
144136
for f in files:
145-
click.echo(f.get("file"))
137+
click.echo(f.get("id"))
146138

147139

148140
@click.command("list")
@@ -174,9 +166,9 @@ def file_attach(file_id: str, output_id: str):
174166
click.echo("SUCCESS")
175167

176168

177-
@click.command("detach_all")
169+
@click.command("delete_all")
178170
@click.argument("output_id")
179-
def file_detach_all(output_id: str):
171+
def file_delete_all(output_id: str):
180172
"""Detach all files from a model output.
181173
182174
Parameters
@@ -185,7 +177,23 @@ def file_detach_all(output_id: str):
185177
Model output ID.
186178
"""
187179
client = _get_client()
188-
_ = _call(client.detach_all_files_from_model_output, id=output_id)
180+
_ = _call(client.delete_all_files_from_model_output, id=output_id)
181+
click.echo("SUCCESS")
182+
183+
184+
@click.command("delete")
185+
@click.argument("output_id")
186+
@click.argument("file_id")
187+
def file_delete(output_id: str, file_id: str):
188+
"""Detach a file from a model output.
189+
190+
Parameters
191+
----------
192+
output_id : str
193+
Model output ID.
194+
"""
195+
client = _get_client()
196+
_ = _call(client.delete_file_from_model_output, id=output_id, file_id=file_id)
189197
click.echo("SUCCESS")
190198

191199

@@ -286,9 +294,8 @@ def cli_analysis():
286294
# Add file commands
287295
cli_file.add_command(file_list)
288296
cli_file.add_command(file_upload)
289-
cli_file.add_command(file_attach)
290-
cli_file.add_command(file_detach_all)
291-
297+
cli_file.add_command(file_delete)
298+
cli_file.add_command(file_delete_all)
292299

293300
# Add endpoint commands
294301
cli_endpoints.add_command(list_endpoints)

meorg_client/client.py

+59-92
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ def logout(self):
221221
def _upload_files_parallel(
222222
self,
223223
files: Union[str, Path, list],
224+
id: str,
224225
n: int = 2,
225-
attach_to: str = None,
226226
progress=True,
227227
):
228228
"""Upload files in parallel.
@@ -231,10 +231,10 @@ def _upload_files_parallel(
231231
----------
232232
files : Union[str, Path, list]
233233
A path to a file, or a list of paths.
234+
id : str
235+
Module output id to attach to, by default None.
234236
n : int, optional
235237
Number of threads to use, by default 2.
236-
attach_to : str, optional
237-
Module output id to attach to, by default None.
238238
239239
Returns
240240
-------
@@ -248,16 +248,17 @@ def _upload_files_parallel(
248248
# Do the parallel upload
249249
responses = None
250250
responses = meop.parallelise(
251-
self._upload_file, n, files=files, attach_to=attach_to, progress=progress
251+
self._upload_file, n, filepath=files, id=id, progress=progress
252252
)
253253

254+
# These should already be a list as per the parallelise function.
254255
return responses
255256

256257
def upload_files(
257258
self,
258259
files: Union[str, Path, list],
260+
id: str,
259261
n: int = 1,
260-
attach_to: str = None,
261262
progress=True,
262263
) -> list:
263264
"""Upload files.
@@ -266,10 +267,11 @@ def upload_files(
266267
----------
267268
files : Union[str, Path, list]
268269
A filepath, or a list of filepaths.
270+
id : str
271+
Model output ID to immediately attach to.
269272
n : int, optional
270273
Number of threads to parallelise over, by default 1
271-
attach_to : str, optional
272-
Model output ID to immediately attach to, by default None
274+
273275
274276
Returns
275277
-------
@@ -288,40 +290,27 @@ def upload_files(
288290
responses = list()
289291
if n == 1:
290292
for fp in tqdm(files, total=len(files)):
291-
response = self._upload_file(fp, attach_to=attach_to)
292-
responses.append(response)
293+
response = self._upload_file(fp, id=id)
294+
responses += response
293295
else:
294-
295-
# Disable the auto attach to avoid race condition
296-
responses = self._upload_files_parallel(
297-
files, n=n, attach_to=None, progress=progress
296+
responses += self._upload_files_parallel(
297+
files, n=n, id=id, progress=progress
298298
)
299299

300-
if attach_to:
301-
302-
file_ids = list()
303-
304-
for response in responses:
305-
file_id = response.get("data").get("files")[0].get("file")
306-
file_ids.append(file_id)
307-
308-
self.attach_files_to_model_output(id=attach_to, files=file_ids)
309-
310-
return mu.ensure_list(responses)
300+
# return mu.ensure_list(responses)
301+
return responses
311302

312303
def _upload_file(
313-
self,
314-
files: Union[str, Path, list],
315-
attach_to: str = None,
304+
self, filepath: Union[str, Path], id: str
316305
) -> Union[dict, requests.Response]:
317-
"""Upload a file.
306+
"""Upload a single file.
318307
319308
Parameters
320309
----------
321-
files : path-like, list
322-
Path to the file, or a list containing paths.
323-
attach_to : str, optional
324-
Optional model_output_id to attach the files to, by default None
310+
filepath : path-like
311+
Path to the file
312+
id : str
313+
model_output_id to attach the files to
325314
326315
Returns
327316
-------
@@ -331,56 +320,42 @@ def _upload_file(
331320
Raises
332321
------
333322
TypeError
334-
When supplied file(s) are neither path-like nor readable.
323+
When supplied file is neither path-like nor readable.
335324
FileNotFoundError
336-
When supplied file(s) cannot be found.
325+
When supplied file cannot be found.
337326
"""
338327

339-
# Cast as list for iterative upload
340-
files = mu.ensure_list(files)
328+
file_obj = None
341329

342-
# Prepare the files
343-
_files = list()
344-
for ix, f in enumerate(files):
345-
# Path-like
346-
if isinstance(f, (str, Path)) and os.path.isfile(f):
347-
_files.append(open(f, "rb"))
330+
if isinstance(filepath, (str, Path)) and os.path.isfile(filepath):
331+
file_obj = open(filepath, "rb")
348332

349-
# Bail out
350-
else:
351-
dtype = type(f)
352-
raise TypeError(
353-
f"File at index {ix} is neither path-like nor readable ({dtype})."
354-
)
333+
# Bail out
334+
else:
335+
dtype = type(file_obj)
336+
raise TypeError(f"File is neither path-like nor readable ({dtype}).")
355337

356338
# Prepare the payload from the files
357339
payload = list()
358340

359-
for _f in _files:
360-
filename = os.path.basename(_f.name)
361-
ext = filename.split(".")[-1]
362-
mimetype = mt.types_map[f".{ext}"]
363-
payload.append(("file", (filename, _f, mimetype)))
341+
filename = os.path.basename(file_obj.name)
342+
ext = filename.split(".")[-1]
343+
mimetype = mt.types_map[f".{ext}"]
344+
payload.append(("file", (filename, file_obj, mimetype)))
364345

365346
# Make the request
366347
response = self._make_request(
367348
method=mcc.HTTP_POST,
368349
endpoint=endpoints.FILE_UPLOAD,
369350
files=payload,
351+
url_params=dict(id=id),
370352
return_json=True,
371353
)
372354

373355
# Close all the file descriptors (requests should do this, but just to be sure)
374356
for fd in payload:
375357
fd[1][1].close()
376358

377-
# Automatically attach to a model output
378-
if attach_to:
379-
380-
_ = self.attach_files_to_model_output(
381-
attach_to, files=mu.get_uploaded_file_ids(response)
382-
)
383-
384359
return mu.ensure_list(response)
385360

386361
def list_files(self, id: str) -> Union[dict, requests.Response]:
@@ -400,42 +375,29 @@ def list_files(self, id: str) -> Union[dict, requests.Response]:
400375
method=mcc.HTTP_GET, endpoint=endpoints.FILE_LIST, url_params=dict(id=id)
401376
)
402377

403-
def attach_files_to_model_output(
404-
self, id: str, files: list
405-
) -> Union[dict, requests.Response]:
406-
"""Attach files to a model output.
378+
def delete_file_from_model_output(self, id: str, file_id: str):
379+
"""Delete file from model output
407380
408381
Parameters
409382
----------
410383
id : str
411384
Model output ID.
412-
files : list
413-
List of file IDs.
385+
file_id : str
386+
File ID.
414387
415388
Returns
416389
-------
417-
Union[dict, requests.Response]
418-
Response from ME.org.
390+
Union[dict, requests.Request]
391+
Response from ME.org
419392
"""
420-
421-
# Get a list of files for the model output
422-
current_files = self.list_files(id).get("data").get("files")
423-
424-
# Attach the new files to this list
425-
new_files = current_files + files
426-
427-
# Update the resource
428393
return self._make_request(
429-
mcc.HTTP_PATCH,
430-
endpoint=endpoints.FILE_LIST,
431-
url_params=dict(id=id),
432-
json=new_files,
394+
method=mcc.HTTP_DELETE,
395+
endpoint=endpoints.FILE_DELETE,
396+
url_params=dict(id=id, fileId=file_id),
433397
)
434398

435-
def detach_all_files_from_model_output(
436-
self, id: str
437-
) -> Union[dict, requests.Response]:
438-
"""Detach all files from a model output.
399+
def delete_all_files_from_model_output(self, id: str):
400+
"""Delete file from model output
439401
440402
Parameters
441403
----------
@@ -444,17 +406,22 @@ def detach_all_files_from_model_output(
444406
445407
Returns
446408
-------
447-
Union[dict, requests.Response]
409+
Union[dict, requests.Request]
448410
Response from ME.org
449411
"""
450412

451-
# Update the resource with an empty file list
452-
return self._make_request(
453-
mcc.HTTP_PATCH,
454-
endpoint=endpoints.FILE_LIST,
455-
url_params=dict(id=id),
456-
json=[],
457-
)
413+
# Get a list of the files currently on the model output
414+
files = self.list_files(id)
415+
file_ids = [f.get("id") for f in files.get("data").get("files")]
416+
417+
responses = list()
418+
419+
# Do the delete one at a time
420+
for file_id in file_ids:
421+
response = self.delete_file_from_model_output(id=id, file_id=file_id)
422+
responses.append(response)
423+
424+
return responses
458425

459426
def start_analysis(self, id: str) -> Union[dict, requests.Response]:
460427
"""Start the analysis chain.

meorg_client/constants.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
VALID_METHODS = [HTTP_PUT, HTTP_GET, HTTP_DELETE, HTTP_PUT, HTTP_POST, HTTP_PATCH]
1111

1212
# Methods that interpolate parameters into the URL
13-
INTERPOLATING_METHODS = [HTTP_GET, HTTP_PUT, HTTP_PATCH]
13+
INTERPOLATING_METHODS = [HTTP_GET, HTTP_PUT, HTTP_PATCH, HTTP_DELETE]
1414

1515
# RFC 2616 states status in the 2xx range are considered successful
1616
HTTP_STATUS_SUCCESS_RANGE = range(200, 300)

0 commit comments

Comments
 (0)