Skip to content

Commit

Permalink
Move testing infra code out of core
Browse files Browse the repository at this point in the history
  • Loading branch information
sameeul committed Jan 15, 2025
1 parent fff0da3 commit 3132544
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 74 deletions.
79 changes: 79 additions & 0 deletions .github/execute_python_workflows.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
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 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 = 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


if __name__ == "__main__":
blindly_execute_python_workflows()
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/ && python .github/execute_python_workflows.py

- 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/ && python .github/execute_python_workflows.py

# 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/ && python .github/execute_python_workflows.py

- 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/ && python .github/execute_python_workflows.py

- 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/ && python .github/execute_python_workflows.py

- 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/ && python .github/execute_python_workflows.py

- 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/ && python .github/execute_python_workflows.py

- 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/ && python .github/execute_python_workflows.py

- 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/ && python .github/execute_python_workflows.py

- 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/ && python .github/execute_python_workflows.py

- name: cwl-docker-extract (i.e. recursively docker pull)
if: always()
Expand Down
64 changes: 0 additions & 64 deletions src/sophios/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,67 +468,3 @@ 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

0 comments on commit 3132544

Please sign in to comment.