From b4f7bafe4590649f11f7401ba7579427e1219296 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Fri, 3 Oct 2025 10:19:07 +0200 Subject: [PATCH 1/3] Fix --capture tee-sys. --- justfile | 8 ++++---- src/_pytask/click.py | 30 ++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/justfile b/justfile index 5dd930e2..a35931aa 100644 --- a/justfile +++ b/justfile @@ -3,12 +3,12 @@ install: uv sync --all-groups # Run tests -test: - uv run --group test pytest +test *FLAGS: + uv run --group test pytest {{FLAGS}} # Run tests with coverage -test-cov: - uv run --group test pytest --nbmake --cov=src --cov=tests --cov-report=xml -n auto +test-cov *FLAGS: + uv run --group test pytest --nbmake --cov=src --cov=tests --cov-report=xml -n auto {{FLAGS}} # Run tests with notebook validation test-nb: diff --git a/src/_pytask/click.py b/src/_pytask/click.py index 10a16867..19199303 100644 --- a/src/_pytask/click.py +++ b/src/_pytask/click.py @@ -10,7 +10,6 @@ from typing import TYPE_CHECKING from typing import Any from typing import ClassVar -from typing import TypeVar import click from click import Choice @@ -29,7 +28,6 @@ from _pytask.console import create_panel_title if TYPE_CHECKING: - from collections.abc import Iterable from collections.abc import Sequence @@ -75,13 +73,29 @@ def convert( _split_opt as split_opt, ) - ParamTypeValue = TypeVar("ParamTypeValue") - class EnumChoice(Choice): # type: ignore[no-redef, type-arg, unused-ignore] - def __init__( - self, choices: Iterable[ParamTypeValue], case_sensitive: bool = False - ) -> None: - super().__init__(choices=choices, case_sensitive=case_sensitive) # type: ignore[arg-type, unused-ignore] + """An enum-based choice type for click >= 8.2. + + Extracts values from enum members to use as valid choices. + + """ + + def __init__(self, enum_type: type[Enum], case_sensitive: bool = False) -> 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) class _OptionHighlighter(RegexHighlighter): From 808f0ebfa02f48f3e4f2ba8e87699dad93301c29 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Fri, 3 Oct 2025 10:36:06 +0200 Subject: [PATCH 2/3] Simplify. --- src/_pytask/click.py | 78 +++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/src/_pytask/click.py b/src/_pytask/click.py index 19199303..e52ca571 100644 --- a/src/_pytask/click.py +++ b/src/_pytask/click.py @@ -36,66 +36,40 @@ if importlib.metadata.version("click") < "8.2": from click.parser import split_opt - - class EnumChoice(Choice): # type: ignore[type-arg, unused-ignore] - """An enum-based choice type. - - 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 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 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 ( # type: ignore[attr-defined, no-redef, unused-ignore] _split_opt as split_opt, ) - class EnumChoice(Choice): # type: ignore[no-redef, type-arg, unused-ignore] - """An enum-based choice type for click >= 8.2. - Extracts values from enum members to use as valid choices. +class EnumChoice(Choice): # type: ignore[type-arg, unused-ignore] + """An enum-based choice type. - """ + 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. - def __init__(self, enum_type: type[Enum], case_sensitive: bool = False) -> 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) + 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 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 _OptionHighlighter(RegexHighlighter): From f4cc9b2e62e2c0b6f160c9a8444ce3fb3b7b9f98 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Fri, 3 Oct 2025 10:37:26 +0200 Subject: [PATCH 3/3] To changes. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d6d0b9b..40dbabd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ 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.6 - 2025-xx-xx + +- {pull}`703` fixes {issue}`701` by allowing `--capture tee-sys` again. + ## 0.5.5 - 2025-07-25 - {pull}`692` documents how to use pytask with workspaces.