Ejemplo n.º 1
0
    def bind_partial(self, *args, **kwds):
        """
        Binds the provided positional and keyword arguments
        and returns a new ``Function`` object with an updated signature.
        """

        # We only need the signature, so clean the function body before eval'ing.
        empty_func = self.replace(tree=replace_fields(self.tree, body=[ast.Pass()]))
        signature = inspect.signature(empty_func.eval())
        bargs = signature.bind_partial(*args, **kwds)

        # Remove the bound arguments from the function AST
        bound_argnames = set(bargs.arguments.keys())
        new_tree = filter_function_def(self.tree, bound_argnames)

        # Add assignments for bound parameters
        assignments = []
        gen_sym = GenSym.for_tree(new_tree)
        new_bindings = {}
        for name, value in bargs.arguments.items():
            node, gen_sym, binding = reify_unwrapped(value, gen_sym)
            new_bindings.update(binding)
            assignments.append(ast.Assign(targets=[ast.Name(id=name, ctx=ast.Store())], value=node))

        new_globals = dict(self.globals)
        new_globals.update(new_bindings)

        new_tree = replace_fields(new_tree, body=assignments + new_tree.body)

        return Function(new_tree, new_globals, self.closure_vals, self._compiler_flags)
Ejemplo n.º 2
0
def test_replace_fields():
    node = ast.Name(id='x', ctx=ast.Load())

    new_node = replace_fields(node, id='y')
    assert new_node is not node
    assert new_node.id == 'y' and type(new_node.ctx) == ast.Load

    new_node = replace_fields(node, id='x')
    # no new object is created if the new value is the same as the old value
    assert new_node is node
    assert new_node.id == 'x' and type(new_node.ctx) == ast.Load
Ejemplo n.º 3
0
    def handle_YieldFrom(state, node, ctx):
        state, result = _peval_expression(state, node.value, ctx)

        # We cannot evaluate a yield expression,
        # so just wrap whatever we've got in a node and return.
        state, new_value = map_reify(state, result)
        return state, replace_fields(node, value=new_value)
Ejemplo n.º 4
0
 def increment(node, walk_field, **kwds):
     if isinstance(node, ast.Assign):
         return replace_fields(node, targets=node.targets, value=walk_field(node.value))
     elif isinstance(node, ast.Num):
         return ast.Num(n=node.n + 1)
     else:
         return node
Ejemplo n.º 5
0
def _handle_loop(node, state, ctx, visit_after, visiting_after, walk_field, **_):
    if not visiting_after:
        # Need to traverse fields explicitly since for the purposes of _replace_returns(),
        # the body of `orelse` field is not inside a loop.
        state = state.update(loop_nesting_ctr=state.loop_nesting_ctr + 1)
        state, new_body = walk_field(state, node.body, block_context=True)
        state = state.update(loop_nesting_ctr=state.loop_nesting_ctr - 1)
        state, new_orelse = walk_field(state, node.orelse, block_context=True)

        visit_after()
        return state, replace_fields(node, body=new_body, orelse=new_orelse)
    else:
        # If there was a return inside a loop, append a conditional break
        # to propagate the return otside all nested loops
        if state.return_inside_a_loop:
            new_nodes = [
                node,
                ast.If(
                    test=ast.Name(id=ctx.return_flag_var),
                    body=[ast.Break()],
                    orelse=[])]
        else:
            new_nodes = node

        # if we are at root level, reset the return-inside-a-loop flag
        if state.loop_nesting_ctr == 0:
            state = state.update(return_inside_a_loop=False)

        return state, new_nodes
Ejemplo n.º 6
0
def remove_simple_assignments(node):
    """
    Remove one assigment of the form `<variable> = <variable>` at a time,
    touching only the top level statements of the block.
    """

    remaining_nodes = list(node.body)
    new_nodes = []

    while len(remaining_nodes) > 0:
        cur_node = remaining_nodes.pop(0)
        if type(cur_node) == ast.Assign:
            can_remove, dest_name, src_name = _can_remove_assignment(cur_node, remaining_nodes)
            if can_remove:
                remaining_nodes = replace_name(
                    remaining_nodes, ctx=dict(dest_name=dest_name, src_name=src_name))
            else:
                new_nodes.append(cur_node)
        else:
            new_nodes.append(cur_node)

    if len(new_nodes) == len(node.body):
        return node

    return replace_fields(node, body=new_nodes)
Ejemplo n.º 7
0
def peval_comprehension(state, node, ctx):

    accum_cls = {
        ast.ListComp: ListAccumulator,
        ast.GeneratorExp: GeneratorExpAccumulator,
        ast.SetComp: SetAccumulator,
        ast.DictComp: DictAccumulator,
    }

    # variables from generators temporary mask bindings
    target_names = set()
    for generator in node.generators:
        if type(generator.target) == ast.Name:
            target_names.add(generator.target.id)
        else:
            target_names.update([elt.id for elt in generator.target.elts])

    # pre-evaluate the expression
    elt_bindings = dict(ctx.bindings)
    for name in target_names:
        if name in elt_bindings:
            del elt_bindings[name]
    elt_ctx = ctx.update(bindings=elt_bindings)

    if type(node) == ast.DictComp:
        elt = ast.Tuple(elts=[node.key, node.value])
    else:
        elt = node.elt
    state, new_elt = _peval_expression(state, elt, elt_ctx)

    try:
        state, container = _peval_comprehension(
            state, accum_cls[type(node)], new_elt, node.generators, ctx)
        evaluated = True
    except CannotEvaluateComprehension:
        evaluated = False

    if evaluated:
        return state, KnownValue(value=container)
    else:
        state, new_elt = map_reify(state, new_elt)
        state, new_generators = _peval_comprehension_generators(state, node.generators, ctx)
        if type(node) == ast.DictComp:
            key, value = new_elt.elts
            return state, replace_fields(node, key=key, value=value, generators=new_generators)
        else:
            return state, replace_fields(node, elt=new_elt, generators=new_generators)
Ejemplo n.º 8
0
    def handle_Attribute(state, node, ctx):
        state, result = _peval_expression(state, node.value, ctx)
        if is_known_value(result):
            success, attr = try_get_attribute(result.value, node.attr)
            if success:
                return state, KnownValue(value=attr)

        state, new_value = map_reify(state, result)
        return state, replace_fields(node, value=new_value)
Ejemplo n.º 9
0
 def handle_Slice(state, node, ctx):
     state, results = map_peval_expression(state, (node.lower, node.upper, node.step), ctx)
     # how do we handle None values in nodes? Technically, they are known values
     if all_known_values_or_none(results):
         lower, upper, step = [result if result is None else result.value for result in results]
         return state, KnownValue(value=slice(lower, upper, step))
     state, new_nodes = map_reify(state, results)
     new_node = replace_fields(node, lower=new_nodes[0], upper=new_nodes[1], step=new_nodes[2])
     return state, new_node
Ejemplo n.º 10
0
def remove_unreachable_statements(node, walk_field, **kwds):
    for attr in ('body', 'orelse'):
        if hasattr(node, attr):
            old_list = getattr(node, attr)
            new_list = filter_block(old_list)
            if new_list is not old_list:
                new_list = walk_field(new_list, block_context=True)
                kwds = {attr: new_list}
                node = replace_fields(node, **kwds)
    return node
Ejemplo n.º 11
0
 def names_and_incremented_nums(node, state, walk_field, **kwds):
     if isinstance(node, ast.Assign):
         value_node, state = walk_field(node.value, state)
         new_node = replace_fields(node, targets=node.targets, value=value_node)
         new_state = state.update(objs=state.objs.add(node.targets[0].id))
         return new_node, new_state
     elif isinstance(node, ast.Num):
         return ast.Num(n=node.n + 1), state.update(objs=state.objs.add(node.n))
     else:
         return node, state
Ejemplo n.º 12
0
    def handle_Set(state, node, ctx):

        state, elts = map_peval_expression(state, node.elts, ctx)
        can_eval = all_known_values(elts)

        if can_eval:
            new_set = set(elt.value for elt in elts)
            return state, KnownValue(value=new_set)
        else:
            state, new_elts = map_reify(state, elts)
            return state, replace_fields(node, elts=new_elts)
Ejemplo n.º 13
0
    def handle_Dict(state, node, ctx):

        state, pairs = map_peval_expression(state, zip(node.keys, node.values), ctx)
        can_eval = all_known_values(pairs)

        if can_eval:
            new_dict = dict((key.value, value.value) for key, value in pairs)
            return state, KnownValue(value=new_dict)
        else:
            state, keys_values = map_reify(state, zip(*pairs))
            new_node = replace_fields(node, keys=list(keys_values[0]), values=list(keys_values[1]))
            return state, new_node
