Python: Click - Handling Date Parameter
I’ve been building a little CLI application using the Python Click Library, and I wanted to pass in a Date as a parameter. There’s more than one way to do this.
Let’s first install the Click library:
pip install click
And now we’ll import our required libraries:
from datetime import date
import click
Now we’ll create a sub command that takes two parameters: date-start
and date-end
.
These parameters have the type DateTime
, and we can pass a string in the format yyyy-mm-dd
from the command line:
@click.group()
def cli():
pass
@click.command()
@click.option('--date-start', type=click.DateTime(formats=["%Y-%m-%d"]),
default=str(date.today()))
@click.option('--date-end', type=click.DateTime(formats=["%Y-%m-%d"]),
default=str(date.today()))
def dummy(date_start, date_end):
click.echo(f"Start: {date_start}, End: {date_end} ")
cli.add_command(dummy)
if __name__ == '__main__':
cli()
We can execute this command by running the following:
$ python blog.py dummy --date-start 2018-01-01
Start: 2018-01-01 00:00:00, End: 2019-07-29 00:00:00
We only passed in date-start
, which means date-end
has defaulted to today’s date.
The dates are correct, but we still have time information that we don’t want.
We can get rid of that by calling the date
function on those DateTime
objects:
@click.command()
@click.option('--date-start', type=click.DateTime(formats=["%Y-%m-%d"]),
default=str(date.today()))
@click.option('--date-end', type=click.DateTime(formats=["%Y-%m-%d"]),
default=str(date.today()))
def dummy(date_start, date_end):
date_start = date_start.date()
date_end = date_end.date()
click.echo(f"Start: {date_start}, End: {date_end} ")
Now let’s run the script again:
$ python blog.py dummy --date-start 2018-01-01
Start: 2018-01-01, End: 2019-07-29
Alternatively we can create our own Date type based on the DateTime type:
from datetime import datetime
class Date(click.ParamType):
name = 'date'
def __init__(self, formats=None):
self.formats = formats or [
'%Y-%m-%d',
'%Y-%m-%dT%H:%M:%S',
'%Y-%m-%d %H:%M:%S'
]
def get_metavar(self, param):
return '[{}]'.format('|'.join(self.formats))
def _try_to_convert_date(self, value, format):
try:
return datetime.strptime(value, format).date()
except ValueError:
return None
def convert(self, value, param, ctx):
for format in self.formats:
date = self._try_to_convert_date(value, format)
if date:
return date
self.fail(
'invalid date format: {}. (choose from {})'.format(
value, ', '.join(self.formats)))
def __repr__(self):
return 'Date'
And then we’ll add a new command that uses this parameter type:
@click.command()
@click.option('--date-start', type=Date(formats=["%Y-%m-%d"]), default=str(date.today()))
@click.option('--date-end', type=Date(formats=["%Y-%m-%d"]), default=str(date.today()))
def dummy2(date_start, date_end):
click.echo(f"Start: {date_start}, End: {date_end} ")
cli.add_command(dummy2)
And now let’s call this sub command:
$ python blog.py dummy2 --date-start 2018-01-02 --date-end 2019-04-05
Start: 2018-01-02, End: 2019-04-05
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.