Skip to content

Commit 107a4ab

Browse files
committed
save
1 parent b5d35e9 commit 107a4ab

File tree

11 files changed

+241
-110
lines changed

11 files changed

+241
-110
lines changed

src/tests/test_asyncio.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
to_list,
2121
try_await,
2222
)
23-
from utilities.datetime import MILLISECOND, ZERO_TIME, duration_to_timedelta
23+
from utilities.datetime import MILLISECOND, ZERO_TIME, datetime_duration_to_timedelta
2424
from utilities.hypothesis import durations
2525
from utilities.pytest import skipif_windows
2626
from utilities.timer import Timer
@@ -125,7 +125,7 @@ class TestSleepDur:
125125
async def test_main(self, *, duration: Duration) -> None:
126126
with Timer() as timer:
127127
await sleep_dur(duration=duration)
128-
assert timer >= duration_to_timedelta(duration / 2)
128+
assert timer >= datetime_duration_to_timedelta(duration / 2)
129129

130130
async def test_none(self) -> None:
131131
with Timer() as timer:

src/tests/test_datetime.py

Lines changed: 68 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@
4545
TODAY_UTC,
4646
WEEK,
4747
YEAR,
48+
ZERO_TIME,
49+
AddDurationError,
4850
AddWeekdaysError,
4951
CheckDateNotDatetimeError,
5052
CheckZonedDatetimeError,
51-
DateAddTimeDeltaError,
5253
EnsureMonthError,
5354
MillisecondsSinceEpochError,
5455
Month,
@@ -57,18 +58,18 @@
5758
TimedeltaToMillisecondsError,
5859
YieldDaysError,
5960
YieldWeekdaysError,
61+
add_duration,
6062
add_weekdays,
6163
check_date_not_datetime,
6264
check_zoned_datetime,
63-
date_add_timedelta,
6465
date_to_datetime,
6566
date_to_month,
67+
datetime_duration_to_float,
68+
datetime_duration_to_timedelta,
6669
days_since_epoch,
6770
days_since_epoch_to_date,
6871
drop_microseconds,
6972
drop_milli_and_microseconds,
70-
duration_to_float,
71-
duration_to_timedelta,
7273
ensure_month,
7374
format_datetime_local_and_utc,
7475
get_half_years,
@@ -84,6 +85,7 @@
8485
is_equal_as_months,
8586
is_equal_mod_tz,
8687
is_instance_date_not_datetime,
88+
is_integral_timedelta,
8789
is_local_datetime,
8890
is_subclass_date_not_datetime,
8991
is_weekday,
@@ -120,6 +122,34 @@
120122
from utilities.types import Number
121123

122124

125+
class TestAddDuration:
126+
@given(date=dates(), days=integers())
127+
def test_date(self, *, date: dt.date, days: int) -> None:
128+
with assume_does_not_raise(OverflowError):
129+
timedelta = days * DAY
130+
with assume_does_not_raise(OverflowError):
131+
result = add_duration(date, timedelta=timedelta)
132+
assert is_instance_date_not_datetime(result)
133+
134+
@given(date=dates(), timedelta=timedeltas())
135+
def test_datetime(self, *, date: dt.date, days: int) -> None:
136+
with assume_does_not_raise(OverflowError):
137+
timedelta = days * DAY
138+
with assume_does_not_raise(OverflowError):
139+
result = add_duration(date, timedelta=timedelta)
140+
assert is_instance_date_not_datetime(result)
141+
142+
@given(date=dates())
143+
def test_none(self, *, date: dt.date) -> None:
144+
result = add_duration(date)
145+
assert result == date
146+
147+
@given(date=dates())
148+
def test_error(self, *, date: dt.date) -> None:
149+
with raises(AddDurationError, match="Timedelta must be day-only; got .*"):
150+
_ = add_duration(date, timedelta=SECOND)
151+
152+
123153
class TestAddWeekdays:
124154
@given(date=dates(), n=integers(-10, 10))
125155
@mark.parametrize("predicate", [param(gt), param(lt)])
@@ -178,26 +208,6 @@ def test_datetime(self, *, datetime: dt.datetime) -> None:
178208
check_zoned_datetime(datetime)
179209

180210