Ejemplo n.º 14
0
def replace_by_path(obj, path, new_value):

    if len(path) > 1:
        if isinstance(ptr, str):
            sub_obj = getattr(obj, ptr)
        elif isinstance(ptr, int):
            sub_obj = obj[ptr]
        new_value = replace_by_path(sub_obj, path[1:], new_value)

    ptr = path[0]
    if isinstance(ptr, str):
        return replace_fields(obj, **{ptr: new_value})
    elif isinstance(ptr, int):
        return obj[:ptr] + [new_value] + obj[ptr+1:]
Ejemplo n.º 15
0
    def handle_Subscript(state, node, ctx):
        state, value_result = _peval_expression(state, node.value, ctx)
        state, slice_result = _peval_expression(state, node.slice, ctx)
        if is_known_value(value_result) and is_known_value(slice_result):
            success, elem = try_call_method(
                value_result.value, '__getitem__', args=(slice_result.value,))
            if success:
                return state, KnownValue(value=elem)

        state, new_value = map_reify(state, value_result)
        state, new_slice = map_reify(state, slice_result)
        if type(new_slice) not in (ast.Index, ast.Slice, ast.ExtSlice):
            new_slice = ast.Index(value=new_slice)
        return state, replace_fields(node, value=new_value, slice=new_slice)
Ejemplo n.º 16
0
    def handle_IfExp(state, node, ctx):
        state, test_value = _peval_expression(state, node.test, ctx)
        if is_known_value(test_value):
            success, bool_value = try_call(bool, args=(test_value.value,))
            if success:
                taken_node = node.body if bool_value else node.orelse
                return _peval_expression(state, taken_node, ctx)

        state, new_body = _peval_expression(state, node.body, ctx)
        state, new_orelse = _peval_expression(state, node.orelse, ctx)

        state, new_body_node = map_reify(state, new_body)
        state, new_orelse_node = map_reify(state, new_orelse)
        return state, replace_fields(
            node, test=test_value, body=new_body_node, orelse=new_orelse_node)
Ejemplo n.º 17
0
    def from_object(cls, func, ignore_decorators=False):
        """
        Creates a ``Function`` object from an evaluated function.
        """

        src = getsource(func)
        tree = ast.parse(src).body[0]
        if ignore_decorators:
            tree = replace_fields(tree, decorator_list=[])

        global_values = func.__globals__

        closure_vals = get_closure(func)

        scope = analyze_scope(tree)
        func_name = func.__name__

        # Builtins can be either a dict or a module
        builtins = global_values["__builtins__"]
        if not isinstance(builtins, dict):
            builtins = dict(vars(builtins))

        globals_ = {}
        for name in scope.globals:
            if name == func_name:
                globals_[name] = func
            elif name in global_values:
                globals_[name] = global_values[name]
            elif name in builtins:
                globals_[name] = builtins[name]
            elif name in closure_vals:
                continue
            else:
                raise NameError(name)

        compiler_flags = func.__code__.co_flags

        # We only need the flags corresponding to future features.
        # Also, these are the only ones supported by compile().
        compiler_flags = compiler_flags & FUTURE_FLAGS

        return cls(tree, globals_, closure_vals, compiler_flags)
Ejemplo n.º 18
0
 def handle_Name(node, ctx, **_):
     if type(node.ctx) == ast.Load and node.id == ctx.dest_name:
         return replace_fields(node, id=ctx.src_name)
     else:
         return node
Ejemplo n.º 19
0
 def handle_ExtSlice(state, node, ctx):
     state, results = map_peval_expression(state, node.dims, ctx)
     if all_known_values(results):
         return state, KnownValue(value=tuple(result.value for result in results))
     state, new_nodes = map_reify(state, results)
     return state, replace_fields(node, dims=new_nodes)
Ejemplo n.º 20
0
 def mangle_outer_functions(node, **kwds):
     if isinstance(node, ast.FunctionDef):
         return replace_fields(node, name='__' + node.name)
     else:
         return node
Ejemplo n.º 21
0
 def mangle_all_functions(node, walk_field, **kwds):
     if isinstance(node, ast.FunctionDef):
         return replace_fields(
             node, name='__' + node.name, body=walk_field(node.body, block_context=True))
     else:
         return node