Exemple #1
0
 def evaluator(_, transformation: Transformation) -> AnyType:
     if callable(x):
         _x = x(**dependency_injection.resolve_dependencies(
             x, transformation._available_symbols).as_kwargs)
         dbg("x resolved to '{}'".format(_x))
     else:
         _x = x
     if callable(y):
         _y = y(**dependency_injection.resolve_dependencies(
             y, transformation._available_symbols).as_kwargs)
         dbg("y resolved to '{}'".format(_y))
     else:
         _y = y
     return operator(_x, _y)
def test_resolve_dependencies_doesnt_get_hung_up_on_None_though():
    def func(foo, bar=None):
        pass

    deps = resolve_dependencies(func, {"foo": 1, "bar": True})
    assert deps.as_args == (1, True)
    assert deps.as_kwargs == {"foo": 1, "bar": True}
def test_resolve_dependencies_honors_kwarg_default():
    def func(foo, bar=False):
        pass

    deps = resolve_dependencies(func, {"foo": 1})
    assert deps.as_args == (1, False)
    assert deps.as_kwargs == {"foo": 1, "bar": False}
def test_resolve_dependencies_honors_kwarg_default_of_None():
    def func(foo, bar=None):
        pass

    deps = resolve_dependencies(func, {"foo": 1})
    assert deps.as_args == (1, None)
    assert deps.as_kwargs == {"foo": 1, "bar": None}
Exemple #5
0
def test_resolve_dependencies_honors_kwarg_default_of_None():
    def func(foo, bar=None):
        pass

    deps = resolve_dependencies(func, {'foo': 1})
    assert deps.as_args == (1, None)
    assert deps.as_kwargs == {'foo': 1, 'bar': None}
Exemple #6
0
def test_resolve_dependencies_honors_kwarg_default():
    def func(foo, bar=False):
        pass

    deps = resolve_dependencies(func, {'foo': 1})
    assert deps.as_args == (1, False)
    assert deps.as_kwargs == {'foo': 1, 'bar': False}
Exemple #7
0
def test_resolve_dependencies_resolves_kwarg():
    def func(foo, bar=False):
        pass

    deps = resolve_dependencies(func, {'foo': 1, 'bar': True})
    assert deps.as_args == (1, True)
    assert deps.as_kwargs == {'foo': 1, 'bar': True}
Exemple #8
0
def test_resolve_dependencies_doesnt_get_hung_up_on_None_though():
    def func(foo, bar=None):
        pass

    deps = resolve_dependencies(func, {'foo': 1, 'bar': True})
    assert deps.as_args == (1, True)
    assert deps.as_kwargs == {'foo': 1, 'bar': True}
Exemple #9
0
 def loop(in_except):
     for function, prev_func in functions_iter:
         if _return_after is not None and prev_func is not _NO_PREVIOUS:
             if prev_func.__name__ == _return_after:
                 break
         try:
             deps = resolve_dependencies(function, state)
             skip = (
                 # When function wants exception but we don't have it.
                 not in_except
                 and 'exception' in deps.signature.required or
                 # When function doesn't want exception but we have it.
                 in_except and 'exception'
                 not in deps.signature.parameters)
             if not skip:
                 new_state = function(**deps.as_kwargs)
                 if new_state is not None:
                     state.update(new_state)
                 if in_except and state['exception'] is None:
                     # exception is cleared, return to normal flow
                     if PYTHON_2:
                         sys.exc_clear()
                     return
         except:
             if _raise_immediately:
                 raise
             state['exception'] = sys.exc_info()[1]
             loop(True)
             if in_except:
                 # an exception occurred while we were handling another
                 # exception, but now it's been cleared, so we return to
                 # the normal flow
                 return
     if in_except:
         raise  # exception hasn't been handled, reraise
def test_resolve_dependencies_resolves_kwarg():
    def func(foo, bar=False):
        pass

    deps = resolve_dependencies(func, {"foo": 1, "bar": True})
    assert deps.as_args == (1, True)
    assert deps.as_kwargs == {"foo": 1, "bar": True}
def cast(website, request, state):
    """Implement typecasting (differently from stock Aspen).

    When matching paths, Aspen looks for ``/%foo/`` and then foo is a variable
    with the value in the URL path, so ``/bar/`` would end up with
    ``foo='bar'``.

    There's a dictionary at ``website.typecasters`` that maps variable names to
    functions, dependency-injectable as with ``website.algorithm``
    (state-chain) functions. If an entry exists in ``typecasters`` for a given
    path variable, then the value of ``path[part]`` is replaced with the result
    of calling the function.

    Before calling your cast function, we add an additional value to the state
    dict at ``path_part``: the URL path part that matched, as a string. That is
    user input, so handle it carefully. It's your job to raise
    ``Response(40x)`` if it's bad input.

    """
    typecasters = website.typecasters
    path = request.line.uri.path

    for part in path.keys():
        if part not in typecasters:
            continue
        state['path_part'] = path[part]
        path.popall(part)
        func = typecasters[part]
        path[part] = func(*resolve_dependencies(func, state).as_args)
