-
Notifications
You must be signed in to change notification settings - Fork 18
Examples
Roberto Prevato edited this page Jan 31, 2021
·
11 revisions
new in version 1.1.0 ⭐
Note how class annotations are used in the example below to define dependencies between services. rodi
can resolve dependencies by class annotations: db_settings: DatabaseSettings
in the PostgresCatsRepository
type, and cats_repository: ICatsRepository
in GetCatRequestHandler
:
from abc import ABC, abstractmethod
from dataclasses import dataclass
from rodi import Container
# domain object:
class Cat:
def __init__(self, name):
self.name = name
# abstract interface
class ICatsRepository(ABC):
@abstractmethod
def get_by_id(self, _id) -> Cat:
pass
@dataclass
class DatabaseSettings:
connection_string: str
class PostgresCatsRepository(ICatsRepository):
db_settings: DatabaseSettings
def get_by_id(self, _id) -> Cat:
# TODO: implement logic to use a connection to the db
return Cat("...")
class GetCatRequestHandler:
cats_repository: ICatsRepository
def get_cat(self, _id):
cat = self.cats_repository.get_by_id(_id)
return cat
container = Container()
container.add_instance(DatabaseSettings(connection_string="<YOUR_CONNECTION_STRING>"))
container.add_transient(ICatsRepository, PostgresCatsRepository)
container.add_exact_transient(GetCatRequestHandler)
provider = container.build_provider()
cats_repo = provider.get(ICatsRepository)
assert isinstance(cats_repo, PostgresCatsRepository)
assert isinstance(cats_repo.db_settings, DatabaseSettings)
get_cat_handler = provider.get(GetCatRequestHandler)
assert isinstance(get_cat_handler, GetCatRequestHandler)
assert isinstance(get_cat_handler.cats_repository, PostgresCatsRepository)
Consider the example below:
from abc import ABC, abstractmethod
# domain object:
class Cat:
def __init__(self, name):
self.name = name
# abstract interface
class ICatsRepository(ABC):
@abstractmethod
def get_by_id(self, _id) -> Cat:
pass
# one of the possible implementations of ICatsRepository
class InMemoryCatsRepository(ICatsRepository):
def __init__(self):
self._cats = {}
def get_by_id(self, _id) -> Cat:
return self._cats.get(_id)
# NB: example of business layer class, using interface of repository
class GetCatRequestHandler:
def __init__(self, cats_repository: ICatsRepository):
self.repo = cats_repository
rodi
configuration to obtain instances of GetCatRequestHandler
would look like this:
# (imports omitted...)
from rodi import Container
container = Container()
# configuring container...
container.add_transient(ICatsRepository, InMemoryCatsRepository)
container.add_exact_transient(GetCatRequestHandler)
# building the provider
services = container.build_provider()
# obtaining instances of container:
get_cat_handler = services.get(GetCatRequestHandler)
assert isinstance(get_cat_handler, GetCatRequestHandler)
assert isinstance(get_cat_handler.repo, InMemoryCatsRepository)
In this example, type resolution happens by parameter name, when requiring Foo
service, a new one is instantiated passing the configured singleton of Settings
to its constructor.
class Foo:
def __init__(self, settings):
self.settings = settings
class Settings:
def __init__(self, db_connection_string):
self.db_connection_string = db_connection_string
# in some other module..
from rodi import Container
container = Container()
# configuring container...
container.add_instance(Settings("whatever/connection/string"))
container.add_exact_transient(Foo)
# building the provider
services = container.build_provider()
# obtaining instances of container:
foo = services.get(Foo)
assert isinstance(foo, Foo)
assert isinstance(foo.settings, Settings)
Please look at tests code, for more examples.