Merge pull request #136 from ets-labs/deprecate_inject_decorator

Deprecate inject decorator
This commit is contained in:
Roman 2016-09-23 00:31:58 +03:00 committed by GitHub
commit 53f60d6fed
28 changed files with 310 additions and 193 deletions

View File

@ -62,6 +62,8 @@ system that consists from several business and platform services:
import sqlite3 import sqlite3
import boto.s3.connection import boto.s3.connection
import example.main
import example.services import example.services
import dependency_injector.containers as containers import dependency_injector.containers as containers
@ -92,29 +94,38 @@ system that consists from several business and platform services:
db=Platform.database, db=Platform.database,
s3=Platform.s3) s3=Platform.s3)
Next example demonstrates usage of ``@inject`` decorator with IoC containers
defined above: class Application(containers.DeclarativeContainer):
"""IoC container of application component providers."""
main = providers.Callable(example.main.main,
users_service=Services.users,
auth_service=Services.auth,
photos_service=Services.photos)
Next example demonstrates usage of IoC containers & providers defined above:
.. code-block:: python .. code-block:: python
"""Dependency Injector @inject decorator example.""" """Run example application."""
import application import containers
import dependency_injector.injections as injections
@injections.inject(users_service=application.Services.users)
@injections.inject(auth_service=application.Services.auth)
@injections.inject(photos_service=application.Services.photos)
def main(users_service, auth_service, photos_service):
"""Main function."""
user = users_service.get_user('user')
auth_service.authenticate(user, 'secret')
photos_service.upload_photo(user['id'], 'photo.jpg')
if __name__ == '__main__': if __name__ == '__main__':
main() containers.Application.main()
# Previous call is an equivalent of next operations:
#
# database = sqlite3.connect(':memory:')
# s3 = boto.s3.connection.S3Connection(aws_access_key_id='KEY',
# aws_secret_access_key='SECRET')
#
# example.main.main(users_service=example.services.Users(db=database),
# auth_service=example.services.Auth(db=database,
# token_ttl=3600),
# photos_service=example.services.Photos(db=database,
# s3=s3))
Alternative definition styles Alternative definition styles
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -136,21 +147,6 @@ IoC containers from previous example could look like these:
.add_kwargs(aws_access_key_id='KEY', .add_kwargs(aws_access_key_id='KEY',
aws_secret_access_key='SECRET') aws_secret_access_key='SECRET')
class Services(containers.DeclarativeContainer):
"""IoC container of business service providers."""
users = providers.Factory(example.services.Users) \
.add_kwargs(db=Platform.database)
auth = providers.Factory(example.services.Auth) \
.add_kwargs(db=Platform.database,
token_ttl=3600)
photos = providers.Factory(example.services.Photos) \
.add_kwargs(db=Platform.database,
s3=Platform.s3)
or like this these: or like this these:
.. code-block:: python .. code-block:: python
@ -165,21 +161,6 @@ or like this these:
s3.add_kwargs(aws_access_key_id='KEY', s3.add_kwargs(aws_access_key_id='KEY',
aws_secret_access_key='SECRET') aws_secret_access_key='SECRET')
class Services(containers.DeclarativeContainer):
"""IoC container of business service providers."""
users = providers.Factory(example.services.Users)
users.add_kwargs(db=Platform.database)
auth = providers.Factory(example.services.Auth)
auth.add_kwargs(db=Platform.database,
token_ttl=3600)
photos = providers.Factory(example.services.Photos)
photos.add_kwargs(db=Platform.database,
s3=Platform.s3)
You can get more *Dependency Injector* examples in ``/examples`` directory on You can get more *Dependency Injector* examples in ``/examples`` directory on
GitHub: GitHub:

View File

