glow 0.15.7__tar.gz → 0.15.8__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.7 → glow-0.15.8}/PKG-INFO +15 -14
- {glow-0.15.7 → glow-0.15.8}/pyproject.toml +7 -6
- {glow-0.15.7 → glow-0.15.8}/src/glow/_parallel.py +22 -24
- {glow-0.15.7 → glow-0.15.8}/src/glow/_parallel.pyi +1 -1
- {glow-0.15.7 → glow-0.15.8}/src/glow/_thread_quota.py +16 -2
- {glow-0.15.7 → glow-0.15.8}/.gitignore +0 -0
- {glow-0.15.7 → glow-0.15.8}/LICENSE +0 -0
- {glow-0.15.7 → glow-0.15.8}/README.md +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/__init__.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_array.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_async.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_async.pyi +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_cache.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_cache.pyi +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_concurrency.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_concurrency.pyi +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_coro.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_debug.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_dev.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_futures.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_ic.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_import_hook.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_imutil.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_keys.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_logging.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_more.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_patch_len.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_patch_print.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_patch_scipy.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_profile.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_profile.pyi +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_reduction.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_repr.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_reusable.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_sizeof.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_streams.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_types.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_uuid.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/_wrap.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/api/__init__.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/api/config.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/api/exporting.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/cli.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/cli.pyi +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/io/__init__.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/io/_sound.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/io/_svg.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/src/glow/py.typed +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/__init__.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_api.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_batch.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_buffered.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_cli.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_iter.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_shm.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_thread_pool.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_timed.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/test/test_timer.py +0 -0
- {glow-0.15.7 → glow-0.15.8}/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.8
|
|
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>
|
|
@@ -33,7 +33,8 @@ Classifier: Operating System :: OS Independent
|
|
|
33
33
|
Classifier: Programming Language :: Python :: 3
|
|
34
34
|
Classifier: Programming Language :: Python :: 3.12
|
|
35
35
|
Classifier: Programming Language :: Python :: 3.13
|
|
36
|
-
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
37
|
+
Requires-Python: <3.15,>=3.12
|
|
37
38
|
Requires-Dist: loguru
|
|
38
39
|
Requires-Dist: loky~=3.1
|
|
39
40
|
Requires-Dist: lxml
|
|
@@ -52,7 +53,7 @@ Requires-Dist: pygments; extra == 'all'
|
|
|
52
53
|
Requires-Dist: sounddevice; extra == 'all'
|
|
53
54
|
Requires-Dist: soundfile; extra == 'all'
|
|
54
55
|
Provides-Extra: dev
|
|
55
|
-
Requires-Dist: black~=
|
|
56
|
+
Requires-Dist: black~=26.1; extra == 'dev'
|
|
56
57
|
Requires-Dist: flake8-alphabetize; extra == 'dev'
|
|
57
58
|
Requires-Dist: flake8-pie; extra == 'dev'
|
|
58
59
|
Requires-Dist: flake8-pyi; extra == 'dev'
|
|
@@ -60,34 +61,34 @@ Requires-Dist: flake8-pyproject; extra == 'dev'
|
|
|
60
61
|
Requires-Dist: flake8-simplify; extra == 'dev'
|
|
61
62
|
Requires-Dist: flake8~=7.0; extra == 'dev'
|
|
62
63
|
Requires-Dist: isort; extra == 'dev'
|
|
63
|
-
Requires-Dist: mypy~=1.
|
|
64
|
+
Requires-Dist: mypy~=1.19; extra == 'dev'
|
|
64
65
|
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
65
|
-
Requires-Dist: pytest~=
|
|
66
|
-
Requires-Dist: ruff~=0.
|
|
66
|
+
Requires-Dist: pytest~=9.0; extra == 'dev'
|
|
67
|
+
Requires-Dist: ruff~=0.15.0; extra == 'dev'
|
|
67
68
|
Provides-Extra: dev-core
|
|
68
|
-
Requires-Dist: black~=
|
|
69
|
+
Requires-Dist: black~=26.1; extra == 'dev-core'
|
|
69
70
|
Requires-Dist: flake8-pie; extra == 'dev-core'
|
|
70
71
|
Requires-Dist: flake8-pyi; extra == 'dev-core'
|
|
71
72
|
Requires-Dist: flake8-pyproject; extra == 'dev-core'
|
|
72
73
|
Requires-Dist: flake8-simplify; extra == 'dev-core'
|
|
73
74
|
Requires-Dist: flake8~=7.0; extra == 'dev-core'
|
|
74
75
|
Requires-Dist: isort; extra == 'dev-core'
|
|
75
|
-
Requires-Dist: mypy~=1.
|
|
76
|
+
Requires-Dist: mypy~=1.19; extra == 'dev-core'
|
|
76
77
|
Requires-Dist: pytest-asyncio; extra == 'dev-core'
|
|
77
|
-
Requires-Dist: pytest~=
|
|
78
|
-
Requires-Dist: ruff~=0.
|
|
78
|
+
Requires-Dist: pytest~=9.0; extra == 'dev-core'
|
|
79
|
+
Requires-Dist: ruff~=0.15.0; extra == 'dev-core'
|
|
79
80
|
Provides-Extra: dev-wemake
|
|
80
|
-
Requires-Dist: black~=
|
|
81
|
+
Requires-Dist: black~=26.1; extra == 'dev-wemake'
|
|
81
82
|
Requires-Dist: flake8-pie; extra == 'dev-wemake'
|
|
82
83
|
Requires-Dist: flake8-pyi; extra == 'dev-wemake'
|
|
83
84
|
Requires-Dist: flake8-pyproject; extra == 'dev-wemake'
|
|
84
85
|
Requires-Dist: flake8-simplify; extra == 'dev-wemake'
|
|
85
86
|
Requires-Dist: flake8~=7.0; extra == 'dev-wemake'
|
|
86
87
|
Requires-Dist: isort; extra == 'dev-wemake'
|
|
87
|
-
Requires-Dist: mypy~=1.
|
|
88
|
+
Requires-Dist: mypy~=1.19; extra == 'dev-wemake'
|
|
88
89
|
Requires-Dist: pytest-asyncio; extra == 'dev-wemake'
|
|
89
|
-
Requires-Dist: pytest~=
|
|
90
|
-
Requires-Dist: ruff~=0.
|
|
90
|
+
Requires-Dist: pytest~=9.0; extra == 'dev-wemake'
|
|
91
|
+
Requires-Dist: ruff~=0.15.0; extra == 'dev-wemake'
|
|
91
92
|
Requires-Dist: wemake-python-styleguide~=1.3.0; extra == 'dev-wemake'
|
|
92
93
|
Provides-Extra: ic
|
|
93
94
|
Requires-Dist: asttokens; extra == 'ic'
|
|
@@ -7,10 +7,10 @@ only-packages = true
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "glow"
|
|
10
|
-
version = "0.15.
|
|
10
|
+
version = "0.15.8"
|
|
11
11
|
description = "Functional Python tools"
|
|
12
12
|
readme = "README.md"
|
|
13
|
-
requires-python = ">=3.12"
|
|
13
|
+
requires-python = ">=3.12, <3.15"
|
|
14
14
|
license = {file = "LICENSE"}
|
|
15
15
|
keywords = []
|
|
16
16
|
authors = [
|
|
@@ -26,6 +26,7 @@ classifiers = [
|
|
|
26
26
|
"Programming Language :: Python :: 3",
|
|
27
27
|
"Programming Language :: Python :: 3.12",
|
|
28
28
|
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Programming Language :: Python :: 3.14",
|
|
29
30
|
]
|
|
30
31
|
dependencies = [
|
|
31
32
|
"loguru",
|
|
@@ -62,17 +63,17 @@ all = [
|
|
|
62
63
|
"matplotlib",
|
|
63
64
|
]
|
|
64
65
|
dev-core = [
|
|
65
|
-
"black~=
|
|
66
|
+
"black~=26.1",
|
|
66
67
|
"flake8~=7.0",
|
|
67
68
|
"flake8-pie",
|
|
68
69
|
"flake8-pyi",
|
|
69
70
|
"flake8-pyproject",
|
|
70
71
|
"flake8-simplify",
|
|
71
72
|
"isort",
|
|
72
|
-
"mypy~=1.
|
|
73
|
-
"pytest~=
|
|
73
|
+
"mypy~=1.19",
|
|
74
|
+
"pytest~=9.0",
|
|
74
75
|
"pytest-asyncio",
|
|
75
|
-
"ruff~=0.
|
|
76
|
+
"ruff~=0.15.0",
|
|
76
77
|
]
|
|
77
78
|
dev = [
|
|
78
79
|
"glow[dev-core]",
|
|
@@ -441,10 +441,10 @@ def _enqueue[T](
|
|
|
441
441
|
return sched_iter, q_get
|
|
442
442
|
|
|
443
443
|
|
|
444
|
-
def _prefetch(s: ExitStack, sched_iter: Iterator,
|
|
444
|
+
def _prefetch(s: ExitStack, sched_iter: Iterator, count: int | None) -> int:
|
|
445
445
|
try:
|
|
446
|
-
# Fetch up to `
|
|
447
|
-
qsize = ilen(islice(sched_iter,
|
|
446
|
+
# Fetch up to `count` tasks to pre-fill `q`
|
|
447
|
+
qsize = ilen(islice(sched_iter, count))
|
|
448
448
|
except BaseException:
|
|
449
449
|
# Unwind stack here on an error
|
|
450
450
|
s.close()
|
|
@@ -469,7 +469,7 @@ def starmap_n[T](
|
|
|
469
469
|
prefetch: int | None = 2,
|
|
470
470
|
mp: bool = False,
|
|
471
471
|
chunksize: int | None = None,
|
|
472
|
-
|
|
472
|
+
unordered: bool = False,
|
|
473
473
|
) -> Iterator[T]:
|
|
474
474
|
"""Equivalent to itertools.starmap(fn, iterable).
|
|
475
475
|
|
|
@@ -478,29 +478,27 @@ def starmap_n[T](
|
|
|
478
478
|
|
|
479
479
|
Options:
|
|
480
480
|
- workers - Count of workers, by default all hardware threads are occupied.
|
|
481
|
-
- prefetch -
|
|
481
|
+
- prefetch - Count of extra jobs to schedule over N workers.
|
|
482
|
+
Helps with CPU stalls in ordered mode.
|
|
483
|
+
Increase if job execution time is highly variable.
|
|
482
484
|
- mp - Whether use processes or threads.
|
|
483
485
|
- chunksize - The size of the chunks the iterable will be broken into
|
|
484
|
-
before being passed to a processes.
|
|
486
|
+
before being passed to a processes.
|
|
487
|
+
Estimated automatically.
|
|
485
488
|
Ignored when threads are used.
|
|
486
|
-
-
|
|
489
|
+
- unordered - Retrieve results in order of completion or in original order.
|
|
490
|
+
In this mode `prefetch` is meaningless, because when some job became done
|
|
491
|
+
it yielded immediately releasing buffer for new job to schedule.
|
|
492
|
+
So no CPU stalls.
|
|
487
493
|
|
|
488
494
|
Unlike multiprocessing.Pool or concurrent.futures.Executor this one:
|
|
489
495
|
- never deadlocks on any exception or Ctrl-C interruption.
|
|
490
|
-
- accepts infinite iterables due to lazy task creation
|
|
496
|
+
- accepts infinite iterables due to lazy task creation.
|
|
491
497
|
- has single interface for both threads and processes.
|
|
492
498
|
- TODO: serializes array-like data using out-of-band Pickle 5 buffers.
|
|
493
|
-
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
Notes:
|
|
497
|
-
- To reduce latency set order to False, order of results will be arbitrary.
|
|
498
|
-
- To increase CPU usage increase prefetch or set it to None.
|
|
499
|
-
- In terms of CPU usage there's no difference between
|
|
500
|
-
prefetch=None and order=False, so choose wisely.
|
|
501
|
-
- Setting order to False makes no use of prefetch more than 0.
|
|
502
|
-
|
|
503
|
-
TODO: replace `order=True` with `unordered=False`
|
|
499
|
+
- call immediately creates pool ready to yield results
|
|
500
|
+
(which could take some time cause of serialization for multiprocessing),
|
|
501
|
+
so first `__next__` runs on warmed up pool.
|
|
504
502
|
"""
|
|
505
503
|
if max_workers is None:
|
|
506
504
|
max_workers = max_cpu_count(_NUM_CPUS, mp=mp)
|
|
@@ -512,11 +510,11 @@ def starmap_n[T](
|
|
|
512
510
|
msg = 'With multiprocessing either chunksize or prefetch should be set'
|
|
513
511
|
raise ValueError(msg)
|
|
514
512
|
|
|
515
|
-
if
|
|
513
|
+
if unordered:
|
|
514
|
+
prefetch = max(max_workers, 1)
|
|
515
|
+
elif prefetch is not None:
|
|
516
516
|
prefetch = max(prefetch + max_workers, 1)
|
|
517
517
|
|
|
518
|
-
unordered = not order
|
|
519
|
-
|
|
520
518
|
it = iter(iterable)
|
|
521
519
|
s = ExitStack()
|
|
522
520
|
submit = s.enter_context(get_executor(max_workers, mp=mp)).submit
|
|
@@ -560,7 +558,7 @@ def map_n[T](
|
|
|
560
558
|
prefetch: int | None = 2,
|
|
561
559
|
mp: bool = False,
|
|
562
560
|
chunksize: int | None = None,
|
|
563
|
-
|
|
561
|
+
unordered: bool = False,
|
|
564
562
|
) -> Iterator[T]:
|
|
565
563
|
"""Return iterator equivalent to map(func, *iterables).
|
|
566
564
|
|
|
@@ -576,7 +574,7 @@ def map_n[T](
|
|
|
576
574
|
prefetch=prefetch,
|
|
577
575
|
mp=mp,
|
|
578
576
|
chunksize=chunksize,
|
|
579
|
-
|
|
577
|
+
unordered=unordered,
|
|
580
578
|
)
|
|
581
579
|
|
|
582
580
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
__all__ = ['ThreadQuota']
|
|
9
9
|
|
|
10
10
|
import os
|
|
11
|
+
import sys
|
|
11
12
|
from collections import deque
|
|
12
13
|
from collections.abc import Callable
|
|
13
14
|
from concurrent.futures import Executor, Future
|
|
@@ -18,6 +19,13 @@ from threading import _register_atexit # type: ignore[attr-defined]
|
|
|
18
19
|
from threading import Lock, Thread
|
|
19
20
|
from weakref import WeakSet
|
|
20
21
|
|
|
22
|
+
if sys.version_info >= (3, 14):
|
|
23
|
+
from concurrent.futures.thread import WorkerContext
|
|
24
|
+
|
|
25
|
+
_worker_ctx = WorkerContext(lambda: None, ())
|
|
26
|
+
else:
|
|
27
|
+
_worker_ctx = None
|
|
28
|
+
|
|
21
29
|
# TODO: investigate hangups when _TIMEOUT <= .01
|
|
22
30
|
_TIMEOUT = 1
|
|
23
31
|
_MIN_IDLE = os.cpu_count() or 1
|
|
@@ -64,7 +72,10 @@ def _worker(q: _Pipe) -> None:
|
|
|
64
72
|
try:
|
|
65
73
|
while executor := _safe_call(q.get, timeout=_TIMEOUT):
|
|
66
74
|
while work_item := _safe_call(executor._work_queue.popleft):
|
|
67
|
-
|
|
75
|
+
if sys.version_info >= (3, 14):
|
|
76
|
+
work_item.run(_worker_ctx) # Process task
|
|
77
|
+
else:
|
|
78
|
+
work_item.run()
|
|
68
79
|
if _shutdown:
|
|
69
80
|
executor._shutdown = True
|
|
70
81
|
return
|
|
@@ -114,7 +125,10 @@ class ThreadQuota(Executor):
|
|
|
114
125
|
msg = 'cannot schedule futures after shutdown'
|
|
115
126
|
raise RuntimeError(msg)
|
|
116
127
|
|
|
117
|
-
|
|
128
|
+
if sys.version_info >= (3, 14):
|
|
129
|
+
self._work_queue.append(_WorkItem(f, (fn, args, kwargs)))
|
|
130
|
+
else:
|
|
131
|
+
self._work_queue.append(_WorkItem(f, fn, args, kwargs))
|
|
118
132
|
|
|
119
133
|
if _safe_call(self._idle.pop): # Pool is not maximized yet
|
|
120
134
|
if q := _safe_call(_idle.pop): # Use idle worker
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|