Coverage for src/lightmlrestapi/cli/make_ml_app.py: 53%

79 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-06-06 07:16 +0200

1""" 

2@file 

3@brief Creates and runs an Falcon application. 

4""" 

5import os 

6import sys 

7import logging 

8 

9 

10def _get_app(name, options, secret, users): 

11 """ 

12 Get application. 

13 """ 

14 try: 

15 from ..testing import dummy_application, dummy_application_image, dummy_application_fct 

16 from ..testing import dummy_application_neighbors, dummy_application_neighbors_image 

17 except (ImportError, ValueError): 

18 folder = os.path.normpath(os.path.join( 

19 os.path.abspath(os.path.dirname(__file__)), "..", "..")) 

20 sys.path.append(folder) 

21 from lightmlrestapi.testing import dummy_application, dummy_application_image, dummy_application_fct 

22 from lightmlrestapi.testing import dummy_application_neighbors, dummy_application_neighbors_image 

23 

24 if name == "dummy": 

25 # Dummy application. 

26 if users: 

27 raise NotImplementedError("users not None, not implemented") 

28 app = dummy_application() 

29 

30 elif name == "dummyfct": 

31 # Dummy application with a function. 

32 name = options 

33 if not os.path.exists(name): 

34 raise FileNotFoundError("Unable to find '{0}'.".format(name)) 

35 path, loc = os.path.split(name) 

36 if path not in sys.path: 

37 sys.path.append(path) 

38 rem = True 

39 else: 

40 rem = False 

41 loc = os.path.splitext(loc)[0] 

42 try: 

43 mod = __import__(loc) 

44 except ImportError as e: 

45 if rem: 

46 sys.path.pop() 

47 with open(name, "r") as f: 

48 code = f.read() 

49 raise ImportError( 

50 "Unable to compile file '{0}'\n{1}".format(name, code)) from e 

51 if rem: 

52 sys.path.pop() 

53 

54 if not hasattr(mod, 'restapi_version'): 

55 with open(name, "r") as f: 

56 code = f.read() 

57 raise AttributeError( 

58 "Unable to find function 'restapi_version' in file '{0}'\n{1}".format(name, code)) 

59 if not hasattr(mod, 'restapi_load'): 

60 with open(name, "r") as f: 

61 code = f.read() 

62 raise AttributeError( 

63 "Unable to find function 'restapi_load' in file '{0}'\n{1}".format(name, code)) 

64 if not hasattr(mod, 'restapi_predict'): 

65 with open(name, "r") as f: 

66 code = f.read() 

67 raise AttributeError( 

68 "Unable to find function 'restapi_predict' in file '{0}'\n{1}".format(name, code)) 

69 

70 if secret == '': 

71 secret = None 

72 app = dummy_application_fct(mod.restapi_load, mod.restapi_predict, secret=secret, 

73 version=mod.restapi_version, users=users) 

74 

75 elif name == "dummyimg": 

76 # Dummy application with an image. 

77 if users: 

78 raise NotImplementedError("users not None, not implemented") 

79 app = dummy_application_image(options=options, secret=secret) 

80 

81 elif name == "dummyknn": 

82 # Dummy application with neighbors. 

83 if users: 

84 raise NotImplementedError("users not None, not implemented") 

85 app = dummy_application_neighbors() 

86 

87 elif name == "dummyknnimg": 

88 # Dummy application with neighbors and an image. 

89 if users: 

90 raise NotImplementedError("users not None, not implemented") 

91 app = dummy_application_neighbors_image(options=options, secret=secret) 

92 

93 elif '.py' in name: 

94 raise NotImplementedError( 

95 "Unable to get application from filename '{}'. Not implemented.".format(name)) 

96 

97 else: 

98 raise NotImplementedError( 

99 "Application '{}' is not implemented.".format(name)) 

100 return app 

101 

102 

103def start_mlrestapi(name='dummy', host='127.0.0.1', port=8081, nostart=False, wsgi='waitress', 

104 options='', secret='', ccall='single', users='', fLOG=print): 

105 """ 

106 Creates an :epkg:`falcon` application and 

107 runs it through a :epkg:`wsgi` server. 

108 

109 :param name: class name or filename which defines the application 

110 :param host: host 

111 :param port: port 

112 :param nostart: do not start the wsgi server 

113 :param wsgi: :epkg:`wsgi` framework which runs the falcon application 

114 :param options: additional options as a string (depends on the application) 

115 :param ccall: calling convention, 'single', 'multi' or 'both' depending on the 

116 fact that the prediction function can predict for only one observation, 

117 multiple ones or both 

118 :param secret: secret used to encrypt the logging, default is empty which 

119 disables the encryption 

120 :param users: registred users, file with two columns login, encrypted password, 

121 and no header 

122 :param fLOG: logging function 

123 

124 Only :epkg:`waitress` is implemented right now. 

125 Other alternative such as :epkg:`mod_wsgi` with :epkg:`Apache`. 

126 :epkg:`uwsgi` are not implemented. 

127 

128 .. cmdref:: 

129 :title: Creates an falcon application and starts it through a wsgi application 

130 :cmd: -m lightmlrestapi start_mlrestapi --help 

131 :lid: cmd_start_mlrestapi_cmd 

132 

133 Creates an :epkg:`falcon` application and starts it through a :epkg:`wsgi` server. 

134 """ 

135 app = _get_app(name, options=options, secret=secret, users=users) 

136 if wsgi == 'waitress': 

137 from waitress import serve 

138 if not nostart: 

139 fLOG("[start_mlrestapi] serve(app, host='{}', port='{}')".format(host, port)) 

140 logger = logging.getLogger('waitress') 

141 logger.setLevel(logging.INFO) 

142 serve(app, host=host, port=port) 

143 else: 

144 fLOG("[start_mlrestapi] do not run serve(app, host='{}', port='{}')".format( 

145 host, port)) 

146 else: 

147 raise NotImplementedError( 

148 "Server '{}' is not implemented.".format(wsgi)) 

149 

150 return app