Example #1
0
    def is_valid_value(self, name, value):
        """Determine whether a value is valid for the named variable.

        The `value` argument must be a list of strings formatted as they would
        appear in the namelist (even for scalar variables, in which case the
        length of the list is always 1).
        """
        name = name.lower()
        # Separate into a type, optional length, and optional size.
        type_, max_len, size = self.split_type_string(name)
        invalid = []

        # Check value against type.
        for scalar in value:
            if not is_valid_fortran_namelist_literal(type_, scalar):
                invalid.append(scalar)
        if len(invalid) > 0:
            logger.warn("Invalid values %s" % invalid)
            return False

        # Now that we know that the strings as input are valid Fortran, do some
        # canonicalization for further checks.
        canonical_value = self._canonicalize_value(type_, value)

        # Check maximum length (if applicable).
        if max_len is not None:
            for scalar in canonical_value:
                if len(scalar) > max_len:
                    return False

        # Check valid value constraints (if applicable).
        valid_values = self._valid_values[name]
        if valid_values is not None:
            expect(
                type_ in ('integer', 'character'),
                "Found valid_values attribute for variable %s with "
                "type %s, but valid_values only allowed for character "
                "and integer variables." % (name, type_))
            if type_ == 'integer':
                compare_list = [int(vv) for vv in valid_values]
            else:
                compare_list = valid_values
            for scalar in canonical_value:
                if scalar not in compare_list:
                    invalid.append(scalar)
            if len(invalid) > 0:
                logger.warn("Invalid values %s" % invalid)
                return False

        # Check size of input array.
        if len(expand_literal_list(value)) > size:
            expect(
                False,
                "Value index exceeds variable size for variable %s, allowed array length is %s value array size is %s"
                % (name, size, len(expand_literal_list(value))))
        return True
Example #2
0
    def add_default(self, name, value=None):
        """Add a value for the specified variable to the namelist.

        If the specified variable is already defined in the object, the existing
        value is preserved. Otherwise, the `value` argument, if provided, will
        be used to set the value. If no such value is found, the defaults file
        will be consulted. If null values are present in any of the above, the
        result will be a merged array of values.

        If no value for the variable is found via any of the above, this method
        will raise an exception.
        """
        group = self._definition.get_node_element_info(name, "group")

        # Use this to see if we need to raise an error when nothing is found.
        have_value = False

        # Check for existing value.
        current_literals = self._namelist.get_variable_value(group, name)
        if current_literals != [""]:
            have_value = True

        # Check for input argument.
        if value is not None:
            have_value = True
            literals = self._to_namelist_literals(
                name, value
            )  #FIXME - this is where an array is compressed into a 3*value
            current_literals = merge_literal_lists(literals, current_literals)

        # Check for default value.
        default = self.get_default(name, allow_none=True)
        if default is not None:
            have_value = True
            default_literals = self._to_namelist_literals(name, default)
            current_literals = merge_literal_lists(default_literals,
                                                   current_literals)
        expect(have_value, "No default value found for %s." % name)

        # Go through file names and prepend input data root directory for
        # absolute pathnames.
        var_input_pathname = self._definition.get_input_pathname(name)
        if var_input_pathname == 'abs':
            current_literals = expand_literal_list(current_literals)
            for i, literal in enumerate(current_literals):
                if literal == '':
                    continue
                file_path = character_literal_to_string(literal)
                if file_path == 'UNSET' or file_path == 'idmap':
                    continue
                if file_path == 'null':
                    continue
                file_path = self.set_abs_file_path(file_path)
                expect(os.path.exists(file_path),
                       "File not found: %s = %s" % (name, literal))
                current_literals[i] = string_to_character_literal(file_path)
            current_literals = compress_literal_list(current_literals)

        # Set the new value.
        self._namelist.set_variable_value(group, name, current_literals)
Example #3
0
    def add_default(self, name, value=None, ignore_abs_path=None):
        """Add a value for the specified variable to the namelist.

        If the specified variable is already defined in the object, the existing
        value is preserved. Otherwise, the `value` argument, if provided, will
        be used to set the value. If no such value is found, the defaults file
        will be consulted. If null values are present in any of the above, the
        result will be a merged array of values.

        If no value for the variable is found via any of the above, this method
        will raise an exception.
        """
        # pylint: disable=protected-access
        group = self._definition.get_group(name)

        # Use this to see if we need to raise an error when nothing is found.
        have_value = False
        # Check for existing value.
        current_literals = self._namelist.get_variable_value(group, name)

        # Check for input argument.
        if value is not None:
            have_value = True
            # if compression were to occur, this is where it does
            literals = self._to_namelist_literals(name, value)
            current_literals = merge_literal_lists(literals, current_literals)

        # Check for default value.
        default = self.get_default(name, allow_none=True)
        if default is not None:
            have_value = True
            default_literals = self._to_namelist_literals(name, default)
            current_literals = merge_literal_lists(default_literals, current_literals)
        expect(have_value, "No default value found for {}.".format(name))

        # Go through file names and prepend input data root directory for
        # absolute pathnames.
        var_type, _, var_size = self._definition.split_type_string(name)
        if var_type == "character" and ignore_abs_path is None:
            var_input_pathname = self._definition.get_input_pathname(name)
            if var_input_pathname == 'abs':
                current_literals = expand_literal_list(current_literals)
                for i, literal in enumerate(current_literals):
                    if literal == '':
                        continue
                    file_path = character_literal_to_string(literal)
                    # NOTE - these are hard-coded here and a better way is to make these extensible
                    if file_path == 'UNSET' or file_path == 'unset' or file_path == 'idmap':
                        continue
                    if file_path == 'null':
                        continue
                    file_path = self.set_abs_file_path(file_path)
                    if not os.path.exists(file_path):
                        logger.warning("File not found: {} = {}, will attempt to download in check_input_data phase".format(name, literal))
                    current_literals[i] = string_to_character_literal(file_path)
                current_literals = compress_literal_list(current_literals)

        # Set the new value.
        self._namelist.set_variable_value(group, name, current_literals, var_size)
Example #4
0
    def add_default(self, name, value=None):
        """Add a value for the specified variable to the namelist.

        If the specified variable is already defined in the object, the existing
        value is preserved. Otherwise, the `value` argument, if provided, will
        be used to set the value. If no such value is found, the defaults file
        will be consulted. If null values are present in any of the above, the
        result will be a merged array of values.

        If no value for the variable is found via any of the above, this method
        will raise an exception.
        """
        group = self._definition.get_node_element_info(name, "group")

        # Use this to see if we need to raise an error when nothing is found.
        have_value = False

        # Check for existing value.
        current_literals = self._namelist.get_variable_value(group, name)
        if current_literals != [""]:
            have_value = True

        # Check for input argument.
        if value is not None:
            have_value = True
            literals = self._to_namelist_literals(name, value) #FIXME - this is where an array is compressed into a 3*value
            current_literals = merge_literal_lists(literals, current_literals)

        # Check for default value.
        default = self.get_default(name, allow_none=True)
        if default is not None:
            have_value = True
            default_literals = self._to_namelist_literals(name, default)
            current_literals = merge_literal_lists(default_literals,
                                                   current_literals)
        expect(have_value, "No default value found for %s." % name)

        # Go through file names and prepend input data root directory for
        # absolute pathnames.
        var_input_pathname = self._definition.get_input_pathname(name)
        if var_input_pathname == 'abs':
            current_literals = expand_literal_list(current_literals)
            for i, literal in enumerate(current_literals):
                if literal == '':
                    continue
                file_path = character_literal_to_string(literal)
                if file_path == 'UNSET' or file_path == 'idmap':
                    continue
                if file_path == 'null':
                    continue
                file_path = self.set_abs_file_path(file_path)
                expect(os.path.exists(file_path),
                       "File not found: %s = %s" % (name, literal))
                current_literals[i] = string_to_character_literal(file_path)
            current_literals = compress_literal_list(current_literals)

        # Set the new value.
        self._namelist.set_variable_value(group, name, current_literals)
    def is_valid_value(self, name, value):
        """Determine whether a value is valid for the named variable.

        The `value` argument must be a list of strings formatted as they would
        appear in the namelist (even for scalar variables, in which case the
        length of the list is always 1).
        """
        name = name.lower()
        # Separate into a type, optional length, and optional size.
        type_, max_len, size = self.split_type_string(name, self.get_type_info(name))
        invalid = []
        # Check value against type.
        for scalar in value:
            if not is_valid_fortran_namelist_literal(type_, scalar):
                invalid.append(scalar)
        if len(invalid) > 0:
            logger.warn("Invalid values %s"%invalid)
            return False


        # Now that we know that the strings as input are valid Fortran, do some
        # canonicalization for further checks.
        canonical_value = self._canonicalize_value(type_, value)

        # Check maximum length (if applicable).
        if max_len is not None:
            for scalar in canonical_value:
                if len(scalar) > max_len:
                    return False

        # Check valid value constraints (if applicable).
        valid_values = self.get_valid_values(name)
        if valid_values is not None:
            expect(type_ in ('integer', 'character'),
                   "Found valid_values attribute for variable %s with "
                   "type %s, but valid_values only allowed for character "
                   "and integer variables." % (name, type_))
            if type_ == 'integer':
                compare_list = [int(vv)
                                for vv in valid_values]
            else:
                compare_list = valid_values
            for scalar in canonical_value:
                if scalar not in compare_list:
                    invalid.append(scalar)
            if len(invalid) > 0:
                logger.warn("Invalid values %s"%invalid)
                return False

        # Check size of input array.
        if len(expand_literal_list(value)) > size:
            return False
        return True
