python-fire icon indicating copy to clipboard operation
python-fire copied to clipboard

Could be cool and likely easy to add optional typechecking from annotations with Typeguard

Open JulesGM opened this issue 3 years ago • 4 comments

Typeguard https://github.com/agronholm/typeguard makes it very easy to add annotation-based type checking that uses the full gamut of what typing offers, with just a decorator, for example.

Using the type checking decorator with Fire is very cool, but I feel like it would be even better if Fire used it internally to display a more user-friendly message to the user when they give an input that doesn't fit the type of the annotation.

Thanks.

@dbieber

JulesGM avatar Jun 22 '21 08:06 JulesGM

FWIW, I tend to use the following custom decorator to get this behavior:

import functools
import inspect

import typeguard

def typechecked(func):
    __annotations__ = getattr(func, '__annotations__', None)
    if __annotations__:
        __signature__ = inspect.signature(func)

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return typeguard.typechecked(func)(*args, **kwargs)
            except TypeError as exc:
                err = str(exc)
                found = False
                for param in __signature__.parameters.values():
                    if f'type of argument "{param.name}" ' not in err:
                        continue
                    found = True
                    if param.kind == param.POSITIONAL_ONLY or param.default == param.empty:
                        err = err.replace(param.name, param.name.upper())
                    elif param.kind in {param.POSITIONAL_OR_KEYWORD, param.KEYWORD_ONLY}:
                        err = err.replace(param.name, f"--{param.name.replace('_', '-')}")
                if found:
                    raise fire.core.FireError(err)
                raise exc

        return wrapper
    return func

Example:

@typechecked
def foo(n: int):
    for i in range(n):
        print(i)

fire.Fire(foo)

melsabagh avatar Sep 19 '21 17:09 melsabagh

That's great -- thanks for sharing that @melsabagh-kw!

dbieber avatar Sep 22 '21 01:09 dbieber

You can try afire, which is a fork of python-fire supporing type convert according to the type hint.

zqqqqz2000 avatar Oct 01 '23 17:10 zqqqqz2000

You can try afire, which is a fork of python-fire supporing type convert according to the type hint.

I created an issue on afire as well, but @zqqqqz2000 , is there any plan to merge this work back into Fire or is there some technical reason why it needs to stay separate?

gamis avatar Mar 16 '24 15:03 gamis