mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-02-18 04:20:46 +03:00
Update examples and docs
This commit is contained in:
parent
bd5ea87ef7
commit
4cf3bdb1fb
273
README.rst
273
README.rst
|
@ -55,259 +55,66 @@ Installation
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
API client example:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
"""Pythonic way for Dependency Injection - API Client."""
|
"""Dependency Injector initial example."""
|
||||||
|
|
||||||
from dependency_injector import providers
|
|
||||||
|
|
||||||
from mock import Mock
|
|
||||||
|
|
||||||
|
|
||||||
class ApiClient(object):
|
|
||||||
"""Some API client."""
|
|
||||||
|
|
||||||
def __init__(self, host, api_key):
|
|
||||||
"""Initializer."""
|
|
||||||
self.host = host
|
|
||||||
self.api_key = api_key
|
|
||||||
|
|
||||||
def call(self, operation, data):
|
|
||||||
"""Make some network operations."""
|
|
||||||
print 'API call [{0}:{1}], method - {2}, data - {3}'.format(
|
|
||||||
self.host, self.api_key, operation, repr(data))
|
|
||||||
|
|
||||||
|
|
||||||
class User(object):
|
|
||||||
"""User model."""
|
|
||||||
|
|
||||||
def __init__(self, id, api_client):
|
|
||||||
"""Initializer."""
|
|
||||||
self.id = id
|
|
||||||
self.api_client = api_client
|
|
||||||
|
|
||||||
def register(self):
|
|
||||||
"""Register user."""
|
|
||||||
self.api_client.call('register', {'id': self.id})
|
|
||||||
|
|
||||||
|
|
||||||
# Creating ApiClient and User providers:
|
|
||||||
api_client = providers.Singleton(ApiClient,
|
|
||||||
host='production.com',
|
|
||||||
api_key='PROD_API_KEY')
|
|
||||||
user_factory = providers.Factory(User,
|
|
||||||
api_client=api_client)
|
|
||||||
|
|
||||||
# Creating several users and register them:
|
|
||||||
user1 = user_factory(1)
|
|
||||||
user1.register()
|
|
||||||
# API call [production.com:PROD_API_KEY], method - register, data - {'id': 1}
|
|
||||||
|
|
||||||
user2 = user_factory(2)
|
|
||||||
user2.register()
|
|
||||||
# API call [production.com:PROD_API_KEY], method - register, data - {'id': 2}
|
|
||||||
|
|
||||||
# Mock ApiClient for testing:
|
|
||||||
with api_client.override(Mock(ApiClient)) as api_client_mock:
|
|
||||||
user = user_factory('test')
|
|
||||||
user.register()
|
|
||||||
api_client_mock().call.assert_called_with('register', {'id': 'test'})
|
|
||||||
|
|
||||||
|
|
||||||
# Overriding of ApiClient on dev environment:
|
|
||||||
api_client.override(providers.Singleton(ApiClient,
|
|
||||||
host='localhost',
|
|
||||||
api_key='DEV_API_KEY'))
|
|
||||||
|
|
||||||
user3 = user_factory(3)
|
|
||||||
user3.register()
|
|
||||||
# API call [localhost:DEV_API_KEY], method - register, data - {'id': 3}
|
|
||||||
|
|
||||||
Auth system example:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
"""Pythonic way for Dependency Injection - Auth System."""
|
|
||||||
|
|
||||||
from dependency_injector import providers
|
|
||||||
from dependency_injector import injections
|
|
||||||
|
|
||||||
|
|
||||||
@providers.DelegatedCallable
|
|
||||||
def get_user_info(user_id):
|
|
||||||
"""Return user info."""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
@providers.Factory
|
|
||||||
@injections.inject(get_user_info=get_user_info)
|
|
||||||
class AuthComponent(object):
|
|
||||||
"""Some authentication component."""
|
|
||||||
|
|
||||||
def __init__(self, get_user_info):
|
|
||||||
"""Initializer."""
|
|
||||||
self.get_user_info = get_user_info
|
|
||||||
|
|
||||||
def authenticate_user(self, token):
|
|
||||||
"""Authenticate user by token."""
|
|
||||||
user_info = self.get_user_info(user_id=token + '1')
|
|
||||||
return user_info
|
|
||||||
|
|
||||||
|
|
||||||
print AuthComponent
|
|
||||||
print get_user_info
|
|
||||||
|
|
||||||
|
|
||||||
@providers.override(get_user_info)
|
|
||||||
@providers.DelegatedCallable
|
|
||||||
def get_user_info(user_id):
|
|
||||||
"""Return user info."""
|
|
||||||
return {'user_id': user_id}
|
|
||||||
|
|
||||||
|
|
||||||
print AuthComponent().authenticate_user(token='abc')
|
|
||||||
# {'user_id': 'abc1'}
|
|
||||||
|
|
||||||
Service providers catalog example:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
"""Pythonic way for Dependency Injection - Service Providers Catalog."""
|
|
||||||
|
|
||||||
|
import sys
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
import boto.s3.connection
|
||||||
|
|
||||||
|
import services
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
from dependency_injector import catalogs
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
from dependency_injector import injections
|
from dependency_injector import injections
|
||||||
|
|
||||||
|
|
||||||
class UsersService(object):
|
class Platform(catalogs.DeclarativeCatalog):
|
||||||
"""Users service, that has dependency on database."""
|
"""Catalog of platform service providers."""
|
||||||
|
|
||||||
def __init__(self, db):
|
|
||||||
"""Initializer."""
|
|
||||||
self.db = db
|
|
||||||
|
|
||||||
|
|
||||||
class AuthService(object):
|
|
||||||
"""Auth service, that has dependencies on users service and database."""
|
|
||||||
|
|
||||||
def __init__(self, db, users_service):
|
|
||||||
"""Initializer."""
|
|
||||||
self.db = db
|
|
||||||
self.users_service = users_service
|
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
|
||||||
"""Catalog of service providers."""
|
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||||
|
|
||||||
users = providers.Factory(UsersService,
|
s3 = providers.Singleton(boto.s3.connection.S3Connection,
|
||||||
db=database)
|
aws_access_key_id='KEY',
|
||||||
|
aws_secret_access_key='SECRET')
|
||||||
auth = providers.Factory(AuthService,
|
|
||||||
db=database,
|
|
||||||
users_service=users)
|
|
||||||
|
|
||||||
|
|
||||||
# Retrieving catalog providers:
|
|
||||||
users_service = Services.users()
|
|
||||||
auth_service = Services.auth()
|
|
||||||
|
|
||||||
# Making some asserts:
|
|
||||||
assert users_service.db is auth_service.db is Services.database()
|
|
||||||
assert isinstance(auth_service.users_service, UsersService)
|
|
||||||
assert users_service is not Services.users()
|
|
||||||
assert auth_service is not Services.auth()
|
|
||||||
|
|
||||||
|
|
||||||
# Making some "inline" injections:
|
|
||||||
@injections.inject(users_service=Services.users)
|
|
||||||
@injections.inject(auth_service=Services.auth)
|
|
||||||
@injections.inject(database=Services.database)
|
|
||||||
def example(users_service, auth_service, database):
|
|
||||||
"""Example callback."""
|
|
||||||
assert users_service.db is auth_service.db
|
|
||||||
assert auth_service.db is database
|
|
||||||
assert database is Services.database()
|
|
||||||
|
|
||||||
|
|
||||||
# Making a call of decorated callback:
|
|
||||||
example()
|
|
||||||
|
|
||||||
Providing callbacks catalog example:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
"""Pythonic way for Dependency Injection - Providing Callbacks Catalog."""
|
|
||||||
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
|
||||||
from dependency_injector import providers
|
|
||||||
from dependency_injector import injections
|
|
||||||
|
|
||||||
|
|
||||||
class UsersService(object):
|
|
||||||
"""Users service, that has dependency on database."""
|
|
||||||
|
|
||||||
def __init__(self, db):
|
|
||||||
"""Initializer."""
|
|
||||||
self.db = db
|
|
||||||
|
|
||||||
|
|
||||||
class AuthService(object):
|
|
||||||
"""Auth service, that has dependencies on users service and database."""
|
|
||||||
|
|
||||||
def __init__(self, db, users_service):
|
|
||||||
"""Initializer."""
|
|
||||||
self.db = db
|
|
||||||
self.users_service = users_service
|
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
class Services(catalogs.DeclarativeCatalog):
|
||||||
"""Catalog of service providers."""
|
"""Catalog of business service providers."""
|
||||||
|
|
||||||
@providers.Singleton
|
users = providers.Factory(services.Users,
|
||||||
def database():
|
db=Platform.database)
|
||||||
"""Provide database connection.
|
|
||||||
|
|
||||||
:rtype: providers.Provider -> sqlite3.Connection
|
photos = providers.Factory(services.Photos,
|
||||||
"""
|
db=Platform.database,
|
||||||
return sqlite3.connect(':memory:')
|
s3=Platform.s3)
|
||||||
|
|
||||||
@providers.Factory
|
auth = providers.Factory(services.Auth,
|
||||||
@injections.inject(db=database)
|
db=Platform.database,
|
||||||
def users(**kwargs):
|
token_ttl=3600)
|
||||||
"""Provide users service.
|
|
||||||
|
|
||||||
:rtype: providers.Provider -> UsersService
|
|
||||||
"""
|
|
||||||
return UsersService(**kwargs)
|
|
||||||
|
|
||||||
@providers.Factory
|
|
||||||
@injections.inject(db=database)
|
|
||||||
@injections.inject(users_service=users)
|
|
||||||
def auth(**kwargs):
|
|
||||||
"""Provide users service.
|
|
||||||
|
|
||||||
:rtype: providers.Provider -> AuthService
|
|
||||||
"""
|
|
||||||
return AuthService(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
# Retrieving catalog providers:
|
@injections.inject(users_service=Services.users)
|
||||||
users_service = Services.users()
|
@injections.inject(auth_service=Services.auth)
|
||||||
auth_service = Services.auth()
|
def main(argv, users_service, auth_service):
|
||||||
|
"""Main function."""
|
||||||
|
login, password, photo_path = argv[1:]
|
||||||
|
|
||||||
# Making some asserts:
|
user = users_service.get_user(login)
|
||||||
assert users_service.db is auth_service.db is Services.database()
|
auth_service.authenticate(user, password)
|
||||||
assert isinstance(auth_service.users_service, UsersService)
|
|
||||||
assert users_service is not Services.users()
|
upload_photo(user, photo_path)
|
||||||
assert auth_service is not Services.auth()
|
|
||||||
|
|
||||||
|
@injections.inject(photos_service=Services.photos)
|
||||||
|
def upload_photo(user, photo_path, photos_service):
|
||||||
|
"""Upload photo."""
|
||||||
|
photos_service.upload_photo(user['id'], photo_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv)
|
||||||
|
|
||||||
You can get more *Dependency Injector* examples in ``/examples`` directory on
|
You can get more *Dependency Injector* examples in ``/examples`` directory on
|
||||||
GitHub:
|
GitHub:
|
||||||
|
@ -334,8 +141,8 @@ Your feedback is quite important!
|
||||||
|
|
||||||
|
|
||||||
.. _PyPi: https://pypi.python.org/pypi/dependency_injector
|
.. _PyPi: https://pypi.python.org/pypi/dependency_injector
|
||||||
.. _User's guide: http://dependency_injector.readthedocs.org/en/stable/
|
.. _User's guide: http://dependency-injector.ets-labs.org/en/stable/
|
||||||
.. _API docs: http://dependency-injector.readthedocs.org/en/stable/api/
|
.. _API docs: http://dependency-injector.ets-labs.org/en/stable/api/
|
||||||
.. _SLOC: http://en.wikipedia.org/wiki/Source_lines_of_code
|
.. _SLOC: http://en.wikipedia.org/wiki/Source_lines_of_code
|
||||||
.. _SOLID: http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29
|
.. _SOLID: http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29
|
||||||
.. _IoC: http://en.wikipedia.org/wiki/Inversion_of_control
|
.. _IoC: http://en.wikipedia.org/wiki/Inversion_of_control
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
||||||
|
:description: Current section of documentation is designed to provide
|
||||||
|
several example mini applications that are built on the top
|
||||||
|
of inversion of control principle and powered by
|
||||||
|
"Dependency Injector" framework.
|
||||||
|
|
||||||
|
Current section of documentation is designed to provide several example mini
|
||||||
|
applications that are built on the top of inversion of control principle and
|
||||||
|
powered by *Dependency Injector* framework.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
movie_lister
|
|
@ -0,0 +1,104 @@
|
||||||
|
Movie lister naive example
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:description: Dependency Injector is a Python dependency injection
|
||||||
|
framework. It was designed to be unified, developer's
|
||||||
|
friendly tool for managing any kind of Python objects and
|
||||||
|
their dependencies in formal, pretty way.
|
||||||
|
|
||||||
|
This naive example was taken from Martin Fowler's article about dependency
|
||||||
|
injection and inversion of control: http://www.martinfowler.com/articles/injection.html
|
||||||
|
|
||||||
|
Like Martin says:
|
||||||
|
|
||||||
|
.. pull-quote::
|
||||||
|
|
||||||
|
*Like all of my examples it's one of those super-simple examples;
|
||||||
|
small enough to be unreal, but hopefully enough for you to visualize
|
||||||
|
what's going on without falling into the bog of a real example.*
|
||||||
|
|
||||||
|
While original Martin's MovieLister example was a bit modified here, it
|
||||||
|
makes sense to provide some description. So, the idea of this example is to
|
||||||
|
create ``movies`` library that can be configurable to work with different
|
||||||
|
movie databases (csv, sqlite) and provide 2 main features:
|
||||||
|
|
||||||
|
1. List all movies that were directed by certain person.
|
||||||
|
2. List all movies that were released in certain year.
|
||||||
|
|
||||||
|
Also this example contains 3 mini applications that are based on ``movies``
|
||||||
|
library :
|
||||||
|
|
||||||
|
1. ``app_csv.py`` - list movies by certain criteria from csv file database.
|
||||||
|
2. ``app_db.py`` - list movies by certain criteria from sqlite database.
|
||||||
|
3. ``app_db_csv.py`` - list movies by certain criteria from csv file and
|
||||||
|
sqlite databases.
|
||||||
|
|
||||||
|
Instructions for running:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python create_db.py
|
||||||
|
|
||||||
|
python app_csv.py
|
||||||
|
python app_db.py
|
||||||
|
python app_db_csv.py
|
||||||
|
|
||||||
|
|
||||||
|
Full code of example could be found on GitHub_.
|
||||||
|
|
||||||
|
Movies library
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Classes diagram:
|
||||||
|
|
||||||
|
.. image:: /images/miniapps/movie_lister/classes.png
|
||||||
|
:width: 100%
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
|
||||||
|
Movies library structure:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
/movies
|
||||||
|
/__init__.py
|
||||||
|
/finders.py
|
||||||
|
/listers.py
|
||||||
|
/models.py
|
||||||
|
|
||||||
|
|
||||||
|
Listing of ``movies/__init__.py``:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/movie_lister/movies/__init__.py
|
||||||
|
:language: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
Csv application
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Listing of ``app_csv.py``:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/movie_lister/app_csv.py
|
||||||
|
:language: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
Database application
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Listing of ``app_db.py``:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/movie_lister/app_db.py
|
||||||
|
:language: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
Csv and database application
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Listing of ``app_db_csv.py``:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/movie_lister/app_db_csv.py
|
||||||
|
:language: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
.. _GitHub: https://github.com/ets-labs/dependency_injector/tree/master/examples/miniapps/movie_lister
|
BIN
docs/images/miniapps/movie_lister/classes.png
Normal file
BIN
docs/images/miniapps/movie_lister/classes.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
|
@ -2,8 +2,7 @@ Dependency Injector --- Python dependency injection framework
|
||||||
=============================================================
|
=============================================================
|
||||||
|
|
||||||
.. meta::
|
.. meta::
|
||||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
:google-site-verification: 6it89zX0_wccKEhAqbAiYQooS95f0BA8YfesHk6bsNA
|
||||||
:google-site-verification: mPdgVBidFHVWRNh0lhxj7q9zi-CpwIU970jINTBKLYQ
|
|
||||||
:description: Dependency Injector is a Python dependency injection
|
:description: Dependency Injector is a Python dependency injection
|
||||||
framework. It was designed to be unified, developer's
|
framework. It was designed to be unified, developer's
|
||||||
friendly tool for managing any kind of Python objects and
|
friendly tool for managing any kind of Python objects and
|
||||||
|
@ -63,6 +62,7 @@ Contents
|
||||||
providers/index
|
providers/index
|
||||||
catalogs/index
|
catalogs/index
|
||||||
advanced_usage/index
|
advanced_usage/index
|
||||||
|
examples/index
|
||||||
api/index
|
api/index
|
||||||
main/feedback
|
main/feedback
|
||||||
main/changelog
|
main/changelog
|
||||||
|
|
|
@ -2,7 +2,6 @@ Dependency injection and inversion of control in Python
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
.. meta::
|
.. meta::
|
||||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
|
||||||
:description: This article describes benefits of dependency injection and
|
:description: This article describes benefits of dependency injection and
|
||||||
inversion of control for Python applications. Also it
|
inversion of control for Python applications. Also it
|
||||||
contains some Python examples that show how dependency
|
contains some Python examples that show how dependency
|
||||||
|
|
|
@ -2,7 +2,6 @@ Introduction
|
||||||
============
|
============
|
||||||
|
|
||||||
.. meta::
|
.. meta::
|
||||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
|
||||||
:description: Current section of documentation is designed to give some
|
:description: Current section of documentation is designed to give some
|
||||||
overview about dependency injection pattern, inversion of
|
overview about dependency injection pattern, inversion of
|
||||||
control principle and "Dependency Injector" framework.
|
control principle and "Dependency Injector" framework.
|
||||||
|
|
|
@ -2,7 +2,6 @@ Key features of Dependency Injector
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
.. meta::
|
.. meta::
|
||||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
|
||||||
:description: This article describes key features of "Dependency Injector"
|
:description: This article describes key features of "Dependency Injector"
|
||||||
framework. It also provides some cases and recommendations
|
framework. It also provides some cases and recommendations
|
||||||
about usage of "Dependency Injector" framework.
|
about usage of "Dependency Injector" framework.
|
||||||
|
|
|
@ -2,7 +2,6 @@ Structure of Dependency Injector
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
.. meta::
|
.. meta::
|
||||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
|
||||||
:description: This article describes "Dependency Injector" framework
|
:description: This article describes "Dependency Injector" framework
|
||||||
components and their interaction between each other.
|
components and their interaction between each other.
|
||||||
Catalogs, providers and injections are the former
|
Catalogs, providers and injections are the former
|
||||||
|
|
|
@ -2,7 +2,6 @@ What is dependency injection and inversion of control?
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
|
||||||
.. meta::
|
.. meta::
|
||||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
|
||||||
:description: This article provides definition of dependency injection,
|
:description: This article provides definition of dependency injection,
|
||||||
inversion of control and dependency inversion. It contains
|
inversion of control and dependency inversion. It contains
|
||||||
example code in Python that is refactored to be following
|
example code in Python that is refactored to be following
|
||||||
|
|
|
@ -11,6 +11,8 @@ Development version
|
||||||
-------------------
|
-------------------
|
||||||
- Add ``@copy`` decorator for copying declarative catalog providers.
|
- Add ``@copy`` decorator for copying declarative catalog providers.
|
||||||
- Add line numbers for all code samples in documentation.
|
- Add line numbers for all code samples in documentation.
|
||||||
|
- Move project documentation into organisation's domain
|
||||||
|
(dependency-injector.ets-labs.org).
|
||||||
|
|
||||||
1.15.2
|
1.15.2
|
||||||
------
|
------
|
||||||
|
|
|
@ -24,7 +24,6 @@ class Catalog(catalogs.DeclarativeCatalog):
|
||||||
fee=config.FEE,
|
fee=config.FEE,
|
||||||
price=config.PRICE,
|
price=config.PRICE,
|
||||||
timezone=config.GLOBAL.TIMEZONE)
|
timezone=config.GLOBAL.TIMEZONE)
|
||||||
""":type: providers.Provider -> ObjectA"""
|
|
||||||
|
|
||||||
|
|
||||||
# Setting config value and making some tests.
|
# Setting config value and making some tests.
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
"""Pythonic way for Dependency Injection - API Client."""
|
|
||||||
|
|
||||||
from dependency_injector import providers
|
|
||||||
|
|
||||||
from mock import Mock
|
|
||||||
|
|
||||||
|
|
||||||
class ApiClient(object):
|
|
||||||
"""Some API client."""
|
|
||||||
|
|
||||||
def __init__(self, host, api_key):
|
|
||||||
"""Initializer."""
|
|
||||||
self.host = host
|
|
||||||
self.api_key = api_key
|
|
||||||
|
|
||||||
def call(self, operation, data):
|
|
||||||
"""Make some network operations."""
|
|
||||||
print 'API call [{0}:{1}], method - {2}, data - {3}'.format(
|
|
||||||
self.host, self.api_key, operation, repr(data))
|
|
||||||
|
|
||||||
|
|
||||||
class User(object):
|
|
||||||
"""User model."""
|
|
||||||
|
|
||||||
def __init__(self, id, api_client):
|
|
||||||
"""Initializer."""
|
|
||||||
self.id = id
|
|
||||||
self.api_client = api_client
|
|
||||||
|
|
||||||
def register(self):
|
|
||||||
"""Register user."""
|
|
||||||
self.api_client.call('register', {'id': self.id})
|
|
||||||
|
|
||||||
|
|
||||||
# Creating ApiClient and User providers:
|
|
||||||
api_client = providers.Singleton(ApiClient,
|
|
||||||
host='production.com',
|
|
||||||
api_key='PROD_API_KEY')
|
|
||||||
user_factory = providers.Factory(User,
|
|
||||||
api_client=api_client)
|
|
||||||
|
|
||||||
# Creating several users and register them:
|
|
||||||
user1 = user_factory(1)
|
|
||||||
user1.register()
|
|
||||||
# API call [production.com:PROD_API_KEY], method - register, data - {'id': 1}
|
|
||||||
|
|
||||||
user2 = user_factory(2)
|
|
||||||
user2.register()
|
|
||||||
# API call [production.com:PROD_API_KEY], method - register, data - {'id': 2}
|
|
||||||
|
|
||||||
# Mock ApiClient for testing:
|
|
||||||
with api_client.override(Mock(ApiClient)) as api_client_mock:
|
|
||||||
user = user_factory('test')
|
|
||||||
user.register()
|
|
||||||
api_client_mock().call.assert_called_with('register', {'id': 'test'})
|
|
||||||
|
|
||||||
|
|
||||||
# Overriding of ApiClient on dev environment:
|
|
||||||
api_client.override(providers.Singleton(ApiClient,
|
|
||||||
host='localhost',
|
|
||||||
api_key='DEV_API_KEY'))
|
|
||||||
|
|
||||||
user3 = user_factory(3)
|
|
||||||
user3.register()
|
|
||||||
# API call [localhost:DEV_API_KEY], method - register, data - {'id': 3}
|
|
|
@ -1,63 +0,0 @@
|
||||||
"""Pythonic way for Dependency Injection - Service Providers Catalog."""
|
|
||||||
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
from dependency_injector import catalogs
|
|
||||||
from dependency_injector import providers
|
|
||||||
from dependency_injector import injections
|
|
||||||
|
|
||||||
|
|
||||||
class UsersService(object):
|
|
||||||
"""Users service, that has dependency on database."""
|
|
||||||
|
|
||||||
def __init__(self, db):
|
|
||||||
"""Initializer."""
|
|
||||||
self.db = db
|
|
||||||
|
|
||||||
|
|
||||||
class AuthService(object):
|
|
||||||
"""Auth service, that has dependencies on users service and database."""
|
|
||||||
|
|
||||||
def __init__(self, db, users_service):
|
|
||||||
"""Initializer."""
|
|
||||||
self.db = db
|
|
||||||
self.users_service = users_service
|
|
||||||
|
|
||||||
|
|
||||||
class Services(catalogs.DeclarativeCatalog):
|
|
||||||
"""Catalog of service providers."""
|
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
|
||||||
|
|
||||||
users = providers.Factory(UsersService,
|
|
||||||
db=database)
|
|
||||||
|
|
||||||
auth = providers.Factory(AuthService,
|
|
||||||
db=database,
|
|
||||||
users_service=users)
|
|
||||||
|
|
||||||
|
|
||||||
# Retrieving catalog providers:
|
|
||||||
users_service = Services.users()
|
|
||||||
auth_service = Services.auth()
|
|
||||||
|
|
||||||
# Making some asserts:
|
|
||||||
assert users_service.db is auth_service.db is Services.database()
|
|
||||||
assert isinstance(auth_service.users_service, UsersService)
|
|
||||||
assert users_service is not Services.users()
|
|
||||||
assert auth_service is not Services.auth()
|
|
||||||
|
|
||||||
|
|
||||||
# Making some "inline" injections:
|
|
||||||
@injections.inject(users_service=Services.users)
|
|
||||||
@injections.inject(auth_service=Services.auth)
|
|
||||||
@injections.inject(database=Services.database)
|
|
||||||
def example(users_service, auth_service, database):
|
|
||||||
"""Example callback."""
|
|
||||||
assert users_service.db is auth_service.db
|
|
||||||
assert auth_service.db is database
|
|
||||||
assert database is Services.database()
|
|
||||||
|
|
||||||
|
|
||||||
# Making a call of decorated callback:
|
|
||||||
example()
|
|
|
@ -13,13 +13,10 @@ class Services(catalogs.DeclarativeCatalog):
|
||||||
"""Example catalog of service providers."""
|
"""Example catalog of service providers."""
|
||||||
|
|
||||||
users = providers.Factory(services.Users)
|
users = providers.Factory(services.Users)
|
||||||
""":type: providers.Provider -> services.Users"""
|
|
||||||
|
|
||||||
auth = providers.Factory(services.Auth)
|
auth = providers.Factory(services.Auth)
|
||||||
""":type: providers.Provider -> services.Auth"""
|
|
||||||
|
|
||||||
photos = providers.Factory(services.Photos)
|
photos = providers.Factory(services.Photos)
|
||||||
""":type: providers.Provider -> services.Photos"""
|
|
||||||
|
|
||||||
|
|
||||||
# Declaring views catalog:
|
# Declaring views catalog:
|
||||||
|
@ -29,12 +26,10 @@ class Views(catalogs.DeclarativeCatalog):
|
||||||
auth = providers.Factory(views.Auth,
|
auth = providers.Factory(views.Auth,
|
||||||
services=Services.Bundle(Services.users,
|
services=Services.Bundle(Services.users,
|
||||||
Services.auth))
|
Services.auth))
|
||||||
""":type: providers.Provider -> views.Auth"""
|
|
||||||
|
|
||||||
photos = providers.Factory(views.Photos,
|
photos = providers.Factory(views.Photos,
|
||||||
services=Services.Bundle(Services.users,
|
services=Services.Bundle(Services.users,
|
||||||
Services.photos))
|
Services.photos))
|
||||||
""":type: providers.Provider -> views.Photos"""
|
|
||||||
|
|
||||||
|
|
||||||
# Creating example views:
|
# Creating example views:
|
||||||
|
|
|
@ -9,10 +9,8 @@ class Catalog(catalogs.DeclarativeCatalog):
|
||||||
"""Providers catalog."""
|
"""Providers catalog."""
|
||||||
|
|
||||||
factory1 = providers.Factory(object)
|
factory1 = providers.Factory(object)
|
||||||
""":type: providers.Provider -> object"""
|
|
||||||
|
|
||||||
factory2 = providers.Factory(object)
|
factory2 = providers.Factory(object)
|
||||||
""":type: providers.Provider -> object"""
|
|
||||||
|
|
||||||
# Creating some objects:
|
# Creating some objects:
|
||||||
object1 = Catalog.factory1()
|
object1 = Catalog.factory1()
|
||||||
|
|
|
@ -8,14 +8,12 @@ class CatalogA(catalogs.DeclarativeCatalog):
|
||||||
"""Example catalog A."""
|
"""Example catalog A."""
|
||||||
|
|
||||||
provider1 = providers.Factory(object)
|
provider1 = providers.Factory(object)
|
||||||
""":type: providers.Provider -> object"""
|
|
||||||
|
|
||||||
|
|
||||||
class CatalogB(CatalogA):
|
class CatalogB(CatalogA):
|
||||||
"""Example catalog B."""
|
"""Example catalog B."""
|
||||||
|
|
||||||
provider2 = providers.Singleton(object)
|
provider2 = providers.Singleton(object)
|
||||||
""":type: providers.Provider -> object"""
|
|
||||||
|
|
||||||
|
|
||||||
# Making some asserts for `providers` attribute:
|
# Making some asserts for `providers` attribute:
|
||||||
|
|
|
@ -27,16 +27,13 @@ class Services(catalogs.DeclarativeCatalog):
|
||||||
"""Catalog of service providers."""
|
"""Catalog of service providers."""
|
||||||
|
|
||||||
database = providers.Singleton(sqlite3.connect, ':memory:')
|
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||||
""":type: providers.Provider -> sqlite3.Connection"""
|
|
||||||
|
|
||||||
users = providers.Factory(UsersService,
|
users = providers.Factory(UsersService,
|
||||||
db=database)
|
db=database)
|
||||||
""":type: providers.Provider -> UsersService"""
|
|
||||||
|
|
||||||
auth = providers.Factory(AuthService,
|
auth = providers.Factory(AuthService,
|
||||||
db=database,
|
db=database,
|
||||||
users_service=users)
|
users_service=users)
|
||||||
""":type: providers.Provider -> AuthService"""
|
|
||||||
|
|
||||||
|
|
||||||
# Retrieving service providers from catalog:
|
# Retrieving service providers from catalog:
|
||||||
|
|
|
@ -31,13 +31,11 @@ class Services(services.Catalog):
|
||||||
users = services.Provider(UsersService,
|
users = services.Provider(UsersService,
|
||||||
config={'option1': '111',
|
config={'option1': '111',
|
||||||
'option2': '222'})
|
'option2': '222'})
|
||||||
""":type: services.Provider -> UsersService"""
|
|
||||||
|
|
||||||
auth = services.Provider(AuthService,
|
auth = services.Provider(AuthService,
|
||||||
config={'option3': '333',
|
config={'option3': '333',
|
||||||
'option4': '444'},
|
'option4': '444'},
|
||||||
users_service=users)
|
users_service=users)
|
||||||
""":type: services.Provider -> AuthService"""
|
|
||||||
|
|
||||||
|
|
||||||
# Creating users & auth services:
|
# Creating users & auth services:
|
||||||
|
|
|
@ -18,18 +18,15 @@ class Catalog(catalogs.DeclarativeCatalog):
|
||||||
object1_factory = providers.Factory(Object1,
|
object1_factory = providers.Factory(Object1,
|
||||||
arg1=1,
|
arg1=1,
|
||||||
arg2=2)
|
arg2=2)
|
||||||
""":type: providers.Provider -> Object1"""
|
|
||||||
|
|
||||||
object2_factory = providers.Factory(Object2,
|
object2_factory = providers.Factory(Object2,
|
||||||
object1=object1_factory)
|
object1=object1_factory)
|
||||||
""":type: providers.Provider -> Object2"""
|
|
||||||
|
|
||||||
|
|
||||||
class AnotherCatalog(catalogs.DeclarativeCatalog):
|
class AnotherCatalog(catalogs.DeclarativeCatalog):
|
||||||
"""Overriding catalog."""
|
"""Overriding catalog."""
|
||||||
|
|
||||||
object2_factory = providers.Factory(ExtendedObject2)
|
object2_factory = providers.Factory(ExtendedObject2)
|
||||||
""":type: providers.Provider -> ExtendedObject2"""
|
|
||||||
|
|
||||||
|
|
||||||
# Overriding `Catalog` with `AnotherCatalog`:
|
# Overriding `Catalog` with `AnotherCatalog`:
|
||||||
|
|
|
@ -18,11 +18,9 @@ class Catalog(catalogs.DeclarativeCatalog):
|
||||||
object1_factory = providers.Factory(Object1,
|
object1_factory = providers.Factory(Object1,
|
||||||
arg1=1,
|
arg1=1,
|
||||||
arg2=2)
|
arg2=2)
|
||||||
""":type: providers.Provider -> Object1"""
|
|
||||||
|
|
||||||
object2_factory = providers.Factory(Object2,
|
object2_factory = providers.Factory(Object2,
|
||||||
object1=object1_factory)
|
object1=object1_factory)
|
||||||
""":type: providers.Provider -> Object2"""
|
|
||||||
|
|
||||||
|
|
||||||
# Overriding `Catalog` with some `DynamicCatalog` instance:
|
# Overriding `Catalog` with some `DynamicCatalog` instance:
|
||||||
|
|
|
@ -17,11 +17,9 @@ class Catalog(catalogs.DeclarativeCatalog):
|
||||||
object1_factory = providers.Factory(Object1,
|
object1_factory = providers.Factory(Object1,
|
||||||
arg1=1,
|
arg1=1,
|
||||||
arg2=2)
|
arg2=2)
|
||||||
""":type: providers.Provider -> Object1"""
|
|
||||||
|
|
||||||
object2_factory = providers.Factory(Object2,
|
object2_factory = providers.Factory(Object2,
|
||||||
object1=object1_factory)
|
object1=object1_factory)
|
||||||
""":type: providers.Provider -> Object2"""
|
|
||||||
|
|
||||||
|
|
||||||
# Overriding `Catalog` with `AnotherCatalog`:
|
# Overriding `Catalog` with `AnotherCatalog`:
|
||||||
|
@ -30,7 +28,6 @@ class AnotherCatalog(catalogs.DeclarativeCatalog):
|
||||||
"""Overriding catalog."""
|
"""Overriding catalog."""
|
||||||
|
|
||||||
object2_factory = providers.Factory(ExtendedObject2)
|
object2_factory = providers.Factory(ExtendedObject2)
|
||||||
""":type: providers.Provider -> ExtendedObject2"""
|
|
||||||
|
|
||||||
|
|
||||||
# Creating some objects using overridden catalog:
|
# Creating some objects using overridden catalog:
|
||||||
|
|
58
examples/initial.py
Normal file
58
examples/initial.py
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
"""Dependency Injector initial example."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import sqlite3
|
||||||
|
import boto.s3.connection
|
||||||
|
|
||||||
|
import services
|
||||||
|
|
||||||
|
from dependency_injector import catalogs
|
||||||
|
from dependency_injector import providers
|
||||||
|
from dependency_injector import injections
|
||||||
|
|
||||||
|
|
||||||
|
class Platform(catalogs.DeclarativeCatalog):
|
||||||
|
"""Catalog of platform service providers."""
|
||||||
|
|
||||||
|
database = providers.Singleton(sqlite3.connect, ':memory:')
|
||||||
|
|
||||||
|
s3 = providers.Singleton(boto.s3.connection.S3Connection,
|
||||||
|
aws_access_key_id='KEY',
|
||||||
|
aws_secret_access_key='SECRET')
|
||||||
|
|
||||||
|
|
||||||
|
class Services(catalogs.DeclarativeCatalog):
|
||||||
|
"""Catalog of business service providers."""
|
||||||
|
|
||||||
|
users = providers.Factory(services.Users,
|
||||||
|
db=Platform.database)
|
||||||
|
|
||||||
|
photos = providers.Factory(services.Photos,
|
||||||
|
db=Platform.database,
|
||||||
|
s3=Platform.s3)
|
||||||
|
|
||||||
|
auth = providers.Factory(services.Auth,
|
||||||
|
db=Platform.database,
|
||||||
|
token_ttl=3600)
|
||||||
|
|
||||||
|
|
||||||
|
@injections.inject(users_service=Services.users)
|
||||||
|
@injections.inject(auth_service=Services.auth)
|
||||||
|
def main(argv, users_service, auth_service):
|
||||||
|
"""Main function."""
|
||||||
|
login, password, photo_path = argv[1:]
|
||||||
|
|
||||||
|
user = users_service.get_user(login)
|
||||||
|
auth_service.authenticate(user, password)
|
||||||
|
|
||||||
|
upload_photo(user, photo_path)
|
||||||
|
|
||||||
|
|
||||||
|
@injections.inject(photos_service=Services.photos)
|
||||||
|
def upload_photo(user, photo_path, photos_service):
|
||||||
|
"""Upload photo."""
|
||||||
|
photos_service.upload_photo(user['id'], photo_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv)
|
15
examples/miniapps/api_client/api.py
Normal file
15
examples/miniapps/api_client/api.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
"""asd."""
|
||||||
|
|
||||||
|
|
||||||
|
class ApiClient(object):
|
||||||
|
"""Some API client."""
|
||||||
|
|
||||||
|
def __init__(self, host, api_key):
|
||||||
|
"""Initializer."""
|
||||||
|
self.host = host
|
||||||
|
self.api_key = api_key
|
||||||
|
|
||||||
|
def call(self, operation, data):
|
||||||
|
"""Make some network operations."""
|
||||||
|
print 'API call [{0}:{1}], method - {2}, data - {3}'.format(
|
||||||
|
self.host, self.api_key, operation, repr(data))
|
36
examples/miniapps/api_client/main.py
Normal file
36
examples/miniapps/api_client/main.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
"""asd."""
|
||||||
|
|
||||||
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
import api
|
||||||
|
import models
|
||||||
|
|
||||||
|
|
||||||
|
# Creating ApiClient and User providers:
|
||||||
|
api_client = providers.Singleton(api.ApiClient,
|
||||||
|
host='production.com',
|
||||||
|
api_key='PROD_API_KEY')
|
||||||
|
user_factory = providers.Factory(models.User,
|
||||||
|
api_client=api_client)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Creating several users and register them:
|
||||||
|
user1 = user_factory(1)
|
||||||
|
user1.register()
|
||||||
|
# API call [production.com:PROD_API_KEY], method - register, data -
|
||||||
|
# {'id': 1}
|
||||||
|
|
||||||
|
user2 = user_factory(2)
|
||||||
|
user2.register()
|
||||||
|
# API call [production.com:PROD_API_KEY], method - register, data -
|
||||||
|
# {'id': 2}
|
||||||
|
|
||||||
|
# Overriding of ApiClient on dev environment:
|
||||||
|
api_client.override(providers.Singleton(api.ApiClient,
|
||||||
|
host='localhost',
|
||||||
|
api_key='DEV_API_KEY'))
|
||||||
|
|
||||||
|
user3 = user_factory(3)
|
||||||
|
user3.register()
|
||||||
|
# API call [localhost:DEV_API_KEY], method - register, data - {'id': 3}
|
14
examples/miniapps/api_client/models.py
Normal file
14
examples/miniapps/api_client/models.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
"""asd."""
|
||||||
|
|
||||||
|
|
||||||
|
class User(object):
|
||||||
|
"""User model."""
|
||||||
|
|
||||||
|
def __init__(self, id, api_client):
|
||||||
|
"""Initializer."""
|
||||||
|
self.id = id
|
||||||
|
self.api_client = api_client
|
||||||
|
|
||||||
|
def register(self):
|
||||||
|
"""Register user."""
|
||||||
|
self.api_client.call('register', {'id': self.id})
|
12
examples/miniapps/api_client/tests.py
Normal file
12
examples/miniapps/api_client/tests.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
"""asd."""
|
||||||
|
|
||||||
|
from mock import Mock
|
||||||
|
|
||||||
|
import main
|
||||||
|
import api
|
||||||
|
|
||||||
|
# Mock ApiClient for testing:
|
||||||
|
with main.api_client.override(Mock(api.ApiClient)) as api_client_mock:
|
||||||
|
user = main.user_factory('test')
|
||||||
|
user.register()
|
||||||
|
api_client_mock().call.assert_called_with('register', {'id': 'test'})
|
10
examples/miniapps/flask_services/app.py
Normal file
10
examples/miniapps/flask_services/app.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
"""Flask application."""
|
||||||
|
|
||||||
|
import flask
|
||||||
|
|
||||||
|
|
||||||
|
app = flask.Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run()
|
8
examples/miniapps/flask_services/services/__init__.py
Normal file
8
examples/miniapps/flask_services/services/__init__.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
"""Services package."""
|
||||||
|
|
||||||
|
from dependency_injector import catalogs
|
||||||
|
from dependency_injector import providers
|
||||||
|
|
||||||
|
|
||||||
|
class ServicesModule(catalogs.DeclarativeCatalog):
|
||||||
|
"""Service providers module."""
|
|
@ -5,6 +5,10 @@ module component providers - ``MoviesModule``. It is recommended to use movies
|
||||||
library functionality by fetching required instances from ``MoviesModule``
|
library functionality by fetching required instances from ``MoviesModule``
|
||||||
providers.
|
providers.
|
||||||
|
|
||||||
|
``MoviesModule.movie_finder`` is a factory that provides abstract component
|
||||||
|
``finders.MovieFinder``. This provider should be overridden by provider of
|
||||||
|
concrete finder implementation in terms of library configuration.
|
||||||
|
|
||||||
Each of ``MoviesModule`` providers could be overridden.
|
Each of ``MoviesModule`` providers could be overridden.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
40
examples/services.py
Normal file
40
examples/services.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
"""Services module."""
|
||||||
|
|
||||||
|
|
||||||
|
class Users(object):
|
||||||
|
"""Users service."""
|
||||||
|
|
||||||
|
def __init__(self, db):
|
||||||
|
"""Initializer."""
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
def get_user(self, login):
|
||||||
|
"""Return user's information by login."""
|
||||||
|
return {'id': 1,
|
||||||
|
'login': login,
|
||||||
|
'password_hash': 'secret_hash'}
|
||||||
|
|
||||||
|
|
||||||
|
class Auth(object):
|
||||||
|
"""Auth service."""
|
||||||
|
|
||||||
|
def __init__(self, db, token_ttl):
|
||||||
|
"""Initializer."""
|
||||||
|
self.db = db
|
||||||
|
self.token_ttl = token_ttl
|
||||||
|
|
||||||
|
def authenticate(self, user, password):
|
||||||
|
"""Authenticate user."""
|
||||||
|
assert user['password_hash'] == '_'.join((password, 'hash'))
|
||||||
|
|
||||||
|
|
||||||
|
class Photos(object):
|
||||||
|
"""Photos service."""
|
||||||
|
|
||||||
|
def __init__(self, db, s3):
|
||||||
|
"""Initializer."""
|
||||||
|
self.db = db
|
||||||
|
self.s3 = s3
|
||||||
|
|
||||||
|
def upload_photo(self, user_id, photo_path):
|
||||||
|
"""Upload user photo."""
|
Loading…
Reference in New Issue
Block a user