Add support for parsing partial isoformats back

This commit is contained in:
Adeodato Simó 2023-10-21 20:27:23 -03:00
parent 4b47646e28
commit 9752819bdb
No known key found for this signature in database
GPG key ID: CDF447845F1A986F
2 changed files with 83 additions and 0 deletions

View file

@ -18,16 +18,76 @@ class SealedDateTest(unittest.TestCase):
sealed = sealed_date.SealedDate.from_datetime(self.dt)
self.assertEqual(self.dt, sealed)
self.assertEqual("2023-10-20", sealed.partial_isoformat())
self.assertTrue(sealed.has_day)
self.assertTrue(sealed.has_month)
def test_month_seal(self):
sealed = sealed_date.MonthSeal.from_datetime(self.dt)
self.assertEqual(self.dt, sealed)
self.assertEqual("2023-10", sealed.partial_isoformat())
self.assertFalse(sealed.has_day)
self.assertTrue(sealed.has_month)
def test_year_seal(self):
sealed = sealed_date.YearSeal.from_datetime(self.dt)
self.assertEqual(self.dt, sealed)
self.assertEqual("2023", sealed.partial_isoformat())
self.assertFalse(sealed.has_day)
self.assertFalse(sealed.has_month)
def test_parse_year_seal(self):
parsed = sealed_date.from_partial_isoformat("1995")
expected = datetime.date(1995, 1, 1)
self.assertEqual(expected, parsed.date())
self.assertFalse(parsed.has_day)
self.assertFalse(parsed.has_month)
def test_parse_year_errors(self):
self.assertRaises(ValueError, sealed_date.from_partial_isoformat, "995")
self.assertRaises(ValueError, sealed_date.from_partial_isoformat, "1995x")
self.assertRaises(ValueError, sealed_date.from_partial_isoformat, "1995-")
def test_parse_month_seal(self):
expected = datetime.date(1995, 5, 1)
test_cases = [
("parse_month", "1995-05"),
("parse_month_lenient", "1995-5"),
]
for desc, value in test_cases:
with self.subTest(desc):
parsed = sealed_date.from_partial_isoformat(value)
self.assertEqual(expected, parsed.date())
self.assertFalse(parsed.has_day)
self.assertTrue(parsed.has_month)
def test_parse_month_dash_required(self):
self.assertRaises(ValueError, sealed_date.from_partial_isoformat, "20056")
self.assertRaises(ValueError, sealed_date.from_partial_isoformat, "200506")
self.assertRaises(ValueError, sealed_date.from_partial_isoformat, "1995-7-")
def test_parse_day_seal(self):
expected = datetime.date(1995, 5, 6)
test_cases = [
("parse_day", "1995-05-06"),
("parse_day_lenient1", "1995-5-6"),
("parse_day_lenient2", "1995-05-6"),
]
for desc, value in test_cases:
with self.subTest(desc):
parsed = sealed_date.from_partial_isoformat(value)
self.assertEqual(expected, parsed.date())
self.assertTrue(parsed.has_day)
self.assertTrue(parsed.has_month)
def test_partial_isoformat_no_time_allowed(self):
self.assertRaises(ValueError, sealed_date.from_partial_isoformat, "2005-06-07 ")
self.assertRaises(ValueError, sealed_date.from_partial_isoformat, "2005-06-07T")
self.assertRaises(
ValueError, sealed_date.from_partial_isoformat, "2005-06-07T00:00:00"
)
self.assertRaises(
ValueError, sealed_date.from_partial_isoformat, "2005-06-07T00:00:00-03"
)
class SealedDateFormFieldTest(unittest.TestCase):

View file

@ -3,6 +3,7 @@
from __future__ import annotations
from datetime import datetime, timedelta
import re
from typing import Any, Optional, Type, TypeVar, cast
from django.core.exceptions import ValidationError
@ -11,6 +12,12 @@ from django.forms.widgets import SelectDateWidget
from django.utils import timezone
__all__ = [
"SealedDate",
"from_partial_isoformat",
]
_partial_re = re.compile(r"(\d{4})(?:-(\d\d?))?(?:-(\d\d?))?$")
_westmost_tz = timezone.get_fixed_timezone(timedelta(hours=-12))
Sealed = TypeVar("Sealed", bound="SealedDate") # TODO: use Self in Python >= 3.11
@ -63,6 +70,22 @@ class YearSeal(SealedDate):
return self.strftime("%Y")
def from_partial_isoformat(value: str) -> SealedDate:
match = _partial_re.match(value)
if not match:
raise ValueError
year, month, day = [val and int(val) for val in match.groups()]
if month is None:
return YearSeal.from_date_parts(year, 1, 1)
elif day is None:
return MonthSeal.from_date_parts(year, month, 1)
else:
return SealedDate.from_date_parts(year, month, day)
class SealedDateFormField(DateField):
"""date form field with support for SealedDate"""