Пример #1
0
    def _method_factory(self, pid):
        """Create a custom function signature with docstring, instantiate it and
        pass it to a wrapper which will actually call the process.

        Parameters
        ----------
        pid: str
          Identifier of the WPS process.

        Returns
        -------
        func
          A Python function calling the remote process, complete with docstring and signature.
        """

        process = self._processes[pid]

        required_inputs_first = sorted(process.dataInputs, key=sort_inputs_key)

        input_names = []
        # defaults will be set to the function's __defaults__:
        # A tuple containing default argument values for those arguments that have defaults,
        # or None if no arguments have a default value.
        defaults = []
        for inpt in required_inputs_first:
            input_names.append(sanitize(inpt.identifier))
            if inpt.minOccurs == 0 or inpt.defaultValue is not None:
                default = inpt.defaultValue if inpt.dataType != "ComplexData" else None
                defaults.append(utils.from_owslib(default, inpt.dataType))
        defaults = tuple(defaults) if defaults else None

        body = dedent("""
            inputs = locals()
            inputs.pop('self')
            return self._execute('{pid}', **inputs)
        """).format(pid=pid)

        func_builder = FunctionBuilder(
            name=sanitize(pid),
            doc=utils.build_process_doc(process),
            args=["self"] + input_names,
            defaults=defaults,
            body=body,
            filename=__file__,
            module=self.__module__,
        )

        self._inputs[pid] = {}
        if hasattr(process, "dataInputs"):
            self._inputs[pid] = OrderedDict(
                (i.identifier, i) for i in process.dataInputs)

        self._outputs[pid] = {}
        if hasattr(process, "processOutputs"):
            self._outputs[pid] = OrderedDict(
                (o.identifier, o) for o in process.processOutputs)

        func = func_builder.get_func()

        return func
Пример #2
0
def test_FunctionBuilder_modify():
    fb = FunctionBuilder('return_five', doc='returns the integer 5',
                         body='return 5')
    f = fb.get_func()
    assert f() == 5

    fb.varkw = 'kw'
    f_kw = fb.get_func()
    assert f_kw(ignored_arg='ignored_val') == 5
Пример #3
0
def test_FunctionBuilder_modify():
    fb = FunctionBuilder('return_five', doc='returns the integer 5',
                         body='return 5')
    f = fb.get_func()
    assert f() == 5

    fb.varkw = 'kw'
    f_kw = fb.get_func()
    assert f_kw(ignored_arg='ignored_val') == 5
Пример #4
0
    def _method_factory(self, pid):
        """Create a custom function signature with docstring, instantiate it and
        pass it to a wrapper which will actually call the process.

        Parameters
        ----------
        pid: str
          Identifier of the WPS process.

        Returns
        -------
        func
          A Python function calling the remote process, complete with docstring and signature.
        """

        process = self._processes[pid]

        input_defaults = OrderedDict()
        for inpt in process.dataInputs:
            iid = sanitize(inpt.identifier)
            default = getattr(inpt, "defaultValue", None) if inpt.dataType != 'ComplexData' else None
            input_defaults[iid] = utils.from_owslib(default, inpt.dataType)

        body = dedent("""
            inputs = locals()
            inputs.pop('self')
            return self._execute('{pid}', **inputs)
        """).format(pid=pid)

        func_builder = FunctionBuilder(
            name=sanitize(pid),
            doc=utils.build_process_doc(process),
            args=["self"] + list(input_defaults),
            defaults=tuple(input_defaults.values()),
            body=body,
            filename=__file__,
            module=self.__module__,
        )

        self._inputs[pid] = {}
        if hasattr(process, "dataInputs"):
            self._inputs[pid] = OrderedDict(
                (i.identifier, i) for i in process.dataInputs
            )

        self._outputs[pid] = {}
        if hasattr(process, "processOutputs"):
            self._outputs[pid] = OrderedDict(
                (o.identifier, o) for o in process.processOutputs
            )

        func = func_builder.get_func()

        return func
Пример #5
0
def test_get_invocation_sig_str(
    args, varargs, varkw, defaults, invocation_str, sig_str
):
    fb = FunctionBuilder(
        name='return_five',
        body='return 5',
        args=args,
        varargs=varargs,
        varkw=varkw,
        defaults=defaults
    )

    assert fb.get_invocation_str() == invocation_str
    assert fb.get_sig_str() == sig_str
