I am trying to port an argparse command-line interface (CLI) to click. This CLI must maintain the order in which parameters are provided by the user. With the argparse version, I used this StackOverflow answer to maintain order. With click, I am not sure how to do this.
I tried creating a custom callback to store params and values in order, but if a parameter is used multiple times, the callback fires the first time it sees a matching parameter.
import click
import typing
class OrderParams:
_options: typing.List[typing.Tuple[click.Parameter, typing.Any]] = []
@classmethod
def append(cls, ctx: click.Context, param: click.Parameter, value: typing.Any):
cls._options.append((param, value))
@click.command()
@click.option("--animal", required=True, multiple=True, callback=OrderParams.append)
@click.option("--thing", required=True, multiple=True, callback=OrderParams.append)
def cli(*, animal, thing):
click.echo("Got this order of parameters:")
for param, value in OrderParams._options:
print(" ", param.name, value)
if __name__ == "__main__":
cli()
Current output:
$ python cli.py --animal cat --thing rock --animal dog
Got this order of parameters:
animal ('cat', 'dog')
thing ('rock',)
Desired output:
$ python cli.py --animal cat --thing rock --animal dog
Got this order of parameters:
animal 'cat'
thing 'rock'
animal 'dog'
The click documentation describes the behavior that a callback is called once the first time a parameter is encountered, even if the parameter is used multiple times.
If an option or argument is split up on the command line into multiple places because it is repeated [...] the callback will fire based on the position of the first option.