Skip to content

Commit

Permalink
Factory: also parse command-line options
Browse files Browse the repository at this point in the history
Co-authored-by: Michael R. Crusoe <[email protected]>
  • Loading branch information
suecharo and mr-c committed Oct 24, 2024
1 parent 8dee8e9 commit 92160f6
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 16 deletions.
85 changes: 72 additions & 13 deletions cwltool/factory.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
"""Wrap a CWL document as a callable Python object."""

import argparse
import functools

Check warning on line 4 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L3-L4

Added lines #L3 - L4 were not covered by tests
import os
import sys

Check warning on line 6 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L6

Added line #L6 was not covered by tests
from typing import Any, Optional, Union

from . import load_tool
from .context import LoadingContext, RuntimeContext
from .argparser import arg_parser
from .context import LoadingContext, RuntimeContext, getdefault

Check warning on line 11 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L10-L11

Added lines #L10 - L11 were not covered by tests
from .errors import WorkflowException
from .executors import JobExecutor, SingleJobExecutor
from .main import find_default_container

Check warning on line 14 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L14

Added line #L14 was not covered by tests
from .process import Process
from .utils import CWLObjectType
from .resolver import tool_resolver
from .secrets import SecretStore
from .utils import DEFAULT_TMP_PREFIX, CWLObjectType

Check warning on line 18 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L16-L18

Added lines #L16 - L18 were not covered by tests


class WorkflowStatus(Exception):
Expand All @@ -25,11 +34,13 @@ def __init__(self, t: Process, factory: "Factory") -> None:
self.t = t
self.factory = factory

def __call__(self, **kwargs):
# type: (**Any) -> Union[str, Optional[CWLObjectType]]
runtime_context = self.factory.runtime_context.copy()
runtime_context.basedir = os.getcwd()
out, status = self.factory.executor(self.t, kwargs, runtime_context)
def __call__(self, **kwargs: Any) -> Union[str, Optional[CWLObjectType]]:

Check warning on line 37 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L37

Added line #L37 was not covered by tests
"""
Execute the process.
:raise WorkflowStatus: If the result is not a success.
"""
out, status = self.factory.executor(self.t, kwargs, self.factory.runtime_context)

Check warning on line 43 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L43

Added line #L43 was not covered by tests
if status != "success":
raise WorkflowStatus(out, status)
else:
Expand All @@ -44,21 +55,27 @@ class Factory:

def __init__(
self,
argsl: Optional[list[str]] = None,
args: Optional[argparse.Namespace] = None,
executor: Optional[JobExecutor] = None,
loading_context: Optional[LoadingContext] = None,
runtime_context: Optional[RuntimeContext] = None,
) -> None:
"""Create a CWL Process factory from a CWL document."""
if argsl is not None:
args = arg_parser().parse_args(argsl)

Check warning on line 66 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L66

Added line #L66 was not covered by tests
if executor is None:
executor = SingleJobExecutor()
self.executor = executor
self.executor: JobExecutor = SingleJobExecutor()

Check warning on line 68 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L68

Added line #L68 was not covered by tests
else:
self.executor = executor

Check warning on line 70 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L70

Added line #L70 was not covered by tests
if runtime_context is None:
self.runtime_context = RuntimeContext()
self.runtime_context = RuntimeContext(vars(args))
self._fix_runtime_context()

Check warning on line 73 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L72-L73

Added lines #L72 - L73 were not covered by tests
else:
self.runtime_context = runtime_context
if loading_context is None:
self.loading_context = LoadingContext()
self.loading_context.singularity = self.runtime_context.singularity
self.loading_context.podman = self.runtime_context.podman
self.loading_context = LoadingContext(vars(args))
self._fix_loading_context(self.runtime_context)

Check warning on line 78 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L77-L78

Added lines #L77 - L78 were not covered by tests
else:
self.loading_context = loading_context

Expand All @@ -68,3 +85,45 @@ def make(self, cwl: Union[str, dict[str, Any]]) -> Callable:
if isinstance(load, int):
raise WorkflowException("Error loading tool")
return Callable(load, self)

