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

Better error messages #15

Merged
merged 11 commits into from
Apr 23, 2024
3 changes: 2 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ repos:
rev: v1.9.0
hooks:
- id: mypy
args: [--strict, --ignore-missing-imports]
args: [--strict, --install-types, --non-interactive]
additional_dependencies: [sympy, attrs, pytest, click, dask]
5 changes: 5 additions & 0 deletions example/extra.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,31 @@

JUMP: int = 10


@task()
def increase(num: int) -> int:
"""Add globally-configured integer JUMP to a number."""
return num + JUMP


@task()
def increment(num: int) -> int:
"""Increment an integer."""
return num + 1


@task()
def double(num: int) -> int:
"""Double an integer."""
return 2 * num


@task()
def mod10(num: int) -> int:
"""Calculate supplied integer modulo 10."""
return num % 10


@task()
def sum(left: int, right: int) -> int:
"""Add two integers."""
Expand Down
8 changes: 3 additions & 5 deletions example/workflow_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Useful as an example of a workflow with a nested task.

```sh
$ python -m dewret workflow_complex.py --pretty run
$ python -m dewret workflow_complex.py --pretty nested_workflow
```
"""

Expand All @@ -12,12 +12,10 @@

STARTING_NUMBER: int = 23


@nested_task()
def nested_workflow() -> int | float:
"""Creates a graph of task calls."""
left = double(num=increase(num=STARTING_NUMBER))
right = increase(num=increase(num=17))
return sum(
left=left,
right=right
)
return sum(left=left, right=right)
41 changes: 33 additions & 8 deletions src/dewret/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,28 @@
from .renderers.cwl import render as cwl_render
from .tasks import Backend, construct


@click.command()
@click.option("--pretty", is_flag=True, show_default=True, default=False, help="Pretty-print output where possible.")
@click.option("--backend", type=click.Choice(list(Backend.__members__)), show_default=True, default=Backend.DASK.name, help="Backend to use for workflow evaluation.")
@click.option(
"--pretty",
is_flag=True,
show_default=True,
default=False,
help="Pretty-print output where possible.",
)
@click.option(
"--backend",
type=click.Choice(list(Backend.__members__)),
show_default=True,
default=Backend.DASK.name,
help="Backend to use for workflow evaluation.",
)
@click.argument("workflow_py")
@click.argument("task")
@click.argument("arguments", nargs=-1)
def render(workflow_py: str, task: str, arguments: list[str], pretty: bool, backend: Backend) -> None:
def render(
workflow_py: str, task: str, arguments: list[str], pretty: bool, backend: Backend
) -> None:
"""Render a workflow.

WORKFLOW_PY is the Python file containing workflow.
Expand All @@ -49,14 +64,24 @@ def render(workflow_py: str, task: str, arguments: list[str], pretty: bool, back
kwargs = {}
for arg in arguments:
if ":" not in arg:
raise RuntimeError("Arguments should be specified as key:val, where val is a JSON representation of the argument")
raise RuntimeError(
"Arguments should be specified as key:val, where val is a JSON representation of the argument"
)
key, val = arg.split(":", 1)
kwargs[key] = json.loads(val)

cwl = cwl_render(construct(task_fn(**kwargs), simplify_ids=True))
if pretty:
yaml.dump(cwl, sys.stdout, indent=2)
try:
cwl = cwl_render(construct(task_fn(**kwargs), simplify_ids=True))
except Exception as exc:
import traceback

print(exc, exc.__cause__, exc.__context__)
traceback.print_exc()
else:
print(cwl)
if pretty:
yaml.dump(cwl, sys.stdout, indent=2)
else:
print(cwl)


render()
10 changes: 9 additions & 1 deletion src/dewret/backends/backend_dask.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from dewret.workflow import Workflow, Lazy, StepReference, Target
from typing import Protocol, runtime_checkable, Any, cast


@runtime_checkable
class Delayed(Protocol):
"""Description of a dask `delayed`.
Expand Down Expand Up @@ -48,6 +49,7 @@ def compute(self, __workflow__: Workflow | None) -> StepReference[Any]:
"""
...


def unwrap(task: Lazy) -> Target:
"""Unwraps a lazy-evaluated function to get the function.

Expand All @@ -69,6 +71,7 @@ def unwrap(task: Lazy) -> Target:
raise RuntimeError("Task is not actually a callable")
return cast(Target, task._obj)


def is_lazy(task: Any) -> bool:
"""Checks if a task is really a lazy-evaluated function for this backend.

Expand All @@ -80,7 +83,10 @@ def is_lazy(task: Any) -> bool:
"""
return isinstance(task, Delayed)


lazy = delayed


def run(workflow: Workflow | None, task: Lazy) -> StepReference[Any]:
"""Execute a task as the output of a workflow.

Expand All @@ -92,5 +98,7 @@ def run(workflow: Workflow | None, task: Lazy) -> StepReference[Any]:
"""
# We need isinstance to reassure type-checker.
if not isinstance(task, Delayed) or not is_lazy(task):
raise RuntimeError("Cannot mix backends")
raise RuntimeError(
f"{task} is not a dask delayed, perhaps you tried to mix backends?"
)
return task.compute(__workflow__=workflow)
Loading
Loading