dycw-utilities 0.163.1__py3-none-any.whl → 0.164.0__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.163.1.dist-info → dycw_utilities-0.164.0.dist-info}/METADATA +1 -1
- {dycw_utilities-0.163.1.dist-info → dycw_utilities-0.164.0.dist-info}/RECORD +16 -16
- utilities/__init__.py +1 -1
- utilities/dataclasses.py +2 -6
- utilities/functions.py +5 -266
- utilities/iterables.py +1 -16
- utilities/operator.py +1 -1
- utilities/orjson.py +2 -1
- utilities/polars.py +4 -6
- utilities/polars_ols.py +1 -1
- utilities/redis.py +2 -11
- utilities/sqlalchemy.py +7 -9
- utilities/typing.py +418 -14
- {dycw_utilities-0.163.1.dist-info → dycw_utilities-0.164.0.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.163.1.dist-info → dycw_utilities-0.164.0.dist-info}/entry_points.txt +0 -0
- {dycw_utilities-0.163.1.dist-info → dycw_utilities-0.164.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=cT3KdUJySCCzC99QlfI301hzQa3WEiHGbk_vNupSr98,60
|
2
2
|
utilities/aeventkit.py,sha256=ddoleSwW9zdc2tjX5Ge0pMKtYwV_JMxhHYOxnWX2AGM,12609
|
3
3
|
utilities/altair.py,sha256=92E2lCdyHY4Zb-vCw6rEJIsWdKipuu-Tu2ab1ufUfAk,9079
|
4
4
|
utilities/asyncio.py,sha256=PUedzQ5deqlSECQ33sam9cRzI9TnygHz3FdOqWJWPTM,15288
|
@@ -11,12 +11,12 @@ utilities/contextlib.py,sha256=m2D5bwvtCZLJcJ3IwVqyErYODuwJ1gLrT2UfATAQl-w,7435
|
|
11
11
|
utilities/contextvars.py,sha256=J8OhC7jqozAGYOCe2KUWysbPXNGe5JYz3HfaY_mIs08,883
|
12
12
|
utilities/cryptography.py,sha256=5PFrzsNUGHay91dFgYnDKwYprXxahrBqztmUqViRzBk,956
|
13
13
|
utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
|
14
|
-
utilities/dataclasses.py,sha256=
|
14
|
+
utilities/dataclasses.py,sha256=xbU3QN1GFy7RC6hIJRZIeUZm7YRlodrgEWmahWG6k2g,32465
|
15
15
|
utilities/enum.py,sha256=5l6pwZD1cjSlVW4ss-zBPspWvrbrYrdtJWcg6f5_J5w,5781
|
16
16
|
utilities/errors.py,sha256=mFlDGSM0LI1jZ1pbqwLAH3ttLZ2JVIxyZLojw8tGVZU,1479
|
17
17
|
utilities/fastapi.py,sha256=TqyKvBjiMS594sXPjrz-KRTLMb3l3D3rZ1zAYV7GfOk,1454
|
18
18
|
utilities/fpdf2.py,sha256=dSiYz0FJTD2sQuxpxqFWwwIe2-p6Y7oTB9Tv0Jajit0,1866
|
19
|
-
utilities/functions.py,sha256=
|
19
|
+
utilities/functions.py,sha256=82qCAaPIB0JmZ5wsQurA3MTYl7fh8LHcoBFkxPs7Zeg,21478
|
20
20
|
utilities/functools.py,sha256=I00ru2gQPakZw2SHVeKIKXfTv741655s6HI0lUoE0D4,1552
|
21
21
|
utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
|
22
22
|
utilities/gzip.py,sha256=fkGP3KdsBfXlstodT4wtlp-PwNyUsogpbDCVVVGdsm4,781
|
@@ -26,7 +26,7 @@ utilities/hypothesis.py,sha256=eoFAFnM2SdvzH6DWD5oCs8cH57LsEEXsRy8vMZDW6i8,44874
|
|
26
26
|
utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
|
27
27
|
utilities/inflect.py,sha256=v7YkOWSu8NAmVghPcf4F3YBZQoJCS47_DLf9jbfWIs0,581
|
28
28
|
utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
|
29
|
-
utilities/iterables.py,sha256=
|
29
|
+
utilities/iterables.py,sha256=8_dljtugLjxL8GCO_udMoH5uldvxdAmsN6aZ3EdnAiA,42564
|
30
30
|
utilities/json.py,sha256=-WcGtSsCr9Y42wHZzAMnfvU6ihAfVftylFfRUORaDFo,2102
|
31
31
|
utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
|
32
32
|
utilities/libcst.py,sha256=TKgKN4bNmtBNEE-TUfhTyd1BrTncfsl_7tTuhpesGYY,5585
|
@@ -37,16 +37,16 @@ utilities/memory_profiler.py,sha256=XzN56jDCa5aqXS_DxEjb_K4L6aIWh_5zyKi6OhcIxw0,
|
|
37
37
|
utilities/modules.py,sha256=iuvLluJya-hvl1Q25-Jk3dLgx2Es3ck4SjJiEkAlVTs,3195
|
38
38
|
utilities/more_itertools.py,sha256=syfIPhQF_WS-YiicdGe2h5F1G-Ld12Q2XsVduL2hA40,10908
|
39
39
|
utilities/numpy.py,sha256=Xn23sA2ZbVNqwUYEgNJD3XBYH6IbCri_WkHSNhg3NkY,26122
|
40
|
-
utilities/operator.py,sha256=
|
40
|
+
utilities/operator.py,sha256=C3NylZWGTVWRpwYHOPVhaLgRhw0DfpS4_XQ8KfPhBLQ,3613
|
41
41
|
utilities/optuna.py,sha256=C-fhWYiXHVPo1l8QctYkFJ4DyhbSrGorzP1dJb_qvd8,1933
|
42
|
-
utilities/orjson.py,sha256=
|
42
|
+
utilities/orjson.py,sha256=rII_rINPcH9X0CfL_WeFjwHgKNkKAF-TVS5rnpLHjzc,41998
|
43
43
|
utilities/os.py,sha256=8TjFLVWlGhhEpzZ0X_vNAyhYntjeVL5WTwaQcdTaNVw,3934
|
44
44
|
utilities/parse.py,sha256=JcJn5yXKhIWXBCwgBdPsyu7Hvcuw6kyEdqvaebCaI9k,17951
|
45
45
|
utilities/pathlib.py,sha256=qGuU8XPmdgGpy8tOMUgelfXx3kxI8h9IaV3TI_06QGE,8428
|
46
46
|
utilities/pickle.py,sha256=MBT2xZCsv0pH868IXLGKnlcqNx2IRVKYNpRcqiQQqxw,653
|
47
47
|
utilities/platform.py,sha256=pTn7gw6N4T6LdKrf0virwarof_mze9WtoQlrGMzhGVI,2798
|
48
|
-
utilities/polars.py,sha256=
|
49
|
-
utilities/polars_ols.py,sha256=
|
48
|
+
utilities/polars.py,sha256=oV63oc7qI100dHoZUu8rfnr5-bEd7iY0O79iEFtDmj4,79772
|
49
|
+
utilities/polars_ols.py,sha256=LNTFNLPuYW7fcAHymlbnams_DhitToblYvib3mhKbwI,5615
|
50
50
|
utilities/postgres.py,sha256=ynCTTaF-bVEOSW-KEAR-dlLh_hYjeVVjm__-4pEU8Zk,12269
|
51
51
|
utilities/pottery.py,sha256=ggMN72Y7wx7Js8VN6eyNyodpm8TIYqZHGghkDPXIVWk,3949
|
52
52
|
utilities/pqdm.py,sha256=idv2seRVP2f6NeSfpeEnT5A-tQezaHZKDyeu16g2-0E,3091
|
@@ -57,14 +57,14 @@ utilities/pytest.py,sha256=M-Om6b3hpF9W_bEB7UFY2IzBCubSxzVQleGrgRXHtxY,7741
|
|
57
57
|
utilities/pytest_regressions.py,sha256=ocjHTtfOeiGfQAKIei8pKNd61sxN9dawrJJ9gPt2wzA,4097
|
58
58
|
utilities/random.py,sha256=hZlH4gnAtoaofWswuJYjcygejrY8db4CzP-z_adO2Mo,4165
|
59
59
|
utilities/re.py,sha256=S4h-DLL6ScMPqjboZ_uQ1BVTJajrqV06r_81D--_HCE,4573
|
60
|
-
utilities/redis.py,sha256=
|
60
|
+
utilities/redis.py,sha256=f16zuOabP_rFDFtan7x1S-d8KOjBK93pS8OEyp7T9Is,30156
|
61
61
|
utilities/reprlib.py,sha256=ssYTcBW-TeRh3fhCJv57sopTZHF5FrPyyUg9yp5XBlo,3953
|
62
62
|
utilities/scipy.py,sha256=wZJM7fEgBAkLSYYvSmsg5ac-QuwAI0BGqHVetw1_Hb0,947
|
63
63
|
utilities/sentinel.py,sha256=A_p5jX2K0Yc5XBfoYHyBLqHsEWzE1ByOdDuzzA2pZnE,1434
|
64
64
|
utilities/shelve.py,sha256=4OzjQI6kGuUbJciqf535rwnao-_IBv66gsT6tRGiUt0,759
|
65
65
|
utilities/slack_sdk.py,sha256=76-DYtcGiUhEvl-voMamc5OjfF7Y7nCq54Bys1arqzw,2233
|
66
66
|
utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
|
67
|
-
utilities/sqlalchemy.py,sha256=
|
67
|
+
utilities/sqlalchemy.py,sha256=gCd7rBn7mDt1ZepxMtW4j0QSUo-zwCC3VvzH8P0LcZI,36411
|
68
68
|
utilities/sqlalchemy_polars.py,sha256=JCGhB37raSR7fqeWV5dTsciRTMVzIdVT9YSqKT0piT0,13370
|
69
69
|
utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
|
70
70
|
utilities/string.py,sha256=shmBK87zZwzGyixuNuXCiUbqzfeZ9xlrFwz6JTaRvDk,582
|
@@ -76,7 +76,7 @@ utilities/timer.py,sha256=oXfTii6ymu57niP0BDGZjFD55LEHi2a19kqZKiTgaFQ,2588
|
|
76
76
|
utilities/traceback.py,sha256=b1nSvlyrGmI1MyZLkkoLVET3DQBSGt9qqIlAAQbyjEw,9629
|
77
77
|
utilities/typed_settings.py,sha256=SFWqS3lAzV7IfNRwqFcTk0YynTcQ7BmrcW2mr_KUnos,4466
|
78
78
|
utilities/types.py,sha256=oeH-hEC3-67Eja4nLz-Nj9WvK6Z9-3T1zobO_XJpuVg,18735
|
79
|
-
utilities/typing.py,sha256=
|
79
|
+
utilities/typing.py,sha256=UXhQPJ25sUawgYFIzH28NyuTje9ybg6tWDuN6BiU55E,24214
|
80
80
|
utilities/tzdata.py,sha256=fgNVj66yUbCSI_-vrRVzSD3gtf-L_8IEJEPjP_Jel5Y,266
|
81
81
|
utilities/tzlocal.py,sha256=KyCXEgCTjqGFx-389JdTuhMRUaT06U1RCMdWoED-qro,728
|
82
82
|
utilities/uuid.py,sha256=nQZs6tFX4mqtc2Ku3KqjloYCqwpTKeTj8eKwQwh3FQI,1572
|
@@ -88,8 +88,8 @@ utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
|
|
88
88
|
utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
89
89
|
utilities/pytest_plugins/pytest_randomly.py,sha256=B1qYVlExGOxTywq2r1SMi5o7btHLk2PNdY_b1p98dkE,409
|
90
90
|
utilities/pytest_plugins/pytest_regressions.py,sha256=9v8kAXDM2ycIXJBimoiF4EgrwbUvxTycFWJiGR_GHhM,1466
|
91
|
-
dycw_utilities-0.
|
92
|
-
dycw_utilities-0.
|
93
|
-
dycw_utilities-0.
|
94
|
-
dycw_utilities-0.
|
95
|
-
dycw_utilities-0.
|
91
|
+
dycw_utilities-0.164.0.dist-info/METADATA,sha256=OTRhIzWSdVocu0RE1zn25hIns4nLsKu0TIBD8i2KdOs,1696
|
92
|
+
dycw_utilities-0.164.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
93
|
+
dycw_utilities-0.164.0.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
|
94
|
+
dycw_utilities-0.164.0.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
95
|
+
dycw_utilities-0.164.0.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/dataclasses.py
CHANGED
@@ -6,11 +6,7 @@ from dataclasses import MISSING, dataclass, field, fields, replace
|
|
6
6
|
from typing import TYPE_CHECKING, Any, Literal, assert_never, overload, override
|
7
7
|
|
8
8
|
from utilities.errors import ImpossibleCaseError
|
9
|
-
from utilities.functions import
|
10
|
-
get_class_name,
|
11
|
-
is_dataclass_class,
|
12
|
-
is_dataclass_instance,
|
13
|
-
)
|
9
|
+
from utilities.functions import get_class_name
|
14
10
|
from utilities.iterables import (
|
15
11
|
OneStrEmptyError,
|
16
12
|
OneStrNonUniqueError,
|
@@ -35,7 +31,7 @@ from utilities.text import (
|
|
35
31
|
split_key_value_pairs,
|
36
32
|
)
|
37
33
|
from utilities.types import MaybeType, SupportsLT
|
38
|
-
from utilities.typing import get_type_hints
|
34
|
+
from utilities.typing import get_type_hints, is_dataclass_class, is_dataclass_instance
|
39
35
|
|
40
36
|
if TYPE_CHECKING:
|
41
37
|
from collections.abc import Callable, Iterable, Iterator
|
utilities/functions.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from collections.abc import Callable, Iterable, Iterator
|
4
|
-
from dataclasses import asdict, dataclass
|
3
|
+
from collections.abc import Callable, Iterable, Iterator
|
4
|
+
from dataclasses import asdict, dataclass
|
5
5
|
from functools import _lru_cache_wrapper, cached_property, partial, reduce, wraps
|
6
6
|
from inspect import getattr_static
|
7
7
|
from pathlib import Path
|
@@ -20,17 +20,10 @@ from whenever import Date, PlainDateTime, Time, TimeDelta, ZonedDateTime
|
|
20
20
|
|
21
21
|
from utilities.reprlib import get_repr, get_repr_and_class
|
22
22
|
from utilities.sentinel import Sentinel, is_sentinel, sentinel
|
23
|
-
from utilities.types import
|
24
|
-
Dataclass,
|
25
|
-
Number,
|
26
|
-
StrMapping,
|
27
|
-
SupportsRichComparison,
|
28
|
-
TupleOrStrMapping,
|
29
|
-
TypeLike,
|
30
|
-
)
|
23
|
+
from utilities.types import Dataclass, Number, SupportsRichComparison, TypeLike
|
31
24
|
|
32
25
|
if TYPE_CHECKING:
|
33
|
-
from collections.abc import Container
|
26
|
+
from collections.abc import Container
|
34
27
|
|
35
28
|
|
36
29
|
def apply_decorators[F1: Callable, F2: Callable](
|
@@ -230,25 +223,6 @@ class EnsureFloatError(Exception):
|
|
230
223
|
##
|
231
224
|
|
232
225
|
|
233
|
-
def ensure_hashable(obj: Any, /) -> Hashable:
|
234
|
-
"""Ensure an object is hashable."""
|
235
|
-
if is_hashable(obj):
|
236
|
-
return obj
|
237
|
-
raise EnsureHashableError(obj=obj)
|
238
|
-
|
239
|
-
|
240
|
-
@dataclass(kw_only=True, slots=True)
|
241
|
-
class EnsureHashableError(Exception):
|
242
|
-
obj: Any
|
243
|
-
|
244
|
-
@override
|
245
|
-
def __str__(self) -> str:
|
246
|
-
return _make_error_msg(self.obj, "hashable")
|
247
|
-
|
248
|
-
|
249
|
-
##
|
250
|
-
|
251
|
-
|
252
226
|
@overload
|
253
227
|
def ensure_int(obj: Any, /, *, nullable: bool) -> int | None: ...
|
254
228
|
@overload
|
@@ -405,44 +379,6 @@ class EnsurePlainDateTimeError(Exception):
|
|
405
379
|
##
|
406
380
|
|
407
381
|
|
408
|
-
def ensure_sized(obj: Any, /) -> Sized:
|
409
|
-
"""Ensure an object is sized."""
|
410
|
-
if is_sized(obj):
|
411
|
-
return obj
|
412
|
-
raise EnsureSizedError(obj=obj)
|
413
|
-
|
414
|
-
|
415
|
-
@dataclass(kw_only=True, slots=True)
|
416
|
-
class EnsureSizedError(Exception):
|
417
|
-
obj: Any
|
418
|
-
|
419
|
-
@override
|
420
|
-
def __str__(self) -> str:
|
421
|
-
return _make_error_msg(self.obj, "sized")
|
422
|
-
|
423
|
-
|
424
|
-
##
|
425
|
-
|
426
|
-
|
427
|
-
def ensure_sized_not_str(obj: Any, /) -> Sized:
|
428
|
-
"""Ensure an object is sized, but not a string."""
|
429
|
-
if is_sized_not_str(obj):
|
430
|
-
return obj
|
431
|
-
raise EnsureSizedNotStrError(obj=obj)
|
432
|
-
|
433
|
-
|
434
|
-
@dataclass(kw_only=True, slots=True)
|
435
|
-
class EnsureSizedNotStrError(Exception):
|
436
|
-
obj: Any
|
437
|
-
|
438
|
-
@override
|
439
|
-
def __str__(self) -> str:
|
440
|
-
return _make_error_msg(self.obj, "sized and not a string")
|
441
|
-
|
442
|
-
|
443
|
-
##
|
444
|
-
|
445
|
-
|
446
382
|
@overload
|
447
383
|
def ensure_str(obj: Any, /, *, nullable: bool) -> str | None: ...
|
448
384
|
@overload
|
@@ -633,67 +569,7 @@ def identity[T](obj: T, /) -> T:
|
|
633
569
|
##
|
634
570
|
|
635
571
|
|
636
|
-
def
|
637
|
-
"""Check if an object is a dataclass."""
|
638
|
-
return isinstance(obj, type) and is_dataclass(obj)
|
639
|
-
|
640
|
-
|
641
|
-
##
|
642
|
-
|
643
|
-
|
644
|
-
def is_dataclass_instance(obj: Any, /) -> TypeGuard[Dataclass]:
|
645
|
-
"""Check if an object is an instance of a dataclass."""
|
646
|
-
return (not isinstance(obj, type)) and is_dataclass(obj)
|
647
|
-
|
648
|
-
|
649
|
-
##
|
650
|
-
|
651
|
-
|
652
|
-
def is_hashable(obj: Any, /) -> TypeGuard[Hashable]:
|
653
|
-
"""Check if an object is hashable."""
|
654
|
-
try:
|
655
|
-
_ = hash(obj)
|
656
|
-
except TypeError:
|
657
|
-
return False
|
658
|
-
return True
|
659
|
-
|
660
|
-
|
661
|
-
##
|
662
|
-
|
663
|
-
|
664
|
-
@overload
|
665
|
-
def is_iterable_of[T](obj: Any, cls: type[T], /) -> TypeGuard[Iterable[T]]: ...
|
666
|
-
@overload
|
667
|
-
def is_iterable_of[T1](
|
668
|
-
obj: Any, cls: tuple[type[T1]], /
|
669
|
-
) -> TypeGuard[Iterable[T1]]: ...
|
670
|
-
@overload
|
671
|
-
def is_iterable_of[T1, T2](
|
672
|
-
obj: Any, cls: tuple[type[T1], type[T2]], /
|
673
|
-
) -> TypeGuard[Iterable[T1 | T2]]: ...
|
674
|
-
@overload
|
675
|
-
def is_iterable_of[T1, T2, T3](
|
676
|
-
obj: Any, cls: tuple[type[T1], type[T2], type[T3]], /
|
677
|
-
) -> TypeGuard[Iterable[T1 | T2 | T3]]: ...
|
678
|
-
@overload
|
679
|
-
def is_iterable_of[T1, T2, T3, T4](
|
680
|
-
obj: Any, cls: tuple[type[T1], type[T2], type[T3], type[T4]], /
|
681
|
-
) -> TypeGuard[Iterable[T1 | T2 | T3 | T4]]: ...
|
682
|
-
@overload
|
683
|
-
def is_iterable_of[T1, T2, T3, T4, T5](
|
684
|
-
obj: Any, cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]], /
|
685
|
-
) -> TypeGuard[Iterable[T1 | T2 | T3 | T4 | T5]]: ...
|
686
|
-
@overload
|
687
|
-
def is_iterable_of[T](obj: Any, cls: TypeLike[T], /) -> TypeGuard[Iterable[T]]: ...
|
688
|
-
def is_iterable_of[T](obj: Any, cls: TypeLike[T], /) -> TypeGuard[Iterable[T]]:
|
689
|
-
"""Check if an object is a iterable of tuple or string mappings."""
|
690
|
-
return isinstance(obj, Iterable) and all(map(make_isinstance(cls), obj))
|
691
|
-
|
692
|
-
|
693
|
-
##
|
694
|
-
|
695
|
-
|
696
|
-
def is_none(obj: Any, /) -> bool:
|
572
|
+
def is_none(obj: Any, /) -> TypeGuard[None]:
|
697
573
|
"""Check if an object is `None`."""
|
698
574
|
return obj is None
|
699
575
|
|
@@ -709,126 +585,6 @@ def is_not_none(obj: Any, /) -> bool:
|
|
709
585
|
##
|
710
586
|
|
711
587
|
|
712
|
-
@overload
|
713
|
-
def is_sequence_of[T](obj: Any, cls: type[T], /) -> TypeGuard[Sequence[T]]: ...
|
714
|
-
@overload
|
715
|
-
def is_sequence_of[T1](
|
716
|
-
obj: Any, cls: tuple[type[T1]], /
|
717
|
-
) -> TypeGuard[Sequence[T1]]: ...
|
718
|
-
@overload
|
719
|
-
def is_sequence_of[T1, T2](
|
720
|
-
obj: Any, cls: tuple[type[T1], type[T2]], /
|
721
|
-
) -> TypeGuard[Sequence[T1 | T2]]: ...
|
722
|
-
@overload
|
723
|
-
def is_sequence_of[T1, T2, T3](
|
724
|
-
obj: Any, cls: tuple[type[T1], type[T2], type[T3]], /
|
725
|
-
) -> TypeGuard[Sequence[T1 | T2 | T3]]: ...
|
726
|
-
@overload
|
727
|
-
def is_sequence_of[T1, T2, T3, T4](
|
728
|
-
obj: Any, cls: tuple[type[T1], type[T2], type[T3], type[T4]], /
|
729
|
-
) -> TypeGuard[Sequence[T1 | T2 | T3 | T4]]: ...
|
730
|
-
@overload
|
731
|
-
def is_sequence_of[T1, T2, T3, T4, T5](
|
732
|
-
obj: Any, cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]], /
|
733
|
-
) -> TypeGuard[Sequence[T1 | T2 | T3 | T4 | T5]]: ...
|
734
|
-
@overload
|
735
|
-
def is_sequence_of[T](obj: Any, cls: TypeLike[T], /) -> TypeGuard[Sequence[T]]: ...
|
736
|
-
def is_sequence_of[T](obj: Any, cls: TypeLike[T], /) -> TypeGuard[Sequence[T]]:
|
737
|
-
"""Check if an object is a sequence of tuple or string mappings."""
|
738
|
-
return isinstance(obj, Sequence) and is_iterable_of(obj, cls)
|
739
|
-
|
740
|
-
|
741
|
-
##
|
742
|
-
|
743
|
-
|
744
|
-
def is_sequence_of_tuple_or_str_mapping(
|
745
|
-
obj: Any, /
|
746
|
-
) -> TypeGuard[Sequence[TupleOrStrMapping]]:
|
747
|
-
"""Check if an object is a sequence of tuple or string mappings."""
|
748
|
-
return isinstance(obj, Sequence) and all(map(is_tuple_or_str_mapping, obj))
|
749
|
-
|
750
|
-
|
751
|
-
##
|
752
|
-
|
753
|
-
|
754
|
-
def is_sized(obj: Any, /) -> TypeGuard[Sized]:
|
755
|
-
"""Check if an object is sized."""
|
756
|
-
try:
|
757
|
-
_ = len(obj)
|
758
|
-
except TypeError:
|
759
|
-
return False
|
760
|
-
return True
|
761
|
-
|
762
|
-
|
763
|
-
##
|
764
|
-
|
765
|
-
|
766
|
-
def is_sized_not_str(obj: Any, /) -> TypeGuard[Sized]:
|
767
|
-
"""Check if an object is sized, but not a string."""
|
768
|
-
return is_sized(obj) and not isinstance(obj, str)
|
769
|
-
|
770
|
-
|
771
|
-
##
|
772
|
-
|
773
|
-
|
774
|
-
def is_string_mapping(obj: Any, /) -> TypeGuard[StrMapping]:
|
775
|
-
"""Check if an object is a string mapping."""
|
776
|
-
return isinstance(obj, dict) and is_iterable_of(obj, str)
|
777
|
-
|
778
|
-
|
779
|
-
##
|
780
|
-
|
781
|
-
|
782
|
-
def is_tuple(obj: Any, /) -> TypeGuard[tuple[Any, ...]]:
|
783
|
-
"""Check if an object is a tuple or string mapping."""
|
784
|
-
return make_isinstance(tuple)(obj)
|
785
|
-
|
786
|
-
|
787
|
-
##
|
788
|
-
|
789
|
-
|
790
|
-
def is_tuple_or_str_mapping(obj: Any, /) -> TypeGuard[TupleOrStrMapping]:
|
791
|
-
"""Check if an object is a tuple or string mapping."""
|
792
|
-
return is_tuple(obj) or is_string_mapping(obj)
|
793
|
-
|
794
|
-
|
795
|
-
##
|
796
|
-
|
797
|
-
|
798
|
-
@overload
|
799
|
-
def make_isinstance[T](cls: type[T], /) -> Callable[[Any], TypeGuard[T]]: ...
|
800
|
-
@overload
|
801
|
-
def make_isinstance[T1](cls: tuple[type[T1]], /) -> Callable[[Any], TypeGuard[T1]]: ...
|
802
|
-
@overload
|
803
|
-
def make_isinstance[T1, T2](
|
804
|
-
cls: tuple[type[T1], type[T2]], /
|
805
|
-
) -> Callable[[Any], TypeGuard[T1 | T2]]: ...
|
806
|
-
@overload
|
807
|
-
def make_isinstance[T1, T2, T3](
|
808
|
-
cls: tuple[type[T1], type[T2], type[T3]], /
|
809
|
-
) -> Callable[[Any], TypeGuard[T1 | T2 | T3]]: ...
|
810
|
-
@overload
|
811
|
-
def make_isinstance[T1, T2, T3, T4](
|
812
|
-
cls: tuple[type[T1], type[T2], type[T3], type[T4]], /
|
813
|
-
) -> Callable[[Any], TypeGuard[T1 | T2 | T3 | T4]]: ...
|
814
|
-
@overload
|
815
|
-
def make_isinstance[T1, T2, T3, T4, T5](
|
816
|
-
cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]], /
|
817
|
-
) -> Callable[[Any], TypeGuard[T1 | T2 | T3 | T4 | T5]]: ...
|
818
|
-
@overload
|
819
|
-
def make_isinstance[T](cls: TypeLike[T], /) -> Callable[[Any], TypeGuard[T]]: ...
|
820
|
-
def make_isinstance[T](cls: TypeLike[T], /) -> Callable[[Any], TypeGuard[T]]:
|
821
|
-
"""Make a curried `isinstance` function."""
|
822
|
-
return partial(_make_instance_core, cls=cls)
|
823
|
-
|
824
|
-
|
825
|
-
def _make_instance_core[T](obj: Any, /, *, cls: TypeLike[T]) -> TypeGuard[T]:
|
826
|
-
return isinstance(obj, cls)
|
827
|
-
|
828
|
-
|
829
|
-
##
|
830
|
-
|
831
|
-
|
832
588
|
def map_object[T](
|
833
589
|
func: Callable[[Any], Any], obj: T, /, *, before: Callable[[Any], Any] | None = None
|
834
590
|
) -> T:
|
@@ -1000,15 +756,12 @@ __all__ = [
|
|
1000
756
|
"EnsureClassError",
|
1001
757
|
"EnsureDateError",
|
1002
758
|
"EnsureFloatError",
|
1003
|
-
"EnsureHashableError",
|
1004
759
|
"EnsureIntError",
|
1005
760
|
"EnsureMemberError",
|
1006
761
|
"EnsureNotNoneError",
|
1007
762
|
"EnsureNumberError",
|
1008
763
|
"EnsurePathError",
|
1009
764
|
"EnsurePlainDateTimeError",
|
1010
|
-
"EnsureSizedError",
|
1011
|
-
"EnsureSizedNotStrError",
|
1012
765
|
"EnsureStrError",
|
1013
766
|
"EnsureTimeDeltaError",
|
1014
767
|
"EnsureTimeError",
|
@@ -1021,15 +774,12 @@ __all__ = [
|
|
1021
774
|
"ensure_class",
|
1022
775
|
"ensure_date",
|
1023
776
|
"ensure_float",
|
1024
|
-
"ensure_hashable",
|
1025
777
|
"ensure_int",
|
1026
778
|
"ensure_member",
|
1027
779
|
"ensure_not_none",
|
1028
780
|
"ensure_number",
|
1029
781
|
"ensure_path",
|
1030
782
|
"ensure_plain_date_time",
|
1031
|
-
"ensure_sized",
|
1032
|
-
"ensure_sized_not_str",
|
1033
783
|
"ensure_str",
|
1034
784
|
"ensure_time",
|
1035
785
|
"ensure_time_delta",
|
@@ -1040,19 +790,8 @@ __all__ = [
|
|
1040
790
|
"get_func_name",
|
1041
791
|
"get_func_qualname",
|
1042
792
|
"identity",
|
1043
|
-
"is_dataclass_class",
|
1044
|
-
"is_dataclass_instance",
|
1045
|
-
"is_hashable",
|
1046
|
-
"is_iterable_of",
|
1047
793
|
"is_none",
|
1048
794
|
"is_not_none",
|
1049
|
-
"is_sequence_of_tuple_or_str_mapping",
|
1050
|
-
"is_sized",
|
1051
|
-
"is_sized_not_str",
|
1052
|
-
"is_string_mapping",
|
1053
|
-
"is_tuple",
|
1054
|
-
"is_tuple_or_str_mapping",
|
1055
|
-
"make_isinstance",
|
1056
795
|
"map_object",
|
1057
796
|
"max_nullable",
|
1058
797
|
"min_nullable",
|
utilities/iterables.py
CHANGED
@@ -31,7 +31,6 @@ from typing import (
|
|
31
31
|
)
|
32
32
|
|
33
33
|
from utilities.errors import ImpossibleCaseError
|
34
|
-
from utilities.functions import ensure_hashable, ensure_str
|
35
34
|
from utilities.math import (
|
36
35
|
_CheckIntegerEqualError,
|
37
36
|
_CheckIntegerEqualOrApproxError,
|
@@ -236,8 +235,7 @@ def check_iterables_equal(left: Iterable[Any], right: Iterable[Any], /) -> None:
|
|
236
235
|
if lv != rv:
|
237
236
|
errors.append((i, lv, rv))
|
238
237
|
except ValueError as error:
|
239
|
-
|
240
|
-
match msg:
|
238
|
+
match one(error.args):
|
241
239
|
case "zip() argument 2 is longer than argument 1":
|
242
240
|
state = "right_longer"
|
243
241
|
case "zip() argument 2 is shorter than argument 1":
|
@@ -695,18 +693,6 @@ def chunked[T](iterable: Iterable[T], n: int, /) -> Iterator[Sequence[T]]:
|
|
695
693
|
##
|
696
694
|
|
697
695
|
|
698
|
-
def ensure_hashables(
|
699
|
-
*args: Any, **kwargs: Any
|
700
|
-
) -> tuple[list[Hashable], dict[str, Hashable]]:
|
701
|
-
"""Ensure a set of positional & keyword arguments are all hashable."""
|
702
|
-
hash_args = list(map(ensure_hashable, args))
|
703
|
-
hash_kwargs = {k: ensure_hashable(v) for k, v in kwargs.items()}
|
704
|
-
return hash_args, hash_kwargs
|
705
|
-
|
706
|
-
|
707
|
-
##
|
708
|
-
|
709
|
-
|
710
696
|
def ensure_iterable(obj: Any, /) -> Iterable[Any]:
|
711
697
|
"""Ensure an object is iterable."""
|
712
698
|
if is_iterable(obj):
|
@@ -1480,7 +1466,6 @@ __all__ = [
|
|
1480
1466
|
"check_unique_modulo_case",
|
1481
1467
|
"chunked",
|
1482
1468
|
"cmp_nullable",
|
1483
|
-
"ensure_hashables",
|
1484
1469
|
"ensure_iterable",
|
1485
1470
|
"ensure_iterable_not_str",
|
1486
1471
|
"enumerate_with_edge",
|
utilities/operator.py
CHANGED
@@ -6,9 +6,9 @@ from dataclasses import asdict, dataclass
|
|
6
6
|
from typing import TYPE_CHECKING, Any, cast, override
|
7
7
|
|
8
8
|
import utilities.math
|
9
|
-
from utilities.functions import is_dataclass_instance
|
10
9
|
from utilities.iterables import SortIterableError, sort_iterable
|
11
10
|
from utilities.reprlib import get_repr
|
11
|
+
from utilities.typing import is_dataclass_instance
|
12
12
|
|
13
13
|
if TYPE_CHECKING:
|
14
14
|
from utilities.types import Dataclass, Number
|
utilities/orjson.py
CHANGED
@@ -38,7 +38,7 @@ from whenever import (
|
|
38
38
|
|
39
39
|
from utilities.concurrent import concurrent_map
|
40
40
|
from utilities.dataclasses import dataclass_to_dict
|
41
|
-
from utilities.functions import ensure_class
|
41
|
+
from utilities.functions import ensure_class
|
42
42
|
from utilities.gzip import read_binary
|
43
43
|
from utilities.iterables import (
|
44
44
|
OneEmptyError,
|
@@ -51,6 +51,7 @@ from utilities.json import write_formatted_json
|
|
51
51
|
from utilities.logging import get_logging_level_number
|
52
52
|
from utilities.math import MAX_INT64, MIN_INT64
|
53
53
|
from utilities.types import Dataclass, LogLevel, MaybeIterable, PathLike, StrMapping
|
54
|
+
from utilities.typing import is_string_mapping
|
54
55
|
from utilities.tzlocal import LOCAL_TIME_ZONE
|
55
56
|
from utilities.version import Version, parse_version
|
56
57
|
from utilities.whenever import (
|
utilities/polars.py
CHANGED
@@ -56,12 +56,7 @@ from whenever import DateDelta, DateTimeDelta, PlainDateTime, TimeDelta, ZonedDa
|
|
56
56
|
import utilities.math
|
57
57
|
from utilities.dataclasses import yield_fields
|
58
58
|
from utilities.errors import ImpossibleCaseError
|
59
|
-
from utilities.functions import
|
60
|
-
get_class_name,
|
61
|
-
is_dataclass_class,
|
62
|
-
is_dataclass_instance,
|
63
|
-
make_isinstance,
|
64
|
-
)
|
59
|
+
from utilities.functions import get_class_name
|
65
60
|
from utilities.gzip import read_binary
|
66
61
|
from utilities.iterables import (
|
67
62
|
CheckIterablesEqualError,
|
@@ -91,11 +86,14 @@ from utilities.reprlib import get_repr
|
|
91
86
|
from utilities.types import MaybeStr, Number, PathLike, WeekDay
|
92
87
|
from utilities.typing import (
|
93
88
|
get_args,
|
89
|
+
is_dataclass_class,
|
90
|
+
is_dataclass_instance,
|
94
91
|
is_frozenset_type,
|
95
92
|
is_list_type,
|
96
93
|
is_literal_type,
|
97
94
|
is_optional_type,
|
98
95
|
is_set_type,
|
96
|
+
make_isinstance,
|
99
97
|
)
|
100
98
|
from utilities.warnings import suppress_warnings
|
101
99
|
from utilities.whenever import (
|
utilities/polars_ols.py
CHANGED
@@ -6,8 +6,8 @@ from polars import Expr, Series, struct
|
|
6
6
|
from polars_ols import RollingKwargs, compute_rolling_least_squares
|
7
7
|
|
8
8
|
from utilities.errors import ImpossibleCaseError
|
9
|
-
from utilities.functions import is_sequence_of
|
10
9
|
from utilities.polars import concat_series, ensure_expr_or_series
|
10
|
+
from utilities.typing import is_sequence_of
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
13
13
|
from polars._typing import IntoExprColumn
|
utilities/redis.py
CHANGED
@@ -26,6 +26,7 @@ from utilities.errors import ImpossibleCaseError
|
|
26
26
|
from utilities.functions import ensure_int, identity
|
27
27
|
from utilities.iterables import always_iterable, one
|
28
28
|
from utilities.os import is_pytest
|
29
|
+
from utilities.typing import is_instance_gen
|
29
30
|
from utilities.whenever import MILLISECOND, SECOND, to_milliseconds, to_seconds
|
30
31
|
|
31
32
|
if TYPE_CHECKING:
|
@@ -788,17 +789,7 @@ async def _subscribe_core[T](
|
|
788
789
|
def _is_message(
|
789
790
|
message: Any, /, *, channels: Collection[bytes]
|
790
791
|
) -> TypeGuard[_RedisMessage]:
|
791
|
-
return (
|
792
|
-
isinstance(message, Mapping)
|
793
|
-
and ("type" in message)
|
794
|
-
and (message["type"] in {"subscribe", "psubscribe", "message", "pmessage"})
|
795
|
-
and ("pattern" in message)
|
796
|
-
and ((message["pattern"] is None) or isinstance(message["pattern"], str))
|
797
|
-
and ("channel" in message)
|
798
|
-
and (message["channel"] in channels)
|
799
|
-
and ("data" in message)
|
800
|
-
and isinstance(message["data"], bytes)
|
801
|
-
)
|
792
|
+
return is_instance_gen(message, _RedisMessage) and (message["channel"] in channels)
|
802
793
|
|
803
794
|
|
804
795
|
def _handle_message[T](
|
utilities/sqlalchemy.py
CHANGED
@@ -66,15 +66,7 @@ from sqlalchemy.orm.exc import UnmappedClassError
|
|
66
66
|
from sqlalchemy.pool import NullPool, Pool
|
67
67
|
|
68
68
|
from utilities.asyncio import timeout_td
|
69
|
-
from utilities.functions import
|
70
|
-
ensure_str,
|
71
|
-
get_class_name,
|
72
|
-
is_sequence_of_tuple_or_str_mapping,
|
73
|
-
is_string_mapping,
|
74
|
-
is_tuple,
|
75
|
-
is_tuple_or_str_mapping,
|
76
|
-
yield_object_attributes,
|
77
|
-
)
|
69
|
+
from utilities.functions import ensure_str, get_class_name, yield_object_attributes
|
78
70
|
from utilities.iterables import (
|
79
71
|
CheckLengthError,
|
80
72
|
CheckSubSetError,
|
@@ -97,6 +89,12 @@ from utilities.types import (
|
|
97
89
|
StrMapping,
|
98
90
|
TupleOrStrMapping,
|
99
91
|
)
|
92
|
+
from utilities.typing import (
|
93
|
+
is_sequence_of_tuple_or_str_mapping,
|
94
|
+
is_string_mapping,
|
95
|
+
is_tuple,
|
96
|
+
is_tuple_or_str_mapping,
|
97
|
+
)
|
100
98
|
|
101
99
|
if TYPE_CHECKING:
|
102
100
|
from enum import Enum, StrEnum
|
utilities/typing.py
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime as dt
|
4
|
-
from collections.abc import Mapping, Sequence
|
5
|
-
from dataclasses import dataclass
|
4
|
+
from collections.abc import Callable, Iterable, Mapping, Sequence
|
5
|
+
from dataclasses import dataclass, is_dataclass
|
6
|
+
from functools import partial
|
6
7
|
from itertools import chain
|
7
8
|
from pathlib import Path
|
8
9
|
from types import NoneType, UnionType
|
9
10
|
from typing import (
|
10
11
|
Any,
|
12
|
+
ForwardRef,
|
11
13
|
Literal,
|
12
14
|
NamedTuple,
|
13
15
|
Optional, # pyright: ignore[reportDeprecated]
|
14
16
|
TypeAliasType,
|
15
17
|
TypeGuard,
|
16
18
|
Union, # pyright: ignore[reportDeprecated]
|
19
|
+
_TypedDictMeta, # pyright: ignore[reportAttributeAccessIssue]
|
20
|
+
cast,
|
17
21
|
get_origin,
|
18
22
|
overload,
|
19
23
|
override,
|
@@ -36,7 +40,7 @@ from whenever import (
|
|
36
40
|
|
37
41
|
from utilities.iterables import unique_everseen
|
38
42
|
from utilities.sentinel import Sentinel
|
39
|
-
from utilities.types import StrMapping
|
43
|
+
from utilities.types import Dataclass, StrMapping, TupleOrStrMapping, TypeLike
|
40
44
|
|
41
45
|
|
42
46
|
def get_args(obj: Any, /, *, optional_drop_none: bool = False) -> tuple[Any, ...]:
|
@@ -147,6 +151,10 @@ def get_type_hints(
|
|
147
151
|
globalns_use = globals() | ({} if globalns is None else dict(globalns))
|
148
152
|
localns_use = {} if localns is None else dict(localns)
|
149
153
|
result: dict[str, Any] = obj.__annotations__
|
154
|
+
result = {
|
155
|
+
k: v.__forward_arg__ if isinstance(v, ForwardRef) else v
|
156
|
+
for k, v in result.items()
|
157
|
+
}
|
150
158
|
try:
|
151
159
|
hints = _get_type_hints(obj, globalns=globalns_use, localns=localns_use)
|
152
160
|
except NameError as error:
|
@@ -202,6 +210,22 @@ class _GetUnionTypeClassesInternalTypeError(GetUnionTypeClassesError):
|
|
202
210
|
##
|
203
211
|
|
204
212
|
|
213
|
+
def is_dataclass_class(obj: Any, /) -> TypeGuard[type[Dataclass]]:
|
214
|
+
"""Check if an object is a dataclass."""
|
215
|
+
return isinstance(obj, type) and is_dataclass(obj)
|
216
|
+
|
217
|
+
|
218
|
+
##
|
219
|
+
|
220
|
+
|
221
|
+
def is_dataclass_instance(obj: Any, /) -> TypeGuard[Dataclass]:
|
222
|
+
"""Check if an object is an instance of a dataclass."""
|
223
|
+
return (not isinstance(obj, type)) and is_dataclass(obj)
|
224
|
+
|
225
|
+
|
226
|
+
##
|
227
|
+
|
228
|
+
|
205
229
|
def is_dict_type(obj: Any, /) -> bool:
|
206
230
|
"""Check if an object is a dict type annotation."""
|
207
231
|
return _is_annotation_of_type(obj, dict)
|
@@ -219,50 +243,170 @@ def is_frozenset_type(obj: Any, /) -> bool:
|
|
219
243
|
|
220
244
|
|
221
245
|
@overload
|
222
|
-
def is_instance_gen[T](
|
246
|
+
def is_instance_gen[T](
|
247
|
+
obj: Any,
|
248
|
+
type_: type[T],
|
249
|
+
/,
|
250
|
+
*,
|
251
|
+
globalns: StrMapping | None = None,
|
252
|
+
localns: StrMapping | None = None,
|
253
|
+
warn_name_errors: bool = False,
|
254
|
+
) -> TypeGuard[T]: ...
|
223
255
|
@overload
|
224
|
-
def is_instance_gen[T1](
|
256
|
+
def is_instance_gen[T1](
|
257
|
+
obj: Any,
|
258
|
+
type_: tuple[T1],
|
259
|
+
/,
|
260
|
+
*,
|
261
|
+
globalns: StrMapping | None = None,
|
262
|
+
localns: StrMapping | None = None,
|
263
|
+
warn_name_errors: bool = False,
|
264
|
+
) -> TypeGuard[T1]: ...
|
225
265
|
@overload
|
226
266
|
def is_instance_gen[T1, T2](
|
227
|
-
obj: Any,
|
267
|
+
obj: Any,
|
268
|
+
type_: tuple[T1, T2],
|
269
|
+
/,
|
270
|
+
*,
|
271
|
+
globalns: StrMapping | None = None,
|
272
|
+
localns: StrMapping | None = None,
|
273
|
+
warn_name_errors: bool = False,
|
228
274
|
) -> TypeGuard[T1 | T2]: ...
|
229
275
|
@overload
|
230
276
|
def is_instance_gen[T1, T2, T3](
|
231
|
-
obj: Any,
|
277
|
+
obj: Any,
|
278
|
+
type_: tuple[T1, T2, T3],
|
279
|
+
/,
|
280
|
+
*,
|
281
|
+
globalns: StrMapping | None = None,
|
282
|
+
localns: StrMapping | None = None,
|
283
|
+
warn_name_errors: bool = False,
|
232
284
|
) -> TypeGuard[T1 | T2 | T3]: ...
|
233
285
|
@overload
|
234
286
|
def is_instance_gen[T1, T2, T3, T4](
|
235
|
-
obj: Any,
|
287
|
+
obj: Any,
|
288
|
+
type_: tuple[T1, T2, T3, T4],
|
289
|
+
/,
|
290
|
+
*,
|
291
|
+
globalns: StrMapping | None = None,
|
292
|
+
localns: StrMapping | None = None,
|
293
|
+
warn_name_errors: bool = False,
|
236
294
|
) -> TypeGuard[T1 | T2 | T3 | T4]: ...
|
237
295
|
@overload
|
238
296
|
def is_instance_gen[T1, T2, T3, T4, T5](
|
239
|
-
obj: Any,
|
297
|
+
obj: Any,
|
298
|
+
type_: tuple[T1, T2, T3, T4, T5],
|
299
|
+
/,
|
300
|
+
*,
|
301
|
+
globalns: StrMapping | None = None,
|
302
|
+
localns: StrMapping | None = None,
|
303
|
+
warn_name_errors: bool = False,
|
240
304
|
) -> TypeGuard[T1 | T2 | T3 | T4 | T5]: ...
|
241
305
|
@overload
|
242
|
-
def is_instance_gen(
|
243
|
-
|
306
|
+
def is_instance_gen(
|
307
|
+
obj: Any,
|
308
|
+
type_: Any,
|
309
|
+
/,
|
310
|
+
*,
|
311
|
+
globalns: StrMapping | None = None,
|
312
|
+
localns: StrMapping | None = None,
|
313
|
+
warn_name_errors: bool = False,
|
314
|
+
) -> bool: ...
|
315
|
+
def is_instance_gen(
|
316
|
+
obj: Any,
|
317
|
+
type_: Any,
|
318
|
+
/,
|
319
|
+
*,
|
320
|
+
globalns: StrMapping | None = None,
|
321
|
+
localns: StrMapping | None = None,
|
322
|
+
warn_name_errors: bool = False,
|
323
|
+
) -> bool:
|
244
324
|
"""Check if an instance relationship holds, except bool<int."""
|
245
325
|
# parent
|
246
326
|
if isinstance(type_, tuple):
|
247
|
-
return any(
|
327
|
+
return any(
|
328
|
+
is_instance_gen(
|
329
|
+
obj,
|
330
|
+
t,
|
331
|
+
globalns=globalns,
|
332
|
+
localns=localns,
|
333
|
+
warn_name_errors=warn_name_errors,
|
334
|
+
)
|
335
|
+
for t in type_
|
336
|
+
) # skipif-ci-and-not-windows
|
248
337
|
if is_literal_type(type_):
|
249
338
|
return obj in get_args(type_)
|
250
339
|
if is_union_type(type_):
|
251
|
-
return any(
|
340
|
+
return any(
|
341
|
+
is_instance_gen(
|
342
|
+
obj,
|
343
|
+
t,
|
344
|
+
globalns=globalns,
|
345
|
+
localns=localns,
|
346
|
+
warn_name_errors=warn_name_errors,
|
347
|
+
)
|
348
|
+
for t in get_args(type_)
|
349
|
+
)
|
252
350
|
# tuple vs tuple
|
253
351
|
if isinstance(obj, tuple) and is_tuple_type(type_):
|
254
352
|
type_args = get_args(type_)
|
255
353
|
return (len(obj) == len(type_args)) and all(
|
256
|
-
is_instance_gen(
|
354
|
+
is_instance_gen(
|
355
|
+
o,
|
356
|
+
t,
|
357
|
+
globalns=globalns,
|
358
|
+
localns=localns,
|
359
|
+
warn_name_errors=warn_name_errors,
|
360
|
+
)
|
361
|
+
for o, t in zip(obj, type_args, strict=True)
|
257
362
|
)
|
258
363
|
if isinstance(obj, tuple) is not is_tuple_type(type_):
|
259
364
|
return False
|
260
365
|
# basic
|
366
|
+
if isinstance(type_, _TypedDictMeta):
|
367
|
+
return _is_instance_typed_dict(
|
368
|
+
obj,
|
369
|
+
type_,
|
370
|
+
globalns=globalns,
|
371
|
+
localns=localns,
|
372
|
+
warn_name_errors=warn_name_errors,
|
373
|
+
)
|
261
374
|
if isinstance(type_, type):
|
262
375
|
return any(_is_instance_gen_type(obj, t) for t in get_type_classes(type_))
|
263
376
|
raise IsInstanceGenError(obj=obj, type_=type_)
|
264
377
|
|
265
378
|
|
379
|
+
def _is_instance_typed_dict[T: _TypedDictMeta](
|
380
|
+
obj: Any,
|
381
|
+
type_: type[T],
|
382
|
+
/,
|
383
|
+
*,
|
384
|
+
globalns: StrMapping | None = None,
|
385
|
+
localns: StrMapping | None = None,
|
386
|
+
warn_name_errors: bool = False,
|
387
|
+
) -> TypeGuard[T]:
|
388
|
+
if not isinstance(obj, dict):
|
389
|
+
return False
|
390
|
+
if not all(isinstance(k, str) for k in obj):
|
391
|
+
return False
|
392
|
+
obj = cast("dict[str, Any]", obj)
|
393
|
+
hints = get_type_hints(
|
394
|
+
type_, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
|
395
|
+
)
|
396
|
+
if not set(obj).issuperset(hints):
|
397
|
+
return False
|
398
|
+
return all(
|
399
|
+
is_instance_gen(
|
400
|
+
obj[k],
|
401
|
+
hints[k],
|
402
|
+
globalns=globalns,
|
403
|
+
localns=localns,
|
404
|
+
warn_name_errors=warn_name_errors,
|
405
|
+
)
|
406
|
+
for k in hints
|
407
|
+
)
|
408
|
+
|
409
|
+
|
266
410
|
def _is_instance_gen_type[T](obj: Any, type_: type[T], /) -> TypeGuard[T]:
|
267
411
|
return (
|
268
412
|
isinstance(obj, type_)
|
@@ -292,6 +436,101 @@ class IsInstanceGenError(Exception):
|
|
292
436
|
##
|
293
437
|
|
294
438
|
|
439
|
+
@overload
|
440
|
+
def is_iterable_of[T](
|
441
|
+
obj: Any,
|
442
|
+
cls: type[T],
|
443
|
+
/,
|
444
|
+
*,
|
445
|
+
globalns: StrMapping | None = None,
|
446
|
+
localns: StrMapping | None = None,
|
447
|
+
warn_name_errors: bool = False,
|
448
|
+
) -> TypeGuard[Iterable[T]]: ...
|
449
|
+
@overload
|
450
|
+
def is_iterable_of[T1](
|
451
|
+
obj: Any,
|
452
|
+
cls: tuple[type[T1]],
|
453
|
+
/,
|
454
|
+
*,
|
455
|
+
globalns: StrMapping | None = None,
|
456
|
+
localns: StrMapping | None = None,
|
457
|
+
warn_name_errors: bool = False,
|
458
|
+
) -> TypeGuard[Iterable[T1]]: ...
|
459
|
+
@overload
|
460
|
+
def is_iterable_of[T1, T2](
|
461
|
+
obj: Any,
|
462
|
+
cls: tuple[type[T1], type[T2]],
|
463
|
+
/,
|
464
|
+
*,
|
465
|
+
globalns: StrMapping | None = None,
|
466
|
+
localns: StrMapping | None = None,
|
467
|
+
warn_name_errors: bool = False,
|
468
|
+
) -> TypeGuard[Iterable[T1 | T2]]: ...
|
469
|
+
@overload
|
470
|
+
def is_iterable_of[T1, T2, T3](
|
471
|
+
obj: Any,
|
472
|
+
cls: tuple[type[T1], type[T2], type[T3]],
|
473
|
+
/,
|
474
|
+
*,
|
475
|
+
globalns: StrMapping | None = None,
|
476
|
+
localns: StrMapping | None = None,
|
477
|
+
warn_name_errors: bool = False,
|
478
|
+
) -> TypeGuard[Iterable[T1 | T2 | T3]]: ...
|
479
|
+
@overload
|
480
|
+
def is_iterable_of[T1, T2, T3, T4](
|
481
|
+
obj: Any,
|
482
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4]],
|
483
|
+
/,
|
484
|
+
*,
|
485
|
+
globalns: StrMapping | None = None,
|
486
|
+
localns: StrMapping | None = None,
|
487
|
+
warn_name_errors: bool = False,
|
488
|
+
) -> TypeGuard[Iterable[T1 | T2 | T3 | T4]]: ...
|
489
|
+
@overload
|
490
|
+
def is_iterable_of[T1, T2, T3, T4, T5](
|
491
|
+
obj: Any,
|
492
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]],
|
493
|
+
/,
|
494
|
+
*,
|
495
|
+
globalns: StrMapping | None = None,
|
496
|
+
localns: StrMapping | None = None,
|
497
|
+
warn_name_errors: bool = False,
|
498
|
+
) -> TypeGuard[Iterable[T1 | T2 | T3 | T4 | T5]]: ...
|
499
|
+
@overload
|
500
|
+
def is_iterable_of[T](
|
501
|
+
obj: Any,
|
502
|
+
cls: TypeLike[T],
|
503
|
+
/,
|
504
|
+
*,
|
505
|
+
globalns: StrMapping | None = None,
|
506
|
+
localns: StrMapping | None = None,
|
507
|
+
warn_name_errors: bool = False,
|
508
|
+
) -> TypeGuard[Iterable[T]]: ...
|
509
|
+
def is_iterable_of[T](
|
510
|
+
obj: Any,
|
511
|
+
cls: TypeLike[T],
|
512
|
+
/,
|
513
|
+
*,
|
514
|
+
globalns: StrMapping | None = None,
|
515
|
+
localns: StrMapping | None = None,
|
516
|
+
warn_name_errors: bool = False,
|
517
|
+
) -> TypeGuard[Iterable[T]]:
|
518
|
+
"""Check if an object is a iterable of tuple or string mappings."""
|
519
|
+
return isinstance(obj, Iterable) and all(
|
520
|
+
is_instance_gen(
|
521
|
+
o,
|
522
|
+
cls,
|
523
|
+
globalns=globalns,
|
524
|
+
localns=localns,
|
525
|
+
warn_name_errors=warn_name_errors,
|
526
|
+
)
|
527
|
+
for o in obj
|
528
|
+
)
|
529
|
+
|
530
|
+
|
531
|
+
##
|
532
|
+
|
533
|
+
|
295
534
|
def is_list_type(obj: Any, /) -> bool:
|
296
535
|
"""Check if an object is a list type annotation."""
|
297
536
|
return _is_annotation_of_type(obj, list)
|
@@ -349,6 +588,104 @@ def is_optional_type(obj: Any, /) -> bool:
|
|
349
588
|
##
|
350
589
|
|
351
590
|
|
591
|
+
@overload
|
592
|
+
def is_sequence_of[T](
|
593
|
+
obj: Any,
|
594
|
+
cls: type[T],
|
595
|
+
/,
|
596
|
+
*,
|
597
|
+
globalns: StrMapping | None = None,
|
598
|
+
localns: StrMapping | None = None,
|
599
|
+
warn_name_errors: bool = False,
|
600
|
+
) -> TypeGuard[Sequence[T]]: ...
|
601
|
+
@overload
|
602
|
+
def is_sequence_of[T1](
|
603
|
+
obj: Any,
|
604
|
+
cls: tuple[type[T1]],
|
605
|
+
/,
|
606
|
+
*,
|
607
|
+
globalns: StrMapping | None = None,
|
608
|
+
localns: StrMapping | None = None,
|
609
|
+
warn_name_errors: bool = False,
|
610
|
+
) -> TypeGuard[Sequence[T1]]: ...
|
611
|
+
@overload
|
612
|
+
def is_sequence_of[T1, T2](
|
613
|
+
obj: Any,
|
614
|
+
cls: tuple[type[T1], type[T2]],
|
615
|
+
/,
|
616
|
+
*,
|
617
|
+
globalns: StrMapping | None = None,
|
618
|
+
localns: StrMapping | None = None,
|
619
|
+
warn_name_errors: bool = False,
|
620
|
+
) -> TypeGuard[Sequence[T1 | T2]]: ...
|
621
|
+
@overload
|
622
|
+
def is_sequence_of[T1, T2, T3](
|
623
|
+
obj: Any,
|
624
|
+
cls: tuple[type[T1], type[T2], type[T3]],
|
625
|
+
/,
|
626
|
+
*,
|
627
|
+
globalns: StrMapping | None = None,
|
628
|
+
localns: StrMapping | None = None,
|
629
|
+
warn_name_errors: bool = False,
|
630
|
+
) -> TypeGuard[Sequence[T1 | T2 | T3]]: ...
|
631
|
+
@overload
|
632
|
+
def is_sequence_of[T1, T2, T3, T4](
|
633
|
+
obj: Any,
|
634
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4]],
|
635
|
+
/,
|
636
|
+
*,
|
637
|
+
globalns: StrMapping | None = None,
|
638
|
+
localns: StrMapping | None = None,
|
639
|
+
warn_name_errors: bool = False,
|
640
|
+
) -> TypeGuard[Sequence[T1 | T2 | T3 | T4]]: ...
|
641
|
+
@overload
|
642
|
+
def is_sequence_of[T1, T2, T3, T4, T5](
|
643
|
+
obj: Any,
|
644
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]],
|
645
|
+
/,
|
646
|
+
*,
|
647
|
+
globalns: StrMapping | None = None,
|
648
|
+
localns: StrMapping | None = None,
|
649
|
+
warn_name_errors: bool = False,
|
650
|
+
) -> TypeGuard[Sequence[T1 | T2 | T3 | T4 | T5]]: ...
|
651
|
+
@overload
|
652
|
+
def is_sequence_of[T](
|
653
|
+
obj: Any,
|
654
|
+
cls: TypeLike[T],
|
655
|
+
/,
|
656
|
+
*,
|
657
|
+
globalns: StrMapping | None = None,
|
658
|
+
localns: StrMapping | None = None,
|
659
|
+
warn_name_errors: bool = False,
|
660
|
+
) -> TypeGuard[Sequence[T]]: ...
|
661
|
+
def is_sequence_of[T](
|
662
|
+
obj: Any,
|
663
|
+
cls: TypeLike[T],
|
664
|
+
/,
|
665
|
+
*,
|
666
|
+
globalns: StrMapping | None = None,
|
667
|
+
localns: StrMapping | None = None,
|
668
|
+
warn_name_errors: bool = False,
|
669
|
+
) -> TypeGuard[Sequence[T]]:
|
670
|
+
"""Check if an object is a sequence of tuple or string mappings."""
|
671
|
+
return isinstance(obj, Sequence) and is_iterable_of(
|
672
|
+
obj, cls, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
|
673
|
+
)
|
674
|
+
|
675
|
+
|
676
|
+
##
|
677
|
+
|
678
|
+
|
679
|
+
def is_sequence_of_tuple_or_str_mapping(
|
680
|
+
obj: Any, /
|
681
|
+
) -> TypeGuard[Sequence[TupleOrStrMapping]]:
|
682
|
+
"""Check if an object is a sequence of tuple or string mappings."""
|
683
|
+
return isinstance(obj, Sequence) and all(map(is_tuple_or_str_mapping, obj))
|
684
|
+
|
685
|
+
|
686
|
+
##
|
687
|
+
|
688
|
+
|
352
689
|
def is_sequence_type(obj: Any, /) -> bool:
|
353
690
|
"""Check if an object is a sequence type annotation."""
|
354
691
|
return _is_annotation_of_type(obj, Sequence)
|
@@ -365,6 +702,14 @@ def is_set_type(obj: Any, /) -> bool:
|
|
365
702
|
##
|
366
703
|
|
367
704
|
|
705
|
+
def is_string_mapping(obj: Any, /) -> TypeGuard[StrMapping]:
|
706
|
+
"""Check if an object is a string mapping."""
|
707
|
+
return isinstance(obj, Mapping) and is_iterable_of(obj, str)
|
708
|
+
|
709
|
+
|
710
|
+
##
|
711
|
+
|
712
|
+
|
368
713
|
@overload
|
369
714
|
def is_subclass_gen[T](cls: type[Any], parent: type[T], /) -> TypeGuard[type[T]]: ...
|
370
715
|
@overload
|
@@ -450,6 +795,22 @@ class IsSubclassGenError(Exception):
|
|
450
795
|
##
|
451
796
|
|
452
797
|
|
798
|
+
def is_tuple(obj: Any, /) -> TypeGuard[tuple[Any, ...]]:
|
799
|
+
"""Check if an object is a tuple."""
|
800
|
+
return isinstance(obj, tuple)
|
801
|
+
|
802
|
+
|
803
|
+
##
|
804
|
+
|
805
|
+
|
806
|
+
def is_tuple_or_str_mapping(obj: Any, /) -> TypeGuard[TupleOrStrMapping]:
|
807
|
+
"""Check if an object is a tuple or string mapping."""
|
808
|
+
return is_tuple(obj) or is_string_mapping(obj)
|
809
|
+
|
810
|
+
|
811
|
+
##
|
812
|
+
|
813
|
+
|
453
814
|
def is_tuple_type(obj: Any, /) -> bool:
|
454
815
|
"""Check if an object is a tuple type annotation."""
|
455
816
|
return _is_annotation_of_type(obj, tuple)
|
@@ -474,6 +835,40 @@ def _is_annotation_of_type(obj: Any, origin: Any, /) -> bool:
|
|
474
835
|
)
|
475
836
|
|
476
837
|
|
838
|
+
##
|
839
|
+
|
840
|
+
|
841
|
+
@overload
|
842
|
+
def make_isinstance[T](cls: type[T], /) -> Callable[[Any], TypeGuard[T]]: ...
|
843
|
+
@overload
|
844
|
+
def make_isinstance[T1](cls: tuple[type[T1]], /) -> Callable[[Any], TypeGuard[T1]]: ...
|
845
|
+
@overload
|
846
|
+
def make_isinstance[T1, T2](
|
847
|
+
cls: tuple[type[T1], type[T2]], /
|
848
|
+
) -> Callable[[Any], TypeGuard[T1 | T2]]: ...
|
849
|
+
@overload
|
850
|
+
def make_isinstance[T1, T2, T3](
|
851
|
+
cls: tuple[type[T1], type[T2], type[T3]], /
|
852
|
+
) -> Callable[[Any], TypeGuard[T1 | T2 | T3]]: ...
|
853
|
+
@overload
|
854
|
+
def make_isinstance[T1, T2, T3, T4](
|
855
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4]], /
|
856
|
+
) -> Callable[[Any], TypeGuard[T1 | T2 | T3 | T4]]: ...
|
857
|
+
@overload
|
858
|
+
def make_isinstance[T1, T2, T3, T4, T5](
|
859
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]], /
|
860
|
+
) -> Callable[[Any], TypeGuard[T1 | T2 | T3 | T4 | T5]]: ...
|
861
|
+
@overload
|
862
|
+
def make_isinstance[T](cls: TypeLike[T], /) -> Callable[[Any], TypeGuard[T]]: ...
|
863
|
+
def make_isinstance[T](cls: TypeLike[T], /) -> Callable[[Any], TypeGuard[T]]:
|
864
|
+
"""Make a curried `isinstance` function."""
|
865
|
+
return partial(_make_instance_core, cls=cls)
|
866
|
+
|
867
|
+
|
868
|
+
def _make_instance_core[T](obj: Any, /, *, cls: TypeLike[T]) -> TypeGuard[T]:
|
869
|
+
return is_instance_gen(obj, cls)
|
870
|
+
|
871
|
+
|
477
872
|
__all__ = [
|
478
873
|
"GetTypeClassesError",
|
479
874
|
"GetUnionTypeClassesError",
|
@@ -483,18 +878,27 @@ __all__ = [
|
|
483
878
|
"get_type_classes",
|
484
879
|
"get_type_hints",
|
485
880
|
"get_union_type_classes",
|
881
|
+
"is_dataclass_class",
|
882
|
+
"is_dataclass_instance",
|
486
883
|
"is_dict_type",
|
487
884
|
"is_frozenset_type",
|
488
885
|
"is_instance_gen",
|
886
|
+
"is_iterable_of",
|
489
887
|
"is_list_type",
|
490
888
|
"is_literal_type",
|
491
889
|
"is_mapping_type",
|
492
890
|
"is_namedtuple_class",
|
493
891
|
"is_namedtuple_instance",
|
494
892
|
"is_optional_type",
|
893
|
+
"is_sequence_of",
|
894
|
+
"is_sequence_of_tuple_or_str_mapping",
|
495
895
|
"is_sequence_type",
|
496
896
|
"is_set_type",
|
897
|
+
"is_string_mapping",
|
497
898
|
"is_subclass_gen",
|
899
|
+
"is_tuple",
|
900
|
+
"is_tuple_or_str_mapping",
|
498
901
|
"is_tuple_type",
|
499
902
|
"is_union_type",
|
903
|
+
"make_isinstance",
|
500
904
|
]
|
File without changes
|
File without changes
|
File without changes
|