diff --git a/development.yaml b/development.yaml deleted file mode 100644 index 0a5d704c1..000000000 --- a/development.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: cset-dev -channels: - - conda-forge -dependencies: - # Just the dependencies needed during development. Others are pulled in by - # tox. - - pre-commit - - black - - tox-conda diff --git a/pyproject.toml b/pyproject.toml index d63cc4b56..b48a3ad60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,9 +12,10 @@ classifiers = [ ] dependencies = [ "numpy", - "scitools-iris", + "scitools-iris >= 3.6", "ruamel.yaml >= 0.17", "importlib_resources >= 3.0.0 ; python_version < '3.9'", + "pygraphviz >= 1.11" ] [project.urls] diff --git a/src/CSET/operators/constraints.py b/src/CSET/operators/constraints.py index 5b6db30aa..95a9f1a66 100644 --- a/src/CSET/operators/constraints.py +++ b/src/CSET/operators/constraints.py @@ -30,7 +30,7 @@ def generate_stash_constraint(stash: str, **kwargs) -> iris.AttributeConstraint: Arguments --------- stash: str - stash code to build iris constraint, currently using "m01s03i236" + stash code to build iris constraint, such as "m01s03i236" Returns ------- diff --git a/src/CSET/operators/filters.py b/src/CSET/operators/filters.py index 03bbf957a..9a0a0e329 100644 --- a/src/CSET/operators/filters.py +++ b/src/CSET/operators/filters.py @@ -18,25 +18,27 @@ import iris import iris.cube +from typing import Union def filter_cubes( - cubelist: iris.cube.CubeList, constraint: iris.Constraint, **kwargs + cube: Union[iris.cube.Cube, iris.cube.CubeList], + constraint: iris.Constraint, + **kwargs, ) -> iris.cube.Cube: """ Filters a cubelist down to a single cube based on a constraint. Arguments --------- - cubelist: iris.cube.CubeList - Cubes to iterate over + cube: iris.cube.Cube | iris.cube.CubeList + Cube(s) to iterate over constraint: iris.Constraint Constraint to extract Returns ------- - cube: iris.cube.Cube - Single variable + iris.cube.Cube Raises ------ @@ -44,7 +46,7 @@ def filter_cubes( If the constraint doesn't produce a single cube. """ - filtered_cubes = cubelist.extract(constraint) + filtered_cubes = cube.extract(constraint) # Check filtered cubes is a CubeList containing one cube. if len(filtered_cubes) == 1: diff --git a/src/CSET/recipes/__init__.py b/src/CSET/recipes/__init__.py index ee097f5f6..c0bf08fdf 100644 --- a/src/CSET/recipes/__init__.py +++ b/src/CSET/recipes/__init__.py @@ -37,7 +37,7 @@ def _unpack_recipes_from_dir(input_dir: Path, output_dir: Path): output_dir.mkdir(parents=True, exist_ok=True) if file.is_file() and file.suffix == ".yaml": if output_dir.joinpath(file.name).exists(): - logging.warn( + logging.warning( "%s already exists in target directory, skipping.", file.name ) else: diff --git a/tests/operators/test_write.py b/tests/operators/test_write.py deleted file mode 100644 index 10412f21d..000000000 --- a/tests/operators/test_write.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2022 Met Office and contributors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from pathlib import Path -import tempfile -from uuid import uuid4 -import os - -from CSET.operators import write, read - - -def test_write_cube_to_nc_string(): - """Write cube to string path and verify.""" - cube = read.read_cubes("tests/test_data/air_temp.nc")[0] - filename = f"{tempfile.gettempdir()}/{uuid4()}.nc" - write.write_cube_to_nc(cube, filename) - # Check that the cube was written correctly - written_cube = read.read_cubes(filename)[0] - assert written_cube == cube - os.unlink(filename) - - -def test_write_cube_to_nc_path(): - """Write cube to Path and verify.""" - cube = read.read_cubes("tests/test_data/air_temp.nc")[0] - filepath = Path(f"{tempfile.gettempdir()}/{uuid4()}.nc") - write.write_cube_to_nc(cube, filepath) - # Check that the cube was written correctly - written_cube = read.read_cubes(filepath)[0] - assert written_cube == cube - filepath.unlink() diff --git a/tests/test_cli.py b/tests/test_cli.py index 7283b3dcf..121f7a575 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -25,15 +25,20 @@ def test_command_line_help(): + """Check that help commands work.""" + subprocess.run(["cset", "--help"], check=True) # test verbose options. This is really just to up the coverage number. subprocess.run(["cset", "-v"], check=True) subprocess.run(["cset", "-vv"], check=True) + subprocess.run(["cset", "--version"], check=True) # Gain coverage of __main__.py subprocess.run(["python3", "-m", "CSET", "-h"], check=True) def test_recipe_execution(): + """Test running CSET recipe from the command line.""" + subprocess.run( [ "cset", @@ -48,6 +53,7 @@ def test_recipe_execution(): def test_environ_var_recipe(): """Test recipe coming from environment variable.""" + os.environ[ "CSET_RECIPE" ] = """ @@ -82,8 +88,28 @@ def test_graph_creation(): output_file.unlink() +def test_graph_creation_env_var(): + """ + Generates a graph with the command line interface from an environment + variable. + """ + + os.environ[ + "CSET_RECIPE" + ] = """ + steps: + - operator: misc.noop + """ + # Run with output path specified + output_file = Path(tempfile.gettempdir(), f"{uuid4()}.svg") + subprocess.run(("cset", "graph", "-o", str(output_file)), check=True) + assert output_file.exists() + output_file.unlink() + + def test_graph_details(): """Generate a graph with details with details.""" + output_file = Path(tempfile.gettempdir(), f"{uuid4()}.svg") subprocess.run( ( @@ -102,6 +128,7 @@ def test_graph_details(): def test_cookbook_cwd(): """Unpacking the recipes into the current working directory.""" + subprocess.run(["cset", "cookbook"], check=True) assert Path.cwd().joinpath("recipes/extract_instant_air_temp.yaml").exists() shutil.rmtree(Path.cwd().joinpath("recipes")) @@ -109,6 +136,7 @@ def test_cookbook_cwd(): def test_cookbook_path(): """Unpacking the recipes into a specified directory.""" + with tempfile.TemporaryDirectory() as tmpdir: subprocess.run(["cset", "cookbook", tmpdir], check=True) assert Path(tmpdir, "extract_instant_air_temp.yaml").exists()