diff --git a/README.rst b/README.rst index f76f864e..51fc3ec0 100644 --- a/README.rst +++ b/README.rst @@ -62,9 +62,126 @@ Documentation Examples -------- +API client example: + .. code-block:: python - """Pythonic way for Dependency Injection (example with Catalog).""" + """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.""" import sqlite3 @@ -131,72 +248,76 @@ Examples # Making a call of decorated callback: example() - - # Overriding auth service provider and making some asserts: - class ExtendedAuthService(AuthService): - """Extended version of auth service.""" - - def __init__(self, db, users_service, ttl): - """Initializer.""" - self.ttl = ttl - super(ExtendedAuthService, self).__init__(db=db, - users_service=users_service) - - - Services.auth.override(providers.Factory(ExtendedAuthService, - db=Services.database, - users_service=Services.users, - ttl=3600)) - - - auth_service = Services.auth() - - assert isinstance(auth_service, ExtendedAuthService) - -Authentication system example: +Providing callbacks catalog example: .. code-block:: python - """Pythonic way for Dependency Injection.""" + """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 - @providers.DelegatedCallable - def get_user_info(user_id): - """Return user info.""" - raise NotImplementedError() + class UsersService(object): + """Users service, that has dependency on database.""" - - @providers.Factory - @injections.inject(get_user_info=get_user_info) - class AuthComponent(object): - """Some authentication component.""" - - def __init__(self, get_user_info): + def __init__(self, db): """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 + self.db = db - print AuthComponent - print get_user_info + 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 - @providers.override(get_user_info) - @providers.DelegatedCallable - def get_user_info(user_id): - """Return user info.""" - return {'user_id': user_id} + class Services(catalogs.DeclarativeCatalog): + """Catalog of service providers.""" + + @providers.Singleton + def database(): + """Provide database connection. + + :rtype: providers.Provider -> sqlite3.Connection + """ + return sqlite3.connect(':memory:') + + @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) - print AuthComponent().authenticate_user(token='abc') - # {'user_id': 'abc1'} + # 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() You can get more *Dependency Injector* examples in ``/examples`` directory on GitHub: diff --git a/examples/api_client.py b/examples/api_client.py new file mode 100644 index 00000000..c547b9e6 --- /dev/null +++ b/examples/api_client.py @@ -0,0 +1,65 @@ +"""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/auth_system.py b/examples/auth_system.py index f09bae8d..be09a56a 100644 --- a/examples/auth_system.py +++ b/examples/auth_system.py @@ -1,4 +1,4 @@ -"""Pythonic way for Dependency Injection.""" +"""Pythonic way for Dependency Injection - Auth System.""" from dependency_injector import providers from dependency_injector import injections diff --git a/examples/concept.py b/examples/catalog.py similarity index 70% rename from examples/concept.py rename to examples/catalog.py index d9302e57..458d2fe9 100644 --- a/examples/concept.py +++ b/examples/catalog.py @@ -1,4 +1,4 @@ -"""Concept example of `Dependency Injector`.""" +"""Pythonic way for Dependency Injection - Service Providers Catalog.""" import sqlite3 @@ -64,25 +64,3 @@ def example(users_service, auth_service, database): # Making a call of decorated callback: example() - - -# Overriding auth service provider and making some asserts: -class ExtendedAuthService(AuthService): - """Extended version of auth service.""" - - def __init__(self, db, users_service, ttl): - """Initializer.""" - self.ttl = ttl - super(ExtendedAuthService, self).__init__(db=db, - users_service=users_service) - - -Services.auth.override(providers.Factory(ExtendedAuthService, - db=Services.database, - users_service=Services.users, - ttl=3600)) - - -auth_service = Services.auth() - -assert isinstance(auth_service, ExtendedAuthService) diff --git a/examples/concept_providing_callbacks.py b/examples/catalog_providing_callbacks.py similarity index 54% rename from examples/concept_providing_callbacks.py rename to examples/catalog_providing_callbacks.py index cdf8f9bc..0ba82db0 100644 --- a/examples/concept_providing_callbacks.py +++ b/examples/catalog_providing_callbacks.py @@ -1,4 +1,4 @@ -"""Concept example of `Dependency Injector`.""" +"""Pythonic way for Dependency Injection - Providing Callbacks Catalog.""" import sqlite3 @@ -64,50 +64,3 @@ 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() - - -# Overriding auth service provider and making some asserts: -class ExtendedAuthService(AuthService): - """Extended version of auth service.""" - - def __init__(self, db, users_service, ttl): - """Initializer.""" - self.ttl = ttl - super(ExtendedAuthService, self).__init__(db=db, - users_service=users_service) - - -class OverriddenServices(Services): - """Catalog of service providers.""" - - @providers.override(Services.auth) - @providers.Factory - @injections.inject(db=Services.database) - @injections.inject(users_service=Services.users) - @injections.inject(ttl=3600) - def auth(**kwargs): - """Provide users service. - - :rtype: providers.Provider -> AuthService - """ - return ExtendedAuthService(**kwargs) - - -auth_service = Services.auth() - -assert isinstance(auth_service, ExtendedAuthService) diff --git a/examples/concept_full_syntax.py b/examples/concept_full_syntax.py deleted file mode 100644 index 16f65cee..00000000 --- a/examples/concept_full_syntax.py +++ /dev/null @@ -1,91 +0,0 @@ -"""Concept example of `Dependency Injector`.""" - -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, - injections.Arg(':memory:')) - """:type: providers.Provider -> sqlite3.Connection""" - - users = providers.Factory(UsersService, - injections.KwArg('db', database)) - """:type: providers.Provider -> UsersService""" - - auth = providers.Factory(AuthService, - injections.KwArg('db', database), - injections.KwArg('users_service', users)) - """:type: providers.Provider -> AuthService""" - - -# 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() - - -# Overriding auth service provider and making some asserts: -class ExtendedAuthService(AuthService): - """Extended version of auth service.""" - - def __init__(self, db, users_service, ttl): - """Initializer.""" - self.ttl = ttl - super(ExtendedAuthService, self).__init__(db=db, - users_service=users_service) - - -Services.auth.override(providers.Factory(ExtendedAuthService, - injections.KwArg('db', - Services.database), - injections.KwArg('users_service', - Services.users), - injections.KwArg('ttl', 3600))) - - -auth_service = Services.auth() - -assert isinstance(auth_service, ExtendedAuthService)