示例#1
0
def test_delitem(owner):
    signal = Signal(owner)
    m1 = mock.Mock()
    signal.append(m1)
    assert len(signal) == 1
    del signal[0]
    assert len(signal) == 0
示例#2
0
def test_setitem(owner):
    signal = Signal(owner)
    m1 = mock.Mock()
    signal.append(m1)
    assert signal[0] is m1
    m2 = mock.Mock()
    signal[0] = m2
    assert signal[0] is m2
示例#3
0
def test_repr(owner):
    signal = Signal(owner)

    signal.append(mock.Mock(__repr__=lambda *a: "<callback>"))

    assert re.match(
        r"<Signal owner=<Owner 0xdeadbeef>, frozen=False, "
        r"\[<callback>\]>", repr(signal)) is not None
示例#4
0
async def test_cannot_send_non_frozen_signal(owner):
    signal = Signal(owner)

    callback_mock = mock.Mock()

    async def callback(**kwargs):
        callback_mock(**kwargs)

    signal.append(callback)

    with pytest.raises(RuntimeError):
        await signal.send()

    assert not callback_mock.called
示例#5
0
def test_cannot_append_to_frozen_signal(owner):
    signal = Signal(owner)
    m1 = mock.Mock()
    m2 = mock.Mock()
    signal.append(m1)
    signal.freeze()
    with pytest.raises(RuntimeError):
        signal.append(m2)

    assert list(signal) == [m1]
示例#6
0
    def __init__(
            self,
            *,
            logger: logging.Logger = web_logger,
            router: Optional[UrlDispatcher] = None,
            middlewares: Iterable[_Middleware] = (),
            handler_args: Optional[Mapping[str, Any]] = None,
            client_max_size: int = 1024**2,
            loop: Optional[asyncio.AbstractEventLoop] = None,
            debug: Any = ...,  # mypy doesn't support ellipsis
    ) -> None:
        if router is None:
            router = UrlDispatcher()
        else:
            warnings.warn("router argument is deprecated",
                          DeprecationWarning,
                          stacklevel=2)
        assert isinstance(router, AbstractRouter), router

        if loop is not None:
            warnings.warn("loop argument is deprecated",
                          DeprecationWarning,
                          stacklevel=2)

        if debug is not ...:
            warnings.warn("debug argument is deprecated",
                          DeprecationWarning,
                          stacklevel=2)
        self._debug = debug
        self._router = router  # type: UrlDispatcher
        self._loop = loop
        self._handler_args = handler_args
        self.logger = logger

        self._middlewares = FrozenList(middlewares)  # type: _Middlewares

        # initialized on freezing
        self._middlewares_handlers = None  # type: _MiddlewaresHandlers
        # initialized on freezing
        self._run_middlewares = None  # type: Optional[bool]

        self._state = {}  # type: Dict[str, Any]
        self._frozen = False
        self._pre_frozen = False
        self._subapps = []  # type: _Subapps

        self._on_response_prepare = Signal(self)  # type: _RespPrepareSignal
        self._on_startup = Signal(self)  # type: _AppSignal
        self._on_shutdown = Signal(self)  # type: _AppSignal
        self._on_cleanup = Signal(self)  # type: _AppSignal
        self._cleanup_ctx = CleanupContext()
        self._on_startup.append(self._cleanup_ctx._on_startup)
        self._on_cleanup.append(self._cleanup_ctx._on_cleanup)
        self._client_max_size = client_max_size
