From 06d8d1d055dea1a086d6fe37b70735229a4456fd Mon Sep 17 00:00:00 2001 From: ddelange <14880945+ddelange@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:48:37 +0100 Subject: [PATCH] Allow '0s', disallow '', allow negative integers --- src/environs/__init__.py | 38 +++++++++++++++++++++++--------------- tests/test_environs.py | 25 +++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/environs/__init__.py b/src/environs/__init__.py index eb38d1e..cad480f 100644 --- a/src/environs/__init__.py +++ b/src/environs/__init__.py @@ -32,15 +32,23 @@ _EXPANDED_VAR_PATTERN = re.compile(r"(? timedelta: if isinstance(value, timedelta): return value match = _TIMEDELTA_PATTERN.match(value) - if match is not None and any(groups := match.groups(default=0)): + if match is not None and match.group(0): # disallow "", allow "0s" return timedelta( - weeks=int(groups[0]), - days=int(groups[1]), - hours=int(groups[2]), - minutes=int(groups[3]), - seconds=int(groups[4]), - milliseconds=int(groups[5]), - microseconds=int(groups[6]), + weeks=int(match.group(1) or 0), + days=int(match.group(2) or 0), + hours=int(match.group(3) or 0), + minutes=int(match.group(4) or 0), + seconds=int(match.group(5) or 0), + milliseconds=int(match.group(6) or 0), + microseconds=int(match.group(7) or 0), ) return super()._deserialize(value, *args, **kwargs) diff --git a/tests/test_environs.py b/tests/test_environs.py index ebdc957..1ddce0a 100644 --- a/tests/test_environs.py +++ b/tests/test_environs.py @@ -229,13 +229,23 @@ def test_date_cast(self, set_env, env): assert env.date("DATE") == date def test_timedelta_cast(self, set_env, env): + # seconds as integer + set_env({"TIMEDELTA": "0"}) + assert env.timedelta("TIMEDELTA") == dt.timedelta() set_env({"TIMEDELTA": "42"}) assert env.timedelta("TIMEDELTA") == dt.timedelta(seconds=42) + set_env({"TIMEDELTA": "-42"}) + assert env.timedelta("TIMEDELTA") == dt.timedelta(seconds=-42) + # seconds as duration string + set_env({"TIMEDELTA": "0s"}) + assert env.timedelta("TIMEDELTA") == dt.timedelta() set_env({"TIMEDELTA": "42s"}) assert env.timedelta("TIMEDELTA") == dt.timedelta(seconds=42) + set_env({"TIMEDELTA": "-42s"}) + assert env.timedelta("TIMEDELTA") == dt.timedelta(seconds=-42) # whitespaces, case-insensitive, units subselection - set_env({"TIMEDELTA": " 42 D 42s "}) - assert env.timedelta("TIMEDELTA") == dt.timedelta(days=42, seconds=42) + set_env({"TIMEDELTA": " 42 D -42s "}) + assert env.timedelta("TIMEDELTA") == dt.timedelta(days=42, seconds=-42) # unicode µs (in addition to us below) set_env({"TIMEDELTA": "42µs"}) assert env.timedelta("TIMEDELTA") == dt.timedelta(microseconds=42) @@ -250,6 +260,17 @@ def test_timedelta_cast(self, set_env, env): milliseconds=42, microseconds=42, ) + # empty string not allowed + set_env({"TIMEDELTA": ""}) + with pytest.raises(environs.EnvError): + env.timedelta("TIMEDELTA") + # float not allowed + set_env({"TIMEDELTA": "4.2"}) + with pytest.raises(environs.EnvError): + env.timedelta("TIMEDELTA") + set_env({"TIMEDELTA": "4.2d"}) + with pytest.raises(environs.EnvError): + env.timedelta("TIMEDELTA") def test_time_cast(self, set_env, env): set_env({"TIME": "10:30"})