Source code for ways.parsing.tracehelper

#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''Common functions used for tracing that cannot go into trace.py.

This module is used in situation.py. If a function in this module were used
and imported by trace.py, it'd create a cyclic import.

'''

# IMPORT STANDARD LIBRARIES
import functools

# IMPORT THIRD-PARTY LIBRARIES
import six


def _trace_method_resolution(context, method, plugins=False):
    '''Show the progression of how a Context's method is resolved.

    This function does that actual work of trace_method_resolution.

    Args:
        context (:class:`ways.api.Context`):
            Some Context to alter and get the items of back.
        method (callable):
            Some function on a Context object.
        plugins (:obj:`bool`, optional):
            If False, the result at every step of the method will be returned.
            If True, the Plugin that created each result will be returned al
            along with the result at every step. Default is False.

    Returns:
        list: The plugin resolution at each step.

    '''
    def substitute_return(obj, *args, **kwargs):  # pylint: disable=unused-argument
        '''Just return the first object that was given to the function.

        Args:
            args: The positional items of get_all_plugins, which we will ignore.
            kwargs: The keyword items of get_all_plugins, which we will ignore.

        Returns:
            The object.

        '''
        return obj

    all_plugins = context.get_all_plugins()

    results = []
    for index in six.moves.range(1, len(all_plugins) + 1):
        context.get_all_plugins = \
            functools.partial(substitute_return, all_plugins[:index])

        known_exceptions = (
            # If you're using OS-specific plugins and the very first plugin
            # is incompatible, it'll cause errors with certain methods
            #
            # This behavior should not stop this function from running because
            # the next plugin after might be fine. Just return None for errors
            #
            RuntimeError,
        )
        try:
            result = method()
        except known_exceptions:
            result = None

        if plugins:
            results.append((result, all_plugins[index - 1]))
        else:
            results.append(result)

    return results


[docs]def trace_method_resolution(method, plugins=False): '''Show the progression of how a Context's method is resolved. Args: method (callable): Some function on a Context object. plugins (:obj:`bool`, optional): If False, the result at every step of the method will be returned. If True, the Plugin that created each result will be returned al along with the result at every step. Default is False. Returns: list: The plugin resolution at each step. ''' context = method.__self__ original = context.get_all_plugins output = [] try: output = _trace_method_resolution(context, method, plugins) except Exception: context.get_all_plugins = original raise context.get_all_plugins = original return output