Skip to content

Poor interaction between some types and default values #2035

@bkurtz

Description

@bkurtz

Types/type functions that do not support being re-initialized with themselves (e.g. pytz.timezone) break with default values in click 8.x.
In click 7.x, it was required to specify the default value for these types as a string, but if you did so, things would work okay. In click 8.x, this is no longer the case.

For example, this code works in click 7.x:

import click
import pytz


@click.command()
@click.option("--timezone", type=pytz.timezone, default="UTC")
def main(timezone: pytz.timezone) -> None:
    print(timezone)


if __name__ == '__main__':
    main()

but in 8.x, produces the following exception:

Traceback (most recent call last):
  File "/Users/ben/Downloads/tz_click_test.py", line 12, in <module>
    main()
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/core.py", line 1137, in __call__
    return self.main(*args, **kwargs)
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/core.py", line 1061, in main
    with self.make_context(prog_name, args, **extra) as ctx:
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/core.py", line 923, in make_context
    self.parse_args(ctx, args)
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/core.py", line 1379, in parse_args
    value, args = param.handle_parse_result(ctx, opts, args)
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/core.py", line 2364, in handle_parse_result
    value = self.process_value(ctx, value)
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/core.py", line 2320, in process_value
    value = self.type_cast_value(ctx, value)
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/core.py", line 2307, in type_cast_value
    return convert(value)
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/types.py", line 75, in __call__
    return self.convert(value, param, ctx)
  File "/private/tmp/tz_venv/lib/python3.7/site-packages/click/types.py", line 170, in convert
    return self.func(value)
  File "/usr/local/lib/python3.7/site-packages/pytz/__init__.py", line 159, in timezone
    if zone.upper() == 'UTC':
AttributeError: 'UTC' object has no attribute 'upper'

This appears to be because click 8.x now does type conversion twice for "default" values:

I'd be happy to help with a fix for this, but would like feedback on the preferred approach. A few that come to mind:

  1. update Parameter.type_cast_value(...) to pass values through un-modified if they appear to be of the correct type
  2. similar, but for FuncParamType.convert(...)
  3. skip the conversion at processing-time if the value source is DEFAULT

It seems to me that the advantage of methods 1 and 2 would be that one could specify default values as the actual type (for more rigorous verification with static type checking tools), rather than needing to specify a string, but method 3 would (approximately!) restore parity with the click 7.x behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions