Coverage for src/lexigram/web/routing/controllers.py: 29%
21 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
1"""Controller base class with DI support"""
3from __future__ import annotations
5from typing import Any
8class Controller:
9 """Base controller class with dependency injection support.
11 Controllers group related route handlers and can specify dependencies
12 to be injected by the DI container.
14 Example:
15 class UserController(Controller):
16 @get("/users")
17 async def list_users(self):
18 return []
19 """
21 def __init__(self) -> None:
22 # Dependencies will be injected by DI container
23 pass
25 @classmethod
26 def collect_routes(cls) -> list[dict[str, Any]]:
27 """Collect routes from controller methods.
29 It scans the class and its base classes for methods with
30 _route_config attribute and returns a list of route definitions.
32 Returns:
33 List of route dictionaries with keys: method, path, handler_name, etc.
34 """
35 routes = []
36 seen_handlers = set()
38 # Collect from MRO (Method Resolution Order) - base classes first
39 for klass in cls.__mro__:
40 if klass is Controller or klass is object:
41 continue
43 for attr_name in dir(klass):
44 if attr_name.startswith("_") or attr_name in seen_handlers:
45 continue
47 attr_value = getattr(klass, attr_name, None)
48 if attr_value is not None and hasattr(attr_value, "_route_config"):
49 route_config = attr_value._route_config
50 routes.append(
51 {
52 "method": route_config["method"],
53 "path": route_config["path"],
54 "handler_name": attr_name,
55 "response_model": route_config.get("response_model"),
56 "request_model": route_config.get("request_model"),
57 "status_code": route_config.get("status_code", 200),
58 "summary": route_config.get("summary"),
59 "description": route_config.get("description"),
60 "tags": route_config.get("tags"),
61 "operation_id": route_config.get("operation_id"),
62 "responses": route_config.get("responses"),
63 "deprecated": route_config.get("deprecated", False),
64 },
65 )
66 seen_handlers.add(attr_name)
68 return routes