Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/fuzzy_compile_weekly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ jobs:

- name: Generate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: Generate Sophios Validation Jsonschema
if: always()
Expand All @@ -108,7 +108,7 @@ jobs:
# WIC Python API workflows as well as the WIC Python API itself.
- name: Validate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

# Since a randomly chosen subschema is used every time, repeat 10X for more coverage.

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/lint_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ jobs:

- name: Generate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: Generate Sophios Validation Jsonschema
if: always()
Expand All @@ -190,7 +190,7 @@ jobs:
# Sophios Python API workflows as well as the Sophios Python API itself.
- name: Validate sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: Build Documentation
if: always()
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/lint_and_test_macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ jobs:

- name: Generate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: Generate Sophios Validation Jsonschema
if: always()
Expand All @@ -114,7 +114,7 @@ jobs:
# Sophios Python API workflows as well as the Sophios Python API itself.
- name: Validate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: Build Documentation
if: always()
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run_workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ jobs:

- name: Generate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: Generate Sophios Validation Jsonschema
if: always()
Expand All @@ -168,7 +168,7 @@ jobs:
# WIC Python API workflows as well as the WIC Python API itself.
- name: Validate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: cwl-docker-extract (i.e. recursively docker pull)
if: always()
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run_workflows_weekly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jobs:

- name: Generate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: Generate Sophios Validation Jsonschema
if: always()
Expand All @@ -131,7 +131,7 @@ jobs:
# Sophios Python API workflows as well as the WIC Python API itself.
- name: Validate Sophios Python API Workflows (*.py -> *.wic)
if: always()
run: cd sophios/ && python -c 'import sophios; import sophios.plugins; sophios.plugins.blindly_execute_python_workflows()'
run: cd sophios/ && pytest -k test_compile_python_workflows

- name: cwl-docker-extract (i.e. recursively docker pull)
if: always()
Expand Down
66 changes: 0 additions & 66 deletions src/sophios/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,69 +466,3 @@ def get_yml_paths(config: Json) -> Dict[str, Dict[str, Path]]:

def get_py_paths(config: Json) -> Dict[str, Dict[str, Path]]:
return get_workflow_paths(config, 'py')


def blindly_execute_python_workflows() -> None:
"""This function imports (read: blindly executes) all python files in 'search_paths_wic'
The python files are assumed to have a top-level workflow() function
which returns a sophios.api.pythonapi.Workflow object.
The python files should NOT call the .run() method!
(from any code path that is automatically executed on import)
"""
# I hope u like Remote Code Execution vulnerabilities!
# See https://en.wikipedia.org/wiki/Arithmetical_hierarchy
from sophios.api import pythonapi # pylint: disable=C0415:import-outside-toplevel
# Since this is completely different test path we have to copy
# default .txt files to default global_config.json
config_file = Path().home()/'wic'/'global_config.json'
global_config = io.read_config_from_disk(config_file)
pythonapi.global_config = get_tools_cwl(global_config) # Use path fallback in the CI
paths = get_py_paths(global_config)
# Above we are assuming that config is default
paths_tuples = [(path_str, path)
for namespace, paths_dict in paths.items()
for path_str, path in paths_dict.items()]
any_import_errors = False
for path_stem, path in paths_tuples:
if 'mm-workflows' in str(path) or 'docs/tutorials/' in str(path):
# Exclude paths that only contain 'regular' python files.
continue
# NOTE: Use anything (unique?) for the python_module_name.
try:
module = import_python_file(path_stem, path)
# Let's require all python API files to define a function, say
# def workflow() -> Workflow
# so we can programmatically call it here:
retval: pythonapi.Workflow = module.workflow() # no arguments
# which allows us to programmatically call Workflow methods:
compiler_info = retval.compile() # hopefully retval is actually a Workflow object!
# But since this is python (i.e. not Haskell) that in no way eliminates
# the above security considerations.

# This lets us use path.parent to write a *.wic file in the
# auto-discovery path, and thus reuse the existing wic CI
retval.write_ast_to_disk(path.parent)