@ -1,5 +1,7 @@
"""Dependency injector injections module.""" """Dependency injector injections module."""
import warnings
import six import six
from dependency_injector.providers.base import ( from dependency_injector.providers.base import (
@ -13,6 +15,13 @@ from dependency_injector import errors
def inject(*args, **kwargs): def inject(*args, **kwargs):
"""Dependency injection decorator. """Dependency injection decorator.
.. warning::
:py:func:`inject` decorator has been deprecated since version 2.2.0.
Usage of :py:func:`inject` decorator can lead to bad design and could
be considered as anti-pattern.
:py:func:`inject` decorator can be used for making inline dependency :py:func:`inject` decorator can be used for making inline dependency
injections. It patches decorated callable in such way that dependency injections. It patches decorated callable in such way that dependency
injection will be done during every call of decorated callable. injection will be done during every call of decorated callable.
@ -41,6 +50,10 @@ def inject(*args, **kwargs):
def __init__(self, arg1, arg2): def __init__(self, arg1, arg2):
pass pass
.. deprecated:: 2.2.0
Usage of :py:func:`inject` decorator can lead to bad design and could
be considered as anti-pattern.
:param args: Tuple of context positional arguments. :param args: Tuple of context positional arguments.
:type args: tuple[object] :type args: tuple[object]
@ -50,6 +63,11 @@ def inject(*args, **kwargs):
:return: Class / callable decorator :return: Class / callable decorator
:rtype: (callable) -> (type | callable) :rtype: (callable) -> (type | callable)
""" """
warnings.warn(message='Call to a deprecated decorator - @{0}.{1}'
.format(inject.__module__, inject.__name__),
category=DeprecationWarning,
stacklevel=2)
arg_injections = _parse_positional_injections(args) arg_injections = _parse_positional_injections(args)
kwarg_injections = _parse_keyword_injections(kwargs) kwarg_injections = _parse_keyword_injections(kwargs)

View File

@ -9,6 +9,10 @@ Current section of documentation describes advanced usage of
.. currentmodule:: dependency_injector.injections .. currentmodule:: dependency_injector.injections
.. warning::
:py:func:`inject` decorator has been deprecated since version 2.2.0.
:py:func:`inject` decorator is a part of :py:func:`inject` decorator is a part of
:py:mod:`dependency_injector.injections` module. :py:mod:`dependency_injector.injections` module.

View File

@ -7,6 +7,5 @@ API Documentation
top_level top_level
providers providers
containers containers
injections
utils utils
errors errors

View File

@ -9,8 +9,8 @@ Examples
"Dependency Injector" framework. "Dependency Injector" framework.
Current section of documentation is designed to provide several example mini Current section of documentation is designed to provide several example mini
applications that are built on the top of inversion of control principle and applications that are built according to the inversion of control principle
powered by *Dependency Injector* framework. and powered by *Dependency Injector* framework.
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2

View File

@ -20,14 +20,14 @@ Like Martin says:
While original Martin's MovieLister example was a bit modified here, it 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 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 create ``movies`` library that can be configured to work with different
movie databases (csv, sqlite) and provide 2 main features: movie databases (csv, sqlite, etc...) and provide 2 main features:
1. List all movies that were directed by certain person. 1. List all movies that were directed by certain person.
2. List all movies that were released in certain year. 2. List all movies that were released in certain year.
Also this example contains 3 mini applications that are based on ``movies`` Also this example contains 3 mini applications that are based on ``movies``
library : library:
1. ``app_csv.py`` - list movies by certain criteria from csv file database. 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. 2. ``app_db.py`` - list movies by certain criteria from sqlite database.
@ -38,8 +38,6 @@ Instructions for running:
.. code-block:: bash .. code-block:: bash
python create_db.py
python app_csv.py python app_csv.py
python app_db.py python app_db.py
python app_db_csv.py python app_db_csv.py
@ -74,6 +72,30 @@ Listing of ``movies/__init__.py``:
:language: python :language: python
:linenos: :linenos:
Example application
~~~~~~~~~~~~~~~~~~~
Example application structure:
.. code-block:: bash
/example
/__init__.py
/db.py
/main.py
Listing of ``examples/main.py``:
.. literalinclude:: ../../examples/miniapps/movie_lister/example/main.py
:language: python
:linenos:
Listing of ``examples/db.py``:
.. literalinclude:: ../../examples/miniapps/movie_lister/example/db.py
:language: python
:linenos:
Csv application Csv application
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~

View File

@ -59,7 +59,6 @@ Contents
main/installation main/installation
providers/index providers/index
containers/index containers/index
advanced_usage/index
examples/index examples/index
api/index api/index
main/feedback main/feedback

View File

@ -9,7 +9,7 @@ follows `Semantic versioning`_
Development version Development version
------------------- -------------------
- No features. - Deprecate ``inject`` decorator.
2.1.1 2.1.1
----- -----

View File

@ -11,8 +11,6 @@ Instructions for running:
.. code-block:: bash .. code-block:: bash
python create_db.py
python app_csv.py python app_csv.py
python app_db.py python app_db.py
python app_db_csv.py python app_db_csv.py

View File

@ -9,42 +9,40 @@ This mini application uses ``movies`` library, that is configured to work with
csv file movies database. csv file movies database.
""" """
import dependency_injector.containers as containers
import dependency_injector.providers as providers
import dependency_injector.injections as injections
import movies import movies
import movies.finders import movies.finders
import example.db
import example.main
import settings import settings
import dependency_injector.containers as containers
import dependency_injector.providers as providers
@containers.override(movies.MoviesModule) @containers.override(movies.MoviesModule)
class MyMoviesModule(containers.DeclarativeContainer): class MyMoviesModule(containers.DeclarativeContainer):
"""IoC container for overriding movies module component providers.""" """IoC container for overriding movies module component providers."""
movie_finder = providers.Factory(movies.finders.CsvMovieFinder, movie_finder = providers.Factory(movies.finders.CsvMovieFinder,
csv_file=settings.MOVIES_CSV_PATH, csv_file_path=settings.MOVIES_CSV_PATH,
delimeter=',', delimiter=',',
**movies.MoviesModule.movie_finder.kwargs) **movies.MoviesModule.movie_finder.kwargs)
@injections.inject(movies.MoviesModule.movie_lister) class CsvApplication(containers.DeclarativeContainer):
def main(movie_lister): """IoC container of csv application component providers."""
"""Main function.
This program prints info about all movies that were directed by different main = providers.Callable(example.main.main,
persons and then prints all movies that were released in 2015. movie_lister=movies.MoviesModule.movie_lister)
:param movie_lister: Movie lister instance init_db = providers.Callable(example.db.init_csv,
:type movie_lister: movies.listers.MovieLister movies_data=settings.MOVIES_SAMPLE_DATA,
""" csv_file_path=settings.MOVIES_CSV_PATH,
print movie_lister.movies_directed_by('Francis Lawrence') delimiter=',')
print movie_lister.movies_directed_by('Patricia Riggen')
print movie_lister.movies_directed_by('JJ Abrams')
print movie_lister.movies_released_in(2015)
if __name__ == '__main__': if __name__ == '__main__':
main() CsvApplication.init_db()
CsvApplication.main()

View File

@ -11,18 +11,20 @@ sqlite movies database.
import sqlite3 import sqlite3
import dependency_injector.containers as containers
import dependency_injector.providers as providers
import dependency_injector.injections as injections
import movies import movies
import movies.finders import movies.finders
import example.db
import example.main
import settings import settings
import dependency_injector.containers as containers
import dependency_injector.providers as providers
class ApplicationModule(containers.DeclarativeContainer):
"""IoC container of application component providers.""" class ResourcesModule(containers.DeclarativeContainer):
"""IoC container of application resource providers."""
database = providers.Singleton(sqlite3.connect, settings.MOVIES_DB_PATH) database = providers.Singleton(sqlite3.connect, settings.MOVIES_DB_PATH)
@ -32,26 +34,21 @@ class MyMoviesModule(containers.DeclarativeContainer):
"""IoC container for overriding movies module component providers.""" """IoC container for overriding movies module component providers."""
movie_finder = providers.Factory(movies.finders.SqliteMovieFinder, movie_finder = providers.Factory(movies.finders.SqliteMovieFinder,
database=ApplicationModule.database, database=ResourcesModule.database,
**movies.MoviesModule.movie_finder.kwargs) **movies.MoviesModule.movie_finder.kwargs)
@injections.inject(movies.MoviesModule.movie_lister) class DbApplication(containers.DeclarativeContainer):
def main(movie_lister): """IoC container of database application component providers."""
"""Main function.
This program prints info about all movies that were directed by different main = providers.Callable(example.main.main,
persons and then prints all movies that were released in 2015. movie_lister=movies.MoviesModule.movie_lister)
:param movie_lister: Movie lister instance init_db = providers.Callable(example.db.init_sqlite,
:type movie_lister: movies.listers.MovieLister movies_data=settings.MOVIES_SAMPLE_DATA,
""" database=ResourcesModule.database)
print movie_lister.movies_directed_by('Francis Lawrence')
print movie_lister.movies_directed_by('Patricia Riggen')
print movie_lister.movies_directed_by('JJ Abrams')
print movie_lister.movies_released_in(2015)
if __name__ == '__main__': if __name__ == '__main__':
main() DbApplication.init_db()
DbApplication.main()

