|
| 1 | +# Interfaces for dependencies and products |
| 2 | + |
| 3 | +Different interfaces exist for dependencies and products, and it might not be obvious |
| 4 | +when to use what. This guide gives you an overview of the different strengths of each |
| 5 | +approach. |
| 6 | + |
| 7 | +## Legend |
| 8 | + |
| 9 | +- ✅ = True |
| 10 | +- ❌ = False |
| 11 | +- ➖ = Does not apply |
| 12 | + |
| 13 | +## Dependencies |
| 14 | + |
| 15 | +In general, pytask regards everything as a task dependency if it is not marked as a |
| 16 | +product. Thus, you can also think of the following examples as how to inject values into |
| 17 | +a task. When we talk about products later, the same interfaces will be used. |
| 18 | + |
| 19 | +| | `def task(arg: ... = ...)` | `Annotated[..., value]` | `@task(kwargs=...)` | `@pytask.mark.depends_on(...)` | |
| 20 | +| --------------------------------------- | :------------------------: | :---------------------: | :-----------------: | :----------------------------: | |
| 21 | +| Not deprecated | ✅ | ✅ | ✅ | ❌ | |
| 22 | +| No type annotations required | ✅ | ❌ | ✅ | ✅ | |
| 23 | +| Flexible choice of argument name | ✅ | ✅ | ✅ | ❌ | |
| 24 | +| Supports third-party functions as tasks | ❌ | ❌ | ✅ | ❌ | |
| 25 | + |
| 26 | +(default-argument)= |
| 27 | + |
| 28 | +### Default argument |
| 29 | + |
| 30 | +You can pass a value to a task as a default argument. |
| 31 | + |
| 32 | +```{literalinclude} ../../../docs_src/how_to_guides/interfaces/dependencies_default.py |
| 33 | +``` |
| 34 | + |
| 35 | +(annotation)= |
| 36 | + |
| 37 | +### Annotation with value |
| 38 | + |
| 39 | +It is possible to include the value in the type annotation. |
| 40 | + |
| 41 | +It is especially helpful if you pass a {class}`~pytask.PNode` to the task. If you passed |
| 42 | +a node as the default argument, type checkers like mypy would expect the node to enter |
| 43 | +the task, but the value injected into the task depends on the nodes |
| 44 | +{meth}`~pytask.PNode.load` method. For a {class}`~pytask.PathNode` |
| 45 | + |
| 46 | +```{literalinclude} ../../../docs_src/how_to_guides/interfaces/dependencies_annotation.py |
| 47 | +``` |
| 48 | + |
| 49 | +(task-kwargs)= |
| 50 | + |
| 51 | +### `@task(kwargs=...)` |
| 52 | + |
| 53 | +You can use the `kwargs` argument of the {func}`@task <pytask.task>` decorator to pass a |
| 54 | +dictionary. It applies to dependencies and products alike. |
| 55 | + |
| 56 | +```{literalinclude} ../../../docs_src/how_to_guides/interfaces/dependencies_task_kwargs.py |
| 57 | +``` |
| 58 | + |
| 59 | +## Products |
| 60 | + |
| 61 | +| | `def task(arg: Annotated[..., Product] = ...)` | `Annotated[..., value, Product]` | `produces` | `@task(produces=...)` | `def task() -> Annotated[..., value]` | `@pytask.mark.produces(...)` | |
| 62 | +| --------------------------------------------------------- | :--------------------------------------------: | :------------------------------: | :--------: | :-------------------: | :-----------------------------------: | :--------------------------: | |
| 63 | +| Not deprecated | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | |
| 64 | +| No type annotations required | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | |
| 65 | +| Flexible choice of argument name | ✅ | ✅ | ❌ | ✅ | ➖ | ❌ | |
| 66 | +| Supports third-party functions as tasks | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | |
| 67 | +| Allows to pass custom node while preserving type of value | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 68 | + |
| 69 | +### `Product` annotation |
| 70 | + |
| 71 | +The syntax is the same as {ref}`default-argument`, but the {class}`~pytask.Product` |
| 72 | +annotation turns the argument into a task product. |
| 73 | + |
| 74 | +```{literalinclude} ../../../docs_src/how_to_guides/interfaces/products_annotation.py |
| 75 | +``` |
| 76 | + |
| 77 | +### `Product` annotation with value |
| 78 | + |
| 79 | +The syntax is the same as {ref}`annotation`, but the {class}`~pytask.Product` annotation |
| 80 | +turns the argument into a task product. |
| 81 | + |
| 82 | +```{literalinclude} ../../../docs_src/how_to_guides/interfaces/products_annotation_with_pnode.py |
| 83 | +``` |
| 84 | + |
| 85 | +### `produces` |
| 86 | + |
| 87 | +Without using any type annotation, you can use `produces` as a magical argument name to |
| 88 | +treat every value passed to it as a task product. |
| 89 | + |
| 90 | +```{literalinclude} ../../../docs_src/how_to_guides/interfaces/products_produces.py |
| 91 | +``` |
| 92 | + |
| 93 | +(return-annotation)= |
| 94 | + |
| 95 | +### Return annotation |
| 96 | + |
| 97 | +You can also add a node or a value that will be parsed to a node to the annotation of |
| 98 | +the return type. It allows us to treat the returns of the task function as products. |
| 99 | + |
| 100 | +```{literalinclude} ../../../docs_src/how_to_guides/interfaces/products_return_annotation.py |
| 101 | +``` |
| 102 | + |
| 103 | +(task-produces)= |
| 104 | + |
| 105 | +### `@task(produces=...)` |
| 106 | + |
| 107 | +In situations where the task return is the product like {ref}`return-annotation`, but |
| 108 | +you cannot modify the type annotation of the return, use the argument `produces` of the |
| 109 | +{func}`@task <pytask.task>` decorator. |
| 110 | + |
| 111 | +Pass the node or value you otherwise include in the type annotation to `produces`. |
| 112 | + |
| 113 | +```{literalinclude} ../../../docs_src/how_to_guides/interfaces/products_task_produces.py |
| 114 | +``` |
0 commit comments