3
0
Fork 0

fix: add get_batch_handler() method for app handler

also `get_batch_handler_specs()`
This commit is contained in:
Lance Edgar 2025-01-13 11:51:36 -06:00
parent 174a17dd5e
commit a302f323af
2 changed files with 157 additions and 6 deletions

View file

@ -842,6 +842,87 @@ class AppHandler:
self.handlers['auth'] = factory(self.config, **kwargs)
return self.handlers['auth']
def get_batch_handler(self, key, default=None, **kwargs):
"""
Get the configured :term:`batch handler` for the given type.
:param key: Unique key designating the :term:`batch type`.
:param default: Spec string to use as the default, if none is
configured.
:returns: :class:`~wuttjamaican.batch.BatchHandler` instance
for the requested type. If no spec can be determined, a
``KeyError`` is raised.
"""
spec = self.config.get(f'{self.appname}.batch.{key}.handler.spec',
default=default)
if not spec:
spec = self.config.get(f'{self.appname}.batch.{key}.handler.default_spec')
if not spec:
raise KeyError(f"handler spec not found for batch key: {key}")
factory = self.load_object(spec)
return factory(self.config, **kwargs)
def get_batch_handler_specs(self, key, default=None):
"""
Get the :term:`spec` strings for all available handlers of the
given batch type.
:param key: Unique key designating the :term:`batch type`.
:param default: Default spec string(s) to include, even if not
registered. Can be a string or list of strings.
:returns: List of batch handler spec strings.
This will gather available spec strings from the following:
First, the ``default`` as provided by caller.
Second, the default spec from config, if set; for example:
.. code-block:: ini
[wutta.batch]
inventory.handler.default_spec = poser.batch.inventory:InventoryBatchHandler
Third, each spec registered via entry points. For instance in
``pyproject.toml``:
.. code-block:: toml
[project.entry-points."wutta.batch.inventory"]
poser = "poser.batch.inventory:InventoryBatchHandler"
The final list will be "sorted" according to the above, with
the latter registered handlers being sorted alphabetically.
"""
handlers = []
# defaults from caller
if isinstance(default, str):
handlers.append(default)
elif default:
handlers.extend(default)
# configured default, if applicable
default = self.config.get(f'{self.config.appname}.batch.{key}.handler.default_spec')
if default and default not in handlers:
handlers.append(default)
# registered via entry points
registered = []
for Handler in load_entry_points(f'{self.appname}.batch.{key}').values():
spec = Handler.get_spec()
if spec not in handlers:
registered.append(spec)
if registered:
registered.sort()
handlers.extend(registered)
return handlers
def get_db_handler(self, **kwargs):
"""
Get the configured :term:`db handler`.
@ -1021,3 +1102,10 @@ class GenericHandler:
See also :attr:`AppHandler.appname`.
"""
return self.app.appname
@classmethod
def get_spec(cls):
"""
Returns the class :term:`spec` string for the handler.
"""
return f'{cls.__module__}:{cls.__name__}'

View file

@ -19,7 +19,15 @@ from wuttjamaican import app as mod
from wuttjamaican.progress import ProgressBase
from wuttjamaican.conf import WuttaConfig
from wuttjamaican.util import UNSPECIFIED
from wuttjamaican.testing import FileTestCase
from wuttjamaican.testing import FileTestCase, ConfigTestCase
from wuttjamaican.batch import BatchHandler
class MockBatchHandler(BatchHandler):
pass
class AnotherBatchHandler(BatchHandler):
pass
class TestAppHandler(FileTestCase):
@ -546,6 +554,59 @@ app_title = WuttaTest
auth = self.app.get_auth_handler()
self.assertIsInstance(auth, AuthHandler)
def test_get_batch_handler(self):
# error if handler not found
self.assertRaises(KeyError, self.app.get_batch_handler, 'CannotFindMe!')
# caller can specify default
handler = self.app.get_batch_handler('foo', default='wuttjamaican.batch:BatchHandler')
self.assertIsInstance(handler, BatchHandler)
# default can be configured
self.config.setdefault('wuttatest.batch.foo.handler.default_spec',
'wuttjamaican.batch:BatchHandler')
handler = self.app.get_batch_handler('foo')
self.assertIsInstance(handler, BatchHandler)
# preference can be configured
self.config.setdefault('wuttatest.batch.foo.handler.spec',
'tests.test_app:MockBatchHandler')
handler = self.app.get_batch_handler('foo')
self.assertIsInstance(handler, MockBatchHandler)
def test_get_batch_handler_specs(self):
# empty by default
specs = self.app.get_batch_handler_specs('foo')
self.assertEqual(specs, [])
# caller can specify default as string
specs = self.app.get_batch_handler_specs('foo', default='wuttjamaican.batch:BatchHandler')
self.assertEqual(specs, ['wuttjamaican.batch:BatchHandler'])
# caller can specify default as list
specs = self.app.get_batch_handler_specs('foo', default=['wuttjamaican.batch:BatchHandler',
'tests.test_app:MockBatchHandler'])
self.assertEqual(specs, ['wuttjamaican.batch:BatchHandler',
'tests.test_app:MockBatchHandler'])
# default can be configured
self.config.setdefault('wuttatest.batch.foo.handler.default_spec',
'wuttjamaican.batch:BatchHandler')
specs = self.app.get_batch_handler_specs('foo')
self.assertEqual(specs, ['wuttjamaican.batch:BatchHandler'])
# the rest come from entry points
with patch.object(mod, 'load_entry_points', return_value={
'mock': MockBatchHandler,
'another': AnotherBatchHandler,
}):
specs = self.app.get_batch_handler_specs('foo')
self.assertEqual(specs, ['wuttjamaican.batch:BatchHandler',
'tests.test_app:AnotherBatchHandler',
'tests.test_app:MockBatchHandler'])
def test_get_db_handler(self):
try:
from wuttjamaican.db.handler import DatabaseHandler
@ -684,15 +745,17 @@ class TestAppProvider(TestCase):
self.assertEqual(self.app.foo_value, 'bar')
class TestGenericHandler(TestCase):
class TestGenericHandler(ConfigTestCase):
def setUp(self):
self.config = WuttaConfig(appname='wuttatest')
self.app = mod.AppHandler(self.config)
self.config._app = self.app
def make_config(self, **kw):
kw.setdefault('appname', 'wuttatest')
return super().make_config(**kw)
def test_constructor(self):
handler = mod.GenericHandler(self.config)
self.assertIs(handler.config, self.config)
self.assertIs(handler.app, self.app)
self.assertEqual(handler.appname, 'wuttatest')
def test_get_spec(self):
self.assertEqual(mod.GenericHandler.get_spec(), 'wuttjamaican.app:GenericHandler')