I'm using the click.option type=<func> argument to convert input arguments from str to Tuple[float,float]. This (example below) code works as I'd expect in Click 7.1.2 but an odd implicit type conversion from string to tuple happens on Click 8.0.1.
Consider this code:
from typing import Optional, Tuple
import click
def parse_vec2(s: str) -> Tuple[float, float]:
'''Parse a floating point 2-vector of syntax 'a,b'.
Example:
'0,1' returns (0,1)
'''
print (s)
parts = s.split(',')
if len(parts) == 2:
return (float(parts[0]), float(parts[1]))
raise ValueError(f'cannot parse 2-vector {s}')
@click.command()
@click.option('--translate', help='Translate XY-coordinate (e.g. \'0.3,1\')', type=parse_vec2, default='0,0')
def main(
translate: Optional[Tuple[float,float]]
):
print (translate)
if __name__ == "__main__":
main()
On Click 7.1.2 this works as I'd expect: the default '0,0' is passed to parse_vec2 as a Python str value if it's not specified on the command line:
$ python clicktest.py
0,0
(0.0, 0.0)
$ python clicktest.py --translate='1,2'
1,2
(1.0, 2.0)
However, on 8.0.1, the default value is somehow implicitly converted to a tuple by Click when parse_vec2 is called.
On Click 8.0.1 parse_vec2 is in fact called twice, once with the original str '0,0' and a second time with (0.0, 0.0) On 7.1.2, parse_vec2 is called only once with the str value.
$ python clicktest.py
0,0
(0.0, 0.0)
Traceback (most recent call last):
File "/home/janne/dev/clicktest.py", line 25, in <module>
main() # pylint: disable=no-value-for-parameter
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/core.py", line 1137, in __call__
return self.main(*args, **kwargs)
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/core.py", line 1061, in main
with self.make_context(prog_name, args, **extra) as ctx:
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/core.py", line 923, in make_context
self.parse_args(ctx, args)
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/core.py", line 1379, in parse_args
value, args = param.handle_parse_result(ctx, opts, args)
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/core.py", line 2364, in handle_parse_result
value = self.process_value(ctx, value)
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/core.py", line 2320, in process_value
value = self.type_cast_value(ctx, value)
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/core.py", line 2307, in type_cast_value
return convert(value)
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/types.py", line 75, in __call__
return self.convert(value, param, ctx)
File "/home/janne/miniconda3/lib/python3.9/site-packages/click/types.py", line 170, in convert
return self.func(value)
File "/home/janne/dev/clicktest.py", line 12, in parse_vec2
parts = s.split(',')
AttributeError: 'tuple' object has no attribute 'split'
$ python clicktest.py --translate='3,2'
3,2
(3.0, 2.0)
I don't understand where and why this type conversion happens and why is parse_vec2 being called twice. I'd expect the default value to be passed directly to the type parse.
Environment:
- Python version: 3.9.5
- Click version: 8.0.1
I'm using the
click.optiontype=<func>argument to convert input arguments fromstrtoTuple[float,float]. This (example below) code works as I'd expect in Click 7.1.2 but an odd implicit type conversion from string to tuple happens on Click 8.0.1.Consider this code:
On Click 7.1.2 this works as I'd expect: the default
'0,0'is passed toparse_vec2as a Pythonstrvalue if it's not specified on the command line:However, on 8.0.1, the default value is somehow implicitly converted to a tuple by Click when
parse_vec2is called.On Click 8.0.1
parse_vec2is in fact called twice, once with the original str'0,0'and a second time with(0.0, 0.0)On 7.1.2, parse_vec2 is called only once with thestrvalue.I don't understand where and why this type conversion happens and why is
parse_vec2being called twice. I'd expect the default value to be passed directly to the type parse.Environment: