2
0
Fork 0

Compare commits

...

5 commits

Author SHA1 Message Date
Lance Edgar 8ae140555a build: just run pytest, avoid tox when building release 2024-07-14 11:10:54 -05:00
Lance Edgar 5197fa9ae9 bump: version 0.1.0 → 0.2.0 2024-07-14 11:10:10 -05:00
Lance Edgar 1d113da45a feat: add "web handler" feature; it must get the menu handler
this makes more sense than (potentially) adding a whole bunch of
methods to the app handler.

also fix entry point for app provider, per wj changes
2024-07-14 11:07:50 -05:00
Lance Edgar 9c5320a31c docs: update project urls to wuttaproject.org 2024-07-14 08:47:34 -05:00
Lance Edgar ca2e0e88a6 docs: add link to test coverage report 2024-07-13 20:57:25 -05:00
12 changed files with 139 additions and 21 deletions

View file

@ -5,6 +5,14 @@ All notable changes to wuttaweb will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## v0.2.0 (2024-07-14)
### Feat
- add basic support for menu handler
- add "web handler" feature; it must get the menu handler
## v0.1.0 (2024-07-12) ## v0.1.0 (2024-07-12)
### Feat ### Feat

View file

@ -0,0 +1,6 @@
``wuttaweb.handler``
====================
.. automodule:: wuttaweb.handler
:members:

View file

@ -8,6 +8,7 @@
:maxdepth: 1 :maxdepth: 1
app app
handler
helpers helpers
menus menus
static static

View file

@ -6,6 +6,11 @@ This package provides a "web layer" for custom apps.
It uses traditional server-side rendering with VueJS on the front-end. It uses traditional server-side rendering with VueJS on the front-end.
Good documentation and 100% `test coverage`_ are priorities for this
project.
.. _test coverage: https://buildbot.rattailproject.org/coverage/wuttaweb/
.. toctree:: .. toctree::
:maxdepth: 3 :maxdepth: 3
:caption: Contents: :caption: Contents:

View file

@ -6,7 +6,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "WuttaWeb" name = "WuttaWeb"
version = "0.1.0" version = "0.2.0"
description = "Web App for Wutta Framework" description = "Web App for Wutta Framework"
readme = "README.md" readme = "README.md"
authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]
@ -35,7 +35,7 @@ dependencies = [
"pyramid_mako", "pyramid_mako",
"waitress", "waitress",
"WebHelpers2", "WebHelpers2",
"WuttJamaican[db]>=0.6.1", "WuttJamaican[db]>=0.7.0",
] ]
@ -48,14 +48,14 @@ tests = ["pytest-cov", "tox"]
main = "wuttaweb.app:main" main = "wuttaweb.app:main"
[project.entry-points."wutta.providers"] [project.entry-points."wutta.app.providers"]
wuttaweb = "wuttaweb.app:WebAppProvider" wuttaweb = "wuttaweb.app:WebAppProvider"
[project.urls] [project.urls]
Homepage = "https://rattailproject.org/" Homepage = "https://wuttaproject.org/"
Repository = "https://kallithea.rattailproject.org/rattail-project/wuttaweb" Repository = "https://forgejo.wuttaproject.org/wutta/wuttaweb"
Changelog = "https://kallithea.rattailproject.org/rattail-project/wuttaweb/files/master/CHANGELOG.md" Changelog = "https://forgejo.wuttaproject.org/wutta/wuttaweb/src/branch/master/CHANGELOG.md"
[tool.commitizen] [tool.commitizen]

View file

@ -34,28 +34,28 @@ from pyramid.config import Configurator
class WebAppProvider(AppProvider): class WebAppProvider(AppProvider):
""" """
The :term:`app provider<app provider>` for WuttaWeb. This adds The :term:`app provider` for WuttaWeb. This adds some methods
some methods to get web-specific :term:`handlers<handler>`. specific to web apps.
""" """
def get_web_menu_handler(self, **kwargs): def get_web_handler(self, **kwargs):
""" """
Get the configured "menu" handler for the web app. Get the configured "web" handler for the app.
Specify a custom handler in your config file like this: Specify a custom handler in your config file like this:
.. code-block:: ini .. code-block:: ini
[wuttaweb] [wutta]
menus.handler_spec = poser.web.menus:PoserMenuHandler web.handler_spec = poser.web.handler:PoserWebHandler
:returns: Instance of :class:`~wuttaweb.menus.MenuHandler`. :returns: Instance of :class:`~wuttaweb.handler.WebHandler`.
""" """
if 'web_menu_handler' not in self.__dict__: if 'web_handler' not in self.__dict__:
spec = self.config.get('wuttaweb.menus.handler_spec', spec = self.config.get(f'{self.appname}.web.handler_spec',
default='wuttaweb.menus:MenuHandler') default='wuttaweb.handler:WebHandler')
self.web_menu_handler = self.app.load_object(spec)(self.config) self.web_handler = self.app.load_object(spec)(self.config)
return self.web_menu_handler return self.web_handler
def make_wutta_config(settings): def make_wutta_config(settings):

