11import inspect
2- import copy
2+ from copy import deepcopy
33from fastapi import APIRouter , Depends
4+ from fastapi_router_controller .lib .exceptions import MultipleResourceException , MultipleRouterException
45
56OPEN_API_TAGS = []
67__app_controllers__ = []
@@ -35,22 +36,29 @@ class Controller:
3536
3637 It expose some utilities and decorator functions to define a router controller class
3738 """
38-
39- RC_KEY = "__router__"
40- SIGNATURE_KEY = "__signature__"
39+ RC_KEY = '__router__'
40+ SIGNATURE_KEY = '__signature__'
41+ HAS_CONTROLLER_KEY = '__has_controller__'
42+ RESOURCE_CLASS_KEY = '__resource_cls__'
4143
4244 def __init__ (self , router : APIRouter , openapi_tag : dict = None ) -> None :
4345 """
4446 :param router: The FastApi router to link to the Class
4547 :param openapi_tag: An openapi object that will describe your routes in the openapi tamplate
4648 """
47- self .router = copy .deepcopy (router )
49+ # Each Controller must be linked to one fastapi router
50+ if hasattr (router , Controller .HAS_CONTROLLER_KEY ):
51+ raise MultipleRouterException ()
52+
53+ self .router = deepcopy (router )
4854 self .openapi_tag = openapi_tag
4955 self .cls = None
5056
5157 if openapi_tag :
5258 OPEN_API_TAGS .append (openapi_tag )
5359
60+ setattr (router , Controller .HAS_CONTROLLER_KEY , True )
61+
5462 def __get_parent_routes (self , router : APIRouter ):
5563 """
5664 Private utility to get routes from an extended class
@@ -65,14 +73,21 @@ def __get_parent_routes(self, router: APIRouter):
6573 self .router .add_api_route (route .path , route .endpoint , ** options )
6674
6775 def add_resource (self , cls ):
68- if self .cls and cls != self .cls :
69- raise Exception ("Every controller needs its own router!" )
70- self .cls = cls
71- # check if cls was extended from another Controller
76+ '''
77+ Mark a class as Controller Resource
78+ '''
79+ # check if the same controller was already used for another cls (Resource)
80+ if hasattr (self , Controller .RESOURCE_CLASS_KEY ) and getattr (self , Controller .RESOURCE_CLASS_KEY ) != cls :
81+ raise MultipleResourceException ()
82+
83+ # check if cls (Resource) was exteded from another
7284 if hasattr (cls , Controller .RC_KEY ):
7385 self .__get_parent_routes (cls .__router__ )
74- cls .__router__ = self .router
86+
87+ setattr (cls , Controller .RC_KEY , self .router )
88+ setattr (self , Controller .RESOURCE_CLASS_KEY , cls )
7589 cls .router = lambda : Controller .__parse_controller_router (cls )
90+
7691 return cls
7792
7893 def resource (self ):
@@ -101,28 +116,31 @@ def __parse_controller_router(cls):
101116
102117 dependencies = None
103118 if hasattr (cls , "dependencies" ):
104- dependencies = copy . deepcopy (cls .dependencies )
119+ dependencies = deepcopy (cls .dependencies )
105120 delattr (cls , "dependencies" )
106121
107122 for route in router .routes :
108- # get the signature of the endpoint function
109- signature = inspect .signature (route .endpoint )
110- # get the parameters of the endpoint function
111- signature_parameters = list (signature .parameters .values ())
112123 # add class dependencies
113124 if dependencies :
114125 for depends in dependencies [::- 1 ]:
115126 route .dependencies .insert (0 , depends )
127+
128+ # get the signature of the endpoint function
129+ signature = inspect .signature (route .endpoint )
130+ # get the parameters of the endpoint function
131+ signature_parameters = list (signature .parameters .values ())
116132
117133 # replace the class instance with the itself FastApi Dependecy
118134 signature_parameters [0 ] = signature_parameters [0 ].replace (
119135 default = Depends (cls )
120136 )
137+
121138 # set self and after it the keyword args
122139 new_parameters = [signature_parameters [0 ]] + [
123140 parameter .replace (kind = inspect .Parameter .KEYWORD_ONLY )
124141 for parameter in signature_parameters [1 :]
125142 ]
143+
126144 new_signature = signature .replace (parameters = new_parameters )
127145 setattr (route .endpoint , Controller .SIGNATURE_KEY , new_signature )
128146
0 commit comments