diff --git a/docs/sections/user_guide/cli/drivers/chgres_cube/help.out b/docs/sections/user_guide/cli/drivers/chgres_cube/help.out index 7d632bb8b..2728654fa 100644 --- a/docs/sections/user_guide/cli/drivers/chgres_cube/help.out +++ b/docs/sections/user_guide/cli/drivers/chgres_cube/help.out @@ -20,5 +20,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/esg_grid/help.out b/docs/sections/user_guide/cli/drivers/esg_grid/help.out index 0069553e6..0e0ae5a98 100644 --- a/docs/sections/user_guide/cli/drivers/esg_grid/help.out +++ b/docs/sections/user_guide/cli/drivers/esg_grid/help.out @@ -20,5 +20,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/filter_topo/help.out b/docs/sections/user_guide/cli/drivers/filter_topo/help.out index 80ff221b5..cd71378b2 100644 --- a/docs/sections/user_guide/cli/drivers/filter_topo/help.out +++ b/docs/sections/user_guide/cli/drivers/filter_topo/help.out @@ -24,5 +24,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/fv3/help.out b/docs/sections/user_guide/cli/drivers/fv3/help.out index 09420ef44..a383dbafe 100644 --- a/docs/sections/user_guide/cli/drivers/fv3/help.out +++ b/docs/sections/user_guide/cli/drivers/fv3/help.out @@ -34,5 +34,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/global_equiv_resol/help.out b/docs/sections/user_guide/cli/drivers/global_equiv_resol/help.out index eb3d7b505..d9d829b91 100644 --- a/docs/sections/user_guide/cli/drivers/global_equiv_resol/help.out +++ b/docs/sections/user_guide/cli/drivers/global_equiv_resol/help.out @@ -20,5 +20,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/ioda/help.out b/docs/sections/user_guide/cli/drivers/ioda/help.out index 692138971..23a0d65ec 100644 --- a/docs/sections/user_guide/cli/drivers/ioda/help.out +++ b/docs/sections/user_guide/cli/drivers/ioda/help.out @@ -24,5 +24,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/jedi/help.out b/docs/sections/user_guide/cli/drivers/jedi/help.out index fe3d01ae0..0386272f6 100644 --- a/docs/sections/user_guide/cli/drivers/jedi/help.out +++ b/docs/sections/user_guide/cli/drivers/jedi/help.out @@ -24,6 +24,8 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config validate_only diff --git a/docs/sections/user_guide/cli/drivers/make_hgrid/help.out b/docs/sections/user_guide/cli/drivers/make_hgrid/help.out index 7acf294ca..177f6ae3c 100644 --- a/docs/sections/user_guide/cli/drivers/make_hgrid/help.out +++ b/docs/sections/user_guide/cli/drivers/make_hgrid/help.out @@ -18,5 +18,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/make_solo_mosaic/help.out b/docs/sections/user_guide/cli/drivers/make_solo_mosaic/help.out index 0b899c013..4ef71e00e 100644 --- a/docs/sections/user_guide/cli/drivers/make_solo_mosaic/help.out +++ b/docs/sections/user_guide/cli/drivers/make_solo_mosaic/help.out @@ -18,5 +18,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/mpas/help.out b/docs/sections/user_guide/cli/drivers/mpas/help.out index cb7106e5f..aeb8b2ccf 100644 --- a/docs/sections/user_guide/cli/drivers/mpas/help.out +++ b/docs/sections/user_guide/cli/drivers/mpas/help.out @@ -26,6 +26,8 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component streams_file The streams file validate diff --git a/docs/sections/user_guide/cli/drivers/mpas_init/help.out b/docs/sections/user_guide/cli/drivers/mpas_init/help.out index c2f743422..262a62bc3 100644 --- a/docs/sections/user_guide/cli/drivers/mpas_init/help.out +++ b/docs/sections/user_guide/cli/drivers/mpas_init/help.out @@ -26,6 +26,8 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component streams_file The streams file validate diff --git a/docs/sections/user_guide/cli/drivers/orog/help.out b/docs/sections/user_guide/cli/drivers/orog/help.out index 7db906799..b3f75f452 100644 --- a/docs/sections/user_guide/cli/drivers/orog/help.out +++ b/docs/sections/user_guide/cli/drivers/orog/help.out @@ -24,5 +24,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/orog_gsl/help.out b/docs/sections/user_guide/cli/drivers/orog_gsl/help.out index fde960dcd..c5ee11d8a 100644 --- a/docs/sections/user_guide/cli/drivers/orog_gsl/help.out +++ b/docs/sections/user_guide/cli/drivers/orog_gsl/help.out @@ -22,6 +22,8 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component topo_data_2p5m Global topographic data on 2.5-minute lat-lon grid topo_data_30s diff --git a/docs/sections/user_guide/cli/drivers/sfc_climo_gen/help.out b/docs/sections/user_guide/cli/drivers/sfc_climo_gen/help.out index f6170ae46..9882b3160 100644 --- a/docs/sections/user_guide/cli/drivers/sfc_climo_gen/help.out +++ b/docs/sections/user_guide/cli/drivers/sfc_climo_gen/help.out @@ -20,5 +20,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/shave/help.out b/docs/sections/user_guide/cli/drivers/shave/help.out index 75ffdf963..d5b2bfba9 100644 --- a/docs/sections/user_guide/cli/drivers/shave/help.out +++ b/docs/sections/user_guide/cli/drivers/shave/help.out @@ -20,5 +20,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/docs/sections/user_guide/cli/drivers/ungrib/help.out b/docs/sections/user_guide/cli/drivers/ungrib/help.out index 252272e05..1794559ad 100644 --- a/docs/sections/user_guide/cli/drivers/ungrib/help.out +++ b/docs/sections/user_guide/cli/drivers/ungrib/help.out @@ -22,6 +22,8 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config vtable diff --git a/docs/sections/user_guide/cli/drivers/upp/help.out b/docs/sections/user_guide/cli/drivers/upp/help.out index 7163d3f71..eb34386b6 100644 --- a/docs/sections/user_guide/cli/drivers/upp/help.out +++ b/docs/sections/user_guide/cli/drivers/upp/help.out @@ -24,5 +24,7 @@ Positional arguments: A run runscript The runscript + show_output + Show the output to be created by this component validate Validate the UW driver config diff --git a/src/uwtools/drivers/driver.py b/src/uwtools/drivers/driver.py index c98775fb7..756479b74 100644 --- a/src/uwtools/drivers/driver.py +++ b/src/uwtools/drivers/driver.py @@ -26,7 +26,7 @@ validate_external, validate_internal, ) -from uwtools.exceptions import UWConfigError +from uwtools.exceptions import UWConfigError, UWNotImplementedError from uwtools.logging import log from uwtools.scheduler import JobScheduler from uwtools.strings import STR @@ -393,6 +393,15 @@ def runscript(self): yield None self._write_runscript(path) + @external + def show_output(self): + """ + Show the output to be created by this component. + """ + yield self.taskname("expected output") + print(json.dumps(self.output, indent=2, sort_keys=True)) + yield asset(None, lambda: True) + @task def _run_via_batch_submission(self): """ @@ -416,7 +425,16 @@ def _run_via_local_execution(self): cmd = "{x} >{x}.out 2>&1".format(x=self._runscript_path) run_shell_cmd(cmd=cmd, cwd=self.rundir, log_output=True) - # Private helper methods + # Public methods + + @property + def output(self) -> dict[str, Union[str, list[str]]]: + """ + Returns a description of the file(s) created when this component runs. + """ + raise UWNotImplementedError("The output() method is not yet implemented for this driver") + + # Private methods @property def _run_resources(self) -> dict[str, Any]: diff --git a/src/uwtools/exceptions.py b/src/uwtools/exceptions.py index 616c6baf1..05aac5358 100644 --- a/src/uwtools/exceptions.py +++ b/src/uwtools/exceptions.py @@ -21,6 +21,12 @@ class UWConfigRealizeError(UWConfigError): """ +class UWNotImplementedError(UWError): + """ + Exception for signaling that uwtools has not (yet) implemented something. + """ + + class UWTemplateRenderError(UWError): """ Exception for issues arising from template rendering. diff --git a/src/uwtools/tests/drivers/test_cdeps.py b/src/uwtools/tests/drivers/test_cdeps.py index 6d7d5a378..75166c5db 100644 --- a/src/uwtools/tests/drivers/test_cdeps.py +++ b/src/uwtools/tests/drivers/test_cdeps.py @@ -17,6 +17,7 @@ from uwtools.config.formats.nml import NMLConfig from uwtools.drivers import cdeps from uwtools.drivers.cdeps import CDEPS +from uwtools.drivers.driver import AssetsCycleBased from uwtools.logging import log from uwtools.tests.support import logged from uwtools.tests.test_schemas import CDEPS_CONFIG @@ -35,6 +36,14 @@ def driverobj(tmp_path): # Tests +@mark.parametrize( + "method", + ["taskname", "_validate"], +) +def test_CDEPS(method): + assert getattr(CDEPS, method) is getattr(AssetsCycleBased, method) + + def test_CDEPS_atm(driverobj): with patch.object(CDEPS, "atm_nml") as atm_nml: with patch.object(CDEPS, "atm_stream") as atm_stream: diff --git a/src/uwtools/tests/drivers/test_chgres_cube.py b/src/uwtools/tests/drivers/test_chgres_cube.py index b796005c6..3f5568b8c 100644 --- a/src/uwtools/tests/drivers/test_chgres_cube.py +++ b/src/uwtools/tests/drivers/test_chgres_cube.py @@ -10,10 +10,11 @@ import f90nml # type: ignore from iotaa import refs -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.chgres_cube import ChgresCube from uwtools.drivers.driver import Driver +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.scheduler import Slurm from uwtools.tests.support import logged, regex_logged @@ -101,6 +102,7 @@ def driverobj(config, cycle): "_scheduler", "_validate", "_write_runscript", + "output", "run", ], ) @@ -140,6 +142,12 @@ def test_ChgresCube_namelist_file_missing_base_file(caplog, driverobj): assert regex_logged(caplog, "missing.nml: State: Not Ready (external asset)") +def test_ChgresCube_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_ChgresCube_provisioned_rundir(driverobj): with patch.multiple(driverobj, namelist_file=D, runscript=D) as mocks: driverobj.provisioned_rundir() diff --git a/src/uwtools/tests/drivers/test_driver.py b/src/uwtools/tests/drivers/test_driver.py index 9b5b11a3f..25dd0f625 100644 --- a/src/uwtools/tests/drivers/test_driver.py +++ b/src/uwtools/tests/drivers/test_driver.py @@ -19,7 +19,7 @@ from uwtools.config.formats.yaml import YAMLConfig from uwtools.drivers import driver -from uwtools.exceptions import UWConfigError +from uwtools.exceptions import UWConfigError, UWNotImplementedError from uwtools.logging import log from uwtools.scheduler import Slurm from uwtools.tests.support import regex_logged @@ -68,7 +68,11 @@ class ConcreteDriverCycleLeadtimeBased(Common, driver.DriverCycleLeadtimeBased): class ConcreteDriverTimeInvariant(Common, driver.DriverTimeInvariant): - pass + + @property + def output(self): + # The dict keys are intentionally out-of-alphabetical-order to test JSON sorting. + return {"bar": ["/path/to/bar1", "/path/to/bar2"], "foo": "/path/to/foo"} def write(path, x): @@ -397,6 +401,22 @@ def test_Driver_namelist_schema_default_disable(driverobj): assert driverobj.namelist_schema() == {"type": "object"} +def test_Driver_output(config): + driverobj = ConcreteDriverTimeInvariant(config) + assert driverobj.output == {"foo": "/path/to/foo", "bar": ["/path/to/bar1", "/path/to/bar2"]} + + +@mark.parametrize("cls", [ConcreteDriverCycleBased, ConcreteDriverCycleLeadtimeBased]) +def test_Driver_output_not_implemented(cls, config): + kwargs = {"config": config, "cycle": dt.datetime(2024, 10, 22, 12)} + if cls == ConcreteDriverCycleLeadtimeBased: + kwargs["leadtime"] = 6 + driverobj = cls(**kwargs) + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + @mark.parametrize("batch", [True, False]) def test_Driver_run(batch, driverobj): driverobj._batch = batch @@ -423,6 +443,45 @@ def test_Driver_runscript(arg, driverobj, type_): assert isinstance(runscript.call_args.kwargs[arg], type_) +def test_driver_show_output(capsys, config): + ConcreteDriverTimeInvariant(config).show_output() + expected = """ + { + "bar": [ + "/path/to/bar1", + "/path/to/bar2" + ], + "foo": "/path/to/foo" + } + """ + assert capsys.readouterr().out.strip() == dedent(expected).strip() + + +@mark.parametrize( + "base_file,update_values,expected", + [ + (False, False, {}), + (False, True, {"a": 33}), + (True, False, {"a": 11, "b": 22}), + (True, True, {"a": 33, "b": 22}), + ], +) +def test_Driver__create_user_updated_config_base_file( + base_file, driverobj, expected, tmp_path, update_values +): + path = tmp_path / "updated.yaml" + if not base_file: + del driverobj._config["base_file"] + if not update_values: + del driverobj._config["update_values"] + ConcreteDriverTimeInvariant._create_user_updated_config( + config_class=YAMLConfig, config_values=driverobj.config, path=path + ) + with open(path, "r", encoding="utf-8") as f: + updated = yaml.safe_load(f) + assert updated == expected + + def test_Driver__run_via_batch_submission(driverobj): runscript = driverobj._runscript_path executable = Path(driverobj.config["execution"]["executable"]) @@ -452,31 +511,6 @@ def test_Driver__run_via_local_execution(driverobj): prd.assert_called_once_with() -@mark.parametrize( - "base_file,update_values,expected", - [ - (False, False, {}), - (False, True, {"a": 33}), - (True, False, {"a": 11, "b": 22}), - (True, True, {"a": 33, "b": 22}), - ], -) -def test_Driver__create_user_updated_config_base_file( - base_file, driverobj, expected, tmp_path, update_values -): - path = tmp_path / "updated.yaml" - if not base_file: - del driverobj._config["base_file"] - if not update_values: - del driverobj._config["update_values"] - ConcreteDriverTimeInvariant._create_user_updated_config( - config_class=YAMLConfig, config_values=driverobj.config, path=path - ) - with open(path, "r", encoding="utf-8") as f: - updated = yaml.safe_load(f) - assert updated == expected - - def test_Driver__run_resources_fail(driverobj): del driverobj._config_intermediate["platform"] with raises(UWConfigError) as e: diff --git a/src/uwtools/tests/drivers/test_esg_grid.py b/src/uwtools/tests/drivers/test_esg_grid.py index f7d891698..96fa5d578 100644 --- a/src/uwtools/tests/drivers/test_esg_grid.py +++ b/src/uwtools/tests/drivers/test_esg_grid.py @@ -9,10 +9,11 @@ import f90nml # type: ignore from iotaa import refs -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.esg_grid import ESGGrid +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.tests.support import logged, regex_logged @@ -75,6 +76,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "taskname", @@ -116,6 +118,12 @@ def test_ESGGrid_namelist_file_missing_base_file(caplog, driverobj): assert regex_logged(caplog, "missing.nml: State: Not Ready (external asset)") +def test_ESGGrid_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_ESGGrid_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_filter_topo.py b/src/uwtools/tests/drivers/test_filter_topo.py index 490ca3695..ef0faf543 100644 --- a/src/uwtools/tests/drivers/test_filter_topo.py +++ b/src/uwtools/tests/drivers/test_filter_topo.py @@ -8,11 +8,12 @@ import f90nml # type: ignore from iotaa import refs -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.config.support import from_od from uwtools.drivers.driver import Driver from uwtools.drivers.filter_topo import FilterTopo +from uwtools.exceptions import UWNotImplementedError # Fixtures @@ -74,6 +75,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "taskname", @@ -108,6 +110,12 @@ def test_FilterTopo_namelist_file(driverobj): assert actual == expected +def test_FilterTopo_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_FilterTopo_provisioned_rundir(driverobj): with patch.multiple( driverobj, input_grid_file=D, filtered_output_file=D, namelist_file=D, runscript=D diff --git a/src/uwtools/tests/drivers/test_fv3.py b/src/uwtools/tests/drivers/test_fv3.py index 2c7cf069a..80939b56a 100644 --- a/src/uwtools/tests/drivers/test_fv3.py +++ b/src/uwtools/tests/drivers/test_fv3.py @@ -10,10 +10,11 @@ import yaml from iotaa import asset, external, refs -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.fv3 import FV3 +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.scheduler import Slurm from uwtools.tests.support import logged, regex_logged @@ -94,6 +95,7 @@ def true(): "_scheduler", "_validate", "_write_runscript", + "output", "run", ], ) @@ -211,6 +213,12 @@ def test_FV3_namelist_file_missing_base_file(caplog, driverobj): assert regex_logged(caplog, "missing.nml: State: Not Ready (external asset)") +def test_FV3_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + @mark.parametrize("domain", ("global", "regional")) def test_FV3_provisioned_rundir(domain, driverobj): driverobj._config["domain"] = domain diff --git a/src/uwtools/tests/drivers/test_global_equiv_resol.py b/src/uwtools/tests/drivers/test_global_equiv_resol.py index bd993f14a..95159d7f9 100644 --- a/src/uwtools/tests/drivers/test_global_equiv_resol.py +++ b/src/uwtools/tests/drivers/test_global_equiv_resol.py @@ -6,10 +6,11 @@ from unittest.mock import DEFAULT as D from unittest.mock import patch -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.global_equiv_resol import GlobalEquivResol +from uwtools.exceptions import UWNotImplementedError # Fixtures @@ -55,6 +56,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "taskname", @@ -76,6 +78,12 @@ def test_GlobalEquivResol_input_file(driverobj): assert driverobj.input_file().ready() +def test_GlobalEquivResol_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_GlobalEquivResol_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_ioda.py b/src/uwtools/tests/drivers/test_ioda.py index 50936d051..b012812a8 100644 --- a/src/uwtools/tests/drivers/test_ioda.py +++ b/src/uwtools/tests/drivers/test_ioda.py @@ -6,10 +6,11 @@ from unittest.mock import DEFAULT as D from unittest.mock import patch -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.ioda import IODA from uwtools.drivers.jedi_base import JEDIBase +from uwtools.exceptions import UWNotImplementedError # Fixtures @@ -79,6 +80,7 @@ def driverobj(config, cycle): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", ], @@ -91,6 +93,12 @@ def test_IODA_driver_name(driverobj): assert driverobj.driver_name() == IODA.driver_name() == "ioda" +def test_IODA_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_IODA_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_jedi.py b/src/uwtools/tests/drivers/test_jedi.py index d5378e281..21d3e4b88 100644 --- a/src/uwtools/tests/drivers/test_jedi.py +++ b/src/uwtools/tests/drivers/test_jedi.py @@ -10,12 +10,13 @@ import yaml from iotaa import asset, external -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.config.formats.yaml import YAMLConfig from uwtools.drivers import jedi, jedi_base from uwtools.drivers.jedi import JEDI from uwtools.drivers.jedi_base import JEDIBase +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.tests.support import regex_logged @@ -89,6 +90,7 @@ def driverobj(config, cycle): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", ], @@ -154,6 +156,12 @@ def test_JEDI_files_linked(driverobj): ) +def test_JEDI_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_JEDI_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_make_hgrid.py b/src/uwtools/tests/drivers/test_make_hgrid.py index bcf90d86c..0d7c1b228 100644 --- a/src/uwtools/tests/drivers/test_make_hgrid.py +++ b/src/uwtools/tests/drivers/test_make_hgrid.py @@ -5,10 +5,11 @@ from unittest.mock import DEFAULT as D from unittest.mock import patch -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.make_hgrid import MakeHgrid +from uwtools.exceptions import UWNotImplementedError # Fixtures @@ -60,6 +61,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "taskname", @@ -73,6 +75,12 @@ def test_MakeHgrid_driver_name(driverobj): assert driverobj.driver_name() == MakeHgrid.driver_name() == "make_hgrid" +def test_MakeHgrid_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_MakeHgrid_provisioned_rundir(driverobj): with patch.multiple(driverobj, runscript=D) as mocks: driverobj.provisioned_rundir() diff --git a/src/uwtools/tests/drivers/test_make_solo_mosaic.py b/src/uwtools/tests/drivers/test_make_solo_mosaic.py index 54ad6f5a6..20fa51699 100644 --- a/src/uwtools/tests/drivers/test_make_solo_mosaic.py +++ b/src/uwtools/tests/drivers/test_make_solo_mosaic.py @@ -4,10 +4,11 @@ """ from unittest.mock import patch -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.make_solo_mosaic import MakeSoloMosaic +from uwtools.exceptions import UWNotImplementedError # Fixtures @@ -56,6 +57,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", ], @@ -68,6 +70,12 @@ def test_MakeSoloMosaic_driver_name(driverobj): assert driverobj.driver_name() == MakeSoloMosaic.driver_name() == "make_solo_mosaic" +def test_MakeSoloMosaic_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_MakeSoloMosaic_provisioned_rundir(driverobj): with patch.object(driverobj, "runscript") as runscript: driverobj.provisioned_rundir() diff --git a/src/uwtools/tests/drivers/test_mpas.py b/src/uwtools/tests/drivers/test_mpas.py index d1a85ac23..ef225ef4b 100644 --- a/src/uwtools/tests/drivers/test_mpas.py +++ b/src/uwtools/tests/drivers/test_mpas.py @@ -12,10 +12,11 @@ import yaml from iotaa import refs from lxml import etree -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.mpas import MPAS from uwtools.drivers.mpas_base import MPASBase +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.tests.support import fixture_path, logged, regex_logged @@ -130,6 +131,7 @@ def driverobj(config, cycle): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "streams_file", @@ -225,6 +227,12 @@ def test_MPAS_namelist_file_missing_base_file(caplog, driverobj): assert regex_logged(caplog, "missing.nml: State: Not Ready (external asset)") +def test_MPAS_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_MPAS_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_mpas_init.py b/src/uwtools/tests/drivers/test_mpas_init.py index cac08798a..d785dd2b3 100644 --- a/src/uwtools/tests/drivers/test_mpas_init.py +++ b/src/uwtools/tests/drivers/test_mpas_init.py @@ -10,10 +10,11 @@ import f90nml # type: ignore from iotaa import refs -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.mpas_base import MPASBase from uwtools.drivers.mpas_init import MPASInit +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.tests.drivers.test_mpas import streams_file from uwtools.tests.support import fixture_path, logged, regex_logged @@ -112,6 +113,7 @@ def driverobj(config, cycle): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "streams_file", @@ -200,6 +202,12 @@ def test_MPASInit_namelist_file_missing_base_file(caplog, driverobj): assert regex_logged(caplog, "missing.nml: State: Not Ready (external asset)") +def test_MPASInit_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_MPASInit_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_orog.py b/src/uwtools/tests/drivers/test_orog.py index d4a231d56..699e4df94 100644 --- a/src/uwtools/tests/drivers/test_orog.py +++ b/src/uwtools/tests/drivers/test_orog.py @@ -7,10 +7,11 @@ from unittest.mock import DEFAULT as D from unittest.mock import patch -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.orog import Orog +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.scheduler import Slurm from uwtools.tests.support import regex_logged @@ -76,6 +77,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "taskname", ], @@ -147,6 +149,12 @@ def test_Orog_input_config_file_old(driverobj): assert content[4] == "none" +def test_Orog_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_Orog_provisioned_rundir(driverobj): with patch.multiple(driverobj, files_linked=D, input_config_file=D, runscript=D) as mocks: driverobj.provisioned_rundir() diff --git a/src/uwtools/tests/drivers/test_orog_gsl.py b/src/uwtools/tests/drivers/test_orog_gsl.py index 3fa2fc6ad..3d74e8505 100644 --- a/src/uwtools/tests/drivers/test_orog_gsl.py +++ b/src/uwtools/tests/drivers/test_orog_gsl.py @@ -6,10 +6,11 @@ from unittest.mock import DEFAULT as D from unittest.mock import patch -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.orog_gsl import OrogGSL +from uwtools.exceptions import UWNotImplementedError # Fixtures @@ -63,6 +64,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "taskname", @@ -93,6 +95,12 @@ def test_OrogGSL_input_grid_file(driverobj): assert path.is_symlink() +def test_OrogGSL_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_OrogGSL_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_sfc_climo_gen.py b/src/uwtools/tests/drivers/test_sfc_climo_gen.py index c5c9d8d21..6bd7b7281 100644 --- a/src/uwtools/tests/drivers/test_sfc_climo_gen.py +++ b/src/uwtools/tests/drivers/test_sfc_climo_gen.py @@ -9,11 +9,12 @@ import f90nml # type: ignore from iotaa import asset, external, refs -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers import sfc_climo_gen from uwtools.drivers.driver import Driver from uwtools.drivers.sfc_climo_gen import SfcClimoGen +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.tests.support import logged @@ -97,6 +98,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "taskname", @@ -131,6 +133,12 @@ def test_SfcClimoGen_namelist_file_fails_validation(caplog, driverobj): assert logged(caplog, " 'string' is not of type 'integer'") +def test_SfcClimoGen_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_SfcClimoGen_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_shave.py b/src/uwtools/tests/drivers/test_shave.py index 951594f32..71696c416 100644 --- a/src/uwtools/tests/drivers/test_shave.py +++ b/src/uwtools/tests/drivers/test_shave.py @@ -6,10 +6,11 @@ from unittest.mock import DEFAULT as D from unittest.mock import patch -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.shave import Shave +from uwtools.exceptions import UWNotImplementedError # Fixtures @@ -63,6 +64,7 @@ def driverobj(config): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", "taskname", @@ -91,6 +93,12 @@ def test_Shave_input_config_file(driverobj): assert content[0] == f"{nx} {ny} {nhalo} '{input_file_path}' '{output_file_path}'" +def test_Shave_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_Shave_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_support.py b/src/uwtools/tests/drivers/test_support.py index 05886c0ac..474382db0 100644 --- a/src/uwtools/tests/drivers/test_support.py +++ b/src/uwtools/tests/drivers/test_support.py @@ -73,6 +73,7 @@ def _validate(self, schema_file: Optional[Path] = None): assert support.tasks(SomeDriver) == { "run": "A run.", "runscript": "The runscript.", + "show_output": "Show the output to be created by this component.", "t1": "@external t1", "t2": "@task t2", "t3": "@tasks t3", diff --git a/src/uwtools/tests/drivers/test_ungrib.py b/src/uwtools/tests/drivers/test_ungrib.py index 9827483ae..0a12af8a0 100644 --- a/src/uwtools/tests/drivers/test_ungrib.py +++ b/src/uwtools/tests/drivers/test_ungrib.py @@ -7,11 +7,12 @@ from unittest.mock import patch import f90nml # type: ignore -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers import ungrib from uwtools.drivers.driver import Driver from uwtools.drivers.ungrib import Ungrib +from uwtools.exceptions import UWNotImplementedError # Fixtures @@ -69,6 +70,7 @@ def driverobj(config, cycle): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", ], @@ -106,6 +108,12 @@ def test_Ungrib_namelist_file(driverobj): assert nml["share"]["end_date"] == "2024-02-02_06:00:00" +def test_Ungrib_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_Ungrib_provisioned_rundir(driverobj): with patch.multiple( driverobj, diff --git a/src/uwtools/tests/drivers/test_upp.py b/src/uwtools/tests/drivers/test_upp.py index 1d869a5c4..c906ffbd4 100644 --- a/src/uwtools/tests/drivers/test_upp.py +++ b/src/uwtools/tests/drivers/test_upp.py @@ -10,10 +10,11 @@ import f90nml # type: ignore from iotaa import refs -from pytest import fixture, mark +from pytest import fixture, mark, raises from uwtools.drivers.driver import Driver from uwtools.drivers.upp import UPP +from uwtools.exceptions import UWNotImplementedError from uwtools.logging import log from uwtools.tests.support import logged, regex_logged @@ -89,6 +90,7 @@ def leadtime(): "_scheduler", "_validate", "_write_runscript", + "output", "run", "runscript", ], @@ -158,6 +160,12 @@ def test_UPP_namelist_file_missing_base_file(caplog, driverobj): assert regex_logged(caplog, "missing.nml: State: Not Ready (external asset)") +def test_UPP_output(driverobj): + with raises(UWNotImplementedError) as e: + assert driverobj.output + assert str(e.value) == "The output() method is not yet implemented for this driver" + + def test_UPP_provisioned_rundir(driverobj): with patch.multiple( driverobj,