Skip to content

Commit f3193ae

Browse files
authored
Document functional interface. (#423)
1 parent 897270a commit f3193ae

14 files changed

+1625
-50
lines changed

.pre-commit-config.yaml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ repos:
6969
additional_dependencies: [
7070
attrs>=21.3.0,
7171
click,
72+
optree,
7273
pluggy,
73-
types-setuptools
74+
types-setuptools,
7475
]
7576
pass_filenames: false
7677
- repo: https://github.com/executablebooks/mdformat
@@ -113,15 +114,25 @@ repos:
113114
docs/source/tutorials/set_up_a_project.md|
114115
docs/source/tutorials/write_a_task.md
115116
)$
116-
- repo: https://github.com/kynan/nbstripout
117-
rev: 0.6.1
118-
hooks:
119-
- id: nbstripout
117+
- repo: https://github.com/nbQA-dev/nbQA
118+
rev: 1.7.0
119+
hooks:
120+
- id: nbqa-black
121+
- id: nbqa-isort
122+
- id: nbqa-mypy
123+
args: [--ignore-missing-imports]
124+
- id: nbqa-ruff
125+
- repo: https://github.com/kynan/nbstripout
126+
rev: 0.6.1
127+
hooks:
128+
- id: nbstripout
129+
exclude: (docs)
120130
- repo: https://github.com/codespell-project/codespell
121131
rev: v2.2.5
122132
hooks:
123133
- id: codespell
124134
additional_dependencies: [tomli]
135+
exclude: (\.ipynb)
125136
- repo: https://github.com/mgedmin/check-manifest
126137
rev: "0.49"
127138
hooks:

docs/source/changes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ releases are available on [PyPI](https://pypi.org/project/pytask) and
4040
decorators.
4141
- {pull}`421` removes the deprecation warning when `produces` is used as an magic
4242
function keyword to define products.
43+
- {pull}`423` adds a notebook to explain the functional interface.
4344
- {pull}`424` fixes problems with {func}`~_pytask.path.import_path`.
45+
- {pull}`426` publishes the {mod}`pytask.tree_util` module.
46+
- {pull}`427` fixes type annotations for {attr}`pytask.PTask.depends_on` and
47+
{attr}`pytask.PTask.produces`.
4448

4549
## 0.3.2 - 2023-06-07
4650

docs/source/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"sphinx.ext.viewcode",
4242
"sphinx_copybutton",
4343
"sphinx_click",
44+
"nbsphinx",
4445
"myst_parser",
4546
"sphinx_design",
4647
]

docs/source/how_to_guides/functional_interface.ipynb

Lines changed: 1572 additions & 0 deletions
Large diffs are not rendered by default.

docs/source/how_to_guides/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ specific tasks with pytask.
1212
maxdepth: 1
1313
---
1414
migrating_from_scripts_to_pytask
15-
invoking_pytask_extended
15+
functional_interface
1616
capture_warnings
1717
how_to_influence_build_order
1818
hashing_inputs_of_tasks

docs/source/how_to_guides/invoking_pytask_extended.md

Lines changed: 0 additions & 20 deletions
This file was deleted.

docs/source/tutorials/invoking_pytask.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,8 @@ You can do a dry run to see which tasks would be executed without executing them
8282

