Coverage for flask/src/app.py: 87%

45 statements  

« prev     ^ index     » next       coverage.py v7.6.8, created at 2024-11-24 13:56 +0900

1#!/usr/bin/env python3 

2""" 

3水やりを自動化するアプリのサーバーです 

4 

5Usage: 

6 app.py [-c CONFIG] [-p PORT] [-D] [-d] 

7 

8Options: 

9 -c CONFIG : CONFIG を設定ファイルとして読み込んで実行します.[default: config.yaml] 

10 -p PORT : WEB サーバのポートを指定します.[default: 5000] 

11 -D : ダミーモードで実行します.CI テストで利用することを想定しています. 

12 -d : デバッグモードで動作します. 

13""" 

14 

15import atexit 

16import logging 

17import os 

18import signal 

19 

20import flask_cors 

21 

22import flask 

23 

24SCHEMA_CONFIG = "config.schema" 

25 

26 

27def sig_handler(num, frame): # noqa: ARG001 

28 global should_terminate 

29 

30 logging.warning("receive signal %d", num) 

31 

32 if num == signal.SIGTERM: 

33 import rasp_water.valve 

34 

35 rasp_water.valve.term() 

36 

37 

38def create_app(config, dummy_mode=False): 

39 # NOTE: オプションでダミーモードが指定された場合,環境変数もそれに揃えておく 

40 if dummy_mode: 

41 os.environ["DUMMY_MODE"] = "true" 

42 else: # pragma: no cover 

43 os.environ["DUMMY_MODE"] = "false" 

44 

45 # NOTE: テストのため,環境変数 DUMMY_MODE をセットしてからロードしたいのでこの位置 

46 import my_lib.webapp.config 

47 

48 my_lib.webapp.config.URL_PREFIX = "/rasp-water" 

49 my_lib.webapp.config.init(config) 

50 

51 import my_lib.webapp.base 

52 import my_lib.webapp.event 

53 import my_lib.webapp.log 

54 import my_lib.webapp.util 

55 import rasp_water.webapp_schedule 

56 import rasp_water.webapp_valve 

57 

58 app = flask.Flask("rasp-water") 

59 

60 # NOTE: アクセスログは無効にする 

61 logging.getLogger("werkzeug").setLevel(logging.ERROR) 

62 

63 if os.environ.get("WERKZEUG_RUN_MAIN") == "true": 

64 if dummy_mode: 

65 logging.warning("Set dummy mode") 

66 else: # pragma: no cover 

67 pass 

68 

69 rasp_water.webapp_schedule.init(config) 

70 rasp_water.webapp_valve.init(config) 

71 my_lib.webapp.log.init(config) 

72 

73 def notify_terminate(): # pragma: no cover 

74 rasp_water.valve.set_state(rasp_water.valve.VALVE_STATE.CLOSE) 

75 my_lib.webapp.log.info("🏃 アプリを再起動します.") 

76 my_lib.webapp.log.term() 

77 

78 atexit.register(notify_terminate) 

79 else: # pragma: no cover 

80 pass 

81 

82 flask_cors.CORS(app) 

83 

84 app.config["CONFIG"] = config 

85 app.config["DUMMY_MODE"] = dummy_mode 

86 

87 app.config["JSONIFY_PRETTYPRINT_REGULAR"] = True 

88 

89 app.register_blueprint(rasp_water.webapp_valve.blueprint) 

90 app.register_blueprint(rasp_water.webapp_schedule.blueprint) 

91 

92 app.register_blueprint(my_lib.webapp.base.blueprint_default) 

93 app.register_blueprint(my_lib.webapp.base.blueprint) 

94 app.register_blueprint(my_lib.webapp.event.blueprint) 

95 app.register_blueprint(my_lib.webapp.log.blueprint) 

96 app.register_blueprint(my_lib.webapp.util.blueprint) 

97 

98 # app.debug = True 

99 

100 return app 

101 

102 

103if __name__ == "__main__": 

104 import pathlib 

105 

106 import docopt 

107 import my_lib.config 

108 import my_lib.logger 

109 

110 args = docopt.docopt(__doc__) 

111 

112 config_file = args["-c"] 

113 port = args["-p"] 

114 dummy_mode = args["-D"] 

115 debug_mode = args["-d"] 

116 

117 my_lib.logger.init("hems.rasp-water", level=logging.DEBUG if debug_mode else logging.INFO) 

118 

119 config = my_lib.config.load(config_file, pathlib.Path(SCHEMA_CONFIG)) 

120 

121 app = create_app(config, dummy_mode) 

122 

123 # NOTE: スクリプトの自動リロード停止したい場合は use_reloader=False にする 

124 app.run(host="0.0.0.0", port=port, threaded=True, use_reloader=True) # noqa: S104 

125 

126 signal.signal(signal.SIGTERM, sig_handler)