Compare commits
	
		
			2 commits
		
	
	
		
			ce79346f76
			...
			a302f323af
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a302f323af | |||
| 174a17dd5e | 
					 3 changed files with 160 additions and 8 deletions
				
			
		|  | @ -182,8 +182,9 @@ Glossary | ||||||
|      The "session" is a SQLAlchemy abstraction for an open database |      The "session" is a SQLAlchemy abstraction for an open database | ||||||
|      connection, essentially. |      connection, essentially. | ||||||
| 
 | 
 | ||||||
|      In practice this generally refers to a |      For the :term:`app database`, the class used is | ||||||
|      :class:`~wuttjamaican.db.sess.Session` instance. |      :class:`~wuttjamaican.db.sess.Session`; other databases may use | ||||||
|  |      different classes. | ||||||
| 
 | 
 | ||||||
|    email handler |    email handler | ||||||
|       The :term:`handler` responsible for sending email on behalf of |       The :term:`handler` responsible for sending email on behalf of | ||||||
|  |  | ||||||
|  | @ -842,6 +842,87 @@ class AppHandler: | ||||||
|             self.handlers['auth'] = factory(self.config, **kwargs) |             self.handlers['auth'] = factory(self.config, **kwargs) | ||||||
|         return self.handlers['auth'] |         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): |     def get_db_handler(self, **kwargs): | ||||||
|         """ |         """ | ||||||
|         Get the configured :term:`db handler`. |         Get the configured :term:`db handler`. | ||||||
|  | @ -1021,3 +1102,10 @@ class GenericHandler: | ||||||
|         See also :attr:`AppHandler.appname`. |         See also :attr:`AppHandler.appname`. | ||||||
|         """ |         """ | ||||||
|         return self.app.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__}' | ||||||
|  |  | ||||||
|  | @ -19,7 +19,15 @@ from wuttjamaican import app as mod | ||||||
| from wuttjamaican.progress import ProgressBase | from wuttjamaican.progress import ProgressBase | ||||||
| from wuttjamaican.conf import WuttaConfig | from wuttjamaican.conf import WuttaConfig | ||||||
| from wuttjamaican.util import UNSPECIFIED | 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): | class TestAppHandler(FileTestCase): | ||||||
|  | @ -546,6 +554,59 @@ app_title = WuttaTest | ||||||
|         auth = self.app.get_auth_handler() |         auth = self.app.get_auth_handler() | ||||||
|         self.assertIsInstance(auth, AuthHandler) |         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): |     def test_get_db_handler(self): | ||||||
|         try: |         try: | ||||||
|             from wuttjamaican.db.handler import DatabaseHandler |             from wuttjamaican.db.handler import DatabaseHandler | ||||||
|  | @ -684,15 +745,17 @@ class TestAppProvider(TestCase): | ||||||
|         self.assertEqual(self.app.foo_value, 'bar') |         self.assertEqual(self.app.foo_value, 'bar') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestGenericHandler(TestCase): | class TestGenericHandler(ConfigTestCase): | ||||||
| 
 | 
 | ||||||
|     def setUp(self): |     def make_config(self, **kw): | ||||||
|         self.config = WuttaConfig(appname='wuttatest') |         kw.setdefault('appname', 'wuttatest') | ||||||
|         self.app = mod.AppHandler(self.config) |         return super().make_config(**kw) | ||||||
|         self.config._app = self.app |  | ||||||
| 
 | 
 | ||||||
|     def test_constructor(self): |     def test_constructor(self): | ||||||
|         handler = mod.GenericHandler(self.config) |         handler = mod.GenericHandler(self.config) | ||||||
|         self.assertIs(handler.config, self.config) |         self.assertIs(handler.config, self.config) | ||||||
|         self.assertIs(handler.app, self.app) |         self.assertIs(handler.app, self.app) | ||||||
|         self.assertEqual(handler.appname, 'wuttatest') |         self.assertEqual(handler.appname, 'wuttatest') | ||||||
|  | 
 | ||||||
|  |     def test_get_spec(self): | ||||||
|  |         self.assertEqual(mod.GenericHandler.get_spec(), 'wuttjamaican.app:GenericHandler') | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue