dycw-utilities 0.166.26__py3-none-any.whl → 0.166.27__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.166.26.dist-info → dycw_utilities-0.166.27.dist-info}/METADATA +1 -1
- {dycw_utilities-0.166.26.dist-info → dycw_utilities-0.166.27.dist-info}/RECORD +8 -8
- utilities/__init__.py +1 -1
- utilities/asyncio.py +63 -0
- utilities/iterables.py +1 -1
- {dycw_utilities-0.166.26.dist-info → dycw_utilities-0.166.27.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.166.26.dist-info → dycw_utilities-0.166.27.dist-info}/entry_points.txt +0 -0
- {dycw_utilities-0.166.26.dist-info → dycw_utilities-0.166.27.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
utilities/__init__.py,sha256=
|
|
1
|
+
utilities/__init__.py,sha256=HjzeHsUXRBIhhvlhaEdygkT-X4czww6QieOICBEASeM,61
|
|
2
2
|
utilities/aeventkit.py,sha256=ddoleSwW9zdc2tjX5Ge0pMKtYwV_JMxhHYOxnWX2AGM,12609
|
|
3
3
|
utilities/altair.py,sha256=nHdpWt8ZwdUwRQN970MvHd5bRWokNqzHcZQEdSHKRuE,9033
|
|
4
|
-
utilities/asyncio.py,sha256=
|
|
4
|
+
utilities/asyncio.py,sha256=60l1IwjnRGeaVphAFiwDIHyfKoZYKY-XGpptUxGiU-M,17034
|
|
5
5
|
utilities/atomicwrites.py,sha256=tPo6r-Rypd9u99u66B9z86YBPpnLrlHtwox_8Z7T34Y,5790
|
|
6
6
|
utilities/atools.py,sha256=6neeCcgXxK2dlsc0xp15Za7nSucbCgFtAJepGI_-WXU,2549
|
|
7
7
|
utilities/cachetools.py,sha256=v1-9sXHLdOLiwmkq6NB0OUbxeKBuVVN6wmAWefWoaHI,2744
|
|
@@ -27,7 +27,7 @@ utilities/hypothesis.py,sha256=CSCJFek07g71iSND7PCty7gyaOT_49QSbnTHn1wWidQ,45535
|
|
|
27
27
|
utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
|
|
28
28
|
utilities/inflect.py,sha256=v7YkOWSu8NAmVghPcf4F3YBZQoJCS47_DLf9jbfWIs0,581
|
|
29
29
|
utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
|
|
30
|
-
utilities/iterables.py,sha256=
|
|
30
|
+
utilities/iterables.py,sha256=t2TsW-K3rVlS6y4_tqcc1fk9RwJV-bi7G_VwduMABK0,42558
|
|
31
31
|
utilities/json.py,sha256=-WcGtSsCr9Y42wHZzAMnfvU6ihAfVftylFfRUORaDFo,2102
|
|
32
32
|
utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
|
|
33
33
|
utilities/libcst.py,sha256=ngD4wxnR3Kh-RBVmU5l5ST7cuZLhMZwyMDjHZe5mhTs,5581
|
|
@@ -91,8 +91,8 @@ utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
|
|
|
91
91
|
utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
92
92
|
utilities/pytest_plugins/pytest_randomly.py,sha256=B1qYVlExGOxTywq2r1SMi5o7btHLk2PNdY_b1p98dkE,409
|
|
93
93
|
utilities/pytest_plugins/pytest_regressions.py,sha256=mnHYBfdprz50UGVkVzV1bZERZN5CFfoF8YbokGxdFwU,1639
|
|
94
|
-
dycw_utilities-0.166.
|
|
95
|
-
dycw_utilities-0.166.
|
|
96
|
-
dycw_utilities-0.166.
|
|
97
|
-
dycw_utilities-0.166.
|
|
98
|
-
dycw_utilities-0.166.
|
|
94
|
+
dycw_utilities-0.166.27.dist-info/METADATA,sha256=zD73RDL_kiYeNBGjNY5R9krPiTk165csMHzG7DzD35I,1700
|
|
95
|
+
dycw_utilities-0.166.27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
96
|
+
dycw_utilities-0.166.27.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
|
|
97
|
+
dycw_utilities-0.166.27.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
|
98
|
+
dycw_utilities-0.166.27.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/asyncio.py
CHANGED
|
@@ -31,6 +31,7 @@ from typing import (
|
|
|
31
31
|
Self,
|
|
32
32
|
TextIO,
|
|
33
33
|
assert_never,
|
|
34
|
+
cast,
|
|
34
35
|
overload,
|
|
35
36
|
override,
|
|
36
37
|
)
|
|
@@ -38,6 +39,7 @@ from typing import (
|
|
|
38
39
|
from utilities.functions import ensure_int, ensure_not_none
|
|
39
40
|
from utilities.os import is_pytest
|
|
40
41
|
from utilities.random import SYSTEM_RANDOM
|
|
42
|
+
from utilities.reprlib import get_repr
|
|
41
43
|
from utilities.sentinel import Sentinel, sentinel
|
|
42
44
|
from utilities.shelve import yield_shelf
|
|
43
45
|
from utilities.text import to_bool
|
|
@@ -48,6 +50,7 @@ if TYPE_CHECKING:
|
|
|
48
50
|
from asyncio import _CoroutineLike
|
|
49
51
|
from asyncio.subprocess import Process
|
|
50
52
|
from collections.abc import (
|
|
53
|
+
AsyncIterable,
|
|
51
54
|
AsyncIterator,
|
|
52
55
|
Callable,
|
|
53
56
|
ItemsView,
|
|
@@ -346,6 +349,24 @@ class EnhancedTaskGroup(TaskGroup):
|
|
|
346
349
|
##
|
|
347
350
|
|
|
348
351
|
|
|
352
|
+
def chain_async[T](*iterables: Iterable[T] | AsyncIterable[T]) -> AsyncIterator[T]:
|
|
353
|
+
"""Asynchronous version of `chain`."""
|
|
354
|
+
|
|
355
|
+
async def iterator() -> AsyncIterator[T]:
|
|
356
|
+
for it in iterables:
|
|
357
|
+
try:
|
|
358
|
+
async for item in cast("AsyncIterable[T]", it):
|
|
359
|
+
yield item
|
|
360
|
+
except TypeError:
|
|
361
|
+
for item in cast("Iterable[T]", it):
|
|
362
|
+
yield item
|
|
363
|
+
|
|
364
|
+
return iterator()
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
##
|
|
368
|
+
|
|
369
|
+
|
|
349
370
|
def get_coroutine_name(func: Callable[[], Coro[Any]], /) -> str:
|
|
350
371
|
"""Get the name of a coroutine, and then dispose of it gracefully."""
|
|
351
372
|
coro = func()
|
|
@@ -394,6 +415,43 @@ def get_items_nowait[T](queue: Queue[T], /, *, max_size: int | None = None) -> l
|
|
|
394
415
|
##
|
|
395
416
|
|
|
396
417
|
|
|
418
|
+
async def one_async[T](*iterables: Iterable[T] | AsyncIterable[T]) -> T:
|
|
419
|
+
"""Asynchronous version of `one`."""
|
|
420
|
+
result: T | Sentinel = sentinel
|
|
421
|
+
async for item in chain_async(*iterables):
|
|
422
|
+
if not isinstance(result, Sentinel):
|
|
423
|
+
raise OneAsyncNonUniqueError(iterables=iterables, first=result, second=item)
|
|
424
|
+
result = item
|
|
425
|
+
if isinstance(result, Sentinel):
|
|
426
|
+
raise OneAsyncEmptyError(iterables=iterables)
|
|
427
|
+
return result
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
@dataclass(kw_only=True, slots=True)
|
|
431
|
+
class OneAsyncError[T](Exception):
|
|
432
|
+
iterables: tuple[Iterable[T] | AsyncIterable[T], ...]
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@dataclass(kw_only=True, slots=True)
|
|
436
|
+
class OneAsyncEmptyError[T](OneAsyncError[T]):
|
|
437
|
+
@override
|
|
438
|
+
def __str__(self) -> str:
|
|
439
|
+
return f"Iterable(s) {get_repr(self.iterables)} must not be empty"
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
@dataclass(kw_only=True, slots=True)
|
|
443
|
+
class OneAsyncNonUniqueError[T](OneAsyncError):
|
|
444
|
+
first: T
|
|
445
|
+
second: T
|
|
446
|
+
|
|
447
|
+
@override
|
|
448
|
+
def __str__(self) -> str:
|
|
449
|
+
return f"Iterable(s) {get_repr(self.iterables)} must contain exactly one item; got {self.first}, {self.second} and perhaps more"
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
##
|
|
453
|
+
|
|
454
|
+
|
|
397
455
|
async def put_items[T](items: Iterable[T], queue: Queue[T], /) -> None:
|
|
398
456
|
"""Put items into a queue; if full then wait."""
|
|
399
457
|
for item in items:
|
|
@@ -542,10 +600,15 @@ async def yield_locked_shelf(
|
|
|
542
600
|
__all__ = [
|
|
543
601
|
"AsyncDict",
|
|
544
602
|
"EnhancedTaskGroup",
|
|
603
|
+
"OneAsyncEmptyError",
|
|
604
|
+
"OneAsyncError",
|
|
605
|
+
"OneAsyncNonUniqueError",
|
|
545
606
|
"StreamCommandOutput",
|
|
607
|
+
"chain_async",
|
|
546
608
|
"get_coroutine_name",
|
|
547
609
|
"get_items",
|
|
548
610
|
"get_items_nowait",
|
|
611
|
+
"one_async",
|
|
549
612
|
"put_items",
|
|
550
613
|
"put_items_nowait",
|
|
551
614
|
"sleep_max",
|
utilities/iterables.py
CHANGED
|
@@ -933,7 +933,7 @@ class MergeStrMappingsError(Exception):
|
|
|
933
933
|
|
|
934
934
|
def one[T](*iterables: Iterable[T]) -> T:
|
|
935
935
|
"""Return the unique value in a set of iterables."""
|
|
936
|
-
it =
|
|
936
|
+
it = chain(*iterables)
|
|
937
937
|
try:
|
|
938
938
|
first = next(it)
|
|
939
939
|
except StopIteration:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|