Skip to content

Commit 3b8f9bc

Browse files
committed
♻️ Add custom TyperChoice type for compatibility with Click 8.2.0, keeping the same behavior of enums
1 parent 5e571b6 commit 3b8f9bc

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

typer/_types.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from enum import Enum
2+
from typing import Generic, TypeVar, Union
3+
4+
import click
5+
6+
ParamTypeValue = TypeVar("ParamTypeValue")
7+
8+
9+
class TyperChoice(click.Choice, Generic[ParamTypeValue]): # type: ignore[type-arg]
10+
def normalize_choice(
11+
self, choice: ParamTypeValue, ctx: Union[click.Context, None]
12+
) -> str:
13+
# Click 8.2.0 added a new method `normalize_choice` to the `Choice` class
14+
# to support enums, but it uses the enum names, while Typer has always used the
15+
# enum values.
16+
# This class overrides that method to maintain the previous behavior.
17+
# In Click:
18+
# normed_value = choice.name if isinstance(choice, Enum) else str(choice)
19+
normed_value = choice.value if isinstance(choice, Enum) else str(choice)
20+
21+
if ctx is not None and ctx.token_normalize_func is not None:
22+
normed_value = ctx.token_normalize_func(normed_value)
23+
24+
if not self.case_sensitive:
25+
normed_value = normed_value.casefold()
26+
27+
return normed_value

typer/main.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from uuid import UUID
1616

1717
import click
18+
from typer._types import TyperChoice
1819

1920
from ._typing import get_args, get_origin, is_union
2021
from .completion import get_completion_inspect_parameters
@@ -787,7 +788,12 @@ def get_click_type(
787788
atomic=parameter_info.atomic,
788789
)
789790
elif lenient_issubclass(annotation, Enum):
790-
return click.Choice(
791+
# The custom TyperChoice is only needed for Click < 8.2.0, to parse the
792+
# command line values matching them to the enum values. Click 8.2.0 added
793+
# support for enum values but reading enum names.
794+
# Passing here the list of enum values (instead of just the enum) accounts for
795+
# Click < 8.2.0.
796+
return TyperChoice(
791797
[item.value for item in annotation],
792798
case_sensitive=parameter_info.case_sensitive,
793799
)

0 commit comments

Comments
 (0)