persisting-theory-0.2.1/0000755000175000001440000000000012416754112017076 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/CHANGES0000644000175000001440000000115112416754011020065 0ustar eliotberriotusers00000000000000Changelog ========= 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 releasepersisting-theory-0.2.1/persisting_theory/0000755000175000001440000000000012416754112022657 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/persisting_theory/__init__.py0000644000175000001440000000010612416754016024770 0ustar eliotberriotusers00000000000000from .registries import Registry, meta_registry __version__ = "0.2.1"persisting-theory-0.2.1/persisting_theory/registries.py0000644000175000001440000001177412416753504025427 0ustar eliotberriotusers00000000000000from 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/COPYING0000644000175000001440000000301612377651526020144 0ustar eliotberriotusers00000000000000Copyright (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.rst0000644000175000001440000001464312377651526020610 0ustar eliotberriotusers00000000000000Introduction ============ 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/0000755000175000001440000000000012416754112024351 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/persisting_theory.egg-info/SOURCES.txt0000644000175000001440000000140412416754112026234 0ustar eliotberriotusers00000000000000CHANGES 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.pypersisting-theory-0.2.1/persisting_theory.egg-info/dependency_links.txt0000644000175000001440000000000112416754112030417 0ustar eliotberriotusers00000000000000 persisting-theory-0.2.1/persisting_theory.egg-info/not-zip-safe0000644000175000001440000000000112377651526026612 0ustar eliotberriotusers00000000000000 persisting-theory-0.2.1/persisting_theory.egg-info/top_level.txt0000644000175000001440000000004012416754112027075 0ustar eliotberriotusers00000000000000tests example persisting_theory persisting-theory-0.2.1/persisting_theory.egg-info/PKG-INFO0000644000175000001440000002201112416754112025442 0ustar eliotberriotusers00000000000000Metadata-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/0000755000175000001440000000000012416754112020531 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/example/dosomething.py0000644000175000001440000000035612377651526023442 0ustar eliotberriotusers00000000000000from registries import callbacks_registry APPS = ( 'app1', 'app2', ) # Trigger autodiscovering process callbacks_registry.autodiscover(APPS) for callback in callbacks_registry.values(): callback() # Wouf # Meowpersisting-theory-0.2.1/example/app2/0000755000175000001440000000000012416754112021373 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/example/app2/callbacks_registry.py0000644000175000001440000000014412377651526025626 0ustar eliotberriotusers00000000000000from registries import callbacks_registry @callbacks_registry.register def cat(): print("Meow")persisting-theory-0.2.1/example/app2/__init__.py0000644000175000001440000000000012377651526023505 0ustar eliotberriotusers00000000000000persisting-theory-0.2.1/example/__init__.py0000644000175000001440000000000012377651526022643 0ustar eliotberriotusers00000000000000persisting-theory-0.2.1/example/registries.py0000644000175000001440000000073312377651526023301 0ustar eliotberriotusers00000000000000import 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/0000755000175000001440000000000012416754112021372 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/example/app1/callbacks_registry.py0000644000175000001440000000014412377651526025625 0ustar eliotberriotusers00000000000000from registries import callbacks_registry @callbacks_registry.register def dog(): print("Wouf")persisting-theory-0.2.1/example/app1/__init__.py0000644000175000001440000000000012377651526023504 0ustar eliotberriotusers00000000000000persisting-theory-0.2.1/PKG-INFO0000644000175000001440000002201112416754112020167 0ustar eliotberriotusers00000000000000Metadata-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.cfg0000644000175000001440000000007312416754112020717 0ustar eliotberriotusers00000000000000[egg_info] tag_date = 0 tag_build = tag_svn_revision = 0 persisting-theory-0.2.1/tests/0000755000175000001440000000000012416754112020240 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/tests/app2/0000755000175000001440000000000012416754112021102 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/tests/app2/vegetables.py0000644000175000001440000000021012416752512023570 0ustar eliotberriotusers00000000000000from ..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.py0000644000175000001440000000014612416752506024466 0ustar eliotberriotusers00000000000000from ..test_registries import awesome_people @awesome_people.register class FrederikPeeters: passpersisting-theory-0.2.1/tests/app2/__init__.py0000644000175000001440000000000012377651526023214 0ustar eliotberriotusers00000000000000persisting-theory-0.2.1/tests/test_registries.py0000644000175000001440000000062712416751674024050 0ustar eliotberriotusers00000000000000from 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__.py0000644000175000001440000000020612416752411022347 0ustar eliotberriotusers00000000000000import 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/0000755000175000001440000000000012416754112022215 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/tests/buggy_app/awesome_people.py0000644000175000001440000000010312416752541025571 0ustar eliotberriotusers00000000000000from ..test_registries import awesome_people print(inexisting_var)persisting-theory-0.2.1/tests/buggy_app/__init__.py0000644000175000001440000000000012377651526024327 0ustar eliotberriotusers00000000000000persisting-theory-0.2.1/tests/app1/0000755000175000001440000000000012416754112021101 5ustar eliotberriotusers00000000000000persisting-theory-0.2.1/tests/app1/vegetables.py0000644000175000001440000000014612416752501023575 0ustar eliotberriotusers00000000000000from ..test_registries import vegetable_registry @vegetable_registry.register class Potato: pass persisting-theory-0.2.1/tests/app1/awesome_people.py0000644000175000001440000000014412416752444024464 0ustar eliotberriotusers00000000000000from ..test_registries import awesome_people @awesome_people.register class AlainDamasio: pass persisting-theory-0.2.1/tests/app1/__init__.py0000644000175000001440000000000012377651526023213 0ustar eliotberriotusers00000000000000persisting-theory-0.2.1/tests/tests.py0000644000175000001440000001170512416753545021771 0ustar eliotberriotusers00000000000000 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.py0000644000175000001440000000202112416753775020621 0ustar eliotberriotusers00000000000000import 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.in0000644000175000001440000000011412377651526020643 0ustar eliotberriotusers00000000000000include COPYING include CHANGES include README.rst recursive-include example