# Coverage for app.py : 81%

## 136 statements

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 import importlib

2 import os

3 import sys

4

5 import click

6 import jinja2

7 from flask import Flask

8 from flask import send_from_directory

9 from flask_admin import Admin

10 from flask_admin.menu import MenuLink

11 from flask_login import current_user

12

13 from shopyo.api.file import trycopy

14

15

16 base_path = os.path.dirname(os.path.abspath(__file__))

17 sys.path.insert(0, base_path)

18 from config import app_config

19 from init import csrf

20 from init import db

21 from init import login_manager

22 from init import ma

23 from init import mail

24 from init import migrate

25 from init import modules_path

26

27

28 from shopyo_admin import DefaultModelView

29 from shopyo_admin import MyAdminIndexView

30

31

32 def create_app(config_name="development"):

33

34 global_template_variables = {}

35 global_configs = {}

36 app = Flask(

37 __name__,

38 instance_path=os.path.join(base_path, "instance"),

39 instance_relative_config=True,

40 )

41 load_config_from_obj(app, config_name)

42 load_config_from_instance(app, config_name)

43 create_config_json()

44 load_extensions(app)

45 setup_flask_admin(app)

46 register_devstatic(app)

47 load_blueprints(app, config_name, global_template_variables, global_configs)

48 setup_theme_paths(app)

49 inject_global_vars(app, global_template_variables)

50 return app

51

52

53 def load_config_from_obj(app, config_name):

54

55 try:

56 configuration = app_config[config_name]

57 except KeyError as e:

58 print(

59 f"[ ] Invalid config name {e}. Available configurations are: "

60 f"{list(app_config.keys())}\n"

61 )

62 sys.exit(1)

63

64 app.config.from_object(configuration)

65

66

67 def load_config_from_instance(app, config_name):

68

69 if config_name != "testing": 69 ↛ 71 line 69 didn't jump to line 71, because the condition on line 69 was never true

70 # load the instance config, if it exists, when not testing

71 app.config.from_pyfile("config.py", silent=True)

72

73 # create empty instance folder and empty config if not present

74 try:

75 os.makedirs(app.instance_path)

76 with open(os.path.join(app.instance_path, "config.py"), "a"):

77 pass

78 except OSError:

79 pass

80

81

82 def create_config_json():

83 if not os.path.exists("config.json"): 83 ↛ 84 line 83 didn't jump to line 84, because the condition on line 83 was never true

84 trycopy("config_demo.json", "config.json")

85

86

87 def load_extensions(app):

88 migrate.init_app(app, db)

89 db.init_app(app)

90 ma.init_app(app)

91 mail.init_app(app)

92 login_manager.init_app(app)

93 csrf.init_app(app)

94

95

96 def setup_flask_admin(app):

97 admin = Admin(

98 app,

99 name="My App",

100 template_mode="bootstrap4",

101 index_view=MyAdminIndexView(),

102 )

103 # admin.add_view(DefaultModelView(Settings, db.session))

104 admin.add_link(MenuLink(name="Logout", category="", url="/auth/logout?next=/admin"))

105

106

107 def register_devstatic(app):

108 @app.route("/devstatic/<path:boxormodule>/f/<path:filename>")

109 def devstatic(boxormodule, filename):

110 if app.config["DEBUG"]:

111 module_static = os.path.join(modules_path, boxormodule, "static")

112 return send_from_directory(module_static, filename=filename)

113

114

115 def load_blueprints(app, config_name, global_template_variables, global_configs):

116 """

117 - Registers blueprints

118 - Adds global template objects from modules

119 - Adds global configs from modules

120 """

121

122 for folder in os.listdir(os.path.join(base_path, "modules")):

123 if folder.startswith("__"): # ignore __pycache__

124 continue

125

126 if folder.startswith("box__"):

127 # boxes

128 for sub_folder in os.listdir(os.path.join(base_path, "modules", folder)):

129 if sub_folder.startswith("__"): # ignore __pycache__ 129 ↛ 130 line 129 didn't jump to line 130, because the condition on line 129 was never true

130 continue

131 elif sub_folder.endswith(".json"): # box_info.json

132 continue

133 try:

134 sys_mod = importlib.import_module(

135 f"modules.{folder}.{sub_folder}.view"

136 )

137 app.register_blueprint(getattr(sys_mod, f"{sub_folder}_blueprint"))

138 except AttributeError:

139 pass

140 try:

141 mod_global = importlib.import_module(

142 f"modules.{folder}.{sub_folder}.global"

143 )

144 global_template_variables.update(mod_global.available_everywhere)

145 except ImportError: 145 ↛ 148 line 145 didn't jump to line 148

146 pass

147

148 except AttributeError:

149 pass

150

151 # load configs

152 try:

153 mod_global = importlib.import_module(

154 f"modules.{folder}.{sub_folder}.global"

155 )

156 if config_name in mod_global.configs: 156 ↛ 128, 156 ↛ 157 2 missed branches: 1) line 156 didn't jump to line 128, because the condition on line 156 was never false, 2) line 156 didn't jump to line 157, because the condition on line 156 was never true

157 global_configs.update(mod_global.configs.get(config_name))

158 except ImportError:

159 pass

160

161 except AttributeError:

162 # click.echo('info: config not found in global')

163 pass

164 else:

165 # apps

166 try:

167 mod = importlib.import_module(f"modules.{folder}.view")

168 app.register_blueprint(getattr(mod, f"{folder}_blueprint"))

169 except AttributeError:

170 # print("[ ] Blueprint skipped:", e)

171 pass

172

173 # global's available everywhere template vars

174 try:

175 mod_global = importlib.import_module(f"modules.{folder}.global")

176 global_template_variables.update(mod_global.available_everywhere)

177 except ImportError:

178 # print(f"[ ] {e}")

179 pass

180

181 except AttributeError:

182 pass

183

184 # load configs

185 try:

186 mod_global = importlib.import_module(f"modules.{folder}.global")

187 if config_name in mod_global.configs: 187 ↛ 122 line 187 didn't jump to line 122, because the condition on line 187 was never false

188 global_configs.update(mod_global.configs.get(config_name))

189 except ImportError: 189 ↛ 192 line 189 didn't jump to line 192

190 # print(f"[ ] {e}")

191 pass

192 except AttributeError:

193 # click.echo('info: config not found in global')

194 pass

195

196 app.config.update(**global_configs)

197

198

199 def setup_theme_paths(app):

200 with app.app_context():

201 front_theme_dir = os.path.join(

202 app.config["BASE_DIR"], "static", "themes", "front"

203 )

204 back_theme_dir = os.path.join(

205 app.config["BASE_DIR"], "static", "themes", "back"

206 )

207 my_loader = jinja2.ChoiceLoader(

208 [

209 app.jinja_loader,

210 jinja2.FileSystemLoader([front_theme_dir, back_theme_dir]),

211 ]

212 )

213 app.jinja_loader = my_loader

214

215

216 def inject_global_vars(app, global_template_variables):

217 @app.context_processor

218 def inject_global_vars():

219 APP_NAME = "dwdwefw"

220

221 base_context = {

222 "APP_NAME": APP_NAME,

223 "len": len,

224 "current_user": current_user,

225 }

226 base_context.update(global_template_variables)

227

228 return base_context