persisting-theory-0.2.1/ 0000755 0001750 0000144 00000000000 12416754112 017076 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/CHANGES 0000644 0001750 0000144 00000001151 12416754011 020065 0 ustar eliotberriot users 0000000 0000000 Changelog
=========
0.2.1
*****
13/10/2014:
- Added tox to testing process (persisting theory is now tested under Python 2.7 and 3.4)
- Moved test directory outside of persisting-theory
- Set ``force_reload`` defaut to ``False`` to in Registry.autodiscover()
0.2.0
*****
26/07/2014:
- Added prepare_data hook for manipulating data before registration
- Added prepare_name hook for manipulating name before registration
- Added post_register hook
0.1.2
*****
13/07/2014:
- Added handling of error in autodiscovering
0.1.1
*****
12/07/2014:
- Added Python 3 support
0.1
***
12/07/2014 - initial release persisting-theory-0.2.1/persisting_theory/ 0000755 0001750 0000144 00000000000 12416754112 022657 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/persisting_theory/__init__.py 0000644 0001750 0000144 00000000106 12416754016 024770 0 ustar eliotberriot users 0000000 0000000 from .registries import Registry, meta_registry
__version__ = "0.2.1" persisting-theory-0.2.1/persisting_theory/registries.py 0000644 0001750 0000144 00000011774 12416753504 025427 0 ustar eliotberriot users 0000000 0000000 from collections import OrderedDict
import inspect
try:
# use Python3 reload
from imp import reload
except:
# we are on Python2
pass
class Registry(OrderedDict):
def register_decorator_factory(self, **kwargs):
"""
Return an actual decorator for registering objects into registry
"""
name = kwargs.get('name')
def decorator(decorated):
self.register_func(data=decorated, name=name)
return decorated
return decorator
def register(self, data=None, name=None, **kwargs):
"""
Use this method as a decorator on class/function you want to register:
@registry.register(name="test")
class Test:
pass
:param:data: Something to register in the registry
:param:name: The unique name that will identify registered data.
If None, by default, registry will try to deduce name from class name (if object is a class or an object).
You can change this behaviour by overriding :py::method:`prepare_name`
"""
if data is None:
return self.register_decorator_factory(data=data, name=name, **kwargs)
else:
self.register_func(data=data, name=name, **kwargs)
return data
def get_object_name(self, data):
"""
Return a name from an element (object, class, function...)
"""
if callable(data):
return data.__name__
elif inspect.isclass(data):
return data.__class__.__name__
else:
raise ValueError("Cannot deduce name from given object ({0}). Please user registry.register() with a 'name' argument.".format(data))
def validate(self, data):
"""
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 prepare_name(self, data, name=None):
if name is None:
return self.get_object_name(data)
return name
def register_func(self, data, name=None, **kwargs):
"""
Register abritrary data into the registry
"""
if self.validate(data):
o = self.prepare_data(data)
n = self.prepare_name(data, name)
self[n] = o
self.post_register(data=0, name=n)
else:
raise ValueError("{0} (type: {0.__class__}) is not a valid value for {1} registry".format(data, self.__class__))
def post_register(self, data, name):
"""
Will be triggered each time a new element is successfully registered.
Feel free to override this method
"""
pass
def prepare_data(self, data):
"""
Override this methode if you want to manipulate data before registering it
You MUST return a value to register
"""
return data
def autodiscover(self, apps, force_reload=False):
"""
Iterate throught every installed apps, trying to import `look_into` package
:param apps: an iterable of string, refering to python modules the registry will try to import via autodiscover
"""
for app in apps:
app_package = __import__(app)
try:
package = '{0}.{1}'.format(app, self.look_into) # try to import self.package inside current app
#print(package)
module = __import__(package)
if force_reload:
reload(module)
except ImportError as exc:
# From django's syncdb
# This is slightly hackish. We want to ignore ImportErrors
# if the module itself is missing -- but we don't
# want to ignore the exception if the module exists
# but raises an ImportError for some reason. The only way we
# can do this is to check the text of the exception. Note that
# we're a bit broad in how we check the text, because different
# Python implementations may not use the same text.
# CPython uses the text "No module named"
# PyPy uses "No module named myproject.myapp"
msg = exc.args[0]
if not msg.startswith('No module named') or self.look_into not in msg:
raise
class MetaRegistry(Registry):
"""
Keep a reference to all registries
"""
look_into = "registries"
def autodiscover(self, apps, cascade=True, **kwargs):
"""
:param cascade: If true, will trigger autodiscover on discovered registries
"""
super(MetaRegistry, self).autodiscover(apps, **kwargs)
if cascade:
self.autodiscover_registries(apps)
def autodiscover_registries(self, apps):
for key, registry in self.items():
registry.autodiscover(apps)
meta_registry = MetaRegistry() persisting-theory-0.2.1/COPYING 0000644 0001750 0000144 00000003016 12377651526 020144 0 ustar eliotberriot users 0000000 0000000 Copyright (c) Eliot Berriot and individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
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 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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
persisting-theory-0.2.1/README.rst 0000644 0001750 0000144 00000014643 12377651526 020610 0 ustar eliotberriot users 0000000 0000000 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.2).
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('Eliot'), name="eliot")
assert r.register.get('world') == "hello World"
assert r.register.get('eliot') == "hello Eliot"
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('Eliot'))
assert r.register.get('world') == "hello World"
assert r.register.get('eliot') == "hello Eliot"
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 .
License
=======
The project is licensed under BSD licence. persisting-theory-0.2.1/persisting_theory.egg-info/ 0000755 0001750 0000144 00000000000 12416754112 024351 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/persisting_theory.egg-info/SOURCES.txt 0000644 0001750 0000144 00000001404 12416754112 026234 0 ustar eliotberriot users 0000000 0000000 CHANGES
COPYING
MANIFEST.in
README.rst
setup.py
example/__init__.py
example/dosomething.py
example/registries.py
example/app1/__init__.py
example/app1/callbacks_registry.py
example/app2/__init__.py
example/app2/callbacks_registry.py
persisting_theory/__init__.py
persisting_theory/registries.py
persisting_theory.egg-info/PKG-INFO
persisting_theory.egg-info/SOURCES.txt
persisting_theory.egg-info/dependency_links.txt
persisting_theory.egg-info/not-zip-safe
persisting_theory.egg-info/top_level.txt
tests/__init__.py
tests/test_registries.py
tests/tests.py
tests/app1/__init__.py
tests/app1/awesome_people.py
tests/app1/vegetables.py
tests/app2/__init__.py
tests/app2/awesome_people.py
tests/app2/vegetables.py
tests/buggy_app/__init__.py
tests/buggy_app/awesome_people.py persisting-theory-0.2.1/persisting_theory.egg-info/dependency_links.txt 0000644 0001750 0000144 00000000001 12416754112 030417 0 ustar eliotberriot users 0000000 0000000
persisting-theory-0.2.1/persisting_theory.egg-info/not-zip-safe 0000644 0001750 0000144 00000000001 12377651526 026612 0 ustar eliotberriot users 0000000 0000000
persisting-theory-0.2.1/persisting_theory.egg-info/top_level.txt 0000644 0001750 0000144 00000000040 12416754112 027075 0 ustar eliotberriot users 0000000 0000000 tests
example
persisting_theory
persisting-theory-0.2.1/persisting_theory.egg-info/PKG-INFO 0000644 0001750 0000144 00000022011 12416754112 025442 0 ustar eliotberriot users 0000000 0000000 Metadata-Version: 1.1
Name: persisting-theory
Version: 0.2.1
Summary: Registries that can autodiscover values accross your project apps
Home-page: http://code.eliotberriot.com/eliotberriot/persisting-theory
Author: Eliot Berriot
Author-email: contact@eliotberriot.com
License: BSD
Description: 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.2).
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('Eliot'), name="eliot")
assert r.register.get('world') == "hello World"
assert r.register.get('eliot') == "hello Eliot"
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('Eliot'))
assert r.register.get('world') == "hello World"
assert r.register.get('eliot') == "hello Eliot"
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 .
License
=======
The project is licensed under BSD licence.
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.4
persisting-theory-0.2.1/example/ 0000755 0001750 0000144 00000000000 12416754112 020531 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/example/dosomething.py 0000644 0001750 0000144 00000000356 12377651526 023442 0 ustar eliotberriot users 0000000 0000000 from registries import callbacks_registry
APPS = (
'app1',
'app2',
)
# Trigger autodiscovering process
callbacks_registry.autodiscover(APPS)
for callback in callbacks_registry.values():
callback()
# Wouf
# Meow persisting-theory-0.2.1/example/app2/ 0000755 0001750 0000144 00000000000 12416754112 021373 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/example/app2/callbacks_registry.py 0000644 0001750 0000144 00000000144 12377651526 025626 0 ustar eliotberriot users 0000000 0000000 from registries import callbacks_registry
@callbacks_registry.register
def cat():
print("Meow") persisting-theory-0.2.1/example/app2/__init__.py 0000644 0001750 0000144 00000000000 12377651526 023505 0 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/example/__init__.py 0000644 0001750 0000144 00000000000 12377651526 022643 0 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/example/registries.py 0000644 0001750 0000144 00000000733 12377651526 023301 0 ustar eliotberriot users 0000000 0000000 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) persisting-theory-0.2.1/example/app1/ 0000755 0001750 0000144 00000000000 12416754112 021372 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/example/app1/callbacks_registry.py 0000644 0001750 0000144 00000000144 12377651526 025625 0 ustar eliotberriot users 0000000 0000000 from registries import callbacks_registry
@callbacks_registry.register
def dog():
print("Wouf") persisting-theory-0.2.1/example/app1/__init__.py 0000644 0001750 0000144 00000000000 12377651526 023504 0 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/PKG-INFO 0000644 0001750 0000144 00000022011 12416754112 020167 0 ustar eliotberriot users 0000000 0000000 Metadata-Version: 1.1
Name: persisting-theory
Version: 0.2.1
Summary: Registries that can autodiscover values accross your project apps
Home-page: http://code.eliotberriot.com/eliotberriot/persisting-theory
Author: Eliot Berriot
Author-email: contact@eliotberriot.com
License: BSD
Description: 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.2).
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('Eliot'), name="eliot")
assert r.register.get('world') == "hello World"
assert r.register.get('eliot') == "hello Eliot"
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('Eliot'))
assert r.register.get('world') == "hello World"
assert r.register.get('eliot') == "hello Eliot"
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 .
License
=======
The project is licensed under BSD licence.
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.4
persisting-theory-0.2.1/setup.cfg 0000644 0001750 0000144 00000000073 12416754112 020717 0 ustar eliotberriot users 0000000 0000000 [egg_info]
tag_date = 0
tag_build =
tag_svn_revision = 0
persisting-theory-0.2.1/tests/ 0000755 0001750 0000144 00000000000 12416754112 020240 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/tests/app2/ 0000755 0001750 0000144 00000000000 12416754112 021102 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/tests/app2/vegetables.py 0000644 0001750 0000144 00000000210 12416752512 023570 0 ustar eliotberriot users 0000000 0000000 from ..test_registries import vegetable_registry
@vegetable_registry.register
class Ketchup:
warning = "ketchup is not a vegetable" persisting-theory-0.2.1/tests/app2/awesome_people.py 0000644 0001750 0000144 00000000146 12416752506 024466 0 ustar eliotberriot users 0000000 0000000 from ..test_registries import awesome_people
@awesome_people.register
class FrederikPeeters:
pass persisting-theory-0.2.1/tests/app2/__init__.py 0000644 0001750 0000144 00000000000 12377651526 023214 0 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/tests/test_registries.py 0000644 0001750 0000144 00000000627 12416751674 024050 0 ustar eliotberriot users 0000000 0000000 from persisting_theory import Registry, meta_registry
class AwesomePeopleRegistry(Registry):
look_into = "awesome_people"
awesome_people = AwesomePeopleRegistry()
meta_registry.register(awesome_people, name="awesome_people")
class VegetableRegistry(Registry):
look_into = "vegetables"
vegetable_registry = VegetableRegistry()
meta_registry.register(vegetable_registry, name="vegetable_registry") persisting-theory-0.2.1/tests/__init__.py 0000644 0001750 0000144 00000000206 12416752411 022347 0 ustar eliotberriot users 0000000 0000000 import os, sys
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(TEST_DIR)
sys.path.append(BASE_DIR) persisting-theory-0.2.1/tests/buggy_app/ 0000755 0001750 0000144 00000000000 12416754112 022215 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/tests/buggy_app/awesome_people.py 0000644 0001750 0000144 00000000103 12416752541 025571 0 ustar eliotberriot users 0000000 0000000 from ..test_registries import awesome_people
print(inexisting_var) persisting-theory-0.2.1/tests/buggy_app/__init__.py 0000644 0001750 0000144 00000000000 12377651526 024327 0 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/tests/app1/ 0000755 0001750 0000144 00000000000 12416754112 021101 5 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/tests/app1/vegetables.py 0000644 0001750 0000144 00000000146 12416752501 023575 0 ustar eliotberriot users 0000000 0000000 from ..test_registries import vegetable_registry
@vegetable_registry.register
class Potato:
pass
persisting-theory-0.2.1/tests/app1/awesome_people.py 0000644 0001750 0000144 00000000144 12416752444 024464 0 ustar eliotberriot users 0000000 0000000 from ..test_registries import awesome_people
@awesome_people.register
class AlainDamasio:
pass
persisting-theory-0.2.1/tests/app1/__init__.py 0000644 0001750 0000144 00000000000 12377651526 023213 0 ustar eliotberriot users 0000000 0000000 persisting-theory-0.2.1/tests/tests.py 0000644 0001750 0000144 00000011705 12416753545 021771 0 ustar eliotberriot users 0000000 0000000
import unittest
from . import test_registries
import persisting_theory
persisting_theory.meta_registry.look_into = "test_registries"
TEST_APPS = (
"tests.app1",
"tests.app2",
)
class RegistryTest(unittest.TestCase):
def test_can_infer_name_from_class_function_and_instance(self):
registry = persisting_theory.Registry()
def something():
pass
class MyClass:
pass
self.assertEqual(registry.get_object_name(something), "something")
self.assertEqual(registry.get_object_name(MyClass), "MyClass")
with self.assertRaises(ValueError):
self.assertEqual(registry.get_object_name(MyClass()), "MyClass")
def test_can_register_data_to_registry(self):
data = "something"
registry = persisting_theory.Registry()
registry.register(data, name="key")
self.assertEqual(len(registry), 1)
self.assertEqual(registry.get("key"), data)
def test_can_restric_registered_data(self):
class RestrictedRegistry(persisting_theory.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 = persisting_theory.Registry()
@registry.register
class ToRegister:
pass
self.assertEqual(registry.get('ToRegister'), ToRegister)
@registry.register
def something():
pass
self.assertEqual(registry.get('something'), something)
def test_can_register_via_decorator_using_custom_name(self):
registry = persisting_theory.Registry()
@registry.register(name="custom_name")
def something():
pass
self.assertEqual(registry.get('custom_name'), something)
def test_registry_can_autodiscover(self):
registry = test_registries.awesome_people
registry.autodiscover(apps=TEST_APPS)
self.assertEqual(len(registry), 2)
self.assertNotEqual(registry.get('AlainDamasio', None), None)
self.assertNotEqual(registry.get('FrederikPeeters', None), None)
registry.clear()
def test_autodiscover_raises_an_error_if_there_is_an_error_in_imported_module(self):
with self.assertRaises(NameError):
registry = test_registries.awesome_people
registry.autodiscover(apps=('tests.buggy_app',))
def test_meta_registry_can_autodiscovering_registries_and_trigger_their_autodiscover_method(self):
registry = persisting_theory.meta_registry
registry.autodiscover(apps=TEST_APPS)
self.assertEqual(len(registry), 2)
self.assertEqual(registry.get('awesome_people'), test_registries.awesome_people)
self.assertEqual(registry.get('vegetable_registry'), test_registries.vegetable_registry)
registry = test_registries.awesome_people
self.assertEqual(len(registry), 2)
self.assertNotEqual(registry.get('AlainDamasio', None), None)
self.assertNotEqual(registry.get('FrederikPeeters', None), None)
registry = test_registries.vegetable_registry
self.assertEqual(len(registry), 2)
self.assertNotEqual(registry.get('Potato', None), None)
self.assertNotEqual(registry.get('Ketchup', None), None)
def test_can_manipulate_data_before_registering(self):
class ModifyData(persisting_theory.Registry):
def prepare_data(self, data):
return "hello " + data
r = ModifyData()
r.register("eliot", name="eliot")
r.register("roger", name="roger")
self.assertEqual(r.get('eliot'), "hello eliot")
self.assertEqual(r.get('roger'), "hello roger")
def test_can_manipulate_key_before_registering(self):
class ModifyKey(persisting_theory.Registry):
def prepare_name(self, data, key=None):
return "custom_key " + data.first_name
r = ModifyKey()
class N:
def __init__(self, first_name):
self.first_name = first_name
n1 = N(first_name="eliot")
n2 = N(first_name="alain")
r.register(n1)
r.register(n2)
self.assertEqual(r.get('custom_key eliot'), n1)
self.assertEqual(r.get('custom_key alain'), n2)
def test_can_post_register_triggers_correctly(self):
class PostRegisterException(Exception):
pass
class PostRegister(persisting_theory.Registry):
def post_register(self, data, name):
raise PostRegisterException('Post register triggered')
r = PostRegister()
with self.assertRaises(PostRegisterException):
r.register("hello", name="world")
if __name__ == '__main__':
unittest.main() persisting-theory-0.2.1/setup.py 0000644 0001750 0000144 00000002021 12416753775 020621 0 ustar eliotberriot users 0000000 0000000 import os
from setuptools import setup, find_packages
import persisting_theory as package
README = open(os.path.join(os.path.dirname(__file__), 'README.rst')).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='persisting-theory',
version=package.__version__,
packages=find_packages(),
include_package_data=True,
license='BSD', # example license
description='Registries that can autodiscover values accross your project apps',
long_description=README,
url='http://code.eliotberriot.com/eliotberriot/persisting-theory',
author='Eliot Berriot',
author_email='contact@eliotberriot.com',
zip_safe=False,
classifiers=[
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
],
) persisting-theory-0.2.1/MANIFEST.in 0000644 0001750 0000144 00000000114 12377651526 020643 0 ustar eliotberriot users 0000000 0000000 include COPYING
include CHANGES
include README.rst
recursive-include example