def _fix_loading_context(self, runtime_context: RuntimeContext) -> None:
self.loading_context.resolver = getdefault(self.loading_context.resolver, tool_resolver)
self.loading_context.singularity = runtime_context.singularity
self.loading_context.podman = runtime_context.podman

Check warning on line 92 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L89-L92

Added lines #L89 - L92 were not covered by tests

def _fix_runtime_context(self) -> None:
self.runtime_context.basedir = os.getcwd()
self.runtime_context.find_default_container = functools.partial(

Check warning on line 96 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L94-L96

Added lines #L94 - L96 were not covered by tests
find_default_container, default_container=None, use_biocontainers=None
)

if sys.platform == "darwin":
default_mac_path = "/private/tmp/docker_tmp"

Check warning on line 101 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L101

Added line #L101 was not covered by tests
if self.runtimeContext.tmp_outdir_prefix == DEFAULT_TMP_PREFIX:
self.runtimeContext.tmp_outdir_prefix = default_mac_path

Check warning on line 103 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L103

Added line #L103 was not covered by tests

for dirprefix in ("tmpdir_prefix", "tmp_outdir_prefix", "cachedir"):
if (
getattr(self.runtime_context, dirprefix)
and getattr(self.runtime_context, dirprefix) != DEFAULT_TMP_PREFIX
):
sl = (

Check warning on line 110 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L110

Added line #L110 was not covered by tests
"/"
if getattr(self.runtime_context, dirprefix).endswith("/")
or dirprefix == "cachedir"
else ""
)
setattr(

Check warning on line 116 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L116

Added line #L116 was not covered by tests
self.runtime_context,
dirprefix,
os.path.abspath(getattr(self.runtime_context, dirprefix)) + sl,
)
if not os.path.exists(os.path.dirname(getattr(self.runtime_context, dirprefix))):
try:
os.makedirs(os.path.dirname(getattr(self.runtime_context, dirprefix)))
except Exception as e:
print("Failed to create directory: %s", e)

Check warning on line 125 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L122-L125

Added lines #L122 - L125 were not covered by tests

self.runtime_context.secret_store = getdefault(

Check warning on line 127 in cwltool/factory.py

View check run for this annotation

Codecov / codecov/patch

cwltool/factory.py#L127

Added line #L127 was not covered by tests
self.runtime_context.secret_store, SecretStore()
)
2 changes: 1 addition & 1 deletion tests/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_replace_default_stdout_stderr() -> None:
runtime_context = RuntimeContext()
runtime_context.default_stdout = subprocess.DEVNULL # type: ignore
runtime_context.default_stderr = subprocess.DEVNULL # type: ignore
factory = Factory(None, None, runtime_context)
factory = Factory(runtime_context=runtime_context)
echo = factory.make(get_data("tests/echo.cwl"))

assert echo(inp="foo") == {"out": "foo\n"}
Expand Down
4 changes: 2 additions & 2 deletions tests/test_parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def test_sequential_workflow(tmp_path: Path) -> None:
runtime_context = RuntimeContext()
runtime_context.outdir = str(tmp_path)
runtime_context.select_resources = executor.select_resources
factory = Factory(executor, None, runtime_context)
factory = Factory(executor=executor, runtime_context=runtime_context)
echo = factory.make(get_data(test_file))
file_contents = {"class": "File", "location": get_data("tests/wf/whale.txt")}
assert echo(file1=file_contents) == {"count_output": 16}
Expand All @@ -25,7 +25,7 @@ def test_sequential_workflow(tmp_path: Path) -> None:
def test_scattered_workflow() -> None:
test_file = "tests/wf/scatter-wf4.cwl"
job_file = "tests/wf/scatter-job2.json"
factory = Factory(MultithreadedJobExecutor())
factory = Factory(executor=MultithreadedJobExecutor())
echo = factory.make(get_data(test_file))
with open(get_data(job_file)) as job:
assert echo(**json.load(job)) == {"out": ["foo one three", "foo two four"]}

0 comments on commit 92160f6

Please sign in to comment.