Coverage for gws-app/gws/base/application/core.py: 93%

166 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-24 12:46 +0200

1"""Core application object""" 

2 

3from typing import Optional 

4 

5import gws 

6import gws.base.action 

7import gws.base.application.middleware 

8import gws.base.auth 

9import gws.base.client 

10import gws.base.database 

11import gws.base.exporter 

12import gws.base.job 

13import gws.base.metadata 

14import gws.base.model 

15import gws.base.printer 

16import gws.base.search 

17import gws.base.storage 

18import gws.base.template 

19import gws.base.web 

20import gws.config 

21import gws.gis.cache 

22import gws.gis.mpx.config 

23import gws.lib.font 

24import gws.server.manager 

25import gws.server.monitor 

26 

27DEFAULT_LOCALE = ['en_CA'] 

28 

29DEFAULT_TEMPLATE_SUBJECTS = [ 

30 'application.home', 

31 'application.error', 

32 'project.home', 

33 'project.description', 

34 'layer.description', 

35 'feature.description', 

36 'feature.title', 

37 'feature.label', 

38] 

39 

40DEFAULT_TEMPLATES = [ 

41 gws.Config( 

42 type='html', 

43 path=f'{gws.c.APP_DIR}/gws/base/application/templates/{_s.replace(".", "_")}.cx.html', 

44 subject=_s, 

45 access=gws.c.PUBLIC, 

46 uid=f'gws.base.application.default_template.{_s}', 

47 ) 

48 for _s in DEFAULT_TEMPLATE_SUBJECTS 

49] 

50 

51DEFAULT_PRINTER = gws.Config( 

52 uid='gws.base.application.default_printer', 

53 access=gws.c.PUBLIC, 

54 template=gws.Config( 

55 type='html', 

56 path=f'{gws.c.APP_DIR}/gws/base/application/templates/project_print.cx.html', 

57 mapSize=(200, 180, gws.Uom.mm), 

58 ), 

59 qualityLevels=[gws.TemplateQualityLevel(dpi=72)], 

60) 

61 

62DEFAULT_CSS_FILENAME = 'style.css' 

63 

64class Config(gws.ConfigWithAccess): 

65 """Main application configuration""" 

66 

67 actions: Optional[list[gws.ext.config.action]] 

68 """System-wide server actions.""" 

69 auth: Optional[gws.base.auth.manager.Config] 

70 """Authorization methods and options.""" 

71 cache: Optional[gws.gis.cache.Config] 

72 """Global cache configuration.""" 

73 client: Optional[gws.base.client.Config] 

74 """Gws client configuration.""" 

75 database: Optional[gws.base.database.manager.Config] 

76 """Database configuration.""" 

77 developer: Optional[dict] 

78 """Developer options.""" 

79 exporters: Optional[list[gws.ext.config.exporter]] 

80 """Exporters configuration.""" 

81 finders: Optional[list[gws.ext.config.finder]] 

82 """Global search providers.""" 

83 fonts: Optional[gws.lib.font.Config] 

84 """Fonts configuration.""" 

85 helpers: Optional[list[gws.ext.config.helper]] 

86 """Helpers configurations.""" 

87 locales: Optional[list[gws.LocaleUid]] 

88 """Default locales for all projects.""" 

89 metadata: Optional[gws.base.metadata.Config] 

90 """Application metadata.""" 

91 models: Optional[list[gws.ext.config.model]] 

92 """Global data models.""" 

93 owsServices: Optional[list[gws.ext.config.owsService]] 

94 """OWS services configuration.""" 

95 projectDirs: Optional[list[gws.DirPath]] 

96 """Directories with additional projects.""" 

97 projectPaths: Optional[list[gws.FilePath]] 

98 """Additional project paths.""" 

99 printers: Optional[list[gws.ext.config.printer]] 

100 """Print configurations.""" 

101 projects: Optional[list[gws.ext.config.project]] 

102 """Project configurations.""" 

103 server: Optional[gws.server.Config] 

104 """Server engine options.""" 

105 storage: Optional[gws.base.storage.manager.Config] 

106 """Database configuration.""" 

107 templates: Optional[list[gws.ext.config.template]] 

108 """Default templates.""" 

109 templateOptions: Optional[gws.TemplateOptions] 

110 """Options for default templates.""" 

111 title: Optional[str] 

112 """Application title.""" 

113 vars: Optional[dict] 

114 """Custom variables.""" 

115 web: Optional[gws.base.web.manager.Config] 

116 """Web server options.""" 

117 lastUid: int = 1 

118 """Last used uid for auto-generated uids.""" 

119 

120 

121class Object(gws.Application): 

122 """Main Application object""" 

123 

124 _helperMap: dict[str, gws.Node] 

125 

126 _developerOptions: dict 

127 

128 mpxUrl = '' 

129 mpxConfig = '' 

130 

131 def configure(self): 

132 self.version = self.root.specs.version 

133 self.versionString = f'GWS version {self.version}' 

134 

135 if gws.u.is_file('/GWS_REVISION'): 

136 self.versionString += ' (rev. ' + gws.u.read_file('/GWS_REVISION') + ')' 

137 

138 if not gws.env.GWS_IN_TEST: 

139 gws.log.info('*' * 80) 

140 gws.log.info(self.versionString) 

141 gws.log.info('*' * 80) 

142 

143 self.vars = self.cfg('vars') or {} 

144 

145 self.title = self.cfg('title') or '' 

146 

147 self.serverMgr = self.create_child(gws.server.manager.Object, self.cfg('server')) 

148 # NB need defaults from the server 

149 self.config.server = self.serverMgr.config 

150 

151 gws.log.set_level(self.cfg('server.log.level')) 

152 

153 self._developerOptions = self.cfg('developer') or {} 

154 if self._developerOptions: 

155 gws.log.warning(f'developer mode enabled: {self._developerOptions}') 

156 

157 self.monitor = self.create_child(gws.server.monitor.Object, self.serverMgr.cfg('monitor')) 

158 

159 self.localeUids = self.cfg('locales') or DEFAULT_LOCALE 

160 self.metadata = gws.base.metadata.from_config(self.cfg('metadata')) 

161 

162 self.middlewareMgr = self.create_child(gws.base.application.middleware.Object) 

163 

164 p = self.cfg('fonts') 

165 if p: 

166 gws.lib.font.configure(p) 

167 

168 # NB the order of initialization is important 

169 # - db 

170 # - helpers 

171 # - auth providers 

172 # - actions, client, web 

173 # - finally, projects 

174 

175 self.databaseMgr = self.create_child(gws.base.database.manager.Object, self.cfg('database')) 

176 

177 helpers = self.create_children(gws.ext.object.helper, self.cfg('helpers')) 

178 self._helperMap = {p.extType: p for p in helpers} 

179 

180 self.storageMgr = self.create_child(gws.base.storage.manager.Object, self.cfg('storage')) 

181 self.authMgr = self.create_child(gws.base.auth.manager.Object, self.cfg('auth')) 

182 

183 # @TODO default API 

184 self.actionMgr = self.create_child(gws.base.action.manager.Object) 

185 self.actions = self.create_children(gws.ext.object.action, self.cfg('actions')) 

186 

187 self.webMgr = self.create_child(gws.base.web.manager.Object, self.cfg('web')) 

188 

189 self.searchMgr = self.create_child(gws.base.search.manager.Object) 

190 self.finders = self.create_children(gws.ext.object.finder, self.cfg('finders')) 

191 

192 self.modelMgr = self.create_child(gws.base.model.manager.Object) 

193 self.models = self.create_children(gws.ext.object.model, self.cfg('models')) 

194 

195 self.templateMgr = self.create_child(gws.base.template.manager.Object) 

196 self.templates = self.create_children(gws.ext.object.template, self.cfg('templates')) 

197 for cfg in DEFAULT_TEMPLATES: 

198 self.templates.append(self.root.create_shared(gws.ext.object.template, cfg)) 

199 

200 p = self.cfg('templateOptions') 

201 defaults = gws.TemplateOptions( 

202 withLogin = any(a.extType == 'auth' for a in self.actions), 

203 homeResources = [], 

204 projectResources = [], 

205 ) 

206 if gws.u.is_file(self.webMgr.site.staticRoot.dir + f'/{DEFAULT_CSS_FILENAME}'): 

207 defaults.homeResources = [f'/{DEFAULT_CSS_FILENAME}'] 

208 defaults.projectResources = [f'/{DEFAULT_CSS_FILENAME}'] 

209 

210 self.templateOptions = gws.u.merge(defaults, self.cfg('templateOptions')) 

211 

212 self.exporterMgr = self.create_child(gws.base.exporter.manager.Object) 

213 self.exporters = self.create_children(gws.ext.object.exporter, self.cfg('exporters')) 

214 

215 self.jobMgr = self.create_child(gws.base.job.manager.Object) 

216 

217 self.printerMgr = self.create_child(gws.base.printer.manager.Object) 

218 self.printers = self.create_children(gws.ext.object.printer, self.cfg('printers')) 

219 self.defaultPrinter = self.root.create_shared(gws.ext.object.printer, DEFAULT_PRINTER) 

220 

221 self.owsServices = self.create_children(gws.ext.object.owsService, self.cfg('owsServices')) 

222 

223 self.client = self.create_child(gws.base.client.Object, self.cfg('client')) 

224 

225 self.projects = self.create_children(gws.ext.object.project, self.cfg('projects')) 

226 

227 def post_configure(self): 

228 if not self.cfg('server.mapproxy.disabled'): 

229 self.mpxUrl = f'http://{self.cfg("server.mapproxy.host")}:{self.cfg("server.mapproxy.port")}' 

230 self.mpxConfig = gws.gis.mpx.config.create_and_save(self.root) 

231 

232 def activate(self): 

233 gws.log.set_level(self.cfg('server.log.level')) 

234 

235 for p in self.root.configPaths: 

236 if p.startswith(gws.c.CONFIG_DIR): 

237 # do not watch derived config paths 

238 continue 

239 self.monitor.watch_file(p) 

240 for d in self.config.get('projectDirs') or []: 

241 self.monitor.watch_directory(d, gws.config.CONFIG_PATH_PATTERN) 

242 

243 def project(self, uid): 

244 for p in self.projects: 

245 if p.uid == uid: 

246 return p 

247 

248 def helper(self, ext_type): 

249 if ext_type not in self._helperMap: 

250 p = self.create_child(gws.ext.object.helper, type=ext_type) 

251 if not p: 

252 raise gws.Error(f'helper {ext_type!r} not found') 

253 gws.log.info(f'created helper {ext_type!r}') 

254 self._helperMap[ext_type] = p 

255 return self._helperMap.get(ext_type) 

256 

257 def developer_option(self, key): 

258 return self._developerOptions.get(key)