3
0
Fork 0

feat: add basic theme system

This is intended to allow override of look/feel without overriding the
logic/structure of templates.  In practice the main goal internally is
to allow testing of Vue 3 + Oruga, to eventually replace Vue 2 + Buefy
as the default theme.
This commit is contained in:
Lance Edgar 2025-06-29 09:16:44 -05:00
parent 749aca560a
commit 796e793547
20 changed files with 1604 additions and 52 deletions

View file

@ -3,7 +3,7 @@
from unittest import TestCase
from unittest.mock import patch
from wuttjamaican.testing import FileTestCase, ConfigTestCase
from wuttjamaican.testing import FileTestCase, ConfigTestCase, DataTestCase
from asgiref.wsgi import WsgiToAsgi
from pyramid.config import Configurator
@ -11,6 +11,8 @@ from pyramid.router import Router
from wuttaweb import app as mod
from wuttjamaican.conf import WuttaConfig
from wuttjamaican.app import AppHandler
from wuttjamaican.util import resource_path
class TestWebAppProvider(TestCase):
@ -45,22 +47,25 @@ class TestMakeWuttaConfig(FileTestCase):
self.assertIs(settings['wutta_config'], config)
class TestMakePyramidConfig(TestCase):
class TestMakePyramidConfig(DataTestCase):
def test_basic(self):
settings = {}
config = mod.make_pyramid_config(settings)
self.assertIsInstance(config, Configurator)
with patch.object(AppHandler, 'make_session', return_value=self.session):
settings = {'wutta_config': self.config}
config = mod.make_pyramid_config(settings)
self.assertIsInstance(config, Configurator)
self.assertEqual(settings['wuttaweb.theme'], 'default')
class TestMain(FileTestCase):
class TestMain(DataTestCase):
def test_basic(self):
global_config = None
myconf = self.write_file('my.conf', '')
settings = {'wutta.config': myconf}
app = mod.main(global_config, **settings)
self.assertIsInstance(app, Router)
with patch.object(AppHandler, 'make_session', return_value=self.session):
global_config = None
myconf = self.write_file('my.conf', '')
settings = {'wutta.config': myconf}
app = mod.main(global_config, **settings)
self.assertIsInstance(app, Router)
def mock_main(global_config, **settings):
@ -75,19 +80,20 @@ def mock_main(global_config, **settings):
return pyramid_config.make_wsgi_app()
class TestMakeWsgiApp(ConfigTestCase):
class TestMakeWsgiApp(DataTestCase):
def test_with_callable(self):
with patch.object(self.app, 'make_session', return_value=self.session):
# specify config
wsgi = mod.make_wsgi_app(mock_main, config=self.config)
self.assertIsInstance(wsgi, Router)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
wsgi = mod.make_wsgi_app(mock_main)
# specify config
wsgi = mod.make_wsgi_app(mock_main, config=self.config)
self.assertIsInstance(wsgi, Router)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
wsgi = mod.make_wsgi_app(mock_main)
self.assertIsInstance(wsgi, Router)
def test_with_spec(self):
# specify config
@ -103,29 +109,87 @@ class TestMakeWsgiApp(ConfigTestCase):
self.assertRaises(ValueError, mod.make_wsgi_app, 42, config=self.config)
class TestMakeAsgiApp(ConfigTestCase):
class TestMakeAsgiApp(DataTestCase):
def test_with_callable(self):
with patch.object(self.app, 'make_session', return_value=self.session):
# specify config
asgi = mod.make_asgi_app(mock_main, config=self.config)
self.assertIsInstance(asgi, WsgiToAsgi)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
asgi = mod.make_asgi_app(mock_main)
# specify config
asgi = mod.make_asgi_app(mock_main, config=self.config)
self.assertIsInstance(asgi, WsgiToAsgi)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
asgi = mod.make_asgi_app(mock_main)
self.assertIsInstance(asgi, WsgiToAsgi)
def test_with_spec(self):
with patch.object(self.app, 'make_session', return_value=self.session):
# specify config
asgi = mod.make_asgi_app('tests.test_app:mock_main', config=self.config)
self.assertIsInstance(asgi, WsgiToAsgi)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
asgi = mod.make_asgi_app('tests.test_app:mock_main')
# specify config
asgi = mod.make_asgi_app('tests.test_app:mock_main', config=self.config)
self.assertIsInstance(asgi, WsgiToAsgi)
# auto config
with patch.object(mod, 'make_config', return_value=self.config):
asgi = mod.make_asgi_app('tests.test_app:mock_main')
self.assertIsInstance(asgi, WsgiToAsgi)
def test_invalid(self):
self.assertRaises(ValueError, mod.make_asgi_app, 42, config=self.config)
class TestEstablishTheme(DataTestCase):
def test_default(self):
settings = {
'wutta_config': self.config,
'mako.directories': ['wuttaweb:templates'],
}
mod.establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'default')
self.assertEqual(settings['mako.directories'], [
resource_path('wuttaweb:templates/themes/default'),
'wuttaweb:templates',
])
def test_mako_dirs_as_string(self):
settings = {
'wutta_config': self.config,
'mako.directories': 'wuttaweb:templates',
}
mod.establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'default')
self.assertEqual(settings['mako.directories'], [
resource_path('wuttaweb:templates/themes/default'),
'wuttaweb:templates',
])
def test_butterfly(self):
settings = {
'wutta_config': self.config,
'mako.directories': 'wuttaweb:templates',
}
self.app.save_setting(self.session, 'wuttaweb.theme', 'butterfly')
self.session.commit()
mod.establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'butterfly')
self.assertEqual(settings['mako.directories'], [
resource_path('wuttaweb:templates/themes/butterfly'),
'wuttaweb:templates',
])
def test_custom(self):
settings = {
'wutta_config': self.config,
'mako.directories': 'wuttaweb:templates',
}
self.config.setdefault('wuttaweb.themes.keys', 'anotherone')
self.app.save_setting(self.session, 'wuttaweb.theme', 'anotherone')
self.session.commit()
mod.establish_theme(settings)
self.assertEqual(settings['wuttaweb.theme'], 'anotherone')
self.assertEqual(settings['mako.directories'], [
resource_path('wuttaweb:templates/themes/anotherone'),
'wuttaweb:templates',
])