dycw-utilities 0.131.13__py3-none-any.whl → 0.131.15__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.131.13.dist-info → dycw_utilities-0.131.15.dist-info}/METADATA +1 -1
- {dycw_utilities-0.131.13.dist-info → dycw_utilities-0.131.15.dist-info}/RECORD +8 -7
- utilities/__init__.py +1 -1
- utilities/hypothesis.py +0 -81
- utilities/luigi.py +71 -104
- utilities/typed_settings.py +61 -0
- {dycw_utilities-0.131.13.dist-info → dycw_utilities-0.131.15.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.131.13.dist-info → dycw_utilities-0.131.15.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=TF72KRTntycdsGaFpyLS49_hW9qrELSmZAvg2kQ0BrA,61
|
2
2
|
utilities/aiolimiter.py,sha256=mD0wEiqMgwpty4XTbawFpnkkmJS6R4JRsVXFUaoitSU,628
|
3
3
|
utilities/altair.py,sha256=HeZBVUocjkrTNwwKrClppsIqgNFF-ykv05HfZSoHYno,9104
|
4
4
|
utilities/asyncio.py,sha256=yfKvAIDCRrWdyQMVZMo4DJQx4nVrXoAcqwhNuF95Ryo,38186
|
@@ -24,7 +24,7 @@ utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
|
|
24
24
|
utilities/git.py,sha256=oi7-_l5e9haSANSCvQw25ufYGoNahuUPHAZ6114s3JQ,1191
|
25
25
|
utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
|
26
26
|
utilities/http.py,sha256=WcahTcKYRtZ04WXQoWt5EGCgFPcyHD3EJdlMfxvDt-0,946
|
27
|
-
utilities/hypothesis.py,sha256=
|
27
|
+
utilities/hypothesis.py,sha256=hEyuJoLH0c6So0P5OESvyANpfM49Ld1iYXC4bZvacm4,42603
|
28
28
|
utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
|
29
29
|
utilities/inflect.py,sha256=DbqB5Q9FbRGJ1NbvEiZBirRMxCxgrz91zy5jCO9ZIs0,347
|
30
30
|
utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
|
@@ -33,7 +33,7 @@ utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
|
|
33
33
|
utilities/libcst.py,sha256=Jto5ppzRzsxn4AD32IS8n0lbgLYXwsVJB6EY8giNZyY,4974
|
34
34
|
utilities/lightweight_charts.py,sha256=JrkrAZMo6JID2Eoc9QCc05Y_pK4l2zsApIhmii1z2Ig,2764
|
35
35
|
utilities/logging.py,sha256=zm5k0Cduxtx2H2o7odxUTJtPNkJS85mqHYN1cS5Kc1w,17863
|
36
|
-
utilities/luigi.py,sha256=
|
36
|
+
utilities/luigi.py,sha256=UAt4TDMtinLAN7sipX0jSvH-aZzHUTQbHB3Rwtbq994,4840
|
37
37
|
utilities/math.py,sha256=_6vrDyjtaqE_OFE-F2DNWrDG_J_kMl3nFAJsok9v_bY,26862
|
38
38
|
utilities/memory_profiler.py,sha256=tf2C51P2lCujPGvRt2Rfc7VEw5LDXmVPCG3z_AvBmbU,962
|
39
39
|
utilities/modules.py,sha256=iuvLluJya-hvl1Q25-Jk3dLgx2Es3ck4SjJiEkAlVTs,3195
|
@@ -80,6 +80,7 @@ utilities/text.py,sha256=ymBFlP_cA8OgNnZRVNs7FAh7OG8HxE6YkiLEMZv5g_A,11297
|
|
80
80
|
utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
|
81
81
|
utilities/timer.py,sha256=VeSl3ot8-f4D1d3HjjSsgKvjxHJGXd_sW4KcTExOR64,2475
|
82
82
|
utilities/traceback.py,sha256=cMXrCD59CROnezAU8VW67CxZ8Igc5QmaxlV8qrBvNMs,8504
|
83
|
+
utilities/typed_settings.py,sha256=zUA0_CmVJT5rwrm3e-dZO83OdPXEel4NfVK24NAD5Vk,1779
|
83
84
|
utilities/types.py,sha256=CHQke10ETEpypxppYVhWp1G68S6mvifalrRLolYBcCg,19506
|
84
85
|
utilities/typing.py,sha256=VuGuztLSkTicxgVwI5wrVOTcY70OlzwsTU7LcFVjGlY,14169
|
85
86
|
utilities/tzdata.py,sha256=fgNVj66yUbCSI_-vrRVzSD3gtf-L_8IEJEPjP_Jel5Y,266
|
@@ -91,7 +92,7 @@ utilities/whenever.py,sha256=2NQ-0SnLNW2kFpefP9dVE8H0RbaeusXYLPmv282Jpto,16755
|
|
91
92
|
utilities/whenever2.py,sha256=iFVL4CjuIOpzsDU6li5smHnDEqam30-FtTgXWeHuWiE,7510
|
92
93
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
93
94
|
utilities/zoneinfo.py,sha256=gJPr9l7V8s3Y7TXpCGYEM1S81Rplb9e4MoV9Nvy2VU8,1852
|
94
|
-
dycw_utilities-0.131.
|
95
|
-
dycw_utilities-0.131.
|
96
|
-
dycw_utilities-0.131.
|
97
|
-
dycw_utilities-0.131.
|
95
|
+
dycw_utilities-0.131.15.dist-info/METADATA,sha256=Aztn9G7ACPHL_tGTOBayxzN6aPT_8gmKwsTUcieAoUA,1585
|
96
|
+
dycw_utilities-0.131.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
97
|
+
dycw_utilities-0.131.15.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
98
|
+
dycw_utilities-0.131.15.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/hypothesis.py
CHANGED
@@ -716,85 +716,6 @@ def lists_fixed_length(
|
|
716
716
|
##
|
717
717
|
|
718
718
|
|
719
|
-
@composite
|
720
|
-
def min_and_max_datetimes(
|
721
|
-
draw: DrawFn,
|
722
|
-
/,
|
723
|
-
*,
|
724
|
-
min_value: MaybeSearchStrategy[dt.datetime | None] = None,
|
725
|
-
max_value: MaybeSearchStrategy[dt.datetime | None] = None,
|
726
|
-
time_zone: MaybeSearchStrategy[ZoneInfo | timezone] = UTC,
|
727
|
-
round_: MathRoundMode | None = None,
|
728
|
-
timedelta: dt.timedelta | None = None,
|
729
|
-
rel_tol: float | None = None,
|
730
|
-
abs_tol: float | None = None,
|
731
|
-
valid: bool = False,
|
732
|
-
) -> tuple[dt.datetime, dt.datetime]:
|
733
|
-
"""Strategy for generating min/max datetimes."""
|
734
|
-
match min_value, max_value:
|
735
|
-
case None, None:
|
736
|
-
return draw(
|
737
|
-
pairs(
|
738
|
-
zoned_datetimes(
|
739
|
-
time_zone=time_zone,
|
740
|
-
round_=round_,
|
741
|
-
timedelta=timedelta,
|
742
|
-
rel_tol=rel_tol,
|
743
|
-
abs_tol=abs_tol,
|
744
|
-
valid=valid,
|
745
|
-
),
|
746
|
-
sorted=True,
|
747
|
-
)
|
748
|
-
)
|
749
|
-
case None, dt.datetime():
|
750
|
-
min_value_ = draw(
|
751
|
-
zoned_datetimes(
|
752
|
-
max_value=max_value,
|
753
|
-
time_zone=time_zone,
|
754
|
-
round_=round_,
|
755
|
-
timedelta=timedelta,
|
756
|
-
rel_tol=rel_tol,
|
757
|
-
abs_tol=abs_tol,
|
758
|
-
valid=valid,
|
759
|
-
)
|
760
|
-
)
|
761
|
-
return min_value_, max_value
|
762
|
-
case dt.datetime(), None:
|
763
|
-
max_value_ = draw(
|
764
|
-
zoned_datetimes(
|
765
|
-
min_value=min_value,
|
766
|
-
time_zone=time_zone,
|
767
|
-
round_=round_,
|
768
|
-
timedelta=timedelta,
|
769
|
-
rel_tol=rel_tol,
|
770
|
-
abs_tol=abs_tol,
|
771
|
-
valid=valid,
|
772
|
-
)
|
773
|
-
)
|
774
|
-
return min_value, max_value_
|
775
|
-
case dt.datetime(), dt.datetime():
|
776
|
-
_ = assume(min_value <= max_value)
|
777
|
-
return min_value, max_value
|
778
|
-
case _, _:
|
779
|
-
strategy = zoned_datetimes(
|
780
|
-
time_zone=time_zone,
|
781
|
-
round_=round_,
|
782
|
-
timedelta=timedelta,
|
783
|
-
rel_tol=rel_tol,
|
784
|
-
abs_tol=abs_tol,
|
785
|
-
valid=valid,
|
786
|
-
)
|
787
|
-
min_value_ = draw2(draw, min_value, strategy)
|
788
|
-
max_value_ = draw2(draw, max_value, strategy)
|
789
|
-
_ = assume(min_value_ <= max_value_)
|
790
|
-
return min_value_, max_value_
|
791
|
-
case _ as never:
|
792
|
-
assert_never(never)
|
793
|
-
|
794
|
-
|
795
|
-
##
|
796
|
-
|
797
|
-
|
798
719
|
@composite
|
799
720
|
def months(
|
800
721
|
draw: DrawFn,
|
@@ -1561,14 +1482,12 @@ __all__ = [
|
|
1561
1482
|
"int64s",
|
1562
1483
|
"int_arrays",
|
1563
1484
|
"lists_fixed_length",
|
1564
|
-
"min_and_max_datetimes",
|
1565
1485
|
"months",
|
1566
1486
|
"namespace_mixins",
|
1567
1487
|
"numbers",
|
1568
1488
|
"pairs",
|
1569
1489
|
"paths",
|
1570
1490
|
"plain_datetimes",
|
1571
|
-
"plain_datetimes",
|
1572
1491
|
"plain_datetimes_whenever",
|
1573
1492
|
"random_states",
|
1574
1493
|
"sentinels",
|
utilities/luigi.py
CHANGED
@@ -2,121 +2,91 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from abc import ABC, abstractmethod
|
4
4
|
from pathlib import Path
|
5
|
-
from typing import
|
5
|
+
from typing import (
|
6
|
+
TYPE_CHECKING,
|
7
|
+
Any,
|
8
|
+
Literal,
|
9
|
+
TypeVar,
|
10
|
+
assert_never,
|
11
|
+
cast,
|
12
|
+
overload,
|
13
|
+
override,
|
14
|
+
)
|
6
15
|
|
7
16
|
import luigi
|
8
17
|
from luigi import Parameter, PathParameter, Target, Task
|
9
18
|
from luigi import build as _build
|
10
|
-
|
11
|
-
from
|
19
|
+
from luigi.parameter import ParameterVisibility, _no_value
|
20
|
+
from whenever import ZonedDateTime
|
12
21
|
|
13
22
|
if TYPE_CHECKING:
|
14
|
-
import
|
15
|
-
from collections.abc import Iterable
|
23
|
+
from collections.abc import Callable, Iterable
|
16
24
|
|
17
25
|
from luigi.execution_summary import LuigiRunResult
|
18
26
|
|
19
|
-
from utilities.types import LogLevel,
|
20
|
-
|
21
|
-
|
22
|
-
# parameters
|
23
|
-
|
24
|
-
|
25
|
-
class DateHourParameter(luigi.DateHourParameter):
|
26
|
-
"""A parameter which takes the value of an hourly `dt.datetime`."""
|
27
|
-
|
28
|
-
def __init__(self, interval: int = 1, **kwargs: Any) -> None:
|
29
|
-
super().__init__(interval, EPOCH_UTC, **kwargs)
|
30
|
-
|
31
|
-
@override
|
32
|
-
def normalize(self, dt: MaybeStr[dt.datetime]) -> dt.datetime:
|
33
|
-
from utilities.whenever import ensure_zoned_datetime
|
34
|
-
|
35
|
-
return ensure_zoned_datetime(dt)
|
36
|
-
|
37
|
-
@override
|
38
|
-
def parse(self, s: str) -> dt.datetime:
|
39
|
-
from utilities.whenever import parse_zoned_datetime
|
40
|
-
|
41
|
-
return parse_zoned_datetime(s)
|
42
|
-
|
43
|
-
@override
|
44
|
-
def serialize(self, dt: dt.datetime) -> str:
|
45
|
-
from utilities.whenever import serialize_zoned_datetime
|
46
|
-
|
47
|
-
return serialize_zoned_datetime(dt)
|
48
|
-
|
49
|
-
|
50
|
-
class DateMinuteParameter(luigi.DateMinuteParameter):
|
51
|
-
"""A parameter which takes the value of a minutely `dt.datetime`."""
|
52
|
-
|
53
|
-
def __init__(self, interval: int = 1, **kwargs: Any) -> None:
|
54
|
-
super().__init__(interval=interval, start=EPOCH_UTC, **kwargs)
|
55
|
-
|
56
|
-
@override
|
57
|
-
def normalize(self, dt: MaybeStr[dt.datetime]) -> dt.datetime:
|
58
|
-
from utilities.whenever import ensure_zoned_datetime
|
59
|
-
|
60
|
-
return ensure_zoned_datetime(dt)
|
61
|
-
|
62
|
-
@override
|
63
|
-
def parse(self, s: str) -> dt.datetime:
|
64
|
-
from utilities.whenever import parse_zoned_datetime
|
65
|
-
|
66
|
-
return parse_zoned_datetime(s)
|
67
|
-
|
68
|
-
@override
|
69
|
-
def serialize(self, dt: dt.datetime) -> str:
|
70
|
-
from utilities.whenever import serialize_zoned_datetime
|
71
|
-
|
72
|
-
return serialize_zoned_datetime(dt)
|
73
|
-
|
27
|
+
from utilities.types import DateTimeRoundUnit, LogLevel, PathLike, ZonedDateTimeLike
|
74
28
|
|
75
|
-
class DateSecondParameter(luigi.DateSecondParameter):
|
76
|
-
"""A parameter which takes the value of a secondly `dt.datetime`."""
|
77
29
|
|
78
|
-
|
79
|
-
super().__init__(interval, EPOCH_UTC, **kwargs)
|
30
|
+
_T = TypeVar("_T")
|
80
31
|
|
81
|
-
@override
|
82
|
-
def normalize(self, dt: MaybeStr[dt.datetime]) -> dt.datetime:
|
83
|
-
from utilities.whenever import ensure_zoned_datetime
|
84
|
-
|
85
|
-
return ensure_zoned_datetime(dt)
|
86
|
-
|
87
|
-
@override
|
88
|
-
def parse(self, s: str) -> dt.datetime:
|
89
|
-
from utilities.whenever import parse_zoned_datetime
|
90
|
-
|
91
|
-
return parse_zoned_datetime(s)
|
92
32
|
|
93
|
-
|
94
|
-
def serialize(self, dt: dt.datetime) -> str:
|
95
|
-
from utilities.whenever import serialize_zoned_datetime
|
96
|
-
|
97
|
-
return serialize_zoned_datetime(dt)
|
98
|
-
|
99
|
-
|
100
|
-
class TimeParameter(Parameter):
|
101
|
-
"""A parameter which takes the value of a `dt.time`."""
|
102
|
-
|
103
|
-
@override
|
104
|
-
def normalize(self, x: MaybeStr[dt.time]) -> dt.time:
|
105
|
-
from utilities.whenever import ensure_time
|
106
|
-
|
107
|
-
return ensure_time(x)
|
108
|
-
|
109
|
-
@override
|
110
|
-
def parse(self, x: str) -> dt.time:
|
111
|
-
from utilities.whenever import parse_time
|
112
|
-
|
113
|
-
return parse_time(x)
|
33
|
+
# parameters
|
114
34
|
|
115
|
-
@override
|
116
|
-
def serialize(self, x: dt.time) -> str:
|
117
|
-
from utilities.whenever import serialize_time
|
118
35
|
|
119
|
-
|
36
|
+
class ZonedDateTimeParameter(Parameter):
|
37
|
+
"""A parameter which takes the value of a zoned datetime."""
|
38
|
+
|
39
|
+
_unit: DateTimeRoundUnit
|
40
|
+
_increment: int
|
41
|
+
|
42
|
+
@override
|
43
|
+
def __init__(
|
44
|
+
self,
|
45
|
+
default: Any = _no_value,
|
46
|
+
is_global: bool = False,
|
47
|
+
significant: bool = True,
|
48
|
+
description: str | None = None,
|
49
|
+
config_path: None = None,
|
50
|
+
positional: bool = True,
|
51
|
+
always_in_help: bool = False,
|
52
|
+
batch_method: Callable[[Iterable[_T]], _T] | None = None,
|
53
|
+
visibility: ParameterVisibility = ParameterVisibility.PUBLIC,
|
54
|
+
*,
|
55
|
+
unit: DateTimeRoundUnit = "second",
|
56
|
+
increment: int = 1,
|
57
|
+
) -> None:
|
58
|
+
super().__init__(
|
59
|
+
default,
|
60
|
+
is_global,
|
61
|
+
significant,
|
62
|
+
description,
|
63
|
+
config_path,
|
64
|
+
positional,
|
65
|
+
always_in_help,
|
66
|
+
batch_method,
|
67
|
+
visibility,
|
68
|
+
)
|
69
|
+
self._unit = unit
|
70
|
+
self._increment = increment
|
71
|
+
|
72
|
+
@override
|
73
|
+
def normalize(self, x: ZonedDateTimeLike) -> ZonedDateTime:
|
74
|
+
match x:
|
75
|
+
case ZonedDateTime() as date_time:
|
76
|
+
...
|
77
|
+
case str() as text:
|
78
|
+
date_time = ZonedDateTime.parse_common_iso(text)
|
79
|
+
case _ as never:
|
80
|
+
assert_never(never)
|
81
|
+
return date_time.round(self._unit, increment=self._increment, mode="floor")
|
82
|
+
|
83
|
+
@override
|
84
|
+
def parse(self, x: str) -> ZonedDateTime:
|
85
|
+
return ZonedDateTime.parse_common_iso(x)
|
86
|
+
|
87
|
+
@override
|
88
|
+
def serialize(self, x: ZonedDateTime) -> str:
|
89
|
+
return x.format_common_iso()
|
120
90
|
|
121
91
|
|
122
92
|
# targets
|
@@ -217,12 +187,9 @@ def build(
|
|
217
187
|
|
218
188
|
|
219
189
|
__all__ = [
|
220
|
-
"DateHourParameter",
|
221
|
-
"DateMinuteParameter",
|
222
|
-
"DateSecondParameter",
|
223
190
|
"ExternalFile",
|
224
191
|
"ExternalTask",
|
225
192
|
"PathTarget",
|
226
|
-
"
|
193
|
+
"ZonedDateTimeParameter",
|
227
194
|
"build",
|
228
195
|
]
|
@@ -0,0 +1,61 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import TYPE_CHECKING, Any, TypeVar, override
|
4
|
+
|
5
|
+
from typed_settings.converters import TSConverter
|
6
|
+
from whenever import (
|
7
|
+
Date,
|
8
|
+
DateDelta,
|
9
|
+
DateTimeDelta,
|
10
|
+
PlainDateTime,
|
11
|
+
Time,
|
12
|
+
TimeDelta,
|
13
|
+
ZonedDateTime,
|
14
|
+
)
|
15
|
+
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from collections.abc import Callable
|
18
|
+
|
19
|
+
|
20
|
+
_T = TypeVar("_T")
|
21
|
+
|
22
|
+
|
23
|
+
class ExtendedTSConverter(TSConverter):
|
24
|
+
"""An extension of the TSConverter for custom types."""
|
25
|
+
|
26
|
+
@override
|
27
|
+
def __init__(
|
28
|
+
self,
|
29
|
+
*,
|
30
|
+
resolve_paths: bool = True,
|
31
|
+
strlist_sep: str | Callable[[str], list] | None = ":",
|
32
|
+
) -> None:
|
33
|
+
super().__init__(resolve_paths=resolve_paths, strlist_sep=strlist_sep)
|
34
|
+
cases: list[tuple[type[Any], Callable[..., Any]]] = [
|
35
|
+
(Date, Date.parse_common_iso),
|
36
|
+
(DateDelta, DateDelta.parse_common_iso),
|
37
|
+
(DateTimeDelta, DateTimeDelta.parse_common_iso),
|
38
|
+
(PlainDateTime, PlainDateTime.parse_common_iso),
|
39
|
+
(Time, Time.parse_common_iso),
|
40
|
+
(TimeDelta, TimeDelta.parse_common_iso),
|
41
|
+
(ZonedDateTime, ZonedDateTime.parse_common_iso),
|
42
|
+
]
|
43
|
+
extras = {cls: _make_converter(cls, func) for cls, func in cases}
|
44
|
+
self.scalar_converters |= extras
|
45
|
+
|
46
|
+
|
47
|
+
def _make_converter(
|
48
|
+
cls: type[_T], parser: Callable[[str], _T], /
|
49
|
+
) -> Callable[[Any, type[Any]], Any]:
|
50
|
+
def hook(value: _T | str, _: type[_T] = cls, /) -> Any:
|
51
|
+
if not isinstance(value, (cls, str)): # pragma: no cover
|
52
|
+
msg = f"Invalid type {type(value).__name__!r}; expected '{cls.__name__}' or 'str'"
|
53
|
+
raise TypeError(msg)
|
54
|
+
if isinstance(value, str):
|
55
|
+
return parser(value)
|
56
|
+
return value
|
57
|
+
|
58
|
+
return hook
|
59
|
+
|
60
|
+
|
61
|
+
__all__ = ["ExtendedTSConverter"]
|
File without changes
|
File without changes
|