plugin: Add HookRegistry.load_included_hooks() method.
This lets us import the plugin module without importing all of the included hooks. This provides better isolation and error reporting in case there's something like a syntax problem in one of the hooks: it doesn't cause importing any plugin module to fail.
This commit is contained in:
parent
fdb62dd1c6
commit
0bf44ade7a
2 changed files with 32 additions and 15 deletions
|
@ -45,6 +45,20 @@ from ..errors import (
|
|||
__plugins__ = ['run']
|
||||
|
||||
class HookRegistry:
|
||||
INCLUDED_HOOKS: Dict[str, Optional[List[str]]] = {
|
||||
'.meta_approval': None,
|
||||
'.meta_entity': None,
|
||||
'.meta_expense_allocation': None,
|
||||
'.meta_income_type': None,
|
||||
'.meta_invoice': None,
|
||||
'.meta_project': None,
|
||||
'.meta_receipt': None,
|
||||
'.meta_receivable_documentation': None,
|
||||
'.meta_repo_links': None,
|
||||
'.meta_rt_links': ['MetaRTLinks'],
|
||||
'.meta_tax_implication': None,
|
||||
}
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.group_name_map: Dict[HookName, Set[Type[Hook]]] = {
|
||||
t.__name__: set() for t in ALL_DIRECTIVES
|
||||
|
@ -61,7 +75,7 @@ class HookRegistry:
|
|||
def import_hooks(self,
|
||||
mod_name: str,
|
||||
*hook_names: str,
|
||||
package: Optional[str]=__module__, # type:ignore[name-defined]
|
||||
package: Optional[str]=None,
|
||||
) -> None:
|
||||
if not hook_names:
|
||||
_, _, hook_name = mod_name.rpartition('.')
|
||||
|
@ -70,6 +84,10 @@ class HookRegistry:
|
|||
for hook_name in hook_names:
|
||||
self.add_hook(getattr(module, hook_name))
|
||||
|
||||
def load_included_hooks(self) -> None:
|
||||
for mod_name, hook_names in self.INCLUDED_HOOKS.items():
|
||||
self.import_hooks(mod_name, *(hook_names or []), package=self.__module__)
|
||||
|
||||
def group_by_directive(self, config_str: str='') -> Iterable[Tuple[HookName, Type[Hook]]]:
|
||||
config_str = config_str.strip()
|
||||
if not config_str:
|
||||
|
@ -96,25 +114,15 @@ class HookRegistry:
|
|||
yield key, hook
|
||||
|
||||
|
||||
HOOK_REGISTRY = HookRegistry()
|
||||
HOOK_REGISTRY.import_hooks('.meta_approval')
|
||||
HOOK_REGISTRY.import_hooks('.meta_entity')
|
||||
HOOK_REGISTRY.import_hooks('.meta_expense_allocation')
|
||||
HOOK_REGISTRY.import_hooks('.meta_income_type')
|
||||
HOOK_REGISTRY.import_hooks('.meta_invoice')
|
||||
HOOK_REGISTRY.import_hooks('.meta_project')
|
||||
HOOK_REGISTRY.import_hooks('.meta_receipt')
|
||||
HOOK_REGISTRY.import_hooks('.meta_receivable_documentation')
|
||||
HOOK_REGISTRY.import_hooks('.meta_repo_links')
|
||||
HOOK_REGISTRY.import_hooks('.meta_rt_links', 'MetaRTLinks')
|
||||
HOOK_REGISTRY.import_hooks('.meta_tax_implication')
|
||||
|
||||
def run(
|
||||
entries: List[Directive],
|
||||
options_map: Dict[str, Any],
|
||||
config: str='',
|
||||
hook_registry: HookRegistry=HOOK_REGISTRY,
|
||||
hook_registry: Optional[HookRegistry]=None,
|
||||
) -> Tuple[List[Directive], List[Error]]:
|
||||
if hook_registry is None:
|
||||
hook_registry = HookRegistry()
|
||||
hook_registry.load_included_hooks()
|
||||
errors: List[Error] = []
|
||||
hooks: Dict[HookName, List[Hook]] = {
|
||||
# mypy thinks NamedTuples don't have __name__ but they do at runtime.
|
||||
|
|
|
@ -112,6 +112,15 @@ def test_registry_unknown_group_name():
|
|||
with pytest.raises(ValueError):
|
||||
next(HOOK_REGISTRY.group_by_directive('UnKnownTestGroup'))
|
||||
|
||||
def test_registry_load_included_hooks():
|
||||
registry = plugin.HookRegistry()
|
||||
assert not list(registry.group_by_directive())
|
||||
registry.load_included_hooks()
|
||||
actual = {hook.__name__ for key, hook in registry.group_by_directive() if key == 'Transaction'}
|
||||
assert len(actual) >= 5
|
||||
assert 'MetaProject' in actual
|
||||
assert 'MetaRTLinks' in actual
|
||||
|
||||
def test_run_with_multiple_hooks(easy_entries, config_map):
|
||||
out_entries, errors = plugin.run(easy_entries, config_map, '', HOOK_REGISTRY)
|
||||
assert len(out_entries) == 2
|
||||
|
|
Loading…
Reference in a new issue