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

Allow choices restriction

Open Borda opened this issue 3 years ago • 7 comments

Hello, and thank you for this great CLI! Recently I get to a situation when I would like to restrict the options for a given argument similar to build-in argparse does with its option choices (see docs: https://docs.python.org/3/library/argparse.html#choices). Then I was checking Fire docs but could not find anything similar to it... Checking alternative CLI packages I found a way that is quite simple but still elegant and would well fit the Fire style. It is leveraging python Enum class:

from enum import Enum
import fire

class Direction(str, Enum):
    up = "up"
    down = "down"
    left = "left"
    right = "right"


def main(move: Direction = Direction.left):
    print(f"Moving in given direction: {move.value}")


if __name__ == "__main__":
    fire.Fire(main)

For clarification, the example above is borrowed and adjusted from Typer/enum

Borda avatar Feb 08 '22 22:02 Borda

That would be great! I use choices quite a lot.

chris-clem avatar Feb 09 '22 09:02 chris-clem

Please help Star

narothsolo avatar Feb 21 '22 19:02 narothsolo

Great idea. We don't currently use type annotations in fire to impose restrictions (but we could in a future version, though no one is actively working toward it atm).

Side note: One alternative that works today is to use a decorator, roughly like this:

def restrict_choices(choices):
  def decorator(f):
    def new_f(x):
      if x not in choices:
        raise FireError("Invalid choice")
      return f(x)
    return new_f
  return decorator

@restrict_choices(['left', 'right'])
def main(move):
    print(f"Moving in given direction: {move}")

See also SetParseFns in https://github.com/google/python-fire/blob/master/fire/decorators.py

dbieber avatar Feb 22 '22 23:02 dbieber

You might also find the HfArgumentParser relevant: https://github.com/huggingface/transformers/blob/514de24abfd4416aeba6a6455ad5920f57f3567d/src/transformers/hf_argparser.py#L109

keyboardAnt avatar Dec 08 '23 01:12 keyboardAnt

You might also find the HfArgumentParser relevant: https://github.com/huggingface/transformers/blob/514de24abfd4416aeba6a6455ad5920f57f3567d/src/transformers/hf_argparser.py#L109

Not really if you have to install full HF package for it...

Borda avatar Dec 08 '23 07:12 Borda

You might also find the HfArgumentParser relevant: https://github.com/huggingface/transformers/blob/514de24abfd4416aeba6a6455ad5920f57f3567d/src/transformers/hf_argparser.py#L109

Not really if you have to install full HF package for it...

The alternative below doesn't need the HF package. It is simple and readable but creates the Config object twice.

from pydantic import BaseModel

class Config(BaseModel):
    ...

def main(**kwargs):
    config = Config().model_copy(update=kwargs)

if __name__ == "__main__":
    fire.Fire(main)

keyboardAnt avatar Dec 08 '23 15:12 keyboardAnt