mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 07:05:43 -03:00
refactor(routes): split recipe handlers into dedicated classes
This commit is contained in:
@@ -11,6 +11,15 @@ from ..config import config
|
|||||||
from ..services.server_i18n import server_i18n
|
from ..services.server_i18n import server_i18n
|
||||||
from ..services.service_registry import ServiceRegistry
|
from ..services.service_registry import ServiceRegistry
|
||||||
from ..services.settings_manager import settings
|
from ..services.settings_manager import settings
|
||||||
|
from .handlers.recipe_handlers import (
|
||||||
|
RecipeAnalysisHandler,
|
||||||
|
RecipeHandlerSet,
|
||||||
|
RecipeListingHandler,
|
||||||
|
RecipeManagementHandler,
|
||||||
|
RecipePageView,
|
||||||
|
RecipeQueryHandler,
|
||||||
|
RecipeSharingHandler,
|
||||||
|
)
|
||||||
from .recipe_route_registrar import ROUTE_DEFINITIONS
|
from .recipe_route_registrar import ROUTE_DEFINITIONS
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -23,6 +32,8 @@ class BaseRecipeRoutes:
|
|||||||
definition.handler_name for definition in ROUTE_DEFINITIONS
|
definition.handler_name for definition in ROUTE_DEFINITIONS
|
||||||
)
|
)
|
||||||
|
|
||||||
|
template_name: str = "recipes.html"
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.recipe_scanner = None
|
self.recipe_scanner = None
|
||||||
self.lora_scanner = None
|
self.lora_scanner = None
|
||||||
@@ -36,6 +47,7 @@ class BaseRecipeRoutes:
|
|||||||
|
|
||||||
self._i18n_registered = False
|
self._i18n_registered = False
|
||||||
self._startup_hooks_registered = False
|
self._startup_hooks_registered = False
|
||||||
|
self._handler_set: RecipeHandlerSet | None = None
|
||||||
self._handler_mapping: dict[str, Callable] | None = None
|
self._handler_mapping: dict[str, Callable] | None = None
|
||||||
|
|
||||||
async def attach_dependencies(self, app: web.Application | None = None) -> None:
|
async def attach_dependencies(self, app: web.Application | None = None) -> None:
|
||||||
@@ -81,10 +93,9 @@ class BaseRecipeRoutes:
|
|||||||
"""Return a mapping of handler name to coroutine for registrar binding."""
|
"""Return a mapping of handler name to coroutine for registrar binding."""
|
||||||
|
|
||||||
if self._handler_mapping is None:
|
if self._handler_mapping is None:
|
||||||
owner = self.get_handler_owner()
|
handler_set = self._create_handler_set()
|
||||||
self._handler_mapping = {
|
self._handler_set = handler_set
|
||||||
name: getattr(owner, name) for name in self._HANDLER_NAMES
|
self._handler_mapping = handler_set.to_route_mapping()
|
||||||
}
|
|
||||||
return self._handler_mapping
|
return self._handler_mapping
|
||||||
|
|
||||||
# Internal helpers -------------------------------------------------
|
# Internal helpers -------------------------------------------------
|
||||||
@@ -105,5 +116,57 @@ class BaseRecipeRoutes:
|
|||||||
def get_handler_owner(self):
|
def get_handler_owner(self):
|
||||||
"""Return the object supplying bound handler coroutines."""
|
"""Return the object supplying bound handler coroutines."""
|
||||||
|
|
||||||
return self
|
if self._handler_set is None:
|
||||||
|
self._handler_set = self._create_handler_set()
|
||||||
|
return self._handler_set
|
||||||
|
|
||||||
|
def _create_handler_set(self) -> RecipeHandlerSet:
|
||||||
|
recipe_scanner_getter = lambda: self.recipe_scanner
|
||||||
|
civitai_client_getter = lambda: self.civitai_client
|
||||||
|
|
||||||
|
page_view = RecipePageView(
|
||||||
|
ensure_dependencies_ready=self.ensure_dependencies_ready,
|
||||||
|
settings_service=self.settings,
|
||||||
|
server_i18n=self.server_i18n,
|
||||||
|
template_env=self.template_env,
|
||||||
|
template_name=self.template_name,
|
||||||
|
recipe_scanner_getter=recipe_scanner_getter,
|
||||||
|
logger=logger,
|
||||||
|
)
|
||||||
|
listing = RecipeListingHandler(
|
||||||
|
ensure_dependencies_ready=self.ensure_dependencies_ready,
|
||||||
|
recipe_scanner_getter=recipe_scanner_getter,
|
||||||
|
logger=logger,
|
||||||
|
)
|
||||||
|
query = RecipeQueryHandler(
|
||||||
|
ensure_dependencies_ready=self.ensure_dependencies_ready,
|
||||||
|
recipe_scanner_getter=recipe_scanner_getter,
|
||||||
|
format_recipe_file_url=listing.format_recipe_file_url,
|
||||||
|
logger=logger,
|
||||||
|
)
|
||||||
|
management = RecipeManagementHandler(
|
||||||
|
ensure_dependencies_ready=self.ensure_dependencies_ready,
|
||||||
|
recipe_scanner_getter=recipe_scanner_getter,
|
||||||
|
logger=logger,
|
||||||
|
)
|
||||||
|
analysis = RecipeAnalysisHandler(
|
||||||
|
ensure_dependencies_ready=self.ensure_dependencies_ready,
|
||||||
|
recipe_scanner_getter=recipe_scanner_getter,
|
||||||
|
civitai_client_getter=civitai_client_getter,
|
||||||
|
logger=logger,
|
||||||
|
)
|
||||||
|
sharing = RecipeSharingHandler(
|
||||||
|
ensure_dependencies_ready=self.ensure_dependencies_ready,
|
||||||
|
recipe_scanner_getter=recipe_scanner_getter,
|
||||||
|
logger=logger,
|
||||||
|
)
|
||||||
|
|
||||||
|
return RecipeHandlerSet(
|
||||||
|
page_view=page_view,
|
||||||
|
listing=listing,
|
||||||
|
query=query,
|
||||||
|
management=management,
|
||||||
|
analysis=analysis,
|
||||||
|
sharing=sharing,
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
1347
py/routes/handlers/recipe_handlers.py
Normal file
1347
py/routes/handlers/recipe_handlers.py
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -128,31 +128,38 @@ def test_register_startup_hooks_appends_once():
|
|||||||
assert len(startup_bound_to_routes) == 2
|
assert len(startup_bound_to_routes) == 2
|
||||||
|
|
||||||
|
|
||||||
def test_to_route_mapping_uses_handler_owner(monkeypatch: pytest.MonkeyPatch):
|
def test_to_route_mapping_uses_handler_set():
|
||||||
class DummyOwner:
|
class DummyHandlerSet:
|
||||||
async def render_page(self, request):
|
def __init__(self):
|
||||||
return web.Response(text="ok")
|
self.calls = 0
|
||||||
|
|
||||||
async def list_recipes(self, request): # pragma: no cover - invoked via mapping
|
def to_route_mapping(self):
|
||||||
return web.json_response({})
|
self.calls += 1
|
||||||
|
|
||||||
|
async def render_page(request): # pragma: no cover - simple coroutine
|
||||||
|
return web.Response(text="ok")
|
||||||
|
|
||||||
|
return {"render_page": render_page}
|
||||||
|
|
||||||
class DummyRoutes(base_routes_module.BaseRecipeRoutes):
|
class DummyRoutes(base_routes_module.BaseRecipeRoutes):
|
||||||
def get_handler_owner(self): # noqa: D401 - simple override for test
|
def __init__(self):
|
||||||
return DummyOwner()
|
super().__init__()
|
||||||
|
self.created = 0
|
||||||
|
|
||||||
monkeypatch.setattr(
|
def _create_handler_set(self): # noqa: D401 - simple override for test
|
||||||
base_routes_module.BaseRecipeRoutes,
|
self.created += 1
|
||||||
"_HANDLER_NAMES",
|
return DummyHandlerSet()
|
||||||
("render_page", "list_recipes"),
|
|
||||||
)
|
|
||||||
|
|
||||||
routes = DummyRoutes()
|
routes = DummyRoutes()
|
||||||
mapping = routes.to_route_mapping()
|
mapping = routes.to_route_mapping()
|
||||||
|
|
||||||
assert set(mapping.keys()) == {"render_page", "list_recipes"}
|
assert set(mapping.keys()) == {"render_page"}
|
||||||
assert asyncio.iscoroutinefunction(mapping["render_page"])
|
assert asyncio.iscoroutinefunction(mapping["render_page"])
|
||||||
# Cached mapping reused on subsequent calls
|
# Cached mapping reused on subsequent calls
|
||||||
assert routes.to_route_mapping() is mapping
|
assert routes.to_route_mapping() is mapping
|
||||||
|
# Handler set cached for get_handler_owner callers
|
||||||
|
assert isinstance(routes.get_handler_owner(), DummyHandlerSet)
|
||||||
|
assert routes.created == 1
|
||||||
|
|
||||||
|
|
||||||
def test_recipe_route_registrar_binds_every_route():
|
def test_recipe_route_registrar_binds_every_route():
|
||||||
|
|||||||
Reference in New Issue
Block a user