Example #6
0
 def _to_python_value(self, name, literals):
     """Transform a literal list as needed for `get_value`."""
     var_type, _, var_size, =  self._definition.split_type_string(name, self._definition.get_type_info(name))
     if len(literals) > 0:
         value = expand_literal_list(literals)
     else:
         value = ''
         return value
     for i, scalar in enumerate(value):
         if scalar == '':
             value[i] = None
         elif var_type == 'character':
             value[i] = character_literal_to_string(scalar)
     if var_size == 1:
         return value[0]
     else:
         return value
Example #7
0
 def _to_python_value(self, name, literals):
     """Transform a literal list as needed for `get_value`."""
     var_type, _, var_size, = self._definition.split_type_string(name)
     if len(literals) > 0:
         value = expand_literal_list(literals)
     else:
         value = ''
         return value
     for i, scalar in enumerate(value):
         if scalar == '':
             value[i] = None
         elif var_type == 'character':
             value[i] = character_literal_to_string(scalar)
     if var_size == 1:
         return value[0]
     else:
         return value
Example #8
0
    def get_default(self, name, config=None, allow_none=False):
        """Get the value of a variable from the namelist definition file.

        The `config` argument is passed through to the underlying
        `NamelistDefaults.get_value` call as the `attribute` argument.

        The return value of this function is a list of values that were found in
        the defaults file. If there is no matching default, this function
        returns `None` if `allow_none=True` is passed, otherwise an error is
        raised.

        Note that we perform some translation of the values, since there are a
        few differences between Fortran namelist literals and values in the
        defaults file:
        1) In the defaults file, whitespace is ignored except within strings, so
           the output of this function strips out most whitespace. (This implies
           that commas are the only way to separate array elements in the
           defaults file.)
        2) In the defaults file, quotes around character literals (strings) are
           optional, as long as the literal does not contain whitespace, commas,
           or (single or double) quotes. If a setting for a character variable
           does not seem to have quotes (and is not a null value), this function
           will add them.
        3) Default values may refer to variables in a case's `env_*.xml` files.
           This function replaces references of the form `$VAR` or `${VAR}` with
           the value of the variable `VAR` in an env file, if that variable
           exists. This behavior is suppressed within single-quoted strings
           (similar to parameter expansion in shell scripts).
        """
        default = self._definition.get_value_match(name, attributes=config, exact_match=True)
        if default is None:
            expect(allow_none, "No default value found for %s." % name)
            return None
        default = expand_literal_list(default)

        var_type,_,_ = self._definition.split_type_string(name, self._definition.get_type_info(name))

        for i, scalar in enumerate(default):
            # Skip single-quoted strings.
            if var_type == 'character' and scalar != '' and \
               scalar[0] == scalar[-1] == "'":
                continue
            match = _var_ref_re.search(scalar)
            while match:
                env_val = self._case.get_value(match.group('name'))
                expect(env_val is not None,
                       "Namelist default for variable %s refers to unknown XML "
                       "variable %s." % (name, match.group('name')))
                scalar = scalar.replace(match.group(0), str(env_val), 1)
                match = _var_ref_re.search(scalar)
            default[i] = scalar

        # Deal with missing quotes.

        if var_type == 'character':
            for i, scalar in enumerate(default):
                # Preserve null values.
                if scalar != '':
                    default[i] = self.quote_string(scalar)

        default = self._to_python_value(name, default)
        return default
