From 47b95a4132a29488cee5cc2bef1d951f7ca85315 Mon Sep 17 00:00:00 2001 From: Gianluca Gippetto Date: Thu, 7 Sep 2023 23:56:11 +0200 Subject: [PATCH 1/3] Run tests once a week --- .github/workflows/tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 7d384b8..d29e9bb 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -5,6 +5,8 @@ on: tags: [v*] pull_request: workflow_dispatch: + schedule: + - cron: "0 6 * * 7" jobs: tests: From 170d0d3ff7a8ba65dd5d8bf145c623d4e4177e4f Mon Sep 17 00:00:00 2001 From: nue Date: Fri, 10 Nov 2023 10:29:58 +0100 Subject: [PATCH 2/3] Redefine cloup.pass_context so the type of the injected context is cloup.Context (not click.Context) --- cloup/__init__.py | 3 +-- cloup/_context.py | 24 +++++++++++++++++++++++- tox.ini | 4 +++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/cloup/__init__.py b/cloup/__init__.py index eec86e7..0c18ac7 100644 --- a/cloup/__init__.py +++ b/cloup/__init__.py @@ -11,7 +11,6 @@ # decorators confirmation_option, help_option, - pass_context, pass_obj, password_option, version_option, @@ -42,7 +41,7 @@ HelpFormatter, HelpSection, ) -from ._context import Context +from ._context import Context, pass_context from ._params import Argument, Option, argument, option from ._option_groups import ( OptionGroup, diff --git a/cloup/_context.py b/cloup/_context.py index 20fa278..8445192 100644 --- a/cloup/_context.py +++ b/cloup/_context.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import warnings -from typing import Any, Callable, Dict, List, Optional, Type +from typing import Any, Callable, cast, Dict, List, Optional, Type, TypeVar, TYPE_CHECKING +from functools import update_wrapper import click @@ -222,3 +225,22 @@ def settings( dictionary, so that you can be guided by your IDE. """ return pick_non_missing(locals()) + + +if TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = TypeVar("R") + + +def pass_context(f: Callable[te.Concatenate[Context, P], R]) -> Callable[P, R]: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(cast(Context, click.get_current_context()), *args, **kwargs) + + return update_wrapper(new_func, f) diff --git a/tox.ini b/tox.ini index d7ffcae..ac359cd 100644 --- a/tox.ini +++ b/tox.ini @@ -39,7 +39,9 @@ deps = flake8 commands = flake8 cloup tests examples [testenv:mypy] -deps = mypy +deps = + mypy + typing-extensions commands = mypy --strict cloup mypy tests examples From edea710bedcec63b0a7e736baf341c2bc7a63e6c Mon Sep 17 00:00:00 2001 From: Gianluca Gippetto Date: Mon, 13 Nov 2023 02:29:00 +0100 Subject: [PATCH 3/3] Add cloup.get_current_context --- cloup/__init__.py | 3 ++- cloup/_context.py | 58 +++++++++++++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/cloup/__init__.py b/cloup/__init__.py index 0c18ac7..637f27c 100644 --- a/cloup/__init__.py +++ b/cloup/__init__.py @@ -41,7 +41,7 @@ HelpFormatter, HelpSection, ) -from ._context import Context, pass_context +from ._context import Context, get_current_context, pass_context from ._params import Argument, Option, argument, option from ._option_groups import ( OptionGroup, @@ -103,6 +103,7 @@ "constraint", "dir_path", "file_path", + "get_current_context", "group", "help_option", "option", diff --git a/cloup/_context.py b/cloup/_context.py index 8445192..9c0ec8e 100644 --- a/cloup/_context.py +++ b/cloup/_context.py @@ -1,8 +1,10 @@ from __future__ import annotations import warnings -from typing import Any, Callable, cast, Dict, List, Optional, Type, TypeVar, TYPE_CHECKING from functools import update_wrapper +from typing import ( + Any, Callable, cast, Dict, List, Optional, Type, TypeVar, TYPE_CHECKING, overload, +) import click @@ -11,6 +13,41 @@ from cloup.formatting import HelpFormatter from cloup.typing import MISSING, Possibly +if TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = TypeVar("R") + + +@overload +def get_current_context() -> "Context": + ... + + +@overload +def get_current_context(silent: bool = False) -> "Optional[Context]": + ... + + +def get_current_context(silent: bool = False) -> "Optional[Context]": + """Equivalent to :func:`click.get_current_context` but casts the returned + :class:`click.Context` object to :class:`cloup.Context` (which is safe when using + cloup commands classes and decorators).""" + return cast(Optional[Context], click.get_current_context(silent=silent)) + + +def pass_context(f: "Callable[te.Concatenate[Context, P], R]") -> "Callable[P, R]": + """Marks a callback as wanting to receive the current context object as first + argument. Equivalent to :func:`click.pass_context` but assumes the current context + is of type :class:`cloup.Context`.""" + + def new_func(*args: "P.args", **kwargs: "P.kwargs") -> R: + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(new_func, f) + def _warn_if_formatter_settings_conflict( ctx_key: str, @@ -225,22 +262,3 @@ def settings( dictionary, so that you can be guided by your IDE. """ return pick_non_missing(locals()) - - -if TYPE_CHECKING: - import typing_extensions as te - - P = te.ParamSpec("P") - -R = TypeVar("R") - - -def pass_context(f: Callable[te.Concatenate[Context, P], R]) -> Callable[P, R]: - """Marks a callback as wanting to receive the current context - object as first argument. - """ - - def new_func(*args: P.args, **kwargs: P.kwargs) -> R: - return f(cast(Context, click.get_current_context()), *args, **kwargs) - - return update_wrapper(new_func, f)