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:
.. code-block:: python
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 <https://pypi.python.org/pypi/persisting-theory/>`_. 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:
.. code-block:: python
# 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:
.. code-block:: python
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:
.. code-block:: python
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:
.. code-block:: python
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':
.. code-block:: python
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:
.. code-block:: python
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:
.. code-block:: python
# 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.
Raw data
{
"_id": null,
"home_page": "https://code.agate.blue/agate/persisting-theory",
"name": "persisting-theory",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "",
"author": "Agate Blue",
"author_email": "",
"download_url": "https://files.pythonhosted.org/packages/8e/2b/02bec776f5f27ead2637035a7b324fa7619252bed373b6d3911153b7adad/persisting-theory-1.0.tar.gz",
"platform": null,
"description": "Introduction\n============\n\nPersisting-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.\nIf you ever used Django framework, you may remember this:\n\n.. code-block:: python\n\n from django.contrib import admin\n admin.autodiscover()\n\nBasically, persisting-theory will do the same, except that it let you declare what you want to autodiscover.\n\nOkay, I'm bad at explaining things, and english is not my mother tongue. Let's build a simple example.\n\nQuickstart\n==========\n\nInstall\n*******\n\nInstall the package from `PyPi <https://pypi.python.org/pypi/persisting-theory/>`_. via pip (or any other tool)::\n\n pip install persisting-theory\n\nPersisting-theory does not require any dependency but a python installation (it has been tested on python 2.7 and python 3.4).\n\nSetup\n*****\n\nA basic setup:\n\n.. code-block:: python\n\n # registries.py\n\n from persiting_theory import Registry\n\n class CallbacksRegistry(Registry):\n \"\"\"\n Allow your apps to register callbacks\n \"\"\"\n # the package where the registry will try to find callbacks in each app\n look_into = \"callbacks_registry\"\n\n callbacks_registry = CallbacksRegistry()\n\n\n # app1/callbacks_registry.py\n\n from registries import callbacks_registry\n\n @callbacks_registry.register\n def dog():\n print(\"Wouf\")\n\n\n # app2/callbacks_registry.py\n\n from registries import callbacks_registry\n\n @callbacks_registry.register\n def cat():\n print(\"Meow\")\n\n\n # dosomething.py\n\n from registries import callbacks_registry\n\n APPS = (\n 'app1',\n 'app2',\n )\n\n # Trigger autodiscovering process\n callbacks_registry.autodiscover(APPS)\n\n for callback in callbacks_registry.values():\n callback()\n\n # Wouf\n # Meow\n\nAPI\n===\n\n``Registry`` inherits from python built-in `collections.OrderedDict`, which means you can use regular dict methods to access registered data:\n\n.. code-block:: python\n\n callbacks_registry.get(\"dog\")() # will print Wouf\n assert callbacks_registry.get(\"chicken\", None) is None\n\nRegistry.register()\n*******************\n\nYou can use this function as a decorator for registering functions and classes:\n\n.. code-block:: python\n\n from persisting_theory import Registry\n\n class AwesomeRegistry(Registry):\n pass\n\n r = AwesomeRegistry()\n\n # register a class\n @r.register\n class AwesomeClass:\n pass\n\n # register a function\n @r.register\n def awesome_function():\n pass\n\n # By default, the key in the registry for a given value is obtained from the function or class name, if possible\n\n assert r.get(\"AwesomeClass\") == AwesomeClass\n assert r.get(\"awesome_function\") == awesome_function\n\n # You can override this behaviour:\n\n @r.register(name=\"Chuck\")\n class AwesomeClass:\n pass\n\n @r.register(name=\"Norris\")\n def awesome_function():\n pass\n\n assert r.get(\"Chuck\") == AwesomeClass\n assert r.get(\"Norris\") == awesome_function\n\n\n # You can also use the register method as is\n\n awesome_var = \"Chuck Norris\"\n r.register(awesome_var, name=\"Who am I ?\")\n\n assert r.get(\"Who am I ?\") == awesome_var\n\n # I f you are not registering a function or a class, you MUST provide a name argument\n\nRegistry.validate()\n*******************\n\nBy 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:\n\n.. code-block:: python\n\n from persisting_theory import Registry\n\n class StartsWithAwesomeRegistry(Registry):\n\n def validate(self, data):\n if isinstance(data, str):\n return data.startswith(\"awesome\")\n return False\n\n r = StartsWithAwesomeRegistry()\n\n # will pass registration\n r.register(\"awesome day\", name=\"awesome_day\")\n\n # will fail and raise ValueError\n r.register(\"not so awesome day\", name=\"not_so_awesome_day\")\n\nRegistry.prepare_data()\n***********************\n\nIf you want to manipulate your data before registering it, override this method. In this example, we prefix every registered string with 'hello':\n\n.. code-block:: python\n\n from persisting_theory import Registry\n\n class HelloRegistry(Registry):\n\n def prepare_data(self, data):\n return 'hello ' + data\n\n r = HelloRegistry()\n\n class Greeting:\n def __init__(self, first_name):\n self.first_name = first_name\n\n\n r.register(Greeting('World'), name=\"world\")\n r.register(Greeting('agate'), name=\"agate\")\n\n assert r.register.get('world') == \"hello World\"\n assert r.register.get('agate') == \"hello agate\"\n\n\nRegistry.prepare_name()\n***********************\n\nIn 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:\n\n.. code-block:: python\n\n from persisting_theory import Registry\n\n class HelloRegistry(Registry):\n\n def prepare_data(self, data):\n return 'hello ' + data\n\n def prepare_name(self, data, name=None):\n return self.data.first_name.lower()\n\n r = HelloRegistry()\n\n class Greeting:\n def __init__(self, first_name):\n self.first_name = first_name\n\n\n r.register(Greeting('World'))\n r.register(Greeting('agate'))\n\n assert r.register.get('world') == \"hello World\"\n assert r.register.get('agate') == \"hello agate\"\n\nGoing meta\n**********\n\nIf you have multiple registries, or want to allow your apps to declare their own registries, this is for you:\n\n.. code-block:: python\n\n # registries.py\n\n from persisting_theory import meta_registry, Registry\n\n class RegistryA(Registry):\n look_into = \"a\"\n\n class RegistryB(Registry):\n look_into = \"b\"\n\n registry_a = RegistryA()\n meta_registry.register(registry_a, name=\"registry_a\")\n\n registry_b = RegistryB()\n meta_registry.register(registry_b, name=\"registry_b\")\n\n\n # dosomethingelse.py\n\n from persisting_theory import meta_registry\n\n # will import registries declared in `registries` packages, and trigger autodiscover() on each of them\n meta_registry.autodiscover(apps=(\"app1\", \"app2\"))\n\n\nWhat the hell is that name ?\n============================\n\nIt's an anagram for \"python registries\".\n\nContribute\n==========\n\nContributions, bug reports, and \"thank you\" are welcomed.\n\nLicense\n=======\n\nThe project is licensed under BSD licence.\n\n\n",
"bugtrack_url": null,
"license": "BSD",
"summary": "Registries that can autodiscover values accross your project apps",
"version": "1.0",
"project_urls": {
"Homepage": "https://code.agate.blue/agate/persisting-theory"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "895d533442b24abd6be67a332987aebc0ce0fcfe39bfad36564d08f3db375291",
"md5": "545d3488939f4bdd48d4ce89ce4f46b6",
"sha256": "73fe3ba1ea7ab67632a1c292fc5c9fa6d3ebfd0e2ad74defa56e316abf3c8d21"
},
"downloads": -1,
"filename": "persisting_theory-1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "545d3488939f4bdd48d4ce89ce4f46b6",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 13042,
"upload_time": "2022-05-06T08:18:23",
"upload_time_iso_8601": "2022-05-06T08:18:23.646425Z",
"url": "https://files.pythonhosted.org/packages/89/5d/533442b24abd6be67a332987aebc0ce0fcfe39bfad36564d08f3db375291/persisting_theory-1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8e2b02bec776f5f27ead2637035a7b324fa7619252bed373b6d3911153b7adad",
"md5": "1aa398c5c738e9e3a663991a82acb311",
"sha256": "0f840fa22247bcaa514094da7f3b26c602359429ab12d2cd88be06b49a336290"
},
"downloads": -1,
"filename": "persisting-theory-1.0.tar.gz",
"has_sig": false,
"md5_digest": "1aa398c5c738e9e3a663991a82acb311",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 11949,
"upload_time": "2022-05-06T08:18:25",
"upload_time_iso_8601": "2022-05-06T08:18:25.805953Z",
"url": "https://files.pythonhosted.org/packages/8e/2b/02bec776f5f27ead2637035a7b324fa7619252bed373b6d3911153b7adad/persisting-theory-1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2022-05-06 08:18:25",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "persisting-theory"
}