How can I register an interface with multiple interfaces in a container?
hi.
Sorry for the confusing question. I want to register only the interface in the Container without having an implementation.
Specifically, it is as follows:
import abc
from dependency_injector import containers, providers
# It is an implementation of Repository that executes user registration/update.
# It is implemented separately for Postgres implementation and InMemory implementation.
class InsertRepository(metaclass=abc.ABCMeta):
def insert(entity):
pass
class UpdateRepository(metaclass=abc.ABCMeta):
def update(entity):
pass
class DeleteRepository(metaclass=abc.ABCMeta):
def delete(entity):
pass
class PostgresInsertRepository(InsertRepository):
def insert(entity):
# awesome code
class PostgresUpdateRepository(UpdateRepository):
def update(entity):
# awesome code
class PostgresDeleteRepository(DeleteRepository):
def delete(entity):
# awesome code
class InMemoryInsertRepository(InsertRepository):
def insert(entity):
# awesome code
class InMemoryUpdateRepository(UpdateRepository):
def update(entity):
# awesome code
class InMemoryDeleteRepository(DeleteRepository):
def delete(entity):
# awesome code
class UserRepository(
InsertRepository,
UpdateRepository,
metaclass=abc.ABCMeta
):
pass
# I want UserRepository to have PostgresInsertRepository and PostgresUpdateRepository implementations
# and register them in Container.
# I thought about creating a PostgresUpdateRepository, but I want to avoid it because I just call it
# example:
class PostgresUserRepository(
UserRepository
):
def __init__(
self,
postgres_insert_repository: PostgresInsertRepository,
postgres_update_repository: PostgresUpdateRepository
):
self.postgres_insert_repository = postgres_insert_repository
self.postgres_update_repository = postgres_update_repository
def insert(entity):
self.postgres_insert_repository.insert(entity)
def update(entity):
self.postgres_update_repository.insert(entity)
class Container(containers.DeclarativeContainer):
insert_repository = providers.Factory(
PostgresInsertRepository
)
update_repository = providers.Factory(
PostgresUpdateRepository
)
user_repository = providers.Factory(
PostgresUserRepository,
postgres_insert_repository=insert_repository,
postgres_update_repository=update_repository,
)
(Of course, the above code normally receives DB related values, but it is a simplified code because it deviates a little from this question.)
Do you have any good ideas?
Hi @satodaiki , take a look at the Dependency provider. Here is an example of what you can do with it:
class Container(containers.DeclarativeContainer):
insert_repository = providers.Factory(
PostgresInsertRepository
)
update_repository = providers.Factory(
PostgresUpdateRepository
)
user_repository = providers.Dependency(
instance_of=UserRepository,
default=providers.Factory(
PostgresUserRepository,
insert_repository=providers.Dependency(InsertRepository, default=insert_repository),
update_repository=providers.Dependency(UpdateRepository, default=update_repository),
)
)
if __name__ == "__main__":
# OK
container = Container()
assert isinstance(container.user_repository(), UserRepository)
# Improper type of user repository
container = Container(user_repository=object())
try:
assert isinstance(container.user_repository(), UserRepository)
except errors.Error as exception:
print(exception)
# Improper type of insert repository
container = Container(insert_repository=object())
try:
assert isinstance(container.user_repository(), UserRepository)
except errors.Error as exception:
print(exception)
# Improper type of update repository
container = Container(update_repository=object())
try:
assert isinstance(container.user_repository(), UserRepository)
except errors.Error as exception:
print(exception)
Does it look like something you were looking for?
PS: Argument default is optional.
@rmk135 Thank you!
However, is it necessary to define the following PostgresUserRepository even in the example presented?
class PostgresUserRepository(
UserRepository
):
def __init__(
self,
postgres_insert_repository: PostgresInsertRepository,
postgres_update_repository: PostgresUpdateRepository
):
self.postgres_insert_repository = postgres_insert_repository
self.postgres_update_repository = postgres_update_repository
def insert(entity):
self.postgres_insert_repository.insert(entity)
def update(entity):
self.postgres_update_repository.insert(entity)
Hi @satodaiki ,
However, is it necessary to define the following PostgresUserRepository even in the example presented?
Yes, I have PostgresUserRepository class defined. Sharing the full sample that I used locally:
import abc
from dependency_injector import containers, providers, errors
class InsertRepository(metaclass=abc.ABCMeta):
def insert(self, entity):
pass
class UpdateRepository(metaclass=abc.ABCMeta):
def update(self, entity):
pass
class DeleteRepository(metaclass=abc.ABCMeta):
def delete(self, entity):
pass
class PostgresInsertRepository(InsertRepository):
def insert(self, entity):
pass
class PostgresUpdateRepository(UpdateRepository):
def update(self, entity):
pass
class PostgresDeleteRepository(DeleteRepository):
def delete(self, entity):
pass
class InMemoryInsertRepository(InsertRepository):
def insert(self, entity):
pass
class InMemoryUpdateRepository(UpdateRepository):
def update(self, entity):
pass
class UserRepository(
InsertRepository,
UpdateRepository,
metaclass=abc.ABCMeta
):
pass
class PostgresUserRepository(
UserRepository
):
def __init__(
self,
insert_repository: PostgresInsertRepository,
update_repository: PostgresUpdateRepository
):
self.insert_repository = insert_repository
self.update_repository = update_repository
class Container(containers.DeclarativeContainer):
insert_repository = providers.Factory(
PostgresInsertRepository
)
update_repository = providers.Factory(
PostgresUpdateRepository
)
user_repository = providers.Dependency(
instance_of=UserRepository,
default=providers.Factory(
PostgresUserRepository,
insert_repository=providers.Dependency(InsertRepository, default=insert_repository),
update_repository=providers.Dependency(UpdateRepository, default=update_repository),
)
)
if __name__ == "__main__":
# OK
container = Container()
assert isinstance(container.user_repository(), UserRepository)
# Improper type of user repository
container = Container(user_repository=object())
try:
assert isinstance(container.user_repository(), UserRepository)
except errors.Error as exception:
print(exception)
# Improper type of insert repository
container = Container(insert_repository=object())
try:
assert isinstance(container.user_repository(), UserRepository)
except errors.Error as exception:
print(exception)
# Improper type of update repository
container = Container(update_repository=object())
try:
assert isinstance(container.user_repository(), UserRepository)
except errors.Error as exception:
print(exception)
Does it cover your initial goal? Please let me know if you're still looking for any answers or improvements.
Best, Roman