@@ -13,53 +13,76 @@ class JsWebApp:
1313 The main application class for the JsWeb framework.
1414 """
1515 def __init__ (self , config ):
16+ """
17+ Initialize the JsWebApp instance.
18+
19+ :param config: Configuration object containing settings like SECRET_KEY, TEMPLATE_FOLDER, etc.
20+ """
1621 self .router = Router ()
1722 self .template_filters = {}
1823 self .config = config
1924 self .blueprints_with_static_files = []
20- self ._init_from_config () # Initial setup
25+ self ._init_from_config ()
2126
2227 def _init_from_config (self ):
2328 """Initializes components that depend on the config."""
2429 template_paths = []
2530
26- # Add the user's template folder
2731 if hasattr (self .config , "TEMPLATE_FOLDER" ) and hasattr (self .config , "BASE_DIR" ):
2832 user_template_path = os .path .join (self .config .BASE_DIR , self .config .TEMPLATE_FOLDER )
2933 if os .path .isdir (user_template_path ):
3034 template_paths .append (user_template_path )
3135
32- # Add the library's main template folder
3336 lib_template_path = os .path .join (os .path .dirname (__file__ ), "templates" )
3437 if os .path .isdir (lib_template_path ):
3538 template_paths .append (lib_template_path )
3639
37- # The admin templates are now self-contained in the admin package,
38- # so we no longer add them to the main app's template paths.
39-
4040 if template_paths :
4141 configure_template_env (template_paths )
4242
4343 if hasattr (self .config , "SECRET_KEY" ):
4444 init_auth (self .config .SECRET_KEY , self ._get_actual_user_loader ())
4545
4646 def _get_actual_user_loader (self ):
47+ """
48+ Retrieves the user loader callback.
49+
50+ :return: The user loader function.
51+ """
4752 if hasattr (self , '_user_loader_callback' ) and self ._user_loader_callback :
4853 return self ._user_loader_callback
4954 return self .user_loader
5055
5156 def user_loader (self , user_id : int ):
57+ """
58+ Default user loader that attempts to load a user from a 'models' module.
59+
60+ :param user_id: The ID of the user to load.
61+ :return: The User object or None.
62+ """
5263 try :
5364 from models import User
5465 return User .query .get (user_id )
5566 except (ImportError , AttributeError ):
5667 return None
5768
5869 def route (self , path , methods = None , endpoint = None ):
70+ """
71+ Decorator to register a new route.
72+
73+ :param path: The URL path.
74+ :param methods: List of HTTP methods allowed.
75+ :param endpoint: Optional endpoint name.
76+ :return: The decorator function.
77+ """
5978 return self .router .route (path , methods , endpoint )
6079
6180 def register_blueprint (self , blueprint : Blueprint ):
62- """Registers a blueprint with the application."""
81+ """
82+ Registers a blueprint with the application.
83+
84+ :param blueprint: The Blueprint instance to register.
85+ """
6386 for path , handler , methods , endpoint in blueprint .routes :
6487 full_path = path
6588 if blueprint .url_prefix :
@@ -72,12 +95,25 @@ def register_blueprint(self, blueprint: Blueprint):
7295 self .blueprints_with_static_files .append (blueprint )
7396
7497 def filter (self , name ):
98+ """
99+ Decorator to register a custom template filter.
100+
101+ :param name: The name of the filter to use in templates.
102+ :return: The decorator function.
103+ """
75104 def decorator (func ):
76105 self .template_filters [name ] = func
77106 return func
78107 return decorator
79108
80109 async def _asgi_app_handler (self , scope , receive , send ):
110+ """
111+ Internal ASGI handler for processing requests.
112+
113+ :param scope: The ASGI scope.
114+ :param receive: The ASGI receive channel.
115+ :param send: The ASGI send channel.
116+ """
81117 req = scope ['jsweb.request' ]
82118 try :
83119 handler , params = self .router .resolve (req .path , req .method )
@@ -95,7 +131,6 @@ async def _asgi_app_handler(self, scope, receive, send):
95131 return
96132
97133 if handler :
98- # Support both sync and async handlers
99134 if asyncio .iscoroutinefunction (handler ):
100135 response = await handler (req , ** params )
101136 else :
@@ -107,17 +142,21 @@ async def _asgi_app_handler(self, scope, receive, send):
107142 if not isinstance (response , Response ):
108143 raise TypeError (f"View function did not return a Response object (got { type (response ).__name__ } )" )
109144
110-
111-
112145 if hasattr (req , 'new_csrf_token_generated' ) and req .new_csrf_token_generated :
113146 response .set_cookie ("csrf_token" , req .csrf_token , httponly = False , samesite = 'Lax' )
114147
115148 await response (scope , receive , send )
116149
117150
118151 async def __call__ (self , scope , receive , send ):
152+ """
153+ The ASGI application entry point.
154+
155+ :param scope: The ASGI scope.
156+ :param receive: The ASGI receive channel.
157+ :param send: The ASGI send channel.
158+ """
119159 if scope ["type" ] != "http" :
120- # For now, we only support http
121160 return
122161
123162 req = Request (scope , receive , self )
@@ -136,12 +175,9 @@ async def __call__(self, scope, receive, send):
136175 static_url = getattr (self .config , "STATIC_URL" , "/static" )
137176 static_dir = getattr (self .config , "STATIC_DIR" , "static" )
138177
139- # The middleware needs to be ASGI compatible.
140- # This will require rewriting the middleware classes.
141- # For now, I will assume they are ASGI compatible.
142178 handler = self ._asgi_app_handler
143179 handler = DBSessionMiddleware (handler )
144180 handler = StaticFilesMiddleware (handler , static_url , static_dir , blueprint_statics = self .blueprints_with_static_files )
145181 handler = CSRFMiddleware (handler )
146182
147- await handler (scope , receive , send )
183+ await handler (scope , receive , send )
0 commit comments