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

57 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-13 13:36 -0600

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

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

3# 

4# wuttaweb -- Web App for Wutta Framework 

5# Copyright © 2024 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, **kwargs): 

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(f"setting '{self.appname}.web.menus.handler_spec' is deprecated; " 

128 f"please use '{self.appname}.web.menus.handler_spec' instead", 

129 DeprecationWarning) 

130 else: 

131 spec = self.config.get(f'{self.appname}.web.menus.handler.default_spec', 

132 default='wuttaweb.menus:MenuHandler') 

133 factory = self.app.load_object(spec) 

134 return factory(self.config) 

135 

136 def get_menu_handler_specs(self, default=None): 

137 """ 

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

139 handlers <menu handler>`. See also 

140 :meth:`get_menu_handler()`. 

141 

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

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

144 

145 :returns: List of menu handler spec strings. 

146 

147 This will gather available spec strings from the following: 

148 

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

150 

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

152 

153 .. code-block:: ini 

154 

155 [wutta.web] 

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

157 

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

159 ``pyproject.toml``: 

160 

161 .. code-block:: toml 

162 

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

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

165 

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

167 the latter registered handlers being sorted alphabetically. 

168 """ 

169 handlers = [] 

170 

171 # defaults from caller 

172 if isinstance(default, str): 

173 handlers.append(default) 

174 elif default: 

175 handlers.extend(default) 

176 

177 # configured default, if applicable 

178 default = self.config.get(f'{self.config.appname}.web.menus.handler.default_spec') 

179 if default and default not in handlers: 

180 handlers.append(default) 

181 

182 # registered via entry points 

183 registered = [] 

184 for Handler in load_entry_points(f'{self.appname}.web.menus').values(): 

185 spec = Handler.get_spec() 

186 if spec not in handlers: 

187 registered.append(spec) 

188 if registered: 

189 registered.sort() 

190 handlers.extend(registered) 

191 

192 return handlers 

193 

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

195 """ 

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

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

198 

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

200 constructor. 

201 """ 

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

203 

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

205 """ 

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

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

208 

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

210 constructor. 

211 """ 

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