diff --git a/README.rst b/README.rst index 1cde7ab1..dd181897 100644 --- a/README.rst +++ b/README.rst @@ -55,259 +55,66 @@ Installation Examples -------- -API client example: - .. code-block:: python - """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} - -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.""" + """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 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.""" + class Platform(catalogs.DeclarativeCatalog): + """Catalog of platform 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() - -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 + s3 = providers.Singleton(boto.s3.connection.S3Connection, + aws_access_key_id='KEY', + aws_secret_access_key='SECRET') class Services(catalogs.DeclarativeCatalog): - """Catalog of service providers.""" + """Catalog of business service providers.""" - @providers.Singleton - def database(): - """Provide database connection. + users = providers.Factory(services.Users, + db=Platform.database) - :rtype: providers.Provider -> sqlite3.Connection - """ - return sqlite3.connect(':memory:') + photos = providers.Factory(services.Photos, + db=Platform.database, + s3=Platform.s3) - @providers.Factory - @injections.inject(db=database) - def users(**kwargs): - """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) + auth = providers.Factory(services.Auth, + db=Platform.database, + token_ttl=3600) - # Retrieving catalog providers: - users_service = Services.users() - auth_service = Services.auth() + @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:] - # 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() + 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) You can get more *Dependency Injector* examples in ``/examples`` directory on GitHub: @@ -334,8 +141,8 @@ Your feedback is quite important! .. _PyPi: https://pypi.python.org/pypi/dependency_injector -.. _User's guide: http://dependency_injector.readthedocs.org/en/stable/ -.. _API docs: http://dependency-injector.readthedocs.org/en/stable/api/ +.. _User's guide: http://dependency-injector.ets-labs.org/en/stable/ +.. _API docs: http://dependency-injector.ets-labs.org/en/stable/api/ .. _SLOC: http://en.wikipedia.org/wiki/Source_lines_of_code .. _SOLID: http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29 .. _IoC: http://en.wikipedia.org/wiki/Inversion_of_control diff --git a/docs/examples/index.rst b/docs/examples/index.rst index e69de29b..907553f5 100644 --- a/docs/examples/index.rst +++ b/docs/examples/index.rst @@ -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 diff --git a/docs/examples/movie_lister.rst b/docs/examples/movie_lister.rst index e69de29b..8cf802e5 100644 --- a/docs/examples/movie_lister.rst +++ b/docs/examples/movie_lister.rst @@ -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 diff --git a/docs/images/miniapps/movie_lister/classes.png b/docs/images/miniapps/movie_lister/classes.png new file mode 100644 index 00000000..78db720d Binary files /dev/null and b/docs/images/miniapps/movie_lister/classes.png differ diff --git a/docs/index.rst b/docs/index.rst index e4fcde00..a7242a4b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,8 +2,7 @@ Dependency Injector --- Python dependency injection framework ============================================================= .. meta:: - :keywords: Python,DI,Dependency injection,IoC,Inversion of Control - :google-site-verification: mPdgVBidFHVWRNh0lhxj7q9zi-CpwIU970jINTBKLYQ + :google-site-verification: 6it89zX0_wccKEhAqbAiYQooS95f0BA8YfesHk6bsNA :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 @@ -63,6 +62,7 @@ Contents providers/index catalogs/index advanced_usage/index + examples/index api/index main/feedback main/changelog diff --git a/docs/introduction/di_in_python.rst b/docs/introduction/di_in_python.rst index 0e81c1b2..27010b14 100644 --- a/docs/introduction/di_in_python.rst +++ b/docs/introduction/di_in_python.rst @@ -2,7 +2,6 @@ Dependency injection and inversion of control in Python ------------------------------------------------------- .. meta:: - :keywords: Python,DI,Dependency injection,IoC,Inversion of Control :description: This article describes benefits of dependency injection and inversion of control for Python applications. Also it contains some Python examples that show how dependency diff --git a/docs/introduction/index.rst b/docs/introduction/index.rst index 3e7ce7cc..a94b6bf0 100644 --- a/docs/introduction/index.rst +++ b/docs/introduction/index.rst @@ -2,7 +2,6 @@ Introduction ============ .. meta:: - :keywords: Python,DI,Dependency injection,IoC,Inversion of Control :description: Current section of documentation is designed to give some overview about dependency injection pattern, inversion of control principle and "Dependency Injector" framework. diff --git a/docs/introduction/key_features.rst b/docs/introduction/key_features.rst index a4f11038..cbec717b 100644 --- a/docs/introduction/key_features.rst +++ b/docs/introduction/key_features.rst @@ -2,7 +2,6 @@ Key features of Dependency Injector ----------------------------------- .. meta:: - :keywords: Python,DI,Dependency injection,IoC,Inversion of Control :description: This article describes key features of "Dependency Injector" framework. It also provides some cases and recommendations about usage of "Dependency Injector" framework. diff --git a/docs/introduction/structure.rst b/docs/introduction/structure.rst index 3756e352..e58c274a 100644 --- a/docs/introduction/structure.rst +++ b/docs/introduction/structure.rst @@ -2,7 +2,6 @@ Structure of Dependency Injector -------------------------------- .. meta:: - :keywords: Python,DI,Dependency injection,IoC,Inversion of Control :description: This article describes "Dependency Injector" framework components and their interaction between each other. Catalogs, providers and injections are the former diff --git a/docs/introduction/what_is_di.rst b/docs/introduction/what_is_di.rst index 05b9b169..4d464586 100644 --- a/docs/introduction/what_is_di.rst +++ b/docs/introduction/what_is_di.rst @@ -2,7 +2,6 @@ What is dependency injection and inversion of control? ------------------------------------------------------ .. meta:: - :keywords: Python,DI,Dependency injection,IoC,Inversion of Control :description: This article provides definition of dependency injection, inversion of control and dependency inversion. It contains example code in Python that is refactored to be following diff --git a/docs/main/changelog.rst b/docs/main/changelog.rst index bf723565..8422c6eb 100644 --- a/docs/main/changelog.rst +++ b/docs/main/changelog.rst @@ -11,6 +11,8 @@ Development version ------------------- - Add ``@copy`` decorator for copying declarative catalog providers. - Add line numbers for all code samples in documentation. +- Move project documentation into organisation's domain + (dependency-injector.ets-labs.org). 1.15.2 ------ diff --git a/examples/advanced_usage/config_provider.py b/examples/advanced_usage/config_provider.py index 15060b88..7794b2f4 100644 --- a/examples/advanced_usage/config_provider.py +++ b/examples/advanced_usage/config_provider.py @@ -24,7 +24,6 @@ class Catalog(catalogs.DeclarativeCatalog): fee=config.FEE, price=config.PRICE, timezone=config.GLOBAL.TIMEZONE) - """:type: providers.Provider -> ObjectA""" # Setting config value and making some tests. diff --git a/examples/api_client.py b/examples/api_client.py deleted file mode 100644 index c547b9e6..00000000 --- a/examples/api_client.py +++ /dev/null @@ -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} diff --git a/examples/catalog.py b/examples/catalog.py deleted file mode 100644 index 771e3f71..00000000 --- a/examples/catalog.py +++ /dev/null @@ -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() diff --git a/examples/catalogs/bundles/catalogs.py b/examples/catalogs/bundles/catalogs.py index 52e16861..e5a9b397 100644 --- a/examples/catalogs/bundles/catalogs.py +++ b/examples/catalogs/bundles/catalogs.py @@ -13,13 +13,10 @@ class Services(catalogs.DeclarativeCatalog): """Example catalog of service providers.""" users = providers.Factory(services.Users) - """:type: providers.Provider -> services.Users""" auth = providers.Factory(services.Auth) - """:type: providers.Provider -> services.Auth""" photos = providers.Factory(services.Photos) - """:type: providers.Provider -> services.Photos""" # Declaring views catalog: @@ -29,12 +26,10 @@ class Views(catalogs.DeclarativeCatalog): auth = providers.Factory(views.Auth, services=Services.Bundle(Services.users, Services.auth)) - """:type: providers.Provider -> views.Auth""" photos = providers.Factory(views.Photos, services=Services.Bundle(Services.users, Services.photos)) - """:type: providers.Provider -> views.Photos""" # Creating example views: diff --git a/examples/catalogs/declarative.py b/examples/catalogs/declarative.py index f11dbe35..a483fc88 100644 --- a/examples/catalogs/declarative.py +++ b/examples/catalogs/declarative.py @@ -9,10 +9,8 @@ class Catalog(catalogs.DeclarativeCatalog): """Providers catalog.""" factory1 = providers.Factory(object) - """:type: providers.Provider -> object""" factory2 = providers.Factory(object) - """:type: providers.Provider -> object""" # Creating some objects: object1 = Catalog.factory1() diff --git a/examples/catalogs/declarative_inheritance.py b/examples/catalogs/declarative_inheritance.py index d73b71a7..e0ff494c 100644 --- a/examples/catalogs/declarative_inheritance.py +++ b/examples/catalogs/declarative_inheritance.py @@ -8,14 +8,12 @@ class CatalogA(catalogs.DeclarativeCatalog): """Example catalog A.""" provider1 = providers.Factory(object) - """:type: providers.Provider -> object""" class CatalogB(CatalogA): """Example catalog B.""" provider2 = providers.Singleton(object) - """:type: providers.Provider -> object""" # Making some asserts for `providers` attribute: diff --git a/examples/catalogs/declarative_injections.py b/examples/catalogs/declarative_injections.py index 0f277f3f..85dc8f87 100644 --- a/examples/catalogs/declarative_injections.py +++ b/examples/catalogs/declarative_injections.py @@ -27,16 +27,13 @@ class Services(catalogs.DeclarativeCatalog): """Catalog of service providers.""" database = providers.Singleton(sqlite3.connect, ':memory:') - """:type: providers.Provider -> sqlite3.Connection""" users = providers.Factory(UsersService, db=database) - """:type: providers.Provider -> UsersService""" auth = providers.Factory(AuthService, db=database, users_service=users) - """:type: providers.Provider -> AuthService""" # Retrieving service providers from catalog: diff --git a/examples/catalogs/declarative_provider_type/catalog.py b/examples/catalogs/declarative_provider_type/catalog.py index d7ed6b9c..520da6cc 100644 --- a/examples/catalogs/declarative_provider_type/catalog.py +++ b/examples/catalogs/declarative_provider_type/catalog.py @@ -31,13 +31,11 @@ class Services(services.Catalog): users = services.Provider(UsersService, config={'option1': '111', 'option2': '222'}) - """:type: services.Provider -> UsersService""" auth = services.Provider(AuthService, config={'option3': '333', 'option4': '444'}, users_service=users) - """:type: services.Provider -> AuthService""" # Creating users & auth services: diff --git a/examples/catalogs/override_declarative.py b/examples/catalogs/override_declarative.py index 825ffe91..a38777ad 100644 --- a/examples/catalogs/override_declarative.py +++ b/examples/catalogs/override_declarative.py @@ -18,18 +18,15 @@ class Catalog(catalogs.DeclarativeCatalog): object1_factory = providers.Factory(Object1, arg1=1, arg2=2) - """:type: providers.Provider -> Object1""" object2_factory = providers.Factory(Object2, object1=object1_factory) - """:type: providers.Provider -> Object2""" class AnotherCatalog(catalogs.DeclarativeCatalog): """Overriding catalog.""" object2_factory = providers.Factory(ExtendedObject2) - """:type: providers.Provider -> ExtendedObject2""" # Overriding `Catalog` with `AnotherCatalog`: diff --git a/examples/catalogs/override_declarative_by_dynamic.py b/examples/catalogs/override_declarative_by_dynamic.py index 8886a271..7246e5f4 100644 --- a/examples/catalogs/override_declarative_by_dynamic.py +++ b/examples/catalogs/override_declarative_by_dynamic.py @@ -18,11 +18,9 @@ class Catalog(catalogs.DeclarativeCatalog): object1_factory = providers.Factory(Object1, arg1=1, arg2=2) - """:type: providers.Provider -> Object1""" object2_factory = providers.Factory(Object2, object1=object1_factory) - """:type: providers.Provider -> Object2""" # Overriding `Catalog` with some `DynamicCatalog` instance: diff --git a/examples/catalogs/override_declarative_decorator.py b/examples/catalogs/override_declarative_decorator.py index 2dcbc828..cb59a752 100644 --- a/examples/catalogs/override_declarative_decorator.py +++ b/examples/catalogs/override_declarative_decorator.py @@ -17,11 +17,9 @@ class Catalog(catalogs.DeclarativeCatalog): object1_factory = providers.Factory(Object1, arg1=1, arg2=2) - """:type: providers.Provider -> Object1""" object2_factory = providers.Factory(Object2, object1=object1_factory) - """:type: providers.Provider -> Object2""" # Overriding `Catalog` with `AnotherCatalog`: @@ -30,7 +28,6 @@ class AnotherCatalog(catalogs.DeclarativeCatalog): """Overriding catalog.""" object2_factory = providers.Factory(ExtendedObject2) - """:type: providers.Provider -> ExtendedObject2""" # Creating some objects using overridden catalog: diff --git a/examples/initial.py b/examples/initial.py new file mode 100644 index 00000000..1bca84dc --- /dev/null +++ b/examples/initial.py @@ -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) diff --git a/examples/miniapps/api_client/api.py b/examples/miniapps/api_client/api.py new file mode 100644 index 00000000..425c7fec --- /dev/null +++ b/examples/miniapps/api_client/api.py @@ -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)) diff --git a/examples/miniapps/api_client/main.py b/examples/miniapps/api_client/main.py new file mode 100644 index 00000000..09cc9bf6 --- /dev/null +++ b/examples/miniapps/api_client/main.py @@ -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} diff --git a/examples/miniapps/api_client/models.py b/examples/miniapps/api_client/models.py new file mode 100644 index 00000000..4652dfa6 --- /dev/null +++ b/examples/miniapps/api_client/models.py @@ -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}) diff --git a/examples/miniapps/api_client/tests.py b/examples/miniapps/api_client/tests.py new file mode 100644 index 00000000..f19995d9 --- /dev/null +++ b/examples/miniapps/api_client/tests.py @@ -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'}) diff --git a/examples/miniapps/flask_services/app.py b/examples/miniapps/flask_services/app.py new file mode 100644 index 00000000..9737eadf --- /dev/null +++ b/examples/miniapps/flask_services/app.py @@ -0,0 +1,10 @@ +"""Flask application.""" + +import flask + + +app = flask.Flask(__name__) + + +if __name__ == '__main__': + app.run() diff --git a/examples/miniapps/flask_services/services/__init__.py b/examples/miniapps/flask_services/services/__init__.py new file mode 100644 index 00000000..3d091cc8 --- /dev/null +++ b/examples/miniapps/flask_services/services/__init__.py @@ -0,0 +1,8 @@ +"""Services package.""" + +from dependency_injector import catalogs +from dependency_injector import providers + + +class ServicesModule(catalogs.DeclarativeCatalog): + """Service providers module.""" diff --git a/examples/miniapps/movie_lister/movies/__init__.py b/examples/miniapps/movie_lister/movies/__init__.py index e7d8437f..360c3979 100644 --- a/examples/miniapps/movie_lister/movies/__init__.py +++ b/examples/miniapps/movie_lister/movies/__init__.py @@ -5,6 +5,10 @@ module component providers - ``MoviesModule``. It is recommended to use movies library functionality by fetching required instances from ``MoviesModule`` 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. """ diff --git a/examples/auth_system.py b/examples/misc/auth_system.py similarity index 100% rename from examples/auth_system.py rename to examples/misc/auth_system.py diff --git a/examples/catalog_providing_callbacks.py b/examples/misc/catalog_providing_callbacks.py similarity index 100% rename from examples/catalog_providing_callbacks.py rename to examples/misc/catalog_providing_callbacks.py diff --git a/examples/services.py b/examples/services.py new file mode 100644 index 00000000..d512e31b --- /dev/null +++ b/examples/services.py @@ -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."""