click
click copied to clipboard
FuncParamType should use ValueError for self.fail(message)
FuncParamType currently just calls self.fail(value,...) if it self.func(value) raise a ValueError. This is missing the point of the self.fail which is to give better feedback.
Using typer so something like
@dataclass
class MyClass:
myvalue: str
@staticmethod
def from_str(cls, input:Any) -> 'MyClass':
if input != 'works':
raise ValueError(f'input was {input=}, should be works')
return cls(input)
@app.command('test', help='get snapshot')
async def test(
mydata: Annotated[
MyClass, typer.Argument(parser=MyClass.from_str)
],
) -> None:
should give str(error) not str(input)
fix would be
class FuncParamType(ParamType):
def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None:
self.name: str = func.__name__
self.func = func
def to_info_dict(self) -> dict[str, t.Any]:
info_dict = super().to_info_dict()
info_dict["func"] = self.func
return info_dict
def convert(
self, value: t.Any, param: Parameter | None, ctx: Context | None
) -> t.Any:
try:
return self.func(value)
except ValueError as e:
self.fail(str(e), param, ctx)
happy to submit a PR if this makes sense. Rather not have to create a customclass when FuncParamType is so close. Not sure what else FuncParamType there there for, as there isn't really any documentation of why it exists, but typer uses it.
in case any else finds this, enjoy my monkey patch:
def patch_click_func_param() -> None:
"""Patch click.FuncParamType to forward ValueError text to Click."""
from click.types import FuncParamType # noqa: PLC0415
if getattr(FuncParamType, '_rt_original_convert', None) is not None:
return
def _patched_convert(
self: FuncParamType,
value: Any,
param: 'Parameter | None',
ctx: 'Context | None',
) -> Any:
try:
return self.func(value)
except ValueError as exc:
self.fail(str(exc), param, ctx)
FuncParamType._rt_original_convert = FuncParamType.convert # noqa: SLF001 # pyright: ignore[reportAttributeAccessIssue]
FuncParamType.convert = _patched_convert
patch_click_func_param()