From 12bbd2f0c16bd445b4d52efc42650c9da23f9fb2 Mon Sep 17 00:00:00 2001 From: Gabriel Soares <70075435+soaressgabriel@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:07:35 -0300 Subject: [PATCH 1/2] Update ModelConfiguration class to remove support for INI file format --- rubem/configuration/model_configuration.py | 21 +--- .../configuration/test_model_configuration.py | 118 ------------------ 2 files changed, 3 insertions(+), 136 deletions(-) diff --git a/rubem/configuration/model_configuration.py b/rubem/configuration/model_configuration.py index 7787379..c869331 100644 --- a/rubem/configuration/model_configuration.py +++ b/rubem/configuration/model_configuration.py @@ -1,4 +1,3 @@ -import configparser from datetime import datetime import json import logging @@ -24,18 +23,16 @@ class ModelConfiguration: """Represents the configuration settings for the model. The `ModelConfiguration` class is responsible for loading and storing the configuration settings - required for running the model. It supports loading configuration from either a dictionary, - an INI file, or a JSON file. + required for running the model. It supports loading configuration from either a dictionary or a JSON file. :param config_input: The configuration input. It can be a dictionary containing the configuration - settings, a file path to an INI or JSON file, or a file-like object. + settings, a file path to a JSON file, or a file-like object. :param validate_input: Whether to validate the input. Defaults to `True`. :type validate_input: bool, optional :raises FileNotFoundError: If the specified config file is not found. :raises ValueError: If the config file type is not supported. - :raises configparser.Error: If the INI file is not valid. :raises json.JSONDecodeError: If the JSON file is not valid. :raises KeyError: If a required setting is missing. :raises ValueError: If a setting value is invalid. @@ -58,9 +55,7 @@ def __init__( self.logger.error("Config file not found: %s", config_input_str) raise FileNotFoundError(f"Config file not found: {config_input_str}") - if config_input_str.endswith(".ini"): - self.config = self.__read_ini(config_input_str) - elif config_input_str.endswith(".json"): + if config_input_str.endswith(".json"): self.config = self.__read_json(config_input_str) else: self.logger.error("Unsupported file type: %s", config_input_str) @@ -235,16 +230,6 @@ def __check_inconsistencies(self): i += 1 print() - def __read_ini(self, file_path: Union[str, bytes, os.PathLike]): - self.logger.debug("Reading INI file: %s", file_path) - try: - parser = configparser.ConfigParser() - parser.read(file_path, encoding="utf-8") - return {section: dict(parser.items(section)) for section in parser.sections()} - except configparser.Error as e: - self.logger.error("Error parsing INI file: %s", e) - raise - def __read_json(self, file_path: Union[str, bytes, os.PathLike]): self.logger.debug("Reading JSON file: %s", file_path) try: diff --git a/tests/unit/configuration/test_model_configuration.py b/tests/unit/configuration/test_model_configuration.py index a2a7658..5dd5e04 100644 --- a/tests/unit/configuration/test_model_configuration.py +++ b/tests/unit/configuration/test_model_configuration.py @@ -84,83 +84,6 @@ class TestModelConfiguration: }, "RASTER_FILE_FORMAT": {"map_raster_series": True, "tiff_raster_series": True}, } - valid_config_ini_content = """ - [SIM_TIME] - start = 01/01/2019 - end = 01/12/2020 - [DIRECTORIES] - output = /test_path/ - etp = /test_path/ - prec = /test_path/ - ndvi = /test_path/ - kp = /test_path/ - landuse = /test_path/ - [FILENAME_PREFIXES] - etp_prefix = etp - prec_prefix = prec - ndvi_prefix = ndvi - kp_prefix = kp - landuse_prefix = cob - [RASTERS] - dem = /test_path/test_file.map - clone = /test_path/test_file.map - ndvi_max = /test_path/test_file.map - ndvi_min = /test_path/test_file.map - soil = /test_path/test_file.map - samples = /test_path/test_file.map - [TABLES] - rainydays = /test_path/test_file.txt - a_i = /test_path/test_file.txt - a_o = /test_path/test_file.txt - a_s = /test_path/test_file.txt - a_v = /test_path/test_file.txt - manning = /test_path/test_file.txt - bulk_density = /test_path/test_file.txt - k_sat = /test_path/test_file.txt - t_fcap = /test_path/test_file.txt - t_sat = /test_path/test_file.txt - t_wp = /test_path/test_file.txt - rootzone_depth = /test_path/test_file.txt - k_c_min = /test_path/test_file.txt - k_c_max = /test_path/test_file.txt - t_por = /test_path/test_file.txt - [GRID] - grid = 500.0 - [CALIBRATION] - alpha = 4.5 - b = 0.5 - w_1 = 0.333 - w_2 = 0.333 - w_3 = 0.334 - rcd = 5.0 - f = 0.5 - alpha_gw = 0.5 - x = 0.5 - [INITIAL_SOIL_CONDITIONS] - t_ini = 1.0 - bfw_ini = 0.1 - bfw_lim = 1.0 - s_sat_ini = 1.1 - [CONSTANTS] - fpar_max = 0.95 - fpar_min = 0.001 - lai_max = 12.0 - i_imp = 2.5 - [GENERATE_FILE] - itp = True - bfw = True - srn = True - eta = True - lfw = True - rec = True - smc = True - rnf = True - arn = True - tss = True - [RASTER_FILE_FORMAT] - map_raster_series = True - tiff_raster_series = True - """ valid_config_json_content = """ { "SIM_TIME": { @@ -315,47 +238,6 @@ def test_init_with_incomplete_dictionary(self): with pytest.raises(Exception): _ = ModelConfiguration({"SIM_TIME": {"start": "01/01/2019", "end": "01/12/2020"}}) - @pytest.mark.unit - def test_init_with_ini_file(self, fs, mocker): - band_mock = MagicMock(spec=RasterBand) - band_mock.no_data_value = -9999 - band_mock.data_array = np.ones((3, 3)) - fs.create_file( - "/test_path/config.ini", - contents=self.valid_config_ini_content, - ) - mocker.patch("osgeo.gdal.OpenEx") - mocker.patch("osgeo.gdal.GetDataTypeName") - mocker.patch("os.path.getsize", return_value=100) - mocker.patch("rubem.configuration.raster_map.RasterBand", return_value=band_mock) - _ = ModelConfiguration("/test_path/config.ini") - - @pytest.mark.unit - def test_init_with_not_existent_ini_file(self): - with pytest.raises(Exception): - _ = ModelConfiguration("/test_path/config.ini") - - @pytest.mark.unit - def test_init_with_empty_ini_file(self, fs): - fs.create_file("/test_path/config.ini") - with pytest.raises(Exception): - _ = ModelConfiguration("/test_path/config.ini") - - @pytest.mark.unit - def test_init_with_invalid_ini_file(self, fs): - fs.create_file("/test_path/config.ini", contents="invalid") - with pytest.raises(Exception): - _ = ModelConfiguration("/test_path/config.ini") - - @pytest.mark.unit - def test_init_with_incomplete_ini_file(self, fs): - fs.create_file( - "/test_path/config.ini", - contents="[SIM_TIME]\nstart = 01/01/2019\nend = 01/12/2020", - ) - with pytest.raises(Exception): - _ = ModelConfiguration("/test_path/config.ini") - @pytest.mark.unit def test_init_with_json_file(self, fs, mocker): band_mock = MagicMock(spec=RasterBand) From 350597c2eb43fa8bbda3cc4e77f0c199285ee324 Mon Sep 17 00:00:00 2001 From: Gabriel Soares <70075435+soaressgabriel@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:07:40 -0300 Subject: [PATCH 2/2] Update file_path_cli_arg_validator to only support JSON file format --- rubem/validation/cli_validators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rubem/validation/cli_validators.py b/rubem/validation/cli_validators.py index c516f7f..93d7520 100644 --- a/rubem/validation/cli_validators.py +++ b/rubem/validation/cli_validators.py @@ -22,11 +22,11 @@ def file_path_cli_arg_validator(path: str): logger.error("Specified file path %s is empty", path) raise argparse.ArgumentTypeError(f'Specified file path "{path}" is empty.') - if not os.path.splitext(path)[1] in [".json", ".ini"]: + if not os.path.splitext(path)[1] in [".json"]: logger.error("Specified file path %s is not a valid file format", path) raise argparse.ArgumentTypeError( f'Specified file path "{path}" is not a valid file format. ' - f"Only JSON and INI file formats are supported." + f"Only JSON file format is supported." ) return path