Skip to content

Commit 3240f01

Browse files
vjaganat90Vasu Jaganath
andauthored
remove args from core sophios 3/3 (#355)
Co-authored-by: Vasu Jaganath <[email protected]>
1 parent 6907bff commit 3240f01

File tree

9 files changed

+123
-84
lines changed

9 files changed

+123
-84
lines changed

src/sophios/apis/python/api.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from sophios import compiler, input_output, plugins, utils_cwl
1616
from sophios import run_local as rl
1717
from sophios import post_compile as pc
18-
from sophios.cli import get_args, get_known_and_unknown_args
18+
from sophios.cli import get_known_and_unknown_args, get_dicts_for_compilation
1919
from sophios.utils_graphs import get_graph_reps
2020
from sophios.utils import convert_args_dict_to_args_list
2121
from sophios.wic_types import CompilerInfo, RoseTree, StepId, Tool, Tools, YamlTree, Json
@@ -711,7 +711,6 @@ def compile(self, write_to_disk: bool = False) -> CompilerInfo:
711711
"""
712712
global global_config
713713
self._validate()
714-
args = get_args(self.process_name) # Use mock CLI args
715714

716715
graph = get_graph_reps(self.process_name)
717716
yaml_tree = YamlTree(StepId(self.process_name, 'global'), self.yaml)
@@ -720,14 +719,17 @@ def compile(self, write_to_disk: bool = False) -> CompilerInfo:
720719
steps_config = extract_tools_paths_NONPORTABLE(self.flatten_steps())
721720
global_config = merge(steps_config, global_config, strategy=Strategy.TYPESAFE_REPLACE)
722721

722+
compiler_options, graph_settings, yaml_tag_paths = get_dicts_for_compilation()
723+
723724
# The compile_workflow function is 100% in-memory
724-
compiler_info = compiler.compile_workflow(yaml_tree, args, [], [graph], {}, {}, {}, {},
725+
compiler_info = compiler.compile_workflow(yaml_tree, compiler_options, graph_settings, yaml_tag_paths,
726+
[], [graph], {}, {}, {}, {},
725727
global_config, True, relative_run_path=True, testing=False)
726728

727729
if write_to_disk:
728730
# Now we can choose whether to write_to_disk or not
729731
rose_tree: RoseTree = compiler_info.rose
730-
input_output.write_to_disk(rose_tree, Path('autogenerated/'), True, args.inputs_file)
732+
input_output.write_to_disk(rose_tree, Path('autogenerated/'), True)
731733

732734
return compiler_info
733735

src/sophios/apis/rest/api.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from sophios.utils_yaml import wic_loader
1414
from sophios import utils_cwl
1515
from sophios.post_compile import cwl_inline_runtag
16-
from sophios.cli import get_args
16+
from sophios.cli import get_args, get_dicts_for_compilation
1717
from sophios.wic_types import CompilerInfo, Json, Tool, Tools, StepId, YamlTree, Cwl, NodeData
1818
from sophios.apis.utils import converter
1919
import sophios.plugins as plugins
@@ -111,8 +111,11 @@ async def compile_wf(request: Request) -> Json:
111111
graph = get_graph_reps(wkflw_name)
112112
yaml_tree: YamlTree = YamlTree(StepId(wkflw_name, plugin_ns), workflow_can)
113113

114+
compiler_options, graph_settings, yaml_tag_paths = get_dicts_for_compilation()
115+
114116
# ========= COMPILE WORKFLOW ================
115-
compiler_info: CompilerInfo = compiler.compile_workflow(yaml_tree, args, [], [graph], {}, {}, {}, {},
117+
compiler_info: CompilerInfo = compiler.compile_workflow(yaml_tree, compiler_options, graph_settings, yaml_tag_paths,
118+
[], [graph], {}, {}, {}, {},
116119
tools_cwl, True, relative_run_path=True, testing=False)
117120

118121
rose_tree = compiler_info.rose

src/sophios/cli.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import argparse
22
import sys
33
from pathlib import Path
4-
from typing import List, Tuple
4+
from typing import List, Tuple, Dict, Any
55
from unittest.mock import patch
66

77
from . import _version
@@ -153,3 +153,36 @@ def get_known_and_unknown_args(yaml_path: str = '', suppliedargs: list[str] = []
153153
with patch.object(sys, 'argv', testargs):
154154
known_args, unknown_args = parser.parse_known_args()
155155
return known_args, unknown_args
156+
157+
158+
def get_dicts_for_compilation() -> Tuple[Dict[str, bool], Dict[str, Any], Dict[str, str]]:
159+
"""This is used to get default command line arguments for compilation
160+
as a tuple of three dictionaries
161+
162+
Returns:
163+
Tuple[Dict[str, bool], Dict[str,Any], Dict[str, str]]: The mocked command line arguments
164+
"""
165+
args = get_args()
166+
# core compiler options for transformation into CWL
167+
compiler_options: Dict[str, bool] = {}
168+
compiler_options['partial_failure_enable'] = args.partial_failure_enable
169+
compiler_options['inference_use_naming_conventions'] = args.inference_use_naming_conventions
170+
compiler_options['insert_steps_automatically'] = args.insert_steps_automatically
171+
compiler_options['inference_disable'] = args.inference_disable
172+
compiler_options['allow_raw_cwl'] = args.allow_raw_cwl
173+
174+
# to be given to graph util functions
175+
graph_settings: Dict[str, Any] = {}
176+
graph_settings['graph_dark_theme'] = args.graph_dark_theme
177+
graph_settings['graph_inline_depth'] = args.graph_inline_depth
178+
graph_settings['graph_label_edges'] = args.graph_label_edges
179+
graph_settings['graph_label_stepname'] = args.graph_label_stepname
180+
graph_settings['graph_show_outputs'] = args.graph_show_outputs
181+
graph_settings['graph_show_inputs'] = args.graph_show_inputs
182+
183+
# to be given to io absolute_yaml_tags function
184+
yaml_tag_paths: Dict[str, str] = {}
185+
yaml_tag_paths['cachedir'] = args.cachedir
186+
yaml_tag_paths['yaml'] = args.yaml
187+
yaml_tag_paths['homedir'] = args.homedir
188+
return (compiler_options, graph_settings, yaml_tag_paths)

src/sophios/compiler.py

Lines changed: 36 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import argparse
21
import copy
32
import json
43
import os
@@ -11,7 +10,6 @@
1110
import networkx as nx
1211
import yaml
1312

14-
1513
from . import input_output as io
1614
from . import inference, utils, utils_cwl, utils_graphs
1715
from .wic_types import (CompilerInfo, EnvData, ExplicitEdgeCalls,
@@ -24,7 +22,9 @@
2422

2523

2624
def compile_workflow(yaml_tree_ast: YamlTree,
27-
args: argparse.Namespace,
25+
compiler_options: Dict[str, bool],
26+
graph_settings: Dict[str, Any],
27+
yaml_tag_paths: Dict[str, str],
2828
namespaces: Namespaces,
2929
subgraphs_: List[GraphReps],
3030
explicit_edge_defs: ExplicitEdgeDefs,
@@ -40,7 +40,9 @@ def compile_workflow(yaml_tree_ast: YamlTree,
4040
4141
Args:
4242
yaml_tree_ast (YamlTree): A tuple of name and yml AST
43-
args (Any): all of the other positional arguments for compile_workflow_once
43+
compiler_options (Dict[str, bool]): The core flags needed for compilation and transformation into CWL
44+
graph_settings (Dict[str, Any]): The settings dict for graphpviz graphs
45+
yaml_tag_paths (Dict[str,str]): The paths that need to be included in (generated) yaml tags
4446
kwargs (Any): all of the other keyword arguments for compile_workflow_once
4547
4648
Returns:
@@ -58,8 +60,8 @@ def compile_workflow(yaml_tree_ast: YamlTree,
5860
i = 0
5961
while ast_modified and i < max_iters:
6062
subgraphs = copy.deepcopy(subgraphs_) # See comment below!
61-
compiler_info = compile_workflow_once(yaml_tree, args, namespaces, subgraphs,
62-
explicit_edge_defs, explicit_edge_calls,
63+
compiler_info = compile_workflow_once(yaml_tree, compiler_options, graph_settings, yaml_tag_paths,
64+
namespaces, subgraphs, explicit_edge_defs, explicit_edge_calls,
6365
input_mapping, output_mapping,
6466
tools, is_root, relative_run_path, testing)
6567
node_data: NodeData = compiler_info.rose.data
@@ -95,14 +97,15 @@ def compile_workflow(yaml_tree_ast: YamlTree,
9597
subgraph_.networkx.update(subgraphs[i].networkx.edges, subgraphs[i].networkx.nodes)
9698

9799
if i == max_iters:
98-
import yaml
99100
print(yaml.dump(node_data.yml))
100101
raise Exception(f'Error! Maximum number of iterations ({max_iters}) reached in compile_workflow!')
101102
return compiler_info
102103

103104

104105
def compile_workflow_once(yaml_tree_ast: YamlTree,
105-
args: argparse.Namespace,
106+
compiler_options: Dict[str, bool],
107+
graph_settings: Dict[str, Any],
108+
yaml_tag_paths: Dict[str, str],
106109
namespaces: Namespaces,
107110
subgraphs: List[GraphReps],
108111
explicit_edge_defs: ExplicitEdgeDefs,
@@ -118,7 +121,9 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
118121
119122
Args:
120123
yaml_tree_ast (YamlTree): A tuple of name and yml AST
121-
args (argparse.Namespace): The command line arguments
124+
graph_settings (Dict[str, Any]): The settings dict for graphpviz graphs
125+
yaml_tag_paths (Dict[str,str]): The paths that need to be included in (generated) yaml tags
126+
compiler_options (Dict[str, bool]): The core flags needed for compilation and transformation into CWL
122127
namespaces (Namespaces): Specifies the path in the yml AST to the current subworkflow
123128
subgraphs (List[Graph]): The graphs associated with the parent workflows of the current subworkflow
124129
explicit_edge_defs (ExplicitEdgeDefs): Stores the (path, value) of the explicit edge definition sites
@@ -209,19 +214,6 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
209214

210215
tools_lst: List[Tool] = []
211216

212-
# to be given to graph util functions
213-
graph_settings = {}
214-
graph_settings['graph_dark_theme'] = args.graph_dark_theme
215-
graph_settings['graph_inline_depth'] = args.graph_inline_depth
216-
graph_settings['graph_label_edges'] = args.graph_label_edges
217-
graph_settings['graph_show_outputs'] = args.graph_show_outputs
218-
219-
# to be gieven io absolute_yaml_tags function
220-
yaml_tag_paths: Dict[str, str] = {}
221-
yaml_tag_paths['cachedir'] = args.cachedir
222-
yaml_tag_paths['yaml'] = args.yaml
223-
yaml_tag_paths['homedir'] = args.homedir
224-
225217
for i, step_key in enumerate(steps_keys):
226218
step_name_i = utils.step_name_str(yaml_stem, i, step_key)
227219
stem = Path(step_key).stem
@@ -254,9 +246,9 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
254246
graphdata = GraphData(step_key)
255247
subgraph = GraphReps(subgraph_gv, subgraph_nx, graphdata)
256248

257-
sub_compiler_info = compile_workflow(sub_yaml_tree, args, namespaces + [step_name_or_key],
258-
subgraphs + [subgraph], explicit_edge_defs_copy,
259-
explicit_edge_calls_copy,
249+
sub_compiler_info = compile_workflow(sub_yaml_tree, compiler_options, graph_settings, yaml_tag_paths,
250+
namespaces + [step_name_or_key], subgraphs + [subgraph],
251+
explicit_edge_defs_copy, explicit_edge_calls_copy,
260252
input_mapping_copy, output_mapping_copy,
261253
tools, False, relative_run_path, testing)
262254

@@ -340,14 +332,6 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
340332
rose_tree_list.append(rose_tree_base_case)
341333
tools_lst.append(tool_i)
342334

343-
if not testing:
344-
# Disable for testing because when testing in parallel, the *.gv Graphviz files
345-
# can be written/read to/from disk simultaneously, which results in
346-
# intermittent 'syntax errors'.
347-
pass
348-
# Actually, this is a significant performance bottleneck and isn't really necessary.
349-
# utils_graphs.make_tool_dag(stem, tool_i, args.graph_dark_theme)
350-
351335
# Add run tag, using relative or flat-directory paths
352336
# NOTE: run: path issues were causing test_cwl_embedding_independence()
353337
# to fail, so I simply ignore the run tag in that test.
@@ -419,13 +403,11 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
419403
# (Solution: refactor all required arguments out of config and list
420404
# them as explicit inputs in the cwl files, then modify the python
421405
# files accordingly.)
422-
# print(args_required)
423406

424407
sub_args_provided = [arg for arg in args_required if arg in explicit_edge_calls_copy]
425-
# print(sub_args_provided)
426408

427409
label = step_key
428-
if args.graph_label_stepname:
410+
if graph_settings['graph_label_stepname']:
429411
label = step_name_or_key
430412
step_node_name = '___'.join(namespaces + [step_name_or_key])
431413

@@ -439,11 +421,11 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
439421
graph_gv.node(step_node_name, **attrs)
440422
graph_nx.add_node(step_node_name)
441423
graphdata.nodes.append((step_node_name, attrs))
442-
elif not (step_key in subkeys and len(namespaces) < args.graph_inline_depth):
424+
elif not (step_key in subkeys and len(namespaces) < graph_settings['graph_inline_depth']):
443425
nssnode = namespaces + [step_name_or_key]
444426
# Just like in add_graph_edge(), here we can hide all of the details
445427
# below a given depth by simply truncating the node's namespaces.
446-
nssnode = nssnode[:(1 + args.graph_inline_depth)]
428+
nssnode = nssnode[:(1 + graph_settings['graph_inline_depth'])]
447429
step_node_name = '___'.join(nssnode)
448430
# NOTE: NOT wic_graphviz_step_i
449431
# get the label (if any) from the subworkflow
@@ -633,11 +615,11 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
633615
new_val = {'source': in_name}
634616
steps[i]['in'][arg_key] = new_val
635617

636-
if args.graph_show_inputs:
618+
if graph_settings['graph_show_inputs']:
637619
input_node_name = '___'.join(namespaces + [step_name_or_key, arg_key])
638620
attrs = {'label': arg_key, 'shape': 'box', 'style': 'rounded, filled', 'fillcolor': 'lightgreen'}
639621
graph_gv.node(input_node_name, **attrs)
640-
font_edge_color = 'black' if args.graph_dark_theme else 'white'
622+
font_edge_color = 'black' if graph_settings['graph_dark_theme'] else 'white'
641623
graph_gv.edge(input_node_name, step_node_name, color=font_edge_color)
642624
graph_nx.add_node(input_node_name)
643625
graph_nx.add_edge(input_node_name, step_node_name)
@@ -668,18 +650,10 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
668650
except Exception:
669651
pass
670652

671-
if not args.allow_raw_cwl and (not hashable or arg_var not in yaml_tree.get('inputs', {})):
672-
if not args.allow_raw_cwl:
673-
print(f"Warning! Did you forget to use !ii before {arg_var} in {yaml_stem}.wic?")
674-
print('If you want to compile the workflow anyway, use --allow_raw_cwl')
675-
sys.exit(1)
676-
677-
inputs = yaml_tree.get('inputs', {})
678-
unbound_lit_var = 'Error! Unbound literal variable'
679-
if inputs == {}:
680-
raise Exception(f"{unbound_lit_var}{arg_var} not in inputs: tag in {yaml_stem}.wic")
681-
inputs_dump = yaml.dump({'inputs': inputs})
682-
raise Exception(f"{unbound_lit_var}{arg_var} not in\n{inputs_dump}\nin {yaml_stem}.wic")
653+
if not compiler_options['allow_raw_cwl'] and (not hashable or arg_var not in yaml_tree.get('inputs', {})):
654+
print(f"Warning! Did you forget to use !ii before {arg_var} in {yaml_stem}.wic?")
655+
print('If you want to compile the workflow anyway, use --allow_raw_cwl')
656+
sys.exit(1)
683657

684658
if 'doc' in inputs_key_dict:
685659
inputs_key_dict['doc'] += '\\n' + in_dict.get('doc', '')
@@ -757,22 +731,24 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
757731
# NOTE: We already added an edge to the appropriate subgraph above.
758732
# TODO: vars_workflow_output_internal?
759733
else:
760-
if args.inference_disable:
734+
if compiler_options['inference_disable']:
761735
continue
762736
insertions: List[StepId] = []
763737
in_name_in_inputs_file_workflow: bool = (in_name in inputs_file_workflow)
764738
arg_key_in_yaml_tree_inputs: bool = (arg_key in yaml_tree.get('inputs', {}))
765-
inference_use_naming_conventions = args.inference_use_naming_conventions
766-
steps[i] = inference.perform_edge_inference(inference_use_naming_conventions, graph_settings, tools, tools_lst, steps_keys,
767-
yaml_stem, i, steps, arg_key, graph, is_root, namespaces,
768-
vars_workflow_output_internal, input_mapping_copy, output_mapping_copy, inputs_workflow, in_name,
769-
in_name_in_inputs_file_workflow, arg_key_in_yaml_tree_inputs, insertions, wic_steps, testing)
739+
steps[i] = inference.perform_edge_inference(compiler_options['inference_use_naming_conventions'],
740+
graph_settings, tools, tools_lst, steps_keys,
741+
yaml_stem, i, steps, arg_key, graph,
742+
is_root, namespaces, vars_workflow_output_internal,
743+
input_mapping_copy, output_mapping_copy, inputs_workflow,
744+
in_name, in_name_in_inputs_file_workflow,
745+
arg_key_in_yaml_tree_inputs, insertions, wic_steps, testing)
770746
# NOTE: For now, perform_edge_inference mutably appends to
771747
# inputs_workflow and vars_workflow_output_internal.
772748

773749
# Automatically insert steps
774750
insertions = list(set(insertions)) # Remove duplicates
775-
if len(insertions) != 0 and args.insert_steps_automatically:
751+
if len(insertions) != 0 and compiler_options['insert_steps_automatically']:
776752
insertion = insertions[0]
777753
print('Automaticaly inserting step', insertion, i)
778754
if len(insertions) != 1:
@@ -802,7 +778,7 @@ def compile_workflow_once(yaml_tree_ast: YamlTree,
802778

803779
steps[i] = utils_cwl.add_yamldict_keyval_out(steps[i], step_key, list(tool_i.cwl['outputs'].keys()))
804780

805-
if args.partial_failure_enable:
781+
if compiler_options['partial_failure_enable']:
806782
when_null_clauses = []
807783
for arg_in in args_required:
808784
when_null_clauses.append(f'inputs["{arg_in}"] != null')

src/sophios/cwl_subinterpreter.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,17 @@ def rerun_cwltool(homedir: str, _directory_realtime: Path, cachedir_path: Path,
109109

110110
# Setup dummy args
111111
args = cli.get_args()
112+
compiler_options, graph_settings, yaml_tag_paths = cli.get_dicts_for_compilation()
112113

113114
# TODO: Support other namespaces
114115
plugin_ns = 'global' # wic['wic'].get('namespace', 'global')
115116
yaml_path = f'{cwl_tool}_only.wic'
116117
stepid = StepId(yaml_path, plugin_ns)
117118
yaml_tree = YamlTree(stepid, yml)
118119
subgraph = GraphReps(graphviz.Digraph(name=yaml_path), nx.DiGraph(), GraphData(yaml_path))
119-
compiler_info = compiler.compile_workflow(yaml_tree, args, [], [subgraph], {}, {}, {}, {},
120+
121+
compiler_info = compiler.compile_workflow(yaml_tree, compiler_options, graph_settings, yaml_tag_paths,
122+
[], [subgraph], {}, {}, {}, {},
120123
tools_cwl, True, relative_run_path=False, testing=False)
121124
rose_tree = compiler_info.rose
122125
working_dir = Path('.') / Path('autogenerated/') # Use a new working directory.

0 commit comments

Comments
 (0)