dycw-utilities 0.129.10__py3-none-any.whl → 0.175.17__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.175.17.dist-info/METADATA +34 -0
- dycw_utilities-0.175.17.dist-info/RECORD +103 -0
- dycw_utilities-0.175.17.dist-info/WHEEL +4 -0
- dycw_utilities-0.175.17.dist-info/entry_points.txt +4 -0
- utilities/__init__.py +1 -1
- utilities/altair.py +14 -14
- utilities/asyncio.py +350 -819
- utilities/atomicwrites.py +18 -6
- utilities/atools.py +77 -22
- utilities/cachetools.py +24 -29
- utilities/click.py +393 -237
- utilities/concurrent.py +8 -11
- utilities/contextlib.py +216 -17
- utilities/contextvars.py +20 -1
- utilities/cryptography.py +3 -3
- utilities/dataclasses.py +83 -118
- utilities/docker.py +293 -0
- utilities/enum.py +26 -23
- utilities/errors.py +17 -3
- utilities/fastapi.py +29 -65
- utilities/fpdf2.py +3 -3
- utilities/functions.py +169 -416
- utilities/functools.py +18 -19
- utilities/git.py +9 -30
- utilities/grp.py +28 -0
- utilities/gzip.py +31 -0
- utilities/http.py +3 -2
- utilities/hypothesis.py +738 -589
- utilities/importlib.py +17 -1
- utilities/inflect.py +25 -0
- utilities/iterables.py +194 -262
- utilities/jinja2.py +148 -0
- utilities/json.py +70 -0
- utilities/libcst.py +38 -17
- utilities/lightweight_charts.py +5 -9
- utilities/logging.py +345 -543
- utilities/math.py +18 -13
- utilities/memory_profiler.py +11 -15
- utilities/more_itertools.py +200 -131
- utilities/operator.py +33 -29
- utilities/optuna.py +6 -6
- utilities/orjson.py +272 -137
- utilities/os.py +61 -4
- utilities/parse.py +59 -61
- utilities/pathlib.py +281 -40
- utilities/permissions.py +298 -0
- utilities/pickle.py +2 -2
- utilities/platform.py +24 -5
- utilities/polars.py +1214 -430
- utilities/polars_ols.py +1 -1
- utilities/postgres.py +408 -0
- utilities/pottery.py +113 -26
- utilities/pqdm.py +10 -11
- utilities/psutil.py +6 -57
- utilities/pwd.py +28 -0
- utilities/pydantic.py +4 -54
- utilities/pydantic_settings.py +240 -0
- utilities/pydantic_settings_sops.py +76 -0
- utilities/pyinstrument.py +8 -10
- utilities/pytest.py +227 -121
- utilities/pytest_plugins/__init__.py +1 -0
- utilities/pytest_plugins/pytest_randomly.py +23 -0
- utilities/pytest_plugins/pytest_regressions.py +56 -0
- utilities/pytest_regressions.py +26 -46
- utilities/random.py +13 -9
- utilities/re.py +58 -28
- utilities/redis.py +401 -550
- utilities/scipy.py +1 -1
- utilities/sentinel.py +10 -0
- utilities/shelve.py +4 -1
- utilities/shutil.py +25 -0
- utilities/slack_sdk.py +36 -106
- utilities/sqlalchemy.py +502 -473
- utilities/sqlalchemy_polars.py +38 -94
- utilities/string.py +2 -3
- utilities/subprocess.py +1572 -0
- utilities/tempfile.py +86 -4
- utilities/testbook.py +50 -0
- utilities/text.py +165 -42
- utilities/timer.py +37 -65
- utilities/traceback.py +158 -929
- utilities/types.py +146 -116
- utilities/typing.py +531 -71
- utilities/tzdata.py +1 -53
- utilities/tzlocal.py +6 -23
- utilities/uuid.py +43 -5
- utilities/version.py +27 -26
- utilities/whenever.py +1776 -386
- utilities/zoneinfo.py +84 -22
- dycw_utilities-0.129.10.dist-info/METADATA +0 -241
- dycw_utilities-0.129.10.dist-info/RECORD +0 -96
- dycw_utilities-0.129.10.dist-info/WHEEL +0 -4
- dycw_utilities-0.129.10.dist-info/licenses/LICENSE +0 -21
- utilities/datetime.py +0 -1409
- utilities/eventkit.py +0 -402
- utilities/loguru.py +0 -144
- utilities/luigi.py +0 -228
- utilities/period.py +0 -324
- utilities/pyrsistent.py +0 -89
- utilities/python_dotenv.py +0 -105
- utilities/streamlit.py +0 -105
- utilities/sys.py +0 -87
- utilities/tenacity.py +0 -145
utilities/click.py
CHANGED
|
@@ -1,65 +1,60 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import enum
|
|
4
|
+
import ipaddress
|
|
4
5
|
import pathlib
|
|
5
|
-
|
|
6
|
-
from
|
|
6
|
+
import uuid
|
|
7
|
+
from enum import StrEnum
|
|
8
|
+
from typing import TYPE_CHECKING, TypedDict, assert_never, override
|
|
7
9
|
|
|
8
|
-
import
|
|
10
|
+
import whenever
|
|
9
11
|
from click import Choice, Context, Parameter, ParamType
|
|
10
|
-
from click.types import
|
|
11
|
-
BoolParamType,
|
|
12
|
-
FloatParamType,
|
|
13
|
-
IntParamType,
|
|
14
|
-
StringParamType,
|
|
15
|
-
UUIDParameterType,
|
|
16
|
-
)
|
|
12
|
+
from click.types import IntParamType, StringParamType
|
|
17
13
|
|
|
18
|
-
import utilities.datetime
|
|
19
|
-
import utilities.types
|
|
20
|
-
from utilities.datetime import EnsureMonthError, MonthLike, ensure_month
|
|
21
14
|
from utilities.enum import EnsureEnumError, ensure_enum
|
|
22
|
-
from utilities.functions import EnsureStrError, ensure_str, get_class_name
|
|
23
|
-
from utilities.iterables import is_iterable_not_str
|
|
15
|
+
from utilities.functions import EnsureStrError, ensure_str, get_class, get_class_name
|
|
16
|
+
from utilities.iterables import is_iterable_not_str, one_unique
|
|
17
|
+
from utilities.parse import ParseObjectError, parse_object
|
|
24
18
|
from utilities.text import split_str
|
|
25
|
-
from utilities.types import (
|
|
26
|
-
DateLike,
|
|
27
|
-
DateTimeLike,
|
|
28
|
-
EnumLike,
|
|
29
|
-
MaybeStr,
|
|
30
|
-
TEnum,
|
|
31
|
-
TimeDeltaLike,
|
|
32
|
-
TimeLike,
|
|
33
|
-
)
|
|
34
19
|
|
|
35
20
|
if TYPE_CHECKING:
|
|
36
|
-
from collections.abc import Iterable
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
21
|
+
from collections.abc import Iterable
|
|
22
|
+
|
|
23
|
+
from utilities.types import (
|
|
24
|
+
DateDeltaLike,
|
|
25
|
+
DateLike,
|
|
26
|
+
DateTimeDeltaLike,
|
|
27
|
+
EnumLike,
|
|
28
|
+
IPv4AddressLike,
|
|
29
|
+
IPv6AddressLike,
|
|
30
|
+
MaybeStr,
|
|
31
|
+
MonthDayLike,
|
|
32
|
+
PathLike,
|
|
33
|
+
PlainDateTimeLike,
|
|
34
|
+
TimeDeltaLike,
|
|
35
|
+
TimeLike,
|
|
36
|
+
YearMonthLike,
|
|
37
|
+
ZonedDateTimeLike,
|
|
38
|
+
)
|
|
40
39
|
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ExistingFilePath = click.Path(
|
|
45
|
-
exists=True, file_okay=True, dir_okay=False, path_type=pathlib.Path
|
|
46
|
-
)
|
|
47
|
-
ExistingDirPath = click.Path(
|
|
48
|
-
exists=True, file_okay=False, dir_okay=True, path_type=pathlib.Path
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class _HelpOptionNames(TypedDict):
|
|
53
|
-
help_option_names: Sequence[str]
|
|
41
|
+
class _ContextSettings(TypedDict):
|
|
42
|
+
context_settings: _ContextSettingsInner
|
|
54
43
|
|
|
55
44
|
|
|
56
|
-
class
|
|
57
|
-
|
|
45
|
+
class _ContextSettingsInner(TypedDict):
|
|
46
|
+
max_content_width: int
|
|
47
|
+
help_option_names: list[str]
|
|
48
|
+
show_default: bool
|
|
58
49
|
|
|
59
50
|
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
_MAX_CONTENT_WIDTH = 120
|
|
52
|
+
_CONTEXT_SETTINGS_INNER = _ContextSettingsInner(
|
|
53
|
+
max_content_width=_MAX_CONTENT_WIDTH,
|
|
54
|
+
help_option_names=["-h", "--help"],
|
|
55
|
+
show_default=True,
|
|
62
56
|
)
|
|
57
|
+
CONTEXT_SETTINGS = _ContextSettings(context_settings=_CONTEXT_SETTINGS_INNER)
|
|
63
58
|
|
|
64
59
|
|
|
65
60
|
# parameters
|
|
@@ -77,20 +72,24 @@ class Date(ParamType):
|
|
|
77
72
|
@override
|
|
78
73
|
def convert(
|
|
79
74
|
self, value: DateLike, param: Parameter | None, ctx: Context | None
|
|
80
|
-
) ->
|
|
75
|
+
) -> whenever.Date:
|
|
81
76
|
"""Convert a value into the `Date` type."""
|
|
82
|
-
|
|
77
|
+
match value:
|
|
78
|
+
case whenever.Date():
|
|
79
|
+
return value
|
|
80
|
+
case str():
|
|
81
|
+
try:
|
|
82
|
+
return whenever.Date.parse_iso(value)
|
|
83
|
+
except ValueError as error:
|
|
84
|
+
self.fail(str(error), param, ctx)
|
|
85
|
+
case never:
|
|
86
|
+
assert_never(never)
|
|
83
87
|
|
|
84
|
-
try:
|
|
85
|
-
return ensure_date(value)
|
|
86
|
-
except EnsureDateError as error:
|
|
87
|
-
self.fail(str(error), param, ctx)
|
|
88
88
|
|
|
89
|
+
class DateDelta(ParamType):
|
|
90
|
+
"""A date-delta-valued parameter."""
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
"""A duration-valued parameter."""
|
|
92
|
-
|
|
93
|
-
name = "duration"
|
|
92
|
+
name = "date delta"
|
|
94
93
|
|
|
95
94
|
@override
|
|
96
95
|
def __repr__(self) -> str:
|
|
@@ -98,27 +97,58 @@ class Duration(ParamType):
|
|
|
98
97
|
|
|
99
98
|
@override
|
|
100
99
|
def convert(
|
|
101
|
-
self,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
100
|
+
self, value: DateDeltaLike, param: Parameter | None, ctx: Context | None
|
|
101
|
+
) -> whenever.DateDelta:
|
|
102
|
+
"""Convert a value into the `DateDelta` type."""
|
|
103
|
+
match value:
|
|
104
|
+
case whenever.DateDelta():
|
|
105
|
+
return value
|
|
106
|
+
case str():
|
|
107
|
+
try:
|
|
108
|
+
return whenever.DateDelta.parse_iso(value)
|
|
109
|
+
except ValueError as error:
|
|
110
|
+
self.fail(str(error), param, ctx)
|
|
111
|
+
case never:
|
|
112
|
+
assert_never(never)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class DateTimeDelta(ParamType):
|
|
116
|
+
"""A date-delta-valued parameter."""
|
|
117
|
+
|
|
118
|
+
name = "date-time delta"
|
|
113
119
|
|
|
120
|
+
@override
|
|
121
|
+
def __repr__(self) -> str:
|
|
122
|
+
return self.name.upper()
|
|
114
123
|
|
|
115
|
-
|
|
124
|
+
@override
|
|
125
|
+
def convert(
|
|
126
|
+
self, value: DateTimeDeltaLike, param: Parameter | None, ctx: Context | None
|
|
127
|
+
) -> whenever.DateTimeDelta:
|
|
128
|
+
"""Convert a value into the `DateTimeDelta` type."""
|
|
129
|
+
match value:
|
|
130
|
+
case whenever.DateTimeDelta():
|
|
131
|
+
return value
|
|
132
|
+
case str():
|
|
133
|
+
try:
|
|
134
|
+
return whenever.DateTimeDelta.parse_iso(value)
|
|
135
|
+
except ValueError as error:
|
|
136
|
+
self.fail(str(error), param, ctx)
|
|
137
|
+
case never:
|
|
138
|
+
assert_never(never)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class Enum[E: enum.Enum](ParamType):
|
|
116
142
|
"""An enum-valued parameter."""
|
|
117
143
|
|
|
118
|
-
|
|
144
|
+
@override
|
|
145
|
+
def __init__(
|
|
146
|
+
self, enum: type[E], /, *, value: bool = False, case_sensitive: bool = False
|
|
147
|
+
) -> None:
|
|
119
148
|
cls = get_class_name(enum)
|
|
120
|
-
self.name = f"
|
|
149
|
+
self.name = f"enum[{cls}]"
|
|
121
150
|
self._enum = enum
|
|
151
|
+
self._value = issubclass(self._enum, StrEnum) or value
|
|
122
152
|
self._case_sensitive = case_sensitive
|
|
123
153
|
super().__init__()
|
|
124
154
|
|
|
@@ -129,8 +159,8 @@ class Enum(ParamType, Generic[TEnum]):
|
|
|
129
159
|
|
|
130
160
|
@override
|
|
131
161
|
def convert(
|
|
132
|
-
self, value: EnumLike[
|
|
133
|
-
) ->
|
|
162
|
+
self, value: EnumLike[E], param: Parameter | None, ctx: Context | None
|
|
163
|
+
) -> E:
|
|
134
164
|
"""Convert a value into the `Enum` type."""
|
|
135
165
|
try:
|
|
136
166
|
return ensure_enum(value, self._enum, case_sensitive=self._case_sensitive)
|
|
@@ -140,34 +170,160 @@ class Enum(ParamType, Generic[TEnum]):
|
|
|
140
170
|
@override
|
|
141
171
|
def get_metavar(self, param: Parameter, ctx: Context) -> str | None:
|
|
142
172
|
_ = ctx
|
|
143
|
-
desc = ",".join(e.name for e in self._enum)
|
|
173
|
+
desc = ",".join(str(e.value) if self._value else e.name for e in self._enum)
|
|
144
174
|
return _make_metavar(param, desc)
|
|
145
175
|
|
|
146
176
|
|
|
147
|
-
class
|
|
148
|
-
"""
|
|
177
|
+
class EnumPartial[E: enum.Enum](ParamType):
|
|
178
|
+
"""An enum-valued parameter."""
|
|
149
179
|
|
|
150
|
-
|
|
180
|
+
@override
|
|
181
|
+
def __init__(
|
|
182
|
+
self,
|
|
183
|
+
members: Iterable[E],
|
|
184
|
+
/,
|
|
185
|
+
*,
|
|
186
|
+
value: bool = False,
|
|
187
|
+
case_sensitive: bool = False,
|
|
188
|
+
) -> None:
|
|
189
|
+
self._members = list(members)
|
|
190
|
+
self._enum = one_unique(get_class(e) for e in self._members)
|
|
191
|
+
cls = get_class_name(self._enum)
|
|
192
|
+
self.name = f"enum-partial[{cls}]"
|
|
193
|
+
self._value = issubclass(self._enum, StrEnum) or value
|
|
194
|
+
self._case_sensitive = case_sensitive
|
|
195
|
+
super().__init__()
|
|
151
196
|
|
|
152
197
|
@override
|
|
153
198
|
def __repr__(self) -> str:
|
|
154
|
-
|
|
199
|
+
cls = get_class_name(self._enum)
|
|
200
|
+
return f"ENUMPARTIAL[{cls}]"
|
|
155
201
|
|
|
156
202
|
@override
|
|
157
203
|
def convert(
|
|
158
|
-
self, value:
|
|
159
|
-
) ->
|
|
160
|
-
"""Convert a value into the `
|
|
204
|
+
self, value: EnumLike[E], param: Parameter | None, ctx: Context | None
|
|
205
|
+
) -> E:
|
|
206
|
+
"""Convert a value into the `Enum` type."""
|
|
161
207
|
try:
|
|
162
|
-
|
|
163
|
-
except
|
|
208
|
+
enum = ensure_enum(value, self._enum, case_sensitive=self._case_sensitive)
|
|
209
|
+
except EnsureEnumError as error:
|
|
164
210
|
self.fail(str(error), param, ctx)
|
|
211
|
+
if enum in self._members:
|
|
212
|
+
return enum
|
|
213
|
+
return self.fail(f"{enum.value!r} is not a selected member")
|
|
214
|
+
|
|
215
|
+
@override
|
|
216
|
+
def get_metavar(self, param: Parameter, ctx: Context) -> str | None:
|
|
217
|
+
_ = ctx
|
|
218
|
+
desc = ",".join(str(e.value) if self._value else e.name for e in self._members)
|
|
219
|
+
return _make_metavar(param, desc)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class IPv4Address(ParamType):
|
|
223
|
+
"""An IPv4 address-valued parameter."""
|
|
224
|
+
|
|
225
|
+
name = "ipv4 address"
|
|
226
|
+
|
|
227
|
+
@override
|
|
228
|
+
def __repr__(self) -> str:
|
|
229
|
+
return self.name.upper()
|
|
230
|
+
|
|
231
|
+
@override
|
|
232
|
+
def convert(
|
|
233
|
+
self, value: IPv4AddressLike, param: Parameter | None, ctx: Context | None
|
|
234
|
+
) -> ipaddress.IPv4Address:
|
|
235
|
+
"""Convert a value into the `IPv4Address` type."""
|
|
236
|
+
match value:
|
|
237
|
+
case ipaddress.IPv4Address():
|
|
238
|
+
return value
|
|
239
|
+
case str():
|
|
240
|
+
try:
|
|
241
|
+
return parse_object(ipaddress.IPv4Address, value)
|
|
242
|
+
except ParseObjectError as error:
|
|
243
|
+
self.fail(str(error), param, ctx)
|
|
244
|
+
case never:
|
|
245
|
+
assert_never(never)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class IPv6Address(ParamType):
|
|
249
|
+
"""An IPv6 address-valued parameter."""
|
|
250
|
+
|
|
251
|
+
name = "ipv6 address"
|
|
252
|
+
|
|
253
|
+
@override
|
|
254
|
+
def __repr__(self) -> str:
|
|
255
|
+
return self.name.upper()
|
|
256
|
+
|
|
257
|
+
@override
|
|
258
|
+
def convert(
|
|
259
|
+
self, value: IPv6AddressLike, param: Parameter | None, ctx: Context | None
|
|
260
|
+
) -> ipaddress.IPv6Address:
|
|
261
|
+
"""Convert a value into the `IPv6Address` type."""
|
|
262
|
+
match value:
|
|
263
|
+
case ipaddress.IPv6Address():
|
|
264
|
+
return value
|
|
265
|
+
case str():
|
|
266
|
+
try:
|
|
267
|
+
return parse_object(ipaddress.IPv6Address, value)
|
|
268
|
+
except ParseObjectError as error:
|
|
269
|
+
self.fail(str(error), param, ctx)
|
|
270
|
+
case never:
|
|
271
|
+
assert_never(never)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class MonthDay(ParamType):
|
|
275
|
+
"""A month-day parameter."""
|
|
276
|
+
|
|
277
|
+
name = "month-day"
|
|
278
|
+
|
|
279
|
+
@override
|
|
280
|
+
def __repr__(self) -> str:
|
|
281
|
+
return self.name.upper()
|
|
282
|
+
|
|
283
|
+
@override
|
|
284
|
+
def convert(
|
|
285
|
+
self, value: MonthDayLike, param: Parameter | None, ctx: Context | None
|
|
286
|
+
) -> whenever.MonthDay:
|
|
287
|
+
"""Convert a value into the `MonthDay` type."""
|
|
288
|
+
match value:
|
|
289
|
+
case whenever.MonthDay():
|
|
290
|
+
return value
|
|
291
|
+
case str():
|
|
292
|
+
try:
|
|
293
|
+
return whenever.MonthDay.parse_iso(value)
|
|
294
|
+
except ValueError as error:
|
|
295
|
+
self.fail(str(error), param, ctx)
|
|
296
|
+
case never:
|
|
297
|
+
assert_never(never)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class Path(ParamType):
|
|
301
|
+
"""A path-valued parameter."""
|
|
302
|
+
|
|
303
|
+
name = "path"
|
|
304
|
+
|
|
305
|
+
@override
|
|
306
|
+
def __repr__(self) -> str:
|
|
307
|
+
return self.name.upper()
|
|
308
|
+
|
|
309
|
+
@override
|
|
310
|
+
def convert(
|
|
311
|
+
self, value: PathLike, param: Parameter | None, ctx: Context | None
|
|
312
|
+
) -> pathlib.Path:
|
|
313
|
+
"""Convert a value into the `Path` type."""
|
|
314
|
+
match value:
|
|
315
|
+
case pathlib.Path():
|
|
316
|
+
return value.expanduser()
|
|
317
|
+
case str():
|
|
318
|
+
return pathlib.Path(value).expanduser()
|
|
319
|
+
case never:
|
|
320
|
+
assert_never(never)
|
|
165
321
|
|
|
166
322
|
|
|
167
323
|
class PlainDateTime(ParamType):
|
|
168
324
|
"""A local-datetime-valued parameter."""
|
|
169
325
|
|
|
170
|
-
name = "plain
|
|
326
|
+
name = "plain date-time"
|
|
171
327
|
|
|
172
328
|
@override
|
|
173
329
|
def __repr__(self) -> str:
|
|
@@ -175,15 +331,19 @@ class PlainDateTime(ParamType):
|
|
|
175
331
|
|
|
176
332
|
@override
|
|
177
333
|
def convert(
|
|
178
|
-
self, value:
|
|
179
|
-
) ->
|
|
180
|
-
"""Convert a value into the `
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
334
|
+
self, value: PlainDateTimeLike, param: Parameter | None, ctx: Context | None
|
|
335
|
+
) -> whenever.PlainDateTime:
|
|
336
|
+
"""Convert a value into the `PlainDateTime` type."""
|
|
337
|
+
match value:
|
|
338
|
+
case whenever.PlainDateTime():
|
|
339
|
+
return value
|
|
340
|
+
case str():
|
|
341
|
+
try:
|
|
342
|
+
return whenever.PlainDateTime.parse_iso(value)
|
|
343
|
+
except ValueError as error:
|
|
344
|
+
self.fail(str(error), param, ctx)
|
|
345
|
+
case never:
|
|
346
|
+
assert_never(never)
|
|
187
347
|
|
|
188
348
|
|
|
189
349
|
class Time(ParamType):
|
|
@@ -198,20 +358,50 @@ class Time(ParamType):
|
|
|
198
358
|
@override
|
|
199
359
|
def convert(
|
|
200
360
|
self, value: TimeLike, param: Parameter | None, ctx: Context | None
|
|
201
|
-
) ->
|
|
361
|
+
) -> whenever.Time:
|
|
202
362
|
"""Convert a value into the `Time` type."""
|
|
203
|
-
|
|
363
|
+
match value:
|
|
364
|
+
case whenever.Time():
|
|
365
|
+
return value
|
|
366
|
+
case str():
|
|
367
|
+
try:
|
|
368
|
+
return whenever.Time.parse_iso(value)
|
|
369
|
+
except ValueError as error:
|
|
370
|
+
self.fail(str(error), param, ctx)
|
|
371
|
+
case never:
|
|
372
|
+
assert_never(never)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class TimeDelta(ParamType):
|
|
376
|
+
"""A timedelta-valued parameter."""
|
|
204
377
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
378
|
+
name = "time-delta"
|
|
379
|
+
|
|
380
|
+
@override
|
|
381
|
+
def __repr__(self) -> str:
|
|
382
|
+
return self.name.upper()
|
|
209
383
|
|
|
384
|
+
@override
|
|
385
|
+
def convert(
|
|
386
|
+
self, value: TimeDeltaLike, param: Parameter | None, ctx: Context | None
|
|
387
|
+
) -> whenever.TimeDelta:
|
|
388
|
+
"""Convert a value into the `TimeDelta` type."""
|
|
389
|
+
match value:
|
|
390
|
+
case whenever.TimeDelta():
|
|
391
|
+
return value
|
|
392
|
+
case str():
|
|
393
|
+
try:
|
|
394
|
+
return whenever.TimeDelta.parse_iso(value)
|
|
395
|
+
except ValueError as error:
|
|
396
|
+
self.fail(str(error), param, ctx)
|
|
397
|
+
case never:
|
|
398
|
+
assert_never(never)
|
|
210
399
|
|
|
211
|
-
class Timedelta(ParamType):
|
|
212
|
-
"""A timedelta-valued parameter."""
|
|
213
400
|
|
|
214
|
-
|
|
401
|
+
class UUID(ParamType):
|
|
402
|
+
"""A UUID-valued parameter."""
|
|
403
|
+
|
|
404
|
+
name = "uuid"
|
|
215
405
|
|
|
216
406
|
@override
|
|
217
407
|
def __repr__(self) -> str:
|
|
@@ -219,21 +409,51 @@ class Timedelta(ParamType):
|
|
|
219
409
|
|
|
220
410
|
@override
|
|
221
411
|
def convert(
|
|
222
|
-
self, value:
|
|
223
|
-
) ->
|
|
224
|
-
"""Convert a value into the `
|
|
225
|
-
|
|
412
|
+
self, value: uuid.UUID | str, param: Parameter | None, ctx: Context | None
|
|
413
|
+
) -> uuid.UUID:
|
|
414
|
+
"""Convert a value into the `UUID` type."""
|
|
415
|
+
match value:
|
|
416
|
+
case uuid.UUID():
|
|
417
|
+
return value
|
|
418
|
+
case str():
|
|
419
|
+
try:
|
|
420
|
+
return uuid.UUID(value)
|
|
421
|
+
except ValueError as error:
|
|
422
|
+
self.fail(str(error), param, ctx)
|
|
423
|
+
case never:
|
|
424
|
+
assert_never(never)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
class YearMonth(ParamType):
|
|
428
|
+
"""A year-month parameter."""
|
|
429
|
+
|
|
430
|
+
name = "year-month"
|
|
226
431
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
432
|
+
@override
|
|
433
|
+
def __repr__(self) -> str:
|
|
434
|
+
return self.name.upper()
|
|
435
|
+
|
|
436
|
+
@override
|
|
437
|
+
def convert(
|
|
438
|
+
self, value: YearMonthLike, param: Parameter | None, ctx: Context | None
|
|
439
|
+
) -> whenever.YearMonth:
|
|
440
|
+
"""Convert a value into the `YearMonth` type."""
|
|
441
|
+
match value:
|
|
442
|
+
case whenever.YearMonth():
|
|
443
|
+
return value
|
|
444
|
+
case str():
|
|
445
|
+
try:
|
|
446
|
+
return whenever.YearMonth.parse_iso(value)
|
|
447
|
+
except ValueError as error:
|
|
448
|
+
self.fail(str(error), param, ctx)
|
|
449
|
+
case never:
|
|
450
|
+
assert_never(never)
|
|
231
451
|
|
|
232
452
|
|
|
233
453
|
class ZonedDateTime(ParamType):
|
|
234
454
|
"""A zoned-datetime-valued parameter."""
|
|
235
455
|
|
|
236
|
-
name = "zoned
|
|
456
|
+
name = "zoned date-time"
|
|
237
457
|
|
|
238
458
|
@override
|
|
239
459
|
def __repr__(self) -> str:
|
|
@@ -241,41 +461,42 @@ class ZonedDateTime(ParamType):
|
|
|
241
461
|
|
|
242
462
|
@override
|
|
243
463
|
def convert(
|
|
244
|
-
self, value:
|
|
245
|
-
) ->
|
|
246
|
-
"""Convert a value into the `
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
464
|
+
self, value: ZonedDateTimeLike, param: Parameter | None, ctx: Context | None
|
|
465
|
+
) -> whenever.ZonedDateTime:
|
|
466
|
+
"""Convert a value into the `ZonedDateTime` type."""
|
|
467
|
+
match value:
|
|
468
|
+
case whenever.ZonedDateTime():
|
|
469
|
+
return value
|
|
470
|
+
case str():
|
|
471
|
+
try:
|
|
472
|
+
return whenever.ZonedDateTime.parse_iso(value)
|
|
473
|
+
except ValueError as error:
|
|
474
|
+
self.fail(str(error), param, ctx)
|
|
475
|
+
case never:
|
|
476
|
+
assert_never(never)
|
|
253
477
|
|
|
254
478
|
|
|
255
479
|
# parameters - frozenset
|
|
256
480
|
|
|
257
481
|
|
|
258
|
-
class FrozenSetParameter
|
|
482
|
+
class FrozenSetParameter[P: ParamType, T](ParamType):
|
|
259
483
|
"""A frozenset-valued parameter."""
|
|
260
484
|
|
|
261
|
-
|
|
262
|
-
|
|
485
|
+
@override
|
|
486
|
+
def __init__(self, param: P, /, *, separator: str = ",") -> None:
|
|
487
|
+
self.name = f"frozenset[{param.name}]"
|
|
263
488
|
self._param = param
|
|
264
489
|
self._separator = separator
|
|
265
490
|
super().__init__()
|
|
266
491
|
|
|
267
492
|
@override
|
|
268
493
|
def __repr__(self) -> str:
|
|
269
|
-
|
|
270
|
-
return f"FROZENSET[{desc}]"
|
|
494
|
+
return f"FROZENSET[{self._param!r}]"
|
|
271
495
|
|
|
272
496
|
@override
|
|
273
497
|
def convert(
|
|
274
|
-
self,
|
|
275
|
-
|
|
276
|
-
param: Parameter | None,
|
|
277
|
-
ctx: Context | None,
|
|
278
|
-
) -> frozenset[_T]:
|
|
498
|
+
self, value: MaybeStr[Iterable[T]], param: Parameter | None, ctx: Context | None
|
|
499
|
+
) -> frozenset[T]:
|
|
279
500
|
"""Convert a value into the `ListDates` type."""
|
|
280
501
|
if is_iterable_not_str(value):
|
|
281
502
|
return frozenset(value)
|
|
@@ -297,26 +518,13 @@ class FrozenSetParameter(ParamType, Generic[_TParam, _T]):
|
|
|
297
518
|
return _make_metavar(param, desc)
|
|
298
519
|
|
|
299
520
|
|
|
300
|
-
class FrozenSetBools(FrozenSetParameter[BoolParamType, str]):
|
|
301
|
-
"""A frozenset-of-bools-valued parameter."""
|
|
302
|
-
|
|
303
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
304
|
-
super().__init__(BoolParamType(), separator=separator)
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
class FrozenSetDates(FrozenSetParameter[Date, dt.date]):
|
|
308
|
-
"""A frozenset-of-dates-valued parameter."""
|
|
309
|
-
|
|
310
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
311
|
-
super().__init__(Date(), separator=separator)
|
|
312
|
-
|
|
313
|
-
|
|
314
521
|
class FrozenSetChoices(FrozenSetParameter[Choice, str]):
|
|
315
522
|
"""A frozenset-of-choices-valued parameter."""
|
|
316
523
|
|
|
524
|
+
@override
|
|
317
525
|
def __init__(
|
|
318
526
|
self,
|
|
319
|
-
choices:
|
|
527
|
+
choices: list[str],
|
|
320
528
|
/,
|
|
321
529
|
*,
|
|
322
530
|
case_sensitive: bool = False,
|
|
@@ -327,79 +535,53 @@ class FrozenSetChoices(FrozenSetParameter[Choice, str]):
|
|
|
327
535
|
)
|
|
328
536
|
|
|
329
537
|
|
|
330
|
-
class FrozenSetEnums(FrozenSetParameter[Enum[
|
|
538
|
+
class FrozenSetEnums[E: enum.Enum](FrozenSetParameter[Enum[E], E]):
|
|
331
539
|
"""A frozenset-of-enums-valued parameter."""
|
|
332
540
|
|
|
541
|
+
@override
|
|
333
542
|
def __init__(
|
|
334
|
-
self,
|
|
335
|
-
enum: type[TEnum],
|
|
336
|
-
/,
|
|
337
|
-
*,
|
|
338
|
-
case_sensitive: bool = False,
|
|
339
|
-
separator: str = ",",
|
|
543
|
+
self, enum: type[E], /, *, case_sensitive: bool = False, separator: str = ","
|
|
340
544
|
) -> None:
|
|
341
545
|
super().__init__(Enum(enum, case_sensitive=case_sensitive), separator=separator)
|
|
342
546
|
|
|
343
547
|
|
|
344
|
-
class FrozenSetFloats(FrozenSetParameter[FloatParamType, float]):
|
|
345
|
-
"""A frozenset-of-floats-valued parameter."""
|
|
346
|
-
|
|
347
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
348
|
-
super().__init__(FloatParamType(), separator=separator)
|
|
349
|
-
|
|
350
|
-
|
|
351
548
|
class FrozenSetInts(FrozenSetParameter[IntParamType, int]):
|
|
352
549
|
"""A frozenset-of-ints-valued parameter."""
|
|
353
550
|
|
|
551
|
+
@override
|
|
354
552
|
def __init__(self, *, separator: str = ",") -> None:
|
|
355
553
|
super().__init__(IntParamType(), separator=separator)
|
|
356
554
|
|
|
357
555
|
|
|
358
|
-
class FrozenSetMonths(FrozenSetParameter[Month, utilities.datetime.Month]):
|
|
359
|
-
"""A frozenset-of-months-valued parameter."""
|
|
360
|
-
|
|
361
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
362
|
-
super().__init__(Month(), separator=separator)
|
|
363
|
-
|
|
364
|
-
|
|
365
556
|
class FrozenSetStrs(FrozenSetParameter[StringParamType, str]):
|
|
366
557
|
"""A frozenset-of-strs-valued parameter."""
|
|
367
558
|
|
|
559
|
+
@override
|
|
368
560
|
def __init__(self, *, separator: str = ",") -> None:
|
|
369
561
|
super().__init__(StringParamType(), separator=separator)
|
|
370
562
|
|
|
371
563
|
|
|
372
|
-
class FrozenSetUUIDs(FrozenSetParameter[UUIDParameterType, UUID]):
|
|
373
|
-
"""A frozenset-of-UUIDs-valued parameter."""
|
|
374
|
-
|
|
375
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
376
|
-
super().__init__(UUIDParameterType(), separator=separator)
|
|
377
|
-
|
|
378
|
-
|
|
379
564
|
# parameters - list
|
|
380
565
|
|
|
381
566
|
|
|
382
|
-
class ListParameter
|
|
567
|
+
class ListParameter[P: ParamType, T](ParamType):
|
|
383
568
|
"""A list-valued parameter."""
|
|
384
569
|
|
|
385
|
-
|
|
386
|
-
|
|
570
|
+
@override
|
|
571
|
+
def __init__(self, param: P, /, *, separator: str = ",") -> None:
|
|
572
|
+
self.name = f"list[{param.name}]"
|
|
387
573
|
self._param = param
|
|
388
574
|
self._separator = separator
|
|
389
575
|
super().__init__()
|
|
390
576
|
|
|
391
577
|
@override
|
|
392
578
|
def __repr__(self) -> str:
|
|
393
|
-
|
|
394
|
-
return f"LIST[{desc}]"
|
|
579
|
+
return f"LIST[{self._param!r}]"
|
|
395
580
|
|
|
396
581
|
@override
|
|
397
582
|
def convert(
|
|
398
|
-
self,
|
|
399
|
-
|
|
400
|
-
param: Parameter | None,
|
|
401
|
-
ctx: Context | None,
|
|
402
|
-
) -> list[_T]:
|
|
583
|
+
self, value: MaybeStr[Iterable[T]], param: Parameter | None, ctx: Context | None
|
|
584
|
+
) -> list[T]:
|
|
403
585
|
"""Convert a value into the `List` type."""
|
|
404
586
|
if is_iterable_not_str(value):
|
|
405
587
|
return list(value)
|
|
@@ -421,69 +603,49 @@ class ListParameter(ParamType, Generic[_TParam, _T]):
|
|
|
421
603
|
return _make_metavar(param, desc)
|
|
422
604
|
|
|
423
605
|
|
|
424
|
-
class
|
|
425
|
-
"""A
|
|
426
|
-
|
|
427
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
428
|
-
super().__init__(BoolParamType(), separator=separator)
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
class ListDates(ListParameter[Date, dt.date]):
|
|
432
|
-
"""A list-of-dates-valued parameter."""
|
|
433
|
-
|
|
434
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
435
|
-
super().__init__(Date(), separator=separator)
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
class ListEnums(ListParameter[Enum[TEnum], TEnum]):
|
|
439
|
-
"""A list-of-enums-valued parameter."""
|
|
606
|
+
class ListChoices(ListParameter[Choice, str]):
|
|
607
|
+
"""A frozenset-of-choices-valued parameter."""
|
|
440
608
|
|
|
609
|
+
@override
|
|
441
610
|
def __init__(
|
|
442
611
|
self,
|
|
443
|
-
|
|
612
|
+
choices: list[str],
|
|
444
613
|
/,
|
|
445
614
|
*,
|
|
446
615
|
case_sensitive: bool = False,
|
|
447
616
|
separator: str = ",",
|
|
448
617
|
) -> None:
|
|
449
|
-
super().__init__(
|
|
618
|
+
super().__init__(
|
|
619
|
+
Choice(choices, case_sensitive=case_sensitive), separator=separator
|
|
620
|
+
)
|
|
450
621
|
|
|
451
622
|
|
|
452
|
-
class
|
|
453
|
-
"""A list-of-
|
|
623
|
+
class ListEnums[E: enum.Enum](ListParameter[Enum[E], E]):
|
|
624
|
+
"""A list-of-enums-valued parameter."""
|
|
454
625
|
|
|
455
|
-
|
|
456
|
-
|
|
626
|
+
@override
|
|
627
|
+
def __init__(
|
|
628
|
+
self, enum: type[E], /, *, case_sensitive: bool = False, separator: str = ","
|
|
629
|
+
) -> None:
|
|
630
|
+
super().__init__(Enum(enum, case_sensitive=case_sensitive), separator=separator)
|
|
457
631
|
|
|
458
632
|
|
|
459
633
|
class ListInts(ListParameter[IntParamType, int]):
|
|
460
634
|
"""A list-of-ints-valued parameter."""
|
|
461
635
|
|
|
636
|
+
@override
|
|
462
637
|
def __init__(self, *, separator: str = ",") -> None:
|
|
463
638
|
super().__init__(IntParamType(), separator=separator)
|
|
464
639
|
|
|
465
640
|
|
|
466
|
-
class ListMonths(ListParameter[Month, utilities.datetime.Month]):
|
|
467
|
-
"""A list-of-months-valued parameter."""
|
|
468
|
-
|
|
469
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
470
|
-
super().__init__(Month(), separator=separator)
|
|
471
|
-
|
|
472
|
-
|
|
473
641
|
class ListStrs(ListParameter[StringParamType, str]):
|
|
474
642
|
"""A list-of-strs-valued parameter."""
|
|
475
643
|
|
|
644
|
+
@override
|
|
476
645
|
def __init__(self, *, separator: str = ",") -> None:
|
|
477
646
|
super().__init__(StringParamType(), separator=separator)
|
|
478
647
|
|
|
479
648
|
|
|
480
|
-
class ListUUIDs(ListParameter[UUIDParameterType, UUID]):
|
|
481
|
-
"""A list-of-UUIDs-valued parameter."""
|
|
482
|
-
|
|
483
|
-
def __init__(self, *, separator: str = ",") -> None:
|
|
484
|
-
super().__init__(UUIDParameterType(), separator=separator)
|
|
485
|
-
|
|
486
|
-
|
|
487
649
|
# private
|
|
488
650
|
|
|
489
651
|
|
|
@@ -493,36 +655,30 @@ def _make_metavar(param: Parameter, desc: str, /) -> str:
|
|
|
493
655
|
|
|
494
656
|
|
|
495
657
|
__all__ = [
|
|
496
|
-
"
|
|
658
|
+
"CONTEXT_SETTINGS",
|
|
659
|
+
"UUID",
|
|
497
660
|
"Date",
|
|
498
|
-
"
|
|
499
|
-
"
|
|
661
|
+
"DateDelta",
|
|
662
|
+
"DateTimeDelta",
|
|
500
663
|
"Enum",
|
|
501
|
-
"
|
|
502
|
-
"ExistingFilePath",
|
|
503
|
-
"FilePath",
|
|
504
|
-
"FrozenSetBools",
|
|
664
|
+
"EnumPartial",
|
|
505
665
|
"FrozenSetChoices",
|
|
506
|
-
"FrozenSetDates",
|
|
507
666
|
"FrozenSetEnums",
|
|
508
|
-
"FrozenSetFloats",
|
|
509
|
-
"FrozenSetInts",
|
|
510
|
-
"FrozenSetMonths",
|
|
511
667
|
"FrozenSetParameter",
|
|
512
668
|
"FrozenSetStrs",
|
|
513
|
-
"
|
|
514
|
-
"
|
|
515
|
-
"
|
|
669
|
+
"IPv4Address",
|
|
670
|
+
"IPv6Address",
|
|
671
|
+
"ListChoices",
|
|
516
672
|
"ListEnums",
|
|
517
|
-
"ListFloats",
|
|
518
673
|
"ListInts",
|
|
519
|
-
"ListMonths",
|
|
520
674
|
"ListParameter",
|
|
521
675
|
"ListStrs",
|
|
522
|
-
"
|
|
523
|
-
"
|
|
676
|
+
"MonthDay",
|
|
677
|
+
"Path",
|
|
678
|
+
"Path",
|
|
524
679
|
"PlainDateTime",
|
|
525
680
|
"Time",
|
|
526
|
-
"
|
|
681
|
+
"TimeDelta",
|
|
682
|
+
"YearMonth",
|
|
527
683
|
"ZonedDateTime",
|
|
528
684
|
]
|