Compare commits
	
		
			4 Commits
		
	
	
		
			main
			...
			pre-regist
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | c8fa52e2d2 | ||
|   | 266af1e279 | ||
|   | 6d3f1e9982 | ||
|   | a0a3840094 | 
							
								
								
									
										52
									
								
								sanic/app.py
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								sanic/app.py
									
									
									
									
									
								
							| @@ -67,6 +67,7 @@ from sanic.exceptions import ( | |||||||
|     URLBuildError, |     URLBuildError, | ||||||
| ) | ) | ||||||
| from sanic.handlers import ErrorHandler | from sanic.handlers import ErrorHandler | ||||||
|  | from sanic.helpers import Default, _default | ||||||
| from sanic.http import Stage | from sanic.http import Stage | ||||||
| from sanic.log import LOGGING_CONFIG_DEFAULTS, Colors, error_logger, logger | from sanic.log import LOGGING_CONFIG_DEFAULTS, Colors, error_logger, logger | ||||||
| from sanic.mixins.listeners import ListenerEvent | from sanic.mixins.listeners import ListenerEvent | ||||||
| @@ -536,6 +537,30 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta): | |||||||
|             blueprint.strict_slashes = self.strict_slashes |             blueprint.strict_slashes = self.strict_slashes | ||||||
|         blueprint.register(self, options) |         blueprint.register(self, options) | ||||||
|  |  | ||||||
|  |     def _register_lazy_blueprints(self): | ||||||
|  |         registry = {**Blueprint.__pre_registry__} | ||||||
|  |         if _default in Blueprint.__pre_registry__: | ||||||
|  |             if len(Sanic._app_registry) > 1: | ||||||
|  |                 raise SanicException( | ||||||
|  |                     "Ambiguous Blueprint pre-registration detected. When " | ||||||
|  |                     "there are multiple Sanic application instances, all " | ||||||
|  |                     "pre-registrations must use an application name." | ||||||
|  |                 ) | ||||||
|  |  | ||||||
|  |             if self.name in registry and _default in registry: | ||||||
|  |                 registry[_default].extend(registry.pop(self.name)) | ||||||
|  |  | ||||||
|  |             registry = { | ||||||
|  |                 self.name if k is _default else k: v | ||||||
|  |                 for k, v in registry.items() | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         for name, registrants in registry.items(): | ||||||
|  |             for reg_info in registrants: | ||||||
|  |                 blueprint = reg_info.pop("bp") | ||||||
|  |                 if name == self.name and blueprint.name not in self.blueprints: | ||||||
|  |                     self.blueprint(blueprint, **reg_info) | ||||||
|  |  | ||||||
|     def url_for(self, view_name: str, **kwargs): |     def url_for(self, view_name: str, **kwargs): | ||||||
|         """Build a URL based on a view name and the values provided. |         """Build a URL based on a view name and the values provided. | ||||||
|  |  | ||||||
| @@ -1677,6 +1702,32 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta): | |||||||
|                 return cls(name) |                 return cls(name) | ||||||
|             raise SanicException(f'Sanic app name "{name}" not found.') |             raise SanicException(f'Sanic app name "{name}" not found.') | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def lazy( | ||||||
|  |         cls, | ||||||
|  |         app_name: Union[str, Default] = _default, | ||||||
|  |         *, | ||||||
|  |         name: str = None, | ||||||
|  |         url_prefix: Optional[str] = None, | ||||||
|  |         host: Optional[Union[List[str], str]] = None, | ||||||
|  |         version: Optional[Union[int, str, float]] = None, | ||||||
|  |         strict_slashes: Optional[bool] = None, | ||||||
|  |         version_prefix: str = "/v", | ||||||
|  |     ) -> Blueprint: | ||||||
|  |         if not name: | ||||||
|  |             flat = [1 for x in Blueprint.__pre_registry__.values() for _ in x] | ||||||
|  |             name = f"bp{len(flat)}" | ||||||
|  |         bp = Blueprint( | ||||||
|  |             name=name, | ||||||
|  |             url_prefix=url_prefix, | ||||||
|  |             host=host, | ||||||
|  |             version=version, | ||||||
|  |             strict_slashes=strict_slashes, | ||||||
|  |             version_prefix=version_prefix, | ||||||
|  |         ) | ||||||
|  |         bp.pre_register(app_name) | ||||||
|  |         return bp | ||||||
|  |  | ||||||
|     # -------------------------------------------------------------------- # |     # -------------------------------------------------------------------- # | ||||||
|     # Lifecycle |     # Lifecycle | ||||||
|     # -------------------------------------------------------------------- # |     # -------------------------------------------------------------------- # | ||||||
| @@ -1697,6 +1748,7 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta): | |||||||
|  |  | ||||||
|     async def _startup(self): |     async def _startup(self): | ||||||
|         self._future_registry.clear() |         self._future_registry.clear() | ||||||
|  |         self._register_lazy_blueprints() | ||||||
|         self.signalize() |         self.signalize() | ||||||
|         self.finalize() |         self.finalize() | ||||||
|         ErrorHandler.finalize( |         ErrorHandler.finalize( | ||||||
|   | |||||||
| @@ -107,6 +107,7 @@ class Blueprint(BaseSanic): | |||||||
|         "version_prefix", |         "version_prefix", | ||||||
|         "websocket_routes", |         "websocket_routes", | ||||||
|     ) |     ) | ||||||
|  |     __pre_registry__: Dict[Union[str, Default], Any] = defaultdict(list) | ||||||
|  |  | ||||||
|     def __init__( |     def __init__( | ||||||
|         self, |         self, | ||||||
| @@ -461,3 +462,30 @@ class Blueprint(BaseSanic): | |||||||
|     ): |     ): | ||||||
|         for app in apps: |         for app in apps: | ||||||
|             app._future_registry.update(set((bp, item) for item in futures)) |             app._future_registry.update(set((bp, item) for item in futures)) | ||||||
|  |  | ||||||
|  |     def pre_register( | ||||||
|  |         self, | ||||||
|  |         name: Union[str, Default], | ||||||
|  |         url_prefix: Optional[str] = None, | ||||||
|  |         host: Optional[Union[List[str], str]] = None, | ||||||
|  |         version: Optional[Union[int, str, float]] = None, | ||||||
|  |         strict_slashes: Optional[bool] = None, | ||||||
|  |         version_prefix: Union[str, Default] = _default, | ||||||
|  |     ) -> None: | ||||||
|  |         if not hasattr(self.ctx, "_prereg"): | ||||||
|  |             self.ctx._prereg = [] | ||||||
|  |         self.ctx._prereg.append(name) | ||||||
|  |         self.__class__.__pre_registry__[name].append( | ||||||
|  |             { | ||||||
|  |                 k: v | ||||||
|  |                 for k, v in { | ||||||
|  |                     "bp": self, | ||||||
|  |                     "url_prefix": url_prefix, | ||||||
|  |                     "host": host, | ||||||
|  |                     "version": version, | ||||||
|  |                     "strict_slashes": strict_slashes, | ||||||
|  |                     "version_prefix": version_prefix, | ||||||
|  |                 }.items() | ||||||
|  |                 if v is not None and v is not _default | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|   | |||||||
| @@ -10,7 +10,9 @@ from typing import Any, List, Union | |||||||
|  |  | ||||||
| from sanic.app import Sanic | from sanic.app import Sanic | ||||||
| from sanic.application.logo import get_logo | from sanic.application.logo import get_logo | ||||||
|  | from sanic.blueprints import Blueprint | ||||||
| from sanic.cli.arguments import Group | from sanic.cli.arguments import Group | ||||||
|  | from sanic.helpers import _default | ||||||
| from sanic.log import error_logger | from sanic.log import error_logger | ||||||
| from sanic.simple import create_simple_server | from sanic.simple import create_simple_server | ||||||
|  |  | ||||||
| @@ -20,6 +22,7 @@ class SanicArgumentParser(ArgumentParser): | |||||||
|  |  | ||||||
|  |  | ||||||
| class SanicCLI: | class SanicCLI: | ||||||
|  |     DEFAULT_APP_NAME = "SANIC" | ||||||
|     DESCRIPTION = indent( |     DESCRIPTION = indent( | ||||||
|         f""" |         f""" | ||||||
| {get_logo(True)} | {get_logo(True)} | ||||||
| @@ -131,7 +134,17 @@ Or, a path to a directory to run as a simple HTTP server: | |||||||
|  |  | ||||||
|                 app_type_name = type(app).__name__ |                 app_type_name = type(app).__name__ | ||||||
|  |  | ||||||
|                 if not isinstance(app, Sanic): |                 if isinstance(app, Blueprint): | ||||||
|  |                     bp = app | ||||||
|  |                     name = ( | ||||||
|  |                         bp.ctx._prereg[0] | ||||||
|  |                         if hasattr(bp.ctx, "_prereg") | ||||||
|  |                         else _default | ||||||
|  |                     ) | ||||||
|  |                     if name is _default: | ||||||
|  |                         name = self.DEFAULT_APP_NAME | ||||||
|  |                     app = Sanic(name) | ||||||
|  |                 elif not isinstance(app, Sanic): | ||||||
|                     raise ValueError( |                     raise ValueError( | ||||||
|                         f"Module is not a Sanic app, it is a {app_type_name}\n" |                         f"Module is not a Sanic app, it is a {app_type_name}\n" | ||||||
|                         f"  Perhaps you meant {self.args.module}.app?" |                         f"  Perhaps you meant {self.args.module}.app?" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user