Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion click/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

# Types
from .types import ParamType, File, Path, Choice, IntRange, Tuple, \
STRING, INT, FLOAT, BOOL, UUID, UNPROCESSED
DateTime, STRING, INT, FLOAT, BOOL, UUID, UNPROCESSED

# Utilities
from .utils import echo, get_binary_stream, get_text_stream, open_file, \
Expand Down
34 changes: 34 additions & 0 deletions click/types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import sys
import stat
from datetime import datetime

from ._compat import open_stream, text_type, filename_to_ui, \
get_filesystem_encoding, get_streerror
Expand Down Expand Up @@ -162,6 +163,39 @@ def __repr__(self):
return 'Choice(%r)' % list(self.choices)


class DateTime(ParamType):
name = 'datetime'

def __init__(self, formats=None):
self.formats = formats or [
'%Y-%m-%d',
'%Y-%m-%dT%H:%M:%S'
]

def get_metavar(self, param):
return '[%s]' % '|'.join(self.formats)

def _try_to_convert_date(self, value, format):
try:
return datetime.strptime(value, format)
except ValueError:
return None

def convert(self, value, param, ctx):
# Exact match
for format in self.formats:
dtime = self._try_to_convert_date(value, format)
if dtime:
return dtime

self.fail(
'invalid datetime format: %s. (choose from %s)' % (
value, ', '.join(self.formats)))

def __repr__(self):
return 'DateTime'


class IntParamType(ParamType):
name = 'integer'

Expand Down
36 changes: 36 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,42 @@ def cli(method):
assert '--method [foo|bar|baz]' in result.output


def test_datetime_option_default(runner):

@click.command()
@click.option('--start_date', type=click.DateTime())
def cli(start_date):
click.echo(start_date.strftime('%Y-%m-%dT%H:%M:%S'))

result = runner.invoke(cli, ['--start_date=2015-09-29'])
assert not result.exception
assert result.output == '2015-09-29T00:00:00\n'

result = runner.invoke(cli, ['--start_date=2015-09-29T09:11:22'])
assert not result.exception
assert result.output == '2015-09-29T09:11:22\n'

result = runner.invoke(cli, ['--start_date=2015-09'])
assert result.exit_code == 2
assert 'Invalid value for "--start_date": invalid datetime format: 2015-09. ' \
'(choose from %Y-%m-%d, %Y-%m-%dT%H:%M:%S)' in result.output

result = runner.invoke(cli, ['--help'])
assert '--start_date [%Y-%m-%d|%Y-%m-%dT%H:%M:%S]' in result.output


def test_datetime_option_custom(runner):
@click.command()
@click.option('--start_date',
type=click.DateTime(formats=['%A %B %d, %Y']))
def cli(start_date):
click.echo(start_date.strftime('%Y-%m-%dT%H:%M:%S'))

result = runner.invoke(cli, ['--start_date=Wednesday June 05, 2010'])
assert not result.exception
assert result.output == '2010-06-05T00:00:00\n'


def test_int_range_option(runner):
@click.command()
@click.option('--x', type=click.IntRange(0, 5))
Expand Down
2 changes: 1 addition & 1 deletion tests/test_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def tracking_import(module, locals=None, globals=None, fromlist=None,
ALLOWED_IMPORTS = set([
'weakref', 'os', 'struct', 'collections', 'sys', 'contextlib',
'functools', 'stat', 're', 'codecs', 'inspect', 'itertools', 'io',
'threading'
'threading', 'datetime'
])


Expand Down