181-
class TestDateAddTimedelta:
182-
@given(date=dates(), days=integers())
183-
def test_main(self, *, date: dt.date, days: int) -> None:
184-
with assume_does_not_raise(OverflowError):
185-
timedelta = days * DAY
186-
with assume_does_not_raise(OverflowError):
187-
result = date_add_timedelta(date, timedelta=timedelta)
188-
assert is_instance_date_not_datetime(result)
189-
190-
@given(date=dates())
191-
def test_none(self, *, date: dt.date) -> None:
192-
result = date_add_timedelta(date)
193-
assert result == date
194-
195-
@given(date=dates())
196-
def test_error(self, *, date: dt.date) -> None:
197-
with raises(DateAddTimeDeltaError, match="Timedelta must be day-only; got .*"):
198-
_ = date_add_timedelta(date, timedelta=SECOND)
199-
200-
201211
class TestDateToDatetime:
202212
@given(date=dates())
203213
def test_main(self, *, date: dt.date) -> None:
@@ -212,6 +222,18 @@ def test_main(self, *, date: dt.date) -> None:
212222
assert result == date
213223

214224

225+
class TestDateTimeDurationToFloat:
226+
@given(duration=integers(0, 10) | floats(0.0, 10.0))
227+
def test_number(self, *, duration: Number) -> None:
228+
result = datetime_duration_to_float(duration)
229+
assert result == duration
230+
231+
@given(duration=timedeltas())
232+
def test_timedelta(self, *, duration: dt.timedelta) -> None:
233+
result = datetime_duration_to_float(duration)
234+
assert result == duration.total_seconds()
235+
236+
215237
class TestDaysSinceEpoch:
216238
@given(date=dates())
217239
def test_datetime_to_microseconds(self, *, date: dt.date) -> None:
@@ -235,33 +257,21 @@ def test_main(self, *, datetime: dt.datetime) -> None:
235257
assert result.microsecond == 0
236258

237259

238-
class TestDurationToFloat:
239-
@given(duration=integers(0, 10) | floats(0.0, 10.0))
240-
def test_number(self, *, duration: Number) -> None:
241-
result = duration_to_float(duration)
242-
assert result == duration
243-
244-
@given(duration=timedeltas())
245-
def test_timedelta(self, *, duration: dt.timedelta) -> None:
246-
result = duration_to_float(duration)
247-
assert result == duration.total_seconds()
248-
249-
250260
class TestDurationToTimedelta:
251261
@given(duration=integers(0, 10))
252262
def test_int(self, *, duration: int) -> None:
253-
result = duration_to_timedelta(duration)
263+
result = datetime_duration_to_timedelta(duration)
254264
assert result.total_seconds() == duration
255265

256266
@given(duration=floats(0.0, 10.0))
257267
def test_float(self, *, duration: float) -> None:
258268
duration = round(10 * duration) / 10
259-
result = duration_to_timedelta(duration)
269+
result = datetime_duration_to_timedelta(duration)
260270
assert isclose(result.total_seconds(), duration)
261271

262272
@given(duration=timedeltas())
263273
def test_timedelta(self, *, duration: dt.timedelta) -> None:
264-
result = duration_to_timedelta(duration)
274+
result = datetime_duration_to_timedelta(duration)
265275
assert result == duration
266276

267277

