def test_loop_bound_when_fparser_not_initialised(): '''This reproduces #1272: a gocean custom loop boundary could not be parsed if the parser has not been initialised previously. Reproduce this bug by re-initialising fparser with an empty class list. ''' GOLoop.add_bounds("go_offset_sw:go_ct:internal_we_halo:1:2:3:4")
def __init__(self, config, section): super(GOceanConfig, self).__init__(section) for key in section.keys(): # Do not handle any keys from the DEFAULT section # since they are handled by Config(), not this class. if key in config.get_default_keys(): continue if key == "iteration-spaces": # The value associated with the iteration-spaces key is a # set of lines, each line defining one new iteration space. # Each individual iteration space added is checked # in add_bounds for correctness. value_as_str = str(section[key]) new_iteration_spaces = value_as_str.split("\n") from psyclone.gocean1p0 import GOLoop for it_space in new_iteration_spaces: GOLoop.add_bounds(it_space) elif key == "access_mapping": # Handled in the base class APISpecificConfig pass else: raise ConfigurationError("Invalid key \"{0}\" found in " "\"{1}\".".format( key, config.filename))
def __init__(self, config, section): # pylint: disable=too-many-locals super(GOceanConfig, self).__init__(section) # Setup the mapping for the grid properties. This dictionary stores # the name of the grid property as key (e.g. ``go_grid_dx_t``), # with the value being a named tuple with an entry for 'property' # and 'type'. The 'property' is a format string to dereference # a property, and 'type' is a string. # These values are taken from the psyclone config file. self._grid_properties = {} # Initialise debug_mode settings (default to False if it doesn't exist) self._debug_mode = False for key in section.keys(): # Do not handle any keys from the DEFAULT section # since they are handled by Config(), not this class. if key in config.get_default_keys(): continue if key == "iteration-spaces": # The value associated with the iteration-spaces key is a # set of lines, each line defining one new iteration space. # Each individual iteration space added is checked # in add_bounds for correctness. value_as_str = str(section[key]) new_iteration_spaces = value_as_str.split("\n") from psyclone.gocean1p0 import GOLoop for it_space in new_iteration_spaces: GOLoop.add_bounds(it_space) elif key == "access_mapping": # Handled in the base class APISpecificConfig pass elif key == "debug_mode": # Boolean that specifies if debug mode is enabled try: self._debug_mode = section.getboolean("debug_mode") except ValueError as err: six.raise_from( ConfigurationError( "error while parsing DEBUG_MODE in the " "[gocean1p0] section of the config file: {0}". format(str(err))), err) elif key == "grid-properties": # Grid properties have the format: # go_grid_area_u: {0}%%grid%%area_u: array: real, # First the name, then the Fortran code to access the property, # followed by the type ("array" or "scalar") and then the # intrinsic type ("integer" or "real") all_props = self.create_dict_from_string(section[key]) for grid_property in all_props: try: fortran, variable_type, intrinsic_type = \ all_props[grid_property].split(":") except ValueError: # Raised when the string does not contain exactly # three values separated by ":" error = "Invalid property \"{0}\" found with value " \ "\"{1}\" in \"{2}\". It must have exactly " \ "three ':'-delimited separated values: the " \ "property, whether it is a scalar or an " \ "array, and the intrinsic type (real or " \ "integer)." \ .format(grid_property, all_props[grid_property], config.filename) raise ConfigurationError(error) # Make sure to remove the spaces which the config # file might contain self._grid_properties[grid_property] = \ GOceanConfig.make_property(fortran.strip(), variable_type.strip(), intrinsic_type.strip()) # Check that the required values for xstop and ystop # are defined: for required in [ "go_grid_xstop", "go_grid_ystop", "go_grid_data", "go_grid_internal_inner_start", "go_grid_internal_inner_stop", "go_grid_internal_outer_start", "go_grid_internal_outer_stop", "go_grid_whole_inner_start", "go_grid_whole_inner_stop", "go_grid_whole_outer_start", "go_grid_whole_outer_stop" ]: if required not in self._grid_properties: error = "The config file {0} does not contain " \ "values for the following, mandatory grid " \ "property: \"{1}\".".format(config.filename, required) raise ConfigurationError(error) else: raise ConfigurationError("Invalid key \"{0}\" found in " "\"{1}\".".format( key, config.filename))
def test_invalid_config_files(tmpdir): ''' Test various error conditions. ''' # Valid configuration file without iteration spaces. We add several # iteration spaces to it to test for various error conditions # pylint: disable=invalid-name # pylint: disable=too-many-statements _CONFIG_CONTENT = '''\ [DEFAULT] DEFAULTAPI = dynamo0.3 DEFAULTSTUBAPI = dynamo0.3 DISTRIBUTED_MEMORY = true REPRODUCIBLE_REDUCTIONS = false REPROD_PAD_SIZE = 8 [gocean1.0] ''' # Create a config files with gocean1.0 section, but an # invalid iteration space: content = _CONFIG_CONTENT + "iteration-spaces=a:b" config_file = tmpdir.join("config1") with config_file.open(mode="w") as new_cfg: new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(str(config_file)) assert "An iteration space must be in the form" in str(err.value) assert "But got \"a:b\"" in str(err.value) # Try a multi-line specification to make sure all lines are tested content = _CONFIG_CONTENT + "iteration-spaces=a:b:c:1:2:3:4\n d:e" config_file = tmpdir.join("config2") with config_file.open(mode="w") as new_cfg: new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(str(config_file)) assert "An iteration space must be in the form" in str(err.value) assert "But got \"d:e\"" in str(err.value) # Invalid {} expression in first loop bound content = _CONFIG_CONTENT + "iteration-spaces=a:b:c:{X}:2:3:4" config_file = tmpdir.join("config3") with config_file.open(mode="w") as new_cfg: new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(str(config_file)) assert "Only '{start}' and '{stop}' are allowed as bracketed "\ "expression in an iteration space." in str(err.value) assert "But got {X}" in str(err.value) # Invalid {} expression in last loop bound: content = _CONFIG_CONTENT + "iteration-spaces=a:b:c:1:2:3:{Y}" config_file = tmpdir.join("config4") with config_file.open(mode="w") as new_cfg: new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(str(config_file)) assert "Only '{start}' and '{stop}' are allowed as bracketed "\ "expression in an iteration space." in str(err.value) assert "But got {Y}" in str(err.value) # Add an invalid key: content = _CONFIG_CONTENT + "invalid-key=value" config_file = tmpdir.join("config5") with config_file.open(mode="w") as new_cfg: new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(str(config_file)) assert "Invalid key \"invalid-key\" found in \"{0}\".".\ format(str(config_file)) in str(err.value) for i in [ "DEFAULTAPI", "DEFAULTSTUBAPI", "DISTRIBUTED_MEMORY", "REPRODUCIBLE_REDUCTIONS" ]: # They keys are returned in lower case assert i.lower() in config.get_default_keys() with pytest.raises(InternalError) as err: GOLoop.add_bounds(1) # Different error message (for type) in python2 vs python3: assert "The parameter 'bound_info' must be a string, got '1' "\ "(type <type 'int'>)" in str(err.value) or \ "The parameter 'bound_info' must be a string, got '1' "\ "(type <class 'int'>)" in str(err.value) # Test syntactically invalid loop boundaries with pytest.raises(ConfigurationError) as err: GOLoop.add_bounds("offset:field:space:1(:2:3:4") assert "Expression '1(' is not a valid do loop boundary" in str(err.value) with pytest.raises(ConfigurationError) as err: GOLoop.add_bounds("offset:field:space:1:2:3:4+") assert "Expression '4+' is not a valid do loop boundary" in str(err.value) # Test invalid field properties - too many fields content = _CONFIG_CONTENT + "grid-properties = a: {0}%%b:c:d:e" config_file = tmpdir.join("config1") with config_file.open(mode="w") as new_cfg: new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(str(config_file)) assert "Invalid property \"a\" found with value \"{0}%b:c:d:e\"" \ in str(err.value) # Test invalid field properties - not enough fields content = _CONFIG_CONTENT + "grid-properties = a:b" config_file = tmpdir.join("config1") with config_file.open(mode="w") as new_cfg: new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(str(config_file)) assert "Invalid property \"a\" found with value \"b\"" \ in str(err.value) # Test missing required values content = _CONFIG_CONTENT + "grid-properties = a:b:array:real" config_file = tmpdir.join("config1") with config_file.open(mode="w") as new_cfg: new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(str(config_file)) # The config file {0} does not contain values for "..." assert "does not contain values for the following, mandatory grid " \ "property: \"go_grid_xstop\"" in str(err.value)
def test_invalid_config_files(): ''' Test various error conditions. ''' # Valid configuration file without iteration spaces. We add several # iteration spaces to it to test for various error conditions # pylint: disable=invalid-name # pylint: disable=too-many-statements _CONFIG_CONTENT = '''\ [DEFAULT] DEFAULTAPI = dynamo0.3 DEFAULTSTUBAPI = dynamo0.3 DISTRIBUTED_MEMORY = true REPRODUCIBLE_REDUCTIONS = false REPROD_PAD_SIZE = 8 [gocean1.0] ''' # Create a config files with gocean1.0 section, but an # invalid iteration space: content = _CONFIG_CONTENT + "iteration-spaces=a:b" with tempfile.NamedTemporaryFile(delete=False, mode="w") as new_cfg: new_name = new_cfg.name new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(new_name) assert "An iteration space must be in the form" in str(err) assert "But got \"a:b\"" in str(err) # Try a multi-line specification to make sure all lines are tested content = _CONFIG_CONTENT + "iteration-spaces=a:b:c:1:2:3:4\n d:e" with tempfile.NamedTemporaryFile(delete=False, mode="w") as new_cfg: new_name = new_cfg.name new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(new_name) assert "An iteration space must be in the form" in str(err) assert "But got \"d:e\"" in str(err) # Invalid {} expression in first loop bound content = _CONFIG_CONTENT + "iteration-spaces=a:b:c:{X}:2:3:4" with tempfile.NamedTemporaryFile(delete=False, mode="w") as new_cfg: new_name = new_cfg.name new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(new_name) assert "Only '{start}' and '{stop}' are allowed as bracketed "\ "expression in an iteration space." in str(err) assert "But got {X}" in str(err) # Invalid {} expression in last loop bound: content = _CONFIG_CONTENT + "iteration-spaces=a:b:c:1:2:3:{Y}" with tempfile.NamedTemporaryFile(delete=False, mode="w") as new_cfg: new_name = new_cfg.name new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(new_name) assert "Only '{start}' and '{stop}' are allowed as bracketed "\ "expression in an iteration space." in str(err) assert "But got {Y}" in str(err) # Add an invalid key: content = _CONFIG_CONTENT + "invalid-key=value" with tempfile.NamedTemporaryFile(delete=False, mode="w") as new_cfg: new_name = new_cfg.name new_cfg.write(content) new_cfg.close() config = Config() with pytest.raises(ConfigurationError) as err: config.load(new_name) assert "Invalid key \"invalid-key\" found in \"{0}\".".\ format(new_name) in str(err) for i in [ "DEFAULTAPI", "DEFAULTSTUBAPI", "DISTRIBUTED_MEMORY", "REPRODUCIBLE_REDUCTIONS" ]: # They keys are returned in lower case assert i.lower() in config.get_default_keys() with pytest.raises(InternalError) as err: GOLoop.add_bounds(1) # Different error message (for type) in python2 vs python3: assert "The parameter 'bound_info' must be a string, got '1' "\ "(type <type 'int'>)" in str(err) or \ "The parameter 'bound_info' must be a string, got '1' "\ "(type <class 'int'>)" in str(err) # Test syntactically invalid loop boundaries with pytest.raises(ConfigurationError) as err: GOLoop.add_bounds("offset:field:space:1(:2:3:4") assert "Expression '1(' is not a valid do loop boundary" in str(err) with pytest.raises(ConfigurationError) as err: GOLoop.add_bounds("offset:field:space:1:2:3:4+") assert "Expression '4+' is not a valid do loop boundary" in str(err)