Пример #6
0
def test_remove_kwonly_arg():
    # example adapted from https://github.com/mahmoud/boltons/issues/123

    def darkhelm_inject_loop(func):
        sig = inspect.signature(func)
        loop_param = sig.parameters['loop'].replace(default=None)
        sig = sig.replace(parameters=[loop_param])

        def add_loop(args, kwargs):
            bargs = sig.bind(*args, **kwargs)
            bargs.apply_defaults()
            if bargs.arguments['loop'] is None:
                bargs.arguments['loop'] = "don't look at me, I just use gevent"

            return bargs.arguments

        def wrapper(*args, **kwargs):
            return func(**add_loop(args, kwargs))

        return wraps(func, injected=['loop'])(wrapper)

    @darkhelm_inject_loop
    def example(test='default', *, loop='lol'):
        return loop

    fb_example = FunctionBuilder.from_func(example)
    assert 'test' in fb_example.args
    assert fb_example.get_defaults_dict()['test'] == 'default'

    assert 'loop' not in fb_example.kwonlyargs
    assert 'loop' not in fb_example.kwonlydefaults
Пример #7
0
def wraps(func):
    """Custom wraps() function for decorators

    This one differs from functiools.wraps and boltons.funcutils.wraps in
    that it allows *adding* keyword arguments to the function signature.

    >>> def decorator(func):
    >>>   @wraps(func)
    >>>   def wrapper(*args, extra_param=None, **kwargs):
    >>>      print("Called with extra_param=%s" % extra_param)
    >>>      func(*args, **kwargs)
    >>>   return wrapper
    >>>
    >>> @decorator()
    >>> def test(arg1, arg2, arg3='default'):
    >>>     pass
    >>>
    >>> test('val1', 'val2', extra_param='xyz')
    """

    fb = FunctionBuilder.from_func(func)
    def wrapper_wrapper(wrapper_func):
        fb_wrapper = FunctionBuilder.from_func(wrapper_func)
        fb.kwonlyargs += fb_wrapper.kwonlyargs
        fb.kwonlydefaults.update(fb_wrapper.kwonlydefaults)
        fb.body = 'return _call(%s)' % fb.get_invocation_str()
        execdict = dict(_call=wrapper_func, _func=func)
        fully_wrapped = fb.get_func(execdict)
        fully_wrapped.__wrapped__ = func
        return fully_wrapped

    return wrapper_wrapper
Пример #8
0
def test_remove_kwonly_arg():
    # example adapted from https://github.com/mahmoud/boltons/issues/123

    def darkhelm_inject_loop(func):
        sig = inspect.signature(func)
        loop_param = sig.parameters['loop'].replace(default=None)
        sig = sig.replace(parameters=[loop_param])

        def add_loop(args, kwargs):
            bargs = sig.bind(*args, **kwargs)
            bargs.apply_defaults()
            if bargs.arguments['loop'] is None:
                bargs.arguments['loop'] = "don't look at me, I just use gevent"

            return bargs.arguments

        def wrapper(*args, **kwargs):
            return func(**add_loop(args, kwargs))

        return wraps(func, injected=['loop'])(wrapper)

    @darkhelm_inject_loop
    def example(test='default', *, loop='lol'):
        return loop

    fb_example = FunctionBuilder.from_func(example)
    assert 'test' in fb_example.args
    assert fb_example.get_defaults_dict()['test'] == 'default'

    assert 'loop' not in fb_example.kwonlyargs
    assert 'loop' not in fb_example.kwonlydefaults
Пример #9
0
 def __repr__(self):
     chunks = [self.__class__.__name__]
     if self.subspec != T:
         chunks.append('({!r})'.format(self.subspec))
     else:
         chunks.append('()')
     for fname, args, _ in reversed(self._iter_stack):
         meth = getattr(self, fname)
         fb = FunctionBuilder.from_func(meth)
         fb.args = fb.args[1:]  # drop self
         arg_names = fb.get_arg_names()
         # TODO: something fancier with defaults:
         chunks.append("." + fname)
         if len(args) == 0:
             chunks.append("()")
         elif len(arg_names) == 1:
             assert len(args) == 1
             chunks.append('({!r})'.format(args[0]))
         elif arg_names:
             chunks.append('({})'.format(", ".join([
                 '{}={!r}'.format(name, val)
                 for name, val in zip(arg_names, args)
             ])))
         else:
             # p much just slice bc no kwargs
             chunks.append('({})'.format(", ".join(['%s' % a
                                                    for a in args])))
     return ''.join(chunks)
