Ejemplo n.º 1
0
    def _test_boolean_literal(self, expr: ast.Expression, value: bool) -> None:
        self.assertIsInstance(expr, ast.Boolean)
        boolean = cast(ast.Boolean, expr)
        self.assertEqual(boolean.value, value)

        # Monkey and Python boolean literals differ
        if value:
            self.assertEqual(expr.token_literal(), "true")
        else:
            self.assertEqual(expr.token_literal(), "false")
Ejemplo n.º 2
0
 def eval_argument(expr):
     """
     Evaluate argument of workspace method call.
     """
     if not hasattr(expr, "lineno"):
         setattr(expr, "lineno", 0)
     return eval(compile(Expression(expr), "<unknown>", 'eval'), context)
Ejemplo n.º 3
0
        def visit_FunctionDef(self, function_def):
            if function_def.decorator_list and self.IsToDo(
                    function_def.decorator_list[0]):
                call = function_def.decorator_list[0]

                function_name = function_def.name

                if call.args:
                    date = ast.literal_eval(call.args[0])
                    date = datetime.datetime(*date)
                else:
                    date = None

                if date is not None and call.keywords:
                    expr = Expression(call.keywords[0].value)
                    b = compile(expr, '', 'eval')

                    days = eval(b)
                else:
                    days = None

                self.todos.append({
                    'function_name': function_name,
                    'date': date,
                    'days': days,
                    'lineno': function_def.lineno,
                })
Ejemplo n.º 4
0
 def matchValue(self, node):
     # This method could have undesirable side-effects, but conditions in
     # requirements should not have side-effects to begin with
     try:
         code = compile(Expression(node), '<internal>', 'eval')
         value = eval(code, dict(self.namespace))
     except Exception:
         return None
     return value
Ejemplo n.º 5
0
def _compile(e, **kwargs):
    if kwargs:
        e = call(lamb(*kwargs.keys())(e), **kwargs)

    if isinstance(e, Module):
        mode = "exec"
    else:
        mode = "eval"
        e = Expression(e)
    fix_missing_locations(e)
    return compile(e, "<string>", mode)
Ejemplo n.º 6
0
def eval_code(code_str, context):
    # Avoid depending on six unless running mathcode directive
    from six import exec_
    mod = parse(code_str, '<string>', 'exec')
    last_line = mod.body.pop() if isinstance(mod.body[-1], Expr) else None
    to_exec = compile(mod, '<string>', 'exec')
    exec_(to_exec, None, context)
    if last_line is None:
        return None
    to_eval = compile(Expression(last_line.value), '<string>', 'eval')
    return eval(to_eval, None, context)
Ejemplo n.º 7
0
    def matchValue(self, node):
        """Match any expression which can be evaluated, returning its value.

        This method could have undesirable side-effects, but conditions in
        requirements should not have side-effects to begin with.
        """
        try:
            code = compile(Expression(node), '<internal>', 'eval')
            value = eval(code, dict(self.namespace))
        except Exception:
            return None
        return value
Ejemplo n.º 8
0
def solve(part, s):
    if part == 1:
        s = s.replace("*", "-")
    else:
        s = s.replace("+", "tmp").replace("*", "+").replace("tmp", "*")

    module = parse(s)
    bin_op = module.body[0].value
    if part == 1:
        replace_ops_1(bin_op)
    else:
        replace_ops_2(bin_op)

    exe = compile(Expression(body=bin_op), filename="", mode="eval")
    val = eval(exe)
    return val
