Skip to content

Commit

Permalink
Add: Add new parse_timedelta function
Browse files Browse the repository at this point in the history
Allow parsing a timedelta from a string of the following format:
`X.YwX.YdX.YhX.YmX.Ys` for example `1.5w1.5d1.5h1.5m1.5s`.
  • Loading branch information
bjoernricks committed Dec 30, 2022
1 parent 3cc3e83 commit 961dada
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
32 changes: 32 additions & 0 deletions pontos/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import sys
import warnings
from contextlib import asynccontextmanager, contextmanager
from datetime import timedelta
from enum import Enum
from functools import wraps
from pathlib import Path
Expand All @@ -45,6 +46,8 @@

import httpx

from pontos.errors import PontosError

DEFAULT_TIMEOUT = 1000
DEFAULT_CHUNK_SIZE = 4096

Expand Down Expand Up @@ -455,3 +458,32 @@ def enum_or_value(value: Union[Enum, Any]) -> Any:
return value.value

return value


regex = re.compile(
r"^((?P<weeks>[\.\d]+?)w)?((?P<days>[\.\d]+?)d)?((?P<hours>[\.\d]+?)h)?"
r"((?P<minutes>[\.\d]+?)m)?((?P<seconds>[\.\d]+?)s)?$"
)


def parse_timedelta(time_str: str) -> timedelta:
"""
Parse a timedelta from a string
Examples:
.. code-block:: python
parse_timedelta("1.5h")
parse_timedelta("1w2d4h5m6s")
"""
parts = regex.match(time_str)
if not parts:
raise PontosError(f"Invalid timedelta format '{time_str}'.")

parts = parts.groupdict()
time_params = {}
for name, param in parts.items():
if param:
time_params[name] = float(param)

return timedelta(**time_params)
47 changes: 47 additions & 0 deletions tests/test_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import httpx

from pontos.errors import PontosError
from pontos.helper import (
DEFAULT_TIMEOUT,
AsyncDownloadProgressIterable,
Expand All @@ -34,6 +35,7 @@
download_async,
ensure_unload_module,
enum_or_value,
parse_timedelta,
snake_case,
unload_module,
)
Expand Down Expand Up @@ -566,3 +568,48 @@ class Foo(Enum):

self.assertEqual(enum_or_value(Foo.BAR), "bar")
self.assertEqual(enum_or_value(Foo.BAZ), "baz")


class ParseTimedeltaTestCase(unittest.TestCase):
def test_parse_complex(self):
delta = parse_timedelta("1w2d4h5m6s")

self.assertEqual(delta.days, 9)
self.assertEqual(delta.seconds, 14706)

def test_parse_weeks(self):
delta = parse_timedelta("1w")
self.assertEqual(delta.days, 7)
self.assertEqual(delta.seconds, 0)

delta = parse_timedelta("1.5w")
self.assertEqual(delta.days, 10)
self.assertEqual(delta.seconds, 43200)

def test_parse_days(self):
delta = parse_timedelta("1d")
self.assertEqual(delta.days, 1)
self.assertEqual(delta.seconds, 0)

delta = parse_timedelta("1.5d")
self.assertEqual(delta.days, 1)
self.assertEqual(delta.seconds, 43200)

def test_parse_hours(self):
delta = parse_timedelta("1h")
self.assertEqual(delta.days, 0)
self.assertEqual(delta.seconds, 3600)

delta = parse_timedelta("1.5h")
self.assertEqual(delta.days, 0)
self.assertEqual(delta.seconds, 5400)

def test_parse_error(self):
with self.assertRaises(PontosError):
parse_timedelta("foo")

with self.assertRaises(PontosError):
parse_timedelta("1d2x")

with self.assertRaises(PontosError):
parse_timedelta("1,2d")

0 comments on commit 961dada

Please sign in to comment.