Merge pull request #8 from rmk135/0.3-dev

0.3 Release
This commit is contained in:
Roman 2015-01-28 14:58:28 +02:00
commit 1192557e1b
10 changed files with 533 additions and 4 deletions

198
README.md
View File

@ -14,6 +14,7 @@ Concept example of objects catalogs.
from objects import AbstractCatalog from objects import AbstractCatalog
from objects.providers import Singleton, NewInstance from objects.providers import Singleton, NewInstance
from objects.injections import InitArg, Attribute from objects.injections import InitArg, Attribute
import sqlite3 import sqlite3
@ -121,6 +122,7 @@ Concept example of objects overrides.
from objects import AbstractCatalog, overrides from objects import AbstractCatalog, overrides
from objects.providers import Singleton, NewInstance from objects.providers import Singleton, NewInstance
from objects.injections import InitArg, Attribute from objects.injections import InitArg, Attribute
import sqlite3 import sqlite3
@ -130,6 +132,7 @@ class ObjectA(object):
self.db = db self.db = db
# Mock of example class.
class ObjectAMock(ObjectA): class ObjectAMock(ObjectA):
pass pass
@ -183,6 +186,7 @@ Concept example of objects catalogs.
from objects import AbstractCatalog from objects import AbstractCatalog
from objects.providers import Singleton, NewInstance, ExternalDependency from objects.providers import Singleton, NewInstance, ExternalDependency
from objects.injections import InitArg, Attribute from objects.injections import InitArg, Attribute
import sqlite3 import sqlite3
@ -231,3 +235,197 @@ assert a1 is not a2
assert b1 is not b2 assert b1 is not b2
assert a1.db is a2.db is b1.db is b2.db is Catalog.database() assert a1.db is a2.db is b1.db is b2.db is Catalog.database()
``` ```
Example of objects catalog with scoped provider:
```python
"""
Scoped provider examples.
"""
from objects import AbstractCatalog
from objects.providers import Singleton, Scoped
from objects.injections import InitArg, Attribute
import sqlite3
class ObjectA(object):
def __init__(self, db):
self.db = db
# Catalog of objects providers.
class Catalog(AbstractCatalog):
"""
Objects catalog.
"""
database = Singleton(sqlite3.Connection,
InitArg('database', ':memory:'),
Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """
object_a = Scoped(ObjectA,
InitArg('db', database))
""" :type: (objects.Provider) -> ObjectA """
# Making scope using `with` statement.
with Catalog.object_a as object_a_provider:
object_a1 = object_a_provider()
object_a2 = object_a_provider()
assert object_a1 is object_a2
assert object_a1.db is object_a2.db
# Making another one scope using `with` statement.
with Catalog.object_a as object_a_provider:
object_a3 = object_a_provider()
object_a4 = object_a_provider()
assert object_a3 is object_a4
assert object_a3.db is object_a4.db
assert (object_a1 is not object_a3) and \
(object_a1 is not object_a4)
assert (object_a2 is not object_a3) and \
(object_a2 is not object_a4)
# Making one more scope using provider methods.
Catalog.object_a.in_scope()
object_a5 = Catalog.object_a()
object_a6 = Catalog.object_a()
assert object_a5 is object_a6
assert object_a5.db is object_a6.db
assert (object_a1 is not object_a3) and \
(object_a1 is not object_a4) and \
(object_a1 is not object_a5) and \
(object_a1 is not object_a6)
assert (object_a2 is not object_a3) and \
(object_a2 is not object_a4) and \
(object_a2 is not object_a5) and \
(object_a2 is not object_a6)
```
Example of objects catalog with callable provider:
```python
"""
Callable provider examples.
"""
from objects import AbstractCatalog
from objects.providers import Singleton, Callable
from objects.injections import Injection, InitArg, Attribute
import sqlite3
# Some example function.
def consuming_function(arg, db):
return arg, db
# Catalog of objects providers.
class Catalog(AbstractCatalog):
"""
Objects catalog.
"""
database = Singleton(sqlite3.Connection,
InitArg('database', ':memory:'),
Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """
consuming_function = Callable(consuming_function,
Injection('db', database))
""" :type: (objects.Provider) -> consuming_function """
# Some calls.
arg1, db1 = Catalog.consuming_function(1)
arg2, db2 = Catalog.consuming_function(2)
arg3, db3 = Catalog.consuming_function(3)
# Some asserts.
assert db1 is db2 is db3
assert arg1 == 1
assert arg2 == 2
assert arg3 == 3
```
Example of objects catalog with config provider:
```python
"""
Config provider examples.
"""
from objects import AbstractCatalog
from objects.providers import Config, NewInstance
from objects.injections import InitArg
# Some example class.
class ObjectA(object):
def __init__(self, setting_one, setting_two, setting_three):
self.setting_one = setting_one
self.setting_two = setting_two
self.setting_three = setting_three
# Catalog of objects providers.
class Catalog(AbstractCatalog):
"""
Objects catalog.
"""
config = Config()
""" :type: (objects.Config) """
object_a = NewInstance(ObjectA,
InitArg('setting_one', config.SETTING_ONE),
InitArg('setting_two', config.SETTING_TWO),
InitArg('setting_three', config.GLOBAL.SETTING_THREE))
""" :type: (objects.Provider) -> ObjectA """
# Setting config value and making some tests.
Catalog.config.update_from({
'SETTING_ONE': 1,
'SETTING_TWO': 2,
'GLOBAL': {
'SETTING_THREE': 3
}
})
object_a1 = Catalog.object_a()
assert object_a1.setting_one == 1
assert object_a1.setting_two == 2
assert object_a1.setting_three == 3
# Changing config value one more time and making some tests.
Catalog.config.update_from({
'SETTING_ONE': 11,
'SETTING_TWO': 22,
'GLOBAL': {
'SETTING_THREE': 33
}
})
object_a2 = Catalog.object_a()
assert object_a2.setting_one == 11
assert object_a2.setting_two == 22
assert object_a2.setting_three == 33
assert object_a1.setting_one == 1
assert object_a1.setting_two == 2
assert object_a1.setting_three == 3
```

