From 8243840be612699752af86b9c2d0e3103e720d87 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sun, 11 May 2025 21:58:52 +0200 Subject: [PATCH 1/9] Fixing compatibility with click.Choice. --- .pre-commit-config.yaml | 2 +- src/_pytask/cli.py | 4 +-- src/_pytask/click.py | 79 +++++++++++++++++++++++++++-------------- 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 701d185f..9110613f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -59,7 +59,7 @@ repos: - id: nbstripout exclude: (docs) - repo: https://github.com/crate-ci/typos - rev: v1 + rev: v1.32.0 hooks: - id: typos exclude: (\.ipynb) diff --git a/src/_pytask/cli.py b/src/_pytask/cli.py index 13046646..49ab6464 100644 --- a/src/_pytask/cli.py +++ b/src/_pytask/cli.py @@ -2,10 +2,10 @@ from __future__ import annotations +import importlib.metadata from typing import Any import click -from packaging.version import parse as parse_version from _pytask.click import ColoredGroup from _pytask.pluginmanager import storage @@ -16,7 +16,7 @@ } -if parse_version(click.__version__) >= parse_version("8"): # pragma: no cover +if importlib.metadata.version("click") >= "8": # pragma: no cover _VERSION_OPTION_KWARGS = {"package_name": "pytask"} else: # pragma: no cover _VERSION_OPTION_KWARGS = {} diff --git a/src/_pytask/click.py b/src/_pytask/click.py index 9b19eb93..b4b2b965 100644 --- a/src/_pytask/click.py +++ b/src/_pytask/click.py @@ -2,6 +2,7 @@ from __future__ import annotations +import importlib.metadata import inspect from enum import Enum from gettext import gettext as _ @@ -9,15 +10,16 @@ from typing import TYPE_CHECKING from typing import Any from typing import ClassVar +from typing import TypeVar import click from click import Choice from click import Command from click import Context from click import Parameter -from click.parser import split_opt from click_default_group import DefaultGroup from rich.highlighter import RegexHighlighter +from rich.padding import Padding from rich.panel import Panel from rich.table import Table from rich.text import Text @@ -27,40 +29,57 @@ from _pytask.console import create_panel_title if TYPE_CHECKING: + from collections.abc import Iterable from collections.abc import Sequence __all__ = ["ColoredCommand", "ColoredGroup", "EnumChoice"] -class EnumChoice(Choice): - """An enum-based choice type. +if importlib.metadata.version("click") < "8.2": + from click.parser import split_opt - The implementation is copied from https://github.com/pallets/click/pull/2210 and - related discussion can be found in https://github.com/pallets/click/issues/605. + class EnumChoice(Choice): # type: ignore[type-arg] + """An enum-based choice type. - In contrast to using :class:`click.Choice`, using this type ensures that the error - message does not show the enum members. + The implementation is copied from https://github.com/pallets/click/pull/2210 and + related discussion can be found in https://github.com/pallets/click/issues/605. - In contrast to the proposed implementation in the PR, this implementation does not - use the members than rather the values of the enum. + In contrast to using :class:`click.Choice`, using this type ensures that the + error message does not show the enum members. - """ + In contrast to the proposed implementation in the PR, this implementation does + not use the members than rather the values of the enum. - def __init__(self, enum_type: type[Enum], case_sensitive: bool = True) -> None: - super().__init__( - choices=[element.value for element in enum_type], - case_sensitive=case_sensitive, - ) - self.enum_type = enum_type + """ + + def __init__(self, enum_type: type[Enum], case_sensitive: bool = True) -> None: + super().__init__( + choices=[element.value for element in enum_type], + case_sensitive=case_sensitive, + ) + self.enum_type = enum_type + + def convert( + self, value: Any, param: Parameter | None, ctx: Context | None + ) -> Any: + if isinstance(value, Enum): + value = value.value + value = super().convert(value=value, param=param, ctx=ctx) + if value is None: + return None + return self.enum_type(value) + +else: + from click.parser import _split_opt as split_opt + + ParamTypeValue = TypeVar("ParamTypeValue") - def convert(self, value: Any, param: Parameter | None, ctx: Context | None) -> Any: - if isinstance(value, Enum): - value = value.value - value = super().convert(value=value, param=param, ctx=ctx) - if value is None: - return None - return self.enum_type(value) + class EnumChoice(Choice): + def __init__( + self, choices: Iterable[ParamTypeValue], case_sensitive: bool = False + ) -> None: + super().__init__(choices=choices, case_sensitive=case_sensitive) class _OptionHighlighter(RegexHighlighter): @@ -119,7 +138,10 @@ def format_help( _print_options(self, ctx) console.print( - "[bold #FF0000]♥[/] [#f2f2f2]https://pytask-dev.readthedocs.io[/]", + Padding( + "[bold #FF0000]♥[/] [#f2f2f2]https://pytask-dev.readthedocs.io[/]", + (0, 3, 0, 0), + ), justify="right", ) @@ -197,7 +219,10 @@ def format_help( _print_options(self, ctx) console.print( - "[bold #FF0000]♥[/] [#f2f2f2]https://pytask-dev.readthedocs.io[/]", + Padding( + "[bold #FF0000]♥[/] [#f2f2f2]https://pytask-dev.readthedocs.io[/]", + (0, 3, 0, 0), + ), justify="right", ) @@ -235,7 +260,7 @@ def _print_options(group_or_command: Command | DefaultGroup, ctx: Context) -> No if param.metavar: opt2 += Text(f" {param.metavar}", style="metavar") elif isinstance(param.type, click.Choice): - choices = "[" + "|".join(param.type.choices) + "]" + choices = "[" + "|".join([str(c.value) for c in param.type.choices]) + "]" opt2 += Text(f" {choices}", style="metavar", overflow="fold") help_text = _format_help_text(param, ctx) @@ -313,7 +338,7 @@ def _format_help_text( # noqa: C901, PLR0912, PLR0915 elif param.is_bool_flag and param.secondary_opts: # type: ignore[attr-defined] # For boolean flags that have distinct True/False opts, # use the opt without prefix instead of the value. - default_string = split_opt( + default_string = split_opt( # type: ignore[operator] (param.opts if param.default else param.secondary_opts)[0] )[1] elif ( From 99268949c2bf0c3115d353aa4ca10f8f520d8614 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sun, 11 May 2025 22:05:24 +0200 Subject: [PATCH 2/9] Fix typing issues. --- src/_pytask/click.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytask/click.py b/src/_pytask/click.py index b4b2b965..51f6b383 100644 --- a/src/_pytask/click.py +++ b/src/_pytask/click.py @@ -75,7 +75,7 @@ def convert( ParamTypeValue = TypeVar("ParamTypeValue") - class EnumChoice(Choice): + class EnumChoice(Choice): # type: ignore[no-redef, type-arg] def __init__( self, choices: Iterable[ParamTypeValue], case_sensitive: bool = False ) -> None: From 273c770cf4fe5518a4a83b57cf05ef64dd9cf062 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 7 Jun 2025 09:20:59 +0200 Subject: [PATCH 3/9] Fix compat. --- pyproject.toml | 2 +- src/_pytask/click.py | 14 ++++++++------ uv.lock | 34 ++++++++++++++++++---------------- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 10e4e536..5c018f46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ classifiers = [ dynamic = ["version"] dependencies = [ "attrs>=21.3.0", - "click>=8.1.8,<8.2.0", + "click>=8.1.8,!=8.2.0", "click-default-group>=1.2.4", "networkx>=2.4.0", "optree>=0.9.0", diff --git a/src/_pytask/click.py b/src/_pytask/click.py index 51f6b383..91ed7a72 100644 --- a/src/_pytask/click.py +++ b/src/_pytask/click.py @@ -39,7 +39,7 @@ if importlib.metadata.version("click") < "8.2": from click.parser import split_opt - class EnumChoice(Choice): # type: ignore[type-arg] + class EnumChoice(Choice): """An enum-based choice type. The implementation is copied from https://github.com/pallets/click/pull/2210 and @@ -71,15 +71,17 @@ def convert( return self.enum_type(value) else: - from click.parser import _split_opt as split_opt + from click.parser import ( # type: ignore[attr-defined, no-redef] + _split_opt as split_opt, + ) ParamTypeValue = TypeVar("ParamTypeValue") - class EnumChoice(Choice): # type: ignore[no-redef, type-arg] + class EnumChoice(Choice): # type: ignore[no-redef] def __init__( self, choices: Iterable[ParamTypeValue], case_sensitive: bool = False ) -> None: - super().__init__(choices=choices, case_sensitive=case_sensitive) + super().__init__(choices=choices, case_sensitive=case_sensitive) # type: ignore[arg-type] class _OptionHighlighter(RegexHighlighter): @@ -260,7 +262,7 @@ def _print_options(group_or_command: Command | DefaultGroup, ctx: Context) -> No if param.metavar: opt2 += Text(f" {param.metavar}", style="metavar") elif isinstance(param.type, click.Choice): - choices = "[" + "|".join([str(c.value) for c in param.type.choices]) + "]" + choices = "[" + "|".join([str(c.value) for c in param.type.choices]) + "]" # type: ignore[attr-defined] opt2 += Text(f" {choices}", style="metavar", overflow="fold") help_text = _format_help_text(param, ctx) @@ -338,7 +340,7 @@ def _format_help_text( # noqa: C901, PLR0912, PLR0915 elif param.is_bool_flag and param.secondary_opts: # type: ignore[attr-defined] # For boolean flags that have distinct True/False opts, # use the opt without prefix instead of the value. - default_string = split_opt( # type: ignore[operator] + default_string = split_opt( (param.opts if param.default else param.secondary_opts)[0] )[1] elif ( diff --git a/uv.lock b/uv.lock index 5591300d..d7d11103 100644 --- a/uv.lock +++ b/uv.lock @@ -3470,6 +3470,7 @@ test = [ { name = "deepdiff" }, { name = "nbmake" }, { name = "pexpect" }, + { name = "pygments" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-xdist" }, @@ -3483,16 +3484,16 @@ typing = [ [package.metadata] requires-dist = [ { name = "attrs", specifier = ">=21.3.0" }, - { name = "click", specifier = ">=8.1.8,<8.2.0" }, + { name = "click", specifier = ">=8.1.8,!=8.2.0" }, { name = "click-default-group", specifier = ">=1.2.4" }, - { name = "networkx", specifier = ">=3.0.0" }, + { name = "networkx", specifier = ">=2.4.0" }, { name = "optree", specifier = ">=0.9.0" }, { name = "packaging", specifier = ">=23.0.0" }, { name = "pluggy", specifier = ">=1.3.0" }, { name = "rich", specifier = ">=13.8.0" }, - { name = "sqlalchemy", specifier = ">=2.0.0" }, + { name = "sqlalchemy", specifier = ">=2.0.31" }, { name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=1" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'", specifier = ">=4.5.0" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'", specifier = ">=4.8.0" }, { name = "universal-pathlib", specifier = ">=0.2.2" }, ] @@ -3502,29 +3503,30 @@ docs = [ { name = "furo", specifier = ">=2024.8.6" }, { name = "ipython", specifier = ">=8.13.2" }, { name = "matplotlib", specifier = ">=3.5.0" }, - { name = "myst-nb" }, - { name = "myst-parser" }, + { name = "myst-nb", specifier = ">=1.2.0" }, + { name = "myst-parser", specifier = ">=3.0.0" }, { name = "sphinx", specifier = ">=7.0.0" }, - { name = "sphinx-click" }, - { name = "sphinx-copybutton" }, + { name = "sphinx-click", specifier = ">=6.0.0" }, + { name = "sphinx-copybutton", specifier = ">=0.5.2" }, { name = "sphinx-design", specifier = ">=0.3" }, - { name = "sphinx-toolbox" }, - { name = "sphinxext-opengraph" }, + { name = "sphinx-toolbox", specifier = ">=4.0.0" }, + { name = "sphinxext-opengraph", specifier = ">=0.10.0" }, ] plugin-list = [ - { name = "httpx" }, + { name = "httpx", specifier = ">=0.27.0" }, { name = "tabulate", extras = ["widechars"], specifier = ">=0.9.0" }, - { name = "tqdm" }, + { name = "tqdm", specifier = ">=4.66.3" }, ] test = [ { name = "aiohttp", specifier = ">=3.11.0" }, { name = "cloudpickle", specifier = ">=3.0.0" }, { name = "coiled", specifier = ">=1.42.0" }, - { name = "deepdiff" }, - { name = "nbmake" }, - { name = "pexpect" }, + { name = "deepdiff", specifier = ">=7.0.0" }, + { name = "nbmake", specifier = ">=1.5.5" }, + { name = "pexpect", specifier = ">=4.9.0" }, + { name = "pygments", specifier = ">=2.18.0" }, { name = "pytest", specifier = ">=8.4.0" }, - { name = "pytest-cov" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, { name = "pytest-xdist", specifier = ">=3.6.1" }, { name = "syrupy", specifier = ">=4.5.0" }, ] From 0776acbd1b129ce4eb07fadd2e97b991a2c34b40 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 7 Jun 2025 09:29:50 +0200 Subject: [PATCH 4/9] Fix error. --- src/_pytask/click.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytask/click.py b/src/_pytask/click.py index 91ed7a72..175bb933 100644 --- a/src/_pytask/click.py +++ b/src/_pytask/click.py @@ -262,7 +262,7 @@ def _print_options(group_or_command: Command | DefaultGroup, ctx: Context) -> No if param.metavar: opt2 += Text(f" {param.metavar}", style="metavar") elif isinstance(param.type, click.Choice): - choices = "[" + "|".join([str(c.value) for c in param.type.choices]) + "]" # type: ignore[attr-defined] + choices = "[" + "|".join(param.type.choices) + "]" # type: ignore[attr-defined] opt2 += Text(f" {choices}", style="metavar", overflow="fold") help_text = _format_help_text(param, ctx) From daa2fe849ab95f51f226197026491050a020d89a Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 7 Jun 2025 09:36:03 +0200 Subject: [PATCH 5/9] Fix type issue. --- src/_pytask/click.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytask/click.py b/src/_pytask/click.py index 175bb933..7da27f08 100644 --- a/src/_pytask/click.py +++ b/src/_pytask/click.py @@ -262,7 +262,7 @@ def _print_options(group_or_command: Command | DefaultGroup, ctx: Context) -> No if param.metavar: opt2 += Text(f" {param.metavar}", style="metavar") elif isinstance(param.type, click.Choice): - choices = "[" + "|".join(param.type.choices) + "]" # type: ignore[attr-defined] + choices = "[" + "|".join(param.type.choices) + "]" opt2 += Text(f" {choices}", style="metavar", overflow="fold") help_text = _format_help_text(param, ctx) From 69bb6a7c9a3db83cda354d2d779658302c1990a4 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 7 Jun 2025 09:40:13 +0200 Subject: [PATCH 6/9] Add type-check to pre-commit hooks. --- .pre-commit-config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 41192f1c..4ceb0aea 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -64,3 +64,10 @@ repos: - id: check-hooks-apply - id: check-useless-excludes # - id: identity # Prints all files passed to pre-commits. Debugging. +- repo: local + hooks: + - id: type-checking + name: type-checking + entry: uv run --group typing mypy + language: system + pass_filenames: false From a6417f611f2519e24ebf62cb34eb6c62b76db0b1 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 7 Jun 2025 09:42:53 +0200 Subject: [PATCH 7/9] To changes: --- docs/source/changes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/changes.md b/docs/source/changes.md index d53d7d24..0e2aa95a 100644 --- a/docs/source/changes.md +++ b/docs/source/changes.md @@ -5,6 +5,12 @@ chronological order. Releases follow [semantic versioning](https://semver.org/) releases are available on [PyPI](https://pypi.org/project/pytask) and [Anaconda.org](https://anaconda.org/conda-forge/pytask). +## 0.5.4 - 2025-xx-xx + +- {pull}`676` ensures compatibility with click >8.2.0. +- {pull}`680` uses uv everywhere. +- {pull}`684` adds tests for lowest and highest dependency resolutions. + ## 0.5.3 - 2025-05-16 - {pull}`650` allows to identify from which data catalog a node is coming from. Thanks From 8ed43db59d36dc9701e2ea54fd02c0d831fcbb83 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 7 Jun 2025 09:44:01 +0200 Subject: [PATCH 8/9] Skip type-checking. --- .pre-commit-config.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4ceb0aea..b9ccf5ca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,6 @@ +ci: + skip: [type-checking] + repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 From e0ed8790cd7321f82d1022c88e6e11ed69bde01f Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 7 Jun 2025 09:49:04 +0200 Subject: [PATCH 9/9] Fix docs. --- .../how_to_guides/functional_interface.ipynb | 137 +++++++++--------- pyproject.toml | 1 + uv.lock | 2 + 3 files changed, 72 insertions(+), 68 deletions(-) diff --git a/docs/source/how_to_guides/functional_interface.ipynb b/docs/source/how_to_guides/functional_interface.ipynb index d4b657ef..76b6eedc 100644 --- a/docs/source/how_to_guides/functional_interface.ipynb +++ b/docs/source/how_to_guides/functional_interface.ipynb @@ -72,11 +72,11 @@ { "data": { "text/html": [ - "
────────────────────────────────────────────── Start pytask session ───────────────────────────────────────────────\n",
+       "
────────────────────────────────────────────── Start pytask session ───────────────────────────────────────────────\n",
        "
