-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validate RTW user config file #3392
Comments
There doesn't seem to be an esmvaltool command line argument to validate a config file, so I think the best solution is to import esmvalcore.config.CFG. According to the docs:
|
Possible scope creep, but whatever you develop as part of this issue could be added as a command line option? I think this could be achieved by adding a |
Yes, scope creep. Will keep it in mind and open a separate issue if it looks like a straightforward extension. New subcommand |
My thinking thus far was to use |
I wonder whether it would be worth validating the configuration file written to disk, since that file will be used by the |
Changes to User Configuration FilesBe aware that user configuration files are changing: Useful Objects/Files in ESMValCore
BasicsSome basics for myself in case useful to others. By default, instantiating a CFG object loads and validates the user configuration file from your default location: from esmvalcore.config._config_object import CFG
my_local_CFG = CFG
print(my_local_CFG) If you try and change a value to an invalid value you'll get an error: my_local_CFG['run_diagnostic'] = 100 # expects a bool To load a specific user configuration file: non_default_usr_cfg = CFG._load_user_config(Path("path/to/non_default_user_config.yml"))
print(non_default_usr_cfg) The my_local_Config = Config()
my_local_Config.load_from_file(Path("path/to/user_config_file_.yml)")
print(my_local_Config) Important When a user config file is loaded it is automatically validated and will throw an error e.g. Solution 1 - Instantiate a CFG object from the user config YAML file we createThis could easily be used to validate the user config file created in Exploring better: Solution 2 - Call the Validators manuallyThere is a constant CFG._validate
Configure._validate or imported directly: from esmvalcore.config._config_validators import ValidationError, _validators It returns a dict where the key is a user configuration field and the value is the validation function for that field. {
'auxiliary_data_dir': <function validate_path at 0x7f0e1964e950>,
'compress_netcdf': <function validate_bool at 0x7f0e1964e7a0>
'config_developer_file': <function validate_config_developer at 0x7f9a0e787370>,
'download_dir': <function validate_path at 0x7f9a0e786950>,
'drs': <function validate_drs at 0x7f9a0e7872e0>,
'exit_on_warning': <function validate_bool at 0x7f9a0e7867a0>
...
} The validation functions live in Currently E.g. def validate_user_config_file(user_config_content):
"""Collects errors from running ``ESMValCore.config._validators`` functions.
Parameters
----------
user_config_content: dict
An ESMValTool user configuration file loaded into memory as a Python
dictionary.
"""
errors = []
for cfg_key, cfg_value in user_config_content.items():
try:
validatation_function = _validators[cfg_key]
except KeyError as err:
errors.append(f'Key Error for {cfg_key.upper()}. May not be a valid ESMValTool user configuration key\nERROR: {err}\n')
else:
try:
print(f'Validating {cfg_key.upper()} with value "{cfg_value}" using function {validatation_function.__name__.upper()}.')
validatation_function(cfg_value)
except ValidationError as err:
errors.append(f'Validation error for {cfg_key.upper()} with value "{cfg_value}"\nERROR: {err}\n')
if errors:
print(errors)
raise ValidationError("\n".join(errors)) Key ErrorsIn addition to I think this code suggest that def __setitem__(self, key, val):
"""Map key to value."""
if key not in self._validate:
raise InvalidConfigParameter(
f"`{key}` is not a valid config parameter."
) And Raise Now vs Raise Later
If we do want a CLI option in ESMValCore per ESMValGroup/ESMValCore#2246 one way to achieve this might be a class decorator. I've played around with this a tiny bit and seems possible but a thought for another day. Discussion with @ehoganWe discussed that Solution No. 1 is too inelegant and runs against the "fail quickly" imperative behind the initial. I am therefore going to implement a fully tested version of Solution 2 - raising Key Errors with possible rogue fields noted as well as Validation Errors. We'll get it to that stage and then at Draft PR potentially seek wise counsel on some of the broader considerations. |
This is how it behaves when run within the workflow. With Valid valuesThe
One Invalid ValueMade this change to - "download_dir": "",
+ "download_dir": 100, The
Multiple Invalid Values & A Key ErrorMade these change to + "INVALID_KEY" : "value",
- "download_dir": "",
+ "download_dir": 100,
- "max_parallel_tasks": int(os.environ["MAX_PARALLEL_TASKS"]),
+ "max_parallel_tasks": "lots and lots",
- "remove_preproc_dir": False,
+ "remove_preproc_dir": 100, The configure task again fails and this is the
|
Is your feature request related to a problem? Please describe.
The recipe test workflow creates a user config file that encapsulates settings (e.g. DRS) defined in the cylc workflow config. This user config file should be validated in, or immediately after, the configure task, so that the workflow fails faster in the event of a config error.
Part of #2786
Would you be able to help out?
Yes
The text was updated successfully, but these errors were encountered: