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

42 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-28 13:33 +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 

18 

19import flask_cors 

20 

21import flask 

22 

23SCHEMA_CONFIG = "config.schema" 

24 

25 

26def create_app(config, dummy_mode=False): 

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

28 if dummy_mode: 

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

30 else: # pragma: no cover 

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

32 

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

34 import my_lib.webapp.config 

35 

36 my_lib.webapp.config.URL_PREFIX = "/rasp-shutter" 

37 my_lib.webapp.config.init(config) 

38 

39 import my_lib.webapp.base 

40 import my_lib.webapp.event 

41 import my_lib.webapp.log 

42 import my_lib.webapp.util 

43 import rasp_shutter.webapp_control 

44 import rasp_shutter.webapp_schedule 

45 import rasp_shutter.webapp_sensor 

46 

47 app = flask.Flask("rasp-shutter") 

48 

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

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

51 

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

53 if dummy_mode: 

54 logging.warning("Set dummy mode") 

55 else: # pragma: no cover 

56 pass 

57 

58 rasp_shutter.webapp_control.init() 

59 rasp_shutter.webapp_schedule.init(config) 

60 my_lib.webapp.log.init(config) 

61 

62 def notify_terminate(): # pragma: no cover 

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

64 my_lib.webapp.log.term() 

65 

66 atexit.register(notify_terminate) 

67 else: # pragma: no cover 

68 pass 

69 

70 flask_cors.CORS(app) 

71 

72 app.config["CONFIG"] = config 

73 app.config["DUMMY_MODE"] = dummy_mode 

74 

75 app.json.compat = True 

76 

77 app.register_blueprint(rasp_shutter.webapp_control.blueprint) 

78 app.register_blueprint(rasp_shutter.webapp_schedule.blueprint) 

79 app.register_blueprint(rasp_shutter.webapp_sensor.blueprint) 

80 

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

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

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

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

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

86 

87 my_lib.webapp.config.show_handler_list(app) 

88 

89 return app 

90 

91 

92if __name__ == "__main__": 

93 import pathlib 

94 

95 import docopt 

96 import my_lib.config 

97 import my_lib.logger 

98 

99 args = docopt.docopt(__doc__) 

100 

101 config_file = args["-c"] 

102 port = args["-p"] 

103 dummy_mode = args["-d"] 

104 debug_mode = args["-D"] 

105 

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

107 

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

109 

110 app = create_app(config, dummy_mode) 

111 

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

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