Compare commits
	
		
			4 Commits
		
	
	
		
			v21.12.2
			...
			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, | ||||
| ) | ||||
| from sanic.handlers import ErrorHandler | ||||
| from sanic.helpers import Default, _default | ||||
| from sanic.http import Stage | ||||
| from sanic.log import LOGGING_CONFIG_DEFAULTS, Colors, error_logger, logger | ||||
| from sanic.mixins.listeners import ListenerEvent | ||||
| @@ -536,6 +537,30 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta): | ||||
|             blueprint.strict_slashes = self.strict_slashes | ||||
|         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): | ||||
|         """Build a URL based on a view name and the values provided. | ||||
|  | ||||
| @@ -1677,6 +1702,32 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta): | ||||
|                 return cls(name) | ||||
|             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 | ||||
|     # -------------------------------------------------------------------- # | ||||
| @@ -1697,6 +1748,7 @@ class Sanic(BaseSanic, metaclass=TouchUpMeta): | ||||
|  | ||||
|     async def _startup(self): | ||||
|         self._future_registry.clear() | ||||
|         self._register_lazy_blueprints() | ||||
|         self.signalize() | ||||
|         self.finalize() | ||||
|         ErrorHandler.finalize( | ||||
|   | ||||
| @@ -107,6 +107,7 @@ class Blueprint(BaseSanic): | ||||
|         "version_prefix", | ||||
|         "websocket_routes", | ||||
|     ) | ||||
|     __pre_registry__: Dict[Union[str, Default], Any] = defaultdict(list) | ||||
|  | ||||
|     def __init__( | ||||
|         self, | ||||
| @@ -461,3 +462,30 @@ class Blueprint(BaseSanic): | ||||
|     ): | ||||
|         for app in apps: | ||||
|             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.application.logo import get_logo | ||||
| from sanic.blueprints import Blueprint | ||||
| from sanic.cli.arguments import Group | ||||
| from sanic.helpers import _default | ||||
| from sanic.log import error_logger | ||||
| from sanic.simple import create_simple_server | ||||
|  | ||||
| @@ -20,6 +22,7 @@ class SanicArgumentParser(ArgumentParser): | ||||
|  | ||||
|  | ||||
| class SanicCLI: | ||||
|     DEFAULT_APP_NAME = "SANIC" | ||||
|     DESCRIPTION = indent( | ||||
|         f""" | ||||
| {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__ | ||||
|  | ||||
|                 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( | ||||
|                         f"Module is not a Sanic app, it is a {app_type_name}\n" | ||||
|                         f"  Perhaps you meant {self.args.module}.app?" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user