Ejemplo n.º 9
0
def arts_agenda(func):
    """
    Parse python method as ARTS agenda

    This decorator can be used to define ARTS agendas using python function syntax.
    The function should have one arguments which is assumed to be a Workspace instance.
    All expressions inside the function must be calls to ARTS WSMs. The result is an
    Agenda object that can be used to copied into a named ARTS agenda

    Example:

    >>> @arts_agenda
    >>> def inversion_iterate_agenda(ws):
    >>>     ws.x2artsStandard()
    >>>     ws.atmfields_checkedCalc()
    >>>     ws.atmgeom_checkedCalc()
    >>>     ws.yCalc()
    >>>     ws.VectorAddVector(ws.yf, ws.y, ws.y_baseline)
    >>>     ws.jacobianAdjustAfterIteration()
    >>>
    >>> ws.Copy(ws.inversion_iterate_agenda, inversion_iterate_agenda)
    """
    source = getsource(func)
    ast = parse(source)

    func_ast = ast.body[0]
    if not type(func_ast) == FunctionDef:
        raise Exception(
            "ARTS agenda definition can only decorate function definiitons.")

    args = func_ast.args.args

    try:
        arg_name = func_ast.args.args[0].arg
    except:
        raise Exception("Agenda definition needs workspace arguments.")

    ws = Workspace()

    context = func.__globals__
    context[arg_name] == ws

    # Create agenda
    a_ptr = arts_api.create_agenda(func.__name__.encode())
    agenda = Agenda(a_ptr)

    for e in func_ast.body:
        if not type(e.value) == Call:
            raise Exception("Agendas may only contain call expressions.")

        # Extract workspace object.
        try:
            call = e.value
            att = call.func.value
            if not att.id == arg_name:
                raise (Exception(
                    "Agenda definition may only contain call to WSMs of the " +
                    "workspace argument " + arg_name + "."))
        except:
            raise (Exception(
                "Agenda definition may only contain call to WSMs of the " +
                "workspace argument " + arg_name + "."))

        # Extract method name.
        try:
            name = call.func.attr
            m = workspace_methods[name]
            if not type(m) == WorkspaceMethod:
                raise Exception(name + " is not a known WSM.")
        except:
            raise Exception(name + " is not a known WSM.")

        # Extract positional arguments
        args = [ws, m]
        for a in call.args:
            args.append(
                eval(compile(Expression(a), "<unknown>", 'eval'), context))

        # Extract keyword arguments
        kwargs = dict()
        for k in call.keywords:
            kwargs[k.arg] = eval(
                compile(Expression(k.value), "<unknown>", 'eval'), context)

        # Add function to agenda
        agenda.add_method(*args, **kwargs)
    return agenda
Ejemplo n.º 10
0
def arts_agenda(func):
    """
    Parse python method as ARTS agenda

    This decorator can be used to define ARTS agendas using python function syntax.
    The function should have one arguments which is assumed to be a Workspace instance.
    All expressions inside the function must be calls to ARTS WSMs. The result is an
    Agenda object that can be used to copied into a named ARTS agenda

    Example:

    >>> @arts_agenda
    >>> def inversion_iterate_agenda(ws):
    >>>     ws.x2artsStandard()
    >>>     ws.atmfields_checkedCalc()
    >>>     ws.atmgeom_checkedCalc()
    >>>     ws.yCalc()
    >>>     ws.VectorAddVector(ws.yf, ws.y, ws.y_baseline)
    >>>     ws.jacobianAdjustAfterIteration()
    >>>
    >>> ws.Copy(ws.inversion_iterate_agenda, inversion_iterate_agenda)
    """

    source = getsource(func)
    source = unindent(source)
    ast = parse(source)

    func_ast = ast.body[0]
    if not type(func_ast) == FunctionDef:
        raise Exception(
            "ARTS agenda definition can only decorate function definiitons.")

    args = func_ast.args.args

    try:
        arg_name = func_ast.args.args[0].arg
    except:
        raise Exception("Agenda definition needs workspace arguments.")

    ws = Workspace()

    context = copy(func.__globals__)
    context.update({arg_name: ws})
    # Add resolved non-local variables from closure.
    nls, _, _, _ = getclosurevars(func)
    context.update(nls)

    def eval_argument(expr):
        if not hasattr(expr, "lineno"):
            setattr(expr, "lineno", 0)
        return eval(compile(Expression(expr), "<unknown>", 'eval'), context)

    # Create agenda
    a_ptr = arts_api.create_agenda(func.__name__.encode())
    agenda = Agenda(a_ptr)

    illegal_statement_exception = Exception(
        "Agenda definitions may only contain calls to WSMs of the"
        "workspace argument " + arg_name + " or INCLUDE statements.")

    for e in func_ast.body:
        try:
            call = e.value
        except:
            raise Exception("Agendas may only contain call expressions.")

        # Include statement
        if type(call.func) == Name:
            if not call.func.id == "INCLUDE":
                raise illegal_statement_exception
            else:
                args = []
                for a in call.args:
                    args.append(eval_argument(a))
                    include = Include(*args)
                    arts_api.agenda_append(agenda.ptr, include.agenda.ptr)
        else:
            att = call.func.value
            if not att.id == arg_name:
                raise illegal_statement_exception

            # Extract method name.
            try:
                name = call.func.attr
                m = workspace_methods[name]
                if not type(m) == WorkspaceMethod:
                    raise Exception(name + " is not a known WSM.")
            except:
                raise Exception(name + " is not a known WSM.")

            # Extract positional arguments
            args = [ws, m]

            for a in call.args:

                # Handle starred expression
                if type(a) == Starred:
                    bs = eval_argument(a.value)
                    for b in bs:
                        args.append(b)
                    continue

                args.append(eval_argument(a))

            # Extract keyword arguments
            kwargs = dict()
            for k in call.keywords:
                kwargs[k.arg] = eval(
                    compile(Expression(k.value), "<unknown>", 'eval'), context)

            # Add function to agenda
            agenda.add_method(*args, **kwargs)
    return agenda