示例#7
0
    def __init__(
            self,
            *,
            logger: logging.Logger = web_logger,
            middlewares: Iterable[Middleware] = (),
            handler_args: Optional[Mapping[str, Any]] = None,
            client_max_size: int = 1024**2,
            debug: Any = ...,  # mypy doesn't support ellipsis
    ) -> None:

        if debug is not ...:
            warnings.warn(
                "debug argument is no-op since 4.0 "
                "and scheduled for removal in 5.0",
                DeprecationWarning,
                stacklevel=2,
            )
        self._router = UrlDispatcher()
        self._handler_args = handler_args
        self.logger = logger

        self._middlewares: _Middlewares = FrozenList(middlewares)

        # initialized on freezing
        self._middlewares_handlers: _MiddlewaresHandlers = tuple()
        # initialized on freezing
        self._run_middlewares: Optional[bool] = None

        self._state: Dict[Union[AppKey[Any], str], object] = {}
        self._frozen = False
        self._pre_frozen = False
        self._subapps: _Subapps = []

        self._on_response_prepare: _RespPrepareSignal = Signal(self)
        self._on_startup: _AppSignal = Signal(self)
        self._on_shutdown: _AppSignal = Signal(self)
        self._on_cleanup: _AppSignal = Signal(self)
        self._cleanup_ctx = CleanupContext()
        self._on_startup.append(self._cleanup_ctx._on_startup)
        self._on_cleanup.append(self._cleanup_ctx._on_cleanup)
        self._client_max_size = client_max_size
示例#8
0
async def test_add_signal_handler_not_a_callable(owner):
    callback = True
    signal = Signal(owner)
    signal.append(callback)
    signal.freeze()
    with pytest.raises(TypeError):
        await signal.send()
示例#9
0
def test_cannot_delitem_in_frozen_signal(owner):
    signal = Signal(owner)
    m1 = mock.Mock()
    signal.append(m1)
    signal.freeze()
    with pytest.raises(RuntimeError):
        del signal[0]

    assert list(signal) == [m1]
示例#10
0
def _create_app_mock() -> mock.MagicMock:
    def get_dict(app: Any, key: str) -> Any:
        return app.__app_dict[key]

    def set_dict(app: Any, key: str, value: Any) -> None:
        app.__app_dict[key] = value

    app = mock.MagicMock()
    app.__app_dict = {}
    app.__getitem__ = get_dict
    app.__setitem__ = set_dict

    app.on_response_prepare = Signal(app)
    app.on_response_prepare.freeze()
    return app
示例#11
0
def test_cannot_setitem_in_frozen_signal(owner: Owner) -> None:
    signal = Signal(owner)
    m1 = mock.Mock()
    m2 = mock.Mock()
    signal.append(m1)
    signal.freeze()
    with pytest.raises(RuntimeError):
        signal[0] = m2

    assert list(signal) == [m1]
示例#12
0
async def test_non_coroutine(owner: Owner) -> None:
    signal = Signal(owner)
    kwargs = {'foo': 1, 'bar': 2}

    callback = mock.Mock()

    signal.append(callback)
    signal.freeze()

    with pytest.raises(TypeError):
        await signal.send(**kwargs)
示例#13
0
async def test_function_signal_dispatch_kwargs(owner):
    signal = Signal(owner)
    kwargs = {'foo': 1, 'bar': 2}

    callback_mock = mock.Mock()

    async def callback(**kwargs):
        callback_mock(**kwargs)

    signal.append(callback)
    signal.freeze()

    await signal.send(**kwargs)
    callback_mock.assert_called_once_with(**kwargs)
示例#14
0
async def test_function_signal_dispatch_args_kwargs(owner: Owner) -> None:
    signal = Signal(owner)
    args = {"a", "b"}
    kwargs = {"foo": 1, "bar": 2}

    callback_mock = mock.Mock()

    async def callback(*args, **kwargs):
        callback_mock(*args, **kwargs)

    signal.append(callback)
    signal.freeze()

    await signal.send(*args, **kwargs)
    callback_mock.assert_called_once_with(*args, **kwargs)