Пример #10
0
def wraps(func):
    """Custom wraps() function for decorators

    This one differs from functiools.wraps and boltons.funcutils.wraps in
    that it allows *adding* keyword arguments to the function signature.

    >>> def decorator(func):
    >>>   @wraps(func)
    >>>   def wrapper(*args, extra_param=None, **kwargs):
    >>>      print("Called with extra_param=%s" % extra_param)
    >>>      func(*args, **kwargs)
    >>>   return wrapper
    >>>
    >>> @decorator()
    >>> def test(arg1, arg2, arg3='default'):
    >>>     pass
    >>>
    >>> test('val1', 'val2', extra_param='xyz')
    """

    fb = FunctionBuilder.from_func(func)

    def wrapper_wrapper(wrapper_func):
        fb_wrapper = FunctionBuilder.from_func(wrapper_func)
        fb.kwonlyargs += fb_wrapper.kwonlyargs
        fb.kwonlydefaults.update(fb_wrapper.kwonlydefaults)
        fb.body = 'return _call(%s)' % fb.get_invocation_str()
        execdict = dict(_call=wrapper_func, _func=func)
        fully_wrapped = fb.get_func(execdict)
        fully_wrapped.__wrapped__ = func
        return fully_wrapped

    return wrapper_wrapper
Пример #11
0
def test_get_arg_names():
    def example(req, test='default'):
        return req

    fb_example = FunctionBuilder.from_func(example)
    assert 'test' in fb_example.args
    assert fb_example.get_arg_names() == ('req', 'test')
    assert fb_example.get_arg_names(only_required=True) == ('req',)
Пример #12
0
def test_get_arg_names():
    def example(req, test='default'):
        return req

    fb_example = FunctionBuilder.from_func(example)
    assert 'test' in fb_example.args
    assert fb_example.get_arg_names() == ('req', 'test')
    assert fb_example.get_arg_names(only_required=True) == ('req',)
Пример #13
0
def test_defaults_dict():
    def example(req, test='default'):
        return req

    fb_example = FunctionBuilder.from_func(example)
    assert 'test' in fb_example.args
    dd = fb_example.get_defaults_dict()
    assert dd['test'] == 'default'
    assert 'req' not in dd
Пример #14
0
def test_defaults_dict():
    def example(req, test='default'):
        return req

    fb_example = FunctionBuilder.from_func(example)
    assert 'test' in fb_example.args
    dd = fb_example.get_defaults_dict()
    assert dd['test'] == 'default'
    assert 'req' not in dd
Пример #15
0
 def wrapper_wrapper(wrapper_func):
     fb_wrapper = FunctionBuilder.from_func(wrapper_func)
     fb.kwonlyargs += fb_wrapper.kwonlyargs
     fb.kwonlydefaults.update(fb_wrapper.kwonlydefaults)
     fb.body = 'return _call(%s)' % fb.get_invocation_str()
     execdict = dict(_call=wrapper_func, _func=func)
     fully_wrapped = fb.get_func(execdict)
     fully_wrapped.__wrapped__ = func
     return fully_wrapped
Пример #16
0
 def wrapper_wrapper(wrapper_func):
     fb_wrapper = FunctionBuilder.from_func(wrapper_func)
     fb.kwonlyargs += fb_wrapper.kwonlyargs
     fb.kwonlydefaults.update(fb_wrapper.kwonlydefaults)
     fb.body = 'return _call(%s)' % fb.get_invocation_str()
     execdict = dict(_call=wrapper_func, _func=func)
     fully_wrapped = fb.get_func(execdict)
     fully_wrapped.__wrapped__ = func
     return fully_wrapped
