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+ return res
60+
61+
62+ class ControllerRouterBuilder (RouterBuilder , controller_type = type (ControllerBase )):
8163 @classmethod
8264 def build (
8365 cls ,
8466 controller_type : t .Union [t .Type [ControllerBase ], t .Any ],
8567 base_route_type : t .Type [t .Union [EllarMount , T_ ]] = EllarMount ,
8668 ** kwargs : t .Any ,
8769 ) -> t .Union [T_ , EllarMount ]:
88- routes = cls ._process_controller_routes (controller_type )
70+ routes = process_controller_routes (controller_type )
71+ routes .extend (process_nested_routes (controller_type ))
8972
9073 include_in_schema = reflect .get_metadata_or_raise_exception (
9174 CONTROLLER_METADATA .INCLUDE_IN_SCHEMA , controller_type
@@ -96,11 +79,18 @@ def build(
9679 )
9780
9881 kwargs .setdefault ("middleware" , middleware )
82+
83+ path = reflect .get_metadata_or_raise_exception (
84+ CONTROLLER_METADATA .PATH , controller_type
85+ )
86+
87+ if "prefix" in kwargs :
88+ prefix = kwargs .pop ("prefix" )
89+ path = normalize_path (f"{ prefix } /{ path } " )
90+
9991 router = base_route_type ( # type:ignore[call-arg]
10092 routes = routes ,
101- path = reflect .get_metadata_or_raise_exception (
102- CONTROLLER_METADATA .PATH , controller_type
103- ),
93+ path = path ,
10494 name = reflect .get_metadata_or_raise_exception (
10595 CONTROLLER_METADATA .NAME , controller_type
10696 ),
@@ -110,6 +100,7 @@ def build(
110100 control_type = controller_type ,
111101 ** kwargs ,
112102 )
103+ reflect .define_metadata (CONTROLLER_METADATA .PROCESSED , True , controller_type )
113104 return router
114105
115106 @classmethod
0 commit comments