示例#15
0
    def __init__(
        self,
        trace_config_ctx_factory: Type[SimpleNamespace] = SimpleNamespace
    ) -> None:
        self._on_request_start: Signal[
            _SignalCallback[TraceRequestStartParams]] = Signal(self)
        self._on_request_chunk_sent: Signal[
            _SignalCallback[TraceRequestChunkSentParams]] = Signal(self)
        self._on_response_chunk_received: Signal[
            _SignalCallback[TraceResponseChunkReceivedParams]] = Signal(self)
        self._on_request_end: Signal[
            _SignalCallback[TraceRequestEndParams]] = Signal(self)
        self._on_request_exception: Signal[
            _SignalCallback[TraceRequestExceptionParams]] = Signal(self)
        self._on_request_redirect: Signal[
            _SignalCallback[TraceRequestRedirectParams]] = Signal(self)
        self._on_connection_queued_start: Signal[
            _SignalCallback[TraceConnectionQueuedStartParams]] = Signal(self)
        self._on_connection_queued_end: Signal[
            _SignalCallback[TraceConnectionQueuedEndParams]] = Signal(self)
        self._on_connection_create_start: Signal[
            _SignalCallback[TraceConnectionCreateStartParams]] = Signal(self)
        self._on_connection_create_end: Signal[
            _SignalCallback[TraceConnectionCreateEndParams]] = Signal(self)
        self._on_connection_reuseconn: Signal[
            _SignalCallback[TraceConnectionReuseconnParams]] = Signal(self)
        self._on_dns_resolvehost_start: Signal[
            _SignalCallback[TraceDnsResolveHostStartParams]] = Signal(self)
        self._on_dns_resolvehost_end: Signal[
            _SignalCallback[TraceDnsResolveHostEndParams]] = Signal(self)
        self._on_dns_cache_hit: Signal[
            _SignalCallback[TraceDnsCacheHitParams]] = Signal(self)
        self._on_dns_cache_miss: Signal[
            _SignalCallback[TraceDnsCacheMissParams]] = Signal(self)
        self._on_request_headers_sent: Signal[
            _SignalCallback[TraceRequestHeadersSentParams]] = Signal(self)

        self._trace_config_ctx_factory = trace_config_ctx_factory
