Commit 4854fb0d authored by Eliot Berriot's avatar Eliot Berriot

Added documentation in README

parent 0361d11d
......@@ -11,7 +11,7 @@ are permitted provided that the following conditions are met:
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of django-dynamic-preferences nor the names of its contributors may be used
3. Neither the name of persisting-theory nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
......
include COPYING
include CHANGES
include README.md
include runtests.py
recursive-include docs
recursive-include dynamic_preferences/templates *
recursive-include dynamic_preferences/static *
\ No newline at end of file
include README.rst
recursive-include example
\ No newline at end of file
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.
Okay, I'm bad at explaining things, and english is not my mother. Let's build a simple example.
Quickstart
==========
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")()
# Wouf
Registry.register
*****************
You can use this function as a decorator for functions and class::
from persiting_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 value registered. Sometimes, it's not what you want, so you can restric what kind of data you accept::
from persiting_theory import Registry
class StartsWithAwesomeRegistry(Registry):
def validate(self, obj):
if isinstance(obj, str):
return obj.startswith("awesome")
return False
r = AwesomeRegistry()
# 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")
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. Feel free to contact me at <contact@eliotberriot.com>.
License
=======
The project is licensed under BSD licence.
\ No newline at end of file
from registries import callbacks_registry
@callbacks_registry.register
def dog():
print("Wouf")
\ No newline at end of file
from registries import callbacks_registry
@callbacks_registry.register
def cat():
print("Meow")
\ No newline at end of file
from registries import callbacks_registry
APPS = (
'app1',
'app2',
)
# Trigger autodiscovering process
callbacks_registry.autodiscover(APPS)
for callback in callbacks_registry.values():
callback()
# Wouf
# Meow
\ No newline at end of file
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from persisting_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()
APPS = (
'app1',
'app2',
)
# Trigger autodiscovering process
callbacks_registry.autodiscover(APPS)
\ No newline at end of file
from registries import Registry, meta_registry
version = "0.1"
\ No newline at end of file
......@@ -45,13 +45,23 @@ class Registry(OrderedDict):
else:
raise ValueError("Cannot deduce name from given object ({0}). Please user registry.register() with a 'name' argument.".format(obj))
def validate(self, obj):
"""
Called before registering a new value into the registry
Override this method if you want to restrict what type of data cna be registered
"""
return True
def register_func(self, obj, name=None, **kwargs):
"""
Register an object, class, function... into the registry
"""
if name is None:
name = self.get_object_name(obj)
self[name] = obj
if self.validate(obj):
if name is None:
name = self.get_object_name(obj)
self[name] = obj
else:
raise ValueError("{0} (type: {0.__class__}) is not a valid value for {1} registry".format(obj, self.__class__))
def autodiscover(self, apps, force_reload=True):
"""
......@@ -68,7 +78,6 @@ class Registry(OrderedDict):
except ImportError, e:
# Module does not exist
pass
print(e)
class MetaRegistry(Registry):
......
......@@ -3,5 +3,3 @@ from test_registries import awesome_people
@awesome_people.register
class AlainDamasio:
pass
print("imported", awesome_people)
\ No newline at end of file
......@@ -37,6 +37,20 @@ class RegistryTest(unittest.TestCase):
self.assertEqual(len(registry), 1)
self.assertEqual(registry.get("key"), data)
def test_can_restric_registered_data(self):
class RestrictedRegistry(registries.Registry):
def validate(self, obj):
"""Only accept integer values"""
return isinstance(obj, int)
registry = RestrictedRegistry()
registry.register(12, name="twelve")
with self.assertRaises(ValueError):
registry.register("not an int", name="not an int")
def test_can_register_class_and_function_via_decorator(self):
registry = registries.Registry()
......@@ -91,8 +105,6 @@ class RegistryTest(unittest.TestCase):
self.assertNotEqual(registry.get('Potato', None), None)
self.assertNotEqual(registry.get('Ketchup', None), None)
def test_reload_autodiscover(self):
fail
if __name__ == '__main__':
unittest.main()
\ No newline at end of file
import os
from setuptools import setup, find_packages
import dynamic_preferences
import persisting_theory
README = open(os.path.join(os.path.dirname(__file__), 'README.md')).read()
# allow setup.py to be run from any path
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
setup(
name='django-dynamic-preferences',
version=dynamic_preferences.__version__,
name='persisting-theory',
version=persisting_theory.__version__,
packages=find_packages(),
include_package_data=True,
license='BSD', # example license
description='A django app for registering dynamic global, site and user preferences',
description='A python package to build registries that can autodiscover values accross your project components.',
long_description=README,
url='http://code.eliotberriot.com/eliotberriot/django-dynamic-preferences',
url='http://code.eliotberriot.com/eliotberriot/persisting-theory',
author='Eliot Berriot',
author_email='contact@eliotberriot.com',
zip_safe=False,
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
# Replace these appropriately if you are stuck on Python 2.
'Programming Language :: Python :: 2.7',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
],
install_requires=[
"django",
],
)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment