コード例 #1
0
ファイル: suite.py プロジェクト: qais-yousef/lisa
    def make_expressions(cls, callable_set, goal_type, tags_getter=None, non_reusable_type_set=None):
        """
        Create a list of :class:`exekall.engine.Expression` out of
        the given ``callable_set``.
        """

        op_set = {
            engine.Operator(
                callable_,
                tags_getter=tags_getter,
                non_reusable_type_set=non_reusable_type_set,
            )
            for callable_ in callable_set
        }

        root_op_set = {
            op
            for op in op_set
            if issubclass(op.value_type, goal_type)
        }

        class_ctx = engine.ClassContext.from_op_set(op_set)

        expr_list = class_ctx.build_expr_list(
            root_op_set,
            non_produced_handler='raise',
            cycle_handler='raise',
        )

        expr_list.sort(key=lambda expr: expr.get_id(full_qual=True, with_tags=True))

        return expr_list
コード例 #2
0
def sweep_param(callable_, param, start, stop, step=1):
    """
    Used to generate a stream of numbers or strings to feed to a callable.

    :param callable_: Callable the numbers will be used by.
    :type callable_: collections.abc.Callable

    :param param: Name of the parameter of the callable the numbers will be
        providing values for.
    :type param: str

    :param start: Starting value.
    :type start: str

    :param stop: End value (inclusive)
    :type stop: str

    :param step: Increment step.
    :type step: str

    If ``start == stop``, only that value will be yielded, and it can be of any
    type.

    The type used will either be one that is annotated on the callable, or the
    one from the default value if no annotation is available, or float if no
    default value is found. The value will then be built by passing the string
    to the type as only parameter.
    """

    op = engine.Operator(callable_)
    annot = op.get_prototype()[0]
    try:
        type_ = annot[param]
    except KeyError:
        sig = op.signature
        default = sig.parameters[param].default
        if default is not inspect.Parameter.default and default is not None:
            type_ = type(default)
        else:
            type_ = str

    if start == stop:
        yield type_(start)
    else:
        i = type_(start)
        step = type_(step)
        stop = type_(stop)
        while i <= stop:
            yield type_(i)
            i += step
コード例 #3
0
def build_op_set(callable_pool, non_reusable_type_set, allowed_pattern_set,
                 adaptor):
    op_set = {
        engine.Operator(callable_,
                        non_reusable_type_set=non_reusable_type_set,
                        tags_getter=adaptor.get_tags)
        for callable_ in callable_pool
    }

    filtered_op_set = adaptor.filter_op_set(op_set)
    # Make sure we have all the explicitely allowed operators
    filtered_op_set.update(
        op for op in op_set
        if utils.match_name(op.get_name(full_qual=True), allowed_pattern_set))
    return filtered_op_set
コード例 #4
0
def _get_callable_set(module, visited_obj_set, verbose):
    log_f = info if verbose else debug
    callable_pool = set()

    for name, obj in vars(module).items():
        # skip internal classes that may end up being exposed as a global
        if inspect.getmodule(obj) is engine:
            continue

        if id(obj) in visited_obj_set:
            continue
        else:
            visited_obj_set.add(id(obj))

        # If it is a class, get the list of methods
        if isinstance(obj, type):
            callable_list = [
                callable_
                for name, callable_ in inspect.getmembers(obj,
                                                          predicate=callable)
            ]
            callable_list.append(obj)
        else:
            callable_list = [obj]

        callable_list = [c for c in callable_list if callable(c)]

        for callable_ in callable_list:
            try:
                op = engine.Operator(callable_)
                param_list, return_type = op.get_prototype()
            # If the callable is partially annotated, warn about it since it is
            # likely to be a mistake.
            except engine.PartialAnnotationError as e:
                log_f('Partially-annotated callable will not be used: {e}'.
                      format(
                          callable=get_name(callable_),
                          e=e,
                      ))
                continue
            # If some annotations fail to resolve
            except NameError as e:
                log_f(
                    'callable with unresolvable annotations will not be used: {e}'
                    .format(
                        callable=get_name(callable_),
                        e=e,
                    ))
                continue
            # If something goes wrong, that means it is not properly annotated
            # so we just ignore it
            except (AttributeError, ValueError, KeyError,
                    engine.AnnotationError):
                continue

            # Swap-in a wrapper object, so we keep track on the class on which
            # the function was looked up
            if op.is_method:
                callable_ = engine.UnboundMethod(callable_, obj)

            # Also make sure we don't accidentally get callables that will
            # return a abstract base class instance, since that would not work
            # anyway.
            if inspect.isabstract(return_type):
                log_f(
                    'Instances of {} will not be created since it has non-implemented abstract methods'
                    .format(get_name(return_type, full_qual=True)))
            else:
                callable_pool.add(callable_)
    return callable_pool
