dycw-utilities 0.113.2__py3-none-any.whl → 0.113.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dycw_utilities-0.113.2.dist-info → dycw_utilities-0.113.3.dist-info}/METADATA +3 -3
- {dycw_utilities-0.113.2.dist-info → dycw_utilities-0.113.3.dist-info}/RECORD +6 -6
- utilities/__init__.py +1 -1
- utilities/datetime.py +98 -1
- {dycw_utilities-0.113.2.dist-info → dycw_utilities-0.113.3.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.113.2.dist-info → dycw_utilities-0.113.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,12 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dycw-utilities
|
3
|
-
Version: 0.113.
|
3
|
+
Version: 0.113.3
|
4
4
|
Author-email: Derek Wan <d.wan@icloud.com>
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.12
|
7
7
|
Requires-Dist: typing-extensions<4.14,>=4.13.1
|
8
8
|
Provides-Extra: test
|
9
|
-
Requires-Dist: hypothesis<6.132,>=6.131.
|
9
|
+
Requires-Dist: hypothesis<6.132,>=6.131.14; extra == 'test'
|
10
10
|
Requires-Dist: pytest-asyncio<0.27,>=0.26.0; extra == 'test'
|
11
11
|
Requires-Dist: pytest-cov<6.2,>=6.1.1; extra == 'test'
|
12
12
|
Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
|
@@ -80,7 +80,7 @@ Provides-Extra: zzz-test-hypothesis
|
|
80
80
|
Requires-Dist: aiosqlite<0.22,>=0.21.0; extra == 'zzz-test-hypothesis'
|
81
81
|
Requires-Dist: asyncpg<0.31,>=0.30.0; extra == 'zzz-test-hypothesis'
|
82
82
|
Requires-Dist: greenlet<3.3,>=3.2.0; extra == 'zzz-test-hypothesis'
|
83
|
-
Requires-Dist: hypothesis<6.132,>=6.131.
|
83
|
+
Requires-Dist: hypothesis<6.132,>=6.131.14; extra == 'zzz-test-hypothesis'
|
84
84
|
Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-hypothesis'
|
85
85
|
Requires-Dist: numpy<2.3,>=2.2.5; extra == 'zzz-test-hypothesis'
|
86
86
|
Requires-Dist: pathvalidate<3.3,>=3.2.3; extra == 'zzz-test-hypothesis'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=eOSRaK1eqblBSlkDTnJ-3-xWW49Ql-RkfxbwvIfUGyQ,60
|
2
2
|
utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
|
3
3
|
utilities/astor.py,sha256=xuDUkjq0-b6fhtwjhbnebzbqQZAjMSHR1IIS5uOodVg,777
|
4
4
|
utilities/asyncio.py,sha256=6Pv0xK2jP55iF6EYjY1g6_rFGOeJyihxRNxXnOsWv14,15691
|
@@ -12,7 +12,7 @@ utilities/contextvars.py,sha256=RsSGGrbQqqZ67rOydnM7WWIsM2lIE31UHJLejnHJPWY,505
|
|
12
12
|
utilities/cryptography.py,sha256=HyOewI20cl3uRXsKivhIaeLVDInQdzgXZGaly7hS5dE,771
|
13
13
|
utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
|
14
14
|
utilities/dataclasses.py,sha256=iiC1wpGXWhaocIikzwBt8bbLWyImoUlOlcDZJGejaIg,33011
|
15
|
-
utilities/datetime.py,sha256=
|
15
|
+
utilities/datetime.py,sha256=PcN-4_sSPX1zbpdzBQRdo08pubCuGHyigxkV6SUnvlo,38733
|
16
16
|
utilities/enum.py,sha256=HoRwVCWzsnH0vpO9ZEcAAIZLMv0Sn2vJxxA4sYMQgDs,5793
|
17
17
|
utilities/errors.py,sha256=BtSNP0JC3ik536ddPyTerLomCRJV9f6kdMe6POz0QHM,361
|
18
18
|
utilities/eventkit.py,sha256=6M5Xu1SzN-juk9PqBHwy5dS-ta7T0qA6SMpDsakOJ0E,13039
|
@@ -87,7 +87,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
87
87
|
utilities/whenever.py,sha256=iLRP_-8CZtBpHKbGZGu-kjSMg1ZubJ-VSmgSy7Eudxw,17787
|
88
88
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
89
89
|
utilities/zoneinfo.py,sha256=-Xm57PMMwDTYpxJdkiJG13wnbwK--I7XItBh5WVhD-o,1874
|
90
|
-
dycw_utilities-0.113.
|
91
|
-
dycw_utilities-0.113.
|
92
|
-
dycw_utilities-0.113.
|
93
|
-
dycw_utilities-0.113.
|
90
|
+
dycw_utilities-0.113.3.dist-info/METADATA,sha256=FekxkXInaGKIntNnsuUBc8VxfVEcuyBaoxzXdhhdxII,12943
|
91
|
+
dycw_utilities-0.113.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
92
|
+
dycw_utilities-0.113.3.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
93
|
+
dycw_utilities-0.113.3.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/datetime.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime as dt
|
4
|
-
from collections.abc import Callable, Iterable
|
4
|
+
from collections.abc import Callable, Iterable, Sequence
|
5
5
|
from dataclasses import dataclass, replace
|
6
6
|
from re import search, sub
|
7
7
|
from statistics import fmean
|
@@ -495,6 +495,101 @@ def get_half_years(*, n: int = 1) -> dt.timedelta:
|
|
495
495
|
|
496
496
|
HALF_YEAR = get_half_years(n=1)
|
497
497
|
|
498
|
+
##
|
499
|
+
|
500
|
+
|
501
|
+
def get_min_max_date(
|
502
|
+
*,
|
503
|
+
min_date: dt.date | None = None,
|
504
|
+
max_date: dt.date | None = None,
|
505
|
+
min_age: Duration | None = None,
|
506
|
+
max_age: Duration | None = None,
|
507
|
+
time_zone: TimeZoneLike = UTC,
|
508
|
+
) -> tuple[dt.date | None, dt.date | None]:
|
509
|
+
"""Get the min/max date given a combination of dates/ages."""
|
510
|
+
today = get_today(time_zone=time_zone)
|
511
|
+
min_parts: Sequence[dt.date] = []
|
512
|
+
if min_date is not None:
|
513
|
+
if min_date > today:
|
514
|
+
raise _GetMinMaxDateMinDateError(min_date=min_date, today=today)
|
515
|
+
min_parts.append(min_date)
|
516
|
+
if max_age is not None:
|
517
|
+
if date_duration_to_timedelta(max_age) < ZERO_TIME:
|
518
|
+
raise _GetMinMaxDateMaxAgeError(max_age=max_age)
|
519
|
+
min_parts.append(sub_duration(today, duration=max_age))
|
520
|
+
min_date_use = max(min_parts, default=None)
|
521
|
+
max_parts: Sequence[dt.date] = []
|
522
|
+
if max_date is not None:
|
523
|
+
if max_date > today:
|
524
|
+
raise _GetMinMaxDateMaxDateError(max_date=max_date, today=today)
|
525
|
+
max_parts.append(max_date)
|
526
|
+
if min_age is not None:
|
527
|
+
if date_duration_to_timedelta(min_age) < ZERO_TIME:
|
528
|
+
raise _GetMinMaxDateMinAgeError(min_age=min_age)
|
529
|
+
max_parts.append(sub_duration(today, duration=min_age))
|
530
|
+
max_date_use = min(max_parts, default=None)
|
531
|
+
if (
|
532
|
+
(min_date_use is not None)
|
533
|
+
and (max_date_use is not None)
|
534
|
+
and (min_date_use > max_date_use)
|
535
|
+
):
|
536
|
+
raise _GetMinMaxDatePeriodError(min_date=min_date_use, max_date=max_date_use)
|
537
|
+
return min_date_use, max_date_use
|
538
|
+
|
539
|
+
|
540
|
+
@dataclass(kw_only=True, slots=True)
|
541
|
+
class GetMinMaxDateError(Exception): ...
|
542
|
+
|
543
|
+
|
544
|
+
@dataclass(kw_only=True, slots=True)
|
545
|
+
class _GetMinMaxDateMinDateError(GetMinMaxDateError):
|
546
|
+
min_date: dt.date
|
547
|
+
today: dt.date
|
548
|
+
|
549
|
+
@override
|
550
|
+
def __str__(self) -> str:
|
551
|
+
return f"Min date must be at most today; got {self.min_date} > {self.today}"
|
552
|
+
|
553
|
+
|
554
|
+
@dataclass(kw_only=True, slots=True)
|
555
|
+
class _GetMinMaxDateMinAgeError(GetMinMaxDateError):
|
556
|
+
min_age: Duration
|
557
|
+
|
558
|
+
@override
|
559
|
+
def __str__(self) -> str:
|
560
|
+
return f"Min age must be non-negative; got {self.min_age}"
|
561
|
+
|
562
|
+
|
563
|
+
@dataclass(kw_only=True, slots=True)
|
564
|
+
class _GetMinMaxDateMaxDateError(GetMinMaxDateError):
|
565
|
+
max_date: dt.date
|
566
|
+
today: dt.date
|
567
|
+
|
568
|
+
@override
|
569
|
+
def __str__(self) -> str:
|
570
|
+
return f"Max date must be at most today; got {self.max_date} > {self.today}"
|
571
|
+
|
572
|
+
|
573
|
+
@dataclass(kw_only=True, slots=True)
|
574
|
+
class _GetMinMaxDateMaxAgeError(GetMinMaxDateError):
|
575
|
+
max_age: Duration
|
576
|
+
|
577
|
+
@override
|
578
|
+
def __str__(self) -> str:
|
579
|
+
return f"Max age must be non-negative; got {self.max_age}"
|
580
|
+
|
581
|
+
|
582
|
+
@dataclass(kw_only=True, slots=True)
|
583
|
+
class _GetMinMaxDatePeriodError(GetMinMaxDateError):
|
584
|
+
min_date: dt.date
|
585
|
+
max_date: dt.date
|
586
|
+
|
587
|
+
@override
|
588
|
+
def __str__(self) -> str:
|
589
|
+
return (
|
590
|
+
f"Min date must be at most max date; got {self.min_date} > {self.max_date}"
|
591
|
+
)
|
592
|
+
|
498
593
|
|
499
594
|
##
|
500
595
|
|
@@ -1244,6 +1339,7 @@ __all__ = [
|
|
1244
1339
|
"CheckDateNotDateTimeError",
|
1245
1340
|
"DateOrMonth",
|
1246
1341
|
"EnsureMonthError",
|
1342
|
+
"GetMinMaxDateError",
|
1247
1343
|
"MeanDateTimeError",
|
1248
1344
|
"MeanTimeDeltaError",
|
1249
1345
|
"MillisecondsSinceEpochError",
|
@@ -1280,6 +1376,7 @@ __all__ = [
|
|
1280
1376
|
"get_date",
|
1281
1377
|
"get_datetime",
|
1282
1378
|
"get_half_years",
|
1379
|
+
"get_min_max_date",
|
1283
1380
|
"get_months",
|
1284
1381
|
"get_now",
|
1285
1382
|
"get_quarters",
|
File without changes
|
File without changes
|