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; it's useful, but in practice you should not update it directly;
instead use :meth:`setdefault()`. 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 .. attribute:: files_read
List of all INI config files which were read on app startup. 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`. 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__( def __init__(
self, self,
@ -572,11 +591,22 @@ class WuttaConfig:
""" """
if not hasattr(self, '_app'): if not hasattr(self, '_app'):
spec = self.get(f'{self.appname}.app.handler', usedb=False, spec = self.get(f'{self.appname}.app.handler', usedb=False,
default='wuttjamaican.app:AppHandler') default=self.default_app_handler_spec)
factory = load_object(spec) factory = load_object(spec)
self._app = factory(self) self._app = factory(self)
return self._app 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: class WuttaConfigExtension:
""" """

View file

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

View file

@ -10,6 +10,7 @@ import sqlalchemy as sa
from wuttjamaican import conf from wuttjamaican import conf
from wuttjamaican.exc import ConfigurationError from wuttjamaican.exc import ConfigurationError
from wuttjamaican.db import Session from wuttjamaican.db import Session
from wuttjamaican.db.conf import make_engine_from_config
from wuttjamaican.app import AppHandler from wuttjamaican.app import AppHandler
from wuttjamaican.testing import FileConfigTestCase from wuttjamaican.testing import FileConfigTestCase
@ -386,12 +387,43 @@ configure_logging = true
self.assertEqual(config.get_list('foo.bar'), ['hello', 'world']) self.assertEqual(config.get_list('foo.bar'), ['hello', 'world'])
def test_get_app(self): def test_get_app(self):
# default handler
config = conf.WuttaConfig() config = conf.WuttaConfig()
self.assertEqual(config.default_app_handler_spec, 'wuttjamaican.app:AppHandler')
app = config.get_app() app = config.get_app()
# make sure we get the true default handler class
self.assertIsInstance(app, AppHandler) self.assertIsInstance(app, AppHandler)
# nb. make extra sure we didn't get a subclass
self.assertIs(type(app), AppHandler) 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): class TestWuttaConfigExtension(TestCase):