click.Choice() doesn't like integers while getting --help

Created on 10 May 2017  路  7Comments  路  Source: pallets/click

click.Choice() doesn't like integers while getting --help.

Given:

click.option(
    "--pk",
    type=click.Choice([1, 2, 3]),
    help="Select the primary key.",
    default=1
    )

Gives:
```
803, in show_help
echo(ctx.get_help(), color=ctx.color)
File "{...}/lib/python3.5/site-packages/click/core.py", line 495, in get_help
return self.command.get_help(self)
File "{...}/lib/python3.5/site-packages/click/core.py", line 824, in get_help
self.format_help(ctx, formatter)
File "{...}/lib/python3.5/site-packages/click/core.py", line 839, in format_help
self.format_options(ctx, formatter)
File "{...}/lib/python3.5/site-packages/click/core.py", line 853, in format_options
rv = param.get_help_record(ctx)
File "{...}/lib/python3.5/site-packages/click/core.py", line 1602, in get_help_record
rv = [_write_opts(self.opts)]
File "{...}/lib/python3.5/site-packages/click/core.py", line 1599, in _write_opts
rv += ' ' + self.make_metavar()
File "{...}/lib/python3.5/site-packages/click/core.py", line 1292, in make_metavar
metavar = self.type.get_metavar(self)
File "{...}/lib/python3.5/site-packages/click/types.py", line 140, in get_metavar
return '[%s]' % '|'.join(self.choices)
TypeError: sequence item 0: expected str instance, int found
````

bug

Most helpful comment

Just hit that issue as well.

Seems that most of the functions of class Choice are expecting self.choices as list of strings, but I guess there is no reason why we should not be able to use ints instead.

I am workarounding the issue by using list of strings though and than calling int(foo) when working with the passed value.

All 7 comments

Just hit that issue as well.

Seems that most of the functions of class Choice are expecting self.choices as list of strings, but I guess there is no reason why we should not be able to use ints instead.

I am workarounding the issue by using list of strings though and than calling int(foo) when working with the passed value.

@prusnak , @fdavis are you sure that this is bug?
To fix it need to change .join(self.choices) to .join([str(i) for i in self.choices]) here, here and here. But we will have a new problem. List of choices is integer, but we will get value as string from command line. So this means that validation will never be successful(because '1' != 1).
I think you can describe choices as strings and convert type inside command if you need. What do you think?

@cli.command()
@click.option("--pk",
    type=click.Choice(['1', '2', '3']),
    help="Select the primary key.",
    default='1')
def test(pk):
    do_something(int(pk))

@d-ganchar Probably not a bug per se, but totally not following the Principle of least surprise.

I know it's possible to create a new Choice type (example), but I think passing ints is quite common, so this might deserve a special treatment. Maybe creating a click.ChoiceInt type derived from click.Choice and with overridden methods?

@prusnak I think that your decision makes sense

While docstring on class Choice says that choices must be a string I agree with @prusnak that its surprising and at the very least we should just enforce the type self.choices in __init__ so it doesn't fail elsewhere

Was this issue resolved?

We are happy to review PRs on this, but I feel that adding a click.ChoiceInt type or similar will add unnecessary complication to the API.

The user is going to be inputting strings from the command line, so I think the default of specifying a choice as a list of strings makes sense.

I am going to close this for now, but feel free to open if someone has an implementation or a PR.

Was this page helpful?
0 / 5 - 0 ratings