Beispiel #1
0
    def check_and_convert(self, value):
        """
        Checks type of :code:`value` against the group specification of this
        ARTS property contained in :code:`self.group`.

        The group specification can be a single string in which case this
        function will try to convert the provided value to the given group
        using the :code:`convert` class method of
        :class:`pyarts.workspace.WorkspaceVariable`.

        It is also possible to specify a list of groups for the expected
        value. In this case this function simply checks whether the group
        inferred by :code:`WorkspaceVariable.get_group_id`
        group of the :code:``

        """
        if type(self.group) == str:
            converted = WorkspaceVariable.convert(self.group, value)

            if converted is None:
                raise Exception(
                    "Provided value of type {0} cannot be converted"
                    " to ARTS group {1}".format(type(value), self.group))
            value = converted
        elif type(self.group) == list:
            g_i = WorkspaceVariable.get_group_id(value)
            g = group_names[g_i]
            if not g in self.group:
                raise Exception("Provided value of type {0} is not of any of "
                                " the expected ARTS groups {1}."\
                                .format(type(value), self.group))

        return value
Beispiel #2
0
    def set_variable(self, wsv, value):
        """
        This will set a WSV to the given value.

        Natively supported types, i.e. any of int, str, [str], [int], numpy.ndarrays,
        and scipy.sparse, will be copied directly into the newly created WSV.

        In addition to that all arts types the can be stored to XML can
        be set to a WSV, but in this case the communication will happen through
        the file system (cf. :code:`WorkspaceVariable.from_arts`).

        Args:
            wsv: The :class:`WorkspaceVariable` to set.
            value: The Python object representing the value to set :code:`wsv` to.
        """
        if is_empty(value):
            err = arts_api.set_variable_value(self.ptr, wsv.ws_id,
                                              wsv.group_id,
                                              VariableValueStruct.empty())
            if not err is None:
                msg = ("The following error occurred when trying to set the"
                       " WSV {}: {}".format(wsv.name, err.decode()))
                raise Exception(msg)
            return None

        group = group_names[WorkspaceVariable.get_group_id(value)]
        if group != wsv.group:
            try:
                converted = WorkspaceVariable.convert(wsv.group, value)
            except:
                converted = None
            if converted is None:
                raise Exception("Cannot set workspace variable of type {} to "
                                " value  '{}'.".format(wsv.group, value))
            value = converted

        s = VariableValueStruct(value)
        if s.ptr:
            err = arts_api.set_variable_value(self.ptr, wsv.ws_id,
                                              wsv.group_id, s)
            if not err is None:
                msg = ("The following error occurred when trying to set the"
                       " WSV {}: {}".format(wsv.name, err.decode()))
                raise Exception(msg)
        # If the type is not supported by the C API try to write the type to XML
        # and read into ARTS workspace.
        else:
            try:
                wsv.from_arts(value)
            except:
                raise Exception("Could not set variable since + " +
                                str(type(value)) +
                                " is neither supported by " +
                                "the C API nor arts XML IO.")
