2
0
Fork 0

fix: let config class specify default app handler, engine maker

this avoids the need for a config subclass to use `setdefault()` hacks
to specify default app handler for instance, since that approach must
compete with config extensions who also may wish to do that.

similar concept for the engine maker; notably the rattail project
needs to override this function somewhat and we need a way to allow
for that without (re-)introducing the app handler here.
This commit is contained in:
Lance Edgar 2024-07-04 07:12:22 -05:00
parent c3efbfbf7b
commit a25712ef54
3 changed files with 68 additions and 4 deletions

View file

@ -126,6 +126,23 @@ class WuttaConfig:
it's useful, but in practice you should not update it directly;
instead use :meth:`setdefault()`.
.. attribute:: default_app_handler_spec
Spec string for the default app handler, if config does not
specify to use another.
The true default for this is ``'wuttjamaican.app:AppHandler'``
(aka. :class:`~wuttjamaican.app.AppHandler`).
.. attribute:: default_engine_maker_spec
Spec string for the default engine maker function, if config
does not specify to use another.
The true default for this is
``'wuttjamaican.db.conf:make_engine_from_config'`` (aka.
:func:`~wuttjamaican.db.conf.make_engine_from_config()`).
.. attribute:: files_read
List of all INI config files which were read on app startup.
@ -165,6 +182,8 @@ class WuttaConfig:
See also :ref:`where-config-settings-come-from`.
"""
default_app_handler_spec = 'wuttjamaican.app:AppHandler'
default_engine_maker_spec = 'wuttjamaican.db.conf:make_engine_from_config'
def __init__(
self,
@ -572,11 +591,22 @@ class WuttaConfig:
"""
if not hasattr(self, '_app'):
spec = self.get(f'{self.appname}.app.handler', usedb=False,
default='wuttjamaican.app:AppHandler')
default=self.default_app_handler_spec)
factory = load_object(spec)
self._app = factory(self)
return self._app
def get_engine_maker(self):
"""
Returns a callable to be used for constructing SQLAlchemy
engines fromc config.
Which callable is used depends on
:attr:`default_engine_maker_spec` but by default will be
:func:`wuttjamaican.db.conf.make_engine_from_config()`.
"""
return load_object(self.default_engine_maker_spec)
class WuttaConfigExtension:
"""

View file

@ -68,16 +68,18 @@ def get_engines(config, prefix):
else:
keys = ['default']
make_engine = config.get_engine_maker()
engines = OrderedDict()
cfg = config.get_dict(prefix)
for key in keys:
key = key.strip()
try:
engines[key] = make_engine_from_config(cfg, prefix=f'{key}.')
engines[key] = make_engine(cfg, prefix=f'{key}.')
except KeyError:
if key == 'default':
try:
engines[key] = make_engine_from_config(cfg, prefix='sqlalchemy.')
engines[key] = make_engine(cfg, prefix='sqlalchemy.')
except KeyError:
pass
return engines

View file

@ -10,6 +10,7 @@ import sqlalchemy as sa
from wuttjamaican import conf
from wuttjamaican.exc import ConfigurationError
from wuttjamaican.db import Session
from wuttjamaican.db.conf import make_engine_from_config
from wuttjamaican.app import AppHandler
from wuttjamaican.testing import FileConfigTestCase
@ -386,12 +387,43 @@ configure_logging = true
self.assertEqual(config.get_list('foo.bar'), ['hello', 'world'])
def test_get_app(self):
# default handler
config = conf.WuttaConfig()
self.assertEqual(config.default_app_handler_spec, 'wuttjamaican.app:AppHandler')
app = config.get_app()
# make sure we get the true default handler class
self.assertIsInstance(app, AppHandler)
# nb. make extra sure we didn't get a subclass
self.assertIs(type(app), AppHandler)
# custom default handler
config = conf.WuttaConfig()
config.default_app_handler_spec = 'tests.test_conf:CustomAppHandler'
app = config.get_app()
self.assertIsInstance(app, CustomAppHandler)
def test_get_engine_maker(self):
# default func
config = conf.WuttaConfig()
self.assertEqual(config.default_engine_maker_spec, 'wuttjamaican.db.conf:make_engine_from_config')
make_engine = config.get_engine_maker()
self.assertIs(make_engine, make_engine_from_config)
# custom default func
config = conf.WuttaConfig()
config.default_engine_maker_spec = 'tests.test_conf:custom_make_engine_from_config'
make_engine = config.get_engine_maker()
self.assertIs(make_engine, custom_make_engine_from_config)
class CustomAppHandler(AppHandler):
pass
def custom_make_engine_from_config(*args, **kwargs):
pass
class TestWuttaConfigExtension(TestCase):