Skip to content

Commit 6c29146

Browse files
VassilisVassiliadisGitHub Enterprise
authored and
GitHub Enterprise
committed
fix: fix DSL lightweight validation logic (#323)
* fix: no IndexError exception when detecting parameters with no default values * fix: detect components with no executable or interpreter during light tests Resolves https://github.ibm.com/st4sd/st4sd-runtime-core/issues/322 Signed-off-by: Vassilis Vassiladis <[email protected]>
1 parent fa992f7 commit 6c29146

File tree

2 files changed

+128
-6
lines changed

2 files changed

+128
-6
lines changed

python/experiment/model/frontends/dsl.py

+27-6
Original file line numberDiff line numberDiff line change
@@ -1322,12 +1322,17 @@ def enter(
13221322
template_location=template_location,
13231323
)
13241324

1325-
for p in template.signature.parameters:
1325+
for i in range(len(template.signature.parameters)):
1326+
p = template.signature.parameters[i] # VV: type hints ...
1327+
13261328
if p.name in parameters:
13271329
continue
13281330
if "default" not in p.model_fields_set:
1329-
errors.append(ValueError(f"The parameter {p.name} in location {'/'.join(location)} "
1330-
f"does not have a value or default"))
1331+
errors.append(experiment.model.errors.DSLInvalidFieldError(
1332+
scope_entry.dsl_location() + ["signature", "parameters", i],
1333+
ValueError(f"The parameter {p.name} in location {'/'.join(location)} does not have a value or default")
1334+
))
1335+
13311336
if errors:
13321337
dsl_error = experiment.model.errors.DSLInvalidError([])
13331338
for e in errors:
@@ -2490,8 +2495,8 @@ def no_param_refs_in_parameter_defaults(
24902495
) -> typing.List[experiment.model.errors.DSLInvalidFieldError]:
24912496
errors = []
24922497

2493-
for idx in range(len(template.signature.parameters)):
2494-
param = comp.signature.parameters[idx]
2498+
for i in range(len(template.signature.parameters)):
2499+
param = template.signature.parameters[i]
24952500

24962501
if not param.default:
24972502
continue
@@ -2501,7 +2506,7 @@ def no_param_refs_in_parameter_defaults(
25012506
for r in refs:
25022507
errors.append(
25032508
experiment.model.errors.DSLInvalidFieldError(
2504-
location=location + ["signature", "parameters", idx, "default"],
2509+
location=location + ["signature", "parameters", i, "default"],
25052510
underlying_error=ValueError(
25062511
f'Reference to parameter/variable "{r}"'
25072512
)
@@ -2510,6 +2515,21 @@ def no_param_refs_in_parameter_defaults(
25102515

25112516
return errors
25122517

2518+
def detect_missing_fields(
2519+
comp: Component,
2520+
index: int
2521+
) -> typing.List[experiment.model.errors.DSLInvalidFieldError]:
2522+
comp_location = ["components", index]
2523+
errors = []
2524+
2525+
if not comp.command.executable and not comp.command.interpreter:
2526+
errors.append(experiment.model.errors.DSLInvalidFieldError(
2527+
comp_location + ["command"],
2528+
ValueError("The component does not specify command.executable or command.interpreter"))
2529+
)
2530+
2531+
return errors
2532+
25132533
def detect_unknown_variables(
25142534
comp: Component,
25152535
index: int
@@ -2587,6 +2607,7 @@ class Field:
25872607
# VV: enumerate messes up typehints
25882608
comp = namespace.components[idx]
25892609
errors_acc.extend(detect_unknown_variables(comp, idx))
2610+
errors_acc.extend(detect_missing_fields(comp, idx))
25902611

25912612
for idx in range(len(namespace.workflows)):
25922613
# VV: enumerate messes up typehints

tests/test_dsl.py

+101
Original file line numberDiff line numberDiff line change
@@ -1362,4 +1362,105 @@ def test_lightweight_validation_parameter_referencing_variable():
13621362
"loc": ["components", 0, "signature", "parameters", 0, "default"],
13631363
"msg": 'Reference to parameter/variable "something"'
13641364
}
1365+
]
1366+
1367+
1368+
def test_lightweight_validation_missing_exec():
1369+
dsl = yaml.safe_load("""
1370+
components:
1371+
- signature:
1372+
name: normalize
1373+
parameters:
1374+
- name: input
1375+
- name: parameter
1376+
- command:
1377+
arguments: serious science stuff here
1378+
executable: echo
1379+
signature:
1380+
name: simulation-a
1381+
parameters:
1382+
- name: data
1383+
- command:
1384+
arguments: '%(input)s'
1385+
executable: echo
1386+
signature:
1387+
description: null
1388+
name: simulation-b
1389+
parameters:
1390+
- name: input
1391+
entrypoint:
1392+
entry-instance: simulate-and-report
1393+
execute:
1394+
- args: {}
1395+
target: <entry-instance>
1396+
workflows:
1397+
- execute:
1398+
- args:
1399+
data: '%(some-data)s'
1400+
target: <simulation>
1401+
- args:
1402+
input: <simulation/second-stage>:ref
1403+
some-parameter: '%(some-parameter)s'
1404+
target: <analysis>
1405+
signature:
1406+
description: You can type text here to help other people use your workflow. For
1407+
example you can explain what kind of inputs it expects, where people can go
1408+
to find more information about this etc.
1409+
name: simulate-and-report
1410+
parameters:
1411+
- name: some-data
1412+
- name: some-parameter
1413+
steps:
1414+
analysis: analysis
1415+
simulation: simulation
1416+
- execute:
1417+
- args:
1418+
input: '%(input)s'
1419+
parameter: '%(some-parameter)s'
1420+
target: <normalize>
1421+
signature:
1422+
description: null
1423+
name: analysis
1424+
parameters:
1425+
- name: input
1426+
- name: some-parameter
1427+
steps:
1428+
normalize: normalize
1429+
- execute:
1430+
- args:
1431+
data: '%(data)s'
1432+
target: <first-stage>
1433+
- args:
1434+
input: <first-stage>:ref
1435+
target: <second-stage>
1436+
signature:
1437+
description: null
1438+
name: simulation
1439+
parameters:
1440+
- name: data
1441+
steps:
1442+
first-stage: simulation-a
1443+
second-stage: simulation-b
1444+
""")
1445+
1446+
namespace = experiment.model.frontends.dsl.Namespace(**dsl)
1447+
1448+
with pytest.raises(experiment.model.errors.DSLInvalidError) as e:
1449+
experiment.model.frontends.dsl.lightweight_validate(namespace)
1450+
1451+
errors = e.value.errors()
1452+
1453+
assert errors == [
1454+
{
1455+
"loc": ["components", 0, "command"],
1456+
"msg": 'The component does not specify command.executable or command.interpreter'
1457+
},
1458+
{
1459+
"loc": ["workflows", 0, "signature", "parameters", 0],
1460+
"msg": 'The parameter some-data in location entry-instance does not have a value or default'
1461+
},
1462+
{
1463+
"loc": ["workflows", 0, "signature", "parameters", 1],
1464+
"msg": 'The parameter some-parameter in location entry-instance does not have a value or default'
1465+
}
13651466
]

0 commit comments

Comments
 (0)