Beispiel #3
0
    def add_method(*args, **kwargs):
        """
        Add a workspace method call to the agenda.

        Parameters:

            ws(arts.workspace.Workspace): A (dummy) workspace object.

            m(arts.workspace.WorkspaceMethod): The method to add to the
            agenda

            *args:  Positional arguments of the WSM call to add to the agenda.

            **kwargs: Key-word arguments of the WSM call to add to the agenda.
        """
        from pyarts.workspace.variables import group_names

        if len(args) < 3:
            raise Exception("Need at least self, a workspace and the method to"
                            " add as arguments.")
        self = args[0]
        ws = args[1]
        m = args[2]
        m_id, args_out, args_in, temps = m._parse_output_input_lists(
            ws, args[3:], kwargs)
        arg_out_ptr = c.cast((c.c_long * len(args_out))(*args_out),
                             c.POINTER(c.c_long))
        arg_in_ptr = c.cast((c.c_long * len(args_in))(*args_in),
                            c.POINTER(c.c_long))
        if not m.name[-3:] == "Set" or not m.name[:-3] in group_names:

            for t in temps:
                arts_api.agenda_insert_set(ws.ptr, self.ptr, t.ws_id,
                                           t.group_id)

            arts_api.agenda_add_method(c.c_void_p(self.ptr),
                                       m_id, len(args_out), arg_out_ptr,
                                       len(args_in), arg_in_ptr)
        else:
            from pyarts.workspace.variables import WorkspaceVariable

            name_out = WorkspaceVariable.get_variable_name(args_out[0])
            name_in = WorkspaceVariable.get_variable_name(args_in[0])
            wsv_out = getattr(ws, name_out)
            wsv_in = getattr(ws, name_in)

            ws.Copy(wsv_out, wsv_in)

            group_id = arts_api.get_variable(args_out[0]).group
            arts_api.agenda_insert_set(ws.ptr, self.ptr, args_out[0], group_id)
Beispiel #4
0
    def __getattr__(self, name):
        """ Lookup the given variable in the local variables and the ARTS workspace.

        Args:
            name(str): Name of the attribute (variable)

        Raises:
            ValueError: If the variable is not found.
        """

        group_id = None
        if name in self._vars:
            var = self._vars[name]
            var.update()
            return var
        else:
            i = arts_api.lookup_workspace_variable(name.encode())
            if i < 0:
                raise AttributeError("No workspace variable " + str(name) +
                                     " found.")
            vs = arts_api.get_variable(i)
            group_id = vs.group
            description = vs.description.decode("utf8")

        # Get its symbolic representation
        wsv = WorkspaceVariable(i, name, group_names[group_id], description,
                                self)
        return wsv
Beispiel #5
0
    def add_variable(self, var, group=None):
        """
        This will try to copy a given python variable to the ARTS workspace and
        return a WorkspaceVariable object representing this newly created
        variable.

        Types are natively supported by the C API are int, str, [str], [int], and
        numpy.ndarrays. These will be copied directly into the newly created WSV.

        In addition to that all arts types the can be stored to XML can
        be set to a WSV, but in this case the communication will happen through
        the file system (cf. WorkspaceVariable.from_arts).

        The user should not have to call this method explicitly, but instead it
        is used by the WorkspaceMethod call function to transfer python
        variable arguments to the ARTS workspace.

        Args:
            var: Python variable of type int, str, [str], [int] or np.ndarray
            which should be copied to the workspace.
        """
        if type(var) == WorkspaceVariable:
            return var

        # Create WSV in ARTS Workspace
        if group is None:
            group = WorkspaceVariable.get_group_id(var)

        group = group_names[group]
        wsv = self.create_variable(group, None)

        # Set WSV value using the ARTS C API
        self.set_variable(wsv, var)
        self._vars[wsv.name] = wsv
        return wsv
Beispiel #6
0
    def get_wsm_kwargs(self, wsm):
        """
        Generate a list of arguments to the given ARTS workspace method
        :code:`wsm` for which the sensor related input parameters are
        replace by the ones of this sensor. This is done by checking
        whether the input argument name is in the sensors :code:`_wsv`
        dictionary and if so replacing the argument.

        Parameters:

           wsm(pyarts.workspace.methods.WorkspaceMethod): The ARTS
               workspace method object for which to generate the input
               argument list.

        Returns:

            The list of input arguments with sensor specific input arguments
            replaced by the corresponding WSVs of the sensor.

        """
        kwargs = {}
        for i in wsm.ins:
            name = WorkspaceVariable.get_variable_name(i)
            if name in self._wsvs:
                kwargs[name] = self._wsvs[name]
            else:
                kwargs[name] = wsv[name]
        return kwargs
