Source code for lightmlrestapi.netrest.rest_helper
"""
Helpers to submit REST API requests.
:githublink:`%|py|5`
"""
import os
import requests
from requests.auth import HTTPBasicAuth
from requests.exceptions import HTTPError
from ..args import zip_dict, bytes2string
from ..tools import json_loads, json_dumps
[docs]def json_upload_model(name, pyfile, data=None):
"""
Builds a REST request to upload a machine learned models to a REST API defined by
:class:`MLStoragePost <lightmlrestapi.mlapp.mlstorage_rest.MLStoragePost>`.
:param name: name of the model, should be unique and not already used
:param pyfile: python file which computes the prediction,
the file must follows the specification defined in
:ref:`l-template-ml`
:param data: binary file, usually everything the models pickled
:return: dictionary ready to be jsonified
:githublink:`%|py|24`
"""
if name is None or name == '':
raise ValueError("name cannot be empty.")
if not os.path.exists(pyfile):
raise FileNotFoundError("Unable to find '{0}'.".format(pyfile))
if data is None:
data = []
if not isinstance(data, list):
data = [data]
for d in data:
if not os.path.exists(d):
raise FileNotFoundError("Unable to find '{0}'.".format(d))
# model file
last_file = os.path.split(pyfile)[-1]
with open(pyfile, "rb") as f:
code = f.read()
if code == '':
raise ValueError("File '{0}' cannot be empty.".format(pyfile))
model_data = {last_file: code}
# model data
if data:
for d in data:
ld = os.path.split(d)[-1]
with open(d, "rb") as f:
content = f.read()
model_data[ld] = content
# zip data
zipped = zip_dict(model_data)
request = dict(name=name, cmd='upload',
zip=bytes2string(zipped))
return request
[docs]def json_predict_model(name, data, format='json'): # pylint: disable=W0622
"""
Builds a REST request to compute the prediction of a machine learning model
upload with :func:`json_upload_model <lightmlrestapi.netrest.rest_helper.json_upload_model>`.
See also :class:`MLStoragePost <lightmlrestapi.mlapp.mlstorage_rest.MLStoragePost>`.
:param name: name of the model, should be unique and not already used
:param data: any kind of data the model request
:param format: ``'json'`` or ``'image'``
:return: dictionary ready to be jsonified
:githublink:`%|py|71`
"""
if name is None or name == '':
raise ValueError("name cannot be empty.")
js = json_dumps(data)
obs = dict(cmd='predict', name=name, input=js, format=format)
return obs
[docs]def submit_rest_request(request, login=None, pwd=None, url='http://127.0.0.1:8081/',
timeout=50, fLOG=None):
"""
Submits a request to a REST API defined by
:class:`MLStoragePost <lightmlrestapi.mlapp.mlstorage_rest.MLStoragePost>`.
:param login: login
:param pwd: password
:param request: request as a dictionary
:param url: url
:param timeout: timeout
:param fLOG: logging function
:return: request results as dictionary
:githublink:`%|py|93`
"""
if login:
if fLOG:
fLOG("[submit_rest_request] submit authentified request as '{0}' to '{1}'".format(
login, url))
auth = HTTPBasicAuth(login, pwd)
jsonified = json_dumps(request)
response = requests.post(
url, auth=auth, data=jsonified, timeout=timeout)
else:
if fLOG:
fLOG("[submit_rest_request] submit request to '{0}'".format(url))
jsonified = json_dumps(request)
response = requests.post(url, data=jsonified, timeout=timeout)
if response.ok:
return json_loads(response.content)
else:
content = None
if hasattr(response, 'content'):
content = response.content
elif hasattr(response, '_content'):
content = response._content # pylint: disable=W0212
if content:
if isinstance(content, bytes):
http_error_msg = content.decode('ascii')
try:
val = json_loads(http_error_msg)
http_error_msg = val
except ValueError:
pass
finally:
pass
else:
http_error_msg = json_loads(content)
if isinstance(http_error_msg, dict):
http_error_msg = "\n".join(
["{0}: {1}".format(k, v) for k, v in sorted(http_error_msg.items())])
else:
http_error_msg = "ERROR"
raise HTTPError(http_error_msg, response=response)