From 38a033d1f4476bd44ad2df230edc7dc127d719dd Mon Sep 17 00:00:00 2001 From: "Decroos, Jeroen" Date: Fri, 20 Dec 2024 00:26:11 +0100 Subject: [PATCH 1/8] adding quick implementation to use docstrings if help not given, no tests, no full functionality --- typer/utils.py | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/typer/utils.py b/typer/utils.py index 93c407447e..679a85c248 100644 --- a/typer/utils.py +++ b/typer/utils.py @@ -3,7 +3,7 @@ from copy import copy from typing import Any, Callable, Dict, List, Tuple, Type, cast -from typing_extensions import Annotated, get_args, get_origin, get_type_hints +from typing_extensions import Annotated, get_args, get_origin, get_type_hints, Doc from .models import ArgumentInfo, OptionInfo, ParameterInfo, ParamMeta @@ -63,6 +63,19 @@ def __str__(self) -> str: return msg +class MultipleDocAnnotationsError(Exception): + argument_name: str + + def __init__(self, argument_name: str): + self.argument_name = argument_name + + def __str__(self) -> str: + return ( + "Cannot specify multiple `Annotated` Doc arguments" + f" for {self.argument_name!r}" + ) + + class MultipleTyperAnnotationsError(Exception): argument_name: str @@ -92,17 +105,27 @@ def __str__(self) -> str: ) -def _split_annotation_from_typer_annotations( +def _split_annotation_from_doc_and_typer_annotations( base_annotation: Type[Any], ) -> Tuple[Type[Any], List[ParameterInfo]]: if get_origin(base_annotation) is not Annotated: return base_annotation, [] - base_annotation, *maybe_typer_annotations = get_args(base_annotation) - return base_annotation, [ + base_annotation, *other_annotations = get_args(base_annotation) + typer_annotations = [ annotation - for annotation in maybe_typer_annotations + for annotation in other_annotations if isinstance(annotation, ParameterInfo) ] + doc_annotations = [ + annotation + for annotation in other_annotations + if isinstance(annotation, Doc) + ] + return ( + base_annotation, + doc_annotations, + typer_annotations, + ) def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: @@ -114,16 +137,21 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: type_hints = get_type_hints(func) params = {} for param in signature.parameters.values(): - annotation, typer_annotations = _split_annotation_from_typer_annotations( + annotation, doc_annotations, typer_annotations = _split_annotation_from_doc_and_typer_annotations( param.annotation, ) if len(typer_annotations) > 1: raise MultipleTyperAnnotationsError(param.name) + if len(doc_annotations) > 1: + raise MultipleDocAnnotationsError(param.name) + doc_help = doc_annotations[0].documentation if doc_annotations else None default = param.default if typer_annotations: # It's something like `my_param: Annotated[str, Argument()]` [parameter_info] = typer_annotations + if not getattr(parameter_info, "help", None): + parameter_info.help = doc_help # Forbid `my_param: Annotated[str, Argument()] = Argument("...")` if isinstance(param.default, ParameterInfo): From 9491362499dbca5422acd6af90ec1f32aaa5d6e4 Mon Sep 17 00:00:00 2001 From: "Decroos, Jeroen" Date: Sun, 5 Jan 2025 22:17:05 +0100 Subject: [PATCH 2/8] :fire: add Doc support for all scenarios --- typer/main.py | 15 ++++++++++++++- typer/models.py | 2 ++ typer/utils.py | 21 ++++++++------------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/typer/main.py b/typer/main.py index 36737e49ef..9bbc3e5669 100644 --- a/typer/main.py +++ b/typer/main.py @@ -12,6 +12,7 @@ from traceback import FrameSummary, StackSummary from types import TracebackType from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, Union +from typing_extensions import Doc from uuid import UUID import click @@ -46,7 +47,7 @@ Required, TyperInfo, ) -from .utils import get_params_from_function +from .utils import get_params_from_function, MultipleDocAnnotationsError try: import rich @@ -821,6 +822,18 @@ def get_click_param( else: default_value = param.default parameter_info = OptionInfo() + if param.other_annotations: + doc_annotations = [ + annotation + for annotation in param.other_annotations + if isinstance(annotation, Doc) + ] + if len(doc_annotations) == 1: + doc_help = doc_annotations[0].documentation if doc_annotations else None + if not getattr(parameter_info, "help", None): + parameter_info.help = doc_help + if len(doc_annotations) > 1: + raise MultipleDocAnnotationsError(param.name) annotation: Any if param.annotation is not param.empty: annotation = param.annotation diff --git a/typer/models.py b/typer/models.py index 544e504761..56a082c1f0 100644 --- a/typer/models.py +++ b/typer/models.py @@ -514,10 +514,12 @@ def __init__( name: str, default: Any = inspect.Parameter.empty, annotation: Any = inspect.Parameter.empty, + other_annotations: List[Any] = None, ) -> None: self.name = name self.default = default self.annotation = annotation + self.other_annotations = other_annotations class DeveloperExceptionConfig: diff --git a/typer/utils.py b/typer/utils.py index 679a85c248..d827f9371e 100644 --- a/typer/utils.py +++ b/typer/utils.py @@ -116,15 +116,15 @@ def _split_annotation_from_doc_and_typer_annotations( for annotation in other_annotations if isinstance(annotation, ParameterInfo) ] - doc_annotations = [ + other_annotations = [ annotation for annotation in other_annotations - if isinstance(annotation, Doc) + if not isinstance(annotation, ParameterInfo) ] return ( base_annotation, - doc_annotations, typer_annotations, + other_annotations, ) @@ -137,21 +137,15 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: type_hints = get_type_hints(func) params = {} for param in signature.parameters.values(): - annotation, doc_annotations, typer_annotations = _split_annotation_from_doc_and_typer_annotations( + annotation, typer_annotations, other_annotations = _split_annotation_from_doc_and_typer_annotations( param.annotation, ) if len(typer_annotations) > 1: raise MultipleTyperAnnotationsError(param.name) - if len(doc_annotations) > 1: - raise MultipleDocAnnotationsError(param.name) - doc_help = doc_annotations[0].documentation if doc_annotations else None - default = param.default if typer_annotations: # It's something like `my_param: Annotated[str, Argument()]` [parameter_info] = typer_annotations - if not getattr(parameter_info, "help", None): - parameter_info.help = doc_help # Forbid `my_param: Annotated[str, Argument()] = Argument("...")` if isinstance(param.default, ParameterInfo): @@ -161,8 +155,6 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: default_param_type=type(param.default), ) - parameter_info = copy(parameter_info) - # When used as a default, `Option` takes a default value and option names # as positional arguments: # `Option(some_value, "--some-argument", "-s")` @@ -214,6 +206,9 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: default = parameter_info params[param.name] = ParamMeta( - name=param.name, default=default, annotation=annotation + name=param.name, + default=default, + annotation=annotation, + other_annotations=other_annotations, ) return params From 90d7e7d23e1293f12c50490468c8a220946410b8 Mon Sep 17 00:00:00 2001 From: "Decroos, Jeroen" Date: Mon, 6 Jan 2025 21:06:45 +0100 Subject: [PATCH 3/8] :white_check_mark: add tests for typing_extension.Doc --- pyproject.toml | 8 +++++ tests/test_ambiguous_params.py | 13 +++++-- tests/test_parameter_help.py | 65 ++++++++++++++++++++++++++++++++++ typer/utils.py | 7 ++-- 4 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 tests/test_parameter_help.py diff --git a/pyproject.toml b/pyproject.toml index e17f3628c9..af7e2a0a49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -200,3 +200,11 @@ known-first-party = ["reigns", "towns", "lands", "items", "users"] [tool.ruff.lint.pyupgrade] # Preserve types, even if a file imports `from __future__ import annotations`. keep-runtime-typing = true + +[tool.uv.sources] +typer = { workspace = true } + +[dependency-groups] +dev = [ + "typer", +] diff --git a/tests/test_ambiguous_params.py b/tests/test_ambiguous_params.py index 0693c8e9aa..2323133c86 100644 --- a/tests/test_ambiguous_params.py +++ b/tests/test_ambiguous_params.py @@ -8,7 +8,7 @@ MultipleTyperAnnotationsError, _split_annotation_from_typer_annotations, ) -from typing_extensions import Annotated +from typing_extensions import Annotated, Doc runner = CliRunner() @@ -17,10 +17,19 @@ def test_split_annotations_from_typer_annotations_simple(): # Simple sanity check that this utility works. If this isn't working on a given # python version, then no other tests for Annotated will work. given = Annotated[str, typer.Argument()] - base, typer_annotations = _split_annotation_from_typer_annotations(given) + base, typer_annotations, other_annotations = _split_annotation_from_typer_annotations(given) assert base is str # No equality check on the param types. Checking the length is sufficient. assert len(typer_annotations) == 1 + assert len(other_annotations) == 0 + +def test_split_other_annotations_from_typer_annotations(): + given = Annotated[str, typer.Argument(), Doc("doc help")] + base, typer_annotations, other_annotations = _split_annotation_from_typer_annotations(given) + assert base is str + assert len(typer_annotations) == 1 + assert len(other_annotations) == 1 + assert isinstance(other_annotations[0], Doc) def test_forbid_default_value_in_annotated_argument(): diff --git a/tests/test_parameter_help.py b/tests/test_parameter_help.py new file mode 100644 index 0000000000..22f220941b --- /dev/null +++ b/tests/test_parameter_help.py @@ -0,0 +1,65 @@ +from typing import Annotated +from typing_extensions import Doc +import pytest + +import typer +import typer.completion +from typer.testing import CliRunner +from typer import Option, Argument + + + +@pytest.fixture +def runner(): + return CliRunner() + + +@pytest.mark.parametrize( + "doc,parameter,expected", + [ + ( + Doc("doc only help"), + None, + "doc only help" + ), + ( + None, + Argument(help="argument only help"), + "argument only help" + ), + ( + Doc("doc help should appear"), + Argument(), + "doc help should appear", + ), + ( + Doc("this help should not appear"), + Argument(help="argument help has priority"), + "argument help has priority", + ), + ( + None, + Option(help="option only help"), + "option only help" + ), + ( + Doc("this help should not appear"), + Option(help="option help has priority"), + "option help has priority", + ), + ( + Doc("doc help should appear"), + Option(), + "doc help should appear", + ), + ], +) +def test_doc_help(runner, doc, parameter, expected): + app = typer.Typer() + + @app.command() + def main(arg: Annotated[str, doc, parameter]): + print(f"Hello {arg}") + + result = runner.invoke(app, ["--help"]) + assert expected in result.stdout diff --git a/typer/utils.py b/typer/utils.py index d827f9371e..b238850224 100644 --- a/typer/utils.py +++ b/typer/utils.py @@ -105,11 +105,11 @@ def __str__(self) -> str: ) -def _split_annotation_from_doc_and_typer_annotations( +def _split_annotation_from_typer_annotations( base_annotation: Type[Any], ) -> Tuple[Type[Any], List[ParameterInfo]]: if get_origin(base_annotation) is not Annotated: - return base_annotation, [] + return base_annotation, [], [] base_annotation, *other_annotations = get_args(base_annotation) typer_annotations = [ annotation @@ -137,7 +137,7 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: type_hints = get_type_hints(func) params = {} for param in signature.parameters.values(): - annotation, typer_annotations, other_annotations = _split_annotation_from_doc_and_typer_annotations( + annotation, typer_annotations, other_annotations = _split_annotation_from_typer_annotations( param.annotation, ) if len(typer_annotations) > 1: @@ -174,6 +174,7 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: parameter_info.default = ... # Forbid `my_param: Annotated[str, Argument('some-default')]` + import pdb; pdb.set_trace() if parameter_info.default is not ...: raise AnnotatedParamWithDefaultValueError( param_type=type(parameter_info), From fde4f649c5826feed02bf531d3f61af6358e7e9f Mon Sep 17 00:00:00 2001 From: "Decroos, Jeroen" Date: Mon, 6 Jan 2025 21:23:05 +0100 Subject: [PATCH 4/8] :fire: cleanup --- pyproject.toml | 8 -------- typer/utils.py | 1 - 2 files changed, 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index af7e2a0a49..e17f3628c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -200,11 +200,3 @@ known-first-party = ["reigns", "towns", "lands", "items", "users"] [tool.ruff.lint.pyupgrade] # Preserve types, even if a file imports `from __future__ import annotations`. keep-runtime-typing = true - -[tool.uv.sources] -typer = { workspace = true } - -[dependency-groups] -dev = [ - "typer", -] diff --git a/typer/utils.py b/typer/utils.py index b238850224..f304bd82d2 100644 --- a/typer/utils.py +++ b/typer/utils.py @@ -174,7 +174,6 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: parameter_info.default = ... # Forbid `my_param: Annotated[str, Argument('some-default')]` - import pdb; pdb.set_trace() if parameter_info.default is not ...: raise AnnotatedParamWithDefaultValueError( param_type=type(parameter_info), From 1b0210580e42a5d4ebd260db6e669361ea5df294 Mon Sep 17 00:00:00 2001 From: "Decroos, Jeroen" Date: Mon, 6 Jan 2025 21:27:18 +0100 Subject: [PATCH 5/8] :art: apply formatting --- tests/test_ambiguous_params.py | 9 +++++++-- tests/test_parameter_help.py | 25 ++++++------------------- typer/main.py | 5 ++--- typer/utils.py | 8 +++++--- 4 files changed, 20 insertions(+), 27 deletions(-) diff --git a/tests/test_ambiguous_params.py b/tests/test_ambiguous_params.py index 2323133c86..5ca8971cab 100644 --- a/tests/test_ambiguous_params.py +++ b/tests/test_ambiguous_params.py @@ -17,15 +17,20 @@ def test_split_annotations_from_typer_annotations_simple(): # Simple sanity check that this utility works. If this isn't working on a given # python version, then no other tests for Annotated will work. given = Annotated[str, typer.Argument()] - base, typer_annotations, other_annotations = _split_annotation_from_typer_annotations(given) + base, typer_annotations, other_annotations = ( + _split_annotation_from_typer_annotations(given) + ) assert base is str # No equality check on the param types. Checking the length is sufficient. assert len(typer_annotations) == 1 assert len(other_annotations) == 0 + def test_split_other_annotations_from_typer_annotations(): given = Annotated[str, typer.Argument(), Doc("doc help")] - base, typer_annotations, other_annotations = _split_annotation_from_typer_annotations(given) + base, typer_annotations, other_annotations = ( + _split_annotation_from_typer_annotations(given) + ) assert base is str assert len(typer_annotations) == 1 assert len(other_annotations) == 1 diff --git a/tests/test_parameter_help.py b/tests/test_parameter_help.py index 22f220941b..8ba99acd9e 100644 --- a/tests/test_parameter_help.py +++ b/tests/test_parameter_help.py @@ -1,12 +1,11 @@ from typing import Annotated -from typing_extensions import Doc -import pytest +import pytest import typer import typer.completion +from typer import Argument, Option from typer.testing import CliRunner -from typer import Option, Argument - +from typing_extensions import Doc @pytest.fixture @@ -17,16 +16,8 @@ def runner(): @pytest.mark.parametrize( "doc,parameter,expected", [ - ( - Doc("doc only help"), - None, - "doc only help" - ), - ( - None, - Argument(help="argument only help"), - "argument only help" - ), + (Doc("doc only help"), None, "doc only help"), + (None, Argument(help="argument only help"), "argument only help"), ( Doc("doc help should appear"), Argument(), @@ -37,11 +28,7 @@ def runner(): Argument(help="argument help has priority"), "argument help has priority", ), - ( - None, - Option(help="option only help"), - "option only help" - ), + (None, Option(help="option only help"), "option only help"), ( Doc("this help should not appear"), Option(help="option help has priority"), diff --git a/typer/main.py b/typer/main.py index 9bbc3e5669..1cde6ebc95 100644 --- a/typer/main.py +++ b/typer/main.py @@ -12,11 +12,10 @@ from traceback import FrameSummary, StackSummary from types import TracebackType from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, Union -from typing_extensions import Doc from uuid import UUID import click -from typing_extensions import get_args, get_origin +from typing_extensions import Doc, get_args, get_origin from ._typing import is_union from .completion import get_completion_inspect_parameters @@ -47,7 +46,7 @@ Required, TyperInfo, ) -from .utils import get_params_from_function, MultipleDocAnnotationsError +from .utils import MultipleDocAnnotationsError, get_params_from_function try: import rich diff --git a/typer/utils.py b/typer/utils.py index f304bd82d2..a6863f2375 100644 --- a/typer/utils.py +++ b/typer/utils.py @@ -3,7 +3,7 @@ from copy import copy from typing import Any, Callable, Dict, List, Tuple, Type, cast -from typing_extensions import Annotated, get_args, get_origin, get_type_hints, Doc +from typing_extensions import Annotated, get_args, get_origin, get_type_hints from .models import ArgumentInfo, OptionInfo, ParameterInfo, ParamMeta @@ -137,8 +137,10 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: type_hints = get_type_hints(func) params = {} for param in signature.parameters.values(): - annotation, typer_annotations, other_annotations = _split_annotation_from_typer_annotations( - param.annotation, + annotation, typer_annotations, other_annotations = ( + _split_annotation_from_typer_annotations( + param.annotation, + ) ) if len(typer_annotations) > 1: raise MultipleTyperAnnotationsError(param.name) From c8bb9361ab6f6d65ef144f97e0fda416ed84ac02 Mon Sep 17 00:00:00 2001 From: "Decroos, Jeroen" Date: Mon, 6 Jan 2025 21:37:41 +0100 Subject: [PATCH 6/8] :green_heart: fix tests locally --- tests/test_parameter_help.py | 8 ++------ typer/main.py | 4 ++-- typer/utils.py | 3 +++ 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/test_parameter_help.py b/tests/test_parameter_help.py index 8ba99acd9e..e2e2f113c0 100644 --- a/tests/test_parameter_help.py +++ b/tests/test_parameter_help.py @@ -8,11 +8,6 @@ from typing_extensions import Doc -@pytest.fixture -def runner(): - return CliRunner() - - @pytest.mark.parametrize( "doc,parameter,expected", [ @@ -41,12 +36,13 @@ def runner(): ), ], ) -def test_doc_help(runner, doc, parameter, expected): +def test_doc_help(doc, parameter, expected): app = typer.Typer() @app.command() def main(arg: Annotated[str, doc, parameter]): print(f"Hello {arg}") + runner = CliRunner() result = runner.invoke(app, ["--help"]) assert expected in result.stdout diff --git a/typer/main.py b/typer/main.py index 1cde6ebc95..1c0fb9d8ac 100644 --- a/typer/main.py +++ b/typer/main.py @@ -827,12 +827,12 @@ def get_click_param( for annotation in param.other_annotations if isinstance(annotation, Doc) ] + if len(doc_annotations) > 1: + raise MultipleDocAnnotationsError(param.name) if len(doc_annotations) == 1: doc_help = doc_annotations[0].documentation if doc_annotations else None if not getattr(parameter_info, "help", None): parameter_info.help = doc_help - if len(doc_annotations) > 1: - raise MultipleDocAnnotationsError(param.name) annotation: Any if param.annotation is not param.empty: annotation = param.annotation diff --git a/typer/utils.py b/typer/utils.py index a6863f2375..aef0da9cd4 100644 --- a/typer/utils.py +++ b/typer/utils.py @@ -144,6 +144,7 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: ) if len(typer_annotations) > 1: raise MultipleTyperAnnotationsError(param.name) + default = param.default if typer_annotations: # It's something like `my_param: Annotated[str, Argument()]` @@ -157,6 +158,8 @@ def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]: default_param_type=type(param.default), ) + parameter_info = copy(parameter_info) + # When used as a default, `Option` takes a default value and option names # as positional arguments: # `Option(some_value, "--some-argument", "-s")` From 8c5430f7040c9f0897dfbee3c0cfd275159b703a Mon Sep 17 00:00:00 2001 From: "Decroos, Jeroen" Date: Mon, 6 Jan 2025 22:35:06 +0100 Subject: [PATCH 7/8] :green_heart: satisfy linter mostly --- pyproject.toml | 4 ++-- typer/main.py | 30 ++++++++++++++++++------------ typer/models.py | 2 +- typer/utils.py | 2 +- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e17f3628c9..7ff5408bbc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "Typer, build great CLIs. Easy to code. Based on Python type hints authors = [ {name = "Sebastián Ramírez", email = "tiangolo@gmail.com"}, ] -requires-python = ">=3.7" +requires-python = ">=3.7" # need 3.8 for typing-extensions >=4.8.0 classifiers = [ "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", @@ -34,7 +34,7 @@ classifiers = [ ] dependencies = [ "click >= 8.0.0", - "typing-extensions >= 3.7.4.3", + "typing-extensions >= 4.8.0", ] readme = "README.md" [project.urls] diff --git a/typer/main.py b/typer/main.py index 1c0fb9d8ac..b665b1dca7 100644 --- a/typer/main.py +++ b/typer/main.py @@ -800,12 +800,29 @@ def lenient_issubclass( return isinstance(cls, type) and issubclass(cls, class_or_tuple) +def _set_doc_help(param: ParamMeta, parameter_info: ParameterInfo) -> None: + if not param.other_annotations: + return + doc_annotations = [ + annotation + for annotation in param.other_annotations + if isinstance(annotation, Doc) + ] + if len(doc_annotations) > 1: + raise MultipleDocAnnotationsError(param.name) + if len(doc_annotations) == 1: + doc_help = doc_annotations[0].documentation if doc_annotations else None + if not getattr(parameter_info, "help", None): + parameter_info.help = doc_help + + def get_click_param( param: ParamMeta, ) -> Tuple[Union[click.Argument, click.Option], Any]: # First, find out what will be: # * ParamInfo (ArgumentInfo or OptionInfo) # * default_value + # * help message # * required default_value = None required = False @@ -821,18 +838,7 @@ def get_click_param( else: default_value = param.default parameter_info = OptionInfo() - if param.other_annotations: - doc_annotations = [ - annotation - for annotation in param.other_annotations - if isinstance(annotation, Doc) - ] - if len(doc_annotations) > 1: - raise MultipleDocAnnotationsError(param.name) - if len(doc_annotations) == 1: - doc_help = doc_annotations[0].documentation if doc_annotations else None - if not getattr(parameter_info, "help", None): - parameter_info.help = doc_help + _set_doc_help(param, parameter_info) annotation: Any if param.annotation is not param.empty: annotation = param.annotation diff --git a/typer/models.py b/typer/models.py index 56a082c1f0..c8155c06e9 100644 --- a/typer/models.py +++ b/typer/models.py @@ -514,7 +514,7 @@ def __init__( name: str, default: Any = inspect.Parameter.empty, annotation: Any = inspect.Parameter.empty, - other_annotations: List[Any] = None, + other_annotations: Optional[List[Any]] = None, ) -> None: self.name = name self.default = default diff --git a/typer/utils.py b/typer/utils.py index aef0da9cd4..83d8841a2a 100644 --- a/typer/utils.py +++ b/typer/utils.py @@ -107,7 +107,7 @@ def __str__(self) -> str: def _split_annotation_from_typer_annotations( base_annotation: Type[Any], -) -> Tuple[Type[Any], List[ParameterInfo]]: +) -> Tuple[Type[Any], List[ParameterInfo], List[Any]]: if get_origin(base_annotation) is not Annotated: return base_annotation, [], [] base_annotation, *other_annotations = get_args(base_annotation) From b68c1e2437dc385db4dd3e8085b26973e1148d71 Mon Sep 17 00:00:00 2001 From: "Decroos, Jeroen" Date: Mon, 6 Jan 2025 22:50:01 +0100 Subject: [PATCH 8/8] :poop: ignore mypy error for now, requires discussion on python version --- typer/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typer/main.py b/typer/main.py index b665b1dca7..aa6674275c 100644 --- a/typer/main.py +++ b/typer/main.py @@ -15,7 +15,7 @@ from uuid import UUID import click -from typing_extensions import Doc, get_args, get_origin +from typing_extensions import Doc, get_args, get_origin # type: ignore from ._typing import is_union from .completion import get_completion_inspect_parameters