case insensitive args
would it be possible to add a case_insensitive parameter to Arg?
from dataclasses import dataclass
from typing import Annotated
import cappa
@dataclass
class Command:
color: Annotated[
str,
cappa.Arg(
choices=["Red", "Green", "Blue"],
case_insensitive=True
)
]
def __call__(self) -> None:
print(self.color)
# with this, the following would be valid:
# my_cli --color blue
# Blue
i know you can currently specify something like parse=[str.title, cappa.default_parse], but it doesn't feel as good.
What i dont like about case_insensitive is the it's a globally available parameter that only applies to a small subset of the total kinds of types. For example, would you expect a list[str] to react to case_insensitive? I think...I probably would.
I would think color: Annotated[Literal["Red", "Green", "Blue"], cappa.Arg(parse=str.title)] would be optimal (which doesn't work as might be nice, today).
And for the hopefully less common case, I might add an Arg(default_parse=False) flag to opt out of the default parse behavior.
in fact today color: Annotated[str, cappa.Arg(choices=["Red", "Green", "Blue"], parse=str.title)] seems to already work how I might hope the Literal usage might work. Choices are internally handled exactly as Literals, but they're currently applied on top of the parse function regardless of the user's supplied parse function (unlike Literal).
What i dont like about case_insensitive is the it's a globally available parameter that only applies to a small subset of the total kinds of types.
i didn't think about that, i agree with your opinion.
also, would the changes in #249 need me to change this code i have?
from dataclasses import dataclass
from typing import Annotated, Literal, Optional, TypeVar
import cappa
T = TypeVar("T")
def parse_none(value: T) -> Optional[T]:
if value == "None":
return None
return value
@dataclass
class Command:
threshold: Annotated[
float | Literal["None"],
cappa.Arg(
short=True,
long=True,
default=0.5,
parse=[
str.title,
cappa.default_parse,
parse_none,
],
),
]
what i'm doing will cause the default parse path to become: parse=[str.title, cappa.default_parse, parse_none, cappa.default_parse], unless you provide parse_inference=False.
With that said, I think your threshold type doesn't seem right, seems like it should be float | None, which would let you do parse=[str.title, parse_none]. or just have parse=parse_none and if value.lower() == "none":...
Should be included in v0.31.0.