View File

@ -11,18 +11,20 @@ sqlite movies database and csv file movies database.
import sqlite3 import sqlite3
import dependency_injector.containers as containers
import dependency_injector.providers as providers
import dependency_injector.injections as injections
import movies import movies
import movies.finders import movies.finders
import example.db
import example.main
import settings import settings
import dependency_injector.containers as containers
import dependency_injector.providers as providers
class ApplicationModule(containers.DeclarativeContainer):
"""IoC container of application component providers.""" class ResourcesModule(containers.DeclarativeContainer):
"""IoC container of application resource providers."""
database = providers.Singleton(sqlite3.connect, settings.MOVIES_DB_PATH) database = providers.Singleton(sqlite3.connect, settings.MOVIES_DB_PATH)
@ -32,7 +34,7 @@ class DbMoviesModule(movies.MoviesModule):
"""IoC container for overriding movies module component providers.""" """IoC container for overriding movies module component providers."""
movie_finder = providers.Factory(movies.finders.SqliteMovieFinder, movie_finder = providers.Factory(movies.finders.SqliteMovieFinder,
database=ApplicationModule.database, database=ResourcesModule.database,
**movies.MoviesModule.movie_finder.kwargs) **movies.MoviesModule.movie_finder.kwargs)
@ -41,31 +43,36 @@ class CsvMoviesModule(movies.MoviesModule):
"""IoC container for overriding movies module component providers.""" """IoC container for overriding movies module component providers."""
movie_finder = providers.Factory(movies.finders.CsvMovieFinder, movie_finder = providers.Factory(movies.finders.CsvMovieFinder,
csv_file=settings.MOVIES_CSV_PATH, csv_file_path=settings.MOVIES_CSV_PATH,
delimeter=',', delimiter=',',
**movies.MoviesModule.movie_finder.kwargs) **movies.MoviesModule.movie_finder.kwargs)
@injections.inject(db_movie_lister=DbMoviesModule.movie_lister) class DbApplication(containers.DeclarativeContainer):
@injections.inject(csv_movie_lister=CsvMoviesModule.movie_lister) """IoC container of database application component providers."""
def main(db_movie_lister, csv_movie_lister):
"""Main function.
This program prints info about all movies that were directed by different main = providers.Callable(example.main.main,
persons and then prints all movies that were released in 2015. movie_lister=DbMoviesModule.movie_lister)
:param db_movie_lister: Movie lister, configured to work with database init_db = providers.Callable(example.db.init_sqlite,
:type db_movie_lister: movies.listers.MovieLister movies_data=settings.MOVIES_SAMPLE_DATA,
database=ResourcesModule.database)
:param csv_movie_lister: Movie lister, configured to work with csv file
:type csv_movie_lister: movies.listers.MovieLister
"""
for movie_lister in (db_movie_lister, csv_movie_lister):
print movie_lister.movies_directed_by('Francis Lawrence')
print movie_lister.movies_directed_by('Patricia Riggen')
print movie_lister.movies_directed_by('JJ Abrams')
print movie_lister.movies_released_in(2015)
class CsvApplication(containers.DeclarativeContainer):
"""IoC container of csv application component providers."""
main = providers.Callable(example.main.main,
movie_lister=CsvMoviesModule.movie_lister)
init_db = providers.Callable(example.db.init_csv,
movies_data=settings.MOVIES_SAMPLE_DATA,
csv_file_path=settings.MOVIES_CSV_PATH,
delimiter=',')
if __name__ == '__main__': if __name__ == '__main__':
main() DbApplication.init_db()
DbApplication.main()
CsvApplication.init_db()
CsvApplication.main()

