from aiosignal import Signal from frozenlist import FrozenList
from . import hdrs from .abc import (
AbstractAccessLogger,
AbstractMatchInfo,
AbstractRouter,
AbstractStreamWriter,
) from .helpers import DEBUG, AppKey from .http_parser import RawRequestMessage from .log import web_logger from .streams import StreamReader from .typedefs import Handler, Middleware from .web_exceptions import NotAppKeyWarning from .web_log import AccessLogger from .web_middlewares import _fix_request_current_app from .web_protocol import RequestHandler from .web_request import Request from .web_response import StreamResponse from .web_routedef import AbstractRouteDef from .web_server import Server from .web_urldispatcher import (
AbstractResource,
AbstractRoute,
Domain,
MaskDomain,
MatchedSubAppResource,
PrefixedSubAppResource,
SystemRoute,
UrlDispatcher,
)
__all__ = ("Application", "CleanupError")
if TYPE_CHECKING:
_AppSignal = Signal[Callable[["Application"], Awaitable[None]]]
_RespPrepareSignal = Signal[Callable[[Request, StreamResponse], Awaitable[None]]]
_Middlewares = FrozenList[Middleware]
_MiddlewaresHandlers = Optional[Sequence[Tuple[Middleware, bool]]]
_Subapps = List["Application"] else: # No type checker mode, skip types
_AppSignal = Signal
_RespPrepareSignal = Signal
_Middlewares = FrozenList
_MiddlewaresHandlers = Optional[Sequence]
_Subapps = List
def _check_frozen(self) -> None: if self._frozen:
warnings.warn( "Changing state of started or joined ""application is deprecated",
DeprecationWarning,
stacklevel=3,
)
########
@property def loop(self) -> asyncio.AbstractEventLoop: # Technically the loop can be None # but we mask it by explicit type cast # to provide more convenient type annotation
warnings.warn("loop property is deprecated", DeprecationWarning, stacklevel=2) return cast(asyncio.AbstractEventLoop, self._loop)
def _set_loop(self, loop: Optional[asyncio.AbstractEventLoop]) -> None: if loop isNone:
loop = asyncio.get_event_loop() if self._loop isnotNoneand self._loop isnot loop: raise RuntimeError( "web.Application instance initialized with different loop"
)
self._loop = loop
# set loop debug if self._debug is ...:
self._debug = loop.get_debug()
# set loop to sub applications for subapp in self._subapps:
subapp._set_loop(loop)
def pre_freeze(self) -> None: if self._pre_frozen: return
self._pre_frozen = True
self._middlewares.freeze()
self._router.freeze()
self._on_response_prepare.freeze()
self._cleanup_ctx.freeze()
self._on_startup.freeze()
self._on_shutdown.freeze()
self._on_cleanup.freeze()
self._middlewares_handlers = tuple(self._prepare_middleware())
self._has_legacy_middlewares = any( not new_style for _, new_style in self._middlewares_handlers
)
# If current app and any subapp do not have middlewares avoid run all # of the code footprint that it implies, which have a middleware # hardcoded per app that sets up the current_app attribute. If no # middlewares are configured the handler will receive the proper # current_app without needing all of this code.
self._run_middlewares = Trueif self.middlewares elseFalse
for subapp in self._subapps:
subapp.pre_freeze()
self._run_middlewares = self._run_middlewares or subapp._run_middlewares
ifnot issubclass(access_log_class, AbstractAccessLogger): raise TypeError( "access_log_class must be subclass of " "aiohttp.abc.AbstractAccessLogger, got {}".format(access_log_class)
)
self._set_loop(loop)
self.freeze()
kwargs["debug"] = self._debug
kwargs["access_log_class"] = access_log_class if self._handler_args: for k, v in self._handler_args.items():
kwargs[k] = v
async def startup(self) -> None: """Causes on_startup signal
Should be called in the event loop along with the request handler. """
await self.on_startup.send(self)
async def shutdown(self) -> None: """Causes on_shutdown signal
Should be called before cleanup() """
await self.on_shutdown.send(self)
async def cleanup(self) -> None: """Causes on_cleanup signal
Should be called after shutdown() """ if self.on_cleanup.frozen:
await self.on_cleanup.send(self) else: # If an exception occurs in startup, ensure cleanup contexts are completed.
await self._cleanup_ctx._on_cleanup(self)
def _prepare_middleware(self) -> Iterator[Tuple[Middleware, bool]]: for m in reversed(self._middlewares): if getattr(m, "__middleware_version__", None) == 1: yield m, True else:
warnings.warn( 'old-style middleware "{!r}" deprecated, '"see #2252".format(m),
DeprecationWarning,
stacklevel=2,
) yield m, False
yield _fix_request_current_app(self), True
async def _handle(self, request: Request) -> StreamResponse:
loop = asyncio.get_event_loop()
debug = loop.get_debug()
match_info = await self._router.resolve(request) if debug: # pragma: no cover ifnot isinstance(match_info, AbstractMatchInfo): raise TypeError( "match_info should be AbstractMatchInfo " "instance, not {!r}".format(match_info)
)
match_info.add_app(self)
match_info.freeze()
request._match_info = match_info
if request.headers.get(hdrs.EXPECT):
resp = await match_info.expect_handler(request)
await request.writer.drain() if resp isnotNone: return resp
handler = match_info.handler
if self._run_middlewares: # If its a SystemRoute, don't cache building the middlewares since # they are constructed for every MatchInfoError as a new handler # is made each time. ifnot self._has_legacy_middlewares andnot isinstance(
match_info.route, SystemRoute
):
handler = _cached_build_middleware(handler, match_info.apps) else: for app in match_info.apps[::-1]: for m, new_style in app._middlewares_handlers: # type: ignore[union-attr] if new_style:
handler = update_wrapper(
partial(m, handler=handler), handler # type: ignore[misc]
) else:
handler = await m(app, handler) # type: ignore[arg-type,assignment]
async def _on_startup(self, app: Application) -> None: for cb in self:
it = cb(app).__aiter__()
await it.__anext__()
self._exits.append(it)
async def _on_cleanup(self, app: Application) -> None:
errors = [] for it in reversed(self._exits): try:
await it.__anext__() except StopAsyncIteration: pass except (Exception, asyncio.CancelledError) as exc:
errors.append(exc) else:
errors.append(RuntimeError(f"{it!r} has more than one 'yield'")) if errors: if len(errors) == 1: raise errors[0] else: raise CleanupError("Multiple errors on cleanup stage", errors)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.