diff --git a/cylc/rose/platform_utils.py b/cylc/rose/platform_utils.py index c44c33b4..eef57631 100644 --- a/cylc/rose/platform_utils.py +++ b/cylc/rose/platform_utils.py @@ -19,9 +19,10 @@ """ from optparse import Values from pathlib import Path -from typing import Optional, Dict, Any +from typing import Dict, Any from cylc.flow.config import WorkflowConfig +from cylc.flow.exceptions import PlatformLookupError from cylc.flow.rundb import CylcWorkflowDAO from cylc.flow.workflow_files import parse_reg from cylc.flow.platforms import get_platform @@ -29,7 +30,7 @@ def get_platform_from_task_def( flow: str, task: str -) -> Optional[Dict[str, Any]]: +) -> Dict[str, Any]: """Return the platform dictionary for a particular task. Uses the flow definition - designed to be used with tasks @@ -42,17 +43,22 @@ def get_platform_from_task_def( Returns: Platform Dictionary. """ - flow_name, flow_file = parse_reg(flow, src=True) + _, flow_file = parse_reg(flow, src=True) config = WorkflowConfig(flow, flow_file, Values()) # Get entire task spec to allow Cylc 7 platform from host guessing. task_spec = config.pcfg.get(['runtime', task]) platform = get_platform(task_spec) + if platform is None: + raise PlatformLookupError( + 'Platform lookup failed; platform is a subshell to be evaluated: ' + f' Task: {task}, platform: {task_spec["platform"]}.' + ) return platform def get_platforms_from_task_jobs( flow: str, cyclepoint: str -) -> Optional[Dict[str, Any]]: +) -> Dict[str, Any]: """Access flow database. Return platform for task at fixed cycle point Uses the workflow database - designed to be used with tasks where jobs @@ -66,7 +72,7 @@ def get_platforms_from_task_jobs( Returns: Platform Dictionary. """ - flow_name, flow_file = parse_reg(flow, src=True) + _, flow_file = parse_reg(flow, src=True) dbfilepath = Path(flow_file).parent / '.service/db' dao = CylcWorkflowDAO(dbfilepath) task_platform_map: Dict = {} diff --git a/tests/test_platform_utils.py b/tests/test_platform_utils.py index fb6661c1..046c4d44 100644 --- a/tests/test_platform_utils.py +++ b/tests/test_platform_utils.py @@ -25,6 +25,7 @@ from shutil import rmtree from subprocess import run from uuid import uuid4 +from cylc.flow.exceptions import PlatformLookupError from cylc.rose.platform_utils import ( get_platform_from_task_def, @@ -125,6 +126,8 @@ def fake_flow(): [[qux]] [[[remote]]] host = cheese + [[kanga]] + platform = $(echo "myplatform") [[BAR]] platform = milk [[child_of_bar]] @@ -180,6 +183,20 @@ def test_get_platform_from_task_def( assert platform['name'] == expected_platform_n +def test_get_platform_from_task_def_raises( + mock_glbl_cfg, fake_flow +): + """Test getting platform from task definition. + + This is approaching an integration test, because + although it's only testing one unit of Cylc Rose, that unit + is calling lots of Cylc Parts, which aren't mocked. + """ + mock_glbl_cfg(*MOCK_GLBL_CFG) + with pytest.raises(PlatformLookupError, match='Platform lookup failed.*'): + get_platform_from_task_def(fake_flow[0], 'kanga') + + @pytest.mark.parametrize( 'task, cycle, expect', [