View File

@ -1,33 +0,0 @@
"""Script for initializing movie databases."""
import os
import csv
import sqlite3
import shutil
from settings import DATA_DIR
from settings import MOVIES_CSV_PATH
from settings import MOVIES_DB_PATH
MOVIES = (('The Hunger Games: Mockingjay - Part 2', 2015, 'Francis Lawrence'),
('The 33', 2015, 'Patricia Riggen'),
('Star Wars: Episode VII - The Force Awakens', 2015, 'JJ Abrams'))
if __name__ == '__main__':
# (Re)create data directory:
if os.path.exists(DATA_DIR):
shutil.rmtree(DATA_DIR)
os.makedirs(DATA_DIR)
# Initialize sqlite database:
connection = sqlite3.connect(MOVIES_DB_PATH)
with connection:
connection.execute('CREATE TABLE movies '
'(name text, year int, director text)')
connection.executemany('INSERT INTO movies VALUES (?,?,?)', MOVIES)
# Initialize csv database:
with open(MOVIES_CSV_PATH, 'w') as csv_file:
csv.writer(csv_file).writerows(MOVIES)

View File

@ -0,0 +1,5 @@
# Ignore everything in this directory
*
# Except this file:
!.gitignore

View File

@ -0,0 +1 @@
"""Example top-level package."""