Ejemplo n.º 11
0
 def eval_argument(expr):
     if not hasattr(expr, "lineno"):
         setattr(expr, "lineno", 0)
     return eval(compile(Expression(expr), "<unknown>", 'eval'), context)
Ejemplo n.º 12
0
 def handleExpression(p):
     return Expression(p[0])
Ejemplo n.º 13
0
def Disjunction(expr1: Expression, expr2: Expression) -> Expression:
    """Return expression which is the disjunction of `expr1` and `expr2`."""
    expr = Expression(ast.BoolOp(ast.Or(), [expr1.body, expr2.body]))
    return ast.fix_missing_locations(expr)
Ejemplo n.º 14
0
def Negation(expr: Expression) -> Expression:
    """Return expression which is the negation of `expr`."""
    expr = Expression(_negate(expr.body))
    return ast.fix_missing_locations(expr)
Ejemplo n.º 15
0
def arts_agenda(func):
    """
    Parse python method as ARTS agenda

    This decorator can be used to define ARTS agendas using python function syntax.
    The function should have one arguments which is assumed to be a Workspace instance.
    All expressions inside the function must be calls to ARTS WSMs. The result is an
    Agenda object that can be used to copied into a named ARTS agenda

    Example:

    >>> @arts_agenda
    >>> def inversion_iterate_agenda(ws):
    >>>     ws.x2artsStandard()
    >>>     ws.atmfields_checkedCalc()
    >>>     ws.atmgeom_checkedCalc()
    >>>     ws.yCalc()
    >>>     ws.VectorAddVector(ws.yf, ws.y, ws.y_baseline)
    >>>     ws.jacobianAdjustAfterIteration()
    >>>
    >>> ws.Copy(ws.inversion_iterate_agenda, inversion_iterate_agenda)
    """

    source = getsource(func)
    source = unindent(source)
    ast = parse(source)

    func_ast = ast.body[0]
    if not type(func_ast) == FunctionDef:
        raise Exception("ARTS agenda definition can only decorate function definiitons.")

    args = func_ast.args.args

    try:
        arg_name = func_ast.args.args[0].arg
    except:
        raise Exception("Agenda definition needs workspace arguments.")

    ws = Workspace(0)

    context = copy(func.__globals__)
    context.update({arg_name : ws})
    # Add resolved non-local variables from closure.
    nls, _, _, _ = getclosurevars(func)
    context.update(nls)

    #
    # Helper functions
    #

    callback_body = []
    def callback_make_fun(body):
        """
        Helper function that creates a wrapper function around
        python code to be executed withing an ARTS agenda.
        """
        m = Module(body)

        def callback(ptr):
            try:
                context[arg_name].ptr = ptr
                eval(compile(m , "<unknown>", 'exec'), context)
            except Exception as e:
                logger.error(r"Exception in Python callback:\n", e)
            context[arg_name].ptr = None

        callback_body = []
        return callback

    def eval_argument(expr):
        """
        Evaluate argument of workspace method call.
        """
        if not hasattr(expr, "lineno"):
            setattr(expr, "lineno", 0)
        return eval(compile(Expression(expr), "<unknown>", 'eval'), context)

    # Create agenda
    a_ptr = arts_api.create_agenda(func.__name__.encode())
    agenda = Agenda(a_ptr)

    illegal_statement_exception = Exception(
        "Agenda definitions may only contain calls to WSMs of the"
        "workspace argument " + arg_name + " or INCLUDE statements.")

    #
    # Here the body of the function definition is traversed. Cases
    # that are treated specieal are INCLUDE statements and calls
    # of workspace methods. Remaining statements are accumulated
    # in callback_body and then added to the agenda as a single callback.
    #

    for e in func_ast.body:
        if not isinstance(e, Expr):
            callback_body += [e]
            continue
        else:
            call = e.value

        if not isinstance(call, Call):
            callback_body += [e]
            continue

        # Include statement
        if type(call.func) == Name:
            if not call.func.id == "INCLUDE":
                callback_body += [e]
            else:
                args = []
                for a in call.args:
                    args.append(eval_argument(a))
                    include = Include(*args)

                    if len(callback_body) > 0:
                        agenda.add_callback(callback_make_fun(callback_body))
                        callback_body = []

                    arts_api.agenda_append(agenda.ptr, include.agenda.ptr)
        else:
            att  = call.func.value
            if not att.id == arg_name:
                callback_body += [e]
                continue

            # Extract method name.
            name = call.func.attr

            # m is not a workspace method
            if not name in workspace_methods:
                callback_body += [e]
                continue

            # m is a workspace method.
            m  = workspace_methods[name]

            args = [ws, m]

            for a in call.args:
                # Handle starred expression
                if type(a) == Starred:
                    bs = eval_argument(a.value)
                    for b in bs:
                        args.append(b)
                    continue

                args.append(eval_argument(a))

            # Extract keyword arguments
            kwargs = dict()
            for k in call.keywords:
                kwargs[k.arg] = eval(
                    compile(Expression(k.value), "<unknown>", 'eval'),
                    context)

            # Add function to agenda
            if len(callback_body) > 0:
                agenda.add_callback(callback_make_fun(callback_body))
                callback_body = []

            agenda.add_method(*args, **kwargs)

    # Check if there's callback code left to add to the agenda.
    if len(callback_body) > 0:
        agenda.add_callback(callback_make_fun(callback_body))
        callback_body = []

    return agenda
