Coverage for .tox / coverage / lib / python3.11 / site-packages / wuttaweb / handler.py: 100%

57 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2025-12-28 15:23 -0600

1# -*- coding: utf-8; -*- 

2################################################################################ 

3# 

4# wuttaweb -- Web App for Wutta Framework 

5# Copyright © 2024-2025 Lance Edgar 

6# 

7# This file is part of Wutta Framework. 

8# 

9# Wutta Framework is free software: you can redistribute it and/or modify it 

10# under the terms of the GNU General Public License as published by the Free 

11# Software Foundation, either version 3 of the License, or (at your option) any 

12# later version. 

13# 

14# Wutta Framework is distributed in the hope that it will be useful, but 

15# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 

16# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 

17# more details. 

18# 

19# You should have received a copy of the GNU General Public License along with 

20# Wutta Framework. If not, see <http://www.gnu.org/licenses/>. 

21# 

22################################################################################ 

23""" 

24Web Handler 

25""" 

26 

27import warnings 

28 

29from wuttjamaican.app import GenericHandler 

30from wuttjamaican.util import load_entry_points 

31 

32from wuttaweb import static, forms, grids 

33 

34 

35class WebHandler(GenericHandler): 

36 """ 

37 Base class and default implementation for the :term:`web handler`. 

38 

39 This is responsible for determining the :term:`menu handler` and 

40 various other customizations. 

41 """ 

42 

43 def get_fanstatic_url(self, request, resource): 

44 """ 

45 Returns the full URL to the given Fanstatic resource. 

46 

47 :param request: Current :term:`request` object. 

48 

49 :param resource: :class:`fanstatic:fanstatic.Resource` 

50 instance representing an image file or other resource. 

51 """ 

52 needed = request.environ["fanstatic.needed"] 

53 url = needed.library_url(resource.library) + "/" 

54 if request.script_name: 

55 url = request.script_name + url 

56 return url + resource.relpath 

57 

58 def get_favicon_url(self, request): 

59 """ 

60 Returns the canonical app favicon image URL. 

61 

62 This will return the fallback favicon from WuttaWeb unless 

63 config specifies an override: 

64 

65 .. code-block:: ini 

66 

67 [wuttaweb] 

68 favicon_url = http://example.com/favicon.ico 

69 """ 

70 url = self.config.get("wuttaweb.favicon_url") 

71 if url: 

72 return url 

73 return self.get_fanstatic_url(request, static.favicon) 

74 

75 def get_header_logo_url(self, request): 

76 """ 

77 Returns the canonical app header image URL. 

78 

79 This will return the value from config if specified (as shown 

80 below); otherwise it will just call :meth:`get_favicon_url()` 

81 and return that. 

82 

83 .. code-block:: ini 

84 

85 [wuttaweb] 

86 header_logo_url = http://example.com/logo.png 

87 """ 

88 url = self.config.get("wuttaweb.header_logo_url") 

89 if url: 

90 return url 

91 return self.get_favicon_url(request) 

92 

93 def get_main_logo_url(self, request): 

94 """ 

95 Returns the canonical app logo image URL. 

96 

97 This will return the fallback logo from WuttaWeb unless config 

98 specifies an override: 

99 

100 .. code-block:: ini 

101 

102 [wuttaweb] 

103 logo_url = http://example.com/logo.png 

104 """ 

105 url = self.config.get("wuttaweb.logo_url") 

106 if url: 

107 return url 

108 return self.get_fanstatic_url(request, static.logo) 

109 

110 def get_menu_handler(self): 

111 """ 

112 Get the configured :term:`menu handler` for the web app. 

113 

114 Specify a custom handler in your config file like this: 

115 

116 .. code-block:: ini 

117 

118 [wutta.web] 

119 menus.handler.spec = poser.web.menus:PoserMenuHandler 

120 

121 :returns: Instance of :class:`~wuttaweb.menus.MenuHandler`. 

122 """ 

123 spec = self.config.get(f"{self.appname}.web.menus.handler.spec") 

124 if not spec: 

125 spec = self.config.get(f"{self.appname}.web.menus.handler_spec") 

126 if spec: 

127 warnings.warn( 

128 f"setting '{self.appname}.web.menus.handler_spec' is deprecated; " 

129 f"please use '{self.appname}.web.menus.handler.spec' instead", 

130 DeprecationWarning, 

131 ) 

132 else: 

133 spec = self.config.get( 

134 f"{self.appname}.web.menus.handler.default_spec", 

135 default="wuttaweb.menus:MenuHandler", 

136 ) 

137 factory = self.app.load_object(spec) 

138 return factory(self.config) 

139 

140 def get_menu_handler_specs(self, default=None): 

141 """ 

142 Get the :term:`spec` strings for all available :term:`menu 

143 handlers <menu handler>`. See also 

144 :meth:`get_menu_handler()`. 

145 

146 :param default: Default spec string(s) to include, even if not 

147 registered. Can be a string or list of strings. 

148 

149 :returns: List of menu handler spec strings. 

150 

151 This will gather available spec strings from the following: 

152 

153 First, the ``default`` as provided by caller. 

154 

155 Second, the default spec from config, if set; for example: 

156 

157 .. code-block:: ini 

158 

159 [wutta.web] 

160 menus.handler.default_spec = poser.web.menus:PoserMenuHandler 

161 

162 Third, each spec registered via entry points. For instance in 

163 ``pyproject.toml``: 

164 

165 .. code-block:: toml 

166 

167 [project.entry-points."wutta.web.menus"] 

168 poser = "poser.web.menus:PoserMenuHandler" 

169 

170 The final list will be "sorted" according to the above, with 

171 the latter registered handlers being sorted alphabetically. 

172 """ 

173 handlers = [] 

174 

175 # defaults from caller 

176 if isinstance(default, str): 

177 handlers.append(default) 

178 elif default: 

179 handlers.extend(default) 

180 

181 # configured default, if applicable 

182 default = self.config.get( 

183 f"{self.config.appname}.web.menus.handler.default_spec" 

184 ) 

185 if default and default not in handlers: 

186 handlers.append(default) 

187 

188 # registered via entry points 

189 registered = [] 

190 for handler in load_entry_points(f"{self.appname}.web.menus").values(): 

191 spec = handler.get_spec() 

192 if spec not in handlers: 

193 registered.append(spec) 

194 if registered: 

195 registered.sort() 

196 handlers.extend(registered) 

197 

198 return handlers 

199 

200 def make_form(self, request, **kwargs): 

201 """ 

202 Make and return a new :class:`~wuttaweb.forms.base.Form` 

203 instance, per the given ``kwargs``. 

204 

205 This is the "base" factory which merely invokes the 

206 constructor. 

207 """ 

208 return forms.Form(request, **kwargs) 

209 

210 def make_grid(self, request, **kwargs): 

211 """ 

212 Make and return a new :class:`~wuttaweb.grids.base.Grid` 

213 instance, per the given ``kwargs``. 

214 

215 This is the "base" factory which merely invokes the 

216 constructor. 

217 """ 

218 return grids.Grid(request, **kwargs)