示例#16
0
class Application(MutableMapping[str, Any]):
    __slots__ = (
        "logger",
        "_debug",
        "_router",
        "_loop",
        "_handler_args",
        "_middlewares",
        "_middlewares_handlers",
        "_run_middlewares",
        "_state",
        "_frozen",
        "_pre_frozen",
        "_subapps",
        "_on_response_prepare",
        "_on_startup",
        "_on_shutdown",
        "_on_cleanup",
        "_client_max_size",
        "_cleanup_ctx",
    )

    def __init__(
            self,
            *,
            logger: logging.Logger = web_logger,
            middlewares: Iterable[_Middleware] = (),
            handler_args: Optional[Mapping[str, Any]] = None,
            client_max_size: int = 1024**2,
            debug: Any = ...,  # mypy doesn't support ellipsis
    ) -> None:

        if debug is not ...:
            warnings.warn(
                "debug argument is no-op since 4.0 "
                "and scheduled for removal in 5.0",
                DeprecationWarning,
                stacklevel=2,
            )
        self._router = UrlDispatcher()
        self._handler_args = handler_args
        self.logger = logger

        self._middlewares = FrozenList(middlewares)  # type: _Middlewares

        # initialized on freezing
        self._middlewares_handlers = tuple()  # type: _MiddlewaresHandlers
        # initialized on freezing
        self._run_middlewares = None  # type: Optional[bool]

        self._state = {}  # type: Dict[str, Any]
        self._frozen = False
        self._pre_frozen = False
        self._subapps = []  # type: _Subapps

        self._on_response_prepare = Signal(self)  # type: _RespPrepareSignal
        self._on_startup = Signal(self)  # type: _AppSignal
        self._on_shutdown = Signal(self)  # type: _AppSignal
        self._on_cleanup = Signal(self)  # type: _AppSignal
        self._cleanup_ctx = CleanupContext()
        self._on_startup.append(self._cleanup_ctx._on_startup)
        self._on_cleanup.append(self._cleanup_ctx._on_cleanup)
        self._client_max_size = client_max_size

    def __init_subclass__(cls: Type["Application"]) -> None:
        raise TypeError("Inheritance class {} from web.Application "
                        "is forbidden".format(cls.__name__))

    # MutableMapping API

    def __eq__(self, other: object) -> bool:
        return self is other

    def __getitem__(self, key: str) -> Any:
        return self._state[key]

    def _check_frozen(self) -> None:
        if self._frozen:
            raise RuntimeError("Changing state of started or joined "
                               "application is forbidden")

    def __setitem__(self, key: str, value: Any) -> None:
        self._check_frozen()
        self._state[key] = value

    def __delitem__(self, key: str) -> None:
        self._check_frozen()
        del self._state[key]

    def __len__(self) -> int:
        return len(self._state)

    def __iter__(self) -> Iterator[str]:
        return iter(self._state)

    ########
    def _set_loop(self, loop: Optional[asyncio.AbstractEventLoop]) -> None:
        warnings.warn(
            "_set_loop() is no-op since 4.0 "
            "and scheduled for removal in 5.0",
            DeprecationWarning,
            stacklevel=2,
        )

    @property
    def pre_frozen(self) -> bool:
        return self._pre_frozen

    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())

        # 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 = True if self.middlewares else False

        for subapp in self._subapps:
            subapp.pre_freeze()
            self._run_middlewares = self._run_middlewares or subapp._run_middlewares

    @property
    def frozen(self) -> bool:
        return self._frozen

    def freeze(self) -> None:
        if self._frozen:
            return

        self.pre_freeze()
        self._frozen = True
        for subapp in self._subapps:
            subapp.freeze()

    @property
    def debug(self) -> bool:
        warnings.warn(
            "debug property is deprecated since 4.0"
            "and scheduled for removal in 5.0",
            DeprecationWarning,
            stacklevel=2,
        )
        return asyncio.get_event_loop().get_debug()

    def _reg_subapp_signals(self, subapp: "Application") -> None:
        def reg_handler(signame: str) -> None:
            subsig = getattr(subapp, signame)

            async def handler(app: "Application") -> None:
                await subsig.send(subapp)

            appsig = getattr(self, signame)
            appsig.append(handler)

        reg_handler("on_startup")
        reg_handler("on_shutdown")
        reg_handler("on_cleanup")

    def add_subapp(self, prefix: str,
                   subapp: "Application") -> AbstractResource:
        if not isinstance(prefix, str):
            raise TypeError("Prefix must be str")
        prefix = prefix.rstrip("/")
        if not prefix:
            raise ValueError("Prefix cannot be empty")
        factory = partial(PrefixedSubAppResource, prefix, subapp)
        return self._add_subapp(factory, subapp)

    def _add_subapp(self, resource_factory: Callable[[], AbstractResource],
                    subapp: "Application") -> AbstractResource:
        if self.frozen:
            raise RuntimeError(
                "Cannot add sub application to frozen application")
        if subapp.frozen:
            raise RuntimeError("Cannot add frozen application")
        resource = resource_factory()
        self.router.register_resource(resource)
        self._reg_subapp_signals(subapp)
        self._subapps.append(subapp)
        subapp.pre_freeze()
        return resource

    def add_domain(self, domain: str,
                   subapp: "Application") -> AbstractResource:
        if not isinstance(domain, str):
            raise TypeError("Domain must be str")
        elif "*" in domain:
            rule = MaskDomain(domain)  # type: Domain
        else:
            rule = Domain(domain)
        factory = partial(MatchedSubAppResource, rule, subapp)
        return self._add_subapp(factory, subapp)

    def add_routes(self,
                   routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]:
        return self.router.add_routes(routes)

    @property
    def on_response_prepare(self) -> _RespPrepareSignal:
        return self._on_response_prepare

    @property
    def on_startup(self) -> _AppSignal:
        return self._on_startup

    @property
    def on_shutdown(self) -> _AppSignal:
        return self._on_shutdown

    @property
    def on_cleanup(self) -> _AppSignal:
        return self._on_cleanup

    @property
    def cleanup_ctx(self) -> "CleanupContext":
        return self._cleanup_ctx

    @property
    def router(self) -> UrlDispatcher:
        return self._router

    @property
    def middlewares(self) -> _Middlewares:
        return self._middlewares

    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[_Middleware]:
        yield from reversed(self._middlewares)
        yield _fix_request_current_app(self)

    async def _handle(self, request: Request) -> StreamResponse:
        match_info = await self._router.resolve(request)
        match_info.add_app(self)
        match_info.freeze()

        resp = None
        request._match_info = match_info
        expect = request.headers.get(hdrs.EXPECT)
        if expect:
            resp = await match_info.expect_handler(request)
            await request.writer.drain()

        if resp is None:
            handler = match_info.handler

            if self._run_middlewares:
                for app in match_info.apps[::-1]:
                    assert app.pre_frozen, "middleware handlers are not ready"
                    for m in app._middlewares_handlers:
                        handler = update_wrapper(partial(m, handler=handler),
                                                 handler)

            resp = await handler(request)

        return resp

    def __call__(self) -> "Application":
        """gunicorn compatibility"""
        return self

    def __repr__(self) -> str:
        return "<Application 0x{:x}>".format(id(self))

    def __bool__(self) -> bool:
        return True
