Minor ExternalDependency provider updates, Adding ExternalDependency provider docs

This commit is contained in:
Roman Mogilatov 2015-06-18 16:34:26 +03:00
parent dbc368d5f6
commit e3ea517d72
7 changed files with 205 additions and 82 deletions

View File

@ -2,86 +2,6 @@ Providers
=========
External dependency providers
-----------------------------
``ExternalDependency`` provider can be useful for development of
self-sufficient libraries / modules / applications, that has required external
dependencies.
For example, you have created self-sufficient library / module / application,
that has dependency on *database connection*.
Second step you want to do is to make this software component to be easy
reusable by wide amount of developers and to be easily integrated into many
applications.
It may be good idea, to move all external dependencies (like
*database connection*) to the top level and make them to be injected on your
software component's initialization. It will make third party developers feel
themselves free about integration of yours component in their applications,
because of they would be able to find right place / right way for doing this
in their application's architectures.
On the other side,
you can be sure, that your external dependency will be satisfied by appropriate
instance.
Example:
.. code-block:: python
"""External dependency providers example."""
import sqlite3
from objects.providers import Singleton
from objects.providers import Factory
from objects.providers import ExternalDependency
from objects.injections import KwArg
from objects.injections import Attribute
class ObjectA(object):
"""ObjectA has dependency on database."""
def __init__(self, database):
"""Initializer.
Database dependency need to be injected via init arg."""
self.database = database
def get_one(self):
"""Select one from database and return it."""
return self.database.execute('SELECT 1').fetchone()[0]
# Database and `ObjectA` providers.
database = ExternalDependency(instance_of=sqlite3.Connection)
object_a_factory = Factory(ObjectA,
KwArg('database', database))
# Satisfaction of external dependency.
database.override(Singleton(sqlite3.Connection,
KwArg('database', ':memory:'),
KwArg('timeout', 30),
KwArg('detect_types', True),
KwArg('isolation_level', 'EXCLUSIVE'),
Attribute('row_factory', sqlite3.Row)))
# Creating several `ObjectA` instances.
object_a_1 = object_a_factory()
object_a_2 = object_a_factory()
# Making some asserts.
assert object_a_1 is not object_a_2
assert object_a_1.database is object_a_2.database is database()
Config providers
----------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,120 @@
External dependency providers
-----------------------------
``ExternalDependency`` provider can be useful for development of
self-sufficient libraries / modules / applications that has required external
dependencies.
For example, you have created self-sufficient library / module / application,
that has dependency on *database connection*.
Second step you want to do is to make this software component to be easy
reusable by wide amount of developers and to be easily integrated into many
applications.
It may be good idea, to move all external dependencies (like
*database connection*) to the top level and make them to be injected on your
software component's initialization. It will make third party developers feel
themselves free about integration of yours component in their applications,
because they would be able to find right place / right way for doing this
in their application's architectures.
At the same time, you can be sure, that your external dependency will be
satisfied by appropriate instance.
Example:
.. note::
Class ``UserService`` is a part of some library. ``UserService`` has
dependency on database connection, which can be satisfied with any
DBAPI 2.0 database connection. Being a self-sufficient library,
``UserService`` doesn't hardcode any kind of database management logic.
Instead of this, ``UserService`` provides external dependency, that has to
be satisfied out of library's scope.
.. image:: /images/external_dependency.png
.. code-block:: python
"""`ExternalDependency` providers example."""
from objects.providers import ExternalDependency
from objects.providers import Factory
from objects.providers import Singleton
from objects.injections import KwArg
from objects.injections import Attribute
# Importing SQLITE3 and contextlib.closing for working with cursors:
import sqlite3
from contextlib import closing
# Definition of example UserService:
class UserService(object):
"""Example class UserService.
UserService has dependency on DBAPI 2.0 database connection."""
def __init__(self, database):
"""Initializer.
Database dependency need to be injected via init arg."""
self.database = database
def init_database(self):
"""Initialize database, if it has not been initialized yet."""
with closing(self.database.cursor()) as cursor:
cursor.execute("""
CREATE TABLE IF NOT EXISTS users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(32)
)
""")
def create(self, name):
"""Create user with provided name and return his id."""
with closing(self.database.cursor()) as cursor:
cursor.execute('INSERT INTO users(name) VALUES (?)', (name,))
return cursor.lastrowid
def get_by_id(self, id):
"""Return user info by user id."""
with closing(self.database.cursor()) as cursor:
cursor.execute('SELECT id, name FROM users WHERE id=?', (id,))
return cursor.fetchone()
# Database and UserService providers:
database = ExternalDependency(instance_of=sqlite3.Connection)
users_service_factory = Factory(UserService,
KwArg('database', database))
# Out of library's scope.
#
# Setting database provider:
database.provided_by(Singleton(sqlite3.Connection,
KwArg('database', ':memory:'),
KwArg('timeout', 30),
KwArg('detect_types', True),
KwArg('isolation_level', 'EXCLUSIVE'),
Attribute('row_factory', sqlite3.Row)))
# Creating UserService instance:
users_service = users_service_factory()
# Initializing UserService database:
users_service.init_database()
# Creating test user and retrieving full information about him:
test_user_id = users_service.create(name='test_user')
test_user = users_service.get_by_id(test_user_id)
# Making some asserts:
assert test_user['id'] == 1
assert test_user['name'] == 'test_user'