コード例 #5
0
def _get_callable_set(namespace, visited_obj_set, verbose):
    """
    :param namespace: Module or class
    """
    log_f = info if verbose else debug
    callable_pool = set()

    if id(namespace) in visited_obj_set:
        return callable_pool
    else:
        visited_obj_set.add(id(namespace))

    attributes = [
        callable_ for name, callable_ in inspect.getmembers(namespace,
                                                            predicate=callable)
    ]
    if isinstance(namespace, type):
        attributes.append(namespace)

    attributes = [
        attr for attr in attributes
        if (id(attr) not in visited_obj_set and
            # skip internal classes that may end up being exposed as a global
            inspect.getmodule(attr) is not engine)
    ]
    visited_obj_set.update(attributes)

    for callable_ in attributes:
        # Explore the class attributes as well for nested types
        if (isinstance(callable_, type) and
                # Do not recurse into the "_type" class attribute of namedtuple, as
                # it has broken globals Python 3.6. The crazy checks are a
                # workaround the fact that there is no direct way to detect if a
                # class is a namedtuple.
                not (isinstance(namespace, type) and callable_.__name__
                     == '_type' and issubclass(callable_, tuple) and hasattr(
                         callable_, '_make') and hasattr(callable_, '_asdict')
                     and hasattr(callable_, '_replace'))):
            callable_pool.update(
                _get_callable_set(callable_, visited_obj_set, verbose))

        try:
            op = engine.Operator(callable_)
            # Trigger exceptions if they have to be raised
            op.prototype
        # If the callable is partially annotated, warn about it since it is
        # likely to be a mistake.
        except engine.PartialAnnotationError as e:
            log_f(
                'Partially-annotated callable "{callable}" will not be used: {e}'
                .format(
                    callable=get_name(callable_),
                    e=e,
                ))
            continue
        # If some annotations fail to resolve
        except NameError as e:
            log_f(
                'callable "{callable}" with unresolvable annotations will not be used: {e}'
                .format(
                    callable=get_name(callable_),
                    e=e,
                ))
            continue
        # If something goes wrong, that means it is not properly annotated
        # so we just ignore it
        except (AttributeError, ValueError, KeyError, engine.AnnotationError):
            continue

        def has_typevar(op):
            return any(
                isinstance(x, typing.TypeVar)
                for x in {op.value_type, *op.prototype[0].values()})

        # Swap-in a wrapper object, so we keep track on the class on which
        # the function was looked up
        if op.is_method:
            assert isinstance(namespace, type)
            callable_ = engine.UnboundMethod(callable_, namespace)
            # If the return annotation was a TypeVar, give a chance to
            # Operator to resolve it in case it was redefined in a
            # subclass, and we are inspecting that subclass
            if has_typevar(op):
                op = engine.Operator(callable_)

        def check_typevar_name(cls, name, var):
            if name != var.__name__:
                log_f(
                    '__name__ of {cls}.{var.__name__} typing.TypeVar differs from the name it is bound to "{name}", which will prevent using it for polymorphic parameters or return annotation'
                    .format(
                        cls=get_name(cls, full_qual=True),
                        var=var,
                        name=name,
                    ))
            return name

        type_vars = sorted(
            check_typevar_name(op.value_type, name, attr)
            for name, attr in inspect.getmembers(
                op.value_type, lambda x: isinstance(x, typing.TypeVar)))

        # Also make sure we don't accidentally get callables that will
        # return a abstract base class instance, since that would not work
        # anyway.
        if inspect.isabstract(op.value_type):
            log_f(
                'Instances of {} will not be created since it has non-implemented abstract methods'
                .format(get_name(op.value_type, full_qual=True)))
        elif type_vars:
            log_f(
                'Instances of {} will not be created since it has non-overridden TypeVar class attributes: {}'
                .format(get_name(op.value_type, full_qual=True),
                        ', '.join(type_vars)))
        elif has_typevar(op):
            log_f(
                'callable "{callable}" with non-resolved associated TypeVar annotations will not be used'
                .format(callable=get_name(callable_), ))
        else:
            callable_pool.add(callable_)

    return callable_pool