Пример #1
0
            async def awaitable(receive: Receive, send: Send) -> None:
                app = scope["app"]

                route, route_scope = app.router.get_route_from_scope(scope)

                state = {
                    "scope": scope,
                    "receive": receive,
                    "send": send,
                    "exc": None,
                    "app": app,
                    "path_params": route_scope["path_params"],
                    "route": route,
                    "request": http.Request(scope, receive),
                }

                injected_func = await app.injector.inject(endpoint, state)

                if asyncio.iscoroutinefunction(endpoint):
                    response = await injected_func()
                else:
                    response = await run_in_threadpool(injected_func)

                # Wrap response data with a proper response class
                if isinstance(response, (dict, list)):
                    response = APIResponse(content=response,
                                           schema=get_output_schema(endpoint))
                elif isinstance(response, str):
                    response = APIResponse(content=response)
                elif response is None:
                    response = APIResponse(content="")

                await response(receive, send)
Пример #2
0
def page_number(func):
    """
    Decorator for adding pagination behavior to a view. That decorator produces a view based on page numbering and
    it adds three query parameters to control the pagination: page, page_size and count. Page has a default value of
    first page, page_size default value is defined in
    :class:`PageNumberResponse` and count defines if the response will define
    the total number of elements.

    The output schema is also modified by :class:`PageNumberSchema`, creating
    a new schema based on it but using the old output schema as the content of its data field.

    :param func: View to be decorated.
    :return: Decorated view.
    """
    assert forge is not None, "`python-forge` must be installed to use Paginator."

    resource_schema = get_output_schema(func)
    data_schema = marshmallow.fields.Nested(resource_schema, many=True) if resource_schema else marshmallow.fields.Raw()

    schema = type(
        "PageNumberPaginated" + resource_schema.__class__.__name__,  # Add a prefix to avoid collision
        (PageNumberSchema,),
        {"data": data_schema},  # Replace generic with resource schema
    )()

    forge_revision_list = (
        forge.copy(func),
        forge.insert(forge.arg("page", default=None, type=int), index=-1),
        forge.insert(forge.arg("page_size", default=None, type=int), index=-1),
        forge.insert(forge.arg("count", default=True, type=bool), index=-1),
        forge.delete("kwargs"),
        forge.returns(schema),
    )

    try:
        if asyncio.iscoroutinefunction(func):

            @forge.compose(*forge_revision_list)
            @functools.wraps(func)
            async def decorator(*args, page: int = None, page_size: int = None, count: bool = True, **kwargs):
                return PageNumberResponse(
                    schema=schema, page=page, page_size=page_size, count=count, content=await func(*args, **kwargs)
                )

        else:

            @forge.compose(*forge_revision_list)
            @functools.wraps(func)
            def decorator(*args, page: int = None, page_size: int = None, count: bool = True, **kwargs):
                return PageNumberResponse(
                    schema=schema, page=page, page_size=page_size, count=count, content=func(*args, **kwargs)
                )

    except ValueError as e:
        raise TypeError("Paginated views must define **kwargs param") from e

    return decorator
Пример #3
0
    async def dispatch(self) -> None:
        request = Request(self.scope, receive=self.receive)
        app = self.scope["app"]

        route, route_scope = app.router.get_route_from_scope(self.scope)

        state = {
            "scope": self.scope,
            "receive": self.receive,
            "send": self.send,
            "exc": None,
            "app": app,
            "path_params": route_scope["path_params"],
            "route": route,
            "request": request,
        }
        handler_name = "get" if request.method == "HEAD" else request.method.lower()
        handler = getattr(self, handler_name, self.method_not_allowed)

        injected_func = await app.injector.inject(handler, state)
        background_task = next(
            (v for k, v in state.items() if k.startswith('backgroundtasks:') and isinstance(v, BackgroundTask)),
            None
        )
        if asyncio.iscoroutinefunction(handler):
            response = await injected_func()
        else:
            response = await run_in_threadpool(injected_func)

        # Wrap response data with a proper response class
        if isinstance(response, (dict, list)):
            response = APIResponse(content=response, schema=get_output_schema(handler), background=background_task)
        elif isinstance(response, str):
            response = APIResponse(content=response, background=background_task)
        elif response is None:
            response = APIResponse(content="", background=background_task)
        elif not isinstance(response, Response):
            schema = get_output_schema(handler)
            if schema is not None:
                response = APIResponse(content=response, schema=get_output_schema(handler), background=background_task)

        await response(self.scope, self.receive, self.send)
Пример #4
0
    async def dispatch(self, request: Request, state: typing.Dict,
                       **kwargs) -> Response:
        handler_name = "get" if request.method == "HEAD" else request.method.lower(
        )
        handler = getattr(self, handler_name, self.method_not_allowed)

        app = state["app"]
        injected_func = await app.injector.inject(handler, state)
        if asyncio.iscoroutinefunction(handler):
            response = await injected_func()
        else:
            response = await run_in_threadpool(injected_func)

        # Wrap response data with a proper response class
        if isinstance(response, (dict, list)):
            response = APIResponse(content=response,
                                   schema=get_output_schema(handler))
        elif isinstance(response, str):
            response = APIResponse(content=response)
        elif response is None:
            response = APIResponse(content="")

        return response
Пример #5
0
        async def _app(scope: Scope, receive: Receive, send: Send) -> None:
            app = scope["app"]

            route, route_scope = app.router.get_route_from_scope(scope)

            state = {
                "scope": scope,
                "receive": receive,
                "send": send,
                "exc": None,
                "app": app,
                "path_params": route_scope["path_params"],
                "route": route,
                "request": http.Request(scope, receive),
            }

            try:
                injected_func = await app.injector.inject(endpoint, state)
                background_task = next((v for k, v in state.items()
                                        if k.startswith('backgroundtasks:')
                                        and isinstance(v, BackgroundTask)),
                                       None)

                if asyncio.iscoroutinefunction(endpoint):
                    response = await injected_func()
                else:
                    response = await run_in_threadpool(injected_func)

                # Wrap response data with a proper response class
                if isinstance(response, (dict, list)):
                    response = APIResponse(
                        content=response,
                        schema=get_output_schema(endpoint),
                        background=background_task,
                        status_code=self.status_code,
                    )
                elif isinstance(response, str):
                    response = APIResponse(
                        content=response,
                        background=background_task,
                        status_code=self.status_code,
                    )
                elif response is None:
                    response = APIResponse(
                        content="",
                        background=background_task,
                        status_code=self.status_code,
                    )
                elif not isinstance(response, Response):
                    schema = get_output_schema(endpoint)
                    if schema is not None:
                        response = APIResponse(
                            content=response,
                            schema=get_output_schema(endpoint),
                            background=background_task,
                            status_code=self.status_code,
                        )
            except Exception:
                logger.exception("Error building response")
                raise

            await response(scope, receive, send)