Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the initial GitHub Action #20

Merged
merged 6 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
40 changes: 40 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Build and test

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build-and-test:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.10']
outputs:
version: ${{ steps.get_version.outputs.version }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker
uses: docker/setup-buildx-action@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install poetry
poetry install
- name: Test with pytest
run: |
poetry run pytest
- name: Build the package
run: |
poetry build
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,6 @@ dmypy.json
tests/data/benchmarks.json
tests/data/workflow.cwl_output/*
src/workflomics_benchmarker/to_implement.py
tests/data/workflow_output/*
tests/data/workflow_fail_output/*
tests/data/workflow_fail2_output/*
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ python src/benchmarker/workflomics.py benchmark tests/data/ --singularity
Run the following command to execute tests:

```bash
poetry run pytest -s
poetry run pytest
```

This command runs a workflow and benchmarks it, assuming Docker is operational. Results are stored in the `./tests/data` directory.
465 changes: 220 additions & 245 deletions poetry.lock

Large diffs are not rendered by default.

30 changes: 22 additions & 8 deletions src/workflomics_benchmarker/cwltool_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
from workflomics_benchmarker.cwltool_wrapper import CWLToolWrapper
from workflomics_benchmarker.loggingwrapper import LoggingWrapper


class CWLToolRunner(CWLToolWrapper):
"""
Class to manage and run CWL (Common Workflow Language) workflows.
"""
success_workflows : list = []
failed_workflows : list = []

success_workflows: list = []
failed_workflows: list = []

def __init__(self, args):
"""
Expand All @@ -37,15 +39,21 @@ def _construct_command(self, workflow_path):
list
A list of command segments to execute the workflow.
"""
base_command = ['cwltool --on-error continue']
base_command = ["cwltool"]
if self.container == "singularity":
base_command.append('--singularity')
base_command.append("--singularity")

workflow_name = Path(workflow_path).stem
output_directory = os.path.join(self.outdir, f"{workflow_name}_output")
Path(output_directory).mkdir(exist_ok=True)

return base_command + ['--outdir', output_directory, workflow_path, self.input_yaml_path], output_directory
base_command.extend(["--on-error", "continue"])

return (
base_command
+ ["--outdir", output_directory, workflow_path, self.input_yaml_path],
output_directory,
)

def _execute_command(self, command, workflow_name):
"""
Expand All @@ -63,11 +71,15 @@ def _execute_command(self, command, workflow_name):
bool
True if the workflow executed successfully, False otherwise.
"""
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
result = subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
)
print(result.stdout)

if result.returncode == 0:
LoggingWrapper.info(f"Workflow {workflow_name} finished successfully.", color="green")
LoggingWrapper.info(
f"Workflow {workflow_name} finished successfully.", color="green"
)
return True
else:
LoggingWrapper.error(f"Workflow {workflow_name} failed.", color="red")
Expand Down Expand Up @@ -97,4 +109,6 @@ def run_workflows(self):
for workflow_path in self.workflows:
self.execute_workflow(workflow_path)
total_workflows = len(self.success_workflows) + len(self.failed_workflows)
LoggingWrapper.info(f"Execution summary: {total_workflows} total, {len(self.success_workflows)} succeeded, {len(self.failed_workflows)} failed.")
LoggingWrapper.info(
f"Execution summary: {total_workflows} total, {len(self.success_workflows)} succeeded, {len(self.failed_workflows)} failed."
)
37 changes: 31 additions & 6 deletions src/workflomics_benchmarker/cwltool_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ def __init__(self, args):

self.workflows = sorted([str(file) for file in Path(args.workflows).glob('*.cwl')], key=natural_keys)
self.version = self.check_cwltool()
self.input = self.update_input_yaml(self.input_yaml_path)
if hasattr(args, 'interactive'):
interactive = True
else:
interactive = False

self.input = self.update_input_yaml(self.input_yaml_path, interactive)


def check_cwltool(self):
Expand All @@ -47,24 +52,44 @@ def check_cwltool(self):
print("cwltool is not installed.")
return version

def update_input_yaml(self, input_yaml_path):
"""Update the input yaml file with the paths to the input files"""
def update_input_yaml(self, input_yaml_path:str, interactive: bool) -> dict:
"""
Update the input yaml file with the paths to the input files.
If interactive is set to True, the user will be allowed to edit the paths to the input files.

Parameters
----------
input_yaml_path : str
The path to the input yaml file.

interactive : bool
If True, the user will be allowed to edit the paths to the input files.

Returns
-------
dict
A dictionary containing the input file names.
"""
inputs = {}
with open(input_yaml_path, 'r') as file:
input_data = yaml.safe_load(file)

for key, value in input_data.items():
if key.startswith('input'):
print(f"The path for {key} is {value['path']}. Do you want to change it? (y/n)")
if not interactive:
inputs[key] = {"filename": Path(value['path']).name}
continue

print(f"The path for {key} is {value['path']}. Would you like to keep this path? ([Y]/n)")
answer = input()
kretep marked this conversation as resolved.
Show resolved Hide resolved
if answer == 'y':
if answer == 'n':
new_path = input(f"Enter the path for {key}: ")
value['path'] = new_path.strip()
inputs[key] = {"filename": Path(value['path']).name}
else:
inputs[key] = {"filename": Path(value['path']).name}
with open(input_yaml_path, 'w') as file:
documents = yaml.dump(input_data, file)
yaml.dump(input_data, file)
return inputs


Expand Down
2 changes: 2 additions & 0 deletions src/workflomics_benchmarker/workflomics.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
def add_benchmark_args(parser):
"""Add the arguments for the benchmark command."""
parser.add_argument('--singularity', action='store_true', help='Use singularity instead of docker.')
parser.add_argument('--interactive', action='store_true', help='Allow the user to interact with the library while running, e.g., to edit the paths to the input files before executing the workflows.')
parser.add_argument('-o','--outdir', help='Path to the output directory to store the results (default: workflows directory).', default= None)
parser.add_argument('-v', '--verbose', action='store_true', help='Print the output of the cwltool command.')
parser.add_argument('-i','--input', help='Path to the input yaml file (default: input.yml in the workflows directory).', default= None)
Expand All @@ -17,6 +18,7 @@ def add_benchmark_args(parser):
def add_run_args(parser):
"""Add the arguments for the run command."""
parser.add_argument('--singularity', action='store_true', help='Use singularity instead of docker.')
parser.add_argument('--interactive', action='store_true', help='Allow the user to interact with the library while running, e.g., to edit the paths to the input files before executing the workflows.')
parser.add_argument('-o','--outdir', help='Path to the output directory to store the results (default: workflows directory).', default= None)
parser.add_argument('-v', '--verbose', action='store_true', help='Print the output of the cwltool command.')
parser.add_argument('-i','--input', help='Path to the input yaml file (default: input.yml in the workflows directory).', default= None)
Expand Down
Loading