dycw-utilities 0.113.0__py3-none-any.whl → 0.113.2__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.0.dist-info → dycw_utilities-0.113.2.dist-info}/METADATA +4 -4
- {dycw_utilities-0.113.0.dist-info → dycw_utilities-0.113.2.dist-info}/RECORD +10 -10
- utilities/__init__.py +1 -1
- utilities/asyncio.py +42 -2
- utilities/dataclasses.py +24 -1
- utilities/iterables.py +30 -14
- utilities/math.py +2 -2
- utilities/types.py +5 -0
- {dycw_utilities-0.113.0.dist-info → dycw_utilities-0.113.2.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.113.0.dist-info → dycw_utilities-0.113.2.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.2
|
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.10; 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'
|
@@ -16,7 +16,7 @@ Requires-Dist: pytest-randomly<3.17,>=3.16.0; extra == 'test'
|
|
16
16
|
Requires-Dist: pytest-regressions<2.8,>=2.7.0; extra == 'test'
|
17
17
|
Requires-Dist: pytest-rerunfailures<16,>=15.0; extra == 'test'
|
18
18
|
Requires-Dist: pytest-rng<1.1,>=1.0.0; extra == 'test'
|
19
|
-
Requires-Dist: pytest-timeout<2.
|
19
|
+
Requires-Dist: pytest-timeout<2.5,>=2.4.0; extra == 'test'
|
20
20
|
Requires-Dist: pytest-xdist<3.7,>=3.6.1; extra == 'test'
|
21
21
|
Requires-Dist: pytest<8.4,>=8.3.5; extra == 'test'
|
22
22
|
Requires-Dist: setuptools>=78.0.2; 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.10; 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,7 +1,7 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=gPP9gUduOhrk3TNScyIM28aOLTbYa1tnDF9Vu80gxZU,60
|
2
2
|
utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
|
3
3
|
utilities/astor.py,sha256=xuDUkjq0-b6fhtwjhbnebzbqQZAjMSHR1IIS5uOodVg,777
|
4
|
-
utilities/asyncio.py,sha256=
|
4
|
+
utilities/asyncio.py,sha256=6Pv0xK2jP55iF6EYjY1g6_rFGOeJyihxRNxXnOsWv14,15691
|
5
5
|
utilities/atomicwrites.py,sha256=geFjn9Pwn-tTrtoGjDDxWli9NqbYfy3gGL6ZBctiqSo,5393
|
6
6
|
utilities/atools.py,sha256=IYMuFSFGSKyuQmqD6v5IUtDlz8PPw0Sr87Cub_gRU3M,1168
|
7
7
|
utilities/cachetools.py,sha256=C1zqOg7BYz0IfQFK8e3qaDDgEZxDpo47F15RTfJM37Q,2910
|
@@ -11,7 +11,7 @@ utilities/contextlib.py,sha256=OOIIEa5lXKGzFAnauaul40nlQnQko6Na4ryiMJcHkIg,478
|
|
11
11
|
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
|
-
utilities/dataclasses.py,sha256=
|
14
|
+
utilities/dataclasses.py,sha256=iiC1wpGXWhaocIikzwBt8bbLWyImoUlOlcDZJGejaIg,33011
|
15
15
|
utilities/datetime.py,sha256=OF7jZE702UecnwAbq9D3N-GINpp9gSGoidki1RhimCE,35752
|
16
16
|
utilities/enum.py,sha256=HoRwVCWzsnH0vpO9ZEcAAIZLMv0Sn2vJxxA4sYMQgDs,5793
|
17
17
|
utilities/errors.py,sha256=BtSNP0JC3ik536ddPyTerLomCRJV9f6kdMe6POz0QHM,361
|
@@ -26,13 +26,13 @@ utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
|
|
26
26
|
utilities/http.py,sha256=WcahTcKYRtZ04WXQoWt5EGCgFPcyHD3EJdlMfxvDt-0,946
|
27
27
|
utilities/hypothesis.py,sha256=OpZhPdPmsYWvqMytFDc-G196eODosUzxQSuo-LfMYmM,46262
|
28
28
|
utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
|
29
|
-
utilities/iterables.py,sha256=
|
29
|
+
utilities/iterables.py,sha256=prKXBdF5QfLTGC-q4567DwO8xzUng_Z-2a4wBkMqyDo,45360
|
30
30
|
utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
|
31
31
|
utilities/lightweight_charts.py,sha256=vyVOzarYhBIOZj2xDhqdbP85qbSKUjdc6Au91rc1W4M,2814
|
32
32
|
utilities/logging.py,sha256=55LVJYd2BKzeTTQr4tG7uSNMDVEgUO56wK4s-rldjrM,25326
|
33
33
|
utilities/loguru.py,sha256=MEMQVWrdECxk1e3FxGzmOf21vWT9j8CAir98SEXFKPA,3809
|
34
34
|
utilities/luigi.py,sha256=fpH9MbxJDuo6-k9iCXRayFRtiVbUtibCJKugf7ygpv0,5988
|
35
|
-
utilities/math.py,sha256
|
35
|
+
utilities/math.py,sha256=-mQgbah-dPJwOEWf3SonrFoVZ2AVxMgpeQ3dfVa-oJA,26764
|
36
36
|
utilities/memory_profiler.py,sha256=tf2C51P2lCujPGvRt2Rfc7VEw5LDXmVPCG3z_AvBmbU,962
|
37
37
|
utilities/modules.py,sha256=iuvLluJya-hvl1Q25-Jk3dLgx2Es3ck4SjJiEkAlVTs,3195
|
38
38
|
utilities/more_itertools.py,sha256=6T0225gBFZtv47-B0JRFOKMz836Wg3Hct79ePPLGpuo,5827
|
@@ -77,7 +77,7 @@ utilities/text.py,sha256=Fo12N4aA7k2rnb4W4vH9iiDh88Q5_nvRssTkfNsvVM8,10965
|
|
77
77
|
utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
|
78
78
|
utilities/timer.py,sha256=Rkc49KSpHuC8s7vUxGO9DU55U9I6yDKnchsQqrUCVBs,4075
|
79
79
|
utilities/traceback.py,sha256=secexUnBsecfWV4ZuqP1W4pGF3prOeO1CRyJK-8zQDU,27402
|
80
|
-
utilities/types.py,sha256=
|
80
|
+
utilities/types.py,sha256=FhE1b8v_s_IlmXucwY7jAMWAq9cfpzyKssQwgwb3jnM,18267
|
81
81
|
utilities/typing.py,sha256=H6ysJkI830aRwLsMKz0SZIw4cpcsm7d6KhQOwr-SDh0,13817
|
82
82
|
utilities/tzdata.py,sha256=yCf70NICwAeazN3_JcXhWvRqCy06XJNQ42j7r6gw3HY,1217
|
83
83
|
utilities/tzlocal.py,sha256=3upDNFBvGh1l9njmLR2z2S6K6VxQSb7QizYGUbAH3JU,960
|
@@ -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.2.dist-info/METADATA,sha256=QgO7W2WhDgyW3k4-rB8FUJXk-vqpi7MfZfthSYdAD2o,12943
|
91
|
+
dycw_utilities-0.113.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
92
|
+
dycw_utilities-0.113.2.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
93
|
+
dycw_utilities-0.113.2.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/asyncio.py
CHANGED
@@ -17,6 +17,7 @@ from asyncio import (
|
|
17
17
|
sleep,
|
18
18
|
timeout,
|
19
19
|
)
|
20
|
+
from collections.abc import Callable
|
20
21
|
from contextlib import (
|
21
22
|
AsyncExitStack,
|
22
23
|
_AsyncGeneratorContextManager,
|
@@ -27,12 +28,22 @@ from dataclasses import dataclass, field
|
|
27
28
|
from io import StringIO
|
28
29
|
from subprocess import PIPE
|
29
30
|
from sys import stderr, stdout
|
30
|
-
from typing import
|
31
|
+
from typing import (
|
32
|
+
TYPE_CHECKING,
|
33
|
+
Generic,
|
34
|
+
Self,
|
35
|
+
TextIO,
|
36
|
+
TypeVar,
|
37
|
+
assert_never,
|
38
|
+
overload,
|
39
|
+
override,
|
40
|
+
)
|
31
41
|
|
32
42
|
from utilities.datetime import MILLISECOND, datetime_duration_to_float
|
33
43
|
from utilities.errors import ImpossibleCaseError
|
34
44
|
from utilities.functions import ensure_int, ensure_not_none
|
35
|
-
from utilities.
|
45
|
+
from utilities.sentinel import Sentinel, sentinel
|
46
|
+
from utilities.types import MaybeCallableEvent, THashable, TSupportsRichComparison
|
36
47
|
|
37
48
|
if TYPE_CHECKING:
|
38
49
|
from asyncio import _CoroutineLike
|
@@ -356,6 +367,34 @@ class UniqueQueue(Queue[THashable]):
|
|
356
367
|
##
|
357
368
|
|
358
369
|
|
370
|
+
@overload
|
371
|
+
def get_event(*, event: MaybeCallableEvent) -> Event: ...
|
372
|
+
@overload
|
373
|
+
def get_event(*, event: None) -> None: ...
|
374
|
+
@overload
|
375
|
+
def get_event(*, event: Sentinel) -> Sentinel: ...
|
376
|
+
@overload
|
377
|
+
def get_event(*, event: MaybeCallableEvent | Sentinel) -> Event | Sentinel: ...
|
378
|
+
@overload
|
379
|
+
def get_event(
|
380
|
+
*, event: MaybeCallableEvent | None | Sentinel = sentinel
|
381
|
+
) -> Event | None | Sentinel: ...
|
382
|
+
def get_event(
|
383
|
+
*, event: MaybeCallableEvent | None | Sentinel = sentinel
|
384
|
+
) -> Event | None | Sentinel:
|
385
|
+
"""Get the event."""
|
386
|
+
match event:
|
387
|
+
case Event() | None | Sentinel():
|
388
|
+
return event
|
389
|
+
case Callable() as func:
|
390
|
+
return get_event(event=func())
|
391
|
+
case _ as never:
|
392
|
+
assert_never(never)
|
393
|
+
|
394
|
+
|
395
|
+
##
|
396
|
+
|
397
|
+
|
359
398
|
async def get_items(
|
360
399
|
queue: Queue[_T], /, *, max_size: int | None = None, lock: Lock | None = None
|
361
400
|
) -> list[_T]:
|
@@ -490,6 +529,7 @@ __all__ = [
|
|
490
529
|
"StreamCommandOutput",
|
491
530
|
"UniquePriorityQueue",
|
492
531
|
"UniqueQueue",
|
532
|
+
"get_event",
|
493
533
|
"get_items",
|
494
534
|
"get_items_nowait",
|
495
535
|
"sleep_dur",
|
utilities/dataclasses.py
CHANGED
@@ -20,7 +20,12 @@ from utilities.functions import (
|
|
20
20
|
is_dataclass_class,
|
21
21
|
is_dataclass_instance,
|
22
22
|
)
|
23
|
-
from utilities.iterables import
|
23
|
+
from utilities.iterables import (
|
24
|
+
OneStrEmptyError,
|
25
|
+
OneStrNonUniqueError,
|
26
|
+
cmp_nullable,
|
27
|
+
one_str,
|
28
|
+
)
|
24
29
|
from utilities.operator import is_equal
|
25
30
|
from utilities.parse import (
|
26
31
|
_ParseObjectExtraNonUniqueError,
|
@@ -43,6 +48,7 @@ from utilities.types import (
|
|
43
48
|
SerializeObjectExtra,
|
44
49
|
StrStrMapping,
|
45
50
|
TDataclass,
|
51
|
+
TSupportsLT,
|
46
52
|
)
|
47
53
|
from utilities.typing import get_type_hints
|
48
54
|
|
@@ -215,6 +221,22 @@ def dataclass_to_dict(
|
|
215
221
|
##
|
216
222
|
|
217
223
|
|
224
|
+
def is_nullable_lt(x: TSupportsLT | None, y: TSupportsLT | None, /) -> bool | None:
|
225
|
+
"""Compare two nullable fields."""
|
226
|
+
match cmp_nullable(x, y):
|
227
|
+
case 1:
|
228
|
+
return False
|
229
|
+
case -1:
|
230
|
+
return True
|
231
|
+
case 0:
|
232
|
+
return None
|
233
|
+
case _ as never:
|
234
|
+
assert_never(never)
|
235
|
+
|
236
|
+
|
237
|
+
##
|
238
|
+
|
239
|
+
|
218
240
|
def mapping_to_dataclass(
|
219
241
|
cls: type[TDataclass],
|
220
242
|
mapping: StrMapping,
|
@@ -1056,6 +1078,7 @@ __all__ = [
|
|
1056
1078
|
"YieldFieldsError",
|
1057
1079
|
"dataclass_repr",
|
1058
1080
|
"dataclass_to_dict",
|
1081
|
+
"is_nullable_lt",
|
1059
1082
|
"mapping_to_dataclass",
|
1060
1083
|
"one_field",
|
1061
1084
|
"parse_dataclass",
|
utilities/iterables.py
CHANGED
@@ -45,7 +45,7 @@ from utilities.math import (
|
|
45
45
|
)
|
46
46
|
from utilities.reprlib import get_repr
|
47
47
|
from utilities.sentinel import Sentinel, sentinel
|
48
|
-
from utilities.types import THashable, THashable2, TSupportsAdd
|
48
|
+
from utilities.types import Sign, THashable, THashable2, TSupportsAdd, TSupportsLT
|
49
49
|
from utilities.zoneinfo import UTC
|
50
50
|
|
51
51
|
if TYPE_CHECKING:
|
@@ -696,6 +696,24 @@ class _CheckUniqueModuloCaseDuplicateLowerCaseStringsError(CheckUniqueModuloCase
|
|
696
696
|
##
|
697
697
|
|
698
698
|
|
699
|
+
def cmp_nullable(x: TSupportsLT | None, y: TSupportsLT | None, /) -> Sign:
|
700
|
+
"""Compare two nullable objects."""
|
701
|
+
match x, y:
|
702
|
+
case None, None:
|
703
|
+
return 0
|
704
|
+
case None, _:
|
705
|
+
return -1
|
706
|
+
case _, None:
|
707
|
+
return 1
|
708
|
+
case _, _:
|
709
|
+
return cast("Sign", (x > y) - (x < y))
|
710
|
+
case _ as never:
|
711
|
+
assert_never(never)
|
712
|
+
|
713
|
+
|
714
|
+
##
|
715
|
+
|
716
|
+
|
699
717
|
def chunked(iterable: Iterable[_T], n: int, /) -> Iterator[Sequence[_T]]:
|
700
718
|
"""Break an iterable into lists of length n."""
|
701
719
|
return iter(partial(take, n, iter(iterable)), [])
|
@@ -1293,7 +1311,7 @@ def sort_iterable(iterable: Iterable[_T], /) -> list[_T]:
|
|
1293
1311
|
return sorted(iterable, key=cmp_to_key(_sort_iterable_cmp))
|
1294
1312
|
|
1295
1313
|
|
1296
|
-
def _sort_iterable_cmp(x: Any, y: Any, /) ->
|
1314
|
+
def _sort_iterable_cmp(x: Any, y: Any, /) -> Sign:
|
1297
1315
|
"""Compare two quantities."""
|
1298
1316
|
if type(x) is not type(y):
|
1299
1317
|
x_qualname = type(x).__qualname__
|
@@ -1318,7 +1336,7 @@ def _sort_iterable_cmp(x: Any, y: Any, /) -> Literal[-1, 0, 1]:
|
|
1318
1336
|
return _sort_iterable_cmp_floats(x, y)
|
1319
1337
|
if isinstance(x, str): # else Sequence
|
1320
1338
|
y = cast("str", y)
|
1321
|
-
return cast("
|
1339
|
+
return cast("Sign", (x > y) - (x < y))
|
1322
1340
|
|
1323
1341
|
# collections
|
1324
1342
|
if isinstance(x, Sized):
|
@@ -1333,14 +1351,14 @@ def _sort_iterable_cmp(x: Any, y: Any, /) -> Literal[-1, 0, 1]:
|
|
1333
1351
|
return _sort_iterable_cmp(sort_iterable(x), sort_iterable(y))
|
1334
1352
|
if isinstance(x, Sequence):
|
1335
1353
|
y = cast("Sequence[Any]", y)
|
1336
|
-
it: Iterable[
|
1354
|
+
it: Iterable[Sign] = (
|
1337
1355
|
_sort_iterable_cmp(x_i, y_i) for x_i, y_i in zip(x, y, strict=True)
|
1338
1356
|
)
|
1339
1357
|
with suppress(StopIteration):
|
1340
1358
|
return next(r for r in it if r != 0)
|
1341
1359
|
|
1342
1360
|
try:
|
1343
|
-
return cast("
|
1361
|
+
return cast("Sign", (x > y) - (x < y))
|
1344
1362
|
except TypeError:
|
1345
1363
|
raise SortIterableError(x=x, y=y) from None
|
1346
1364
|
|
@@ -1355,13 +1373,11 @@ class SortIterableError(Exception):
|
|
1355
1373
|
return f"Unable to sort {get_repr(self.x)} and {get_repr(self.y)}"
|
1356
1374
|
|
1357
1375
|
|
1358
|
-
def _sort_iterable_cmp_datetimes(
|
1359
|
-
x: dt.datetime, y: dt.datetime, /
|
1360
|
-
) -> Literal[-1, 0, 1]:
|
1376
|
+
def _sort_iterable_cmp_datetimes(x: dt.datetime, y: dt.datetime, /) -> Sign:
|
1361
1377
|
"""Compare two datetimes."""
|
1362
1378
|
match x.tzinfo, y.tzinfo:
|
1363
1379
|
case None, None:
|
1364
|
-
return cast("
|
1380
|
+
return cast("Sign", (x > y) - (x < y))
|
1365
1381
|
case dt.tzinfo(), None:
|
1366
1382
|
return 1
|
1367
1383
|
case None, dt.tzinfo():
|
@@ -1369,20 +1385,19 @@ def _sort_iterable_cmp_datetimes(
|
|
1369
1385
|
case dt.tzinfo(), dt.tzinfo():
|
1370
1386
|
x_utc = x.astimezone(tz=UTC)
|
1371
1387
|
y_utc = y.astimezone(tz=UTC)
|
1372
|
-
result = cast("
|
1388
|
+
result = cast("Sign", (x_utc > y_utc) - (x_utc < y_utc))
|
1373
1389
|
if result != 0:
|
1374
1390
|
return result
|
1375
1391
|
x_time_zone = ensure_not_none(ensure_not_none(x.tzinfo).tzname(x))
|
1376
1392
|
y_time_zone = ensure_not_none(ensure_not_none(y.tzinfo).tzname(y))
|
1377
1393
|
return cast(
|
1378
|
-
"
|
1379
|
-
(x_time_zone > y_time_zone) - (x_time_zone < y_time_zone),
|
1394
|
+
"Sign", (x_time_zone > y_time_zone) - (x_time_zone < y_time_zone)
|
1380
1395
|
)
|
1381
1396
|
case _ as never:
|
1382
1397
|
assert_never(never)
|
1383
1398
|
|
1384
1399
|
|
1385
|
-
def _sort_iterable_cmp_floats(x: float, y: float, /) ->
|
1400
|
+
def _sort_iterable_cmp_floats(x: float, y: float, /) -> Sign:
|
1386
1401
|
"""Compare two floats."""
|
1387
1402
|
x_nan, y_nan = map(isnan, [x, y])
|
1388
1403
|
match x_nan, y_nan:
|
@@ -1393,7 +1408,7 @@ def _sort_iterable_cmp_floats(x: float, y: float, /) -> Literal[-1, 0, 1]:
|
|
1393
1408
|
case False, True:
|
1394
1409
|
return -1
|
1395
1410
|
case False, False:
|
1396
|
-
return cast("
|
1411
|
+
return cast("Sign", (x > y) - (x < y))
|
1397
1412
|
case _ as never:
|
1398
1413
|
assert_never(never)
|
1399
1414
|
|
@@ -1517,6 +1532,7 @@ __all__ = [
|
|
1517
1532
|
"check_superset",
|
1518
1533
|
"check_unique_modulo_case",
|
1519
1534
|
"chunked",
|
1535
|
+
"cmp_nullable",
|
1520
1536
|
"ensure_hashables",
|
1521
1537
|
"ensure_iterable",
|
1522
1538
|
"ensure_iterable_not_str",
|
utilities/math.py
CHANGED
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, Literal, assert_never, overload, override
|
|
10
10
|
from utilities.errors import ImpossibleCaseError
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
13
|
-
from utilities.types import Number, RoundMode
|
13
|
+
from utilities.types import Number, RoundMode, Sign
|
14
14
|
|
15
15
|
|
16
16
|
MIN_FLOAT32, MAX_FLOAT32 = -3.4028234663852886e38, 3.4028234663852886e38
|
@@ -860,7 +860,7 @@ class SafeRoundError(Exception):
|
|
860
860
|
|
861
861
|
def sign(
|
862
862
|
x: float, /, *, rel_tol: float | None = None, abs_tol: float | None = None
|
863
|
-
) ->
|
863
|
+
) -> Sign:
|
864
864
|
"""Get the sign of an integer/float."""
|
865
865
|
match x:
|
866
866
|
case int():
|
utilities/types.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime as dt
|
4
|
+
from asyncio import Event
|
4
5
|
from collections.abc import Awaitable, Callable, Coroutine, Hashable, Iterable, Mapping
|
5
6
|
from enum import Enum
|
6
7
|
from logging import Logger
|
@@ -57,6 +58,7 @@ type TupleOrStrMapping = tuple[Any, ...] | StrMapping
|
|
57
58
|
# asyncio
|
58
59
|
type Coroutine1[_T] = Coroutine[Any, Any, _T]
|
59
60
|
type MaybeAwaitable[_T] = _T | Awaitable[_T]
|
61
|
+
type MaybeCallableEvent = MaybeCallable[Event]
|
60
62
|
type MaybeCoroutine1[_T] = _T | Coroutine1[_T]
|
61
63
|
|
62
64
|
|
@@ -140,6 +142,7 @@ type RoundMode = Literal[
|
|
140
142
|
"standard-tie-toward-zero",
|
141
143
|
"standard-tie-away-zero",
|
142
144
|
]
|
145
|
+
type Sign = Literal[-1, 0, 1]
|
143
146
|
|
144
147
|
|
145
148
|
# operator
|
@@ -276,6 +279,7 @@ __all__ = [
|
|
276
279
|
"MaybeCallable",
|
277
280
|
"MaybeCallableDate",
|
278
281
|
"MaybeCallableDateTime",
|
282
|
+
"MaybeCallableEvent",
|
279
283
|
"MaybeCoroutine1",
|
280
284
|
"MaybeIterable",
|
281
285
|
"MaybeIterableHashable",
|
@@ -291,6 +295,7 @@ __all__ = [
|
|
291
295
|
"RoundMode",
|
292
296
|
"Seed",
|
293
297
|
"SerializeObjectExtra",
|
298
|
+
"Sign",
|
294
299
|
"StrMapping",
|
295
300
|
"StrStrMapping",
|
296
301
|
"SupportsAbs",
|
File without changes
|
File without changes
|