Exemple #12
0
def test_resolve_dependencies_resolves_dependencies():
    def func(foo):
        pass

    deps = resolve_dependencies(func, {'foo': 1})
    assert deps.signature.parameters == ('foo', )
    assert deps.signature.required == ('foo', )
    assert deps.signature.optional == {}
    assert deps.as_args == (1, )
    assert deps.as_kwargs == {'foo': 1}
def test_resolve_dependencies_resolves_dependencies():
    def func(foo):
        pass

    deps = resolve_dependencies(func, {"foo": 1})
    assert deps.signature.parameters == ("foo",)
    assert deps.signature.required == ("foo",)
    assert deps.signature.optional == {}
    assert deps.as_args == (1,)
    assert deps.as_kwargs == {"foo": 1}
Exemple #14
0
 def _apply_handlers(self, *handlers: Union[Callable, Exception]) -> None:
     dbg("Applying handlers.")
     for handler in handlers:
         if _is_flow_control(handler):
             raise handler
         kwargs = dependency_injection.resolve_dependencies(
             handler, self._available_symbols).as_kwargs
         if isinstance(handler, Transformation):
             kwargs["input"] = self.states.current_node or self.states.root
             kwargs["copy"] = False
         dbg(f"Applying handler {handler}.")
         self.states.previous_result = handler(**kwargs)
Exemple #15
0
 def _apply_handlers(self, *handlers) -> None:
     dbg('Applying handlers.')
     for handler in handlers:
         if _is_flow_control(handler):
             raise handler
         kwargs = dependency_injection.resolve_dependencies(
             handler, self._available_symbols).as_kwargs
         if isinstance(handler, Transformation):
             kwargs[
                 'transformation_root'] = self.states.current_element or self.states.root
             kwargs['copy'] = False
         dbg("Applying handler {}.".format(handler))
         self.states.previous_result = handler(**kwargs)
Exemple #16
0
 def render_notifications(self, state):
     r = []
     escape = state['escape']
     state['escape'] = lambda a: a
     for name in self.notifications:
         try:
             f = getattr(notifications, name)
             typ, msg = f(*resolve_dependencies(f, state).as_args)
             r.append(dict(jsonml=msg, name=name, type=typ))
         except Exception as e:
             self._tell_sentry(e, state)
     state['escape'] = escape
     return r
Exemple #17
0
 def render_notifications(self, state):
     r = []
     escape = state['escape']
     state['escape'] = lambda a: a
     for name in self.notifications:
         try:
             f = getattr(notifications, name)
             typ, msg = f(*resolve_dependencies(f, state).as_args)
             r.append(dict(jsonml=msg, name=name, type=typ))
         except Exception as e:
             self._tell_sentry(e, state)
     state['escape'] = escape
     return r
Exemple #18
0
def _apply_handlers(handlers, context):
    echo(click.style(os.path.relpath(context['filepath']), fg='yellow'))
    for handler in handlers:
        kwargs = dependency_injection.resolve_dependencies(handler,
                                                           context).as_kwargs

        handler_verbosity = getattr(handler, "verbosity", 1)
        handler_name = getattr(handler, "verbose_name", handler.__name__)
        echo("\n - {}".format(handler_name), verbosity=handler_verbosity)

        try:
            context['input'] = handler(**kwargs)
        except SkipHandler:
            continue
        except AbortHandling as e:
            echo(str(e), verbosity=e.verbosity)
            break

    context.pop('input', None)
Exemple #19
0
 def loop(in_except):
     signatures = self._signatures
     for function, prev_func in functions_iter:
         if _return_after is not None and prev_func is not _NO_PREVIOUS:
             if prev_func.__name__ == _return_after:
                 break
         try:
             if function not in signatures:
                 signatures[function] = get_signature(function)
             deps = resolve_dependencies(signatures[function], state)
             skip = (
                 # When function wants exception but we don't have it.
                 not in_except and 'exception' in deps.signature.required
                 or
                 # When function doesn't want exception but we have it.
                 in_except and 'exception' not in deps.signature.parameters
             )
             if not skip:
                 new_state = function(**deps.as_kwargs)
                 if new_state is not None:
                     state.update(new_state)
                 if in_except and state['exception'] is None:
                     # exception is cleared, return to normal flow
                     if PYTHON_2:
                         sys.exc_clear()
                     return
         except:
             if _raise_immediately:
                 raise
             state['exception'] = sys.exc_info()[1]
             loop(True)
             if in_except:
                 # an exception occurred while we were handling another
                 # exception, but now it's been cleared, so we return to
                 # the normal flow
                 return
     if in_except:
         raise  # exception hasn't been handled, reraise
Exemple #20
0
 def render_in_english(self):
     f = self.lazy_body
     fake_state = {}
     from liberapay.i18n.base import LOCALE_EN, add_helpers_to_context
     add_helpers_to_context(fake_state, LOCALE_EN)
     return f(*resolve_dependencies(f, fake_state).as_args)
