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. Python catalogs of objects providers.
Example: Example of objects catalog definition and usage:
```python ```python
""" """
@ -16,12 +16,12 @@ import sqlite3
# Some example classes. # Some example classes.
class A(object): class ObjectA(object):
def __init__(self, db): def __init__(self, db):
self.db = db self.db = db
class B(object): class ObjectB(object):
def __init__(self, a, db): def __init__(self, a, db):
self.a = a self.a = a
self.db = db self.db = db
@ -38,14 +38,14 @@ class AppCatalog(Catalog):
Attribute('row_factory', sqlite3.Row)) Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """ """ :type: (objects.Provider) -> sqlite3.Connection """
object_a = NewInstance(A, object_a = NewInstance(ObjectA,
InitArg('db', database)) InitArg('db', database))
""" :type: (objects.Provider) -> A """ """ :type: (objects.Provider) -> ObjectA """
object_b = NewInstance(B, object_b = NewInstance(ObjectB,
InitArg('a', object_a), InitArg('a', object_a),
InitArg('db', database)) InitArg('db', database))
""" :type: (objects.Provider) -> B """ """ :type: (objects.Provider) -> ObjectB """
# Catalog injection into consumer class. # Catalog injection into consumer class.
@ -69,3 +69,91 @@ 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 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. # Some example classes.
class A(object): class ObjectA(object):
def __init__(self, db): def __init__(self, db):
self.db = db self.db = db
class B(object): class ObjectB(object):
def __init__(self, a, db): def __init__(self, a, db):
self.a = a self.a = a
self.db = db self.db = db
@ -29,14 +29,14 @@ class AppCatalog(Catalog):
Attribute('row_factory', sqlite3.Row)) Attribute('row_factory', sqlite3.Row))
""" :type: (objects.Provider) -> sqlite3.Connection """ """ :type: (objects.Provider) -> sqlite3.Connection """
object_a = NewInstance(A, object_a = NewInstance(ObjectA,
InitArg('db', database)) InitArg('db', database))
""" :type: (objects.Provider) -> A """ """ :type: (objects.Provider) -> ObjectA """
object_b = NewInstance(B, object_b = NewInstance(ObjectB,
InitArg('a', object_a), InitArg('a', object_a),
InitArg('db', database)) InitArg('db', database))
""" :type: (objects.Provider) -> B """ """ :type: (objects.Provider) -> ObjectB """
# Catalog injection into consumer class. # 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 .catalog import Catalog
from .std_providers import (Provider, NewInstance, Singleton, Class, Object, from .providers import (Provider, NewInstance, Singleton, Class, Object,
Function, Value) Function, Value)
from .injections import InitArg, Attribute, Method from .injections import InitArg, Attribute, Method, inject
__all__ = ['Catalog', __all__ = ['Catalog',
@ -15,4 +15,4 @@ __all__ = ['Catalog',
'Object', 'Function', 'Value', 'Object', 'Function', 'Value',
# Injections # Injections
'InitArg', 'Attribute', 'Method'] 'InitArg', 'Attribute', 'Method', 'inject']

View File

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

View File

@ -2,6 +2,9 @@
Injections module. Injections module.
""" """
from inspect import isclass
from functools import wraps
class Injection(object): class Injection(object):
""" """
@ -15,14 +18,14 @@ class Injection(object):
self.name = name self.name = name
self.injectable = injectable self.injectable = injectable
@classmethod @property
def fetch(cls, injections): def value(self):
""" """
Fetches injections of self type from list. Returns injectable value.
""" """
return tuple([injection if hasattr(self.injectable, '__is_objects_provider__'):
for injection in injections return self.injectable()
if isinstance(injection, cls)]) return self.injectable
class InitArg(Injection): class InitArg(Injection):
@ -41,3 +44,27 @@ class Method(Injection):
""" """
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. Base provider class.
""" """
__is_objects_provider__ = True
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
""" """
Returns provided instance. Returns provided instance.
""" """
raise NotImplementedError() raise NotImplementedError()
@staticmethod
def prepare_injections(injections): def prepare_injections(injections):
""" """
Prepares injections list to injection. Prepares injections list to injection.
""" """
prepared_injections = dict() return [(injection.name, injection.value) for injection in injections]
for injection in injections:
if isinstance(injection.injectable, Provider):
value = injection.injectable.__call__() def fetch_injections(injections, injection_type):
else: """
value = injection.injectable Fetches injections of injection type from list.
prepared_injections[injection.name] = value """
return prepared_injections return tuple([injection
for injection in injections
if isinstance(injection, injection_type)])
class NewInstance(Provider): class NewInstance(Provider):
@ -41,26 +45,26 @@ class NewInstance(Provider):
Initializer. Initializer.
""" """
self.provides = provides self.provides = provides
self.init_injections = InitArg.fetch(injections) self.init_injections = fetch_injections(injections, InitArg)
self.attribute_injections = Attribute.fetch(injections) self.attribute_injections = fetch_injections(injections, Attribute)
self.method_injections = Method.fetch(injections) self.method_injections = fetch_injections(injections, Method)
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
""" """
Returns provided instance. 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) init_injections.update(kwargs)
provided = self.provides(*args, **init_injections) provided = self.provides(*args, **init_injections)
attribute_injections = Provider.prepare_injections( attribute_injections = prepare_injections(self.attribute_injections)
self.attribute_injections) for name, injectable in attribute_injections:
for name, injectable in attribute_injections.iteritems():
setattr(provided, name, injectable) setattr(provided, name, injectable)
method_injections = Provider.prepare_injections(self.method_injections) method_injections = prepare_injections(self.method_injections)
for name, injectable in method_injections.iteritems(): for name, injectable in method_injections:
getattr(provided, name)(injectable) getattr(provided, name)(injectable)
return provided return provided

View File

@ -2,8 +2,6 @@
`Objects` setup script. `Objects` setup script.
""" """
import os
import sys
from setuptools import setup from setuptools import setup
@ -26,16 +24,9 @@ with open('requirements.txt') as version:
with open('VERSION') as version: with open('VERSION') as version:
version = version.read().strip() 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', name='Objects',
version=version, version=version,
description='Python catalogs of objects providers', description='Python catalogs of objects providers',
@ -78,4 +69,4 @@ setup(
'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Libraries :: Python Modules',
] ]
) )