Check 'parallel' type — validate both formats.
(self, body, errors, warnings, defined_vars, path)
| 327 | defined_vars.add(save_as) |
| 328 | |
| 329 | def _check_parallel(self, body, errors, warnings, defined_vars, path): |
| 330 | """Check 'parallel' type — validate both formats.""" |
| 331 | if isinstance(body, list): |
| 332 | # Format 1: list of inline steps — check for save_as misuse |
| 333 | for i, sub_step in enumerate(body): |
| 334 | if not isinstance(sub_step, dict): |
| 335 | continue |
| 336 | for step_type, step_body in sub_step.items(): |
| 337 | if isinstance(step_body, dict) and "save_as" in step_body: |
| 338 | errors.append( |
| 339 | f"{path}.parallel[{i}].{step_type}: 'save_as' inside parallel " |
| 340 | "inline steps does NOT propagate to outer context. The variable " |
| 341 | f"'{step_body['save_as']}' will be silently lost. Use sequential " |
| 342 | "task/step instead, or use gather with submodule files." |
| 343 | ) |
| 344 | # Still check inner steps for other issues |
| 345 | self._check_steps( |
| 346 | body, errors, warnings, defined_vars.copy(), f"{path}.parallel" |
| 347 | ) |
| 348 | elif isinstance(body, dict): |
| 349 | # Format 2: module + parameters_list (delegates to gather) |
| 350 | if "module" not in body: |
| 351 | errors.append( |
| 352 | f"{path}.parallel: dict format requires 'module' and 'parameters_list'" |
| 353 | ) |
| 354 | if "parameters_list" not in body: |
| 355 | errors.append( |
| 356 | f"{path}.parallel: dict format requires 'parameters_list'" |
| 357 | ) |
| 358 | save_results_as = body.get("save_results_as") |
| 359 | if save_results_as: |
| 360 | defined_vars.add(save_results_as) |
| 361 | else: |
| 362 | errors.append( |
| 363 | f"{path}.parallel: must be a list of steps or a dict with module+parameters_list" |
| 364 | ) |
| 365 | |
| 366 | def _check_gather(self, body, errors, warnings, defined_vars, path): |
| 367 | """Check 'gather' type — requires calls with module paths.""" |
nothing calls this directly
no test coverage detected