Beispiel #7
0
    def call_wsm(self, ws, wsm):
        """
        Call workspace method on the given workspace.

        This method replaces inputs of the workspace variable with the private
        WSMs of the object. After execution of the method the results are
        copied to the private WSMs of the object.

        Parameters:

            ws(pyarts.workspace.Workspace): The workspace on which to
            execute the method.

            wsm(pyarts.workspace.WorkspaceMethod): The workspace method
            to execute.

        """
        args = self.get_wsm_kwargs(wsm)
        wsm.call(ws, **args)

        # Copy output
        for i in wsm.outs:
            name = WorkspaceVariable.get_variable_name(i)
            if name in self._wsvs and not i in wsm.ins:
                ws.Copy(self._wsvs[name], wsv[name])
Beispiel #8
0
    def get_default_input_dict(m_id, g_in):
        """Get dict mapping names of generic input arguments to default values.

        Is None if no default value for a given generic input is given.

        Args:
            m_id(int):   Index of the method.
            g_in([str]): Names of the generic input arguments.
        Return:
            dict: The mapping.
        """
        res = dict()
        for i, t in enumerate(g_in):
            k = arts_api.get_method_g_in(m_id, i).decode("utf8")
            d = arts_api.get_method_g_in_default(m_id,
                                                 i).decode("utf8").strip()
            if d == nodef:
                d = None
            elif d == "Inf":
                res[k] = np.float64("inf")
            else:
                try:
                    d = WorkspaceVariable.convert(group_names[t],
                                                  ast.literal_eval(d))
                    res[k] = d
                except:
                    res[k] = d
        return res
Beispiel #9
0
    def convert_argument(self, name, value):
        """
        Tries to infer type of argument based on types of input and
        generic input.
        """
        if isinstance(value, WSV):
            return value

        if name in self.wsm_ins:
            v = workspace_variables[name]
            value_converted = WorkspaceVariable.convert(v.group, value)
            if not value_converted is None:
                value = value_converted

        if name in self.wsm_gins:
            if len(self.wsm.g_in_types) == 1:
                g = group_names[self.wsm.g_in_types[0][name]]

                value_converted = WorkspaceVariable.convert(g, value)
                if not value_converted is None:
                    value = value_converted
        return value
Beispiel #10
0
    def __init__(self, name, args, kwargs):

        if not name in workspace_methods:
            raise Exception("{} is not a known workspace method.".format(name))

        self.wsm = workspace_methods[name]

        self.wsm_outs = [
            WorkspaceVariable.get_variable_name(m) for m in self.wsm.outs
        ]
        self.wsm_gouts = self.wsm.g_out
        self.wsm_ins = [WorkspaceVariable.get_variable_name(m) for m in self.wsm.ins \
                        if not m in self.wsm.outs]
        self.wsm_gins = self.wsm.g_in
        self.arg_names = self.wsm_outs + self.wsm_gouts + self.wsm_ins + self.wsm_gins

        self.name = name
        self.args = args
        self.kwargs = kwargs

        if not kwargs is None:
            if "in" in kwargs:
                self.kwargs_to_args()
Beispiel #11
0
    def create(self, ws, name=None):
        """
        Call to <Group>Create WSMs are handled differently. This method simply
        determines the group type from the function name and then add a variable of
        this type to the workspace ws. A handle of this variable is then added to
        as attribute to the arts.workspace.variables module.

        Args:
            ws(Workspace): Workspace object to add the variable to
            name(str):     Name of the variable to add to the workspace
        """
        group = WorkspaceMethod.create_regexp.match(self.name).group(1)
        group_id = group_ids[group]

        if not name:
            name = "__anonymous_" + str(len(ws._vars))
            ws_id = arts_api.add_variable(ws.ptr, group_id, name.encode())
        else:
            # Is there a WSM with that name?
            if name in workspace_methods.keys():
                raise Exception("A WSM with the name " + name +
                                " already exists.")

            # Is there a WSV with that name?
            ws_id = arts_api.lookup_workspace_variable(name.encode())
            # Is yes, check that it is of the same group?
            if not ws_id == -1:
                v = arts_api.get_variable(ws_id)
                if not v.group == group_id:
                    raise Exception("A WSV with the name " + name +
                                    " but of goup " + group_names[v.group] +
                                    " already exists.")
            # Otherwise we add the variable.
            else:
                ws_id = arts_api.add_variable(ws.ptr, group_id, name.encode())

        wsv = WorkspaceVariable(ws_id, name, group, "User defined variable.",
                                ws)
        setattr(variables, name, wsv)
        ws._vars[name] = wsv
        return wsv
