Skip to content

Commit

Permalink
Validate YAML file using schema before constructing module. (#1560)
Browse files Browse the repository at this point in the history
<!--Please ensure the PR fulfills the following requirements! -->
<!-- If this is your first PR, make sure to add your details to the
AUTHORS.rst! -->
### Pull Request Checklist:
- [x] This PR addresses an already opened issue (for bug fixes /
features)
    - This PR fixes #1523
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] (If applicable) Documentation has been added / updated (for bug
fixes / features)
- [x] CHANGES.rst has been updated (with summary of main changes)
- [ ] Link to issue (:issue:`number`) and pull request (:pull:`number`)
has been added

### What kind of change does this PR introduce?

* Use Yamale to validate schema before constructing module. Good news,
no error found in the test suite.

### Does this PR introduce a breaking change?


### Other information:

There was an issue raised by @tlogan2000 about indicators accepting
wrong arguments without failing. Could you post an offending example ?
  • Loading branch information
huard authored Dec 15, 2023
2 parents 20ee8b4 + ad70965 commit 03a717d
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 24 deletions.
3 changes: 2 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
Changelog
=========


v0.48 (unreleased)
------------------
Contributors to this version: Juliette Lavoie (:user:`juliettelavoie`), Pascal Bourgault (:user:`aulemahal`), Trevor James Smith (:user:`Zeitsperre`), David Huard (:user:`huard`), Éric Dupuis (:user:`coxipi`).

New features and enhancements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Added uncertainty partitioning method `lafferty_sriver` from Lafferty and Sriver (2023), which can partition uncertainty related to the downscaling method. (:issue:`1497`, :pull:`1529`).
* Validate YAML indicators description before trying to build module. (:issue:`1523`, :pull:`1560`).



v0.47.0 (2023-12-01)
Expand Down
23 changes: 8 additions & 15 deletions docs/notebooks/extendxclim.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -397,26 +397,15 @@
"\n",
"\n",
"#### Validation of the YAML file\n",
"Using [yamale](https://github.com/23andMe/Yamale), it is possible to check if the YAML file is valid. `xclim` ships with a schema (in `xclim/data/schema.yml`) file. The file can be located with:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from importlib.resources import path\n",
"\n",
"with path(\"xclim.data\", \"schema.yml\") as f:\n",
" print(f)"
"Using [yamale](https://github.com/23andMe/Yamale), it is possible to check if the YAML file is valid. `xclim` ships with a schema (in `xclim/data/schema.yml`) file. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And the validation can be executed either in a python session:"
"The validation can be executed in a python session:"
]
},
{
Expand All @@ -425,6 +414,8 @@
"metadata": {},
"outputs": [],
"source": [
"from importlib.resources import path\n",
"\n",
"import yamale\n",
"\n",
"with path(\"xclim.data\", \"schema.yml\") as f:\n",
Expand All @@ -437,13 +428,15 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"No errors means it passed. The validation can also be run through the command line with:\n",
"Or the validation can alternatively be run from the command line with:\n",
"\n",
"```bash\n",
"yamale -s path/to/schema.yml path/to/module.yml\n",
"```\n",
"\n",
"#### Loading the module and computating of the indices."
"Note that xclim builds indicators from a yaml file, as shown in the next example, it validates it first. \n",
"\n",
"#### Loading the module and computing indicators."
]
},
{
Expand Down
6 changes: 0 additions & 6 deletions tests/test_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,6 @@ def test_custom_indices(open_dataset):
# Use the example data used in the Extending Xclim notebook for testing.
example_path = Path(__file__).parent.parent / "docs" / "notebooks" / "example"

schema = yamale.make_schema(
Path(__file__).parent.parent / "xclim" / "data" / "schema.yml"
)
data = yamale.make_data(example_path / "example.yml")
yamale.validate(schema, data)

pr = open_dataset("ERA5/daily_surface_cancities_1990-1993.nc").pr

# This tests load_module with a python file that is _not_ on the PATH
Expand Down
13 changes: 11 additions & 2 deletions xclim/core/indicator.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@
In the following, the section under `<identifier>` is referred to as `data`. When creating indicators from
a dictionary, with :py:meth:`Indicator.from_dict`, the input dict must follow the same structure of `data`.
The resulting yaml file can be validated using the provided schema (in xclim/data/schema.yml)
and the YAMALE tool :cite:p:`lopker_yamale_2022`. See the "Extending xclim" notebook for more info.
When a module is built from a yaml file, the yaml is first validated against the schema (see xclim/data/schema.yml)
using the YAMALE library (:cite:p:`lopker_yamale_2022`). See the "Extending xclim" notebook for more info.
Inputs
~~~~~~
Expand Down Expand Up @@ -115,6 +115,7 @@

import numpy as np
import xarray
import yamale
from xarray import DataArray, Dataset
from yaml import safe_load

Expand Down Expand Up @@ -1716,6 +1717,14 @@ def build_indicator_module_from_yaml( # noqa: C901
with ymlpath.open(encoding=encoding) as f:
yml = safe_load(f)

# Read schema
schema = yamale.make_schema(Path(__file__).parent.parent / "data" / "schema.yml")

# Validate - a YamaleError will be raised if the module does not comply with the schema.
yamale.validate(
schema, yamale.make_data(content=ymlpath.read_text(encoding=encoding))
)

# Load values from top-level in yml.
# Priority of arguments differ.
module_name = name or yml.get("module", filepath.stem)
Expand Down

0 comments on commit 03a717d

Please sign in to comment.