11import typing as t
22from abc import ABC , abstractmethod
33
4- from ellar .common .compatible import cached_property
4+ from ellar .common .compatible import AttributeDict , cached_property
55from ellar .common .constants import (
66 GUARDS_KEY ,
77 METHODS_WITH_BODY ,
1919from ellar .common .shortcuts import normalize_path
2020from ellar .core .routing import EllarMount , RouteOperation
2121from ellar .core .services .reflector import reflector
22- from ellar .openapi .constants import IGNORE_CONTROLLER_TYPE , OPENAPI_OPERATION_KEY
22+ from ellar .openapi .constants import (
23+ IGNORE_CONTROLLER_TYPE ,
24+ OPENAPI_OPERATION_KEY ,
25+ OPENAPI_TAG ,
26+ )
2327from ellar .pydantic import (
2428 JsonSchemaValue ,
2529 ModelField ,
@@ -55,27 +59,33 @@ class OpenAPIMountDocumentation(OpenAPIRoute):
5559 def __init__ (
5660 self ,
5761 mount : t .Union [EllarMount , Mount ],
62+ global_route_models_update : t .Callable [
63+ ["OpenAPIMountDocumentation" , t .Dict ], t .Any
64+ ],
5865 name : t .Optional [str ] = None ,
5966 global_guards : t .Optional [
6067 t .List [t .Union [t .Type ["GuardCanActivate" ], "GuardCanActivate" ]]
6168 ] = None ,
69+ path_prefix : t .Optional [str ] = None ,
6270 ) -> None :
6371 self .tag = name
6472 self .mount = mount
6573 self .path_regex , self .path_format , self .param_convertors = compile_path (
66- self .mount .path
74+ normalize_path (f"/{ path_prefix } /{ mount .path } " )
75+ if path_prefix
76+ else mount .path
6777 )
6878 # if there is some convertor on ModuleMount Object, then we need to convert it to ModelField
6979 self .global_route_parameters : t .List [ModelField ] = [
7080 EndpointArgsModel .get_convertor_model_field (name , convertor )
7181 for name , convertor in self .param_convertors .items ()
7282 ]
7383 self .global_guards = global_guards or []
74-
75- self ._routes : t .List ["OpenAPIRouteDocumentation" ] = self ._build_routes ()
84+ self . _global_route_models_update = global_route_models_update
85+ self .routes : t .List ["OpenAPIRouteDocumentation" ] = self ._build_routes ()
7686
7787 def _build_routes (self ) -> t .List ["OpenAPIRouteDocumentation" ]:
78- _routes : t .List [OpenAPIRouteDocumentation ] = []
88+ routes : t .List [OpenAPIRouteDocumentation ] = []
7989
8090 for route in self .mount .routes :
8191 if isinstance (route , RouteOperation ) and route .include_in_schema :
@@ -85,20 +95,40 @@ def _build_routes(self) -> t.List["OpenAPIRouteDocumentation"]:
8595 if not openapi .get ("tags" , False ):
8696 openapi .update (tags = [self .tag ] if self .tag else ["default" ])
8797
88- _routes .append (
98+ routes .append (
8999 OpenAPIRouteDocumentation (
90100 route = route ,
91101 global_route_parameters = self .global_route_parameters ,
92102 guards = guards or self .global_guards ,
93103 ** openapi ,
94104 )
95105 )
96- return _routes
106+ elif isinstance (route , EllarMount ):
107+ openapi_tags = AttributeDict (
108+ reflector .get (OPENAPI_TAG , route .get_control_type ()) or {}
109+ )
110+
111+ if route .name :
112+ openapi_tags .setdefault ("name" , route .name )
113+
114+ guards = reflector .get (GUARDS_KEY , route .get_control_type ())
115+
116+ self ._global_route_models_update (
117+ OpenAPIMountDocumentation (
118+ mount = route ,
119+ global_guards = guards or self .global_guards ,
120+ name = openapi_tags .name ,
121+ global_route_models_update = self ._global_route_models_update ,
122+ path_prefix = self .path_format ,
123+ ),
124+ openapi_tags ,
125+ )
126+ return routes
97127
98128 @cached_property
99129 def _openapi_models (self ) -> t .List [ModelField ]:
100130 _models = []
101- for route in self ._routes :
131+ for route in self .routes :
102132 _models .extend (route .get_route_models ())
103133 return _models
104134
@@ -121,7 +151,7 @@ def get_openapi_path(
121151 if path_prefix
122152 else self .path_format
123153 )
124- for openapi_route in self ._routes :
154+ for openapi_route in self .routes :
125155 openapi_route .get_openapi_path (
126156 paths = paths ,
127157 security_schemes = security_schemes ,
0 commit comments