Skip to main content

No project description provided

Project description

registry-py

Overview

Metaprogramming means writing programs that manipulate other programs, such as compilers, interpreters, macros, etc. Python enables metaprogramming in a number of ways, one of which is metaclasses, which are special classes that can hook into child class creation methods, and can enforce invariants on those child classes. The abc.ABCMeta class is one example, and allows for the declaration of abstractmethods which must be implemented by child classes. registry-py uses metaprogramming to implement the registry pattern, where a metaclass stores a map of all child classes. This pattern is particularly useful for auto-discovery or auto-registration, where a program doesn't doesn't need to know where code is stored to know what's been implemented.

Installation

Install from PyPi (preferred method)

pip install lc-registry

Install from GitHub with Pip

pip install git+https://github.com/libcommon/registry-py.git@vx.x.x#egg=lc_registry

where x.x.x is the version you want to download.

Install by Manual Download

To download the source distribution and/or wheel files, navigate to https://github.com/libcommon/registry-py/tree/releases/vx.x.x/dist, where x.x.x is the version you want to install, and download either via the UI or with a tool like wget. Then to install run:

pip install <downloaded file>

Do not change the name of the file after downloading, as Pip requires a specific naming convention for installation files.

Dependencies

registry-py does not have external dependencies. Only Python versions >= 3.6 are officially supported.

Getting Started

Suppose you want to implement a plugin system for a command line tool. One approach could be to require that plugin files are written to a specific folder, say src/plugins/contrib, and use importlib.import_module to import modules from there on program startup. However, plugin files not in the proper directory will not get loaded, and finding plugins requires walking a directory tree. Using a registry would alleviate both these issues.

# plugin_registry.py
from abc import ABCMeta
from typing import Any, ClassVar, Dict, Type

from lc_registry import RegistryMetaclassMixin


class PluginRegistry(RegistryMetaclassMixin, ABCMeta):
    """Metaclass with registry."""
    __slots__ = ()
    _REGISTRY: ClassVar[Dict[str, Type[Any]]] = dict()

    @classmethod
    def _add_class(cls, name: str, new_cls: Type[Any]) -> None:
        # All plugins must be named "*Plugin"
        # NOTE: This is just an example what you can do with _add_class
        if name == "PluginBase" or not name.endswith("Plugin"):
            return None
        cls._REGISTRY[name] = new_cls
        return None

    @classmethod
    def run_plugins(cls):
        # Use cls._REGISTRY (or cls.registry() method) to
        # iterate over each plugin and run it.


class PluginBase(metaclass=PluginRegistry):
    """Base class for all plugins. All child classes
    will be added to the plugin registry once they come
    into scope (AKA when Python creates the type).
    """
    __slots__ = ()

    @abstractmethod
    def run_plugin(self, context: Dict[str, Any]) -> None:
        """Plugin entrypoint."""
        raise NotImplementedError


# line_count_plugin.py
from typing import Any, Dict

from plugin_registry import PluginBase


class LineCountPlugin(PluginBase):
    """Plugin that counts the number of lines in a file."""
    __slots__ = ()

    def run_plugin(self, context: Dict[str, Any]) -> None:
        if "filepath" in context:
            filepath = context.get("filepath")
            line_count = 0
            with open(filepath) as source_file:
                for _ in source_file:
                    line_count += 1
            print("{}\t{}".format(filepath, line_count))

Note the doc string for the PluginBase class in the example above: "... once they come into scope (AKA when Python creates the type)." This is important - child classes will only be added to the registry if Python loads them into the program, meaning if they get imported somewhere.

Contributing/Suggestions

Contributions and suggestions are welcome! To make a feature request, report a bug, or otherwise comment on existing functionality, please file an issue. For contributions please submit a PR, but make sure to lint, type-check, and test your code before doing so. Thanks in advance!

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

lc_registry-0.1.2.tar.gz (4.7 kB view details)

Uploaded Source

Built Distribution

lc_registry-0.1.2-py3-none-any.whl (6.3 kB view details)

Uploaded Python 3

File details

Details for the file lc_registry-0.1.2.tar.gz.

File metadata

  • Download URL: lc_registry-0.1.2.tar.gz
  • Upload date:
  • Size: 4.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/42.0.1 requests-toolbelt/0.9.1 tqdm/4.46.0 CPython/3.7.7

File hashes

Hashes for lc_registry-0.1.2.tar.gz
Algorithm Hash digest
SHA256 27e62956b8e02a7458a52f5bd627b7d143971ea8ea1d2aafa356d741f08a7cfe
MD5 ca04a80ee4ea3be2ee1dbe6ed904e82a
BLAKE2b-256 4c8a0dec8ca80e448416aed867c9edd0ed83f25168efe3bbab7d0a50e5dd6760

See more details on using hashes here.

File details

Details for the file lc_registry-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: lc_registry-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 6.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/42.0.1 requests-toolbelt/0.9.1 tqdm/4.46.0 CPython/3.7.7

File hashes

Hashes for lc_registry-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f709fb32c11c53efbce23d2e2807deed040ce8c29f4f15bd5915d3ada139eca9
MD5 3a553abf34b355003dbe4e7a7e9ecf72
BLAKE2b-256 be318f0b1a3862e22c79018c74bfa64d2cfeaf19e80af8c70f526730fd7016b0

See more details on using hashes here.

Supported by

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