Fix `format_timedelta` function's parsing of negative timedeltas (#5740)

* Fix `format_timedelta` function's parsing of negative timedeltas.

The entire timedelta can be negative.

* Refactor to use a single timedelta regular expression.

* Fix typo in `format_timedelta` function argument.
This commit is contained in:
Sean Rose 2024-06-05 09:05:12 -07:00 коммит произвёл GitHub
Родитель 214d062b5b
Коммит 5a7d7985c1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 16 добавлений и 10 удалений

Просмотреть файл

@ -1,9 +1,9 @@
"""This file contains custom filters for formatting data types in Jinja templates."""
import re
from datetime import datetime, timedelta
from bigquery_etl import query_scheduling
from bigquery_etl.query_scheduling.utils import TIMEDELTA_RE
def format_schedule_interval(interval):
@ -36,20 +36,18 @@ def format_date(date_string):
# based on https://stackoverflow.com/questions/4628122/how-to-construct-a
# -timedelta-object-from-a-simple-string
def format_timedelta(timdelta_string):
def format_timedelta(timedelta_string):
"""Format a timedelta object."""
timedelta_regex = re.compile(
r"^((?P<hours>-?\d+?)h)?((?P<minutes>-?\d+?)m)?((?P<seconds>-?\d+?)s)?$"
)
parts = timedelta_regex.match(timdelta_string)
parts = TIMEDELTA_RE.match(timedelta_string)
if not parts:
return timdelta_string
return timedelta_string
parts = parts.groupdict()
is_negative = timedelta_string.startswith("-")
time_params = {}
for name, param in parts.items():
if param:
time_params[name] = int(param)
time_params[name] = int(param) * (-1 if is_negative else 1)
return timedelta(**time_params)

Просмотреть файл

@ -3,6 +3,10 @@
import re
from datetime import datetime
TIMEDELTA_RE = re.compile(
r"^-?((?P<hours>\d+)h)?((?P<minutes>\d+)m)?((?P<seconds>\d+)s)?$"
)
def is_timedelta_string(s):
"""
@ -10,8 +14,7 @@ def is_timedelta_string(s):
Timedeltas in configs are specified like: 1h, 30m, 1h15m, ...
"""
timedelta_regex = re.compile(r"^-?(\d+h)?(\d+m)?(\d+s)?$")
return timedelta_regex.match(s)
return TIMEDELTA_RE.match(s)
def validate_timedelta_string(s):

Просмотреть файл

@ -43,10 +43,15 @@ class TestFormatters:
assert format_timedelta(123)
assert format_timedelta("1h") == datetime.timedelta(seconds=3600)
assert format_timedelta("-1h") == datetime.timedelta(seconds=-3600)
assert format_timedelta("15m") == datetime.timedelta(seconds=900)
assert format_timedelta("-15m") == datetime.timedelta(seconds=-900)
assert format_timedelta("1h15m") == datetime.timedelta(seconds=4500)
assert format_timedelta("-1h15m") == datetime.timedelta(seconds=-4500)
assert format_timedelta("1s") == datetime.timedelta(seconds=1)
assert format_timedelta("-1s") == datetime.timedelta(seconds=-1)
assert format_timedelta("1h1m1s") == datetime.timedelta(seconds=3661)
assert format_timedelta("-1h1m1s") == datetime.timedelta(seconds=-3661)
assert format_timedelta("1d1h1m1s") == "1d1h1m1s"
def test_format_optional_string(self):