diff --git a/README.md b/README.md index a4265950..619ced27 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,63 @@ Objects ======= Python catalogs of objects providers. + + +Example: + +```python +import objects +import sqlite3 + + +class A(object): + def __init__(self, db): + self.db = db + + +class B(object): + def __init__(self, a, db): + self.a = a + self.db = db + + +class Catalog(objects.Catalog): + """ + Objects catalog. + """ + + database = objects.Singleton(sqlite3.Connection, + database='example.db') + """ :type: (objects.Provider) -> sqlite3.Connection """ + + object_a = objects.NewInstance(A, + db=database) + """ :type: (objects.Provider) -> A """ + + object_b = objects.NewInstance(B, + a=object_a, + db=database) + """ :type: (objects.Provider) -> B """ + + +class Consumer(object): + catalog = Catalog(Catalog.object_a, + Catalog.object_b) + + def return_a_b(self): + return (self.catalog.object_a(), + self.catalog.object_b()) + +a1, b1 = Consumer().return_a_b() + +a2 = Catalog.object_a() +b2 = Catalog.object_b() + +print a1, a1.db +print a2, a2.db +print b1, b1.db +print b2, b2.db + +assert a1 is not a2 +assert b1 is not b2 +``` diff --git a/examples/concept.py b/examples/concept.py index f5d861f6..5b16c5da 100644 --- a/examples/concept.py +++ b/examples/concept.py @@ -36,10 +36,15 @@ class Catalog(objects.Catalog): """ :type: (objects.Provider) -> B """ -catalog = Catalog(Catalog.object_a, - Catalog.object_b) -a1 = catalog.object_a() -b1 = catalog.object_b() +class Consumer(object): + catalog = Catalog(Catalog.object_a, + Catalog.object_b) + + def return_a_b(self): + return (self.catalog.object_a(), + self.catalog.object_b()) + +a1, b1 = Consumer().return_a_b() a2 = Catalog.object_a() b2 = Catalog.object_b() diff --git a/objects/__init__.py b/objects/__init__.py index 16243060..b206d951 100644 --- a/objects/__init__.py +++ b/objects/__init__.py @@ -2,48 +2,10 @@ `Objects` library. """ - -class Catalog(object): - def __init__(self, *args): - args = set(args) - for attribute_name in set(dir(self.__class__)) - set(dir(Catalog)): - provider = getattr(self, attribute_name) - if not isinstance(provider, Provider): - continue - if provider not in args: - setattr(self, attribute_name, None) +from .catalog import Catalog +from .std_providers import (Provider, NewInstance, Singleton, Class, Object, + Function, Value) -class Provider(object): - def __call__(self, *args, **kwargs): - raise NotImplementedError() - - -class NewInstance(Provider): - def __init__(self, provides, **dependencies): - self.provides = provides - self.dependencies = dependencies - - def __call__(self, *args, **kwargs): - for name, dependency in self.dependencies.iteritems(): - if name in kwargs: - continue - - if isinstance(dependency, Provider): - value = dependency.__call__() - else: - value = dependency - - kwargs[name] = value - return self.provides(*args, **kwargs) - - -class Singleton(NewInstance): - def __init__(self, *args, **kwargs): - self.instance = None - super(Singleton, self).__init__(*args, **kwargs) - - def __call__(self, *args, **kwargs): - if not self.instance: - self.instance = super(Singleton, self).__call__(*args, **kwargs) - return self.instance +__all__ = ['Catalog', 'Provider', 'NewInstance', 'Singleton', 'Class', + 'Object', 'Function', 'Value'] diff --git a/objects/catalog.py b/objects/catalog.py new file mode 100644 index 00000000..66a706a4 --- /dev/null +++ b/objects/catalog.py @@ -0,0 +1,32 @@ +""" +Catalog module. +""" + +from .std_providers import Provider + + +class Catalog(object): + """ + Object provides catalog. + """ + + def __init__(self, *used_providers): + """ + Initializer. + """ + self._clean_unused_providers(used_providers) + + def _clean_unused_providers(self, used_providers): + """ + Sets every catalog's provider in None except of `used_providers` list. + + :param list|tuple|set used_providers: + :return: + """ + used_providers = set(used_providers) + for attribute_name in set(dir(self.__class__)) - set(dir(Catalog)): + provider = getattr(self, attribute_name) + if not isinstance(provider, Provider): + continue + if provider not in used_providers: + setattr(self, attribute_name, None) diff --git a/objects/std_providers.py b/objects/std_providers.py new file mode 100644 index 00000000..460987e3 --- /dev/null +++ b/objects/std_providers.py @@ -0,0 +1,108 @@ +""" +Standard providers. +""" + + +class Provider(object): + """ + Base provider class. + """ + + def __call__(self, *args, **kwargs): + """ + Returns provided instance. + """ + raise NotImplementedError() + + +class NewInstance(Provider): + """ + New instance providers will create and return new instance on every call. + """ + + def __init__(self, provides, **dependencies): + """ + Initializer. + """ + self.provides = provides + self.dependencies = dependencies + + def __call__(self, *args, **kwargs): + """ + Returns provided instance. + """ + for name, dependency in self.dependencies.iteritems(): + if name in kwargs: + continue + + if isinstance(dependency, Provider): + value = dependency.__call__() + else: + value = dependency + + kwargs[name] = value + return self.provides(*args, **kwargs) + + +class Singleton(NewInstance): + """ + Singleton provider will create instance once and return it on every call. + """ + + def __init__(self, *args, **kwargs): + """ + Initializer. + """ + self.instance = None + super(Singleton, self).__init__(*args, **kwargs) + + def __call__(self, *args, **kwargs): + """ + Returns provided instance. + """ + if not self.instance: + self.instance = super(Singleton, self).__call__(*args, **kwargs) + return self.instance + + +class _StaticProvider(Provider): + """ + Static provider is base implementation that provides exactly the same as + it got on input. + """ + + def __init__(self, provides): + """ + Initializer. + """ + self.provides = provides + + def __call__(self): + """ + Returns provided instance. + """ + return self.provides + + +class Class(_StaticProvider): + """ + Class provider provides class. + """ + + +class Object(_StaticProvider): + """ + Object provider provides object. + """ + + +class Function(_StaticProvider): + """ + Function provider provides function. + """ + + +class Value(_StaticProvider): + """ + Value provider provides value. + """