# Programmatically blacklist subworkflows from running in config_ci.json
# (Again, because subworkflows are missing inputs and cannot run.)
config_ci = path.parent / 'config_ci.json'
json_contents = {}
if config_ci.exists():
with open(config_ci, mode='r', encoding='utf-8') as r:
json_contents = json.load(r)
run_blacklist: list[str] = json_contents.get('run_blacklist', [])
# Use [1:] for proper subworkflows only
subworkflows: list[pythonapi.Workflow] = retval.flatten_subworkflows()[1:]
run_blacklist += [wf.process_name for wf in subworkflows]
json_contents['run_blacklist'] = run_blacklist
with open(config_ci, mode='w', encoding='utf-8') as f:
json.dump(json_contents, f)

except Exception as e:
any_import_errors = True
if sys.version_info >= (3, 10):
traceback.print_exception(type(e), value=e, tb=None)
else:
traceback.print_exception(etype=type(e), value=e, tb=None)
if any_import_errors:
sys.exit(1) # Make sure the CI fails
73 changes: 73 additions & 0 deletions tests/test_compile_python_workflows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import json
import sys
import traceback
from pathlib import Path

import sophios
import sophios.plugins
from sophios import input_output as io
from sophios.python_cwl_adapter import import_python_file


def test_compile_python_workflows() -> None:
"""This function imports (read: blindly executes) all python files in 'search_paths_wic'
The python files are assumed to have a top-level workflow() function
which returns a sophios.api.pythonapi.Workflow object.
The python files should NOT call the .run() method!
(from any code path that is automatically executed on import)
"""
from sophios.api import pythonapi # pylint: disable=C0415:import-outside-toplevel
# Since this is completely different test path we have to copy
# default .txt files to default global_config.json
config_file = Path().home()/'wic'/'global_config.json'
global_config = io.read_config_from_disk(config_file)
pythonapi.global_config = sophios.plugins.get_tools_cwl(global_config) # Use path fallback in the CI
paths = sophios.plugins.get_py_paths(global_config)
# Above we are assuming that config is default
paths_tuples = [(path_str, path)
for namespace, paths_dict in paths.items()
for path_str, path in paths_dict.items()]
any_import_errors = False
for path_stem, path in paths_tuples:
if 'mm-workflows' in str(path) or 'docs/tutorials/' in str(path):
# Exclude paths that only contain 'regular' python files.
continue
# NOTE: Use anything (unique?) for the python_module_name.
try:
module = import_python_file(path_stem, path)
# Let's require all python API files to define a function, say
# def workflow() -> Workflow
# so we can programmatically call it here:
retval: pythonapi.Workflow = module.workflow() # no arguments
# which allows us to programmatically call Workflow methods:
compiler_info = retval.compile() # hopefully retval is actually a Workflow object!
# But since this is python (i.e. not Haskell) that in no way eliminates
# the above security considerations.

# This lets us use path.parent to write a *.wic file in the
# auto-discovery path, and thus reuse the existing wic CI
retval.write_ast_to_disk(path.parent)

# Programmatically blacklist subworkflows from running in config_ci.json
# (Again, because subworkflows are missing inputs and cannot run.)
config_ci = path.parent / 'config_ci.json'
json_contents = {}
if config_ci.exists():
with open(config_ci, mode='r', encoding='utf-8') as r:
json_contents = json.load(r)
run_blacklist: list[str] = json_contents.get('run_blacklist', [])
# Use [1:] for proper subworkflows only
subworkflows: list[pythonapi.Workflow] = retval.flatten_subworkflows()[1:]
run_blacklist += [wf.process_name for wf in subworkflows]
json_contents['run_blacklist'] = run_blacklist
with open(config_ci, mode='w', encoding='utf-8') as f:
json.dump(json_contents, f)

except Exception as e:
any_import_errors = True
if sys.version_info >= (3, 10):
traceback.print_exception(type(e), value=e, tb=None)
else:
traceback.print_exception(etype=type(e), value=e, tb=None)
if any_import_errors:
sys.exit(1) # Make sure the CI fails
Loading