\n" ], "text/plain": [ - "────────────────────────────────────────────── Start pytask session ───────────────────────────────────────────────\n" + "\u001b[39m────────────────────────────────────────────── \u001b[0mStart pytask session\u001b[39m ───────────────────────────────────────────────\u001b[0m\n" ] }, "metadata": {}, @@ -85,11 +85,11 @@ { "data": { "text/html": [ - "
Platform: linux -- Python 3.11.5, pytask 0.4.0, pluggy 1.3.0\n",
+       "
Platform: darwin -- Python 3.12.2, pytask 0.5.4.dev16+g8ed43db.d20250607, pluggy 1.6.0\n",
        "
\n" ], "text/plain": [ - "Platform: linux -- Python 3.11.5, pytask 0.4.0rc3.dev4+gfb5a25d.d20230930, pluggy 1.3.0\n" + "Platform: darwin -- Python \u001b[1;36m3.12\u001b[0m.\u001b[1;36m2\u001b[0m, pytask \u001b[1;36m0.5\u001b[0m.\u001b[1;36m4.\u001b[0mdev16+g8ed43db.d20250607, pluggy \u001b[1;36m1.6\u001b[0m.\u001b[1;36m0\u001b[0m\n" ] }, "metadata": {}, @@ -98,11 +98,11 @@ { "data": { "text/html": [ - "
Root: /home/tobia/git/pytask\n",
+       "
Root: /Users/tobiasr/git/pytask\n",
        "
\n" ], "text/plain": [ - "Root: /home/tobia/git/pytask\n" + "Root: \u001b[35m/Users/tobiasr/git/\u001b[0m\u001b[95mpytask\u001b[0m\n" ] }, "metadata": {}, @@ -125,7 +125,7 @@ "
\n" ], "text/plain": [ - "Collected 3 tasks.\n" + "Collected \u001b[1;36m3\u001b[0m tasks.\n" ] }, "metadata": {}, @@ -147,7 +147,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "d684c1a12c55404f8acd8c563bd99577", + "model_id": "59c1696ceef94890b5833506da638d2d", "version_major": 2, "version_minor": 0 }, @@ -174,19 +174,19 @@ "
╭─────────────────────────┬─────────╮\n",
        "│ Task                     Outcome │\n",
        "├─────────────────────────┼─────────┤\n",
-       "│ task_create_first_file .       │\n",
-       "│ task_create_second_file.       │\n",
-       "│ task_merge_files       .       │\n",
+       "│ task_create_first_file .       │\n",
+       "│ task_create_second_file.       │\n",
+       "│ task_merge_files       .       │\n",
        "╰─────────────────────────┴─────────╯\n",
        "
\n" ], "text/plain": [ "╭─────────────────────────┬─────────╮\n", - "│ Task │ Outcome │\n", + "│\u001b[1m \u001b[0m\u001b[1mTask \u001b[0m\u001b[1m \u001b[0m│\u001b[1m \u001b[0m\u001b[1mOutcome\u001b[0m\u001b[1m \u001b[0m│\n", "├─────────────────────────┼─────────┤\n", - "│ task_create_first_file │ . │\n", - "│ task_create_second_file │ . │\n", - "│ task_merge_files │ . │\n", + "│ \u001b]8;id=761467;file:///None\u001b\\task_create_first_file \u001b]8;;\u001b\\ │ \u001b[38;2;19;124;57m. \u001b[0m │\n", + "│ \u001b]8;id=184911;file:///None\u001b\\task_create_second_file\u001b]8;;\u001b\\ │ \u001b[38;2;19;124;57m. \u001b[0m │\n", + "│ \u001b]8;id=880445;file:///None\u001b\\task_merge_files \u001b]8;;\u001b\\ │ \u001b[38;2;19;124;57m. \u001b[0m │\n", "╰─────────────────────────┴─────────╯\n" ] }, @@ -213,7 +213,7 @@ "
\n" ], "text/plain": [ - "───────────────────────────────────────────────────────────────────────────────────────────────────────────────────\n" + "\u001b[2m───────────────────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\n" ] }, "metadata": {}, @@ -222,17 +222,17 @@ { "data": { "text/html": [ - "
╭─────────── Summary ────────────╮\n",
+       "
╭─────────── Summary ────────────╮\n",
        "  3  Collected tasks            \n",
        "  3  Succeeded        (100.0%)  \n",
        "╰────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "╭─────────── Summary ────────────╮\n", - "│ 3 Collected tasks │\n", - "│ 3 Succeeded (100.0%) │\n", - "╰────────────────────────────────╯\n" + "\u001b[38;2;19;124;57m╭─\u001b[0m\u001b[38;2;19;124;57m──────────\u001b[0m\u001b[1;38;2;242;242;242m Summary \u001b[0m\u001b[38;2;19;124;57m───────────\u001b[0m\u001b[38;2;19;124;57m─╮\u001b[0m\n", + "\u001b[38;2;19;124;57m│\u001b[0m \u001b[38;2;242;242;242m \u001b[0m\u001b[38;2;242;242;242m3\u001b[0m\u001b[38;2;242;242;242m \u001b[0m\u001b[38;2;242;242;242m \u001b[0m\u001b[38;2;242;242;242mCollected tasks\u001b[0m\u001b[38;2;242;242;242m \u001b[0m\u001b[38;2;242;242;242m \u001b[0m\u001b[38;2;242;242;242m \u001b[0m\u001b[38;2;242;242;242m \u001b[0m \u001b[38;2;19;124;57m│\u001b[0m\n", + "\u001b[38;2;19;124;57m│\u001b[0m \u001b[38;2;242;242;242;48;2;19;124;57m \u001b[0m\u001b[38;2;242;242;242;48;2;19;124;57m3\u001b[0m\u001b[38;2;242;242;242;48;2;19;124;57m \u001b[0m\u001b[38;2;242;242;242;48;2;19;124;57m \u001b[0m\u001b[38;2;242;242;242;48;2;19;124;57mSucceeded \u001b[0m\u001b[38;2;242;242;242;48;2;19;124;57m \u001b[0m\u001b[38;2;242;242;242;48;2;19;124;57m \u001b[0m\u001b[38;2;242;242;242;48;2;19;124;57m(100.0%)\u001b[0m\u001b[38;2;242;242;242;48;2;19;124;57m \u001b[0m \u001b[38;2;19;124;57m│\u001b[0m\n", + "\u001b[38;2;19;124;57m╰────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -241,11 +241,11 @@ { "data": { "text/html": [ - "
──────────────────────────────────────────── Succeeded in 0.19 seconds ────────────────────────────────────────────\n",
+       "
──────────────────────────────────────────── Succeeded in 0.1 seconds ─────────────────────────────────────────────\n",
        "
\n" ], "text/plain": [ - "──────────────────────────────────────────── Succeeded in 0.19 seconds ────────────────────────────────────────────\n" + "\u001b[38;2;19;124;57m──────────────────────────────────────────── \u001b[0m\u001b[38;2;19;124;57mSucceeded in 0.1 seconds\u001b[0m\u001b[38;2;19;124;57m ─────────────────────────────────────────────\u001b[0m\n" ] }, "metadata": {}, @@ -273,7 +273,7 @@ { "data": { "text/plain": [ - "Session(config={'pm': , 'markers': {'depends_on': 'Add dependencies to a task. See this tutorial for more information: [link https://bit.ly/3JlxylS]https://bit.ly/3JlxylS[/].', 'filterwarnings': 'Add a filter for a warning to a task.', 'persist': 'Prevent execution of a task if all products exist and even if something has changed (dependencies, source file, products). This decorator might be useful for expensive tasks where only the formatting of the file has changed. The state of the files which have changed will also be remembered and another run will skip the task with success.', 'produces': 'Add products to a task. See this tutorial for more information: [link https://bit.ly/3JlxylS]https://bit.ly/3JlxylS[/].', 'skip': 'Skip a task and all its dependent tasks.', 'skip_ancestor_failed': 'Internal decorator applied to tasks if any of its preceding tasks failed.', 'skip_unchanged': 'Internal decorator applied to tasks which have already been executed and have not been changed.', 'skipif': 'Skip a task and all its dependent tasks if a condition is met.', 'task': 'Mark a function as a task regardless of its name. Or mark tasks which are repeated in a loop. See this tutorial for more information: [link https://bit.ly/3DWrXS3]https://bit.ly/3DWrXS3[/].', 'try_first': 'Try to execute a task a early as possible.', 'try_last': 'Try to execute a task a late as possible.'}, 'config': None, 'database_url': sqlite:////home/tobia/git/pytask/.pytask/.pytask.sqlite3, 'editor_url_scheme': 'file', 'export': <_ExportFormats.NO: 'no'>, 'ignore': ['.codecov.yml', '.gitignore', '.pre-commit-config.yaml', '.readthedocs.yml', '.readthedocs.yaml', 'readthedocs.yml', 'readthedocs.yaml', 'environment.yml', 'pyproject.toml', 'tox.ini', '.git/*', '.venv/*', '*.egg-info/*', '.ipynb_checkpoints/*', '.mypy_cache/*', '.nox/*', '.tox/*', '_build/*', '__pycache__/*', 'build/*', 'dist/*', 'pytest_cache/*'], 'paths': [], 'layout': 'dot', 'output_path': 'dag.pdf', 'rank_direction': <_RankDirection.TB: 'TB'>, 'expression': '', 'marker_expression': '', 'nodes': False, 'strict_markers': False, 'directories': False, 'exclude': [None, '.git/*'], 'mode': <_CleanMode.DRY_RUN: 'dry-run'>, 'quiet': False, 'capture': , 'debug_pytask': False, 'disable_warnings': False, 'dry_run': False, 'force': False, 'max_failures': inf, 'n_entries_in_table': 15, 'pdb': False, 'pdbcls': None, 's': False, 'show_capture': True, 'show_errors_immediately': False, 'show_locals': False, 'show_traceback': True, 'sort_table': True, 'trace': False, 'verbose': 1, 'stop_after_first_failure': False, 'check_casing_of_paths': True, 'pdb_cls': '', 'tasks': [, , at 0x7f3c1b407d80>], 'task_files': ['task_*.py'], 'command': 'build', 'root': PosixPath('/home/tobia/git/pytask'), 'filterwarnings': []}, hook=, collection_reports=[CollectionReport(outcome=, node=TaskWithoutPath(name='task_create_first_file', function=, depends_on={}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/first.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/first.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.0767577, 1696055304.077608)}), exc_info=None), CollectionReport(outcome=, node=TaskWithoutPath(name='task_merge_files', function=, depends_on={'first': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/first.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/first.txt')), 'second': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/second.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/second.txt'))}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/hello_world.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/hello_world.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.123595, 1696055304.1244528)}), exc_info=None), CollectionReport(outcome=, node=TaskWithoutPath(name='task_create_second_file', function= at 0x7f3c1b407d80>, depends_on={}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/second.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/second.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.025182, 1696055304.0267167)}), exc_info=None)], tasks=[TaskWithoutPath(name='task_create_first_file', function=, depends_on={}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/first.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/first.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.0767577, 1696055304.077608)}), TaskWithoutPath(name='task_merge_files', function=, depends_on={'first': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/first.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/first.txt')), 'second': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/second.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/second.txt'))}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/hello_world.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/hello_world.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.123595, 1696055304.1244528)}), TaskWithoutPath(name='task_create_second_file', function= at 0x7f3c1b407d80>, depends_on={}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/second.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/second.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.025182, 1696055304.0267167)})], dag=, resolving_dependencies_report=None, execution_reports=[ExecutionReport(task=TaskWithoutPath(name='task_create_second_file', function= at 0x7f3c1b407d80>, depends_on={}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/second.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/second.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.025182, 1696055304.0267167)}), outcome=, exc_info=None, sections=[]), ExecutionReport(task=TaskWithoutPath(name='task_create_first_file', function=, depends_on={}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/first.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/first.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.0767577, 1696055304.077608)}), outcome=, exc_info=None, sections=[]), ExecutionReport(task=TaskWithoutPath(name='task_merge_files', function=, depends_on={'first': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/first.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/first.txt')), 'second': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/second.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/second.txt'))}, produces={'return': PathNode(name='/home/tobia/git/pytask/docs/source/how_to_guides/hello_world.txt', path=PosixPath('/home/tobia/git/pytask/docs/source/how_to_guides/hello_world.txt'))}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'duration': (1696055304.123595, 1696055304.1244528)}), outcome=, exc_info=None, sections=[])], exit_code=, collection_start=1696055303.989013, collection_end=1696055303.9959698, execution_start=1696055304.0121965, execution_end=1696055304.207084, n_tasks_failed=0, scheduler=TopologicalSorter(dag=, priorities={'task_create_first_file': 0, 'task_merge_files': 0, 'task_create_second_file': 0}, _dag_backup=, _is_prepared=True, _nodes_out=set()), should_stop=False, warnings=[])" + "Session(config={'pm': , 'markers': {'filterwarnings': 'Add a filter for a warning to a task.', 'persist': 'Prevent execution of a task if all products exist and even if something has changed (dependencies, source file, products). This decorator might be useful for expensive tasks where only the formatting of the file has changed. The state of the files which have changed will also be remembered and another run will skip the task with success.', 'skip': 'Skip a task and all its dependent tasks.', 'skip_ancestor_failed': 'Internal decorator applied to tasks if any of its preceding tasks failed.', 'skip_unchanged': 'Internal decorator applied to tasks which have already been executed and have not been changed.', 'skipif': 'Skip a task and all its dependent tasks if a condition is met.', 'task': 'Mark a function as a task regardless of its name. Or mark tasks which are repeated in a loop. See this tutorial for more information: [link https://bit.ly/3DWrXS3]https://bit.ly/3DWrXS3[/].', 'try_first': 'Try to execute a task a early as possible.', 'try_last': 'Try to execute a task a late as possible.'}, 'config': None, 'database_url': sqlite:////Users/tobiasr/git/pytask/.pytask/pytask.sqlite3, 'editor_url_scheme': 'file', 'export': <_ExportFormats.NO: 'no'>, 'hook_module': None, 'ignore': ['.codecov.yml', '.gitignore', '.pre-commit-config.yaml', '.readthedocs.yml', '.readthedocs.yaml', 'readthedocs.yml', 'readthedocs.yaml', 'environment.yml', 'pyproject.toml', 'setup.cfg', 'tox.ini', '.git/*', '.venv/*', '.pixi/*', '*.egg-info/*', '.ipynb_checkpoints/*', '.mypy_cache/*', '.nox/*', '.tox/*', '_build/*', '__pycache__/*', 'build/*', 'dist/*', 'pytest_cache/*'], 'paths': [], 'layout': 'dot', 'output_path': 'dag.pdf', 'rank_direction': <_RankDirection.TB: 'TB'>, 'expression': '', 'marker_expression': '', 'nodes': False, 'strict_markers': False, 'directories': False, 'exclude': [None, '.git/*', '/Users/tobiasr/git/pytask/.pytask/*'], 'mode': <_CleanMode.DRY_RUN: 'dry-run'>, 'quiet': False, 'capture': , 'debug_pytask': False, 'disable_warnings': False, 'dry_run': False, 'force': False, 'max_failures': inf, 'n_entries_in_table': 15, 'pdb': False, 'pdbcls': None, 's': False, 'show_capture': , 'show_errors_immediately': False, 'show_locals': False, 'show_traceback': True, 'sort_table': True, 'trace': False, 'verbose': 1, 'stop_after_first_failure': False, 'check_casing_of_paths': True, 'pdb_cls': '', 'tasks': [, , at 0x115ac0a40>], 'task_files': ('task_*.py',), 'command': 'build', 'root': PosixPath('/Users/tobiasr/git/pytask'), 'filterwarnings': []}, collection_reports=[CollectionReport(outcome=, node=TaskWithoutPath(name='task_create_first_file', function=, depends_on={}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/first.txt'), name='pytask/docs/source/how_to_guides/first.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('768f2f6b-85b9-4ed4-8b08-22e66ec68143'), 'after': [], 'is_generator': False, 'duration': (1749282510.968756, 1749282510.969585)}), exc_info=None), CollectionReport(outcome=, node=TaskWithoutPath(name='task_merge_files', function=, depends_on={'first': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/first.txt'), name='pytask/docs/source/how_to_guides/first.txt', attributes={}), 'second': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/second.txt'), name='pytask/docs/source/how_to_guides/second.txt', attributes={})}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/hello_world.txt'), name='pytask/docs/source/how_to_guides/hello_world.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('2fe578c8-ab38-4d0d-bb34-e12df5b5975b'), 'after': [], 'is_generator': False, 'duration': (1749282511.055661, 1749282511.056195)}), exc_info=None), CollectionReport(outcome=, node=TaskWithoutPath(name='task_create_second_file', function= at 0x115ac0a40>, depends_on={}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/second.txt'), name='pytask/docs/source/how_to_guides/second.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('d096742c-b6fd-4b68-9b43-ae5d3c775001'), 'after': [], 'is_generator': False, 'duration': (1749282511.046389, 1749282511.046774)}), exc_info=None)], dag=, hook=, tasks=[TaskWithoutPath(name='task_create_first_file', function=, depends_on={}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/first.txt'), name='pytask/docs/source/how_to_guides/first.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('768f2f6b-85b9-4ed4-8b08-22e66ec68143'), 'after': [], 'is_generator': False, 'duration': (1749282510.968756, 1749282510.969585)}), TaskWithoutPath(name='task_merge_files', function=, depends_on={'first': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/first.txt'), name='pytask/docs/source/how_to_guides/first.txt', attributes={}), 'second': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/second.txt'), name='pytask/docs/source/how_to_guides/second.txt', attributes={})}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/hello_world.txt'), name='pytask/docs/source/how_to_guides/hello_world.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('2fe578c8-ab38-4d0d-bb34-e12df5b5975b'), 'after': [], 'is_generator': False, 'duration': (1749282511.055661, 1749282511.056195)}), TaskWithoutPath(name='task_create_second_file', function= at 0x115ac0a40>, depends_on={}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/second.txt'), name='pytask/docs/source/how_to_guides/second.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('d096742c-b6fd-4b68-9b43-ae5d3c775001'), 'after': [], 'is_generator': False, 'duration': (1749282511.046389, 1749282511.046774)})], dag_report=None, execution_reports=[ExecutionReport(task=TaskWithoutPath(name='task_create_first_file', function=, depends_on={}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/first.txt'), name='pytask/docs/source/how_to_guides/first.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('768f2f6b-85b9-4ed4-8b08-22e66ec68143'), 'after': [], 'is_generator': False, 'duration': (1749282510.968756, 1749282510.969585)}), outcome=, exc_info=None, sections=[]), ExecutionReport(task=TaskWithoutPath(name='task_create_second_file', function= at 0x115ac0a40>, depends_on={}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/second.txt'), name='pytask/docs/source/how_to_guides/second.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('d096742c-b6fd-4b68-9b43-ae5d3c775001'), 'after': [], 'is_generator': False, 'duration': (1749282511.046389, 1749282511.046774)}), outcome=, exc_info=None, sections=[]), ExecutionReport(task=TaskWithoutPath(name='task_merge_files', function=, depends_on={'first': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/first.txt'), name='pytask/docs/source/how_to_guides/first.txt', attributes={}), 'second': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/second.txt'), name='pytask/docs/source/how_to_guides/second.txt', attributes={})}, produces={'return': PathNode(path=PosixPath('/Users/tobiasr/git/pytask/docs/source/how_to_guides/hello_world.txt'), name='pytask/docs/source/how_to_guides/hello_world.txt', attributes={})}, markers=[Mark(name='task', args=(), kwargs={})], report_sections=[], attributes={'collection_id': UUID('2fe578c8-ab38-4d0d-bb34-e12df5b5975b'), 'after': [], 'is_generator': False, 'duration': (1749282511.055661, 1749282511.056195)}), outcome=, exc_info=None, sections=[])], exit_code=, collection_start=1749282510.959347, collection_end=1749282510.9617531, execution_start=1749282510.962504, execution_end=1749282511.06384, n_tasks_failed=0, scheduler=TopologicalSorter(dag=, priorities={'82d6a7ce01a2a50d5d4bd5081d662df92b8c500fbc172f94fb026c9d1d4ebc4a': 0, '45a637ca3cc7aa973d4b315cc1bef02217b79918357fd35c6fa61f4e2d2f9948': 0, '2a06f358fc8e621754c133af76f5ac1b3e8ad5172b5803823cb264b30ea5d829': 0}, _nodes_processing=set(), _nodes_done={'2a06f358fc8e621754c133af76f5ac1b3e8ad5172b5803823cb264b30ea5d829', '82d6a7ce01a2a50d5d4bd5081d662df92b8c500fbc172f94fb026c9d1d4ebc4a', '45a637ca3cc7aa973d4b315cc1bef02217b79918357fd35c6fa61f4e2d2f9948'}), should_stop=False, warnings=[])" ] }, "execution_count": 4, @@ -303,41 +303,41 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001b[0;31mSignature:\u001b[0m\n", - "\u001b[0mpytask\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbuild\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mcapture\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m\"Literal['fd', 'no', 'sys', 'tee-sys'] | CaptureMethod\"\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m<\u001b[0m\u001b[0mCaptureMethod\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mNO\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'no'\u001b[0m\u001b[0;34m>\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mcheck_casing_of_paths\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mconfig\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'Path | None'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mdatabase_url\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'str'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mdebug_pytask\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mdisable_warnings\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mdry_run\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0meditor_url_scheme\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m\"Literal['no_link', 'file', 'vscode', 'pycharm'] | str\"\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'file'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mexpression\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'str'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mforce\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mignore\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'Iterable[str]'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mmarker_expression\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'str'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mmax_failures\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'float'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minf\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mn_entries_in_table\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'int'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m15\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mpaths\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'str | Path | Iterable[str | Path]'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mpdb\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mpdb_cls\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'str'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0ms\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mshow_capture\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mshow_errors_immediately\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mshow_locals\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mshow_traceback\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0msort_table\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mstop_after_first_failure\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mstrict_markers\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mtasks\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'Callable[..., Any] | PTask | Iterable[Callable[..., Any] | PTask]'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mtask_files\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'str | Iterable[str]'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'task_*.py'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mtrace\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'bool'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mverbose\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'int'\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'Any'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0;34m'Session'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mDocstring:\u001b[0m\n", + "\u001b[31mSignature:\u001b[39m\n", + "pytask.build(\n", + " *,\n", + " capture: \u001b[33m\"Literal['fd', 'no', 'sys', 'tee-sys'] | CaptureMethod\"\u001b[39m = ,\n", + " check_casing_of_paths: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mTrue\u001b[39;00m,\n", + " config: \u001b[33m'Path | None'\u001b[39m = \u001b[38;5;28;01mNone\u001b[39;00m,\n", + " database_url: \u001b[33m'str'\u001b[39m = \u001b[33m''\u001b[39m,\n", + " debug_pytask: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " disable_warnings: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " dry_run: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " editor_url_scheme: \u001b[33m\"Literal['no_link', 'file', 'vscode', 'pycharm'] | str\"\u001b[39m = \u001b[33m'file'\u001b[39m,\n", + " expression: \u001b[33m'str'\u001b[39m = \u001b[33m''\u001b[39m,\n", + " force: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " ignore: \u001b[33m'Iterable[str]'\u001b[39m = (),\n", + " marker_expression: \u001b[33m'str'\u001b[39m = \u001b[33m''\u001b[39m,\n", + " max_failures: \u001b[33m'float'\u001b[39m = inf,\n", + " n_entries_in_table: \u001b[33m'int'\u001b[39m = \u001b[32m15\u001b[39m,\n", + " paths: \u001b[33m'Path | Iterable[Path]'\u001b[39m = (),\n", + " pdb: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " pdb_cls: \u001b[33m'str'\u001b[39m = \u001b[33m''\u001b[39m,\n", + " s: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " show_capture: \u001b[33m\"Literal['no', 'stdout', 'stderr', 'all'] | ShowCapture\"\u001b[39m = ,\n", + " show_errors_immediately: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " show_locals: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " show_traceback: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mTrue\u001b[39;00m,\n", + " sort_table: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mTrue\u001b[39;00m,\n", + " stop_after_first_failure: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " strict_markers: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " tasks: \u001b[33m'Callable[..., Any] | PTask | Iterable[Callable[..., Any] | PTask]'\u001b[39m = (),\n", + " task_files: \u001b[33m'Iterable[str]'\u001b[39m = (\u001b[33m'task_*.py'\u001b[39m,),\n", + " trace: \u001b[33m'bool'\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n", + " verbose: \u001b[33m'int'\u001b[39m = \u001b[32m1\u001b[39m,\n", + " **kwargs: \u001b[33m'Any'\u001b[39m,\n", + ") -> \u001b[33m'Session'\u001b[39m\n", + "\u001b[31mDocstring:\u001b[39m\n", "Run pytask.\n", "\n", "This is the main command to run pytask which usually receives kwargs from the\n", @@ -362,14 +362,14 @@ " Whether a dry-run should be performed that shows which tasks need to be rerun.\n", "editor_url_scheme\n", " An url scheme that allows to click on task names, node names and filenames and\n", - " jump right into you preferred edior to the right line.\n", + " jump right into you preferred editor to the right line.\n", "expression\n", " Same as ``-k`` on the command line. Select tasks via expressions on task ids.\n", "force\n", " Run tasks even though they would be skipped since nothing has changed.\n", "ignore\n", - " A pattern to ignore files or directories. Refer to ``pathlib.Path.match``\n", - " for more info.\n", + " A pattern to ignore files or directories. Refer to ``pathlib.Path.match`` for\n", + " more info.\n", "marker_expression\n", " Same as ``-m`` on the command line. Select tasks via marker expressions.\n", "max_failures\n", @@ -386,7 +386,7 @@ " Start a custom debugger on errors. For example:\n", " ``--pdbcls=IPython.terminal.debugger:TerminalPdb``\n", "s\n", - " Shortcut for ``pytask.build(capture\"no\")``.\n", + " Shortcut for ``capture=\"no\"``.\n", "show_capture\n", " Choose which captured output should be shown for failed tasks.\n", "show_errors_immediately\n", @@ -402,7 +402,8 @@ "strict_markers\n", " Raise errors for unknown markers.\n", "tasks\n", - " A task or a collection of tasks that is passed to ``pytask.build(tasks=...)``.\n", + " A task or a collection of tasks which can be callables or instances following\n", + " {class}`~pytask.PTask`.\n", "task_files\n", " A pattern to describe modules that contain tasks.\n", "trace\n", @@ -414,8 +415,8 @@ "-------\n", "session : pytask.Session\n", " The session captures all the information of the current run.\n", - "\u001b[0;31mFile:\u001b[0m ~/git/pytask/src/_pytask/build.py\n", - "\u001b[0;31mType:\u001b[0m function" + "\u001b[31mFile:\u001b[39m ~/git/pytask/src/_pytask/build.py\n", + "\u001b[31mType:\u001b[39m function" ] } ], @@ -437,7 +438,7 @@ ], "metadata": { "kernelspec": { - "display_name": "pytask", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -451,7 +452,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.12.2" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index 5c018f46..042f00bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ dev = ["pygraphviz>=1.11;platform_system=='Linux'"] docs = [ "furo>=2024.8.6", "ipython>=8.13.2", + "ipywidgets>=8.1.6", "matplotlib>=3.5.0", "myst-parser>=3.0.0", "myst-nb>=1.2.0", diff --git a/uv.lock b/uv.lock index d7d11103..86aff736 100644 --- a/uv.lock +++ b/uv.lock @@ -3444,6 +3444,7 @@ docs = [ { name = "ipython", version = "8.18.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "ipython", version = "8.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "ipython", version = "9.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "ipywidgets" }, { name = "matplotlib", version = "3.9.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "matplotlib", version = "3.10.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, { name = "myst-nb" }, @@ -3502,6 +3503,7 @@ dev = [{ name = "pygraphviz", marker = "sys_platform == 'linux'", specifier = "> docs = [ { name = "furo", specifier = ">=2024.8.6" }, { name = "ipython", specifier = ">=8.13.2" }, + { name = "ipywidgets", specifier = ">=8.1.6" }, { name = "matplotlib", specifier = ">=3.5.0" }, { name = "myst-nb", specifier = ">=1.2.0" }, { name = "myst-parser", specifier = ">=3.0.0" },