Skip to content

Commit

Permalink
Additional date hardening / test cases.
Browse files Browse the repository at this point in the history
  • Loading branch information
chaseastewart committed Jan 30, 2024
1 parent 51424d9 commit c8793d5
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 20 deletions.
45 changes: 32 additions & 13 deletions fhir_converter/filters.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from base64 import b64encode
from datetime import datetime, timezone
from functools import wraps
from functools import partial, wraps
from hashlib import sha1, sha256
from re import Match
from re import findall as re_findall
from re import sub as re_sub
from typing import Any, Callable, Iterable, List, Mapping, Sequence, Tuple
Expand Down Expand Up @@ -34,7 +35,7 @@
FilterT = Callable[..., Any]
"""Callable[..., Any]: A liquid filter function"""

FORMAT_MAP = frozendict(
FORMAT_MAP: frozendict[str, str] = frozendict(
{
"yyyy": "%Y",
"MM": "%m",
Expand All @@ -43,12 +44,36 @@
"mm": "%M",
"ss": "%S",
"%K": "%Z",
"zzz": "%Z",
"zz": "%h",
}
)
"""Dict[str, str]: C# format mappings"""
"""frozendict[str, str]: C# format mappings"""

ISO_FORMATING_MAP = frozendict({"fff": lambda dt: "%03d" % (dt.microsecond // 1000)})
"""Dict[str, Callable[[datetime], str]]: ISO formatting map"""
FORMAT_PATTERN = "|".join(["y+", "M+", "d+", "H+", "m+", "s+", "%K", "z+"])
"""C# Date Format Regex Pattern"""

ISO_FORMATING_MAP: frozendict[str, Callable[[datetime], str]] = frozendict(
{
"ffffff": lambda dt: "%06d" % dt.microsecond,
"fff": lambda dt: "%03d" % (dt.microsecond // 1000),
}
)
"""frozendict[str, Callable[[datetime], str]]: ISO formatting map"""

ISO_FORMAT_PATTERN = "f+"
"""ISO format Regex Pattern"""


def _repl_format(m: Match[str]) -> str:
return FORMAT_MAP.get(m.group(0), m.group(0))


def _repl_iso_format(dt: datetime, m: Match[str]) -> str:
format_f = ISO_FORMATING_MAP.get(m.group(0), None)
if format_f is not None:
return format_f(dt)
return m.group(0)


def str_arg(val: Any, default: str = "") -> str:
Expand Down Expand Up @@ -146,16 +171,10 @@ def date(input: str, format: Any = None) -> str:
if not format:
return datetime_isoformat(parse_datetime(input))

format = re_sub(
"|".join(FORMAT_MAP.keys()),
lambda m: FORMAT_MAP[m.group(0)],
format,
)
format = re_sub(FORMAT_PATTERN, _repl_format, format)
dt = parse_datetime(input)
return re_sub(
"|".join(ISO_FORMATING_MAP.keys()),
lambda m: ISO_FORMATING_MAP[m.group(0)](dt),
datetime_isoformat(dt, format),
ISO_FORMAT_PATTERN, partial(_repl_iso_format, dt), datetime_isoformat(dt, format)
)


Expand Down
114 changes: 107 additions & 7 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,50 +219,150 @@ def test_year(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="yyyy")
self.assertEqual(result, "2014")

def test_year_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%Y")
self.assertEqual(result, "2014")

def test_month(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="MM")
self.assertEqual(result, "10")

def test_month_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%m")
self.assertEqual(result, "10")

def test_day(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="dd")
self.assertEqual(result, "09")

def test_day_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%d")
self.assertEqual(result, "09")

def test_hour(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="HH")
self.assertEqual(result, "11")

def test_hour_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%H")
self.assertEqual(result, "11")

def test_minute(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="mm")
self.assertEqual(result, "58")

def test_minute_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%M")
self.assertEqual(result, "58")

def test_second(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="ss")
self.assertEqual(result, "10")

def test_second_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%S")
self.assertEqual(result, "10")

def test_milli(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="fff")
self.assertEqual(result, "001")

def test_micro(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="ffffff")
self.assertEqual(result, "001981")

def test_micro_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%f")
self.assertEqual(result, "001981")

def test_k_specifier_tz_undefined(self) -> None:
result = self.bound_template.render(dt="2014-10-09T11:58:10", format="%K")
self.assertEqual(result, "")

def test_k_specifier_tz_offset(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%K")
self.assertEqual(result, "+08:00")

def test_k_specifier_tz_offset_zero(self) -> None:
result = self.bound_template.render(dt="2014-10-09T11:58:10+00:00", format="%K")
self.assertEqual(result, "Z")

def test_k_specifier_tz_utc(self) -> None:
result = self.bound_template.render(dt="2014-10-09T11:58:10Z", format="%K")
self.assertEqual(result, "Z")

def test_tz_hour_min_offset(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="zzz")
self.assertEqual(result, "+08:00")

def test_tz_hour_min_offset_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%Z")
self.assertEqual(result, "+08:00")

def test_tz_hour_offset(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="zz")
self.assertEqual(result, "+08")

def test_tz_hour_offset_python(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="%h")
self.assertEqual(result, "+08")

def test_year_month(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="yyyy-MM")
self.assertEqual(result, "2014-10")

def test_day(self) -> None:
def test_year_month_day(self) -> None:
result = self.bound_template.render(dt=self.datetime_with_us, format="yyyy-MM-dd")
self.assertEqual(result, "2014-10-09")

def test_hour(self) -> None:
def test_year_month_day_hour(self) -> None:
result = self.bound_template.render(
dt=self.datetime_with_us, format="yyyy-MM-ddTHH"
)
self.assertEqual(result, "2014-10-09T11")

def test_minute(self) -> None:
def test_year_month_day_hour_minute(self) -> None:
result = self.bound_template.render(
dt=self.datetime_with_us, format="yyyy-MM-ddTHH:mm"
)
self.assertEqual(result, "2014-10-09T11:58")

def test_second(self) -> None:
def test_year_month_day_hour_minute_second(self) -> None:
result = self.bound_template.render(
dt=self.datetime_with_us, format="yyyy-MM-ddTHH:mm:ss"
)
self.assertEqual(result, "2014-10-09T11:58:10")

def test_second_tz(self) -> None:
def test_year_month_day_hour_minute_second_tz(self) -> None:
result = self.bound_template.render(
dt=self.datetime_with_us, format="yyyy-MM-ddTHH:mm:ss%K"
)
self.assertEqual(result, "2014-10-09T11:58:10+08:00")

def test_milli(self) -> None:
def test_year_month_day_hour_minute_second_milli(self) -> None:
result = self.bound_template.render(
dt=self.datetime_with_us, format="yyyy-MM-ddTHH:mm:ss.fff"
)
self.assertEqual(result, "2014-10-09T11:58:10.001")

def test_milli_tz(self) -> None:
def test_year_month_day_hour_minute_second_milli_tz(self) -> None:
result = self.bound_template.render(
dt=self.datetime_with_us, format="yyyy-MM-ddTHH:mm:ss.fff%K"
)
self.assertEqual(result, "2014-10-09T11:58:10.001+08:00")

def test_year_month_day_hour_minute_second_milli_micro(self) -> None:
result = self.bound_template.render(
dt=self.datetime_with_us, format="yyyy-MM-ddTHH:mm:ss.ffffff"
)
self.assertEqual(result, "2014-10-09T11:58:10.001981")

def test_year_month_day_hour_minute_second_milli_micro_tz(self) -> None:
result = self.bound_template.render(
dt=self.datetime_with_us, format="yyyy-MM-ddTHH:mm:ss.ffffff%K"
)
self.assertEqual(result, "2014-10-09T11:58:10.001981+08:00")


class NowTest(TestCase, FilterTest):
template = """{{ "" | now }}"""
Expand Down

0 comments on commit c8793d5

Please sign in to comment.