View File

@ -0,0 +1,35 @@
"""Example database module."""
import csv
def init_sqlite(movies_data, database):
"""Initialize sqlite3 movies database.
:param movies_data: Data about movies
:type movies_data: tuple[tuple]
:param database: Connection to sqlite database with movies data
:type database: sqlite3.Connection
"""
with database:
database.execute('CREATE TABLE IF NOT EXISTS movies '
'(name text, year int, director text)')
database.execute('DELETE FROM movies')
database.executemany('INSERT INTO movies VALUES (?,?,?)', movies_data)
def init_csv(movies_data, csv_file_path, delimiter):
"""Initialize csv movies database.
:param movies_data: Data about movies
:type movies_data: tuple[tuple]
:param csv_file_path: Path to csv file with movies data
:type csv_file_path: str
:param delimiter: Csv file's delimiter
:type delimiter: str
"""
with open(csv_file_path, 'w') as csv_file:
csv.writer(csv_file, delimiter=delimiter).writerows(movies_data)

View File

@ -0,0 +1,17 @@
"""Example main module."""
def main(movie_lister):
"""Main function.
This program prints info about all movies that were directed by different
persons and then prints all movies that were released in 2015.
:param movie_lister: Movie lister instance
:type movie_lister: movies.listers.MovieLister
"""
print(movie_lister.movies_directed_by('Francis Lawrence'))
print(movie_lister.movies_directed_by('Patricia Riggen'))
print(movie_lister.movies_directed_by('JJ Abrams'))
print(movie_lister.movies_released_in(2015))

View File

