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)
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet)
¤
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.