dycw-utilities 0.146.2__py3-none-any.whl → 0.178.1__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.
Potentially problematic release.
This version of dycw-utilities might be problematic. Click here for more details.
- dycw_utilities-0.178.1.dist-info/METADATA +34 -0
- dycw_utilities-0.178.1.dist-info/RECORD +105 -0
- dycw_utilities-0.178.1.dist-info/WHEEL +4 -0
- {dycw_utilities-0.146.2.dist-info → dycw_utilities-0.178.1.dist-info}/entry_points.txt +1 -0
- utilities/__init__.py +1 -1
- utilities/altair.py +10 -7
- utilities/asyncio.py +129 -50
- utilities/atomicwrites.py +1 -1
- utilities/atools.py +64 -4
- utilities/cachetools.py +9 -6
- utilities/click.py +144 -49
- utilities/concurrent.py +1 -1
- utilities/contextlib.py +4 -2
- utilities/contextvars.py +20 -1
- utilities/cryptography.py +3 -3
- utilities/dataclasses.py +15 -28
- utilities/docker.py +387 -0
- utilities/enum.py +2 -2
- utilities/errors.py +17 -3
- utilities/fastapi.py +8 -3
- utilities/fpdf2.py +2 -2
- utilities/functions.py +20 -297
- utilities/git.py +19 -0
- utilities/grp.py +28 -0
- utilities/hypothesis.py +361 -79
- utilities/importlib.py +17 -1
- utilities/inflect.py +1 -1
- utilities/iterables.py +33 -58
- utilities/jinja2.py +148 -0
- utilities/json.py +1 -1
- utilities/libcst.py +7 -7
- utilities/logging.py +131 -93
- utilities/math.py +8 -4
- utilities/more_itertools.py +4 -6
- utilities/operator.py +1 -1
- utilities/orjson.py +86 -34
- utilities/os.py +49 -2
- utilities/packaging.py +115 -0
- utilities/parse.py +2 -2
- utilities/pathlib.py +66 -34
- utilities/permissions.py +298 -0
- utilities/platform.py +5 -4
- utilities/polars.py +934 -420
- utilities/polars_ols.py +1 -1
- utilities/postgres.py +317 -153
- utilities/pottery.py +10 -86
- utilities/pqdm.py +3 -3
- utilities/pwd.py +28 -0
- utilities/pydantic.py +4 -51
- utilities/pydantic_settings.py +240 -0
- utilities/pydantic_settings_sops.py +76 -0
- utilities/pyinstrument.py +5 -5
- utilities/pytest.py +100 -126
- utilities/pytest_plugins/pytest_randomly.py +1 -1
- utilities/pytest_plugins/pytest_regressions.py +7 -3
- utilities/pytest_regressions.py +27 -8
- utilities/random.py +11 -6
- utilities/re.py +1 -1
- utilities/redis.py +101 -64
- utilities/sentinel.py +10 -0
- utilities/shelve.py +4 -1
- utilities/shutil.py +25 -0
- utilities/slack_sdk.py +9 -4
- utilities/sqlalchemy.py +422 -352
- utilities/sqlalchemy_polars.py +28 -52
- utilities/string.py +1 -1
- utilities/subprocess.py +1977 -0
- utilities/tempfile.py +112 -4
- utilities/testbook.py +50 -0
- utilities/text.py +174 -42
- utilities/throttle.py +158 -0
- utilities/timer.py +2 -2
- utilities/traceback.py +59 -38
- utilities/types.py +68 -22
- utilities/typing.py +479 -19
- utilities/uuid.py +42 -5
- utilities/version.py +27 -26
- utilities/whenever.py +663 -178
- utilities/zoneinfo.py +80 -22
- dycw_utilities-0.146.2.dist-info/METADATA +0 -41
- dycw_utilities-0.146.2.dist-info/RECORD +0 -99
- dycw_utilities-0.146.2.dist-info/WHEEL +0 -4
- dycw_utilities-0.146.2.dist-info/licenses/LICENSE +0 -21
- utilities/aiolimiter.py +0 -25
- utilities/eventkit.py +0 -388
- utilities/period.py +0 -237
- utilities/python_dotenv.py +0 -101
- utilities/streamlit.py +0 -105
- utilities/typed_settings.py +0 -144
utilities/typing.py
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
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
|
|
9
|
+
from re import search
|
|
8
10
|
from types import NoneType, UnionType
|
|
9
11
|
from typing import (
|
|
10
12
|
Any,
|
|
13
|
+
ForwardRef,
|
|
11
14
|
Literal,
|
|
12
15
|
NamedTuple,
|
|
16
|
+
NotRequired,
|
|
13
17
|
Optional, # pyright: ignore[reportDeprecated]
|
|
14
18
|
TypeAliasType,
|
|
15
19
|
TypeGuard,
|
|
16
20
|
Union, # pyright: ignore[reportDeprecated]
|
|
21
|
+
_TypedDictMeta, # pyright: ignore[reportAttributeAccessIssue]
|
|
22
|
+
cast,
|
|
17
23
|
get_origin,
|
|
18
24
|
overload,
|
|
19
25
|
override,
|
|
@@ -23,6 +29,7 @@ from typing import get_type_hints as _get_type_hints
|
|
|
23
29
|
from uuid import UUID
|
|
24
30
|
from warnings import warn
|
|
25
31
|
|
|
32
|
+
import whenever
|
|
26
33
|
from whenever import (
|
|
27
34
|
Date,
|
|
28
35
|
DateDelta,
|
|
@@ -35,7 +42,13 @@ from whenever import (
|
|
|
35
42
|
|
|
36
43
|
from utilities.iterables import unique_everseen
|
|
37
44
|
from utilities.sentinel import Sentinel
|
|
38
|
-
from utilities.types import
|
|
45
|
+
from utilities.types import (
|
|
46
|
+
Dataclass,
|
|
47
|
+
StrMapping,
|
|
48
|
+
StrStrMapping,
|
|
49
|
+
TupleOrStrMapping,
|
|
50
|
+
TypeLike,
|
|
51
|
+
)
|
|
39
52
|
|
|
40
53
|
|
|
41
54
|
def get_args(obj: Any, /, *, optional_drop_none: bool = False) -> tuple[Any, ...]:
|
|
@@ -51,6 +64,18 @@ def get_args(obj: Any, /, *, optional_drop_none: bool = False) -> tuple[Any, ...
|
|
|
51
64
|
##
|
|
52
65
|
|
|
53
66
|
|
|
67
|
+
def get_forward_ref_args(obj: Any, /) -> StrStrMapping:
|
|
68
|
+
"""Get the forward args."""
|
|
69
|
+
return {
|
|
70
|
+
k: v.__forward_arg__
|
|
71
|
+
for k, v in obj.__annotations__.items()
|
|
72
|
+
if isinstance(v, ForwardRef)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
|
|
78
|
+
|
|
54
79
|
def get_literal_elements(obj: Any, /) -> list[Any]:
|
|
55
80
|
"""Get the elements of a literal annotation."""
|
|
56
81
|
return _get_literal_elements_inner(obj)
|
|
@@ -122,7 +147,6 @@ def get_type_hints(
|
|
|
122
147
|
warn_name_errors: bool = False,
|
|
123
148
|
) -> dict[str, Any]:
|
|
124
149
|
"""Get the type hints of an object."""
|
|
125
|
-
result: dict[str, Any] = obj.__annotations__
|
|
126
150
|
_ = {
|
|
127
151
|
Date,
|
|
128
152
|
DateDelta,
|
|
@@ -136,21 +160,31 @@ def get_type_hints(
|
|
|
136
160
|
TimeDelta,
|
|
137
161
|
UUID,
|
|
138
162
|
ZonedDateTime,
|
|
139
|
-
|
|
163
|
+
whenever.Date,
|
|
164
|
+
whenever.DateDelta,
|
|
165
|
+
whenever.DateTimeDelta,
|
|
166
|
+
whenever.PlainDateTime,
|
|
167
|
+
whenever.Time,
|
|
168
|
+
whenever.TimeDelta,
|
|
169
|
+
whenever.ZonedDateTime,
|
|
140
170
|
}
|
|
141
171
|
globalns_use = globals() | ({} if globalns is None else dict(globalns))
|
|
142
172
|
localns_use = {} if localns is None else dict(localns)
|
|
173
|
+
result: dict[str, Any] = obj.__annotations__
|
|
174
|
+
result = result | dict(get_forward_ref_args(obj))
|
|
143
175
|
try:
|
|
144
|
-
hints = _get_type_hints(
|
|
176
|
+
hints = _get_type_hints(
|
|
177
|
+
obj, globalns=globalns_use, localns=localns_use, include_extras=True
|
|
178
|
+
)
|
|
145
179
|
except NameError as error:
|
|
146
180
|
if warn_name_errors:
|
|
147
181
|
warn(f"Error getting type hints for {obj!r}; {error}", stacklevel=2)
|
|
148
182
|
else:
|
|
149
|
-
result
|
|
183
|
+
result = result | {
|
|
150
184
|
key: value
|
|
151
185
|
for key, value in hints.items()
|
|
152
186
|
if (key not in result) or isinstance(result[key], str)
|
|
153
|
-
}
|
|
187
|
+
}
|
|
154
188
|
return result
|
|
155
189
|
|
|
156
190
|
|
|
@@ -195,6 +229,22 @@ class _GetUnionTypeClassesInternalTypeError(GetUnionTypeClassesError):
|
|
|
195
229
|
##
|
|
196
230
|
|
|
197
231
|
|
|
232
|
+
def is_dataclass_class(obj: Any, /) -> TypeGuard[type[Dataclass]]:
|
|
233
|
+
"""Check if an object is a dataclass."""
|
|
234
|
+
return isinstance(obj, type) and is_dataclass(obj)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
##
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def is_dataclass_instance(obj: Any, /) -> TypeGuard[Dataclass]:
|
|
241
|
+
"""Check if an object is an instance of a dataclass."""
|
|
242
|
+
return (not isinstance(obj, type)) and is_dataclass(obj)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
##
|
|
246
|
+
|
|
247
|
+
|
|
198
248
|
def is_dict_type(obj: Any, /) -> bool:
|
|
199
249
|
"""Check if an object is a dict type annotation."""
|
|
200
250
|
return _is_annotation_of_type(obj, dict)
|
|
@@ -212,50 +262,174 @@ def is_frozenset_type(obj: Any, /) -> bool:
|
|
|
212
262
|
|
|
213
263
|
|
|
214
264
|
@overload
|
|
215
|
-
def is_instance_gen[T](
|
|
265
|
+
def is_instance_gen[T](
|
|
266
|
+
obj: Any,
|
|
267
|
+
type_: type[T],
|
|
268
|
+
/,
|
|
269
|
+
*,
|
|
270
|
+
globalns: StrMapping | None = None,
|
|
271
|
+
localns: StrMapping | None = None,
|
|
272
|
+
warn_name_errors: bool = False,
|
|
273
|
+
) -> TypeGuard[T]: ...
|
|
216
274
|
@overload
|
|
217
|
-
def is_instance_gen[T1](
|
|
275
|
+
def is_instance_gen[T1](
|
|
276
|
+
obj: Any,
|
|
277
|
+
type_: tuple[T1],
|
|
278
|
+
/,
|
|
279
|
+
*,
|
|
280
|
+
globalns: StrMapping | None = None,
|
|
281
|
+
localns: StrMapping | None = None,
|
|
282
|
+
warn_name_errors: bool = False,
|
|
283
|
+
) -> TypeGuard[T1]: ...
|
|
218
284
|
@overload
|
|
219
285
|
def is_instance_gen[T1, T2](
|
|
220
|
-
obj: Any,
|
|
286
|
+
obj: Any,
|
|
287
|
+
type_: tuple[T1, T2],
|
|
288
|
+
/,
|
|
289
|
+
*,
|
|
290
|
+
globalns: StrMapping | None = None,
|
|
291
|
+
localns: StrMapping | None = None,
|
|
292
|
+
warn_name_errors: bool = False,
|
|
221
293
|
) -> TypeGuard[T1 | T2]: ...
|
|
222
294
|
@overload
|
|
223
295
|
def is_instance_gen[T1, T2, T3](
|
|
224
|
-
obj: Any,
|
|
296
|
+
obj: Any,
|
|
297
|
+
type_: tuple[T1, T2, T3],
|
|
298
|
+
/,
|
|
299
|
+
*,
|
|
300
|
+
globalns: StrMapping | None = None,
|
|
301
|
+
localns: StrMapping | None = None,
|
|
302
|
+
warn_name_errors: bool = False,
|
|
225
303
|
) -> TypeGuard[T1 | T2 | T3]: ...
|
|
226
304
|
@overload
|
|
227
305
|
def is_instance_gen[T1, T2, T3, T4](
|
|
228
|
-
obj: Any,
|
|
306
|
+
obj: Any,
|
|
307
|
+
type_: tuple[T1, T2, T3, T4],
|
|
308
|
+
/,
|
|
309
|
+
*,
|
|
310
|
+
globalns: StrMapping | None = None,
|
|
311
|
+
localns: StrMapping | None = None,
|
|
312
|
+
warn_name_errors: bool = False,
|
|
229
313
|
) -> TypeGuard[T1 | T2 | T3 | T4]: ...
|
|
230
314
|
@overload
|
|
231
315
|
def is_instance_gen[T1, T2, T3, T4, T5](
|
|
232
|
-
obj: Any,
|
|
316
|
+
obj: Any,
|
|
317
|
+
type_: tuple[T1, T2, T3, T4, T5],
|
|
318
|
+
/,
|
|
319
|
+
*,
|
|
320
|
+
globalns: StrMapping | None = None,
|
|
321
|
+
localns: StrMapping | None = None,
|
|
322
|
+
warn_name_errors: bool = False,
|
|
233
323
|
) -> TypeGuard[T1 | T2 | T3 | T4 | T5]: ...
|
|
234
324
|
@overload
|
|
235
|
-
def is_instance_gen(
|
|
236
|
-
|
|
325
|
+
def is_instance_gen(
|
|
326
|
+
obj: Any,
|
|
327
|
+
type_: Any,
|
|
328
|
+
/,
|
|
329
|
+
*,
|
|
330
|
+
globalns: StrMapping | None = None,
|
|
331
|
+
localns: StrMapping | None = None,
|
|
332
|
+
warn_name_errors: bool = False,
|
|
333
|
+
) -> bool: ...
|
|
334
|
+
def is_instance_gen(
|
|
335
|
+
obj: Any,
|
|
336
|
+
type_: Any,
|
|
337
|
+
/,
|
|
338
|
+
*,
|
|
339
|
+
globalns: StrMapping | None = None,
|
|
340
|
+
localns: StrMapping | None = None,
|
|
341
|
+
warn_name_errors: bool = False,
|
|
342
|
+
) -> bool:
|
|
237
343
|
"""Check if an instance relationship holds, except bool<int."""
|
|
238
344
|
# parent
|
|
239
345
|
if isinstance(type_, tuple):
|
|
240
|
-
return any(
|
|
346
|
+
return any(
|
|
347
|
+
is_instance_gen(
|
|
348
|
+
obj,
|
|
349
|
+
t,
|
|
350
|
+
globalns=globalns,
|
|
351
|
+
localns=localns,
|
|
352
|
+
warn_name_errors=warn_name_errors,
|
|
353
|
+
)
|
|
354
|
+
for t in type_
|
|
355
|
+
)
|
|
241
356
|
if is_literal_type(type_):
|
|
242
357
|
return obj in get_args(type_)
|
|
243
358
|
if is_union_type(type_):
|
|
244
|
-
return any(
|
|
359
|
+
return any(
|
|
360
|
+
is_instance_gen(
|
|
361
|
+
obj,
|
|
362
|
+
t,
|
|
363
|
+
globalns=globalns,
|
|
364
|
+
localns=localns,
|
|
365
|
+
warn_name_errors=warn_name_errors,
|
|
366
|
+
)
|
|
367
|
+
for t in get_args(type_)
|
|
368
|
+
)
|
|
245
369
|
# tuple vs tuple
|
|
246
370
|
if isinstance(obj, tuple) and is_tuple_type(type_):
|
|
247
371
|
type_args = get_args(type_)
|
|
248
372
|
return (len(obj) == len(type_args)) and all(
|
|
249
|
-
is_instance_gen(
|
|
373
|
+
is_instance_gen(
|
|
374
|
+
o,
|
|
375
|
+
t,
|
|
376
|
+
globalns=globalns,
|
|
377
|
+
localns=localns,
|
|
378
|
+
warn_name_errors=warn_name_errors,
|
|
379
|
+
)
|
|
380
|
+
for o, t in zip(obj, type_args, strict=True)
|
|
250
381
|
)
|
|
251
382
|
if isinstance(obj, tuple) is not is_tuple_type(type_):
|
|
252
383
|
return False
|
|
253
384
|
# basic
|
|
385
|
+
if isinstance(type_, _TypedDictMeta):
|
|
386
|
+
return _is_instance_typed_dict(
|
|
387
|
+
obj,
|
|
388
|
+
type_,
|
|
389
|
+
globalns=globalns,
|
|
390
|
+
localns=localns,
|
|
391
|
+
warn_name_errors=warn_name_errors,
|
|
392
|
+
)
|
|
254
393
|
if isinstance(type_, type):
|
|
255
394
|
return any(_is_instance_gen_type(obj, t) for t in get_type_classes(type_))
|
|
256
395
|
raise IsInstanceGenError(obj=obj, type_=type_)
|
|
257
396
|
|
|
258
397
|
|
|
398
|
+
def _is_instance_typed_dict[T: _TypedDictMeta](
|
|
399
|
+
obj: Any,
|
|
400
|
+
type_: type[T],
|
|
401
|
+
/,
|
|
402
|
+
*,
|
|
403
|
+
globalns: StrMapping | None = None,
|
|
404
|
+
localns: StrMapping | None = None,
|
|
405
|
+
warn_name_errors: bool = False,
|
|
406
|
+
) -> TypeGuard[T]:
|
|
407
|
+
if not isinstance(obj, dict):
|
|
408
|
+
return False
|
|
409
|
+
if not all(isinstance(k, str) for k in obj):
|
|
410
|
+
return False
|
|
411
|
+
obj = cast("dict[str, Any]", obj)
|
|
412
|
+
hints = get_type_hints(
|
|
413
|
+
type_, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
|
|
414
|
+
)
|
|
415
|
+
optional = {
|
|
416
|
+
k for k, v in type_.__annotations__.items() if is_not_required_annotation(v)
|
|
417
|
+
}
|
|
418
|
+
required = {k: v for k, v in hints.items() if k not in optional}
|
|
419
|
+
if not set(obj).issuperset(required):
|
|
420
|
+
return False
|
|
421
|
+
return all(
|
|
422
|
+
is_instance_gen(
|
|
423
|
+
obj[k],
|
|
424
|
+
required[k],
|
|
425
|
+
globalns=globalns,
|
|
426
|
+
localns=localns,
|
|
427
|
+
warn_name_errors=warn_name_errors,
|
|
428
|
+
)
|
|
429
|
+
for k in required
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
|
|
259
433
|
def _is_instance_gen_type[T](obj: Any, type_: type[T], /) -> TypeGuard[T]:
|
|
260
434
|
return (
|
|
261
435
|
isinstance(obj, type_)
|
|
@@ -285,6 +459,101 @@ class IsInstanceGenError(Exception):
|
|
|
285
459
|
##
|
|
286
460
|
|
|
287
461
|
|
|
462
|
+
@overload
|
|
463
|
+
def is_iterable_of[T](
|
|
464
|
+
obj: Any,
|
|
465
|
+
cls: type[T],
|
|
466
|
+
/,
|
|
467
|
+
*,
|
|
468
|
+
globalns: StrMapping | None = None,
|
|
469
|
+
localns: StrMapping | None = None,
|
|
470
|
+
warn_name_errors: bool = False,
|
|
471
|
+
) -> TypeGuard[Iterable[T]]: ...
|
|
472
|
+
@overload
|
|
473
|
+
def is_iterable_of[T1](
|
|
474
|
+
obj: Any,
|
|
475
|
+
cls: tuple[type[T1]],
|
|
476
|
+
/,
|
|
477
|
+
*,
|
|
478
|
+
globalns: StrMapping | None = None,
|
|
479
|
+
localns: StrMapping | None = None,
|
|
480
|
+
warn_name_errors: bool = False,
|
|
481
|
+
) -> TypeGuard[Iterable[T1]]: ...
|
|
482
|
+
@overload
|
|
483
|
+
def is_iterable_of[T1, T2](
|
|
484
|
+
obj: Any,
|
|
485
|
+
cls: tuple[type[T1], type[T2]],
|
|
486
|
+
/,
|
|
487
|
+
*,
|
|
488
|
+
globalns: StrMapping | None = None,
|
|
489
|
+
localns: StrMapping | None = None,
|
|
490
|
+
warn_name_errors: bool = False,
|
|
491
|
+
) -> TypeGuard[Iterable[T1 | T2]]: ...
|
|
492
|
+
@overload
|
|
493
|
+
def is_iterable_of[T1, T2, T3](
|
|
494
|
+
obj: Any,
|
|
495
|
+
cls: tuple[type[T1], type[T2], type[T3]],
|
|
496
|
+
/,
|
|
497
|
+
*,
|
|
498
|
+
globalns: StrMapping | None = None,
|
|
499
|
+
localns: StrMapping | None = None,
|
|
500
|
+
warn_name_errors: bool = False,
|
|
501
|
+
) -> TypeGuard[Iterable[T1 | T2 | T3]]: ...
|
|
502
|
+
@overload
|
|
503
|
+
def is_iterable_of[T1, T2, T3, T4](
|
|
504
|
+
obj: Any,
|
|
505
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4]],
|
|
506
|
+
/,
|
|
507
|
+
*,
|
|
508
|
+
globalns: StrMapping | None = None,
|
|
509
|
+
localns: StrMapping | None = None,
|
|
510
|
+
warn_name_errors: bool = False,
|
|
511
|
+
) -> TypeGuard[Iterable[T1 | T2 | T3 | T4]]: ...
|
|
512
|
+
@overload
|
|
513
|
+
def is_iterable_of[T1, T2, T3, T4, T5](
|
|
514
|
+
obj: Any,
|
|
515
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]],
|
|
516
|
+
/,
|
|
517
|
+
*,
|
|
518
|
+
globalns: StrMapping | None = None,
|
|
519
|
+
localns: StrMapping | None = None,
|
|
520
|
+
warn_name_errors: bool = False,
|
|
521
|
+
) -> TypeGuard[Iterable[T1 | T2 | T3 | T4 | T5]]: ...
|
|
522
|
+
@overload
|
|
523
|
+
def is_iterable_of[T](
|
|
524
|
+
obj: Any,
|
|
525
|
+
cls: TypeLike[T],
|
|
526
|
+
/,
|
|
527
|
+
*,
|
|
528
|
+
globalns: StrMapping | None = None,
|
|
529
|
+
localns: StrMapping | None = None,
|
|
530
|
+
warn_name_errors: bool = False,
|
|
531
|
+
) -> TypeGuard[Iterable[T]]: ...
|
|
532
|
+
def is_iterable_of[T](
|
|
533
|
+
obj: Any,
|
|
534
|
+
cls: TypeLike[T],
|
|
535
|
+
/,
|
|
536
|
+
*,
|
|
537
|
+
globalns: StrMapping | None = None,
|
|
538
|
+
localns: StrMapping | None = None,
|
|
539
|
+
warn_name_errors: bool = False,
|
|
540
|
+
) -> TypeGuard[Iterable[T]]:
|
|
541
|
+
"""Check if an object is a iterable of tuple or string mappings."""
|
|
542
|
+
return isinstance(obj, Iterable) and all(
|
|
543
|
+
is_instance_gen(
|
|
544
|
+
o,
|
|
545
|
+
cls,
|
|
546
|
+
globalns=globalns,
|
|
547
|
+
localns=localns,
|
|
548
|
+
warn_name_errors=warn_name_errors,
|
|
549
|
+
)
|
|
550
|
+
for o in obj
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
##
|
|
555
|
+
|
|
556
|
+
|
|
288
557
|
def is_list_type(obj: Any, /) -> bool:
|
|
289
558
|
"""Check if an object is a list type annotation."""
|
|
290
559
|
return _is_annotation_of_type(obj, list)
|
|
@@ -331,6 +600,30 @@ def _is_namedtuple_core(obj: Any, /) -> bool:
|
|
|
331
600
|
##
|
|
332
601
|
|
|
333
602
|
|
|
603
|
+
def is_not_required_annotation(obj: Any) -> bool:
|
|
604
|
+
"""Check if an annotation is not required."""
|
|
605
|
+
if is_not_required_type(obj):
|
|
606
|
+
return True
|
|
607
|
+
match obj:
|
|
608
|
+
case str() as text:
|
|
609
|
+
return bool(search("NotRequired", text))
|
|
610
|
+
case ForwardRef() as fr:
|
|
611
|
+
return is_not_required_annotation(fr.__forward_arg__)
|
|
612
|
+
case _:
|
|
613
|
+
return False
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
##
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
def is_not_required_type(obj: Any, /) -> bool:
|
|
620
|
+
"""Check if an object is a not-required type annotation."""
|
|
621
|
+
return (obj is NotRequired) or _is_annotation_of_type(obj, NotRequired)
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
##
|
|
625
|
+
|
|
626
|
+
|
|
334
627
|
def is_optional_type(obj: Any, /) -> bool:
|
|
335
628
|
"""Check if an object is an optional type annotation."""
|
|
336
629
|
is_optional = _is_annotation_of_type(obj, Optional) # pyright: ignore[reportDeprecated]
|
|
@@ -342,6 +635,104 @@ def is_optional_type(obj: Any, /) -> bool:
|
|
|
342
635
|
##
|
|
343
636
|
|
|
344
637
|
|
|
638
|
+
@overload
|
|
639
|
+
def is_sequence_of[T](
|
|
640
|
+
obj: Any,
|
|
641
|
+
cls: type[T],
|
|
642
|
+
/,
|
|
643
|
+
*,
|
|
644
|
+
globalns: StrMapping | None = None,
|
|
645
|
+
localns: StrMapping | None = None,
|
|
646
|
+
warn_name_errors: bool = False,
|
|
647
|
+
) -> TypeGuard[Sequence[T]]: ...
|
|
648
|
+
@overload
|
|
649
|
+
def is_sequence_of[T1](
|
|
650
|
+
obj: Any,
|
|
651
|
+
cls: tuple[type[T1]],
|
|
652
|
+
/,
|
|
653
|
+
*,
|
|
654
|
+
globalns: StrMapping | None = None,
|
|
655
|
+
localns: StrMapping | None = None,
|
|
656
|
+
warn_name_errors: bool = False,
|
|
657
|
+
) -> TypeGuard[Sequence[T1]]: ...
|
|
658
|
+
@overload
|
|
659
|
+
def is_sequence_of[T1, T2](
|
|
660
|
+
obj: Any,
|
|
661
|
+
cls: tuple[type[T1], type[T2]],
|
|
662
|
+
/,
|
|
663
|
+
*,
|
|
664
|
+
globalns: StrMapping | None = None,
|
|
665
|
+
localns: StrMapping | None = None,
|
|
666
|
+
warn_name_errors: bool = False,
|
|
667
|
+
) -> TypeGuard[Sequence[T1 | T2]]: ...
|
|
668
|
+
@overload
|
|
669
|
+
def is_sequence_of[T1, T2, T3](
|
|
670
|
+
obj: Any,
|
|
671
|
+
cls: tuple[type[T1], type[T2], type[T3]],
|
|
672
|
+
/,
|
|
673
|
+
*,
|
|
674
|
+
globalns: StrMapping | None = None,
|
|
675
|
+
localns: StrMapping | None = None,
|
|
676
|
+
warn_name_errors: bool = False,
|
|
677
|
+
) -> TypeGuard[Sequence[T1 | T2 | T3]]: ...
|
|
678
|
+
@overload
|
|
679
|
+
def is_sequence_of[T1, T2, T3, T4](
|
|
680
|
+
obj: Any,
|
|
681
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4]],
|
|
682
|
+
/,
|
|
683
|
+
*,
|
|
684
|
+
globalns: StrMapping | None = None,
|
|
685
|
+
localns: StrMapping | None = None,
|
|
686
|
+
warn_name_errors: bool = False,
|
|
687
|
+
) -> TypeGuard[Sequence[T1 | T2 | T3 | T4]]: ...
|
|
688
|
+
@overload
|
|
689
|
+
def is_sequence_of[T1, T2, T3, T4, T5](
|
|
690
|
+
obj: Any,
|
|
691
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]],
|
|
692
|
+
/,
|
|
693
|
+
*,
|
|
694
|
+
globalns: StrMapping | None = None,
|
|
695
|
+
localns: StrMapping | None = None,
|
|
696
|
+
warn_name_errors: bool = False,
|
|
697
|
+
) -> TypeGuard[Sequence[T1 | T2 | T3 | T4 | T5]]: ...
|
|
698
|
+
@overload
|
|
699
|
+
def is_sequence_of[T](
|
|
700
|
+
obj: Any,
|
|
701
|
+
cls: TypeLike[T],
|
|
702
|
+
/,
|
|
703
|
+
*,
|
|
704
|
+
globalns: StrMapping | None = None,
|
|
705
|
+
localns: StrMapping | None = None,
|
|
706
|
+
warn_name_errors: bool = False,
|
|
707
|
+
) -> TypeGuard[Sequence[T]]: ...
|
|
708
|
+
def is_sequence_of[T](
|
|
709
|
+
obj: Any,
|
|
710
|
+
cls: TypeLike[T],
|
|
711
|
+
/,
|
|
712
|
+
*,
|
|
713
|
+
globalns: StrMapping | None = None,
|
|
714
|
+
localns: StrMapping | None = None,
|
|
715
|
+
warn_name_errors: bool = False,
|
|
716
|
+
) -> TypeGuard[Sequence[T]]:
|
|
717
|
+
"""Check if an object is a sequence of tuple or string mappings."""
|
|
718
|
+
return isinstance(obj, Sequence) and is_iterable_of(
|
|
719
|
+
obj, cls, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
##
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
def is_sequence_of_tuple_or_str_mapping(
|
|
727
|
+
obj: Any, /
|
|
728
|
+
) -> TypeGuard[Sequence[TupleOrStrMapping]]:
|
|
729
|
+
"""Check if an object is a sequence of tuple or string mappings."""
|
|
730
|
+
return isinstance(obj, Sequence) and all(map(is_tuple_or_str_mapping, obj))
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
##
|
|
734
|
+
|
|
735
|
+
|
|
345
736
|
def is_sequence_type(obj: Any, /) -> bool:
|
|
346
737
|
"""Check if an object is a sequence type annotation."""
|
|
347
738
|
return _is_annotation_of_type(obj, Sequence)
|
|
@@ -358,6 +749,14 @@ def is_set_type(obj: Any, /) -> bool:
|
|
|
358
749
|
##
|
|
359
750
|
|
|
360
751
|
|
|
752
|
+
def is_string_mapping(obj: Any, /) -> TypeGuard[StrMapping]:
|
|
753
|
+
"""Check if an object is a string mapping."""
|
|
754
|
+
return isinstance(obj, Mapping) and is_iterable_of(obj, str)
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
##
|
|
758
|
+
|
|
759
|
+
|
|
361
760
|
@overload
|
|
362
761
|
def is_subclass_gen[T](cls: type[Any], parent: type[T], /) -> TypeGuard[type[T]]: ...
|
|
363
762
|
@overload
|
|
@@ -443,6 +842,22 @@ class IsSubclassGenError(Exception):
|
|
|
443
842
|
##
|
|
444
843
|
|
|
445
844
|
|
|
845
|
+
def is_tuple(obj: Any, /) -> TypeGuard[tuple[Any, ...]]:
|
|
846
|
+
"""Check if an object is a tuple."""
|
|
847
|
+
return isinstance(obj, tuple)
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
##
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
def is_tuple_or_str_mapping(obj: Any, /) -> TypeGuard[TupleOrStrMapping]:
|
|
854
|
+
"""Check if an object is a tuple or string mapping."""
|
|
855
|
+
return is_tuple(obj) or is_string_mapping(obj)
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
##
|
|
859
|
+
|
|
860
|
+
|
|
446
861
|
def is_tuple_type(obj: Any, /) -> bool:
|
|
447
862
|
"""Check if an object is a tuple type annotation."""
|
|
448
863
|
return _is_annotation_of_type(obj, tuple)
|
|
@@ -467,6 +882,40 @@ def _is_annotation_of_type(obj: Any, origin: Any, /) -> bool:
|
|
|
467
882
|
)
|
|
468
883
|
|
|
469
884
|
|
|
885
|
+
##
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
@overload
|
|
889
|
+
def make_isinstance[T](cls: type[T], /) -> Callable[[Any], TypeGuard[T]]: ...
|
|
890
|
+
@overload
|
|
891
|
+
def make_isinstance[T1](cls: tuple[type[T1]], /) -> Callable[[Any], TypeGuard[T1]]: ...
|
|
892
|
+
@overload
|
|
893
|
+
def make_isinstance[T1, T2](
|
|
894
|
+
cls: tuple[type[T1], type[T2]], /
|
|
895
|
+
) -> Callable[[Any], TypeGuard[T1 | T2]]: ...
|
|
896
|
+
@overload
|
|
897
|
+
def make_isinstance[T1, T2, T3](
|
|
898
|
+
cls: tuple[type[T1], type[T2], type[T3]], /
|
|
899
|
+
) -> Callable[[Any], TypeGuard[T1 | T2 | T3]]: ...
|
|
900
|
+
@overload
|
|
901
|
+
def make_isinstance[T1, T2, T3, T4](
|
|
902
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4]], /
|
|
903
|
+
) -> Callable[[Any], TypeGuard[T1 | T2 | T3 | T4]]: ...
|
|
904
|
+
@overload
|
|
905
|
+
def make_isinstance[T1, T2, T3, T4, T5](
|
|
906
|
+
cls: tuple[type[T1], type[T2], type[T3], type[T4], type[T5]], /
|
|
907
|
+
) -> Callable[[Any], TypeGuard[T1 | T2 | T3 | T4 | T5]]: ...
|
|
908
|
+
@overload
|
|
909
|
+
def make_isinstance[T](cls: TypeLike[T], /) -> Callable[[Any], TypeGuard[T]]: ...
|
|
910
|
+
def make_isinstance[T](cls: TypeLike[T], /) -> Callable[[Any], TypeGuard[T]]:
|
|
911
|
+
"""Make a curried `isinstance` function."""
|
|
912
|
+
return partial(_make_instance_core, cls=cls)
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
def _make_instance_core[T](obj: Any, /, *, cls: TypeLike[T]) -> TypeGuard[T]:
|
|
916
|
+
return is_instance_gen(obj, cls)
|
|
917
|
+
|
|
918
|
+
|
|
470
919
|
__all__ = [
|
|
471
920
|
"GetTypeClassesError",
|
|
472
921
|
"GetUnionTypeClassesError",
|
|
@@ -476,18 +925,29 @@ __all__ = [
|
|
|
476
925
|
"get_type_classes",
|
|
477
926
|
"get_type_hints",
|
|
478
927
|
"get_union_type_classes",
|
|
928
|
+
"is_dataclass_class",
|
|
929
|
+
"is_dataclass_instance",
|
|
479
930
|
"is_dict_type",
|
|
480
931
|
"is_frozenset_type",
|
|
481
932
|
"is_instance_gen",
|
|
933
|
+
"is_iterable_of",
|
|
482
934
|
"is_list_type",
|
|
483
935
|
"is_literal_type",
|
|
484
936
|
"is_mapping_type",
|
|
485
937
|
"is_namedtuple_class",
|
|
486
938
|
"is_namedtuple_instance",
|
|
939
|
+
"is_not_required_annotation",
|
|
940
|
+
"is_not_required_type",
|
|
487
941
|
"is_optional_type",
|
|
942
|
+
"is_sequence_of",
|
|
943
|
+
"is_sequence_of_tuple_or_str_mapping",
|
|
488
944
|
"is_sequence_type",
|
|
489
945
|
"is_set_type",
|
|
946
|
+
"is_string_mapping",
|
|
490
947
|
"is_subclass_gen",
|
|
948
|
+
"is_tuple",
|
|
949
|
+
"is_tuple_or_str_mapping",
|
|
491
950
|
"is_tuple_type",
|
|
492
951
|
"is_union_type",
|
|
952
|
+
"make_isinstance",
|
|
493
953
|
]
|