diff --git a/setup.py b/setup.py index 43980ab..8898a2f 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name='django-variable-resolution-date', - version='0.1.6', + version='0.1.7', description='A django field that can represent either a year, or a year and a month, or a full calendar date', long_description='', author='Nicholas Wolff', diff --git a/tests/test_field.py b/tests/test_field.py index 4020e7f..3fb6976 100644 --- a/tests/test_field.py +++ b/tests/test_field.py @@ -18,14 +18,14 @@ def test_it_can_create_vrd_with_full_date(self): def test_it_cannot_create_vrd_with_invalid_full_date(self): with raises(ValidationError) as ex: ClubMember(name='dave', member_since='1997-02-29').full_clean() - assert ex.value.messages == ['Enter a year, year-month, or year-month-day.'] + assert ex.value.messages == ['Must be a valid year, year-month, or year-month-day.'] def test_it_cannot_create_vrd_with_extra_characters(self): with raises(ValidationError) as ex: ClubMember(name='earl', member_since='20001').full_clean() - assert ex.value.messages == ['Enter a year, year-month, or year-month-day.'] + assert ex.value.messages == ['Must be a valid year, year-month, or year-month-day.'] def test_it_cannot_create_vrd_with_month_day(self): with raises(ValidationError) as ex: ClubMember(name='fred', member_since='02-03').full_clean() - assert ex.value.messages == ['Enter a year, year-month, or year-month-day.'] + assert ex.value.messages == ['Must be a valid year, year-month, or year-month-day.'] diff --git a/tests/test_parsing.py b/tests/test_parsing.py new file mode 100644 index 0000000..2b95e36 --- /dev/null +++ b/tests/test_parsing.py @@ -0,0 +1,40 @@ +from django.core.exceptions import ValidationError +from django.test import TestCase +from pytest import raises + +from variable_resolution_date import parse + + +class VariableResolutionDateFieldTest(TestCase): + def test_it_can_parse_vrd_with_year(self): + y, m, d = parse('1996') + assert y == 1996 + assert m is None + assert d is None + + def test_it_can_parse_vrd_with_year_and_month(self): + y, m, d = parse('1996-02') + assert y == 1996 + assert m == 2 + assert d is None + + def test_it_can_parse_vrd_with_full_date(self): + y, m, d = parse('1996-02-29') + assert y == 1996 + assert m == 2 + assert d is 29 + + def test_it_cannot_parse_vrd_with_invalid_full_date(self): + with raises(ValidationError) as ex: + parse('1997-02-29') + assert ex.value.messages == ['Must be a valid year, year-month, or year-month-day.'] + + def test_it_cannot_parse_vrd_with_extra_characters(self): + with raises(ValidationError) as ex: + parse('20001') + assert ex.value.messages == ['Must be a valid year, year-month, or year-month-day.'] + + def test_it_cannot_parse_vrd_with_month_day(self): + with raises(ValidationError) as ex: + parse('02-03') + assert ex.value.messages == ['Must be a valid year, year-month, or year-month-day.'] diff --git a/variable_resolution_date/__init__.py b/variable_resolution_date/__init__.py index ae9f682..abe122d 100644 --- a/variable_resolution_date/__init__.py +++ b/variable_resolution_date/__init__.py @@ -23,22 +23,28 @@ VARIABLE_RESOLUTION_DATE_LENGTH = 10 -def validate_variable_resolution_date(value): +def parse(value): + """ returns a triple: year, month, day (month and day may be None) """ match = VARIABLE_RESOLUTION_DATE_RE.match(force_text(value)) if match: year = int(match.group(1)) - month = int(match.group(2) or 1) - day = int(match.group(3) or 1) + month = int(match.group(2)) if match.group(2) else None + day = int(match.group(3)) if match.group(3) else None try: - datetime.date(year, month, day) - return - except Exception: + # Make sure the different parts taken together represent a valid date. + datetime.date(year, month or 1, day or 1) + return year, month, day + except ValueError: pass - raise ValidationError('Enter a year, year-month, or year-month-day.') + raise ValidationError('Must be a valid year, year-month, or year-month-day.') + + +def validate(value): + parse(value) class VariableResolutionDateField(models.CharField): - default_validators = [validate_variable_resolution_date] + default_validators = [validate] description = 'A year, year-month, or year-month-day date' def __init__(self, *args, **kwargs):