Writing plugins

A number of aspects of Jacquard are pluggable: the key ones right now being storage engines and directories.

You will probably want to write a directory plugin to interface with your database.

Directories

Declared in the directory_entries plugin group.

API

class jacquard.directory.base.Directory(**kwargs)[source]

User directory.

classmethod from_configuration(config, options)[source]

Construct from a Config object, and a dictionary of options.

By default this does not use the config and just defers to __init__ passing the options as kwargs.

lookup(user_id)[source]

Look up user by ID.

For missing users this must return None, otherwise it must return a corresponding UserEntry.

class jacquard.directory.base.UserEntry

Description of attributes of a single user.

Internally this is a collections.namedtuple.

id

String user ID.

join_date

Date at which the user is considered to have joined.

tags

Container of tags which apply to this user, defined by the directory.

Declaring plugins

Plugin entry points (such as new directory engines) can be declared in one of two ways: simplified plugins, and setuptools plugins.

simplified plugins

Simplified plugins are declared in the Jacquard configuration file. To add, for instance, a directory engine called “my_directory_engine” which loads the Directory subclass MyDirectory from a Python module my_directory.py one would add:

[plugins:directory_engines]
my_directory_engine = my_directory:MyDirectory

This will look for my_directory.py anywhere on the Python path, which for Jacquard includes /etc/jacquard/plugins. This is the simplest way to add plugins.

setuptools plugins

For advanced use, or for plugins which are made for redistribution and/or installation through pip and PyPI, you can declare plugins via the standard Python entry_points mechanism.

Where this is normally used to declare entry points for command-line tools via the console_scripts group, in this case entry points are declared for the jacquard.directory_engines group.

Storage engines

Storage plugins can be added for new ways to store data, such as custom key/ value stores, or even a fast enough SQL database if you’re feeling particularly crazy.

Declared in the storage_engines plugin group.

API

class jacquard.storage.base.StorageEngine(connection_string)[source]

Base storage engine class.

StorageEngine subclasses are required to be thread-safe.

begin()[source]

Enter a new transaction.

begin_read_only()[source]

Enter a new, read-only transaction.

May be overloaded for efficiency - by default, just calls begin().

commit(changes, deletions)[source]

Commit transaction.

Writes to make are given in the two arguments: changes is a mapping of keys to their new string values, and deletions is an iterable of keys to remove entirely.

If optimistic locking or other transactional mechanisms fail, this can raise the Retry exception to request that the entire transaction be repeated.

decode_key(key)[source]

Convert a given key for use in Jacquard.

This optional method must be implemented if encode_key is given, and must be its inverse.

The default implementation is the identity function.

encode_key(key)[source]

Convert a given key for use in the storage engine.

This optional method is given for engine-specific encodings of keys - for instance, replacing slashes with the more idiomatic colons and prefix for the Redis backend. All keys entering the rest of the API are encoded.

The default implementation is the identity function.

get(key)[source]

Get the current value corresponding with a given key.

Where there is no current value this must return None.

Only ever called in a transaction.

keys()[source]

Get an iterable over all keys in the store.

This is only ever called in transactions.

rollback()[source]

Roll back the current transaction without writing any changes.

This is used not only in exceptions but also when no writes were necessary after a transaction, so should ideally be fairly fast.

transaction(read_only=False)[source]

Run a transactional sequence on this store.

This is (currently?) the main user API for StorageEngine. The context manager yields an object supporting the mutable mapping protocol in all its glory, which can be treated as if a dict in, say, the standard library’s shelve module.

When the context manager exits, the transaction is rolled back if there are no writes or if an exception is escaping.

Commits are allowed to raise the Retry exception and it is left to users of the API to deal with this. Retry is guaranteed not to be raised if the transaction was read-only.

Subcommands

Subcommand plugins add new subcommands to the jacquard command-line utility.

Declared in the commands plugin group.

Note

Due to current technical restrictions, simplified plugins cannot add subcommands—only setuptools plugins.

API

class jacquard.commands.BaseCommand[source]

Abstract base class for subcommands.

Subclasses must override handle and may also provide a help string and/or override add_arguments.

add_arguments(parser)[source]

Add argument definitions to a given argparse ArgumentParser.

handle(config, options)[source]

Run command.

config is the system configuration from jacquard.config and options is a Namespace-like object of command-line options, generally defined from add_arguments with a few standard options such as verbose thrown in for good measure.

HTTP endpoints

HTTP endpoint plugins add new URL handlers for the HTTP API.

Declared in the http_endpoints plugin group.

API

class jacquard.service.base.Endpoint(config)[source]

Base HTTP endpoint.

Subclasses must implement url and handle. url is a URL pattern in the standard Werkzeug/Flask form, and handle is the method which is actually called to dispatch the endpoint.

Instances have two states: bound and unbound. When the endpoint is loaded it is instantiated in an unbound state. Before it’s actually dispatched, the dispatcher calls bind which copies the endpoint to produce a bound version. Bound endpoints have context available in attributes: reverse and request.

bind(request, reverse)[source]

Create bound version of this endpoint.

Clones with copy.copy and assigns instance.request and instance.reverse.

build_rule(name)[source]

Build Rule instance which represents this unbound endpoint.

defaults

Default values for URL parameters.

classmethod handle(**kwargs)[source]

Endpoint handler.

Any URL parameters are passed in as keyword arguments. This is only called on bound instances, so you can rely on self.request and friends existing.

Return JSON structures.

request

Request this endpoint is handling.

reverse(name, **kwargs)[source]

Look up URL for a given endpoint with given kwargs.

url

URL config, to be overridden in subclasses.

Takes the standard Werkzeug/Flask format. Examples:

  • ‘/’
  • ‘/foo/bar/bazz’
  • ‘/foo/<user>’
  • ‘/order/<id:int>’

Full documentation can be found in Werkzeug’s werkzeug.routing docs.