Skip to content

Commit 6d1a4e6

Browse files
Stellatsuualdbr
authored andcommitted
fix: added ExpressionTool and updated code
1 parent beaeefb commit 6d1a4e6

3 files changed

Lines changed: 61 additions & 60 deletions

File tree

pixi.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/dirac_cwl/submission_models.py

Lines changed: 28 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from typing import Any, Optional
1111

12-
from cwl_utils.parser import WorkflowStep, save
12+
from cwl_utils.parser import save
1313
from cwl_utils.parser.cwl_v1_2 import (
1414
CommandLineTool,
1515
ExpressionTool,
@@ -186,65 +186,38 @@ def validate_production(cls, values):
186186
# Temporary code, waiting on cwltool PR: https://github.com/common-workflow-language/cwltool/pull/2179.
187187

188188

189-
def validate_resource_requirements(task):
190-
"""
191-
Validate ResourceRequirements of a task (CommandLineTool, Workflow, WorkflowStep, WorkflowStep.run).
189+
def validate_resource_requirements(task: CommandLineTool | Workflow | ExpressionTool):
190+
"""Validate ResourceRequirements of a task recursively.
192191
193-
:param task: The task to validate
192+
:param task: The task to validate.
193+
:raises ValueError: If any ResourceRequirement has min > max.
194194
"""
195-
cwl_req = _get_resource_requirement(task)
196-
197-
# Validate Workflow/CLT requirements.
198-
if cwl_req:
199-
_validate_resource_requirement(cwl_req)
200-
201-
# Validate WorkflowStep requirements.
202-
if not isinstance(task, CommandLineTool) and task.steps:
203-
for step in task.steps:
204-
step_req = _get_resource_requirement(step)
205-
if step_req:
206-
_validate_resource_requirement(step_req)
207-
208-
# Validate run requirements for each step if they exist.
195+
# Validate task-level requirements
196+
for req in getattr(task, "requirements", None) or []:
197+
if isinstance(req, ResourceRequirement):
198+
_validate_min_max(req)
199+
200+
# Recurse into workflow steps
201+
if isinstance(task, Workflow):
202+
for step in task.steps or []:
203+
for req in getattr(step, "requirements", None) or []:
204+
if isinstance(req, ResourceRequirement):
205+
_validate_min_max(req)
209206
if step.run:
210-
if isinstance(step.run, Workflow):
211-
# Validate nested Workflow requirements, if any.
212-
validate_resource_requirements(task=step.run)
213-
214-
step_run_req = _get_resource_requirement(step.run)
215-
if step_run_req:
216-
_validate_resource_requirement(step_run_req)
217-
207+
validate_resource_requirements(step.run)
218208

219-
def _validate_resource_requirement(requirement):
220-
"""Validate a ResourceRequirement.
221209

222-
Verify that resourceMin is not higher than resourceMax (CommandLineTool, Workflow, WorkflowStep, WorkflowStep.run)
210+
def _validate_min_max(req: ResourceRequirement):
211+
"""Check that min does not exceed max for any resource.
223212
224-
:param requirement: The current ResourceRequirement to validate.
225-
:raises ValueError: If the requirement is invalid.
213+
:param req: The ResourceRequirement to validate.
214+
:raises ValueError: If min > max for any resource.
226215
"""
227-
for resource, min_value, max_value in [
228-
("ram", requirement.ramMin, requirement.ramMax),
229-
("cores", requirement.coresMin, requirement.coresMax),
230-
("tmpdir", requirement.tmpdirMin, requirement.tmpdirMax),
231-
("outdir", requirement.outdirMin, requirement.outdirMax),
216+
for name, lo, hi in [
217+
("cores", req.coresMin, req.coresMax),
218+
("ram", req.ramMin, req.ramMax),
219+
("tmpdir", req.tmpdirMin, req.tmpdirMax),
220+
("outdir", req.outdirMin, req.outdirMax),
232221
]:
233-
if min_value and max_value and min_value > max_value:
234-
raise ValueError(f"{resource}Min is higher than {resource}Max")
235-
236-
237-
def _get_resource_requirement(
238-
cwl_object: Workflow | CommandLineTool | WorkflowStep,
239-
) -> ResourceRequirement | None:
240-
"""
241-
Extract the resource requirement from the current cwl_object.
242-
243-
:param cwl_object: The cwl_object to extract the requirement from.
244-
:return: The resource requirement object, or None if not found.
245-
"""
246-
requirements = getattr(cwl_object, "requirements", []) or []
247-
for requirement in requirements:
248-
if isinstance(requirement, ResourceRequirement):
249-
return requirement
250-
return None
222+
if lo and hi and lo > hi:
223+
raise ValueError(f"{name}Min ({lo}) exceeds {name}Max ({hi})")

test/test_resource_requirements.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""Integration tests for CWL Resource Requirements validation."""
22

3-
from typing import List, Optional
3+
from typing import Optional
44

55
import pytest
6-
from cwl_utils.parser.cwl_v1_2 import CommandLineTool, ResourceRequirement, Workflow, WorkflowStep
6+
from cwl_utils.parser.cwl_v1_2 import CommandLineTool, ExpressionTool, ResourceRequirement, Workflow, WorkflowStep
77

88
from dirac_cwl.submission_models import JobSubmissionModel, ProductionSubmissionModel, TransformationSubmissionModel
99

@@ -27,7 +27,7 @@ def create_commandlinetool(
2727

2828
def create_workflow(
2929
requirements: Optional[list] = None,
30-
steps: Optional[List[WorkflowStep]] = None,
30+
steps: Optional[list[WorkflowStep]] = None,
3131
inputs: Optional[list] = None,
3232
outputs: Optional[list] = None,
3333
) -> Workflow:
@@ -55,6 +55,20 @@ def create_step(
5555
)
5656

5757

58+
def create_expressiontool(
59+
requirements: Optional[list] = None,
60+
inputs: Optional[list] = None,
61+
outputs: Optional[list] = None,
62+
) -> ExpressionTool:
63+
"""Create an ExpressionTool with the given requirements, inputs, and outputs."""
64+
return ExpressionTool(
65+
expression="",
66+
requirements=requirements or [],
67+
inputs=inputs or [],
68+
outputs=outputs or [],
69+
)
70+
71+
5872
def assert_submission_fails(task):
5973
"""Assert that submission fails with ValueError for Job and Transformation models with bad resource requirements.
6074
@@ -86,17 +100,30 @@ def test_bad_min_max_resource_reqs(bad_min_max_reqs):
86100
clt = create_commandlinetool(requirements=[bad_min_max_reqs])
87101
assert_submission_fails(clt)
88102

103+
# ExpressionTool with bad minmax reqs
104+
expression_tool = create_expressiontool(requirements=[bad_min_max_reqs])
105+
assert_submission_fails(expression_tool)
106+
89107
# WorkflowStep.run with bad minmax reqs
90108
step_bad_run = create_step(run=clt)
91109
workflow = create_workflow(steps=[step_bad_run])
92110
assert_submission_fails(workflow)
93111

112+
step_bad_run = create_step(run=expression_tool)
113+
workflow = create_workflow(steps=[step_bad_run])
114+
assert_submission_fails(workflow)
115+
94116
# WorkflowStep with bad minmax reqs
95117
clt = create_commandlinetool()
96118
step = create_step(run=clt, requirements=[bad_min_max_reqs])
97119
workflow = create_workflow(steps=[step])
98120
assert_submission_fails(workflow)
99121

122+
expression_tool = create_commandlinetool()
123+
step = create_step(run=expression_tool, requirements=[bad_min_max_reqs])
124+
workflow = create_workflow(steps=[step])
125+
assert_submission_fails(workflow)
126+
100127
# Workflow with bad minmax reqs
101128
workflow = create_workflow(requirements=[bad_min_max_reqs])
102129
assert_submission_fails(workflow)

0 commit comments

Comments
 (0)