Esempio n. 1
0
def _delegate_method_dispatch(fn: Callable, attr: str, prop_name: str, skip: int = 2):

    adapter = wrapt.adapter_factory(partial(argspec_factory, fn=fn, skip=skip))

    @wrapt.decorator(adapter=adapter)
    def delegate(wrapped, instance, args, kwargs):
        # first, get the correct method based on the dispatcher (can't use wrapped.dispatch..., since it's a function)
        # then, call the actual function
        return getattr(instance, attr)(
            getattr(instance, prop_name), prop_name, *args, **kwargs
        )

    return delegate(fn)
Esempio n. 2
0
    def test_adapter_factory(self):
        def factory(wrapped):
            argspec = inspect.getargspec(wrapped)
            argspec.args.insert(0, 'arg0')
            return argspec

        @wrapt.decorator(adapter=wrapt.adapter_factory(factory))
        def _wrapper_1(wrapped, instance, args, kwargs):
            return wrapped(*args, **kwargs)

        @_wrapper_1
        def _function_1(arg1, arg2):
            pass

        argspec = inspect.getargspec(_function_1)

        self.assertEqual(argspec.args, ['arg0', 'arg1', 'arg2'])
Esempio n. 3
0
    def test_adapter_factory(self):
        def factory(wrapped):
            argspec = inspect.getargspec(wrapped)
            argspec.args.insert(0, 'arg0')
            return argspec

        @wrapt.decorator(adapter=wrapt.adapter_factory(factory))
        def _wrapper_1(wrapped, instance, args, kwargs):
            return wrapped(*args, **kwargs)

        @_wrapper_1
        def _function_1(arg1, arg2):
            pass

        argspec = inspect.getargspec(_function_1)

        self.assertEqual(argspec.args, ['arg0', 'arg1', 'arg2'])
Esempio n. 4
0
def change_signature(
    force_annotation: Optional[Dict[str, Type]] = None,
    change_annotation: Optional[Dict[str, Type]] = None,
    namespace: Optional[Dict[str, Any]] = None,
) -> Callable[[Callable], Callable]:
    """Change function signature.

    Parameters
    ----------
    force_annotation : dict, optional
        mapping of {argument_name: type_hint}.  Will force any arguments named
        ``argument_name`` to be annotated as ``type_hint``.
    change_annotation : dict
        mapping of {current_hint: new_hint}.  Will force any arguments currently
        annotated with a type of ``curent_hint`` to ``new_hint`.
    namespace : dict
        mapping of {name: object}.  Namespaces required for importing any types
        declared as type annotations in the other arguments.

    Returns
    -------
    adapter : callable
        The returned function may be provided to the `adapter` argument of the
        ``wrapt.decorator`` function.
    """
    force_annotation = force_annotation or dict()
    change_annotation = change_annotation or dict()
    namespace = namespace or dict()
    if not namespace:
        for val in chain(change_annotation.values(), force_annotation.values()):
            mod = val.__module__.split(".")[0]
            namespace[mod] = import_module(mod)

    def argspec_factory(wrapped):
        sig = inspect.signature(wrapped)
        new_params = OrderedDict(sig.parameters.items())
        for name, param in new_params.items():
            if name in force_annotation:
                new_params[name] = param.replace(annotation=force_annotation[name])
        new_sig = sig.replace(parameters=list(new_params.values()))
        _globals = {}
        exec(f"def _func{new_sig}: pass", namespace, _globals)
        return _globals["_func"]

    return wrapt.adapter_factory(argspec_factory)
Esempio n. 5
0
def _delegate(
    *,
    prop_name: Optional[str] = None,
    return_type: Optional[Type] = None,
    skip: int = 2,
) -> Callable:
    @wrapt.decorator()
    def pass_through(wrapped, _instance, args, kwargs):
        return wrapped(*args, **kwargs)

    if prop_name is None:
        return pass_through

    adapter = wrapt.adapter_factory(
        partial(argspec_factory, skip=skip, return_type=return_type))

    @wrapt.decorator(adapter=adapter)
    def wrapper(wrapped, instance, args, kwargs):
        return wrapped(getattr(instance, prop_name), prop_name, *args,
                       **kwargs)

    return wrapper
Esempio n. 6
0
def _inject_api_method(
    clazz: type,
) -> None:
    """
    Create a decorator which does nothing except for modifying the function signature in the docstring.

    The function to be decorated must be a class method and is allowed only to have positional arguments,
    and variable keyword arguments (**kwargs).

    The resulting decorated function will containing only the positional arguments (including original type annotations)
    and possibly keyword only arguments. In this example signature might def fn(foo, bar, *, baz, quux),
    `baz` and `quux` are the keyword only arguments.

    Parameters
    ----------
    clazz
        The class for which to create the query. Must not be abstract.

    Returns
    -------
    :class:`callable`
        The decorator as described above.
    """

    def argspec_factory(orig_fn: Callable) -> Callable:
        orig_params = inspect.signature(orig_fn).parameters
        # maintain the original signature if the subclass has overriden the method
        # this will lose the docstring of the original function
        parameters = {
            k: v
            for k, v in orig_params.items()
            if k != "cls"
            and v.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD)
        }
        annotations = {
            k: v for k, v in clazz._annotations().items() if k not in parameters
        }

        sig = inspect.signature(lambda _: _)
        sig = sig.replace(
            parameters=[Parameter("cls", kind=Parameter.POSITIONAL_ONLY)]
            + list(parameters.values())
            + [
                Parameter(k, kind=Parameter.KEYWORD_ONLY, annotation=a)
                for k, a in sorted(annotations.items())
            ]
            + [Parameter("kwargs", kind=Parameter.VAR_KEYWORD)]
        )
        # modify locals() for argspec factory
        import omnipath  # noqa: F401

        NoneType, pandas = type(None), pd

        exec(
            f"def adapter{sig}: pass".replace(" /,", ""),
            globals(),
            locals(),
        )
        return locals()["adapter"]

    if not isinstance(clazz, type):
        raise TypeError(
            f"Expected `clazz` to be a type, found `{type(clazz).__name__}`."
        )

    if isabstract(clazz):
        return

    @wrapt.decorator(adapter=wrapt.adapter_factory(argspec_factory))
    def wrapper(wrapped, _instance, args, kwargs):
        return wrapped(*args, **kwargs)

    if hasattr(clazz, "get") and not hasattr(clazz.get, "__wrapped__"):
        # overriding in subclass
        clazz.get = wrapper(unwrap(clazz.get))
        return

    clazz.get = wrapper(MethodType(_get_helper, clazz))