glow 0.15.5__tar.gz → 0.15.7__tar.gz
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.
- {glow-0.15.5 → glow-0.15.7}/PKG-INFO +2 -1
- {glow-0.15.5 → glow-0.15.7}/pyproject.toml +2 -1
- {glow-0.15.5 → glow-0.15.7}/src/glow/__init__.py +4 -1
- {glow-0.15.5 → glow-0.15.7}/src/glow/_async.py +53 -20
- {glow-0.15.5 → glow-0.15.7}/src/glow/_async.pyi +8 -1
- {glow-0.15.5 → glow-0.15.7}/src/glow/_cache.py +8 -9
- {glow-0.15.5 → glow-0.15.7}/src/glow/_cache.pyi +2 -1
- {glow-0.15.5 → glow-0.15.7}/src/glow/_concurrency.py +7 -9
- {glow-0.15.5 → glow-0.15.7}/src/glow/_concurrency.pyi +5 -4
- {glow-0.15.5 → glow-0.15.7}/src/glow/_coro.py +1 -1
- {glow-0.15.5 → glow-0.15.7}/src/glow/_debug.py +13 -6
- {glow-0.15.5 → glow-0.15.7}/src/glow/_futures.py +22 -2
- {glow-0.15.5 → glow-0.15.7}/src/glow/_import_hook.py +4 -4
- {glow-0.15.5 → glow-0.15.7}/src/glow/_parallel.py +101 -68
- {glow-0.15.5 → glow-0.15.7}/src/glow/_profile.py +8 -8
- {glow-0.15.5 → glow-0.15.7}/src/glow/_profile.pyi +7 -7
- {glow-0.15.5 → glow-0.15.7}/src/glow/_reduction.py +2 -6
- {glow-0.15.5 → glow-0.15.7}/src/glow/_streams.py +4 -3
- glow-0.15.7/src/glow/_types.py +31 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_uuid.py +7 -1
- {glow-0.15.5 → glow-0.15.7}/src/glow/_wrap.py +3 -1
- {glow-0.15.5 → glow-0.15.7}/src/glow/cli.py +56 -25
- {glow-0.15.5 → glow-0.15.7}/src/glow/cli.pyi +9 -1
- {glow-0.15.5 → glow-0.15.7}/src/glow/io/_sound.py +20 -8
- {glow-0.15.5 → glow-0.15.7}/test/test_cli.py +28 -2
- glow-0.15.5/src/glow/_types.py +0 -53
- {glow-0.15.5 → glow-0.15.7}/.gitignore +0 -0
- {glow-0.15.5 → glow-0.15.7}/LICENSE +0 -0
- {glow-0.15.5 → glow-0.15.7}/README.md +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_array.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_dev.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_ic.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_imutil.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_keys.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_logging.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_more.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_parallel.pyi +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_patch_len.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_patch_print.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_patch_scipy.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_repr.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_reusable.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_sizeof.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/_thread_quota.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/api/__init__.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/api/config.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/api/exporting.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/io/__init__.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/io/_svg.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/src/glow/py.typed +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/__init__.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_api.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_batch.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_buffered.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_iter.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_shm.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_thread_pool.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_timed.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_timer.py +0 -0
- {glow-0.15.5 → glow-0.15.7}/test/test_uuid.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: glow
|
|
3
|
-
Version: 0.15.
|
|
3
|
+
Version: 0.15.7
|
|
4
4
|
Summary: Functional Python tools
|
|
5
5
|
Project-URL: homepage, https://github.com/arquolo/glow
|
|
6
6
|
Author-email: Paul Maevskikh <arquolo@gmail.com>
|
|
@@ -40,6 +40,7 @@ Requires-Dist: lxml
|
|
|
40
40
|
Requires-Dist: numpy<3,>=1.21
|
|
41
41
|
Requires-Dist: tqdm
|
|
42
42
|
Requires-Dist: typing-extensions~=4.1; python_version < '3.11'
|
|
43
|
+
Requires-Dist: typing-inspection~=0.4.1
|
|
43
44
|
Requires-Dist: wrapt~=1.15
|
|
44
45
|
Provides-Extra: all
|
|
45
46
|
Requires-Dist: asttokens; extra == 'all'
|
|
@@ -7,7 +7,7 @@ only-packages = true
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "glow"
|
|
10
|
-
version = "0.15.
|
|
10
|
+
version = "0.15.7"
|
|
11
11
|
description = "Functional Python tools"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.12"
|
|
@@ -33,6 +33,7 @@ dependencies = [
|
|
|
33
33
|
"lxml",
|
|
34
34
|
"numpy >=1.21, <3",
|
|
35
35
|
"typing-extensions~=4.1; python_version < '3.11'",
|
|
36
|
+
"typing-inspection~=0.4.1",
|
|
36
37
|
"tqdm",
|
|
37
38
|
"wrapt~=1.15",
|
|
38
39
|
]
|
|
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
|
|
|
6
6
|
|
|
7
7
|
from . import _patch_len, _patch_print, _patch_scipy
|
|
8
8
|
from ._array import aceil, afloor, apack, around, pascal
|
|
9
|
-
from ._async import amap, amap_dict, astarmap, astreaming, azip
|
|
9
|
+
from ._async import RwLock, amap, amap_dict, astarmap, astreaming, azip
|
|
10
10
|
from ._cache import cache_status, memoize
|
|
11
11
|
from ._concurrency import (
|
|
12
12
|
call_once,
|
|
@@ -17,6 +17,7 @@ from ._concurrency import (
|
|
|
17
17
|
)
|
|
18
18
|
from ._coro import as_actor, coroutine, summary
|
|
19
19
|
from ._debug import lock_seed, trace, trace_module, whereami
|
|
20
|
+
from ._dev import hide_frame
|
|
20
21
|
from ._import_hook import register_post_import_hook, when_imported
|
|
21
22
|
from ._logging import init_loguru
|
|
22
23
|
from ._more import (
|
|
@@ -69,6 +70,7 @@ else:
|
|
|
69
70
|
|
|
70
71
|
__all__ = [
|
|
71
72
|
'Reusable',
|
|
73
|
+
'RwLock',
|
|
72
74
|
'Uid',
|
|
73
75
|
'aceil',
|
|
74
76
|
'afloor',
|
|
@@ -91,6 +93,7 @@ __all__ = [
|
|
|
91
93
|
'eat',
|
|
92
94
|
'get_executor',
|
|
93
95
|
'groupby',
|
|
96
|
+
'hide_frame',
|
|
94
97
|
'ic',
|
|
95
98
|
'ic_repr',
|
|
96
99
|
'ichunked',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
__all__ = ['amap', 'amap_dict', 'astarmap', 'azip']
|
|
1
|
+
__all__ = ['RwLock', 'amap', 'amap_dict', 'astarmap', 'azip']
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
from asyncio import Queue, Task
|
|
4
|
+
from asyncio import Event, Future, Lock, Queue, Task, TaskGroup
|
|
5
5
|
from collections import deque
|
|
6
6
|
from collections.abc import (
|
|
7
7
|
AsyncIterator,
|
|
@@ -12,22 +12,13 @@ from collections.abc import (
|
|
|
12
12
|
Mapping,
|
|
13
13
|
Sequence,
|
|
14
14
|
)
|
|
15
|
-
from contextlib import suppress
|
|
15
|
+
from contextlib import asynccontextmanager, suppress
|
|
16
16
|
from functools import partial
|
|
17
17
|
from typing import TypeGuard, cast, overload
|
|
18
18
|
|
|
19
19
|
from ._dev import hide_frame
|
|
20
|
-
from ._futures import adispatch
|
|
21
|
-
from ._types import
|
|
22
|
-
ABatchDecorator,
|
|
23
|
-
ABatchFn,
|
|
24
|
-
AnyFuture,
|
|
25
|
-
AnyIterable,
|
|
26
|
-
AnyIterator,
|
|
27
|
-
Coro,
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
type _Job[T, R] = tuple[T, AnyFuture[R]]
|
|
20
|
+
from ._futures import ABatchDecorator, ABatchFn, Job, adispatch
|
|
21
|
+
from ._types import AnyIterable, AnyIterator, Coro
|
|
31
22
|
|
|
32
23
|
|
|
33
24
|
async def amap_dict[K, T1, T2](
|
|
@@ -93,7 +84,7 @@ async def astarmap[*Ts, R](
|
|
|
93
84
|
yield await func(*args)
|
|
94
85
|
return
|
|
95
86
|
|
|
96
|
-
async with
|
|
87
|
+
async with TaskGroup() as tg:
|
|
97
88
|
ts = (
|
|
98
89
|
(tg.create_task(func(*args)) for args in iterable)
|
|
99
90
|
if isinstance(iterable, Iterable)
|
|
@@ -263,10 +254,10 @@ def astreaming[T, R](
|
|
|
263
254
|
assert batch_size is None or batch_size >= 1
|
|
264
255
|
assert timeout > 0
|
|
265
256
|
|
|
266
|
-
buf: list[
|
|
257
|
+
buf: list[Job[T, R]] = []
|
|
267
258
|
deadline = float('-inf')
|
|
268
|
-
not_last =
|
|
269
|
-
lock =
|
|
259
|
+
not_last = Event()
|
|
260
|
+
lock = Lock()
|
|
270
261
|
ncalls = 0
|
|
271
262
|
|
|
272
263
|
async def wrapper(items: Sequence[T]) -> list[R]:
|
|
@@ -279,10 +270,10 @@ def astreaming[T, R](
|
|
|
279
270
|
not_last.set()
|
|
280
271
|
|
|
281
272
|
ncalls += 1
|
|
282
|
-
fs: list[
|
|
273
|
+
fs: list[Future[R]] = []
|
|
283
274
|
try:
|
|
284
275
|
for x in items:
|
|
285
|
-
f =
|
|
276
|
+
f = Future[R]()
|
|
286
277
|
fs.append(f)
|
|
287
278
|
buf.append((x, f))
|
|
288
279
|
|
|
@@ -314,3 +305,45 @@ def astreaming[T, R](
|
|
|
314
305
|
return await asyncio.gather(*fs)
|
|
315
306
|
|
|
316
307
|
return wrapper
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
# ----------------------------- read/write guard -----------------------------
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class RwLock:
|
|
314
|
+
"""Guard code from concurrent writes.
|
|
315
|
+
|
|
316
|
+
Reads are not limited.
|
|
317
|
+
When write is issued, new reads are delayed until write is finished.
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
def __init__(self) -> None:
|
|
321
|
+
self._num_reads = 0
|
|
322
|
+
self._readable = Event()
|
|
323
|
+
self._readable.set()
|
|
324
|
+
self._writable = Event()
|
|
325
|
+
self._writable.set()
|
|
326
|
+
|
|
327
|
+
@asynccontextmanager
|
|
328
|
+
async def read(self) -> AsyncIterator[None]:
|
|
329
|
+
await self._readable.wait()
|
|
330
|
+
self._writable.clear()
|
|
331
|
+
try:
|
|
332
|
+
yield
|
|
333
|
+
finally:
|
|
334
|
+
self._num_reads -= 1
|
|
335
|
+
if self._num_reads == 0:
|
|
336
|
+
self._writable.set()
|
|
337
|
+
|
|
338
|
+
@asynccontextmanager
|
|
339
|
+
async def write(self) -> AsyncIterator[None]:
|
|
340
|
+
self._readable.clear() # Stop new READs
|
|
341
|
+
try:
|
|
342
|
+
await self._writable.wait() # Wait for all READs or single WRITE
|
|
343
|
+
self._writable.clear() # Only single WRITE is allowed
|
|
344
|
+
try:
|
|
345
|
+
yield
|
|
346
|
+
finally:
|
|
347
|
+
self._writable.set()
|
|
348
|
+
finally:
|
|
349
|
+
self._readable.set()
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from collections.abc import AsyncIterator, Callable, Mapping
|
|
2
|
+
from contextlib import AbstractAsyncContextManager
|
|
2
3
|
from typing import Any, Required, TypedDict, Unpack, overload
|
|
3
4
|
|
|
4
|
-
from .
|
|
5
|
+
from ._futures import ABatchDecorator, ABatchFn
|
|
6
|
+
from ._types import AnyIterable, Coro
|
|
5
7
|
|
|
6
8
|
class _AmapKwargs(TypedDict, total=False):
|
|
7
9
|
limit: Required[int]
|
|
@@ -106,3 +108,8 @@ def astreaming[T, R](
|
|
|
106
108
|
batch_size: int | None = ...,
|
|
107
109
|
timeout: float = ...,
|
|
108
110
|
) -> ABatchFn[T, R]: ...
|
|
111
|
+
|
|
112
|
+
class RwLock:
|
|
113
|
+
def __init__(self) -> None: ...
|
|
114
|
+
def read(self) -> AbstractAsyncContextManager: ...
|
|
115
|
+
def write(self) -> AbstractAsyncContextManager: ...
|
|
@@ -21,20 +21,19 @@ from typing import Any, Final, Protocol, SupportsInt, cast
|
|
|
21
21
|
from weakref import WeakValueDictionary
|
|
22
22
|
|
|
23
23
|
from ._dev import clone_exc, hide_frame
|
|
24
|
-
from ._futures import
|
|
25
|
-
from ._keys import make_key
|
|
26
|
-
from ._repr import si_bin
|
|
27
|
-
from ._sizeof import sizeof
|
|
28
|
-
from ._types import (
|
|
24
|
+
from ._futures import (
|
|
29
25
|
ABatchFn,
|
|
30
26
|
AnyFuture,
|
|
31
27
|
BatchFn,
|
|
32
|
-
CachePolicy,
|
|
33
|
-
Decorator,
|
|
34
28
|
Job,
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
adispatch,
|
|
30
|
+
dispatch,
|
|
31
|
+
gather_fs,
|
|
37
32
|
)
|
|
33
|
+
from ._keys import make_key
|
|
34
|
+
from ._repr import si_bin
|
|
35
|
+
from ._sizeof import sizeof
|
|
36
|
+
from ._types import CachePolicy, Decorator, KeyFn, Some
|
|
38
37
|
|
|
39
38
|
|
|
40
39
|
class _Empty(enum.Enum):
|
|
@@ -19,15 +19,15 @@ from warnings import warn
|
|
|
19
19
|
|
|
20
20
|
from ._cache import memoize
|
|
21
21
|
from ._dev import hide_frame
|
|
22
|
-
from ._futures import dispatch, gather_fs
|
|
23
|
-
from ._types import
|
|
22
|
+
from ._futures import BatchDecorator, BatchFn, Job, dispatch, gather_fs
|
|
23
|
+
from ._types import Get
|
|
24
24
|
|
|
25
25
|
_PATIENCE = 0.01
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
def threadlocal[T](
|
|
29
|
-
fn: Callable[
|
|
30
|
-
) ->
|
|
28
|
+
def threadlocal[**P, T](
|
|
29
|
+
fn: Callable[P, T], /, *args: P.args, **kwargs: P.kwargs
|
|
30
|
+
) -> Get[T]:
|
|
31
31
|
"""Create thread-local singleton factory function (functools.partial)."""
|
|
32
32
|
local_ = threading.local()
|
|
33
33
|
|
|
@@ -41,7 +41,7 @@ def threadlocal[T](
|
|
|
41
41
|
return update_wrapper(wrapper, fn)
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def call_once[T](fn:
|
|
44
|
+
def call_once[T](fn: Get[T], /) -> Get[T]:
|
|
45
45
|
"""Make callable a singleton.
|
|
46
46
|
|
|
47
47
|
Supports async-def functions (but not async-gen functions).
|
|
@@ -81,8 +81,6 @@ def weak_memoize[**P, R](fn: Callable[P, R], /) -> Callable[P, R]:
|
|
|
81
81
|
|
|
82
82
|
# ----------------------------- batch collation ------------------------------
|
|
83
83
|
|
|
84
|
-
type _Job[T, R] = tuple[T, Future[R]]
|
|
85
|
-
|
|
86
84
|
|
|
87
85
|
def _fetch_batch[T](
|
|
88
86
|
q: SimpleQueue[T], batch_size: int | None, timeout: float
|
|
@@ -120,7 +118,7 @@ def _start_fetch_compute[T, R](
|
|
|
120
118
|
workers: int,
|
|
121
119
|
batch_size: int | None,
|
|
122
120
|
timeout: float,
|
|
123
|
-
) -> SimpleQueue[
|
|
121
|
+
) -> SimpleQueue[Job[T, R]]:
|
|
124
122
|
q = SimpleQueue() # type: ignore[var-annotated]
|
|
125
123
|
lock = Lock()
|
|
126
124
|
|
|
@@ -2,13 +2,14 @@ from collections.abc import Callable
|
|
|
2
2
|
from contextlib import AbstractContextManager
|
|
3
3
|
from typing import overload
|
|
4
4
|
|
|
5
|
-
from .
|
|
5
|
+
from ._futures import BatchDecorator, BatchFn
|
|
6
|
+
from ._types import Get
|
|
6
7
|
|
|
7
8
|
def threadlocal[T, **P](
|
|
8
|
-
fn: Callable[P, T], *args: P.args, **kwargs: P.kwargs
|
|
9
|
-
) ->
|
|
9
|
+
fn: Callable[P, T], /, *args: P.args, **kwargs: P.kwargs
|
|
10
|
+
) -> Get[T]: ...
|
|
10
11
|
def interpreter_lock(timeout: float = ...) -> AbstractContextManager[None]: ...
|
|
11
|
-
def call_once[T](fn:
|
|
12
|
+
def call_once[T](fn: Get[T], /) -> Get[T]: ...
|
|
12
13
|
def shared_call[**P, R](fn: Callable[P, R], /) -> Callable[P, R]: ...
|
|
13
14
|
def weak_memoize[**P, R](fn: Callable[P, R], /) -> Callable[P, R]: ...
|
|
14
15
|
@overload
|
|
@@ -29,7 +29,7 @@ class _Sync[Y, S, R](wrapt.ObjectProxy): # type: ignore[misc]
|
|
|
29
29
|
self._self_lock = Lock()
|
|
30
30
|
|
|
31
31
|
def _call[**P, T](
|
|
32
|
-
self, op: Callable[P, T], *args: P.args, **kwargs: P.kwargs
|
|
32
|
+
self, op: Callable[P, T], /, *args: P.args, **kwargs: P.kwargs
|
|
33
33
|
) -> T:
|
|
34
34
|
with self._self_lock:
|
|
35
35
|
return op(*args, **kwargs)
|
|
@@ -3,12 +3,11 @@ __all__ = ['lock_seed', 'trace', 'trace_module', 'whereami']
|
|
|
3
3
|
import gc
|
|
4
4
|
import os
|
|
5
5
|
import random
|
|
6
|
-
import
|
|
7
|
-
from collections.abc import Iterator
|
|
6
|
+
from collections.abc import Callable, Iterator
|
|
8
7
|
from contextlib import suppress
|
|
9
8
|
from inspect import currentframe, getmodule, isfunction
|
|
10
9
|
from itertools import islice
|
|
11
|
-
from types import FrameType
|
|
10
|
+
from types import FrameType, ModuleType
|
|
12
11
|
|
|
13
12
|
import numpy as np
|
|
14
13
|
import wrapt
|
|
@@ -74,12 +73,19 @@ def trace(fn, _, args, kwargs):
|
|
|
74
73
|
return fn(*args, **kwargs)
|
|
75
74
|
|
|
76
75
|
|
|
77
|
-
def _set_trace(
|
|
76
|
+
def _set_trace(
|
|
77
|
+
obj: ModuleType | Callable,
|
|
78
|
+
*,
|
|
79
|
+
seen: set[str] | None = None,
|
|
80
|
+
prefix: str | None = None,
|
|
81
|
+
module: ModuleType | None = None,
|
|
82
|
+
) -> None:
|
|
78
83
|
# TODO: rewrite using unittest.mock
|
|
79
|
-
if isinstance(obj,
|
|
84
|
+
if isinstance(obj, ModuleType):
|
|
80
85
|
if seen is None:
|
|
81
86
|
seen = set()
|
|
82
87
|
prefix = obj.__name__
|
|
88
|
+
assert isinstance(prefix, str)
|
|
83
89
|
if not obj.__name__.startswith(prefix) or obj.__name__ in seen:
|
|
84
90
|
return
|
|
85
91
|
seen.add(obj.__name__)
|
|
@@ -91,6 +97,7 @@ def _set_trace(obj, seen=None, prefix=None, module=None):
|
|
|
91
97
|
if not callable(obj):
|
|
92
98
|
return
|
|
93
99
|
|
|
100
|
+
assert isinstance(module, ModuleType)
|
|
94
101
|
if not hasattr(obj, '__dict__'):
|
|
95
102
|
setattr(module, obj.__qualname__, trace(obj))
|
|
96
103
|
print(f'wraps "{module.__name__}:{obj.__qualname__}"')
|
|
@@ -113,7 +120,7 @@ def _set_trace(obj, seen=None, prefix=None, module=None):
|
|
|
113
120
|
print(f'wraps "{module.__name__}:{obj.__qualname__}.{name}"')
|
|
114
121
|
|
|
115
122
|
|
|
116
|
-
def trace_module(name):
|
|
123
|
+
def trace_module(name: str) -> None:
|
|
117
124
|
"""Enable call logging for each callable inside module name."""
|
|
118
125
|
register_post_import_hook(_set_trace, name)
|
|
119
126
|
|
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import concurrent.futures as cf
|
|
3
|
-
from collections.abc import Hashable, Iterable, Sequence
|
|
3
|
+
from collections.abc import Callable, Hashable, Iterable, Sequence
|
|
4
|
+
from typing import Protocol, overload
|
|
4
5
|
|
|
5
6
|
from ._dev import hide_frame
|
|
6
|
-
from ._types import
|
|
7
|
+
from ._types import Coro, Some
|
|
8
|
+
|
|
9
|
+
type AnyFuture[R] = cf.Future[R] | asyncio.Future[R]
|
|
10
|
+
type Job[T, R] = tuple[T, AnyFuture[R]]
|
|
11
|
+
|
|
12
|
+
type BatchFn[T, R] = Callable[[Sequence[T]], Sequence[R]]
|
|
13
|
+
type ABatchFn[T, R] = Callable[[Sequence[T]], Coro[Sequence[R]]]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BatchDecorator(Protocol):
|
|
17
|
+
def __call__[T, R](self, fn: BatchFn[T, R], /) -> BatchFn[T, R]: ...
|
|
18
|
+
class ABatchDecorator(Protocol):
|
|
19
|
+
def __call__[T, R](self, fn: ABatchFn[T, R], /) -> ABatchFn[T, R]: ...
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AnyBatchDecorator(Protocol):
|
|
23
|
+
@overload
|
|
24
|
+
def __call__[T, R](self, fn: BatchFn[T, R], /) -> BatchFn[T, R]: ...
|
|
25
|
+
@overload
|
|
26
|
+
def __call__[T, R](self, fn: ABatchFn[T, R], /) -> ABatchFn[T, R]: ...
|
|
7
27
|
|
|
8
28
|
|
|
9
29
|
def dispatch[T, R](fn: BatchFn[T, R], *xs: Job[T, R]) -> None:
|
|
@@ -7,11 +7,11 @@ from importlib.machinery import ModuleSpec
|
|
|
7
7
|
from threading import RLock
|
|
8
8
|
from types import ModuleType
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
from ._types import Callback
|
|
11
11
|
|
|
12
12
|
_INITIALIZED = False
|
|
13
13
|
_LOCK = RLock()
|
|
14
|
-
_HOOKS: dict[str, list[
|
|
14
|
+
_HOOKS: dict[str, list[Callback[ModuleType]]] = {}
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class _ImportHookChainedLoader(abc.Loader):
|
|
@@ -71,7 +71,7 @@ class _ImportHookFinder(abc.MetaPathFinder, set[str]):
|
|
|
71
71
|
return None
|
|
72
72
|
|
|
73
73
|
|
|
74
|
-
def register_post_import_hook(hook:
|
|
74
|
+
def register_post_import_hook(hook: Callback[ModuleType], name: str) -> None:
|
|
75
75
|
"""Register a new post import hook for the target module name.
|
|
76
76
|
|
|
77
77
|
This will result in a proxy callback being registered which will defer
|
|
@@ -92,7 +92,7 @@ def register_post_import_hook(hook: _Hook, name: str) -> None:
|
|
|
92
92
|
hook(module)
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
def when_imported[H:
|
|
95
|
+
def when_imported[H: Callback[ModuleType]](name: str) -> Callable[[H], H]:
|
|
96
96
|
"""Create decorator making a function a post import hook for a module.
|
|
97
97
|
|
|
98
98
|
Simplified version of wrapt.when_imported.
|