click doesn't have a builtin date
type, only a datetime
. (They won't be adding one either.)
This litters my cli code with an annoying convert to date chore that I end up using all over the place:
@click.command()
@click.argument("datetime_", type=click.DateTime())
def old_main(datetime_: datetime.datetime) -> None:
date = datetime_.date() # annoying, I want to pass in a date
click.echo(f"Date: {date}")
import datetime
from typing import Any, Optional
import click
class ClickDate(click.ParamType):
name = "date"
def convert(
self, value: Any, param: Optional[click.Parameter], ctx: Optional[click.Context]
) -> datetime.date:
if isinstance(value, datetime.date):
return value
try:
return datetime.date.fromisoformat(value)
# if you want, you could extend to accept other formats,
# but `YYYY-MM-DD` is the only one I care about
except ValueError:
self.fail(f"{value!r} is not a valid date", param, ctx)
You can then use dates easily:
@click.command()
@click.argument("date", type=ClickDate())
def main(date: datetime.date) -> None:
click.echo(f"Date: {date}")