Ejemplo n.º 16
0
    def transformAssign(self, node):

        # Only transform constant assignments
        if not is_const(node.expr):
            return self._transform_children(node)

        # '__foo' names come from each lhs name at the head of the assignment:
        #   'l = a,b = 0,1' -> 'l = a,b = __a,__b', { '__a':0, '__b':1 }
        #
        # Unpack the rhs enough to map each '__foo' name to a value.
        #   'a,l = 0,[1,2]' -> 'a,l = __a,__l', { '__a':0, '__l':[1,2] }
        #   'a,l = 2'       -> SyntaxError

        def lvalue_name(node):
            'Construct a "magic" name to represent an l-value.'
            prefix = sep = '__'
            dot = '_'
            if isinstance(node, AssName):
                return prefix + node.name
            elif isinstance(node, AssAttr):
                name = node.attrname
                expr = node.expr
                while isinstance(expr, Getattr):
                    name = sep.join([expr.attrname, name])
                    expr = expr.expr
                if isinstance(expr, Name):
                    expr_name = expr.name
                else:
                    expr_name = dot
                return prefix + sep.join([expr_name, name])

        # In these trees, strings and tuples are leaves
        leaves = (str, tuple, AssAttr, AssName)
        tree_zip = partial(tree.tree_zip, leaves=leaves)
        flatten = partial(tree.flatten, leaves=leaves)
        tree_embeds = partial(tree.tree_embeds, leaves=leaves)

        # Grab the (right-most) lhs and the rhs
        lhs, rhs = node.nodes[-1], node.expr

        # Associate constants with l-value names
        if not tree_embeds(lhs, rhs):
            raise SyntaxError('Not enough r-values to unpack: %s' % node)
        zipped = flatten(tree_zip(lhs, rhs))
        const_ast_for = map_keys(lambda v: lvalue_name(v), dict(zipped))

        # Gather name<->const mappings for names we haven't seen before
        name_for = {}
        for name in list(const_ast_for.keys()):
            if name not in list(self.const_for.keys()):
                self.const_for[name] = eval_ast(Expression(
                    const_ast_for[name]))
                assert const_ast_for[name] not in name_for
                name_for[const_ast_for[name]] = name

        class C(Transformer):
            def transform(self, node):
                if isinstance(node, Node) and node in list(name_for.keys()):
                    return Name(name_for[node])
                else:
                    return super(C, self).transform(node)

        return Assign(node.nodes, C().transform(rhs))
Ejemplo n.º 17
0
def parse_function(func, allow_callbacks):
    """
    Parse python method as ARTS agenda

    Args:
        func: The function object to parse.
        allow_callbacks: Whether to allow callbacks in the agenda.

    Return:
        An 'Agenda' object containing the code in the given function.
    """

    source = getsource(func)
    source = unindent(source)
    ast = parse(source)

    func_ast = ast.body[0]
    if not type(func_ast) == FunctionDef:
        raise Exception("ARTS agenda definition can only decorate function definitions.")

    args = func_ast.args.args

    try:
        arg_name = func_ast.args.args[0].arg
    except:
        raise Exception("Agenda definition needs workspace arguments.")

    ws = Workspace(0)

    context = copy(func.__globals__)
    context.update({arg_name : ws})
    # Add resolved non-local variables from closure.
    nls, _, _, _ = getclosurevars(func)
    context.update(nls)

    #
    # Helper functions
    #

    callback_body = []
    def callback_make_fun(body):
        """
        Helper function that creates a wrapper function around
        python code to be executed withing an ARTS agenda.
        """
        if sys.version_info >= (3, 8):
            # https://bugs.python.org/issue35894#msg334808
            m = Module(body, [])
        else:
            m = Module(body)

        def callback(ptr):
            try:
                context[arg_name].ptr = ptr
                eval(compile(m , "<unknown>", 'exec'), context)
            except Exception as e:
                logger.error(r"Exception in Python callback:\n", e)
            context[arg_name].ptr = None

        callback_body = []
        return callback

    def eval_argument(expr):
        """
        Evaluate argument of workspace method call.
        """
        if not hasattr(expr, "lineno"):
            setattr(expr, "lineno", 0)
        return eval(compile(Expression(expr), "<unknown>", 'eval'), context)

    # Create agenda
    a_ptr = arts_api.create_agenda(func.__name__.encode())
    agenda = Agenda(a_ptr)

    illegal_statement_exception = Exception(
        "Pure ARTS agenda definitions may only contain calls to WSMs of"
        " the workspace argument '{arg_name}' or INCLUDE statements."
        " If you want to allow Python callbacks you need to use"
        " the '@arts_agenda' decorator with the 'allow_callbacks'"
        " keyword argument set to 'True'."
    )

    #
    # Here the body of the function definition is traversed. Cases
    # that are treated specieal are INCLUDE statements and calls
    # of workspace methods. Remaining statements are accumulated
    # in callback_body and then added to the agenda as a single callback.
    #

    for e in func_ast.body:
        if not isinstance(e, Expr):
            if allow_callbacks:
                callback_body += [e]
                continue
            else:
                raise illegal_statement_exception
        else:
            call = e.value

        if not isinstance(call, Call):
            if isinstance(call, Str):
                continue
            elif allow_callbacks:
                callback_body += [e]
                continue
            else:
                raise illegal_statement_exception

        # Include statement
        if type(call.func) == Name:
            if call.func.id != "INCLUDE":
                if allow_callbacks:
                    callback_body += [e]
                else:
                    raise illegal_statement_exception
            else:
                args = []
                for a in call.args:
                    args.append(eval_argument(a))
                    include = Include(*args)

                    if len(callback_body) > 0:
                        agenda.add_callback(callback_make_fun(callback_body))
                        callback_body = []

                    arts_api.agenda_append(agenda.ptr, include.agenda.ptr)
        else:
            att = call.func.value
            if not att.id == arg_name:
                callback_body += [e]
                continue

            # Extract method name.
            name = call.func.attr

            # m is not a workspace method
            if name not in workspace_methods:
                if allow_callbacks:
                    callback_body += [e]
                    continue
                else:
                    raise ValueError(
                        f"{name} is not a know ARTS WSM."
                    )

            # m is a workspace method.
            m = workspace_methods[name]

            args = [ws, m]
            kwargs = dict()

            for a in call.args:
                # Handle starred expression
                if type(a) == Starred:
                    bs = eval_argument(a.value)
                    for b in bs:
                        args.append(b)
                else:
                    args.append(eval_argument(a))

            # Extract keyword arguments
            for k in call.keywords:
                if k.arg is None:
                    d = eval(compile(Expression(k.value), "<unknown>", 'eval'),
                             context)
                    kwargs.update(d)
                else:
                    kwargs[k.arg] = eval(compile(Expression(k.value),
                                                 "<unknown>", 'eval'),
                                         context)

            # Add function to agenda
            if len(callback_body) > 0:
                agenda.add_callback(callback_make_fun(callback_body))
                callback_body = []

            agenda.add_method(*args, **kwargs)

    # Check if there's callback code left to add to the agenda.
    if len(callback_body) > 0:
        agenda.add_callback(callback_make_fun(callback_body))
        callback_body = []

    return agenda