Skip to main content

Package which provides the plugin API for the Jinjanator tool

Project description

jinjanator-plugins: An API package for Jinjanator plugins

Jinjanator can be extended through the use of plugins; these are Python packages installed into the same environment as the tool itself, which use special markers to 'hook' into various features. There is a minimal example in the plugin_example directory which demonstrates three of the four possible hooks.

For a more complete example, intended for publication, check out the jinjanator-plugin-ansible repository.

Plugins can provide:

  • formats: data parsers used to extract data from input files.

  • filters: functions used in Jinja2 templates to transform data.

  • tests: functions used in Jinja2 templates to make decisions in conditional logic.

  • globals: functions used in Jinja2 templates to obtain data from external sources.

For more details on the functionality and requirements for 'filters', 'tests', and 'globals', refer to the Jinja2 documentation.

Installation

Normally there is no need to install this package; instead it should be listed as one of the dependencies for the plugin package itself.

Note: It is strongly recommended to pin the dependency for this package to a specific version, or if not, a "year.release" version range (like "23.2.*"). Failure to pin to a very narrow range of versions may result in breakage of a plugin when the API is changed in a non-backward-compatible fashion.

This is somewhat similar to semantic versioning, except not that :)

Basic structure

A minimal plugin consists of two files:

  • pyproject.toml: provides package and project information, and build instructions

  • Python source: provides functions to implement the desired features, and hook markers to plug them into Jinjanator

pyproject.toml

[build-system]
build-backend = "setuptools.build_meta"
requires = [
  "setuptools>=61",
]

[project]
name = "jinjanator-plugin-example"
version = "0.0.0"
dependencies = [
  "jinjanator-plugins==23.1.0",
]

[tool.setuptools]
py-modules = ["jinjanator_plugin_example"]

[project.entry-points.jinjanator]
example = "jinjanator_plugin_example"

build-system

Any PEP517-compatible build system can be used, for this simple example setuptools is being used.

project

The name and version are required to build a package containing the plugin. Note the specific version dependency on the jinjanator-plugins package.

tool.setuptools

This section tells setuptools to include a single source file (not a package directory) into the distribution. Note that this is a module name, not a file name, so there is no .py extension.

project.entry-points.jinjanator

This is the first part of the 'magic' mechanism which allows Jinjanator to find the plugin. The entry here (which can use any name, but should be related to the project name in order to avoid conflicts) creates an 'entry point' which Jinjanator can use to find the plugin; the value is the name of the module which Jinjanator should import to find the plugin's hooks (and must match the name specified in the tool.setuptools section).

jinjanator_plugin_example.py

import codecs

from jinjanator_plugins import (
    Format,
    FormatOptionUnknownError,
    FormatOptionUnsupportedError,
    FormatOptionValueError,
    plugin_filters_hook,
    plugin_formats_hook,
    plugin_identity_hook,
    plugin_tests_hook,
)


def rot13_filter(value):
    return codecs.encode(value, "rot13")


def is_len12_test(value):
    return len(value) == 12


def spam_format(data_string, options):
    ham = False

    if options:
        for option in options:
            if option == "ham":
                ham = True
            else:
                raise FormatOptionUnknownError(option)

    if ham:
        return {
            "ham": "ham",
            "cheese": "ham and cheese",
            "potatoes": "ham and potatoes",
        }

    return {
        "spam": "spam",
        "cheese": "spam and cheese",
        "potatoes": "spam and potatoes",
    }


@plugin_identity_hook
def plugin_identities():
    return "example"


@plugin_filters_hook
def plugin_filters():
    return {"rot13": rot13_filter}


@plugin_tests_hook
def plugin_tests():
    return {"len12": is_len12_test}


@plugin_formats_hook
def plugin_formats():
    return {"spam": Format(parser=spam_format, suffixes=[".spam"])}

Note that the real example makes use of type annotations, but they have been removed here for simplicity.

Imports