57
src/wuttaweb/handler.py Normal file
View file

@ -0,0 +1,57 @@
# -*- coding: utf-8; -*-
################################################################################
#
# wuttaweb -- Web App for Wutta Framework
# Copyright © 2024 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# Wutta Framework is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Web Handler
This defines the :term:`handler` for the web layer.
"""
from wuttjamaican.app import GenericHandler
class WebHandler(GenericHandler):
"""
Base class and default implementation for the "web" :term:`handler`.
This is responsible for determining the "menu handler" and
(eventually) possibly other things.
"""
def get_menu_handler(self, **kwargs):
"""
Get the configured "menu" handler for the web app.
Specify a custom handler in your config file like this:
.. code-block:: ini
[wutta.web]
menus.handler_spec = poser.web.menus:PoserMenuHandler
:returns: Instance of :class:`~wuttaweb.menus.MenuHandler`.
"""
if not hasattr(self, 'menu_handler'):
spec = self.config.get(f'{self.appname}.web.menus.handler_spec',
default='wuttaweb.menus:MenuHandler')
self.menu_handler = self.app.load_object(spec)(self.config)
return self.menu_handler

View file

@ -138,7 +138,7 @@ class MenuHandler(GenericHandler):
The web app calls this method but you normally should not need The web app calls this method but you normally should not need
to override it; you can override :meth:`make_menus()` instead. to override it; you can override :meth:`make_menus()` instead.
""" """
raw_menus = self.make_menus(request, **kwargs) raw_menus = self._make_raw_menus(request, **kwargs)
# now we have "simple" (raw) menus definition, but must refine # now we have "simple" (raw) menus definition, but must refine
# that somewhat to produce our final menus # that somewhat to produce our final menus
@ -209,6 +209,16 @@ class MenuHandler(GenericHandler):
return final_menus return final_menus
def _make_raw_menus(self, request, **kwargs):
"""
Construct the initial full set of "raw" menus.
For now this just calls :meth:`make_menus()` which generally
means a "hard-coded" menu set. Eventually it may allow for
loading dynamic menus from config instead.
"""
return self.make_menus(request, **kwargs)
def _is_allowed(self, request, item): def _is_allowed(self, request, item):
""" """
Logic to determine if a given menu item is "allowed" for Logic to determine if a given menu item is "allowed" for

View file

@ -36,12 +36,16 @@ hooks contained here, depending on the circumstance.
""" """
import json import json
import logging
from pyramid import threadlocal from pyramid import threadlocal
from wuttaweb import helpers from wuttaweb import helpers
log = logging.getLogger(__name__)
def new_request(event): def new_request(event):
""" """
Event hook called when processing a new request. Event hook called when processing a new request.
@ -129,6 +133,7 @@ def before_render(event):
request = event.get('request') or threadlocal.get_current_request() request = event.get('request') or threadlocal.get_current_request()
config = request.wutta_config config = request.wutta_config
app = config.get_app() app = config.get_app()
web = app.get_web_handler()
context = event context = event
context['app'] = app context['app'] = app
@ -137,7 +142,7 @@ def before_render(event):
context['url'] = request.route_url context['url'] = request.route_url
context['json'] = json context['json'] = json
menus = app.get_web_menu_handler() menus = web.get_menu_handler()
context['menus'] = menus.do_make_menus(request) context['menus'] = menus.do_make_menus(request)

View file

@ -15,7 +15,7 @@ def release(c, skip_tests=False):
Release a new version of WuttJamaican Release a new version of WuttJamaican
""" """
if not skip_tests: if not skip_tests:
c.run('tox') c.run('pytest')
# rebuild pkg # rebuild pkg
if os.path.exists('dist'): if os.path.exists('dist'):

20
tests/test_handler.py Normal file
View file

@ -0,0 +1,20 @@
# -*- coding: utf-8; -*-
from unittest import TestCase
from wuttjamaican.conf import WuttaConfig
from wuttaweb import handler as mod
from wuttaweb.menus import MenuHandler
class TestWebHandler(TestCase):
def setUp(self):
self.config = WuttaConfig()
self.app = self.config.get_app()
self.handler = mod.WebHandler(self.config)
def test_menu_handler_default(self):
menus = self.handler.get_menu_handler()
self.assertIsInstance(menus, MenuHandler)

View file

@ -159,6 +159,12 @@ class TestMenuHandler(TestCase):
self.assertTrue(entry['is_sep']) self.assertTrue(entry['is_sep'])
self.assertFalse(entry['is_menu']) self.assertFalse(entry['is_menu'])
def test_make_raw_menus(self):
# minimal test to ensure it calls the other method
with patch.object(self.handler, 'make_menus') as make_menus:
self.handler._make_raw_menus(self.request, foo='bar')
make_menus.assert_called_once_with(self.request, foo='bar')
def test_do_make_menus_prune_unallowed_item(self): def test_do_make_menus_prune_unallowed_item(self):
test_menus = [ test_menus = [
{ {