Пример #17
0
def test_get_invocation_sig_str(
    args,
    varargs,
    varkw,
    defaults,
    kwonlyargs,
    kwonlydefaults,
    invocation_str,
    sig_str,
):
    fb = FunctionBuilder(
        name="return_five",
        body="return 5",
        args=args,
        varargs=varargs,
        varkw=varkw,
        defaults=defaults,
        kwonlyargs=kwonlyargs,
        kwonlydefaults=kwonlydefaults,
    )

    assert fb.get_invocation_str() == invocation_str
    assert fb.get_sig_str() == sig_str
Пример #18
0
def get_fb(f, drop_self=True):
    # TODO: support partials
    if not (inspect.isfunction(f) or inspect.ismethod(f) or \
            inspect.isbuiltin(f)) and hasattr(f, '__call__'):
        if isinstance(getattr(f, '_sinter_fb', None), FunctionBuilder):
            return f._sinter_fb
        f = f.__call__  # callable objects

    if isinstance(getattr(f, '_sinter_fb', None), FunctionBuilder):
        return f._sinter_fb  # we'll take your word for it; good luck, lil buddy.

    ret = FunctionBuilder.from_func(f)

    if not all([isinstance(a, str) for a in ret.args]):
        raise TypeError('does not support anonymous tuple arguments'
                        ' or any other strange args for that matter.')
    if drop_self and isinstance(f, types.MethodType):
        ret.args = ret.args[1:]  # discard "self" on methods
    return ret
Пример #19
0
def get_fb(f, drop_self=True):
    # TODO: support partials
    if not (inspect.isfunction(f) or inspect.ismethod(f) or \
            inspect.isbuiltin(f)) and hasattr(f, '__call__'):
        if isinstance(getattr(f, '_sinter_fb', None), FunctionBuilder):
            return f._sinter_fb
        f = f.__call__  # callable objects

    if isinstance(getattr(f, '_sinter_fb', None), FunctionBuilder):
        return f._sinter_fb  # we'll take your word for it; good luck, lil buddy.

    ret = FunctionBuilder.from_func(f)

    if not all([isinstance(a, str) for a in ret.args]):
        raise TypeError('does not support anonymous tuple arguments'
                        ' or any other strange args for that matter.')
    if drop_self and isinstance(f, types.MethodType):
        ret.args = ret.args[1:]  # discard "self" on methods
    return ret
Пример #20
0
def proxy(remote_method: RemoteMethod, ordinal: int) -> Callable:
    """
    Generate a method proxying a remote method.

    The method will have the same signature as the remote method.

    However, its body will consist of a call to the ``Proxy`` class ``_call()`` method  to forward
    the method call across the network.

    :param remote_method: Remote method to proxy.
    :param ordinal: ordinal of remote method in class.
    """
    signature = inspect.signature(remote_method)

    # check that all parameters are positional or keyword and are serializable
    if not issubclass(signature.return_annotation, Serializable):
        raise TypeError(
            f"return type {signature.return_annotation} is not serializable")

    returntype = signature.return_annotation
    # skip "self"
    argnames: list[str] = list(signature.parameters)[1:]

    async def body(self: Proxy, *args: Serializable) -> returntype:
        arguments = bytearray()
        for i, arg in enumerate(args):
            try:
                arguments.extend(arg.serialize())
            except Exception as e:
                raise ArgumentSerializationError(f"argument {i}: {arg}") from e

        ret = await self._client.call(ordinal, arguments)

        try:
            return returntype.deserialize(ret)
        except Exception as e:
            raise ReturnDeserializationError(f"of type {returntype}") from e

    builder = FunctionBuilder.from_func(remote_method)
    builder.is_async = True
    builder.body = f"return await body(self, {','.join(argnames)})"

    return builder.get_func(execdict={"body": body})
Пример #21
0
def test_FunctionBuilder_add_arg_kwonly():
    fb = FunctionBuilder('return_val',
                         doc='returns the value',
                         body='return val')

    broken_func = fb.get_func()
    with pytest.raises(NameError):
        broken_func()

    fb.add_arg('val', default='default_val', kwonly=True)

    better_func = fb.get_func()
    assert better_func() == 'default_val'

    with pytest.raises(ValueError):
        fb.add_arg('val')

    assert better_func(val='keyword') == 'keyword'

    with pytest.raises(TypeError):
        assert better_func('positional')
    return
