saas_api/actions/dynamic_import/service_factory.py

64 lines
2.2 KiB
Python

import importlib
import re
from functools import lru_cache
from typing import Type, TypeVar, Optional
from actions.config.config import Config
from actions.env.env_config_loader import EnvConfigLoader
# Genérico para garantir que o retorno respeite o Protocolo
T = TypeVar("T")
class ServiceFactory:
def __init__(self, package: str, table: str):
# Instancia o loader com o prefixo correto
env = EnvConfigLoader(".env")
# Ex: "packages.v1"
self.base_root = "packages.v1"
self.package = package
self.table = table
# Carrega config apenas uma vez
self.app_config = Config.get("app.json")
# Define a UF da aplicação
self.current_state = env.ORIUS_CLIENT_STATE
@lru_cache(maxsize=32)
def make(self, class_name: str, interface: Type[T]) -> T:
"""
Instancia um serviço dinamicamente com comportamento de Autoload.
"""
# 1. Converte CamelCase para snake_case (Autoload style)
# Ex: TAtoIndexService -> t_ato_index_service
module_name = re.sub(r"(?<!^)(?=[A-Z])", "_", class_name).lower()
# 2. Monta o caminho completo
# Ex: packages.v1.servicos.balcao.services.t_ato.SP.t_ato_index_service
import_path = (
f"{self.base_root}.{self.package}.services."
f"{self.table}.{self.current_state}.{module_name}"
)
try:
# 3. Importação Dinâmica
module = importlib.import_module(import_path)
# 4. Pega a classe do módulo
clazz = getattr(module, class_name)
# 5. Retorna a INSTÂNCIA da classe (já com () )
# Se seus serviços precisam de argumentos no __init__, altere aqui.
return clazz()
except ImportError as e:
raise ImportError(
f"FATAL: Não foi possível carregar o serviço '{class_name}' para o estado '{self.current_state}'.\nCaminho tentado: {import_path}\nErro: {e}"
)
except AttributeError:
raise AttributeError(
f"FATAL: O arquivo '{module_name}.py' existe, mas a classe '{class_name}' não foi encontrada dentro dele."
)