Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2@file 

3@brief Helpers to submit REST API requests. 

4""" 

5import os 

6import requests 

7from requests.auth import HTTPBasicAuth 

8from requests.exceptions import HTTPError 

9from ..args import zip_dict, bytes2string 

10from ..tools import json_loads, json_dumps 

11 

12 

13def json_upload_model(name, pyfile, data=None): 

14 """ 

15 Builds a REST request to upload a machine learned models to a REST API defined by 

16 @see cl MLStoragePost. 

17 

18 :param name: name of the model, should be unique and not already used 

19 :param pyfile: python file which computes the prediction, 

20 the file must follows the specification defined in 

21 :ref:`l-template-ml` 

22 :param data: binary file, usually everything the models pickled 

23 :return: dictionary ready to be jsonified 

24 """ 

25 if name is None or name == '': 

26 raise ValueError("name cannot be empty.") 

27 if not os.path.exists(pyfile): 

28 raise FileNotFoundError("Unable to find '{0}'.".format(pyfile)) 

29 if data is None: 

30 data = [] 

31 if not isinstance(data, list): 

32 data = [data] 

33 for d in data: 

34 if not os.path.exists(d): 

35 raise FileNotFoundError("Unable to find '{0}'.".format(d)) 

36 

37 # model file 

38 last_file = os.path.split(pyfile)[-1] 

39 with open(pyfile, "rb") as f: 

40 code = f.read() 

41 

42 if code == '': 

43 raise ValueError("File '{0}' cannot be empty.".format(pyfile)) 

44 model_data = {last_file: code} 

45 

46 # model data 

47 if data: 

48 for d in data: 

49 ld = os.path.split(d)[-1] 

50 with open(d, "rb") as f: 

51 content = f.read() 

52 model_data[ld] = content 

53 

54 # zip data 

55 zipped = zip_dict(model_data) 

56 request = dict(name=name, cmd='upload', 

57 zip=bytes2string(zipped)) 

58 return request 

59 

60 

61def json_predict_model(name, data, format='json'): # pylint: disable=W0622 

62 """ 

63 Builds a REST request to compute the prediction of a machine learning model 

64 upload with @see fn json_upload_model. 

65 See also @see cl MLStoragePost. 

66 

67 :param name: name of the model, should be unique and not already used 

68 :param data: any kind of data the model request 

69 :param format: ``'json'`` or ``'image'`` 

70 :return: dictionary ready to be jsonified 

71 """ 

72 if name is None or name == '': 

73 raise ValueError("name cannot be empty.") 

74 

75 js = json_dumps(data) 

76 obs = dict(cmd='predict', name=name, input=js, format=format) 

77 return obs 

78 

79 

80def submit_rest_request(request, login=None, pwd=None, url='http://127.0.0.1:8081/', 

81 timeout=50, fLOG=None): 

82 """ 

83 Submits a request to a REST API defined by 

84 @see cl MLStoragePost. 

85 

86 :param login: login 

87 :param pwd: password 

88 :param request: request as a dictionary 

89 :param url: url 

90 :param timeout: timeout 

91 :param fLOG: logging function 

92 :return: request results as dictionary 

93 """ 

94 if login: 

95 if fLOG: 

96 fLOG("[submit_rest_request] submit authentified request as '{0}' to '{1}'".format( 

97 login, url)) 

98 auth = HTTPBasicAuth(login, pwd) 

99 jsonified = json_dumps(request) 

100 response = requests.post( 

101 url, auth=auth, data=jsonified, timeout=timeout) 

102 else: 

103 if fLOG: 

104 fLOG("[submit_rest_request] submit request to '{0}'".format(url)) 

105 jsonified = json_dumps(request) 

106 response = requests.post(url, data=jsonified, timeout=timeout) 

107 

108 if response.ok: 

109 return json_loads(response.content) 

110 else: 

111 content = None 

112 if hasattr(response, 'content'): 

113 content = response.content 

114 elif hasattr(response, '_content'): 

115 content = response._content # pylint: disable=W0212 

116 if content: 

117 if isinstance(content, bytes): 

118 http_error_msg = content.decode('ascii') 

119 try: 

120 val = json_loads(http_error_msg) 

121 http_error_msg = val 

122 except ValueError: 

123 pass 

124 finally: 

125 pass 

126 else: 

127 http_error_msg = json_loads(content) 

128 if isinstance(http_error_msg, dict): 

129 http_error_msg = "\n".join( 

130 ["{0}: {1}".format(k, v) for k, v in sorted(http_error_msg.items())]) 

131 else: 

132 http_error_msg = "ERROR" 

133 raise HTTPError(http_error_msg, response=response)