View File

@ -1 +1 @@
0.2.1 0.3.0

View File

@ -0,0 +1,42 @@
"""
Callable provider examples.
"""
from objects import AbstractCatalog
from objects.providers import Singleton, Callable
from objects.injections import Injection, InitArg, Attribute
import sqlite3
# Some example function.
def consuming_function(arg, db):
return arg, db
# Catalog of objects providers.
class Catalog(AbstractCatalog):
"""
Objects catalog.
"""
database = Singleton(sqlite3.Connection,
InitArg('database', ':memory:'),
Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """
consuming_function = Callable(consuming_function,
Injection('db', database))
""" :type: (objects.Provider) -> consuming_function """
# Some calls.
arg1, db1 = Catalog.consuming_function(1)
arg2, db2 = Catalog.consuming_function(2)
arg3, db3 = Catalog.consuming_function(3)
# Some asserts.
assert db1 is db2 is db3
assert arg1 == 1
assert arg2 == 2
assert arg3 == 3

View File

@ -5,6 +5,7 @@ Concept example of objects catalogs.
from objects import AbstractCatalog from objects import AbstractCatalog
from objects.providers import Singleton, NewInstance from objects.providers import Singleton, NewInstance
from objects.injections import InitArg, Attribute from objects.injections import InitArg, Attribute
import sqlite3 import sqlite3

View File

@ -0,0 +1,66 @@
"""
Config provider examples.
"""
from objects import AbstractCatalog
from objects.providers import Config, NewInstance
from objects.injections import InitArg
# Some example class.
class ObjectA(object):
def __init__(self, setting_one, setting_two, setting_three):
self.setting_one = setting_one
self.setting_two = setting_two
self.setting_three = setting_three
# Catalog of objects providers.
class Catalog(AbstractCatalog):
"""
Objects catalog.
"""
config = Config()
""" :type: (objects.Config) """
object_a = NewInstance(ObjectA,
InitArg('setting_one', config.SETTING_ONE),
InitArg('setting_two', config.SETTING_TWO),
InitArg('setting_three', config.GLOBAL.SETTING_THREE))
""" :type: (objects.Provider) -> ObjectA """
# Setting config value and making some tests.
Catalog.config.update_from({
'SETTING_ONE': 1,
'SETTING_TWO': 2,
'GLOBAL': {
'SETTING_THREE': 3
}
})
object_a1 = Catalog.object_a()
assert object_a1.setting_one == 1
assert object_a1.setting_two == 2
assert object_a1.setting_three == 3
# Changing config value one more time and making some tests.
Catalog.config.update_from({
'SETTING_ONE': 11,
'SETTING_TWO': 22,
'GLOBAL': {
'SETTING_THREE': 33
}
})
object_a2 = Catalog.object_a()
assert object_a2.setting_one == 11
assert object_a2.setting_two == 22
assert object_a2.setting_three == 33
assert object_a1.setting_one == 1
assert object_a1.setting_two == 2
assert object_a1.setting_three == 3

View File

@ -5,6 +5,7 @@ Concept example of objects catalogs.
from objects import AbstractCatalog from objects import AbstractCatalog
from objects.providers import Singleton, NewInstance, ExternalDependency from objects.providers import Singleton, NewInstance, ExternalDependency
from objects.injections import InitArg, Attribute from objects.injections import InitArg, Attribute
import sqlite3 import sqlite3

View File

@ -6,6 +6,7 @@ Concept example of objects overrides.
from objects import AbstractCatalog, overrides from objects import AbstractCatalog, overrides
from objects.providers import Singleton, NewInstance from objects.providers import Singleton, NewInstance
from objects.injections import InitArg, Attribute from objects.injections import InitArg, Attribute
import sqlite3 import sqlite3
@ -15,6 +16,7 @@ class ObjectA(object):
self.db = db self.db = db
# Mock of example class.
class ObjectAMock(ObjectA): class ObjectAMock(ObjectA):
pass pass

View File

@ -0,0 +1,71 @@
"""
Scoped provider examples.
"""
from objects import AbstractCatalog
from objects.providers import Singleton, Scoped
from objects.injections import InitArg, Attribute
import sqlite3
class ObjectA(object):
def __init__(self, db):
self.db = db
# Catalog of objects providers.
class Catalog(AbstractCatalog):
"""
Objects catalog.
"""
database = Singleton(sqlite3.Connection,
InitArg('database', ':memory:'),
Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """
object_a = Scoped(ObjectA,
InitArg('db', database))
""" :type: (objects.Provider) -> ObjectA """
# Making scope using `with` statement.
with Catalog.object_a as object_a_provider:
object_a1 = object_a_provider()
object_a2 = object_a_provider()
assert object_a1 is object_a2
assert object_a1.db is object_a2.db
# Making another one scope using `with` statement.
with Catalog.object_a as object_a_provider:
object_a3 = object_a_provider()
object_a4 = object_a_provider()
assert object_a3 is object_a4
assert object_a3.db is object_a4.db
assert (object_a1 is not object_a3) and \
(object_a1 is not object_a4)
assert (object_a2 is not object_a3) and \
(object_a2 is not object_a4)
# Making one more scope using provider methods.
Catalog.object_a.in_scope()
object_a5 = Catalog.object_a()
object_a6 = Catalog.object_a()
assert object_a5 is object_a6
assert object_a5.db is object_a6.db
assert (object_a1 is not object_a3) and \
(object_a1 is not object_a4) and \
(object_a1 is not object_a5) and \
(object_a1 is not object_a6)
assert (object_a2 is not object_a3) and \
(object_a2 is not object_a4) and \
(object_a2 is not object_a5) and \
(object_a2 is not object_a6)

View File

@ -33,14 +33,14 @@ class AbstractCatalog(object):
return attribute return attribute
@classmethod @classmethod
def __all_providers__(cls): def __all_providers__(cls, provider_type=Provider):
""" """
Returns set of all class providers. Returns set of all class providers.
""" """
providers = set() providers = set()
for attr_name in set(dir(cls)) - set(dir(AbstractCatalog)): for attr_name in set(dir(cls)) - set(dir(AbstractCatalog)):
provider = getattr(cls, attr_name) provider = getattr(cls, attr_name)
if not isinstance(provider, Provider): if not isinstance(provider, provider_type):
continue continue
providers.add((attr_name, provider)) providers.add((attr_name, provider))
return providers return providers

View File

@ -3,7 +3,7 @@ Standard providers.
""" """
from collections import Iterable from collections import Iterable
from .injections import InitArg, Attribute, Method from .injections import Injection, InitArg, Attribute, Method
class Provider(object): class Provider(object):
@ -108,6 +108,60 @@ class Singleton(NewInstance):
self.instance = super(Singleton, self).__call__(*args, **kwargs) self.instance = super(Singleton, self).__call__(*args, **kwargs)
return self.instance return self.instance
def _reset_instance(self):
"""
Resets instance.
"""
self.instance = None
class Scoped(Singleton):
"""
Scoped provider will create instance once for every scope and return it on every call.
"""
def __init__(self, *args, **kwargs):
"""
Initializer.
"""
self.is_in_scope = None
super(Scoped, self).__init__(*args, **kwargs)
def in_scope(self):
"""
Sets provider in "in scope" state.
"""
self.is_in_scope = True
self._reset_instance()
def out_of_scope(self):
"""
Sets provider in "out of scope" state.
"""
self.is_in_scope = False
self._reset_instance()
def __call__(self, *args, **kwargs):
"""
Returns provided instance.
"""
if not self.is_in_scope:
raise RuntimeError('Trying to provide {} while provider is not in scope'.format(self.provides))
return super(Scoped, self).__call__(*args, **kwargs)
def __enter__(self):
"""
With __enter__() implementation. Makes provider to be in scope.
"""
self.in_scope()
return self
def __exit__(self, *_):
"""
With __exit__() implementation. Makes provider to be out of scope.
"""
self.out_of_scope()
class ExternalDependency(Provider): class ExternalDependency(Provider):
""" """
@ -193,3 +247,97 @@ class Value(_StaticProvider):
""" """
Value provider provides value. Value provider provides value.
""" """
class Callable(Provider):
"""
Callable provider will provide callable calls with some predefined
dependencies injections.
"""
def __init__(self, calls, *injections):
"""
Initializer.
"""
self.calls = calls
self.injections = fetch_injections(injections, Injection)
super(Callable, self).__init__()
def __call__(self, *args, **kwargs):
"""
Returns provided instance.
"""
if self.__overridden_by__:
return self.__overridden_by__[-1].__call__(*args, **kwargs)
injections = prepare_injections(self.injections)
injections = dict(injections)
injections.update(kwargs)
return self.calls(*args, **injections)
class _DeferredConfig(Provider):
"""
Deferred config providers provide an value from the root config object.
"""
def __init__(self, paths, root_config):
"""
Initializer.
"""
self.paths = paths
self.root_config = root_config
super(_DeferredConfig, self).__init__()
def __getattr__(self, item):
"""
Returns instance of deferred config.
"""
return _DeferredConfig(paths=self.paths + (item,),
root_config=self.root_config)
def __call__(self, *args, **kwargs):
"""
Returns provided instance.
"""
return self.root_config(self.paths)
class Config(Provider):
"""
Config provider provides dict values. Also config provider creates
deferred config objects for all undefined attribute calls.
"""
def __init__(self, value=None):
"""
Initializer.
"""
if not value:
value = dict()
self.value = value
super(Config, self).__init__()
def update_from(self, value):
"""
Updates current value from another one.
"""
self.value.update(value)
def __getattr__(self, item):
"""
Returns instance of deferred config.
"""
return _DeferredConfig(paths=(item,),
root_config=self)
def __call__(self, paths=None):
"""
Returns provided instance.
"""
value = self.value
if paths:
for path in paths:
value = value[path]
return value