View File

@ -12,3 +12,4 @@ All providers are callable. They describe how particular objects are provided.
singleton
static
callable
external_dependency

View File

@ -0,0 +1,78 @@
"""`ExternalDependency` providers example."""
from objects.providers import ExternalDependency
from objects.providers import Factory
from objects.providers import Singleton
from objects.injections import KwArg
from objects.injections import Attribute
# Importing SQLITE3 and contextlib.closing for working with cursors:
import sqlite3
from contextlib import closing
# Definition of example UserService:
class UserService(object):
"""Example class UserService.
UserService has dependency on DBAPI 2.0 database connection."""
def __init__(self, database):
"""Initializer.
Database dependency need to be injected via init arg."""
self.database = database
def init_database(self):
"""Initialize database, if it has not been initialized yet."""
with closing(self.database.cursor()) as cursor:
cursor.execute("""
CREATE TABLE IF NOT EXISTS users(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(32)
)
""")
def create(self, name):
"""Create user with provided name and return his id."""
with closing(self.database.cursor()) as cursor:
cursor.execute('INSERT INTO users(name) VALUES (?)', (name,))
return cursor.lastrowid
def get_by_id(self, id):
"""Return user info by user id."""
with closing(self.database.cursor()) as cursor:
cursor.execute('SELECT id, name FROM users WHERE id=?', (id,))
return cursor.fetchone()
# Database and UserService providers:
database = ExternalDependency(instance_of=sqlite3.Connection)
users_service_factory = Factory(UserService,
KwArg('database', database))
# Out of library's scope.
#
# Setting database provider:
database.provided_by(Singleton(sqlite3.Connection,
KwArg('database', ':memory:'),
KwArg('timeout', 30),
KwArg('detect_types', True),
KwArg('isolation_level', 'EXCLUSIVE'),
Attribute('row_factory', sqlite3.Row)))
# Creating UserService instance:
users_service = users_service_factory()
# Initializing UserService database:
users_service.init_database()
# Creating test user and retrieving full information about him:
test_user_id = users_service.create(name='test_user')
test_user = users_service.get_by_id(test_user_id)
# Making some asserts:
assert test_user['id'] == 1
assert test_user['name'] == 'test_user'

View File

@ -189,6 +189,10 @@ class ExternalDependency(Provider):
return instance
def provided_by(self, provider):
"""Set external dependency provider."""
return self.override(provider)
class _StaticProvider(Provider):

View File

@ -323,12 +323,12 @@ class ExternalDependencyTests(unittest.TestCase):
def test_call_overridden(self):
"""Test call of overridden external dependency."""
self.provider.override(Factory(list))
self.provider.provided_by(Factory(list))
self.assertIsInstance(self.provider(), list)
def test_call_overridden_but_not_instance_of(self):
"""Test call of overridden external dependency, but not instance of."""
self.provider.override(Factory(dict))
self.provider.provided_by(Factory(dict))
self.assertRaises(Error, self.provider)
def test_call_not_overridden(self):