fruitfly

Modular event-driven framework.


License
WTFPL
Install
pip install fruitfly==0.1.4

Documentation

pypi

Fruitfly

Python framework for minimalist, modular, event-driven embedded applications.

Architecture

Fruitfly is intended to be used in embedded systems where fault tolerance and low overheads are desirable properties.

The user is encouraged to create a series of small modules with clear responsibilities, and to pass events between these modules. A module can register to have several callbacks at varying intervals, and to be notified when another module sends an event matching a pattern.

Features

  • Takes care of logging (syslog, stderr) and configuration. (one YAML file)
  • Simple module loading.
  • Easy event handler registration, with glob syntax. (match events like foo.*)
  • Module crash detection and retrying, with execution frequency backoff after an uncaught exception.
  • Supports python 2 and 3.
  • Only one non-stdlib dependency, yaml

Intended use

It is hoped that Fruitfly will be a useful base to build upon for projects like:

  • In-car entertainment or data logging.
  • Interactive/installation art.
  • Home automation, perhaps as a lighting controller.

Examples

# A simple YAML configuration file defining two modules.
modules:
  producer:
    message: foo
  consumer:
# Example producer module, sends an event every second.
import fruitfly

class producer(fruitfly.Module):
    @fruitfly.repeat(1)
    def everysecond(self):
      self.send_event("test.bar", (123, self.config['message']))
# Example consumer module, receives messages from another module.
import fruitfly

class consumer(fruitfly.Module):
    @fruitfly.event("test.*")
    def handler(self, event, payload):
        self.logger.info("Got event %s with payload %s", event, payload)
# An example session.
/home/user/fruitfly/example/producer_consumer $ python -m fruitfly
fruitfly[3724] INFO fruitfly Using /home/user/fruitfly/example/producer_consumer to find config and modules.
fruitfly[3724] INFO fruitfly Loaded config from /home/user/fruitfly/example/producer_consumer/fruitfly.yaml
fruitfly[3724] INFO fruitfly Loading modules from /home/user/fruitfly/example/producer_consumer/mod_*.py
fruitfly[3724] DEBUG fruitfly Loading module consumer from /home/user/fruitfly/example/producer_consumer/mod_consumer.py with config None
fruitfly[3724] INFO fruitfly Enabled module consumer
fruitfly[3724] DEBUG fruitfly Loading module producer from /home/user/fruitfly/example/producer_consumer/mod_producer.py with config {'message': 'foo'}
fruitfly[3724] INFO fruitfly Enabled module producer
fruitfly[3724] DEBUG producer event: test.bar '(123, 'foo')'
fruitfly[3724] DEBUG fruitfly Distributing event test.bar '(123, 'foo')'
fruitfly[3724] INFO consumer Got event test.bar with payload (123, 'foo')
fruitfly[3724] DEBUG producer event: test.bar '(123, 'foo')'
fruitfly[3724] DEBUG fruitfly Distributing event test.bar '(123, 'foo')'
fruitfly[3724] INFO consumer Got event test.bar with payload (123, 'foo')

Crash behaviour

When a module raises an exception handling an event, it is logged:

fruitfly[4247] ERROR consumer handler handling test.bar event with payload '(123, 'foo')' crashed: ZeroDivisionError('float division by zero',)

... but the event handler remains registered for future events.

When a repeatedly called function raises an exception, it is logged and the next run delayed:

fruitfly[4283] ERROR producer everysecond crashed: ZeroDivisionError('float division by zero',) (next run delayed by 5.00s)

The objective is to allow users to easily write robust systems that won't need a restart or fiddling to get back to normal operation.

TODO

  • Tests.
  • Continuous integration.
  • Debian packaging with an init script.

Bugs

  • Probably!

Contributing

Contributions are welcome. Open an issue or send a pull request.

License

See LICENSE file.