Skip to content

Commit d3e06c1

Browse files
committed
Review suggestions. Fixes #23
1 parent 85b3a63 commit d3e06c1

File tree

4 files changed

+75
-73
lines changed

4 files changed

+75
-73
lines changed

meorg_client/cli.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def file_upload(file_path):
115115
client = _get_client()
116116

117117
# Upload the file, get the job ID
118-
response = _call(client.upload_file, file_path=list(file_path))
118+
response = _call(client.upload_files, files=list(file_path))
119119
files = response.get("data").get("files")
120120
for f in files:
121121
click.echo(f.get("file"))
@@ -247,7 +247,6 @@ def cli_analysis():
247247
# Add file commands
248248
cli_file.add_command(file_list)
249249
cli_file.add_command(file_upload)
250-
# cli_file.add_command(file_status)
251250
cli_file.add_command(file_attach)
252251

253252
# Add endpoint commands

meorg_client/client.py

+43-46
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import meorg_client.exceptions as mx
1111
import mimetypes as mt
1212
import io
13+
from pathlib import Path
1314

1415

1516
class Client:
@@ -214,68 +215,64 @@ def logout(self):
214215
self.headers.pop("X-User-Id", None)
215216
self.headers.pop("X-Auth-Token", None)
216217

217-
def upload_file(
218+
def upload_files(
218219
self,
219-
file_path: Union[str, list],
220-
file_obj: Union[io.BufferedReader, list] = None,
220+
files,
221221
) -> Union[dict, requests.Response]:
222222
"""Upload a file.
223223
224224
Parameters
225225
----------
226-
file_path : str or list
227-
Path to the file.
228-
file_obj : io.BufferedReader, optional
229-
File object (handle) to allow direct supply of file object, by default None
226+
files : path-like, readable or list
227+
Path to the file, readable object, or a list containing either.
230228
231229
Returns
232230
-------
233231
Union[dict, requests.Response]
234232
Response from ME.org.
235-
"""
236233
237-
payload = list()
234+
Raises
235+
------
236+
TypeError
237+
When supplied file(s) are neither path-like nor readable.
238+
FileNotFoundError
239+
When supplied file(s) cannot be found.
240+
"""
238241

239242
# Cast as list for iterative upload
240-
if not isinstance(file_path, list):
241-
file_path = [file_path]
242-
243-
# Payload assembly
244-
if file_obj is not None:
245-
# Cast as a list for iterative upload
246-
if not isinstance(file_obj, list):
247-
file_objs = [file_obj]
248-
249-
if len(file_objs) != len(file_path):
250-
raise ValueError("Supplied file paths and file objects do not match")
251-
252-
for ix, file_obj in enumerate(file_objs):
253-
if not isinstance(file_obj, io.BufferedReader) and not isinstance(
254-
file_obj, io.BytesIO
255-
):
256-
raise TypeError(
257-
f"Supplied file object {ix} is not an io.BufferedReader or io.BytesIO."
258-
)
259-
260-
_file_path = file_path[ix]
261-
262-
# Get the filename and extension
263-
filename = os.path.basename(_file_path)
264-
ext = filename.split(".")[-1]
265-
mimetype = mt.types_map[f".{ext}"]
266-
267-
payload.append(("file", (filename, file_obj, mimetype)))
268-
269-
else:
270-
for _file_path in file_path:
271-
# Get the filename and extension
272-
filename = os.path.basename(_file_path)
273-
ext = filename.split(".")[-1]
274-
mimetype = mt.types_map[f".{ext}"]
275-
file_obj = open(_file_path, "rb")
243+
if not isinstance(files, list):
244+
files = [files]
245+
246+
# Prepare the files
247+
_files = list()
248+
for ix, f in enumerate(files):
249+
# Path-like
250+
if isinstance(f, (str, Path)):
251+
_files.append(open(f, "rb"))
252+
253+
# IO handle (i.e. open file or bytes)
254+
elif isinstance(
255+
f, (io.BufferedReader, io.BytesIO, io.TextIOWrapper)
256+
) and hasattr(f, "name"):
257+
_files.append(f)
258+
259+
# Bail out
260+
else:
261+
dtype = type(f)
262+
raise TypeError(
263+
f"File at index {ix} is neither path-like nor readable ({dtype})."
264+
)
265+
266+
# Prepare the payload from the files
267+
payload = list()
276268

277-
payload.append(("file", (filename, file_obj, mimetype)))
269+
for _f in _files:
270+
filename = os.path.basename(_f.name)
271+
ext = filename.split(".")[-1]
272+
mimetype = mt.types_map[f".{ext}"]
273+
payload.append(("file", (filename, _f, mimetype)))
278274

275+
# Make the request
279276
return self._make_request(
280277
method=mcc.HTTP_POST,
281278
endpoint=endpoints.FILE_UPLOAD,

meorg_client/tests/test_cli.py

-13
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,6 @@ def test_file_multiple(runner):
4848
time.sleep(5)
4949

5050

51-
# def test_file_status(runner):
52-
# """Test file-status via CLI."""
53-
54-
# # Get the file ID based on the job ID
55-
# job_id = store.get("job_id")
56-
# result = runner.invoke(cli.file_status, [job_id])
57-
# assert result.exit_code == 0
58-
# assert result.output != "Pending"
59-
60-
# # Add file_id to the store for the next test
61-
# store.set("file_id", result.output.strip())
62-
63-
6451
def test_file_list(runner):
6552
"""Test file-list via CLI."""
6653
result = runner.invoke(cli.file_list, [store.get("model_output_id")])

meorg_client/tests/test_client.py

+31-12
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,28 @@
88

99

1010
def _get_authenticated_client():
11+
"""Get an authenticated client for tests.
12+
13+
Returns
14+
-------
15+
meorg_client.client.Client
16+
Client object.
17+
18+
Raises
19+
------
20+
TypeError
21+
Raised with test secrets are not set in the environment.
22+
"""
23+
24+
# Get the details from the environment.
1125
email = os.environ.get("MEORG_EMAIL")
1226
password = os.environ.get("MEORG_PASSWORD")
1327
model_output_id = os.environ.get("MEORG_MODEL_OUTPUT_ID")
1428

29+
# Connect
1530
client = Client(email=email, password=password)
1631

32+
# Ensure everything is set
1733
if None in [email, password, model_output_id, client.base_url]:
1834
raise TypeError("Test Secrets not set!!!")
1935

@@ -47,7 +63,7 @@ def test_upload_file(client):
4763
filepath = os.path.join(mu.get_installed_data_root(), "test/test.txt")
4864

4965
# Upload the file
50-
response = client.upload_file(filepath)
66+
response = client.upload_files(filepath)
5167

5268
# Make sure it worked
5369
assert client.success()
@@ -62,7 +78,7 @@ def test_upload_file_multiple(client):
6278
filepath = os.path.join(mu.get_installed_data_root(), "test/test.txt")
6379

6480
# Upload the file
65-
response = client.upload_file([filepath, filepath])
81+
response = client.upload_files([filepath, filepath])
6682

6783
# Make sure it worked
6884
assert client.success()
@@ -72,14 +88,14 @@ def test_upload_file_multiple(client):
7288

7389

7490
def test_file_list(client):
91+
"""Test the listinf of files for a model output."""
7592
response = client.list_files(client._model_output_id)
7693
assert client.success()
7794
assert isinstance(response.get("data").get("files"), list)
7895

7996

8097
def test_attach_files_to_model_output(client):
8198
# Get the file id from the job id
82-
# file_id = store.get("file_status").get("data").get("files")[0].get("file")
8399
file_id = store.get("file_upload").get("data").get("files")[0].get("file")
84100

85101
# Attach it to the model output
@@ -89,38 +105,41 @@ def test_attach_files_to_model_output(client):
89105

90106

91107
def test_start_analysis(client):
108+
"""Test starting an analysis."""
92109
response = client.start_analysis(client._model_output_id)
93110
assert client.success()
94111
store.set("start_analysis", response)
95112

96113

97114
def test_get_analysis_status(client):
115+
"""Test getting the analysis status."""
98116
# Get the analysis id from the store
99117
analysis_id = store.get("start_analysis").get("data").get("analysisId")
100118
_ = client.get_analysis_status(analysis_id)
101119
assert client.success()
102120

103121

104-
def test_logout(client):
105-
"""Test logout."""
106-
client.logout()
107-
assert "X-Auth-Token" not in client.headers.keys()
108-
109-
110122
def test_upload_file_large(client):
111123
"""Test the uploading of a large-ish file."""
112124

113125
# Create an in-memory 10mb file
114126
size = 10000000
115127
with io.BytesIO() as buffer:
128+
# Create a byte array (readable)
116129
buffer.write(bytearray(os.urandom(size)))
117130
buffer.seek(0)
118131

119-
# Upload the file.
120-
filepath = os.path.join(mu.get_installed_data_root(), "test/test.txt")
132+
# Mock the filename for the test
133+
buffer.name = "test/test.txt"
121134

122135
# Upload the file
123-
_ = client.upload_file(file_path=filepath, file_obj=buffer)
136+
_ = client.upload_files(buffer)
124137

125138
# Make sure it worked
126139
assert client.success()
140+
141+
142+
def test_logout(client):
143+
"""Test logout."""
144+
client.logout()
145+
assert "X-Auth-Token" not in client.headers.keys()

0 commit comments

Comments
 (0)