0.0.3 version

This commit is contained in:
Roman Mogilatov 2015-01-11 15:03:45 +02:00
parent 2a29c43115
commit 028e5e9ef7
10 changed files with 327 additions and 101 deletions

102
README.md
View File

@ -4,7 +4,7 @@ Objects
Python catalogs of objects providers.
Example:
Example of objects catalog definition and usage:
```python
"""
@ -16,12 +16,12 @@ import sqlite3
# Some example classes.
class A(object):
class ObjectA(object):
def __init__(self, db):
self.db = db
class B(object):
class ObjectB(object):
def __init__(self, a, db):
self.a = a
self.db = db
@ -38,14 +38,14 @@ class AppCatalog(Catalog):
Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """
object_a = NewInstance(A,
object_a = NewInstance(ObjectA,
InitArg('db', database))
""" :type: (objects.Provider) -> A """
""" :type: (objects.Provider) -> ObjectA """
object_b = NewInstance(B,
object_b = NewInstance(ObjectB,
InitArg('a', object_a),
InitArg('db', database))
""" :type: (objects.Provider) -> B """
""" :type: (objects.Provider) -> ObjectB """
# Catalog injection into consumer class.
@ -69,3 +69,91 @@ assert a1 is not a2
assert b1 is not b2
assert a1.db is a2.db is b1.db is b2.db
```
Example of injections using objects.catalog:
```python
"""
Concept example of objects injections.
"""
from objects import Catalog, Singleton, NewInstance, InitArg, Attribute, inject
import sqlite3
# Some example class.
class ObjectA(object):
def __init__(self, db):
self.db = db
# Catalog of objects providers.
class AppCatalog(Catalog):
"""
Objects catalog.
"""
database = Singleton(sqlite3.Connection,
InitArg('database', ':memory:'),
Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """
object_a = NewInstance(ObjectA,
InitArg('db', database))
""" :type: (objects.Provider) -> ObjectA """
# Class attributes injections.
@inject(Attribute('a', AppCatalog.object_a))
@inject(Attribute('database', AppCatalog.database))
class Consumer(object):
"""
Some consumer class with database dependency via attribute.
"""
a = None
""" :type: (objects.Provider) -> ObjectA """
database = None
""" :type: (objects.Provider) -> sqlite3.Connection """
def tests(self):
a1, a2 = self.a(), self.a()
assert a1 is not a2
assert a1.db is a2.db is self.database()
consumer = Consumer()
consumer.tests()
# Class __init__ injections.
@inject(InitArg('a1', AppCatalog.object_a))
@inject(InitArg('a2', AppCatalog.object_a))
@inject(InitArg('database', AppCatalog.database))
class ConsumerWithInitArg(object):
"""
Some consumer class with database dependency via init arg.
"""
def __init__(self, a1, a2, database):
"""
Initializer.
:param a1: ObjectA
:param a2: ObjectA
:param database: sqlite3.Connection
"""
self.a1 = a1
self.a2 = a2
self.database = database
def tests(self):
assert self.a1 is not self.a2
assert self.a1.db is self.a2.db is self.database
consumer = ConsumerWithInitArg()
consumer.tests()
```

View File

@ -1 +1 @@
0.0.2
0.0.3

View File

@ -7,12 +7,12 @@ import sqlite3
# Some example classes.
class A(object):
class ObjectA(object):
def __init__(self, db):
self.db = db
class B(object):
class ObjectB(object):
def __init__(self, a, db):
self.a = a
self.db = db
@ -29,14 +29,14 @@ class AppCatalog(Catalog):
Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """
object_a = NewInstance(A,
object_a = NewInstance(ObjectA,
InitArg('db', database))
""" :type: (objects.Provider) -> A """
""" :type: (objects.Provider) -> ObjectA """
object_b = NewInstance(B,
object_b = NewInstance(ObjectB,
InitArg('a', object_a),
InitArg('db', database))
""" :type: (objects.Provider) -> B """
""" :type: (objects.Provider) -> ObjectB """
# Catalog injection into consumer class.

83
examples/injections.py Normal file
View File

@ -0,0 +1,83 @@
"""
Concept example of objects injections.
"""
from objects import Catalog, Singleton, NewInstance, InitArg, Attribute, inject
import sqlite3
# Some example class.
class ObjectA(object):
def __init__(self, db):
self.db = db
# Catalog of objects providers.
class AppCatalog(Catalog):
"""
Objects catalog.
"""
database = Singleton(sqlite3.Connection,
InitArg('database', ':memory:'),
Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """
object_a = NewInstance(ObjectA,
InitArg('db', database))
""" :type: (objects.Provider) -> ObjectA """
# Class attributes injections.
@inject(Attribute('a', AppCatalog.object_a))
@inject(Attribute('database', AppCatalog.database))
class Consumer(object):
"""
Some consumer class with database dependency via attribute.
"""
a = None
""" :type: (objects.Provider) -> ObjectA """
database = None
""" :type: (objects.Provider) -> sqlite3.Connection """
def tests(self):
a1, a2 = self.a(), self.a()
assert a1 is not a2
assert a1.db is a2.db is self.database()
consumer = Consumer()
consumer.tests()
# Class __init__ injections.
@inject(InitArg('a1', AppCatalog.object_a))
@inject(InitArg('a2', AppCatalog.object_a))
@inject(InitArg('database', AppCatalog.database))
class ConsumerWithInitArg(object):
"""
Some consumer class with database dependency via init arg.
"""
def __init__(self, a1, a2, database):
"""
Initializer.
:param a1: ObjectA
:param a2: ObjectA
:param database: sqlite3.Connection
"""
self.a1 = a1
self.a2 = a2
self.database = database
def tests(self):
assert self.a1 is not self.a2
assert self.a1.db is self.a2.db is self.database
consumer = ConsumerWithInitArg()
consumer.tests()

