diff --git a/examples/concept_providing_callbacks.py b/examples/concept_providing_callbacks.py new file mode 100644 index 00000000..cdf8f9bc --- /dev/null +++ b/examples/concept_providing_callbacks.py @@ -0,0 +1,113 @@ +"""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.""" + + @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) + + +# 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) + + +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/tests/test_catalogs.py b/tests/test_catalogs.py index 740365c3..190e5400 100644 --- a/tests/test_catalogs.py +++ b/tests/test_catalogs.py @@ -4,6 +4,7 @@ import unittest2 as unittest from dependency_injector import catalogs from dependency_injector import providers +from dependency_injector import injections from dependency_injector import errors @@ -670,3 +671,76 @@ class CatalogModuleBackwardCompatibility(unittest.TestCase): from dependency_injector import catalogs self.assertIs(catalog, catalogs) + + +class TestCatalogWithProvidingCallbacks(unittest.TestCase): + """Catalog with providing callback tests.""" + + def test_concept(self): + """Test concept.""" + class UsersService(object): + """Users service, that has dependency on database.""" + + class AuthService(object): + """Auth service, that has dependencies on users service.""" + + def __init__(self, users_service): + """Initializer.""" + self.users_service = users_service + + class Services(catalogs.DeclarativeCatalog): + """Catalog of service providers.""" + + @providers.Factory + def users(): + """Provide users service. + + :rtype: providers.Provider -> UsersService + """ + return UsersService() + + @providers.Factory + @injections.inject(users_service=users) + def auth(**kwargs): + """Provide users service. + + :rtype: providers.Provider -> AuthService + """ + return AuthService(**kwargs) + + # Retrieving catalog providers: + users_service = Services.users() + auth_service = Services.auth() + + # Making some asserts: + self.assertIsInstance(auth_service.users_service, UsersService) + self.assertIsNot(users_service, Services.users()) + self.assertIsNot(auth_service, Services.auth()) + + # Overriding auth service provider and making some asserts: + class ExtendedAuthService(AuthService): + """Extended version of auth service.""" + + def __init__(self, users_service, ttl): + """Initializer.""" + self.ttl = ttl + super(ExtendedAuthService, self).__init__( + users_service=users_service) + + class OverriddenServices(Services): + """Catalog of service providers.""" + + @providers.override(Services.auth) + @providers.Factory + @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() + + self.assertIsInstance(auth_service, ExtendedAuthService)