@@ -428,6 +438,25 @@ def test_local_vs_zoned(
428438
assert result is expected
429439

430440

441+
class TestIsIntegralTimeDelta:
442+
@given(n=integers())
443+
def test_integral(self, *, n: int) -> None:
444+
with assume_does_not_raise(OverflowError):
445+
timedelta = dt.timedelta(days=n)
446+
assert is_integral_timedelta(timedelta)
447+
448+
@given(
449+
n=integers(),
450+
frac=timedeltas(
451+
min_value=-(DAY - MICROSECOND), max_value=DAY - MICROSECOND
452+
).filter(lambda x: x != ZERO_TIME),
453+
)
454+
def test_non_integral(self, *, n: int, frac: dt.timedelta) -> None:
455+
with assume_does_not_raise(OverflowError):
456+
timedelta = dt.timedelta(days=n) + frac
457+
assert not is_integral_timedelta(timedelta)
458+
459+
431460
class TestIsLocalDateTime:
432461
@mark.parametrize(
433462
("obj", "expected"),

src/tests/test_hypothesis.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@
3333
from sqlalchemy.ext.asyncio import AsyncEngine
3434

3535
from tests.conftest import FLAKY, SKIPIF_CI_AND_NOT_LINUX, SKIPIF_CI_AND_WINDOWS
36-
from utilities.datetime import duration_to_float, is_local_datetime, is_zoned_datetime
36+
from utilities.datetime import (
37+
datetime_duration_to_float,
38+
is_local_datetime,
39+
is_zoned_datetime,
40+
)
3741
from utilities.functions import make_isinstance
3842
from utilities.git import _GIT_REMOTE_GET_URL_ORIGIN, _GIT_REV_PARSE_ABBREV_REV_HEAD
3943
from utilities.hypothesis import (
@@ -200,7 +204,7 @@ def test_int_and_float_bounds(self, *, data: DataObject) -> None:
200204
max_number = data.draw(floats(0.0, 10.0))
201205
duration = data.draw(durations(min_number=min_number, max_number=max_number))
202206
_ = assume(isinstance(duration, int | float))
203-
as_float = duration_to_float(duration)
207+
as_float = datetime_duration_to_float(duration)
204208
assert min_number <= as_float <= max_number
205209

206210
@given(

src/utilities/asyncio.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from sys import stderr, stdout
1919
from typing import TYPE_CHECKING, Any, TextIO, TypeAlias, TypeGuard, TypeVar, cast
2020

21-
from utilities.datetime import duration_to_float
21+
from utilities.datetime import datetime_duration_to_float
2222
from utilities.functions import EnsureStrError, ensure_int, ensure_not_none, ensure_str
2323
from utilities.iterables import OneError, one
2424
from utilities.types import MaybeAwaitable
@@ -75,7 +75,7 @@ async def sleep_dur(*, duration: Duration | None = None) -> None:
7575
"""Sleep which accepts durations."""
7676
if duration is None:
7777
return
78-
await sleep(duration_to_float(duration))
78+
await sleep(datetime_duration_to_float(duration))
7979

8080

8181
@dataclass(kw_only=True, slots=True)
@@ -127,7 +127,7 @@ async def _stream_one(
127127

128128
def timeout_dur(*, duration: Duration | None = None) -> Timeout:
129129
"""Timeout context manager which accepts durations."""
130-
delay = None if duration is None else duration_to_float(duration)
130+
delay = None if duration is None else datetime_duration_to_float(duration)
131131
return timeout(delay)
132132

133133

src/utilities/atools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from atools._memoize_decorator import Pickler, _AsyncMemoize
2020
from typing_extensions import override
2121

22-
from utilities.datetime import duration_to_timedelta
22+
from utilities.datetime import datetime_duration_to_timedelta
2323
from utilities.functions import ensure_class
2424
from utilities.types import Coroutine1, Duration
2525
from utilities.typing import get_args
@@ -136,7 +136,7 @@ async def call_memoized(
136136
"""Call an asynchronous function, with possible memoization."""
137137
if refresh is None:
138138
return await func(*args, **kwargs)
139-
timedelta = duration_to_timedelta(refresh)
139+
timedelta = datetime_duration_to_timedelta(refresh)
140140
try:
141141
memoized = _MEMOIZED_FUNCS[(func, timedelta)]
142142
except KeyError:

src/utilities/cachetools.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from cachetools.func import ttl_cache
77

8-
from utilities.datetime import duration_to_float
8+
from utilities.datetime import datetime_duration_to_float
99
from utilities.functions import identity
1010
from utilities.functools import lru_cache
1111

@@ -20,7 +20,7 @@ def cache(
2020
) -> Callable[[_F], _F]:
2121
"""Decorate a function with `max_size` and/or `ttl` settings."""
2222
if max_duration is not None:
23-
return ttl_cache(maxsize=max_size, ttl=duration_to_float(max_duration))
23+
return ttl_cache(maxsize=max_size, ttl=datetime_duration_to_float(max_duration))
2424
if max_size is not None:
2525
return cast(Any, lru_cache(max_size=max_size))
2626
return identity

0 commit comments

Comments
 (0)