charms.reactive.bus

Summary

BrokenHandlerException
ExternalHandler A variant Handler for external executable actions (such as bash scripts).
Handler Class representing a reactive state handler.
State A reactive state that can be set.
StateList Base class for a set of states that can be set by a relation or layer.
StateWatch
discover Discover handlers based on convention.
dispatch Dispatch registered handlers.
get_state Return the value associated with an active state, or None
get_states Return a mapping of all active states to their values.
remove_state Remove / deactivate a state.
set_state Set the given state as active, optionally associating with a relation.

Reference

exception charms.reactive.bus.BrokenHandlerException(path)

Bases: Exception

class charms.reactive.bus.ExternalHandler(filepath)

Bases: charms.reactive.bus.Handler

A variant Handler for external executable actions (such as bash scripts).

External handlers must adhere to the following protocol:

  • The handler can be any executable
  • When invoked with the --test command-line flag, it should exit with an exit code of zero to indicate that the handler should be invoked, and a non-zero exit code to indicate that it need not be invoked. It can also provide a line of output to be passed to the --invoke call, e.g., to indicate which sub-handlers should be invoked. The handler should not perform its action when given this flag.
  • When invoked with the --invoke command-line flag (which will be followed by any output returned by the --test call), the handler should perform its action(s).
id()
invoke()

Call the external handler to be invoked.

classmethod register(filepath)
test()

Call the external handler to test whether it should be invoked.

class charms.reactive.bus.Handler(action)

Bases: object

Class representing a reactive state handler.

add_args(args)

Add arguments to be passed to the action when invoked.

Parameters:args – Any sequence or iterable, which will be lazily evaluated to provide args. Subsequent calls to add_args() can be used to add additional arguments.
add_post_callback(callback)

Add a callback to be run after the action is invoked.

add_predicate(predicate)

Add a new predicate callback to this handler.

classmethod clear()

Clear all registered handlers.

classmethod get(action)

Get or register a handler for the given action.

Parameters:
  • action (func) – Callback that is called when invoking the Handler
  • args_source (func) – Optional callback that generates args for the action
classmethod get_handlers()

Clear all registered handlers.

id()
invoke()

Invoke this handler.

register_states(states)

Register states as being relevant to this handler.

Relevant states will be used to determine if the handler should be re-invoked due to changes in the set of active states. If this handler has already been invoked during this dispatch() run and none of its relevant states have been set or removed since then, then the handler will be skipped.

This is also used for linting and composition purposes, to determine if a layer has unhandled states.

test()

Check the predicate(s) and return True if this handler should be invoked.

class charms.reactive.bus.State

Bases: str

A reactive state that can be set.

States are essentially just strings, but this class should be used to enable them to be discovered and introspected, for documentation, composition, or linting.

This should be used with StateList.

class charms.reactive.bus.StateList

Bases: object

Base class for a set of states that can be set by a relation or layer.

This class should be used so that they can be discovered and introspected, for documentation, composition, or linting.

Example usage:

class MyRelation(RelationBase):
    class states(StateList):
        connected = State('{relation_name}.connected')
        available = State('{relation_name}.available')
class charms.reactive.bus.StateWatch

Bases: object

classmethod change(state)
classmethod commit()
classmethod iteration(i)
key = 'reactive.state_watch'
classmethod reset()
classmethod watch(watcher, states)
charms.reactive.bus.discover()

Discover handlers based on convention.

Handlers will be loaded from the following directories and their subdirectories:

  • $CHARM_DIR/reactive/
  • $CHARM_DIR/hooks/reactive/
  • $CHARM_DIR/hooks/relations/

They can be Python files, in which case they will be imported and decorated functions registered. Or they can be executables, in which case they must adhere to the ExternalHandler protocol.

charms.reactive.bus.dispatch()

Dispatch registered handlers.

Handlers are dispatched according to the following rules:

  • Handlers are repeatedly tested and invoked in iterations, until the system settles into quiescence (that is, until no new handlers match to be invoked).
  • In the first iteration, @hook and @action handlers will be invoked, if they match.
  • In subsequent iterations, other handlers are invoked, if they match.
  • Added states will not trigger new handlers until the next iteration, to ensure that chained states are invoked in a predictable order.
  • Removed states will cause the current set of matched handlers to be re-tested, to ensure that no handler is invoked after its matching state has been removed.
  • Other than the guarantees mentioned above, the order in which matching handlers are invoked is undefined.
  • States are preserved between hook and action invocations, and all matching handlers are re-invoked for every hook and action. There are decorators and helpers to prevent unnecessary reinvocations, such as only_once().
charms.reactive.bus.get_state(state, default=None)

Return the value associated with an active state, or None

charms.reactive.bus.get_states()

Return a mapping of all active states to their values.

charms.reactive.bus.remove_state(state)

Remove / deactivate a state.

charms.reactive.bus.set_state(state, value=None)

Set the given state as active, optionally associating with a relation.