The imports from jinjanator_plugins are necessary for the plugin to:

  • Mark the hooks it wishes to use to provide additional features.
  • Construct one (or more) Format objects to describe the formats it supports, if any.
  • Raise option-related exceptions from its format function, if any.

rot13_filter

A simple filter function which applies the rot13 transformation to the string value it receives.

is_len12_test

A simple test function which returns True if the value it receives has length 12.

spam_format

A simple format function which ignores the content provided (which Jinjanator would have read from a data file), and instead returns one of two canned responses based on whether the ham option has been provided by the user.

plugin_identities

The hook function which will be called by Jinjanator to allow this plugin to identify itself; the @plugin_identities_hook decorator marks the function so that it will be found.

The function must return a string, which can contain any information needed to identify the plugin. This should include the plugin's name and version, and can include versions of any packages on which it depends.

This string will be included in the output generated by jinjanate --version, so it should not include any newlines or other formatting characters.

plugin_filters

The hook function which will be called by Jinjanator to allow this plugin to register any filter functions it provides; the @plugin_filters_hook decorator marks the function so that it will be found.

The function must return a dictionary, with each key being a filter function name (the name which will be used in the Jinja2 template to invoke the function) and the corresponding value being a reference to the function itself.

Note that the function must be named plugin_filters; it is the second part of the 'magic' mechanism mentioned above.

plugin_tests

The hook function which will be called by Jinjanator to allow this plugin to register any test functions it provides; the @plugin_tests_hook decorator marks the function so that it will be found.

The function must return a dictionary, with each key being a test function name (the name which will be used in the Jinja2 template to invoke the function) and the corresponding value being a reference to the function itself.

Note that the function must be named plugin_tests; it is the second part of the 'magic' mechanism mentioned above.

plugin_formats

The hook function which will be called by Jinjanator to allow this plugin to register any format functions it provides; the @plugin_formats_hook decorator marks the function so that it will be found.

The function must return a dictionary, with each key being a format function name (the name which will be used in the --format argument to Jinjanator, if needed) and the corresponding value being a Format object containing a reference to the format function itself and an optional list of file suffixes which can be matched to this format during format auto-detection.

Note that the function must be named plugin_formats; it is the second part of the 'magic' mechanism mentioned above.

Format functions can accept 'options' to modify their behavior, and should raise the exceptions listed below when needed to inform the user if one of the provided options does not meet the format's requirements.

  • FormatOptionUnknownError should be raised when a provided option name is not valid.

  • FormatOptionUnsupportedError should be raised when a provided option is not supported in combination with the other provided options; it should also be raised when options are provided to a format which does not support options.

  • FormatOptionValueError should be raised when a provided option has a value that is not valid.

Release Information

Additions

  • Add documentation for features added in version 23.2.0.

→ Full Changelog

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jinjanator_plugins-23.2.1.tar.gz (14.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jinjanator_plugins-23.2.1-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

Details for the file jinjanator_plugins-23.2.1.tar.gz.

File metadata

  • Download URL: jinjanator_plugins-23.2.1.tar.gz
  • Upload date:
  • Size: 14.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/4.0.2 CPython/3.11.4

File hashes

Hashes for jinjanator_plugins-23.2.1.tar.gz
Algorithm Hash digest
SHA256 ff88b715ac5cc01a88090288ad13824be9c438cbd0705565300545e4831afe98
MD5 2efe7780d5c91eb0dd4cdd230c395158
BLAKE2b-256 9896b0f1642dd8dcbbb7bcc9348aa84a0fa93b91f2c3d28bce133be880b68a86

See more details on using hashes here.

File details

Details for the file jinjanator_plugins-23.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for jinjanator_plugins-23.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 207ef20ec99174fe17a49cade8b34240fcb9bc66b3a5e0a3130df2aad4e9a132
MD5 8653f8610808b4e53cb39be0de6572b9
BLAKE2b-256 f7ca73b89a5cf618d4c2e1bb1941f9db6affb09ff1c24e98d9cbdc24f296728a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page