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
« 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"""
27import warnings
29from wuttjamaican.app import GenericHandler
30from wuttjamaican.util import load_entry_points
32from wuttaweb import static, forms, grids
35class WebHandler(GenericHandler):
36 """
37 Base class and default implementation for the :term:`web handler`.
39 This is responsible for determining the :term:`menu handler` and
40 various other customizations.
41 """
43 def get_fanstatic_url(self, request, resource):
44 """
45 Returns the full URL to the given Fanstatic resource.
47 :param request: Current :term:`request` object.
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
58 def get_favicon_url(self, request):
59 """
60 Returns the canonical app favicon image URL.
62 This will return the fallback favicon from WuttaWeb unless
63 config specifies an override:
65 .. code-block:: ini
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)
75 def get_header_logo_url(self, request):
76 """
77 Returns the canonical app header image URL.
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.
83 .. code-block:: ini
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)
93 def get_main_logo_url(self, request):
94 """
95 Returns the canonical app logo image URL.
97 This will return the fallback logo from WuttaWeb unless config
98 specifies an override:
100 .. code-block:: ini
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)
110 def get_menu_handler(self):
111 """
112 Get the configured :term:`menu handler` for the web app.
114 Specify a custom handler in your config file like this:
116 .. code-block:: ini
118 [wutta.web]
119 menus.handler.spec = poser.web.menus:PoserMenuHandler
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)
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()`.
146 :param default: Default spec string(s) to include, even if not
147 registered. Can be a string or list of strings.
149 :returns: List of menu handler spec strings.
151 This will gather available spec strings from the following:
153 First, the ``default`` as provided by caller.
155 Second, the default spec from config, if set; for example:
157 .. code-block:: ini
159 [wutta.web]
160 menus.handler.default_spec = poser.web.menus:PoserMenuHandler
162 Third, each spec registered via entry points. For instance in
163 ``pyproject.toml``:
165 .. code-block:: toml
167 [project.entry-points."wutta.web.menus"]
168 poser = "poser.web.menus:PoserMenuHandler"
170 The final list will be "sorted" according to the above, with
171 the latter registered handlers being sorted alphabetically.
172 """
173 handlers = []
175 # defaults from caller
176 if isinstance(default, str):
177 handlers.append(default)
178 elif default:
179 handlers.extend(default)
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)
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)
198 return handlers
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``.
205 This is the "base" factory which merely invokes the
206 constructor.
207 """
208 return forms.Form(request, **kwargs)
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``.
215 This is the "base" factory which merely invokes the
216 constructor.
217 """
218 return grids.Grid(request, **kwargs)