Exemple #21
0
 def render_body(self, state):
     f = self.lazy_body
     self.body = f(*resolve_dependencies(f, state).as_args)
Exemple #22
0
 def render_body(self, state):
     f = self.lazy_body
     self.body = f(*resolve_dependencies(f, state).as_args)
Exemple #23
0
    def run(self, _raise_immediately=None, _return_after=None, **state):
        """Run through the functions in the :py:attr:`functions` list.

        :param bool _raise_immediately: if not ``None``, will override any
            default for ``raise_immediately`` that was set in the constructor

        :param str _return_after: if not ``None``, return after calling the function
            with this name

        :param dict state: remaining keyword arguments are used for the initial
            state dictionary for this run of the algorithm

        :raises: :py:exc:`FunctionNotFound`, if there is no function named
            ``_return_after``

        :returns: a dictionary representing the final algorithm state

        The state dictionary is initialized with three items (their default
        values can be overriden using keyword arguments to :py:func:`run`):

         - ``algorithm`` - a reference to the parent :py:class:`Algorithm` instance
         - ``state`` - a circular reference to the state dictionary
         - ``exception`` - ``None``

        For each function in the :py:attr:`functions` list, we look at the
        function signature and compare it to the current value of ``exception``
        in the state dictionary. If ``exception`` is ``None`` then we skip any
        function that asks for ``exception``, and if ``exception`` is *not*
        ``None`` then we only call functions that *do* ask for it. The upshot
        is that any function that raises an exception will cause us to
        fast-forward to the next exception-handling function in the list.

        Here are some further notes on exception handling:

         - If a function provides a default value for ``exception``, then that
           function will be called whether or not there is an exception being
           handled.

         - You should return ``{'exception': None}`` to reset exception
           handling. Under Python 2 we will call ``sys.exc_clear`` for you
           (under Python 3 exceptions are cleared automatically at the end of
           except blocks).

         - If ``exception`` is not ``None`` after all functions have been run,
           then we re-raise it.

         - If ``raise_immediately`` evaluates to ``True`` (looking first at any
           per-call ``_raise_immediately`` and then at the instance default),
           then we re-raise any exception immediately instead of
           fast-forwarding to the next exception handler.

        """

        if _raise_immediately is None:
            _raise_immediately = self.default_raise_immediately

        if _return_after is not None:
            if _return_after not in self.get_names():
                raise FunctionNotFound(_return_after)

        if 'algorithm' not in state:    state['algorithm'] = self
        if 'state' not in state:        state['state'] = state
        if 'exception' not in state:    state['exception'] = None

        for function in self.functions:
            function_name = function.__name__
            try:
                deps = resolve_dependencies(function, state)
                have_exception = state['exception'] is not None
                if 'exception' in deps.signature.required and not have_exception:
                    pass    # Function wants exception but we don't have it.
                elif 'exception' not in deps.signature.parameters and have_exception:
                    pass    # Function doesn't want exception but we have it.
                else:
                    new_state = function(**deps.as_kwargs)
                    if new_state is not None:
                        if PYTHON_2:
                            if 'exception' in new_state:
                                if new_state['exception'] is None:
                                    sys.exc_clear()
                        state.update(new_state)
            except:
                ExceptionClass, exception = sys.exc_info()[:2]
                state['exception'] = exception
                if _raise_immediately:
                    raise

            if _return_after is not None and function_name == _return_after:
                break

        if state['exception'] is not None:
            if PYTHON_2:

                # Under Python 2, raising state['exception'] means the
                # traceback stops at this reraise. We want the traceback to go
                # back to where the exception was first raised, and a naked
                # raise will reraise the current exception.

                raise

            else:

                # Under Python 3, exceptions are cleared at the end of the
                # except block, meaning we have no current exception to reraise
                # here. Thankfully, the traceback off this reraise will show
                # back to the original exception.

                raise state['exception']

        return state
Exemple #24
0
 def render_in_english(self):
     f = self.lazy_body
     fake_state = {}
     from liberapay.i18n.base import LOCALE_EN, add_helpers_to_context
     add_helpers_to_context(fake_state, LOCALE_EN)
     return f(*resolve_dependencies(f, fake_state).as_args)
Exemple #25
0
def check_callable(cllbl):
    deps = resolve_dependencies(cllbl, {'foo': 1, 'bar': True})
    assert deps.as_args == (1, True)
    assert deps.as_kwargs == {'foo': 1, 'bar': True}
Exemple #26
0
 def callable_evaluator(transformation):
     kwargs = dependency_injection.resolve_dependencies(
         constraints, transformation._available_symbols).as_kwargs
     return MatchesAttributes(constraints(**kwargs))(
         transformation.states.current_element)
def check_callable(cllbl):
    deps = resolve_dependencies(cllbl, {"foo": 1, "bar": True})
    assert deps.as_args == (1, True)
    assert deps.as_kwargs == {"foo": 1, "bar": True}