Example #9
0
    def add_default(self, name, value=None, ignore_abs_path=None):
        """Add a value for the specified variable to the namelist.

        If the specified variable is already defined in the object, the existing
        value is preserved. Otherwise, the `value` argument, if provided, will
        be used to set the value. If no such value is found, the defaults file
        will be consulted. If null values are present in any of the above, the
        result will be a merged array of values.

        If no value for the variable is found via any of the above, this method
        will raise an exception.
        """
        # pylint: disable=protected-access
        group = self._definition.get_group(name)

        # Use this to see if we need to raise an error when nothing is found.
        have_value = False

        # Check for existing value.
        current_literals = self._namelist.get_variable_value(group, name)
        if current_literals != [""]:
            have_value = True
            # Do not proceed further since this has been obtained the -infile contents
            return

        # Check for input argument.
        if value is not None:
            have_value = True
            # if compression were to occur, this is where it does
            literals = self._to_namelist_literals(name, value)
            current_literals = merge_literal_lists(literals, current_literals)

        # Check for default value.
        default = self.get_default(name, allow_none=True)
        if default is not None:
            have_value = True
            default_literals = self._to_namelist_literals(name, default)
            current_literals = merge_literal_lists(default_literals,
                                                   current_literals)
        expect(have_value, "No default value found for %s." % name)

        # Go through file names and prepend input data root directory for
        # absolute pathnames.
        if ignore_abs_path is None:
            var_input_pathname = self._definition.get_input_pathname(name)
            if var_input_pathname == 'abs':
                current_literals = expand_literal_list(current_literals)
                for i, literal in enumerate(current_literals):
                    if literal == '':
                        continue
                    file_path = character_literal_to_string(literal)
                    # NOTE - these are hard-coded here and a better way is to make these extensible
                    if file_path == 'UNSET' or file_path == 'idmap':
                        continue
                    if file_path == 'null':
                        continue
                    file_path = self.set_abs_file_path(file_path)
                    if not os.path.exists(file_path):
                        logger.warn(
                            "File not found: %s = %s, will attempt to download in check_input_data phase"
                            % (name, literal))
                    current_literals[i] = string_to_character_literal(
                        file_path)
                current_literals = compress_literal_list(current_literals)

        # Set the new value.
        self._namelist.set_variable_value(group, name, current_literals)
Example #10
0
    def get_default(self, name, config=None, allow_none=False):
        """Get the value of a variable from the namelist definition file.

        The `config` argument is passed through to the underlying
        `NamelistDefaults.get_value` call as the `attribute` argument.

        The return value of this function is a list of values that were found in
        the defaults file. If there is no matching default, this function
        returns `None` if `allow_none=True` is passed, otherwise an error is
        raised.

        Note that we perform some translation of the values, since there are a
        few differences between Fortran namelist literals and values in the
        defaults file:
        1) In the defaults file, whitespace is ignored except within strings, so
           the output of this function strips out most whitespace. (This implies
           that commas are the only way to separate array elements in the
           defaults file.)
        2) In the defaults file, quotes around character literals (strings) are
           optional, as long as the literal does not contain whitespace, commas,
           or (single or double) quotes. If a setting for a character variable
           does not seem to have quotes (and is not a null value), this function
           will add them.
        3) Default values may refer to variables in a case's `env_*.xml` files.
           This function replaces references of the form `$VAR` or `${VAR}` with
           the value of the variable `VAR` in an env file, if that variable
           exists. This behavior is suppressed within single-quoted strings
           (similar to parameter expansion in shell scripts).
        """
        default = self._definition.get_value_match(name,
                                                   attributes=config,
                                                   exact_match=False)
        if default is None:
            expect(allow_none, "No default value found for %s." % name)
            return None
        default = expand_literal_list(default)

        var_type, _, _ = self._definition.split_type_string(name)

        for i, scalar in enumerate(default):
            # Skip single-quoted strings.
            if var_type == 'character' and scalar != '' and \
               scalar[0] == scalar[-1] == "'":
                continue
            match = _var_ref_re.search(scalar)
            while match:
                env_val = self._case.get_value(match.group('name'))
                expect(
                    env_val is not None,
                    "Namelist default for variable %s refers to unknown XML "
                    "variable %s." % (name, match.group('name')))
                scalar = scalar.replace(match.group(0), str(env_val), 1)
                match = _var_ref_re.search(scalar)
            default[i] = scalar

        # Deal with missing quotes.

        if var_type == 'character':
            for i, scalar in enumerate(default):
                # Preserve null values.
                if scalar != '':
                    default[i] = self.quote_string(scalar)

        default = self._to_python_value(name, default)
        return default