Esempio n. 1
0
    def _patch_get(
            self,
            client_response: aiohttp.ClientResponse) -> aiohttp.ClientResponse:
        """ Wrap aiohttp.ClientResponse text and json coros in run_until_complete. Monkeypatch text and json with wrappers."""
        # May iter through methods and wrap all coro's in the future
        # however that may not work if a non-coro returns a async context manager for example
        text = self._wrap_coro_in_callable(client_response.text)
        json = self._wrap_coro_in_callable(client_response.json)
        # resign signatures
        text = forge.copy(aiohttp.ClientResponse.text, exclude="self")(text)
        json = forge.copy(aiohttp.ClientResponse.json, exclude="self")(json)

        client_response.text = text
        client_response.json = json
        return client_response
Esempio n. 2
0
def copy_signatures(
    target_function: Callable,
    template_functions: List[TemplateFunction],
    exclude_args: Iterable[str] = None,
) -> Callable:
    """A decorator that copies function signatures from one or more template functions to a
    target function.

    Args:
        target_function: Function to modify
        template_functions: Functions containing params to apply to ``target_function``
    """
    # Start with 'self' parameter if this is an instance method
    fparams = {}
    if 'self' in signature(target_function).parameters or ismethod(
            target_function):
        fparams['self'] = forge.self

    # Add and combine parameters from all template functions, excluding duplicates, self, and *args
    for func in template_functions:
        new_fparams = {
            k: v
            for k, v in forge.copy(func).signature.parameters.items()
            if k != 'self' and v.kind != Parameter.VAR_POSITIONAL
        }
        fparams.update(new_fparams)

    # Manually remove any excluded parameters
    for key in ensure_list(exclude_args):
        fparams.pop(key, None)

    fparams = deduplicate_var_kwargs(fparams)
    revision = forge.sign(*fparams.values())
    return revision(target_function)
Esempio n. 3
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
Esempio n. 4
0
def get_combined_revision(*functions: Callable):
    """Combine the parameters of all revisions into a single revision"""
    import forge

    params = {}
    for func in functions:
        params.update(forge.copy(func).signature.parameters)
    params = deduplicate_kwargs(params)
    return forge.sign(*params.values())
Esempio n. 5
0
    def wrapper(target_function: Callable):
        try:
            import forge
        except ImportError:
            return target_function

        revision = forge.copy(template_function,
                              include=include,
                              exclude=exclude)
        return revision(target_function)
Esempio n. 6
0
def _get_combined_revision(template_functions: List[TemplateFunction]):
    """ Create a :py:class:`forge.Revision` from the combined parameters of multiple functions """
    import forge

    # Use forge.copy to create a revision for each template function
    revisions = [forge.copy(func) for func in template_functions]

    # Combine the parameters of all revisions into a single revision
    fparams = [list(rev.signature.parameters.values()) for rev in revisions]
    return forge.sign(*list(chain.from_iterable(fparams)))
Esempio n. 7
0
def forge_client_session(init):
    """ Forge CachedSession.__init__ method signature """
    forged_signature = forge.compose(
        forge.copy(CachedSession.__init__),
        forge.insert(
            [
                forge.kwarg("retry", default=True, type=bool),
                forge.kwarg("n_retries", default=3, type=int),
            ],
            before=lambda x: x.kind == Parameter.KEYWORD_ONLY,
        ),
    )(init)
    return forged_signature
Esempio n. 8
0
    def decorator(corofunc):
        if not inspect.iscoroutinefunction(corofunc):
            raise TypeError("Expected coroutine function")

        @forge.compose(
            forge.copy(corofunc),
            forge.modify(channel_arg_name,
                         name=port_fixture_name,
                         interface_name="port_fixture_value"),
        )
        async def new_corofunc(*, port_fixture_value, **kwargs):
            import purerpc
            async with purerpc.insecure_channel("127.0.0.1",
                                                port_fixture_value) as channel:
                await corofunc(**kwargs, channel=channel)

        return new_corofunc
Esempio n. 9
0
    def decorator(func):
        if hasattr(func, "__parallelized__") and func.__parallelized__:
            raise TypeError(
                "Cannot pass gRPC channel to already parallelized test, grpc_client_parallelize should "
                "be the last decorator in chain")

        @forge.compose(
            forge.copy(func),
            forge.modify(channel_arg_name,
                         name=port_fixture_name,
                         interface_name="port_fixture_value"),
        )
        def new_func(*, port_fixture_value, **kwargs):
            import grpc
            with grpc.insecure_channel(
                    '127.0.0.1:{}'.format(port_fixture_value)) as channel:
                func(**kwargs, channel=channel)

        return new_func
Esempio n. 10
0
import forge
import aiohttp
from typing import Dict, List, Union

# RestClient signature decorators

GET_SIGNATURE = forge.compose(
    forge.copy(aiohttp.ClientSession.get),
    forge.modify("url", default=None),
    forge.returns(aiohttp.ClientResponse),
    forge.insert(
        [
            forge.kwo("parameters",
                      default={},
                      type=Dict[str, Union[str, List[str]]]),
            forge.kwo("headers", default={}, type=Dict[str, str]),
        ],
        before=lambda arg: arg.kind == forge.FParameter.VAR_KEYWORD,
    ),
)

MGET_SIGNATURE = forge.compose(
    forge.copy(aiohttp.ClientSession.get, exclude="url"),
    forge.returns(List[aiohttp.ClientResponse]),
    forge.insert(
        forge.pok(
            "urls",
            type=forge.fsignature(aiohttp.ClientSession.get)["url"].type,
            default=None,
        ),
        index=1,
def get_combined_revision(functions: Iterable[Callable]) -> forge.Revision:
    """Combine the parameters of all revisions into a single revision"""
    params = {}
    for func in functions:
        params.update(forge.copy(func).signature.parameters)
    return forge.sign(*params.values())