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,
Function, Value)
from .injections import InitArg, Attribute, Method
from .providers import (Provider, NewInstance, Singleton, Class, Object,
Function, Value)
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):
"""
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
def prepare_injections(injections):
"""
Prepares injections list to injection.
"""
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,56 +24,49 @@ 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(
name='Objects',
version=version,
description='Python catalogs of objects providers',
long_description=description,
author='Roman Mogilatov',
author_email='rmogilatov@gmail.com',
maintainer='Roman Mogilatov',
maintainer_email='rmogilatov@gmail.com',
url='https://github.com/rmk135/objects',
license='BSD New',
packages=['objects'],
zip_safe=True,
install_requires=requirements,
# keywords=['Dependency injection',
# 'Dependency injection container',
# 'DI',
# 'DIC',
# 'Dependency injector',
# 'Inversion of Control',
# 'Inversion of Control container',
# 'IoC',
# 'IoC container'],
classifiers=[
'Development Status :: 1 - Planning',
# 'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
# 'Programming Language :: Python :: 3',
# 'Programming Language :: Python :: 3.2',
# 'Programming Language :: Python :: 3.3',
# 'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: Implementation :: CPython',
# 'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
]
)
if __name__ == '__main__':
setup(
name='Objects',
version=version,
description='Python catalogs of objects providers',
long_description=description,
author='Roman Mogilatov',
author_email='rmogilatov@gmail.com',
maintainer='Roman Mogilatov',
maintainer_email='rmogilatov@gmail.com',
url='https://github.com/rmk135/objects',
license='BSD New',
packages=['objects'],
zip_safe=True,
install_requires=requirements,
# keywords=['Dependency injection',
# 'Dependency injection container',
# 'DI',
# 'DIC',
# 'Dependency injector',
# 'Inversion of Control',
# 'Inversion of Control container',
# 'IoC',
# 'IoC container'],
classifiers=[
'Development Status :: 1 - Planning',
# 'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
# 'Programming Language :: Python :: 3',
# 'Programming Language :: Python :: 3.2',
# 'Programming Language :: Python :: 3.3',
# 'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: Implementation :: CPython',
# 'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Software Development',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
]
)