@ -12,13 +12,13 @@ concrete finder implementation in terms of library configuration.
Each of ``MoviesModule`` providers could be overridden. Each of ``MoviesModule`` providers could be overridden.
""" """
import dependency_injector.containers as containers
import dependency_injector.providers as providers
import movies.finders import movies.finders
import movies.listers import movies.listers
import movies.models import movies.models
import dependency_injector.containers as containers
import dependency_injector.providers as providers
class MoviesModule(containers.DeclarativeContainer): class MoviesModule(containers.DeclarativeContainer):
"""IoC container of movies module component providers.""" """IoC container of movies module component providers."""

View File

@ -33,20 +33,20 @@ class MovieFinder(object):
class CsvMovieFinder(MovieFinder): class CsvMovieFinder(MovieFinder):
"""Movie finder that fetches movies data from csv file.""" """Movie finder that fetches movies data from csv file."""
def __init__(self, movie_model, csv_file, delimeter): def __init__(self, movie_model, csv_file_path, delimiter):
"""Initializer. """Initializer.
:param movie_model: Movie model's factory :param movie_model: Movie model's factory
:type movie_model: movies.models.Movie :type movie_model: movies.models.Movie
:param csv_file: Path to csv file with movies data :param csv_file_path: Path to csv file with movies data
:type csv_file: str :type csv_file_path: str
:param delimeter: Csv file's delimeter :param delimiter: Csv file's delimiter
:type delimeter: str :type delimiter: str
""" """
self._csv_file = csv_file self._csv_file_path = csv_file_path
self._delimeter = delimeter self._delimiter = delimiter
super(CsvMovieFinder, self).__init__(movie_model) super(CsvMovieFinder, self).__init__(movie_model)
def find_all(self): def find_all(self):
@ -55,9 +55,9 @@ class CsvMovieFinder(MovieFinder):
:rtype: list[movies.models.Movie] :rtype: list[movies.models.Movie]
:return: List of movie instances. :return: List of movie instances.
""" """
with open(self._csv_file) as csv_file: with open(self._csv_file_path) as csv_file:
reader = csv.reader(csv_file, delimiter=self._delimeter) csv_reader = csv.reader(csv_file, delimiter=self._delimiter)
return [self._movie_model(*row) for row in reader] return [self._movie_model(*row) for row in csv_reader]
class SqliteMovieFinder(MovieFinder): class SqliteMovieFinder(MovieFinder):

View File

@ -7,8 +7,11 @@ import os
DATA_DIR = os.path.abspath(os.path.dirname(__file__) + '/data') DATA_DIR = os.path.abspath(os.path.dirname(__file__) + '/data')
MOVIES_CSV_PATH = DATA_DIR + '/movies.csv' MOVIES_CSV_PATH = DATA_DIR + '/movies.csv'
MOVIES_CSV_DELIMETER = ','
MOVIES_DB_PATH = DATA_DIR + '/movies.db' MOVIES_DB_PATH = DATA_DIR + '/movies.db'
MOVIES_SAMPLE_DATA = (
('The Hunger Games: Mockingjay - Part 2', 2015, 'Francis Lawrence'),
('The 33', 2015, 'Patricia Riggen'),
('Star Wars: Episode VII - The Force Awakens', 2015, 'JJ Abrams'),
)

View File

@ -5,4 +5,4 @@ Instructions for running
.. code-block:: bash .. code-block:: bash
python main.py python run.py

View File

@ -2,6 +2,8 @@
import sqlite3 import sqlite3
import boto.s3.connection import boto.s3.connection
import example.main
import example.services import example.services
import dependency_injector.containers as containers import dependency_injector.containers as containers
@ -31,3 +33,12 @@ class Services(containers.DeclarativeContainer):
photos = providers.Factory(example.services.Photos, photos = providers.Factory(example.services.Photos,
db=Platform.database, db=Platform.database,
s3=Platform.s3) s3=Platform.s3)
class Application(containers.DeclarativeContainer):
"""IoC container of application component providers."""
main = providers.Callable(example.main.main,
users_service=Services.users,
auth_service=Services.auth,
photos_service=Services.photos)

View File