Beispiel #12
0
    def create_variable(self, group, name):
        """
        Create a workspace variable.

        Args:

            group: The group name of the variable to create.
            name: The name of the variable to create. If None, the
            ARTS API will assign a unique name.

        """
        if not name is None:
            name = name.encode()

        group_id = group_ids[group]
        ws_id = arts_api.add_variable(self.ptr, group_id, name)
        v = arts_api.get_variable(ws_id)
        wsv = WorkspaceVariable(ws_id, v.name.decode(), group_names[group_id],
                                "User defined variable.", self)
        self._vars[wsv.name] = wsv
        return wsv
Beispiel #13
0
    def _parse_output_input_lists(self, ws, args, kwargs):

        ins = [i for i in self.ins if not i in self.outs]
        outs = self.outs[:]
        temps = []

        # Can call function using only positional or named arguments
        if len(args) and len(kwargs.keys()):
            raise SyntaxError("ARTS WSMs can only be called using either " +
                              " positional or named arguments.")

        # Use dict to store named arguments. Generic in- and outputs
        # will be added to this.
        named_args = dict(**kwargs)

        #
        # Parse positional arguments
        #

        for j in range(len(args)):
            # Parse output arguments
            if j < self.n_out:
                if not type(args[j]) == WorkspaceVariable:
                    out_name = WorkspaceVariable.get_variable_name(outs[j])
                    raise TypeError(
                        "Positional argument for output {} is not of type "
                        "WorkspaceVariable.".format(out_name))

                outs[j] = args[j].ws_id
            # Parse generic output arguments and to list of named
            # args.
            elif j < self.n_out + self.n_g_out:
                k = j - self.n_out
                name = self.g_out[k]
                named_args[name] = args[j]

            # Parse input arguments
            elif j < self.n_out + self.n_g_out + len(ins):
                k = j - self.n_g_out - self.n_out
                if type(args[j]) == WorkspaceVariable:
                    ins[k] = args[j].ws_id
                else:
                    temps.append(ws.add_variable(args[j]))
                    ins[k] = temps[-1].ws_id
            # Parse generic input arguments
            elif j < self.n_out + self.n_g_out + len(ins) + self.n_g_in:
                k = j - self.n_g_out - self.n_out - len(ins)
                name = self.g_in[k]
                named_args[name] = args[j]
            else:
                raise Exception(
                    " {} positional arguments given, but this WSM takes at "
                    "most {}.".format(len(args), j))

        # Parse named arguments
        ins_names = [WorkspaceVariable.get_variable_name(i) for i in ins]
        outs_names = [WorkspaceVariable.get_variable_name(i) for i in outs]

        # Raise exception if named argument does not match method arguments.
        for k in kwargs:
            if not (k in ins_names or k in outs_names or k in self.g_in
                    or k in self.g_out):
                raise Exception(
                    "The provided named argument '{0}' does not match "
                    " any of the arguments of WSM {1}.".format(k, self.name))

            if k in ins_names:
                i = ins_names.index(k)
                arg = kwargs[k]
                if type(arg) == WorkspaceVariable:
                    ins[i] = arg.ws_id
                else:
                    temps.append(ws.add_variable(arg))
                    ins[i] = temps[-1].ws_id

            if k in outs_names:
                i = outs_names.index(k)
                arg = kwargs[k]
                if type(arg) == WorkspaceVariable:
                    outs[i] = arg.ws_id
                else:
                    raise Exception(
                        ("Output argument {} must be a workspace " +
                         "variable.").format(k))

        # Check output argument names
        g_output_args = dict()
        for k in self.g_out:
            if not k in named_args:
                raise Exception("WSM " + self.name + " needs generic output " +
                                k)
            else:
                g_output_args[k] = named_args[k]

        # Check input argument names
        g_input_args = dict()
        for k in self.g_in:
            if not k in named_args:
                if k in self.g_in_default:
                    g_input_args[k] = self.g_in_default[k]
                else:
                    raise Exception("WSM " + self.name +
                                    " needs generic input " + k)
            else:
                g_input_args[k] = named_args[k]

        m_id = self.m_ids[0]
        sg_index = 0

        if (len(self.m_ids) > 1):

            #
            # First, try resolving solely based on WSV input since we can
            # easily identify their type.
            #

            candidates = []
            for i, m_id in enumerate(self.m_ids):
                g_in_types = self.g_in_types[i]
                g_out_types = self.g_out_types[i]

                convertable = True

                for k in g_in_types:
                    in_type = group_names[g_in_types[k]]
                    in_arg = g_input_args[k]
                    if isinstance(in_arg, WorkspaceVariable):
                        if not in_arg.group == in_type:
                            convertable = False
                            break

                for k in g_out_types:
                    out_type = group_names[g_out_types[k]]
                    out_arg = g_output_args[k]
                    if isinstance(out_arg, WorkspaceVariable):
                        if not out_arg.group == out_type:
                            convertable = False
                            break

                if convertable:
                    candidates.append((m_id, i))

            if len(candidates) == 1:
                m_id, sg_index = candidates[0]
            else:
                # Resolve overload (if necessary).
                g_out_types = dict([
                    (k, WorkspaceVariable.get_group_id(g_output_args[k]))
                    for k in self.g_out
                ])
                g_in_types = dict([
                    (k, WorkspaceVariable.get_group_id(g_input_args[k]))
                    for k in self.g_in
                ])

                out_indices = [
                    i for i, ts in enumerate(self.g_out_types)
                    if ts == g_out_types
                ]
                in_indices = [
                    i for i, ts in enumerate(self.g_in_types)
                    if ts == g_in_types
                ]
                sg_indices = set(out_indices) & set(in_indices)

                if len(sg_indices) > 1:
                    raise Exception(
                        "Could not uniquely resolve super-generic overload.")

                if len(sg_indices) == 0:
                    raise Exception(
                        "Could not find super-generic overload matching" +
                        " the given groups.")

                sg_index = sg_indices.pop()
                m_id = self.m_ids[sg_index]

        # Combine input and output arguments into lists.
        arts_args_out = []
        for out in outs:
            arts_args_out.append(out)

        for name in self.g_out:
            arg = g_output_args[name]
            if not type(arg) == WorkspaceVariable:
                raise ValueError("Generic Output " + name +
                                 " must be an ARTS WSV.")
            group_id = arg.group_id
            expected = self.g_out_types[sg_index][name]
            if not group_id == expected:
                raise Exception("Generic output " + name +
                                " expected to be of type " +
                                group_names[expected])
            arts_args_out.append(arg.ws_id)

        arts_args_in = []
        for i in ins:
            if not i in outs:
                arts_args_in.append(i)

        for name in self.g_in:
            arg = g_input_args[name]
            if type(arg) == WorkspaceVariable:
                arts_args_in.append(arg.ws_id)
            else:
                gid = self.g_in_types[sg_index][name]
                arg_converted = WorkspaceVariable.convert(
                    group_names[gid], arg)
                if arg_converted is None:
                    raise Exception(
                        "Could not convert input {} to expected group {}".
                        format(arg, group_names[gid]))
                temps.append(ws.add_variable(arg_converted, gid))
                arts_args_in.append(temps[-1].ws_id)
        return (m_id, arts_args_out, arts_args_in, temps)