33
manage.py Normal file
View File

@ -0,0 +1,33 @@
"""
CLI Commands.
"""
import os
from setup import version
from manager import Manager
manager = Manager()
@manager.command
def publish(with_tag=True):
"""
Publishes current version to PyPi.
"""
os.system('python setup.py sdist upload')
if with_tag:
tag()
@manager.command
def tag():
"""
Makes tag from current version.
"""
os.system('git tag -a {0} -m \'version {0}\''.format(version))
os.system('git push --tags')
if __name__ == '__main__':
manager.main()

View File

@ -3,9 +3,9 @@
"""
from .catalog import Catalog
from .std_providers import (Provider, NewInstance, Singleton, Class, Object,
from .providers import (Provider, NewInstance, Singleton, Class, Object,
Function, Value)
from .injections import InitArg, Attribute, Method
from .injections import InitArg, Attribute, Method, inject
__all__ = ['Catalog',
@ -15,4 +15,4 @@ __all__ = ['Catalog',
'Object', 'Function', 'Value',
# Injections
'InitArg', 'Attribute', 'Method']
'InitArg', 'Attribute', 'Method', 'inject']

View File

@ -2,7 +2,7 @@
Catalog module.
"""
from .std_providers import Provider
from .providers import Provider
class Catalog(object):

View File

@ -2,6 +2,9 @@
Injections module.
"""
from inspect import isclass
from functools import wraps
class Injection(object):
"""
@ -15,14 +18,14 @@ class Injection(object):
self.name = name
self.injectable = injectable
@classmethod
def fetch(cls, injections):
@property
def value(self):
"""
Fetches injections of self type from list.
Returns injectable value.
"""
return tuple([injection
for injection in injections
if isinstance(injection, cls)])
if hasattr(self.injectable, '__is_objects_provider__'):
return self.injectable()
return self.injectable
class InitArg(Injection):
@ -41,3 +44,27 @@ class Method(Injection):
"""
Method injection.
"""
def inject(injection):
"""
Injection decorator.
"""
def decorator(callback_or_cls):
if isclass(callback_or_cls):
cls = callback_or_cls
if isinstance(injection, Attribute):
setattr(cls, injection.name, injection.injectable)
elif isinstance(injection, InitArg):
cls.__init__ = decorator(cls.__init__)
return cls
else:
callback = callback_or_cls
@wraps(callback)
def wrapped(*args, **kwargs):
if injection.name not in kwargs:
kwargs[injection.name] = injection.value
return callback(*args, **kwargs)
return wrapped
return decorator

View File

@ -10,25 +10,29 @@ class Provider(object):
Base provider class.
"""
__is_objects_provider__ = True
def __call__(self, *args, **kwargs):
"""
Returns provided instance.
"""
raise NotImplementedError()
@staticmethod
def prepare_injections(injections):
def prepare_injections(injections):
"""
Prepares injections list to injection.
"""
prepared_injections = dict()
for injection in injections:
if isinstance(injection.injectable, Provider):
value = injection.injectable.__call__()
else:
value = injection.injectable
prepared_injections[injection.name] = value
return prepared_injections
return [(injection.name, injection.value) for injection in injections]
def fetch_injections(injections, injection_type):
"""
Fetches injections of injection type from list.
"""
return tuple([injection
for injection in injections
if isinstance(injection, injection_type)])
class NewInstance(Provider):
@ -41,26 +45,26 @@ class NewInstance(Provider):
Initializer.
"""
self.provides = provides
self.init_injections = InitArg.fetch(injections)
self.attribute_injections = Attribute.fetch(injections)
self.method_injections = Method.fetch(injections)
self.init_injections = fetch_injections(injections, InitArg)
self.attribute_injections = fetch_injections(injections, Attribute)
self.method_injections = fetch_injections(injections, Method)
def __call__(self, *args, **kwargs):
"""
Returns provided instance.
"""
init_injections = Provider.prepare_injections(self.init_injections)
init_injections = prepare_injections(self.init_injections)
init_injections = dict(init_injections)
init_injections.update(kwargs)
provided = self.provides(*args, **init_injections)
attribute_injections = Provider.prepare_injections(
self.attribute_injections)
for name, injectable in attribute_injections.iteritems():
attribute_injections = prepare_injections(self.attribute_injections)
for name, injectable in attribute_injections:
setattr(provided, name, injectable)
method_injections = Provider.prepare_injections(self.method_injections)
for name, injectable in method_injections.iteritems():
method_injections = prepare_injections(self.method_injections)
for name, injectable in method_injections:
getattr(provided, name)(injectable)
return provided

View File

@ -2,8 +2,6 @@
`Objects` setup script.
"""
import os
import sys
from setuptools import setup
@ -26,16 +24,9 @@ with open('requirements.txt') as version:
with open('VERSION') as version:
version = version.read().strip()
# Helper commands.
if sys.argv[-1] == 'publish':
os.system('python setup.py sdist upload')
sys.exit()
if sys.argv[-1] == 'tag':
os.system('git tag -a {0} -m \'version {0}\''.format(version))
os.system('git push --tags')
sys.exit()
setup(
if __name__ == '__main__':
setup(
name='Objects',
version=version,
description='Python catalogs of objects providers',
@ -78,4 +69,4 @@ setup(
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
]
)
)