Skip to content

Commit b6e1448

Browse files
committed
Client tests FINALLY passing on new API Spec. Fixes #56
1 parent 397a300 commit b6e1448

File tree

7 files changed

+352
-355
lines changed

7 files changed

+352
-355
lines changed

meorg_client/cli.py

+3-7
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,7 +126,7 @@ 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

meorg_client/client.py

+58-79
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,28 +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)
293+
response = self._upload_file(fp, id=id)
292294
responses.append(response)
293295
else:
294-
responses = self._upload_files_parallel(
295-
files, n=n, attach_to=attach_to, progress=progress
296+
responses += self._upload_files_parallel(
297+
files, n=n, id=id, progress=progress
296298
)
297299

298-
return mu.ensure_list(responses)
300+
# return mu.ensure_list(responses)
301+
return responses
299302

300303
def _upload_file(
301-
self,
302-
files: Union[str, Path, list],
303-
attach_to: str = None,
304+
self, filepath: Union[str, Path], id: str
304305
) -> Union[dict, requests.Response]:
305-
"""Upload a file.
306+
"""Upload a single file.
306307
307308
Parameters
308309
----------
309-
files : path-like, list
310-
Path to the file, or a list containing paths.
311-
attach_to : str, optional
312-
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
313314
314315
Returns
315316
-------
@@ -319,56 +320,42 @@ def _upload_file(
319320
Raises
320321
------
321322
TypeError
322-
When supplied file(s) are neither path-like nor readable.
323+
When supplied file is neither path-like nor readable.
323324
FileNotFoundError
324-
When supplied file(s) cannot be found.
325+
When supplied file is cannot be found.
325326
"""
326327

327-
# Cast as list for iterative upload
328-
files = mu.ensure_list(files)
328+
file_obj = None
329329

330-
# Prepare the files
331-
_files = list()
332-
for ix, f in enumerate(files):
333-
# Path-like
334-
if isinstance(f, (str, Path)) and os.path.isfile(f):
335-
_files.append(open(f, "rb"))
330+
if isinstance(filepath, (str, Path)) and os.path.isfile(filepath):
331+
file_obj = open(filepath, "rb")
336332

337-
# Bail out
338-
else:
339-
dtype = type(f)
340-
raise TypeError(
341-
f"File at index {ix} is neither path-like nor readable ({dtype})."
342-
)
333+
# Bail out
334+
else:
335+
dtype = type(f)
336+
raise TypeError(f"File is neither path-like nor readable ({dtype}).")
343337

344338
# Prepare the payload from the files
345339
payload = list()
346340

347-
for _f in _files:
348-
filename = os.path.basename(_f.name)
349-
ext = filename.split(".")[-1]
350-
mimetype = mt.types_map[f".{ext}"]
351-
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)))
352345

353346
# Make the request
354347
response = self._make_request(
355348
method=mcc.HTTP_POST,
356349
endpoint=endpoints.FILE_UPLOAD,
357350
files=payload,
351+
url_params=dict(id=id),
358352
return_json=True,
359353
)
360354

361355
# Close all the file descriptors (requests should do this, but just to be sure)
362356
for fd in payload:
363357
fd[1][1].close()
364358

365-
# Automatically attach to a model output
366-
if attach_to:
367-
368-
_ = self.attach_files_to_model_output(
369-
attach_to, files=mu.get_uploaded_file_ids(response)
370-
)
371-
372359
return mu.ensure_list(response)
373360

374361
def list_files(self, id: str) -> Union[dict, requests.Response]:
@@ -388,42 +375,29 @@ def list_files(self, id: str) -> Union[dict, requests.Response]:
388375
method=mcc.HTTP_GET, endpoint=endpoints.FILE_LIST, url_params=dict(id=id)
389376
)
390377

391-
def attach_files_to_model_output(
392-
self, id: str, files: list
393-
) -> Union[dict, requests.Response]:
394-
"""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
395380
396381
Parameters
397382
----------
398383
id : str
399384
Model output ID.
400-
files : list
401-
List of file IDs.
385+
file_id : str
386+
File ID.
402387
403388
Returns
404389
-------
405-
Union[dict, requests.Response]
406-
Response from ME.org.
390+
Union[dict, requests.Request]
391+
Response from ME.org
407392
"""
408-
409-
# Get a list of files for the model output
410-
current_files = self.list_files(id).get("data").get("files")
411-
412-
# Attach the new files to this list
413-
new_files = current_files + files
414-
415-
# Update the resource
416393
return self._make_request(
417-
mcc.HTTP_PATCH,
418-
endpoint=endpoints.FILE_LIST,
419-
url_params=dict(id=id),
420-
json=new_files,
394+
method=mcc.HTTP_DELETE,
395+
endpoint=endpoints.FILE_DELETE,
396+
url_params=dict(id=id, fileId=file_id),
421397
)
422398

423-
def detach_all_files_from_model_output(
424-
self, id: str
425-
) -> Union[dict, requests.Response]:
426-
"""Detach all files from a model output.
399+
def delete_all_files_from_model_output(self, id: str):
400+
"""Delete file from model output
427401
428402
Parameters
429403
----------
@@ -432,17 +406,22 @@ def detach_all_files_from_model_output(
432406
433407
Returns
434408
-------
435-
Union[dict, requests.Response]
409+
Union[dict, requests.Request]
436410
Response from ME.org
437411
"""
438412

439-
# Update the resource with an empty file list
440-
return self._make_request(
441-
mcc.HTTP_PATCH,
442-
endpoint=endpoints.FILE_LIST,
443-
url_params=dict(id=id),
444-
json=[],
445-
)
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
446425

447426
def start_analysis(self, id: str) -> Union[dict, requests.Response]:
448427
"""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)