Пример #22
0
 def __repr__(self):
     base_args = ()
     if self.subspec != T:
         base_args = (self.subspec, )
     base = format_invocation(self.__class__.__name__,
                              base_args,
                              repr=bbrepr)
     chunks = [base]
     for fname, args, _ in reversed(self._iter_stack):
         meth = getattr(self, fname)
         fb = FunctionBuilder.from_func(meth)
         fb.args = fb.args[1:]  # drop self
         arg_names = fb.get_arg_names()
         # TODO: something fancier with defaults:
         kwargs = []
         if len(args) > 1 and arg_names:
             args, kwargs = (), zip(arg_names, args)
         chunks.append('.' +
                       format_invocation(fname, args, kwargs, repr=bbrepr))
     return ''.join(chunks)
Пример #23
0
def test_FunctionBuilder_add_arg_kwonly():
    fb = FunctionBuilder('return_val', doc='returns the value',
                         body='return val')

    broken_func = fb.get_func()
    with pytest.raises(NameError):
        broken_func()

    fb.add_arg('val', default='default_val', kwonly=True)

    better_func = fb.get_func()
    assert better_func() == 'default_val'

    with pytest.raises(ValueError):
        fb.add_arg('val')

    assert better_func(val='keyword') == 'keyword'

    with pytest.raises(TypeError):
        assert better_func('positional')
    return
Пример #24
0
def test_FunctionBuilder_add_arg():
    fb = FunctionBuilder('return_five', doc='returns the integer 5',
                         body='return 5')
    f = fb.get_func()
    assert f() == 5

    fb.add_arg('val')
    f = fb.get_func()
    assert f(val='ignored') == 5

    with pytest.raises(ValueError) as excinfo:
        fb.add_arg('val')
    excinfo.typename == 'ExistingArgument'

    fb = FunctionBuilder('return_val', doc='returns the value',
                         body='return val')

    broken_func = fb.get_func()
    with pytest.raises(NameError):
        broken_func()

    fb.add_arg('val', default='default_val')

    better_func = fb.get_func()
    assert better_func() == 'default_val'

    assert better_func('positional') == 'positional'
    assert better_func(val='keyword') == 'keyword'
Пример #25
0
    try:
        try:
            glom(target, spec)
        except GlomError as e:
            stack = _norm_stack(traceback.format_exc(), e)
    finally:
        traceback._some_str = _orig_some_str
    return stack


# quick way to get a function in this file, which doesn't have a glom
# package file path prefix on it. this prevents the function getting
# removed in the stack flattening.
from boltons.funcutils import FunctionBuilder
fb = FunctionBuilder(name='_raise_exc',
                     body='raise Exception("unique message")',
                     args=['t'])
_raise_exc = fb.get_func()

# NB: if we keep this approach, eventually
# boltons.funcutils.FunctionBuilder will put lines into the linecache,
# and comparisons may break


def test_regular_error_stack():
    actual = _make_stack({'results': [{'value': _raise_exc}]})
    expected = """\
Traceback (most recent call last):
  File "test_error.py", line ___, in _make_stack
    glom(target, spec)
  File "core.py", line ___, in glom
Пример #26
0
def test_FunctionBuilder_add_arg():
    fb = FunctionBuilder('return_five', doc='returns the integer 5',
                         body='return 5')
    f = fb.get_func()
    assert f() == 5

    fb.add_arg('val')
    f = fb.get_func()
    assert f(val='ignored') == 5

    with pytest.raises(ValueError) as excinfo:
        fb.add_arg('val')
    excinfo.typename == 'ExistingArgument'

    fb = FunctionBuilder('return_val', doc='returns the value',
                         body='return val')

    broken_func = fb.get_func()
    with pytest.raises(NameError):
        broken_func()

    fb.add_arg('val', default='default_val')

    better_func = fb.get_func()
    assert better_func() == 'default_val'

    assert better_func('positional') == 'positional'
    assert better_func(val='keyword') == 'keyword'
Пример #27
0
def test_FunctionBuilder_invalid_body():
    with pytest.raises(SyntaxError):
        FunctionBuilder(name="fails", body="*").get_func()
Пример #28
0
def test_FunctionBuilder_invalid_args():
    with pytest.raises(TypeError):
        FunctionBuilder(name="fails", foo="bar")