Creating a module function

Creating a module function is just a matter of creating a simple class.

In this example we will create a module function which calculates the grand total of an itemized bill.

Some key points of a module function:

  • Your class must base wishbone.function.module.ModuleFunction
  • Your class must have a do() method which accepts the event and returns it modified.
  • Write a terse docstring as this will be used when issuing wishbone show --docs wishbone_external.function.module.grandtotal.
  • Install your template function along a similar entrypoint in setup.py:
entry_points={
  'wishbone_external.module.grandtotal': [
      'grandtotal = wishbone_external.module.grantotal:GrandTotal'
  ]
}
from wishbone.function.module import ModuleFunction


class GrandTotal(ModuleFunction):
    '''
    Calculates the grand total of all articles.

    A Wishbone module function which calculates the grand total of all the
    article items stored under ``articles``.

    Args:
        source (str): The source field where the articles are stored
        destination (str): The destination field where to write the total.
    '''

    def __init__(self, source='data.articles', destination='data.total'):

        self.source = source
        self.destination = destination

    def do(self, event):
        '''
        The function mapped to the module function.

        Args:
            event (wishbone.event.Event): The Wishbone event.

        Returns:
            wishbone.event.Event: The modified event.
        '''

        total = 0
        for article, price in event.get(self.source).items():
            total += int(price)

        event.set(total, self.destination)
        return event

The following bootstrap YAML file demonstrates how the grandtotal module can be used:

module_functions:
  make_grand_total:
    function: wishbone_external.function.module.grandtotal

template_functions:
  get_price:
    function: wishbone.function.template.random_integer
    arguments:
      minimum: 1
      maximum: 100

modules:
  input:
    module: wishbone.module.input.generator
    arguments:
      payload:
        articles:
          article_1: "{{ get_price() }}"
          article_2: "{{ get_price() }}"
          article_3: "{{ get_price() }}"
          article_4: "{{ get_price() }}"
          article_5: "{{ get_price() }}"

  output:
    module: wishbone.module.output.stdout
    functions:
      inbox:
        - make_grand_total
    arguments:
        selection: .

routingtable:
  - input.outbox -> output.inbox

The output looks like:

$ wishbone start --config module_function_grandtotal.yaml --no-fork
Instance started in foreground with pid 29585
2017-10-29T19:56:51.7004+00:00 wishbone[29585] debug input: Connected queue input._logs to _logs._input
2017-10-29T19:56:51.7006+00:00 wishbone[29585] debug input: Connected queue input._metrics to _metrics._input
2017-10-29T19:56:51.7007+00:00 wishbone[29585] debug input: Connected queue input.outbox to output.inbox
2017-10-29T19:56:51.7009+00:00 wishbone[29585] debug input: preHook() found, executing
2017-10-29T19:56:51.7010+00:00 wishbone[29585] debug input: Started with max queue size of 100 events and metrics interval of 10 seconds.
2017-10-29T19:56:51.7011+00:00 wishbone[29585] debug output: Connected queue output._logs to _logs._output
2017-10-29T19:56:51.7013+00:00 wishbone[29585] debug output: Connected queue output._metrics to _metrics._output
2017-10-29T19:56:51.7014+00:00 wishbone[29585] debug output: preHook() found, executing
2017-10-29T19:56:51.7015+00:00 wishbone[29585] debug output: Started with max queue size of 100 events and metrics interval of 10 seconds.
2017-10-29T19:56:51.7016+00:00 wishbone[29585] debug output: Function 'consume' has been registered to consume queue 'inbox'
{'cloned': False, 'bulk': False, 'data': {'articles': {'article_1': '39', 'article_2': '35', 'article_3': '64', 'article_4': '44', 'article_5': '71'}, 'total': 253}, 'errors': {}, 'tags': [], 'timestamp': 1509307012.7014496, 'tmp': {}, 'ttl': 253, 'uuid_previous': [], 'uuid': 'b42ab53f-9f41-4ad4-814e-2c227537e4fe'}
{'cloned': False, 'bulk': False, 'data': {'articles': {'article_1': '26', 'article_2': '95', 'article_3': '58', 'article_4': '10', 'article_5': '72'}, 'total': 261}, 'errors': {}, 'tags': [], 'timestamp': 1509307013.702464, 'tmp': {}, 'ttl': 253, 'uuid_previous': [], 'uuid': '94a854a6-8400-4a36-b790-070ee0bd5c2c'}
{'cloned': False, 'bulk': False, 'data': {'articles': {'article_1': '36', 'article_2': '10', 'article_3': '96', 'article_4': '89', 'article_5': '82'}, 'total': 313}, 'errors': {}, 'tags': [], 'timestamp': 1509307014.7034726, 'tmp': {}, 'ttl': 253, 'uuid_previous': [], 'uuid': '020e5aed-50fd-46f9-a7a4-495b8a474984'}