-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
15 changed files
with
221 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# Packages required to build the documentation | ||
sphinx == 7.4.7 | ||
sphinx-autodoc-typehints == 2.3.0 | ||
sphinx_rtd_theme == 2.0.0 | ||
sphinx == 8.0.2 | ||
sphinx-autodoc-typehints == 2.5.0 | ||
sphinx_rtd_theme == 3.0.0 | ||
sphinx-exec-code == 0.12 | ||
autodoc_pydantic == 2.2.0 | ||
sphinx-copybutton == 0.5.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
aiohttp == 3.10.8 | ||
aiohttp == 3.10.9 | ||
pydantic == 2.9.2 | ||
msgspec == 0.18.6 | ||
bidict == 0.23.1 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
from __future__ import annotations | ||
|
||
from datetime import datetime as dt_datetime | ||
from datetime import timedelta as dt_timedelta | ||
from operator import ge, gt, le, lt | ||
from typing import TYPE_CHECKING, Any, Final, TypeAlias, overload | ||
|
||
from whenever import Instant, TimeDelta | ||
|
||
|
||
if TYPE_CHECKING: | ||
from collections.abc import Callable | ||
|
||
|
||
HINT_OBJ: TypeAlias = dt_timedelta | TimeDelta | int | str | Instant | ||
|
||
|
||
class InstantView: | ||
__slots__ = ('_instant',) | ||
|
||
def __init__(self, instant: Instant) -> None: | ||
self._instant: Final = instant | ||
|
||
def delta(self, now: Instant | None = None) -> TimeDelta: | ||
"""Return the delta between the instant and now | ||
:param now: optional instant to compare to | ||
""" | ||
|
||
if now is None: | ||
now = Instant.now() | ||
return now - self._instant | ||
|
||
def py_timedelta(self, now: Instant | None = None) -> dt_timedelta: | ||
"""Return the timedelta between the instant and now | ||
:param now: optional instant to compare to | ||
""" | ||
return self.delta(now).py_timedelta() | ||
|
||
def py_datetime(self) -> dt_datetime: | ||
"""Return the datetime of the instant""" | ||
return self._instant.to_system_tz().local().py_datetime() | ||
|
||
def __repr__(self) -> str: | ||
return f'InstantView({self._instant.to_system_tz()})' | ||
|
||
def _cmp(self, op: Callable[[Any, Any], bool], obj: HINT_OBJ | None, **kwargs: float) -> bool: | ||
match obj: | ||
case None: | ||
if days := kwargs.get('days', 0): | ||
kwargs['hours'] = kwargs.get('hours', 0) + days * 24 | ||
td = TimeDelta(**kwargs) | ||
case TimeDelta(): | ||
td = obj | ||
case dt_timedelta(): | ||
td = TimeDelta.from_py_timedelta(obj) | ||
case int(): | ||
td = TimeDelta(seconds=obj) | ||
case str(): | ||
td = TimeDelta.parse_common_iso(obj) | ||
case Instant(): | ||
return op(self._instant, obj) | ||
case _: | ||
msg = f'Invalid type: {type(obj).__name__}' | ||
raise TypeError(msg) | ||
|
||
if td <= TimeDelta.ZERO: | ||
msg = 'Delta must be positive since instant is in the past' | ||
raise ValueError(msg) | ||
|
||
return op(self._instant, Instant.now() - td) | ||
|
||
@overload | ||
def older_than(self, *, days: float = 0, hours: float = 0, minutes: float = 0, seconds: float = 0) -> bool: ... | ||
@overload | ||
def older_than(self, obj: HINT_OBJ) -> bool: ... | ||
|
||
def older_than(self, obj=None, **kwargs): | ||
"""Check if the instant is older than the given value""" | ||
return self._cmp(lt, obj, **kwargs) | ||
|
||
@overload | ||
def newer_than(self, *, days: float = 0, hours: float = 0, minutes: float = 0, seconds: float = 0) -> bool: ... | ||
@overload | ||
def newer_than(self, obj: HINT_OBJ) -> bool: ... | ||
|
||
def newer_than(self, obj=None, **kwargs): | ||
"""Check if the instant is newer than the given value""" | ||
return self._cmp(gt, obj, **kwargs) | ||
|
||
def __lt__(self, other: HINT_OBJ) -> bool: | ||
return self._cmp(lt, other) | ||
|
||
def __le__(self, other: HINT_OBJ) -> bool: | ||
return self._cmp(le, other) | ||
|
||
def __gt__(self, other: HINT_OBJ) -> bool: | ||
return self._cmp(gt, other) | ||
|
||
def __ge__(self, other: HINT_OBJ) -> bool: | ||
return self._cmp(ge, other) | ||
|
||
def __eq__(self, other: InstantView | Instant) -> bool: | ||
if isinstance(other, InstantView): | ||
return self._instant == other._instant | ||
if isinstance(other, Instant): | ||
return self._instant == other | ||
return NotImplemented |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
from eascheduler.builder import FilterBuilder as filter | ||
from eascheduler.builder import TriggerBuilder as trigger | ||
from eascheduler import add_holiday, get_holiday_name, get_holidays_by_name, get_sun_position, is_holiday, pop_holiday | ||
from whenever import hours, minutes, seconds, milliseconds |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
from datetime import timedelta as dt_timedelta | ||
|
||
import pytest | ||
from whenever import Instant, SystemDateTime, TimeDelta, patch_current_time, seconds | ||
|
||
from HABApp.core.items.base_valueitem import datetime | ||
from HABApp.core.lib.instant_view import InstantView | ||
|
||
|
||
@pytest.fixture | ||
def view(): | ||
now = Instant.now().subtract(minutes=1) | ||
view = InstantView(now.subtract(minutes=1)) | ||
|
||
with patch_current_time(now, keep_ticking=False): | ||
yield view | ||
|
||
|
||
def test_methods(view: InstantView): | ||
assert view < seconds(1) | ||
assert not view < seconds(60) | ||
assert view <= seconds(60) | ||
|
||
assert view > seconds(61) | ||
assert not view > seconds(60) | ||
assert view >= seconds(60) | ||
|
||
|
||
def test_cmp_obj(view: InstantView): | ||
assert view < TimeDelta(seconds=59) | ||
assert view < dt_timedelta(seconds=59) | ||
assert view < 'PT59S' | ||
assert view < 59 | ||
|
||
|
||
def test_cmp_funcs(view: InstantView): | ||
assert view.older_than(seconds=59) | ||
assert view.newer_than(seconds=61) | ||
|
||
|
||
def test_delta_funcs(view: InstantView): | ||
assert view.delta() == seconds(60) | ||
assert view.py_timedelta() == dt_timedelta(seconds=60) | ||
|
||
|
||
def test_convert(): | ||
s = SystemDateTime(2021, 1, 2, 10, 11, 12) | ||
view = InstantView(s.instant()) | ||
assert view.py_datetime() == datetime(2021, 1, 2, 10, 11, 12) | ||
|
||
|
||
def test_repr(): | ||
view = InstantView(SystemDateTime(2021, 1, 2, 10, 11, 12).instant()) | ||
assert str(view) == 'InstantView(2021-01-02T10:11:12+01:00)' |