1- import inspect
21import typing as t
32
43from ellar .common .constants import (
54 CONTROLLER_METADATA ,
65 CONTROLLER_OPERATION_HANDLER_KEY ,
76 CONTROLLER_WATERMARK ,
8- OPERATION_ENDPOINT_KEY ,
97 ROUTE_OPERATION_PARAMETERS ,
108)
119from ellar .common .logging import logger
12- from ellar .common .models import ControllerBase , ControllerType
10+ from ellar .common .models . controller import ControllerBase , ControllerType
1311from ellar .common .operations import RouteParameters , WsRouteParameters
12+ from ellar .common .shortcuts import normalize_path
1413from ellar .core .routing import (
1514 ControllerRouteOperation ,
1615 ControllerWebsocketRouteOperation ,
2019from starlette .routing import BaseRoute
2120
2221from .base import RouterBuilder
22+ from .utils import get_route_functions , process_nested_routes
2323
2424T_ = t .TypeVar ("T_" )
2525
2626
27- class ControllerRouterBuilder (RouterBuilder , controller_type = type (ControllerBase )):
28- @classmethod
29- def _get_route_functions (
30- cls ,
31- klass : t .Type ,
32- ) -> t .Iterable [t .Callable ]:
33- for _method_name , method in inspect .getmembers (
34- klass , predicate = inspect .isfunction
35- ):
36- if hasattr (method , OPERATION_ENDPOINT_KEY ):
37- yield method
27+ def process_controller_routes (controller : t .Type [ControllerBase ]) -> t .List [BaseRoute ]:
28+ res : t .List [BaseRoute ] = []
3829
39- @classmethod
40- def _process_controller_routes (
41- cls , controller : t .Type [ControllerBase ]
42- ) -> t .Sequence [BaseRoute ]:
43- res = []
44-
45- if reflect .get_metadata (CONTROLLER_METADATA .PROCESSED , controller ):
46- return (
47- reflect .get_metadata (CONTROLLER_OPERATION_HANDLER_KEY , controller ) or []
48- )
30+ if reflect .get_metadata (CONTROLLER_METADATA .PROCESSED , controller ):
31+ return reflect .get_metadata (CONTROLLER_OPERATION_HANDLER_KEY , controller ) or []
4932
50- for item in cls ._get_route_functions (controller ):
51- parameters = item .__dict__ [ROUTE_OPERATION_PARAMETERS ]
52- operation : t .Union [
53- ControllerRouteOperation , ControllerWebsocketRouteOperation
54- ]
55-
56- if not isinstance (parameters , list ):
57- parameters = [parameters ]
58-
59- for parameter in parameters :
60- if isinstance (parameter , RouteParameters ):
61- operation = ControllerRouteOperation (controller , ** parameter .dict ())
62- elif isinstance (parameter , WsRouteParameters ):
63- operation = ControllerWebsocketRouteOperation (
64- controller , ** parameter .dict ()
65- )
66- else : # pragma: no cover
67- logger .warning (
68- f"Parameter type is not recognized. { type (parameter ) if not isinstance (parameter , type ) else parameter } "
69- )
70- continue
71-
72- reflect .define_metadata (
73- CONTROLLER_OPERATION_HANDLER_KEY ,
74- [operation ],
75- controller ,
33+ for _ , item in get_route_functions (controller ):
34+ parameters = item .__dict__ [ROUTE_OPERATION_PARAMETERS ]
35+ operation : t .Union [ControllerRouteOperation , ControllerWebsocketRouteOperation ]
36+
37+ if not isinstance (parameters , list ):
38+ parameters = [parameters ]
39+
40+ for parameter in parameters :
41+ if isinstance (parameter , RouteParameters ):
42+ operation = ControllerRouteOperation (controller , ** parameter .dict ())
43+ elif isinstance (parameter , WsRouteParameters ):
44+ operation = ControllerWebsocketRouteOperation (
45+ controller , ** parameter .dict ()
7646 )
77- res .append (operation )
78- reflect .define_metadata (CONTROLLER_METADATA .PROCESSED , True , controller )
79- return res
47+ else : # pragma: no cover
48+ logger .warning (
49+ f"Parameter type is not recognized. { type (parameter ) if not isinstance (parameter , type ) else parameter } "
50+ )
51+ continue
8052
53+ reflect .define_metadata (
54+ CONTROLLER_OPERATION_HANDLER_KEY ,
55+ [operation ],
56+ controller ,
57+ )
58+ res .append (operation )
59+ reflect .define_metadata (CONTROLLER_METADATA .PROCESSED , True , controller )
60+ return res
61+
62+
63+ class ControllerRouterBuilder (RouterBuilder , controller_type = type (ControllerBase )):
8164 @classmethod
8265 def build (
8366 cls ,
8467 controller_type : t .Union [t .Type [ControllerBase ], t .Any ],
8568 base_route_type : t .Type [t .Union [EllarMount , T_ ]] = EllarMount ,
8669 ** kwargs : t .Any ,
8770 ) -> t .Union [T_ , EllarMount ]:
88- routes = cls ._process_controller_routes (controller_type )
71+ routes = process_controller_routes (controller_type )
72+ routes .extend (process_nested_routes (controller_type ))
8973
9074 include_in_schema = reflect .get_metadata_or_raise_exception (
9175 CONTROLLER_METADATA .INCLUDE_IN_SCHEMA , controller_type
@@ -96,11 +80,18 @@ def build(
9680 )
9781
9882 kwargs .setdefault ("middleware" , middleware )
83+
84+ path = reflect .get_metadata_or_raise_exception (
85+ CONTROLLER_METADATA .PATH , controller_type
86+ )
87+
88+ if "prefix" in kwargs :
89+ prefix = kwargs .pop ("prefix" )
90+ path = normalize_path (f"{ prefix } /{ path } " )
91+
9992 router = base_route_type ( # type:ignore[call-arg]
10093 routes = routes ,
101- path = reflect .get_metadata_or_raise_exception (
102- CONTROLLER_METADATA .PATH , controller_type
103- ),
94+ path = path ,
10495 name = reflect .get_metadata_or_raise_exception (
10596 CONTROLLER_METADATA .NAME , controller_type
10697 ),
0 commit comments