1

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 Answers1

1

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']
afterburner
  • 2,552
  • 13
  • 21
  • Hey, thanks for the response. But, I guess this solution will work only if I can wrap the fruits in double quotes like in the example you gave. However, in my use case I can't wrap them in quotes like in the second example. – Priyansh Maheshwari Sep 08 '22 at 07:58
  • I've updated my response to support not adding quotes. The only downside is, you'd have to manually invoke the command, passing every instance of the option manually. ```--fruit apple --fruit banana ``` – afterburner Sep 09 '22 at 08:25
  • Hey, thanks for the response. I had the same solution from the click documentation too, but the issue lies with the last line I mentioned in question, that we don't have any freedom of changing the way we receive the input. – Priyansh Maheshwari Sep 12 '22 at 08:40
  • So, you just want to receive the code as `--fruit apple banana` ? Why the restriction? – afterburner Sep 12 '22 at 09:33
  • Actually in the main use case we are migrating an already existing and widely used script to click API. Since the users have been using it with a given format we don't want the input to change. – Priyansh Maheshwari Sep 13 '22 at 11:03
  • Does this help at all? https://stackoverflow.com/questions/48391777/nargs-equivalent-for-options-in-click – afterburner Sep 13 '22 at 18:29
  • Hey, yeah this looks good. Will go through this further and work on this. Thanks for the help. – Priyansh Maheshwari Sep 15 '22 at 06:50