示例#17
0
class Application(MutableMapping[str, Any]):
    ATTRS = frozenset([
        "logger",
        "_debug",
        "_router",
        "_loop",
        "_handler_args",
        "_middlewares",
        "_middlewares_handlers",
        "_run_middlewares",
        "_state",
        "_frozen",
        "_pre_frozen",
        "_subapps",
        "_on_response_prepare",
        "_on_startup",
        "_on_shutdown",
        "_on_cleanup",
        "_client_max_size",
        "_cleanup_ctx",
    ])

    def __init__(
            self,
            *,
            logger: logging.Logger = web_logger,
            router: Optional[UrlDispatcher] = None,
            middlewares: Iterable[_Middleware] = (),
            handler_args: Optional[Mapping[str, Any]] = None,
            client_max_size: int = 1024**2,
            loop: Optional[asyncio.AbstractEventLoop] = None,
            debug: Any = ...,  # mypy doesn't support ellipsis
    ) -> None:
        if router is None:
            router = UrlDispatcher()
        else:
            warnings.warn("router argument is deprecated",
                          DeprecationWarning,
                          stacklevel=2)
        assert isinstance(router, AbstractRouter), router

        if loop is not None:
            warnings.warn("loop argument is deprecated",
                          DeprecationWarning,
                          stacklevel=2)

        if debug is not ...:
            warnings.warn("debug argument is deprecated",
                          DeprecationWarning,
                          stacklevel=2)
        self._debug = debug
        self._router = router  # type: UrlDispatcher
        self._loop = loop
        self._handler_args = handler_args
        self.logger = logger

        self._middlewares = FrozenList(middlewares)  # type: _Middlewares

        # initialized on freezing
        self._middlewares_handlers = None  # type: _MiddlewaresHandlers
        # initialized on freezing
        self._run_middlewares = None  # type: Optional[bool]

        self._state = {}  # type: Dict[str, Any]
        self._frozen = False
        self._pre_frozen = False
        self._subapps = []  # type: _Subapps

        self._on_response_prepare = Signal(self)  # type: _RespPrepareSignal
        self._on_startup = Signal(self)  # type: _AppSignal
        self._on_shutdown = Signal(self)  # type: _AppSignal
        self._on_cleanup = Signal(self)  # type: _AppSignal
        self._cleanup_ctx = CleanupContext()
        self._on_startup.append(self._cleanup_ctx._on_startup)
        self._on_cleanup.append(self._cleanup_ctx._on_cleanup)
        self._client_max_size = client_max_size

    def __init_subclass__(cls: Type["Application"]) -> None:
        warnings.warn(
            "Inheritance class {} from web.Application "
            "is discouraged".format(cls.__name__),
            DeprecationWarning,
            stacklevel=2,
        )

    if DEBUG:  # pragma: no cover

        def __setattr__(self, name: str, val: Any) -> None:
            if name not in self.ATTRS:
                warnings.warn(
                    "Setting custom web.Application.{} attribute "
                    "is discouraged".format(name),
                    DeprecationWarning,
                    stacklevel=2,
                )
            super().__setattr__(name, val)

    # MutableMapping API

    def __eq__(self, other: object) -> bool:
        return self is other

    def __getitem__(self, key: str) -> Any:
        return self._state[key]

    def _check_frozen(self) -> None:
        if self._frozen:
            warnings.warn(
                "Changing state of started or joined "
                "application is deprecated",
                DeprecationWarning,
                stacklevel=3,
            )

    def __setitem__(self, key: str, value: Any) -> None:
        self._check_frozen()
        self._state[key] = value

    def __delitem__(self, key: str) -> None:
        self._check_frozen()
        del self._state[key]

    def __len__(self) -> int:
        return len(self._state)

    def __iter__(self) -> Iterator[str]:
        return iter(self._state)

    ########
    @property
    def loop(self) -> asyncio.AbstractEventLoop:
        # Technically the loop can be None
        # but we mask it by explicit type cast
        # to provide more convinient 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 is None:
            loop = asyncio.get_event_loop()
        if self._loop is not None and self._loop is not 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)

    @property
    def pre_frozen(self) -> bool:
        return self._pre_frozen

    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())

        # 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 = True if self.middlewares else False

        for subapp in self._subapps:
            subapp.pre_freeze()
            self._run_middlewares = self._run_middlewares or subapp._run_middlewares

    @property
    def frozen(self) -> bool:
        return self._frozen

    def freeze(self) -> None:
        if self._frozen:
            return

        self.pre_freeze()
        self._frozen = True
        for subapp in self._subapps:
            subapp.freeze()

    @property
    def debug(self) -> bool:
        warnings.warn("debug property is deprecated",
                      DeprecationWarning,
                      stacklevel=2)
        return self._debug  # type: ignore[no-any-return]

    def _reg_subapp_signals(self, subapp: "Application") -> None:
        def reg_handler(signame: str) -> None:
            subsig = getattr(subapp, signame)

            async def handler(app: "Application") -> None:
                await subsig.send(subapp)

            appsig = getattr(self, signame)
            appsig.append(handler)

        reg_handler("on_startup")
        reg_handler("on_shutdown")
        reg_handler("on_cleanup")

    def add_subapp(self, prefix: str,
                   subapp: "Application") -> AbstractResource:
        if not isinstance(prefix, str):
            raise TypeError("Prefix must be str")
        prefix = prefix.rstrip("/")
        if not prefix:
            raise ValueError("Prefix cannot be empty")
        factory = partial(PrefixedSubAppResource, prefix, subapp)
        return self._add_subapp(factory, subapp)

    def _add_subapp(self, resource_factory: Callable[[], AbstractResource],
                    subapp: "Application") -> AbstractResource:
        if self.frozen:
            raise RuntimeError(
                "Cannot add sub application to frozen application")
        if subapp.frozen:
            raise RuntimeError("Cannot add frozen application")
        resource = resource_factory()
        self.router.register_resource(resource)
        self._reg_subapp_signals(subapp)
        self._subapps.append(subapp)
        subapp.pre_freeze()
        if self._loop is not None:
            subapp._set_loop(self._loop)
        return resource

    def add_domain(self, domain: str,
                   subapp: "Application") -> AbstractResource:
        if not isinstance(domain, str):
            raise TypeError("Domain must be str")
        elif "*" in domain:
            rule = MaskDomain(domain)  # type: Domain
        else:
            rule = Domain(domain)
        factory = partial(MatchedSubAppResource, rule, subapp)
        return self._add_subapp(factory, subapp)

    def add_routes(self,
                   routes: Iterable[AbstractRouteDef]) -> List[AbstractRoute]:
        return self.router.add_routes(routes)

    @property
    def on_response_prepare(self) -> _RespPrepareSignal:
        return self._on_response_prepare

    @property
    def on_startup(self) -> _AppSignal:
        return self._on_startup

    @property
    def on_shutdown(self) -> _AppSignal:
        return self._on_shutdown

    @property
    def on_cleanup(self) -> _AppSignal:
        return self._on_cleanup

    @property
    def cleanup_ctx(self) -> "CleanupContext":
        return self._cleanup_ctx

    @property
    def router(self) -> UrlDispatcher:
        return self._router

    @property
    def middlewares(self) -> _Middlewares:
        return self._middlewares

    def _make_handler(
        self,
        *,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        access_log_class: Type[AbstractAccessLogger] = AccessLogger,
        **kwargs: Any,
    ) -> Server:

        if not 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

        return Server(
            self._handle,  # type: ignore[arg-type]
            request_factory=self._make_request,
            loop=self._loop,
            **kwargs,
        )

    def make_handler(
        self,
        *,
        loop: Optional[asyncio.AbstractEventLoop] = None,
        access_log_class: Type[AbstractAccessLogger] = AccessLogger,
        **kwargs: Any,
    ) -> Server:

        warnings.warn(
            "Application.make_handler(...) is deprecated, "
            "use AppRunner API instead",
            DeprecationWarning,
            stacklevel=2,
        )

        return self._make_handler(loop=loop,
                                  access_log_class=access_log_class,
                                  **kwargs)

    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 _make_request(
        self,
        message: RawRequestMessage,
        payload: StreamReader,
        protocol: RequestHandler,
        writer: AbstractStreamWriter,
        task: "asyncio.Task[None]",
        _cls: Type[Request] = Request,
    ) -> Request:
        return _cls(
            message,
            payload,
            protocol,
            writer,
            task,
            self._loop,
            client_max_size=self._client_max_size,
        )

    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
            if not 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()

        resp = None
        request._match_info = match_info
        expect = request.headers.get(hdrs.EXPECT)
        if expect:
            resp = await match_info.expect_handler(request)
            await request.writer.drain()

        if resp is None:
            handler = match_info.handler

            if self._run_middlewares:
                for app in match_info.apps[::-1]:
                    for m, new_style in app._middlewares_handlers:  # type: ignore[union-attr] # noqa
                        if new_style:
                            handler = update_wrapper(
                                partial(m, handler=handler), handler)
                        else:
                            handler = await m(app, handler
                                              )  # type: ignore[arg-type]

            resp = await handler(request)

        return resp

    def __call__(self) -> "Application":
        """gunicorn compatibility"""
        return self

    def __repr__(self) -> str:
        return f"<Application 0x{id(self):x}>"

    def __bool__(self) -> bool:
        return True
