python dependency injector with multiple containers

x·2024년 4월 14일
0

dependency-injection

목록 보기
1/1

https://python-dependency-injector.ets-labs.org/examples/decoupled-packages.html

런타임 의존성 : Service class -> class -> class
소스코드 의존성 : Service class <- class <- class

이렇게 클래스 간의 디커플링을 해보자. 디커플링이 잘 돼있으면 모킹이 편해지고 테스트코드에서 원하는 응답으로 바꿀 수 있어서 다양한 경우에 대해 테스트할 수 있게 된다. 의존성이 줄어들기 때문에 특정 클래스의 코드가 바뀌어도 그걸 사용하는 클래스에선 변경이 적어진다.

services/get_real_estates_on_search_service.py

from real_estate.containers.service_container import (
    ServiceContainer,
)
from dependency_injector.wiring import inject, Provide

from real_estate.services.search_real_estates import SearchRealEstates
from real_estate.services.set_real_estates import SetRealEstates


class GetRealEstatesOnSearchService:
    @inject
    def __init__(
        self,
        set_real_estate: SetRealEstates = Provide[
            ServiceContainer.set_real_estate_real_estates
        ],
        set_region: SetRealEstates = Provide[ServiceContainer.set_real_estate_regions],
        search_real_estates=Provide[ServiceContainer.search_real_estates],
    ) -> None:
        self.set_real_estate: SetRealEstates = set_real_estate
        self.set_region: SetRealEstates = set_region
        self.search_real_estates: SearchRealEstates = search_real_estates

services/set_real_estates.py

from typing import Union

from real_estate.serializers import (
    GetRealEstatesOnSearchResponseSerializer,
    GetRegionsOnSearchResponseSerializer,
)


class SetRealEstates:
    def __init__(self, serializer, key) -> None:
        self.serializer: Union[
            GetRealEstatesOnSearchResponseSerializer,
            GetRegionsOnSearchResponseSerializer,
        ] = serializer
        self.key = key

services/search_real_estates.py

from dependency_injector.wiring import inject, Provide

from manticore.manticore_client import SearchClientInterface

from real_estate.containers.search_container import SearchContainer


class SearchRealEstates:
    @inject
    def __init__(
        self,
        search_client: SearchClientInterface = Provide[SearchContainer.search_client],
    ) -> None:
        self.search_client: SearchClientInterface = search_client

containers/service_container.py

from dependency_injector import containers, providers

from manticore.manticore_client import ManticoreClient
from real_estate.containers.search_container import SearchContainer
from real_estate.serializers import (
    GetRealEstatesOnSearchResponseSerializer,
    GetRegionsOnSearchResponseSerializer,
)
from real_estate.services.search_real_estates import SearchRealEstates
from real_estate.services.set_real_estates import SetRealEstates


class ServiceContainer(containers.DeclarativeContainer):
    config = providers.Configuration()

    set_real_estate_real_estates = providers.Factory(
        provides=SetRealEstates,
        serializer=GetRealEstatesOnSearchResponseSerializer,
        key="real_estates",
    )
    set_real_estate_regions = providers.Factory(
        provides=SetRealEstates,
        serializer=GetRegionsOnSearchResponseSerializer,
        key="regions",
    )

    search_client: providers.Factory[ManticoreClient] = SearchContainer.search_client
    search_real_estates = providers.Singleton(
        provides=SearchRealEstates,
        search_client=search_client,
    )


ServiceContainer().wire(
    modules=[
        "real_estate.services.get_real_estates_on_map_service",
        "real_estate.services.get_real_estates_on_search_service",
    ]
)

containers/search_container.py

from dependency_injector import containers, providers
from manticore.manticore_client import ManticoreClient


class SearchContainer(containers.DeclarativeContainer):
    config = providers.Configuration()

    search_client = providers.Factory(provides=ManticoreClient)


SearchContainer().wire(
    modules=[
        "real_estate.views.manticore_view",
    ]
)

views/__init__.py

# 컨테이너 초기화용 import

from real_estate.containers.service_container import ServiceContainer  # noqa
from real_estate.containers.search_container import SearchContainer  # noqa

manticore/manticore_client.py

from abc import ABC, abstractmethod
import os
from typing import Any, Dict, List, Optional
import manticoresearch
import manticoresearch

from manticoresearch.api import search_api


class SearchClientInterface(ABC):
    @abstractmethod
    def run_indexer(self) -> None:
        pass

    @abstractmethod
    def search(
        self, index: str, query: dict, limit: int
    ) -> List[Optional[Dict[str, Any]]]:
        pass


class ManticoreClient(SearchClientInterface):
    def __init__(self) -> None:
        self.configuration = manticoresearch.Configuration(
            host=f"http://{os.getenv('HTTP_HOST')}:{os.getenv('HTTP_PORT')}"
        )
        self.api_client = manticoresearch.ApiClient(self.configuration)
        self.search_api = search_api.SearchApi(self.api_client)

0개의 댓글