@ -5,6 +5,8 @@ Alternative injections definition style #1.
import sqlite3 import sqlite3
import boto.s3.connection import boto.s3.connection
import example.main
import example.services import example.services
import dependency_injector.containers as containers import dependency_injector.containers as containers
@ -35,3 +37,12 @@ class Services(containers.DeclarativeContainer):
photos = providers.Factory(example.services.Photos) \ photos = providers.Factory(example.services.Photos) \
.add_kwargs(db=Platform.database, .add_kwargs(db=Platform.database,
s3=Platform.s3) s3=Platform.s3)
class Application(containers.DeclarativeContainer):
"""IoC container of application component providers."""
main = providers.Callable(example.main.main) \
.add_kwargs(users_service=Services.users,
auth_service=Services.auth,
photos_service=Services.photos)

View File

@ -5,6 +5,8 @@ Alternative injections definition style #2.
import sqlite3 import sqlite3
import boto.s3.connection import boto.s3.connection
import example.main
import example.services import example.services
import dependency_injector.containers as containers import dependency_injector.containers as containers
@ -35,3 +37,12 @@ class Services(containers.DeclarativeContainer):
photos = providers.Factory(example.services.Photos) photos = providers.Factory(example.services.Photos)
photos.add_kwargs(db=Platform.database, photos.add_kwargs(db=Platform.database,
s3=Platform.s3) s3=Platform.s3)
class Application(containers.DeclarativeContainer):
"""IoC container of application component providers."""
main = providers.Callable(example.main.main)
main.add_kwargs(users_service=Services.users,
auth_service=Services.auth,
photos_service=Services.photos)

View File

@ -0,0 +1,8 @@
"""Example main module."""
def main(users_service, auth_service, photos_service):
"""Example main function."""
user = users_service.get_user('user')
auth_service.authenticate(user, 'secret')
photos_service.upload_photo(user['id'], 'photo.jpg')

View File

@ -1,18 +0,0 @@
"""Dependency Injector @inject decorator example."""
import application
import dependency_injector.injections as injections
@injections.inject(users_service=application.Services.users)
@injections.inject(auth_service=application.Services.auth)
@injections.inject(photos_service=application.Services.photos)
def main(users_service, auth_service, photos_service):
"""Main function."""
user = users_service.get_user('user')
auth_service.authenticate(user, 'secret')
photos_service.upload_photo(user['id'], 'photo.jpg')
if __name__ == '__main__':
main()

View File

@ -0,0 +1,19 @@
"""Run example application."""
import containers
if __name__ == '__main__':
containers.Application.main()
# Previous call is an equivalent of next operations:
#
# database = sqlite3.connect(':memory:')
# s3 = boto.s3.connection.S3Connection(aws_access_key_id='KEY',
# aws_secret_access_key='SECRET')
#
# example.main.main(users_service=example.services.Users(db=database),
# auth_service=example.services.Auth(db=database,
# token_ttl=3600),
# photos_service=example.services.Photos(db=database,
# s3=s3))

View File

@ -1,5 +1,7 @@
"""Dependency injector injections unittests.""" """Dependency injector injections unittests."""
import warnings
import unittest2 as unittest import unittest2 as unittest
from dependency_injector import injections from dependency_injector import injections
@ -176,3 +178,25 @@ class InjectTests(unittest.TestCase):
@injections.inject(arg1=123) @injections.inject(arg1=123)
class Test(object): class Test(object):
"""Test class.""" """Test class."""
class InjectDeprecationTests(unittest.TestCase):
"""Deprecation of `@inject()` tests."""
def test_deprecation_warning_on_usage(self):
"""Test that DeprecationWarning is produced when `@inject` is used."""
with warnings.catch_warnings(record=True) as caught_warnings:
warnings.simplefilter('always')
@injections.inject(1)
def _example(arg):
pass
warnings.simplefilter('default')
self.assertEquals(len(caught_warnings), 1)
self.assertEquals(caught_warnings[-1].category, DeprecationWarning)
self.assertIn('Call to a deprecated decorator',
str(caught_warnings[-1].message))
self.assertIn('@dependency_injector.injections.inject',
str(caught_warnings[-1].message))