Interfaces for dependencies and products¶
Different interfaces exist for dependencies and products, and it might not be obvious when to use what. This guide gives you an overview of the different strengths of each approach.
Legend¶
✅ = True
❌ = False
➖ = Does not apply
Dependencies¶
In general, pytask regards everything as a task dependency if it is not marked as a product. Thus, you can also think of the following examples as how to inject values into a task. When we talk about products later, the same interfaces will be used.
|
|
|
|
---|---|---|---|
Not deprecated |
✅ |
✅ |
✅ |
No type annotations required |
✅ |
❌ |
✅ |
Flexible choice of argument name |
✅ |
✅ |
✅ |
Supports third-party functions as tasks |
❌ |
❌ |
✅ |
Default argument¶
You can pass a value to a task as a default argument.
from pathlib import Path
def task_example(path: Path = Path("input.txt")) -> None: ...
Annotation with value¶
It is possible to include the value in the type annotation.
It is especially helpful if you pass a PNode
to the task. If you passed
a node as the default argument, type checkers like mypy would expect the node to enter
the task, but the value injected into the task depends on the nodes
load()
method. For a PathNode
from pathlib import Path
from typing import Annotated
from pytask import PathNode
def task_example(path: Annotated[Path, PathNode(path=Path("input.txt"))]) -> None: ...
@task(kwargs=...)
¶
You can use the kwargs
argument of the @task
decorator to pass a
dictionary. It applies to dependencies and products alike.
from pathlib import Path
from pytask import task
@task(kwargs={"path": Path("input.txt")})
def task_example(path: Path) -> None: ...
Products¶
|
|
|
|
|
|
---|---|---|---|---|---|
Not deprecated |
✅ |
✅ |
✅ |
✅ |
✅ |
No type annotations required |
❌ |
❌ |
✅ |
✅ |
❌ |
Flexible choice of argument name |
✅ |
✅ |
❌ |
✅ |
➖ |
Supports third-party functions as tasks |
❌ |
❌ |
❌ |
✅ |
❌ |
Allows to pass custom node while preserving type of value |
❌ |
✅ |
✅ |
✅ |
✅ |
Product
annotation¶
The syntax is the same as Default argument, but the Product
annotation turns the argument into a task product.
from pathlib import Path
from typing import Annotated
from pytask import Product
def task_write_file(path: Annotated[Path, Product] = Path("file.txt")) -> None:
path.touch()
Product
annotation with value¶
The syntax is the same as Annotation with value, but the Product
annotation
turns the argument into a task product.
from pathlib import Path
from typing import Annotated
from pytask import PathNode
from pytask import Product
def task_write_file(
path: Annotated[Path, PathNode(path=Path("file.txt")), Product],
) -> None:
path.touch()
produces
¶
Without using any type annotation, you can use produces
as a magical argument name to
treat every value passed to it as a task product.
from pathlib import Path
def task_write_file(produces: Path = Path("file.txt")) -> None:
produces.touch()
Return annotation¶
You can also add a node or a value that will be parsed to a node to the annotation of the return type. It allows us to treat the returns of the task function as products.
from pathlib import Path
from typing import Annotated
def task_write_file() -> Annotated[str, Path("file.txt")]:
return ""
@task(produces=...)
¶
In situations where the task return is the product like Return annotation, but
you cannot modify the type annotation of the return, use the argument produces
of the
@task
decorator.
Pass the node or value you otherwise include in the type annotation to produces
.
from pathlib import Path
from pytask import task
@task(produces=Path("file.txt"))
def task_write_file() -> str:
return ""