8383
```{include} ../_static/md/dry-run.md
8484
```
85+
86+
## Functional interface
87+
88+
pytask also has a functional interface that is explained in this
89+
[article](../how_to_guides/functional_interface.ipynb).

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ ignore = [
6767
"src/_pytask/dag.py" = ["B023"]
6868
"tests/test_capture.py" = ["T201", "PT011"]
6969
"tests/*" = ["D", "ANN", "PLR2004", "S101"]
70+
"tests/test_jupyter/*" = ["INP001"]
7071
"scripts/*" = ["D", "INP001"]
7172
"docs/source/conf.py" = ["D401", "INP001"]
73+
"docs/source/how_to_guides/functional_interface*" = ["D", "INP", "ARG005"]
7274
"docs_src/*" = ["ARG001", "D", "INP001"]
7375
"docs_src/*/*_py310.py" = ["FA102"]
7476
"docs_src/*/*_py38.py" = ["FA100"]

src/_pytask/collect_command.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,9 @@ def _print_collected_tasks(
200200

201201
if show_nodes:
202202
nodes = list(tree_leaves(task.depends_on))
203-
sorted_nodes = sorted(nodes, key=lambda x: x.name)
203+
sorted_nodes = sorted(
204+
nodes, key=lambda x: x.name # type: ignore[attr-defined]
205+
)
204206
for node in sorted_nodes:
205207
if isinstance(node, PPathNode):
206208
if node.path.as_posix() in node.name:
@@ -214,12 +216,15 @@ def _print_collected_tasks(
214216
)
215217
text = Text(reduced_node_name, style=url_style)
216218
else:
217-
text = node.name
219+
text = node.name # type: ignore[attr-defined]
218220

219221
task_branch.add(Text.assemble(FILE_ICON, "<Dependency ", text, ">"))
220222

221223
for node in sorted(
222-
tree_leaves(task.produces), key=lambda x: getattr(x, "path", x.name)
224+
tree_leaves(task.produces),
225+
key=lambda x: getattr(
226+
x, "path", x.name # type: ignore[attr-defined]
227+
),
223228
):
224229
if isinstance(node, PPathNode):
225230
reduced_node_name = str(relative_to(node.path, common_ancestor))
@@ -228,7 +233,7 @@ def _print_collected_tasks(
228233
)
229234
text = Text(reduced_node_name, style=url_style)
230235
else:
231-
text = Text(node.name)
236+
text = Text(node.name) # type: ignore[attr-defined]
232237
task_branch.add(Text.assemble(FILE_ICON, "<Product ", text, ">"))
233238

234239
console.print(tree)

src/_pytask/console.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing import Any
1010
from typing import Callable
1111
from typing import Iterable
12+
from typing import Literal
1213
from typing import TYPE_CHECKING
1314

1415
import rich
@@ -56,7 +57,7 @@
5657
_IS_LEGACY_WINDOWS = False
5758

5859

59-
_COLOR_SYSTEM = None if _IS_LEGACY_WINDOWS else "auto"
60+
_COLOR_SYSTEM: Literal["auto"] | None = None if _IS_LEGACY_WINDOWS else "auto"
6061

6162

6263
_HORIZONTAL_PADDING = (0, 1, 0, 1)

src/_pytask/execute.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def pytask_execute_task(session: Session, task: PTask) -> bool:
175175
nodes = tree_leaves(task.produces["return"])
176176
values = structure_return.flatten_up_to(out)
177177
for node, value in zip(nodes, values):
178-
node.save(value)
178+
node.save(value) # type: ignore[attr-defined]
179179

180180
return True
181181

src/_pytask/tree_util.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import functools
55
from pathlib import Path
6-
from typing import Any
76

87
import optree
98
from optree import PyTree
@@ -40,10 +39,3 @@
4039
tree_flatten_with_path = functools.partial(
4140
_optree_tree_flatten_with_path, none_is_leaf=True, namespace="pytask"
4241
)
43-
44-
45-
def tree_index(path: tuple[Any, ...], tree: PyTree) -> Any:
46-
"""Index a tree with a path."""
47-
if not path:
48-
return tree
49-
return tree_index(path[1:], tree[path[0]])

tests/test_jupyter/test_functional_interface.ipynb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@
99
"source": [
1010
"from pathlib import Path\n",
1111
"\n",
12-
"import pytask\n",
12+
"from typing_extensions import Annotated\n",
1313
"\n",
14-
"from pytask import ExitCode\n",
15-
"from pytask import PathNode\n",
16-
"from pytask import PythonNode\n",
17-
"from typing_extensions import Annotated"
14+
"import pytask\n",
15+
"from pytask import ExitCode, PathNode, PythonNode"
1816
]
1917
},
2018
{
@@ -26,11 +24,14 @@
2624
"source": [
2725
"node_text = PythonNode(name=\"text\", hash=True)\n",
2826
"\n",
27+
"\n",
2928
"def create_text() -> Annotated[int, node_text]:\n",
3029
" return \"This is the text.\"\n",
3130
"\n",
31+
"\n",
3232
"node_file = PathNode.from_path(Path(\"file.txt\").resolve())\n",
3333
"\n",
34+
"\n",
3435
"def create_file(text: Annotated[int, node_text]) -> Annotated[str, node_file]:\n",
3536
" return text"
3637
]

tests/test_jupyter/test_functional_interface_w_relative_path.ipynb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@
99
"source": [
1010
"from pathlib import Path\n",
1111
"\n",
12-
"import pytask\n",
12+
"from typing_extensions import Annotated\n",
1313
"\n",
14-
"from pytask import ExitCode\n",
15-
"from pytask import PathNode\n",
16-
"from pytask import PythonNode\n",
17-
"from typing_extensions import Annotated"
14+
"import pytask\n",
15+
"from pytask import ExitCode, PathNode, PythonNode"
1816
]
1917
},
2018
{
@@ -26,11 +24,14 @@
2624
"source": [
2725
"node_text = PythonNode(name=\"text\", hash=True)\n",
2826
"\n",
27+
"\n",
2928
"def create_text() -> Annotated[int, node_text]:\n",
3029
" return \"This is the text.\"\n",
3130
"\n",
31+
"\n",
3232
"node_file = PathNode(name=\"product\", path=Path(\"file.txt\"))\n",
3333
"\n",
34+
"\n",
3435
"def create_file(text: Annotated[int, node_text]) -> Annotated[str, node_file]:\n",
3536
" return text"
3637
]

0 commit comments

Comments
 (0)