refactor(routes): add registrar for example images

This commit is contained in:
pixelpaws
2025-09-23 11:12:05 +08:00
parent e0aba6c49a
commit 613cd81152
3 changed files with 106 additions and 17 deletions

View File

@@ -0,0 +1,61 @@
"""Route registrar for example image endpoints."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Callable, Iterable, Mapping
from aiohttp import web
@dataclass(frozen=True)
class RouteDefinition:
"""Declarative configuration for a HTTP route."""
method: str
path: str
handler_name: str
ROUTE_DEFINITIONS: tuple[RouteDefinition, ...] = (
RouteDefinition("POST", "/api/lm/download-example-images", "download_example_images"),
RouteDefinition("POST", "/api/lm/import-example-images", "import_example_images"),
RouteDefinition("GET", "/api/lm/example-images-status", "get_example_images_status"),
RouteDefinition("POST", "/api/lm/pause-example-images", "pause_example_images"),
RouteDefinition("POST", "/api/lm/resume-example-images", "resume_example_images"),
RouteDefinition("POST", "/api/lm/open-example-images-folder", "open_example_images_folder"),
RouteDefinition("GET", "/api/lm/example-image-files", "get_example_image_files"),
RouteDefinition("GET", "/api/lm/has-example-images", "has_example_images"),
RouteDefinition("POST", "/api/lm/delete-example-image", "delete_example_image"),
RouteDefinition("POST", "/api/lm/force-download-example-images", "force_download_example_images"),
)
class ExampleImagesRouteRegistrar:
"""Bind declarative example image routes to an aiohttp router."""
_METHOD_MAP = {
"GET": "add_get",
"POST": "add_post",
"PUT": "add_put",
"DELETE": "add_delete",
}
def __init__(self, app: web.Application) -> None:
self._app = app
def register_routes(
self,
handler_lookup: Mapping[str, Callable[[web.Request], object]],
*,
definitions: Iterable[RouteDefinition] = ROUTE_DEFINITIONS,
) -> None:
"""Register each route definition using the supplied handlers."""
for definition in definitions:
handler = handler_lookup[definition.handler_name]
self._bind_route(definition.method, definition.path, handler)
def _bind_route(self, method: str, path: str, handler: Callable[[web.Request], object]) -> None:
add_method_name = self._METHOD_MAP[method.upper()]
add_method = getattr(self._app.router, add_method_name)
add_method(path, handler)

View File

@@ -1,4 +1,9 @@
import logging import logging
from typing import Callable
from aiohttp import web
from .example_images_route_registrar import ExampleImagesRouteRegistrar
from ..utils.example_images_download_manager import DownloadManager from ..utils.example_images_download_manager import DownloadManager
from ..utils.example_images_processor import ExampleImagesProcessor from ..utils.example_images_processor import ExampleImagesProcessor
from ..utils.example_images_file_manager import ExampleImagesFileManager from ..utils.example_images_file_manager import ExampleImagesFileManager
@@ -6,22 +11,31 @@ from ..services.websocket_manager import ws_manager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class ExampleImagesRoutes: class ExampleImagesRoutes:
"""Routes for example images related functionality""" """Routes for example images related functionality"""
@staticmethod @staticmethod
def setup_routes(app): def setup_routes(app: web.Application) -> None:
"""Register example images routes""" """Register example images routes using the registrar."""
app.router.add_post('/api/lm/download-example-images', ExampleImagesRoutes.download_example_images)
app.router.add_post('/api/lm/import-example-images', ExampleImagesRoutes.import_example_images) registrar = ExampleImagesRouteRegistrar(app)
app.router.add_get('/api/lm/example-images-status', ExampleImagesRoutes.get_example_images_status) registrar.register_routes(ExampleImagesRoutes._route_mapping())
app.router.add_post('/api/lm/pause-example-images', ExampleImagesRoutes.pause_example_images)
app.router.add_post('/api/lm/resume-example-images', ExampleImagesRoutes.resume_example_images) @staticmethod
app.router.add_post('/api/lm/open-example-images-folder', ExampleImagesRoutes.open_example_images_folder) def _route_mapping() -> dict[str, Callable[[web.Request], object]]:
app.router.add_get('/api/lm/example-image-files', ExampleImagesRoutes.get_example_image_files) return {
app.router.add_get('/api/lm/has-example-images', ExampleImagesRoutes.has_example_images) "download_example_images": ExampleImagesRoutes.download_example_images,
app.router.add_post('/api/lm/delete-example-image', ExampleImagesRoutes.delete_example_image) "import_example_images": ExampleImagesRoutes.import_example_images,
app.router.add_post('/api/lm/force-download-example-images', ExampleImagesRoutes.force_download_example_images) "get_example_images_status": ExampleImagesRoutes.get_example_images_status,
"pause_example_images": ExampleImagesRoutes.pause_example_images,
"resume_example_images": ExampleImagesRoutes.resume_example_images,
"open_example_images_folder": ExampleImagesRoutes.open_example_images_folder,
"get_example_image_files": ExampleImagesRoutes.get_example_image_files,
"has_example_images": ExampleImagesRoutes.has_example_images,
"delete_example_image": ExampleImagesRoutes.delete_example_image,
"force_download_example_images": ExampleImagesRoutes.force_download_example_images,
}
@staticmethod @staticmethod
async def download_example_images(request): async def download_example_images(request):
@@ -42,7 +56,7 @@ class ExampleImagesRoutes:
async def resume_example_images(request): async def resume_example_images(request):
"""Resume the example images download""" """Resume the example images download"""
return await DownloadManager.resume_download(request) return await DownloadManager.resume_download(request)
@staticmethod @staticmethod
async def open_example_images_folder(request): async def open_example_images_folder(request):
"""Open the example images folder for a specific model""" """Open the example images folder for a specific model"""
@@ -57,7 +71,7 @@ class ExampleImagesRoutes:
async def import_example_images(request): async def import_example_images(request):
"""Import local example images for a model""" """Import local example images for a model"""
return await ExampleImagesProcessor.import_images(request) return await ExampleImagesProcessor.import_images(request)
@staticmethod @staticmethod
async def has_example_images(request): async def has_example_images(request):
"""Check if example images folder exists and is not empty for a model""" """Check if example images folder exists and is not empty for a model"""
@@ -71,4 +85,4 @@ class ExampleImagesRoutes:
@staticmethod @staticmethod
async def force_download_example_images(request): async def force_download_example_images(request):
"""Force download example images for specific models""" """Force download example images for specific models"""
return await DownloadManager.start_force_download(request) return await DownloadManager.start_force_download(request)

View File

@@ -1,6 +1,6 @@
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any, List, Tuple from typing import Any, List, Set, Tuple
from aiohttp import web from aiohttp import web
from aiohttp.test_utils import TestClient, TestServer from aiohttp.test_utils import TestClient, TestServer
@@ -8,6 +8,7 @@ import pytest
from py.routes import example_images_routes from py.routes import example_images_routes
from py.routes.example_images_routes import ExampleImagesRoutes from py.routes.example_images_routes import ExampleImagesRoutes
from py.routes.example_images_route_registrar import ROUTE_DEFINITIONS
@dataclass @dataclass
@@ -110,6 +111,19 @@ async def example_images_app(monkeypatch: pytest.MonkeyPatch) -> ExampleImagesHa
await client.close() await client.close()
async def test_setup_routes_registers_all_definitions(monkeypatch: pytest.MonkeyPatch):
async with example_images_app(monkeypatch) as harness:
registered: Set[tuple[str, str]] = {
(route.method, route.resource.canonical)
for route in harness.client.app.router.routes()
if route.resource.canonical
}
expected = {(definition.method, definition.path) for definition in ROUTE_DEFINITIONS}
assert expected <= registered
@pytest.mark.parametrize( @pytest.mark.parametrize(
"endpoint, payload", "endpoint, payload",
[ [