Skip to main content

Introduction

Persisting-theory is a small python utility designed to automate data discovering and access inside a list of packages. Use case: you are building an application that will have pluggable components. You want to allow these components to register data so it can be accessed by any other component of your app. If you ever used Django framework, you may remember this:

from django.contrib import admin
admin.autodiscover()

Basically, persisting-theory will do the same, except that it let you declare what you want to autodiscover.

Okay, I’m bad at explaining things, and english is not my mother tongue. Let’s build a simple example.

Quickstart

Install

Install the package from PyPi. via pip (or any other tool):

pip install persisting-theory

Persisting-theory does not require any dependency but a python installation (it has been tested on python 2.7 and python 3.4).

Setup

A basic setup:

# registries.py

from persiting_theory import Registry

class CallbacksRegistry(Registry):
    """
        Allow your apps to register callbacks
    """
    # the package where the registry will try to find callbacks in each app
    look_into = "callbacks_registry"

callbacks_registry = CallbacksRegistry()


# app1/callbacks_registry.py

from registries import callbacks_registry

@callbacks_registry.register
def dog():
    print("Wouf")


# app2/callbacks_registry.py

from registries import callbacks_registry

@callbacks_registry.register
def cat():
    print("Meow")


# dosomething.py

from registries import callbacks_registry

APPS = (
    'app1',
    'app2',
)

# Trigger autodiscovering process
callbacks_registry.autodiscover(APPS)

for callback in callbacks_registry.values():
    callback()

    # Wouf
    # Meow

API

Registry inherits from python built-in collections.OrderedDict, which means you can use regular dict methods to access registered data:

callbacks_registry.get("dog")()  #  will print Wouf
assert callbacks_registry.get("chicken", None) is None

Registry.register()

You can use this function as a decorator for registering functions and classes:

from persisting_theory import Registry

class AwesomeRegistry(Registry):
    pass

r = AwesomeRegistry()

# register a class
@r.register
class AwesomeClass:
    pass

# register a function
@r.register
def awesome_function():
    pass

# By default, the key in the registry for a given value is obtained from the function or class name, if possible

assert r.get("AwesomeClass") == AwesomeClass
assert r.get("awesome_function") == awesome_function

# You can override this behaviour:

@r.register(name="Chuck")
class AwesomeClass:
    pass

@r.register(name="Norris")
def awesome_function():
    pass

assert r.get("Chuck") == AwesomeClass
assert r.get("Norris") == awesome_function


# You can also use the register method as is

awesome_var = "Chuck Norris"
r.register(awesome_var, name="Who am I ?")

assert r.get("Who am I ?") == awesome_var

# I f you are not registering a function or a class, you MUST provide a name argument

Registry.validate()

By default, a registry will accept any registered value. Sometimes, it’s not what you want, so you can restrict what kind of data your registry accepts:

from persisting_theory import Registry

class StartsWithAwesomeRegistry(Registry):

    def validate(self, data):
        if isinstance(data, str):
            return data.startswith("awesome")
        return False

r = StartsWithAwesomeRegistry()

# will pass registration
r.register("awesome day", name="awesome_day")

# will fail and raise ValueError
r.register("not so awesome day", name="not_so_awesome_day")

Registry.prepare_data()

If you want to manipulate your data before registering it, override this method. In this example, we prefix every registered string with ‘hello’:

from persisting_theory import Registry

class HelloRegistry(Registry):

    def prepare_data(self, data):
        return 'hello ' + data

r = HelloRegistry()

class Greeting:
    def __init__(self, first_name):
        self.first_name = first_name


r.register(Greeting('World'), name="world")
r.register(Greeting('agate'), name="agate")

assert r.register.get('world') == "hello World"
assert r.register.get('agate') == "hello agate"

Registry.prepare_name()

In a similar way, you can manipulate the name of registered data. This can help if you want to avoid repetitions. Let’s improve our previous example:

from persisting_theory import Registry

class HelloRegistry(Registry):

    def prepare_data(self, data):
        return 'hello ' + data

    def prepare_name(self, data, name=None):
        return self.data.first_name.lower()

r = HelloRegistry()

class Greeting:
    def __init__(self, first_name):
        self.first_name = first_name


r.register(Greeting('World'))
r.register(Greeting('agate'))

assert r.register.get('world') == "hello World"
assert r.register.get('agate') == "hello agate"

Going meta

If you have multiple registries, or want to allow your apps to declare their own registries, this is for you:

# registries.py

from persisting_theory import meta_registry, Registry

class RegistryA(Registry):
    look_into = "a"

class RegistryB(Registry):
    look_into = "b"

registry_a = RegistryA()
meta_registry.register(registry_a, name="registry_a")

registry_b = RegistryB()
meta_registry.register(registry_b, name="registry_b")


# dosomethingelse.py

from persisting_theory import meta_registry

# will import registries declared in `registries` packages, and trigger autodiscover() on each of them
meta_registry.autodiscover(apps=("app1", "app2"))

What the hell is that name ?

It’s an anagram for “python registries”.

Contribute

Contributions, bug reports, and “thank you” are welcomed.

License

The project is licensed under BSD licence.

Metadata

Release files for persisting-theory 1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for persisting-theory 1.0
File Size Uploaded
persisting-theory-1.0.tar.gz 11.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for persisting-theory 1.0
File Interpreter ABI Platform
persisting_theory-1.0-py3-none-any.whl Python 3 none any Details

Total release size: 25.0 kB

Release files / persisting-theory-1.0.tar.gz

Download URL persisting-theory-1.0.tar.gz
Size 11.9 kB
Tags Source
SHA-256 checksum
How to use checksums
0f840fa22247bcaa514094da7f3b26c602359429ab12d2cd88be06b49a336290
BLAKE2b-256 checksum
How to use checksums
8e2b02bec776f5f27ead2637035a7b324fa7619252bed373b6d3911153b7adad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

Release files / persisting_theory-1.0-py3-none-any.whl

Download URL persisting_theory-1.0-py3-none-any.whl
Size 13.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
73fe3ba1ea7ab67632a1c292fc5c9fa6d3ebfd0e2ad74defa56e316abf3c8d21
BLAKE2b-256 checksum
How to use checksums
895d533442b24abd6be67a332987aebc0ce0fcfe39bfad36564d08f3db375291
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.7

Release history Release notifications | RSS feed

This release

1.0 This release

2 release files

0.2.1

1 release file

0.2.0

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page