Python Click API - Multiple value option with unknown number

Viewed 46

I want to receive multi value option from click API, but the number of values is unknown. I went through the documentation for click API, but it directly supports only multi value when the number of values is know from before and can be mentioned in nargs parameter. In my case, the number of values can change and I want to receive all the values.

python demo.py shop --fruits apple --vegetable potato
python demo.py shop --fruits apple bananna --vegetable potato

For example if we consider shop to be the click command we are calling in the first case we should get

fruits: 'apple', vegetable: 'potato'

In second case

fruits: 'apple banana', vegetable: 'potato'

The format of output of course can be changed to an array or something else, but we don't have any freedom in the way we receive the input.

1 Answers

I was able to achieve this by overriding the action the parser takes regarding the option, to explicitly append the value of any option rather than override it. I've marked the explicit line with a comment.


class ManyParser(OptionParser):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def add_option(self, obj: "CoreOption", opts: t.Sequence[str], dest: t.Optional[str],
                   action: t.Optional[str] = None, nargs: int = 1, const: t.Optional[t.Any] = None) -> None:
        action = 'append' # This line here is all I've had to add
        super().add_option(obj, opts, dest, action, nargs, const)


class ManyVarCommand(click.Command):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def make_parser(self, ctx: Context) -> OptionParser:
        """Creates the underlying option parser for this command."""
        parser = ManyParser(ctx)
        for param in self.get_params(ctx):
            param.add_to_parser(parser, ctx)
        return parser


@click.command(cls=ManyVarCommand)
@click.option('--fruit', default="", required=False)
@click.option('--veggie', default="", required=False)
def com(fruit, veggie):
    print(fruit)
    print(veggie)
python main.py --fruit apple --fruit banana --veggie potato --veggie cabbage
['apple', 'banana']
['potato', 'cabbage']
Related