示例#18
0
class TraceConfig:
    """First-class used to trace requests launched via ClientSession objects."""
    def __init__(
        self,
        trace_config_ctx_factory: Type[SimpleNamespace] = SimpleNamespace
    ) -> None:
        self._on_request_start = Signal(
            self)  # type: Signal[_SignalCallback[TraceRequestStartParams]]
        self._on_request_chunk_sent = Signal(
            self)  # type: Signal[_SignalCallback[TraceRequestChunkSentParams]]
        self._on_response_chunk_received = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceResponseChunkReceivedParams]]
        self._on_request_end = Signal(
            self)  # type: Signal[_SignalCallback[TraceRequestEndParams]]
        self._on_request_exception = Signal(
            self)  # type: Signal[_SignalCallback[TraceRequestExceptionParams]]
        self._on_request_redirect = Signal(
            self)  # type: Signal[_SignalCallback[TraceRequestRedirectParams]]
        self._on_connection_queued_start = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceConnectionQueuedStartParams]]
        self._on_connection_queued_end = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceConnectionQueuedEndParams]]
        self._on_connection_create_start = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceConnectionCreateStartParams]]
        self._on_connection_create_end = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceConnectionCreateEndParams]]
        self._on_connection_reuseconn = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceConnectionReuseconnParams]]
        self._on_dns_resolvehost_start = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceDnsResolveHostStartParams]]
        self._on_dns_resolvehost_end = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceDnsResolveHostEndParams]]
        self._on_dns_cache_hit = Signal(
            self)  # type: Signal[_SignalCallback[TraceDnsCacheHitParams]]
        self._on_dns_cache_miss = Signal(
            self)  # type: Signal[_SignalCallback[TraceDnsCacheMissParams]]
        self._on_request_headers_sent = Signal(
            self
        )  # type: Signal[_SignalCallback[TraceRequestHeadersSentParams]]

        self._trace_config_ctx_factory = trace_config_ctx_factory

    def trace_config_ctx(
        self,
        trace_request_ctx: Optional[SimpleNamespace] = None
    ) -> SimpleNamespace:
        """Return a new trace_config_ctx instance"""
        return self._trace_config_ctx_factory(
            trace_request_ctx=trace_request_ctx)

    def freeze(self) -> None:
        self._on_request_start.freeze()
        self._on_request_chunk_sent.freeze()
        self._on_response_chunk_received.freeze()
        self._on_request_end.freeze()
        self._on_request_exception.freeze()
        self._on_request_redirect.freeze()
        self._on_connection_queued_start.freeze()
        self._on_connection_queued_end.freeze()
        self._on_connection_create_start.freeze()
        self._on_connection_create_end.freeze()
        self._on_connection_reuseconn.freeze()
        self._on_dns_resolvehost_start.freeze()
        self._on_dns_resolvehost_end.freeze()
        self._on_dns_cache_hit.freeze()
        self._on_dns_cache_miss.freeze()
        self._on_request_headers_sent.freeze()

    @property
    def on_request_start(
            self) -> "Signal[_SignalCallback[TraceRequestStartParams]]":
        return self._on_request_start

    @property
    def on_request_chunk_sent(
        self, ) -> "Signal[_SignalCallback[TraceRequestChunkSentParams]]":
        return self._on_request_chunk_sent

    @property
    def on_response_chunk_received(
        self, ) -> "Signal[_SignalCallback[TraceResponseChunkReceivedParams]]":
        return self._on_response_chunk_received

    @property
    def on_request_end(
            self) -> "Signal[_SignalCallback[TraceRequestEndParams]]":
        return self._on_request_end

    @property
    def on_request_exception(
        self, ) -> "Signal[_SignalCallback[TraceRequestExceptionParams]]":
        return self._on_request_exception

    @property
    def on_request_redirect(
        self, ) -> "Signal[_SignalCallback[TraceRequestRedirectParams]]":
        return self._on_request_redirect

    @property
    def on_connection_queued_start(
        self, ) -> "Signal[_SignalCallback[TraceConnectionQueuedStartParams]]":
        return self._on_connection_queued_start

    @property
    def on_connection_queued_end(
        self, ) -> "Signal[_SignalCallback[TraceConnectionQueuedEndParams]]":
        return self._on_connection_queued_end

    @property
    def on_connection_create_start(
        self, ) -> "Signal[_SignalCallback[TraceConnectionCreateStartParams]]":
        return self._on_connection_create_start

    @property
    def on_connection_create_end(
        self, ) -> "Signal[_SignalCallback[TraceConnectionCreateEndParams]]":
        return self._on_connection_create_end

    @property
    def on_connection_reuseconn(
        self, ) -> "Signal[_SignalCallback[TraceConnectionReuseconnParams]]":
        return self._on_connection_reuseconn

    @property
    def on_dns_resolvehost_start(
        self, ) -> "Signal[_SignalCallback[TraceDnsResolveHostStartParams]]":
        return self._on_dns_resolvehost_start

    @property
    def on_dns_resolvehost_end(
        self, ) -> "Signal[_SignalCallback[TraceDnsResolveHostEndParams]]":
        return self._on_dns_resolvehost_end

    @property
    def on_dns_cache_hit(
            self) -> "Signal[_SignalCallback[TraceDnsCacheHitParams]]":
        return self._on_dns_cache_hit

    @property
    def on_dns_cache_miss(
            self) -> "Signal[_SignalCallback[TraceDnsCacheMissParams]]":
        return self._on_dns_cache_miss

    @property
    def on_request_headers_sent(
        self, ) -> "Signal[_SignalCallback[TraceRequestHeadersSentParams]]":
        return self._on_request_headers_sent