hooks: Hooks declare what order they run in.

This commit is contained in:
Brett Smith 2017-12-30 18:09:59 -05:00
parent e8bcbd5f99
commit 85b665200c
9 changed files with 47 additions and 6 deletions

View file

@ -59,6 +59,9 @@ Hooks make arbitrary transformations to entry data dicts. Every entry data dict
If this method returns any other value, the program replaces the entry data with the return value, and continues processing.
Class attribute ``KIND``
This should be one of the values of the ``hooks.HOOK_KINDS`` enum. This information determines what order hooks run in.
Templates
~~~~~~~~~

View file

@ -8,10 +8,6 @@ The big idea: make it easier for hooks to customize *what* template(s) are rende
Required:
* Add some sort of ordering for hooks
Thinking an enum of named stages: data adders, data mungers, filters, actions.
The return value of ``hooks.load_all()`` must respect this ordering.
* Make the main loop seed the entry data with information about the importer used.
* Move template rendering into a hook, where the template to load is determined by a value in the entry data.

View file

@ -1,6 +1,27 @@
import operator
try:
import enum
except ImportError:
import enum34 as enum
from .. import dynload
HOOK_KINDS = enum.Enum('HOOK_KINDS', [
# Hooks will run in the order that their KIND appears in this list.
# DATA_ADDER hooks should add data to the entry from outside sources like
# the user's configuration.
'DATA_ADDER',
# DATA_MUNGER hooks should add or change data in the entry based on what's
# already in it.
'DATA_MUNGER',
# DATA_FILTER hooks make a decision about whether or not to proceed with
# processing the entry.
'DATA_FILTER',
])
def load_all():
return dynload.submodule_items_named(__file__, operator.methodcaller('endswith', 'Hook'))
hooks = list(dynload.submodule_items_named(__file__, operator.methodcaller('endswith', 'Hook')))
hooks.sort(key=operator.attrgetter('KIND.value'))
return hooks

View file

@ -1,7 +1,10 @@
import re
import unicodedata
from . import HOOK_KINDS
class AddEntityHook:
KIND = HOOK_KINDS.DATA_MUNGER
NAME_PREFIXES = frozenset([
'da',
'de',

View file

@ -1,4 +1,8 @@
from . import HOOK_KINDS
class DefaultDateHook:
KIND = HOOK_KINDS.DATA_ADDER
def __init__(self, config):
self.config = config

View file

@ -1,4 +1,8 @@
from . import HOOK_KINDS
class FilterByDateHook:
KIND = HOOK_KINDS.DATA_FILTER
def __init__(self, config):
self.config = config

View file

@ -1,4 +1,8 @@
from . import HOOK_KINDS
class InvoicePaymentHook:
KIND = HOOK_KINDS.DATA_MUNGER
def __init__(self, config):
pass

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3
import itertools
import sys
from setuptools import setup, find_packages
@ -12,6 +13,9 @@ REQUIREMENTS = {
},
}
if sys.version_info < (3, 4):
REQUIREMENTS['install_requires'].extend(['enum34'])
REQUIREMENTS['tests_require'] = [
'pytest',
'PyYAML',

View file

@ -9,7 +9,9 @@ from import2ledger.hooks import add_entity, default_date, filter_by_date
def test_load_all():
all_hooks = list(hooks.load_all())
assert add_entity.AddEntityHook in all_hooks
positions = {hook: index for index, hook in enumerate(all_hooks)}
assert positions[default_date.DefaultDateHook] < positions[add_entity.AddEntityHook]
assert positions[add_entity.AddEntityHook] < positions[filter_by_date.FilterByDateHook]
@pytest.mark.parametrize('in_key,payee,out_key,expected', [
('payee', 'Alex Smith', 'entity', 'Smith-Alex'),