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.providers import Singleton, NewInstance
from objects.injections import InitArg, Attribute
import sqlite3
@ -121,6 +122,7 @@ Concept example of objects overrides.
from objects import AbstractCatalog, overrides
from objects.providers import Singleton, NewInstance
from objects.injections import InitArg, Attribute
import sqlite3
@ -130,6 +132,7 @@ class ObjectA(object):
self.db = db
# Mock of example class.
class ObjectAMock(ObjectA):
pass
@ -183,6 +186,7 @@ Concept example of objects catalogs.
from objects import AbstractCatalog
from objects.providers import Singleton, NewInstance, ExternalDependency
from objects.injections import InitArg, Attribute
import sqlite3
@ -231,3 +235,197 @@ assert a1 is not a2
assert b1 is not b2
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.providers import Singleton, NewInstance
from objects.injections import InitArg, Attribute
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.providers import Singleton, NewInstance, ExternalDependency
from objects.injections import InitArg, Attribute
import sqlite3

View File

@ -6,6 +6,7 @@ Concept example of objects overrides.
from objects import AbstractCatalog, overrides
from objects.providers import Singleton, NewInstance
from objects.injections import InitArg, Attribute
import sqlite3
@ -15,6 +16,7 @@ class ObjectA(object):
self.db = db
# Mock of example class.
class ObjectAMock(ObjectA):
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
@classmethod
def __all_providers__(cls):
def __all_providers__(cls, provider_type=Provider):
"""
Returns set of all class providers.
"""
providers = set()
for attr_name in set(dir(cls)) - set(dir(AbstractCatalog)):
provider = getattr(cls, attr_name)
if not isinstance(provider, Provider):
if not isinstance(provider, provider_type):
continue
providers.add((attr_name, provider))
return providers

View File

@ -3,7 +3,7 @@ Standard providers.
"""
from collections import Iterable
from .injections import InitArg, Attribute, Method
from .injections import Injection, InitArg, Attribute, Method
class Provider(object):
@ -108,6 +108,60 @@ class Singleton(NewInstance):
self.instance = super(Singleton, self).__call__(*args, **kwargs)
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):
"""
@ -193,3 +247,97 @@ class Value(_StaticProvider):
"""
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