asyncio-extensions 0.3.0__tar.gz → 0.3.2__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.
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/.github/workflows/release.yml +2 -2
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/.github/workflows/tests.yml +2 -2
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/.pre-commit-config.yaml +1 -1
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/CHANGELOG.md +24 -13
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/PKG-INFO +5 -4
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/README.md +3 -2
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/src/asyncio_extensions/_compat.py +1 -1
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/src/asyncio_extensions/_iterators.py +13 -6
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/src/asyncio_extensions/_task_groups.py +1 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/tests/test_iterators.py +19 -3
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/.github/dependabot.yml +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/.gitignore +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/AGENTS.md +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/CLAUDE.md +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/LICENSE.txt +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/codecov.yml +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/pyproject.toml +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/src/asyncio_extensions/__init__.py +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/src/asyncio_extensions/_scheduling.py +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/src/asyncio_extensions/_sync.py +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/src/asyncio_extensions/py.typed +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/tests/__init__.py +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/tests/test_scheduling.py +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/tests/test_sync.py +0 -0
- {asyncio_extensions-0.3.0 → asyncio_extensions-0.3.2}/tests/test_task_groups.py +0 -0
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
persist-credentials: false
|
|
19
19
|
|
|
20
20
|
- name: Set up Python
|
|
21
|
-
uses: actions/setup-python@
|
|
21
|
+
uses: actions/setup-python@v7
|
|
22
22
|
with:
|
|
23
23
|
python-version: "3.x"
|
|
24
24
|
|
|
@@ -54,4 +54,4 @@ jobs:
|
|
|
54
54
|
path: dist/
|
|
55
55
|
|
|
56
56
|
- name: Publish distribution 📦 to PyPI
|
|
57
|
-
uses: pypa/gh-action-pypi-publish@v1.14.
|
|
57
|
+
uses: pypa/gh-action-pypi-publish@v1.14.2
|
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
- uses: actions/checkout@v7
|
|
23
23
|
|
|
24
24
|
- name: Set up Python 3.13
|
|
25
|
-
uses: actions/setup-python@
|
|
25
|
+
uses: actions/setup-python@v7
|
|
26
26
|
with:
|
|
27
27
|
python-version: "3.13"
|
|
28
28
|
|
|
@@ -49,7 +49,7 @@ jobs:
|
|
|
49
49
|
- uses: actions/checkout@v7
|
|
50
50
|
|
|
51
51
|
- name: Set up Python ${{ matrix.python-version }}
|
|
52
|
-
uses: actions/setup-python@
|
|
52
|
+
uses: actions/setup-python@v7
|
|
53
53
|
with:
|
|
54
54
|
python-version: ${{ matrix.python-version }}
|
|
55
55
|
allow-prereleases: true
|
|
@@ -8,6 +8,20 @@ This project adheres to both [Semantic Versioning](https://semver.org/spec/v2.0.
|
|
|
8
8
|
|
|
9
9
|
## [UNRELEASED]
|
|
10
10
|
|
|
11
|
+
## [0.3.2] - 2026-09-24
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- `merge_iterables` no longer raises `ValueError` when called with no arguments.
|
|
16
|
+
|
|
17
|
+
## [0.3.1] - 2026-09-23
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- `drain` now returns the number of items consumed as an `int` instead of `None`.
|
|
22
|
+
|
|
23
|
+
## [0.3.0] - 2026-07-03
|
|
24
|
+
|
|
11
25
|
### Added
|
|
12
26
|
|
|
13
27
|
- `drain` coroutine to consume and discard remaining items from an async iterator or async iterable.
|
|
@@ -18,7 +32,7 @@ This project adheres to both [Semantic Versioning](https://semver.org/spec/v2.0.
|
|
|
18
32
|
- Type validation now includes Pyrefly checks for enhanced type safety.
|
|
19
33
|
- Enabled mypy strict mode to enforce stricter type checking standards.
|
|
20
34
|
- `STOP` is now a proper sentinel instance (via `typing_extensions.sentinel` on Python < 3.15) instead of a class used as a sentinel. Behaviour is unchanged; only the type changes.
|
|
21
|
-
- Use built-in TaskGroup on Python 3.15
|
|
35
|
+
- Use built-in `TaskGroup` on Python 3.15+.
|
|
22
36
|
|
|
23
37
|
## [0.2.0] - 2026-05-15
|
|
24
38
|
|
|
@@ -45,23 +59,16 @@ This project adheres to both [Semantic Versioning](https://semver.org/spec/v2.0.
|
|
|
45
59
|
|
|
46
60
|
### Added
|
|
47
61
|
|
|
48
|
-
- Expose `iscoroutinefunction` and `markcoroutinefunction` functions.
|
|
49
|
-
- `iterate_queue` async generator to consume an `asyncio.Queue` as an `async for` loop, stopping automatically when the queue is shut down.
|
|
50
|
-
- Expose `iscoroutinefunction` and `markcoroutinefunction` functions.
|
|
51
62
|
- `iterate_queue` async generator to consume an `asyncio.Queue` as an `async for` loop, stopping automatically when the queue is shut down or when the `STOP` sentinel is dequeued.
|
|
52
63
|
- `fill_queue` coroutine to fill an `asyncio.Queue` from any sync or async iterable.
|
|
53
64
|
- `merge_iterables` async context manager to merge multiple sync or async iterables into a single interleaved stream.
|
|
54
65
|
- `STOP` sentinel object used to signal the end of an `iterate_queue` stream.
|
|
66
|
+
- Expose `iscoroutinefunction` and `markcoroutinefunction` functions.
|
|
55
67
|
|
|
56
68
|
### Changed
|
|
57
69
|
|
|
58
70
|
- Rename `noop` to `identity` so the utility clearly expresses returning the passed value after yielding once to the event loop.
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
### Changed
|
|
62
|
-
|
|
63
|
-
- Renamed `noop` to `identity` so the utility clearly expresses returning the passed value after yielding once to the event loop.
|
|
64
|
-
|
|
65
72
|
## [0.0.4] - 2026-03-18
|
|
66
73
|
|
|
67
74
|
### Added
|
|
@@ -75,13 +82,13 @@ This project adheres to both [Semantic Versioning](https://semver.org/spec/v2.0.
|
|
|
75
82
|
- This CHANGELOG file.
|
|
76
83
|
- pre-commit config.
|
|
77
84
|
- test coverage using Codecov
|
|
78
|
-
- LimitedTaskGroup to execute tasks limiting concurrency
|
|
79
|
-
- heartbeat function to run something at regular interval
|
|
85
|
+
- `LimitedTaskGroup` to execute tasks limiting concurrency.
|
|
86
|
+
- `heartbeat` function to run something at regular interval.
|
|
80
87
|
|
|
81
88
|
### Changed
|
|
82
89
|
|
|
83
90
|
- Package building and publishing are run in separate jobs to avoid credential sharing.
|
|
84
|
-
- Improved README
|
|
91
|
+
- Improved README.
|
|
85
92
|
|
|
86
93
|
## [0.0.2] - 2025-12-23
|
|
87
94
|
|
|
@@ -97,7 +104,11 @@ This project adheres to both [Semantic Versioning](https://semver.org/spec/v2.0.
|
|
|
97
104
|
- `checkpoint` function to yield control to the event loop.
|
|
98
105
|
- `sleep_forever` function.
|
|
99
106
|
|
|
100
|
-
[unreleased]: https://github.com/hartungstenio/asyncio-extensions/compare/0.
|
|
107
|
+
[unreleased]: https://github.com/hartungstenio/asyncio-extensions/compare/0.3.2...HEAD
|
|
108
|
+
[0.3.2]: https://github.com/hartungstenio/asyncio-extensions/compare/0.3.1...0.3.2
|
|
109
|
+
[0.3.1]: https://github.com/hartungstenio/asyncio-extensions/compare/0.3.0...0.3.1
|
|
110
|
+
[0.3.0]: https://github.com/hartungstenio/asyncio-extensions/compare/0.2.0...0.3.0
|
|
111
|
+
[0.2.0]: https://github.com/hartungstenio/asyncio-extensions/compare/0.1.0...0.2.0
|
|
101
112
|
[0.1.0]: https://github.com/hartungstenio/asyncio-extensions/compare/0.0.5...0.1.0
|
|
102
113
|
[0.0.5]: https://github.com/hartungstenio/asyncio-extensions/compare/0.0.4...0.0.5
|
|
103
114
|
[0.0.4]: https://github.com/hartungstenio/asyncio-extensions/compare/0.0.3...0.0.4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: asyncio-extensions
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Some (maybe) useful extensions for asyncio
|
|
5
5
|
Project-URL: Changelog, https://github.com/hartungstenio/asyncio-extensions/blob/main/CHANGELOG.md
|
|
6
6
|
Project-URL: Documentation, https://github.com/hartungstenio/asyncio-extensions#readme
|
|
@@ -272,7 +272,7 @@ await fill_queue(source(), queue)
|
|
|
272
272
|
|
|
273
273
|
### drain
|
|
274
274
|
|
|
275
|
-
The `drain` coroutine consumes and discards the remaining items from an async iterator or async iterable. This is useful when you want to stop processing early but must ensure the source is exhausted so producers can finish and resources can be released.
|
|
275
|
+
The `drain` coroutine consumes and discards the remaining items from an async iterator or async iterable, returning the number of items consumed. This is useful when you want to stop processing early but must ensure the source is exhausted so producers can finish and resources can be released.
|
|
276
276
|
|
|
277
277
|
Example — process only the first N items, then discard the rest so the producer can complete:
|
|
278
278
|
|
|
@@ -287,7 +287,8 @@ async for idx, item in enumerate(iter_items()):
|
|
|
287
287
|
break
|
|
288
288
|
print(item)
|
|
289
289
|
# ensure the remaining items are consumed and the producer can finish
|
|
290
|
-
await drain(stream)
|
|
290
|
+
discarded = await drain(stream)
|
|
291
|
+
print(f"discarded {discarded} items")
|
|
291
292
|
```
|
|
292
293
|
### merge_iterables
|
|
293
294
|
|
|
@@ -242,7 +242,7 @@ await fill_queue(source(), queue)
|
|
|
242
242
|
|
|
243
243
|
### drain
|
|
244
244
|
|
|
245
|
-
The `drain` coroutine consumes and discards the remaining items from an async iterator or async iterable. This is useful when you want to stop processing early but must ensure the source is exhausted so producers can finish and resources can be released.
|
|
245
|
+
The `drain` coroutine consumes and discards the remaining items from an async iterator or async iterable, returning the number of items consumed. This is useful when you want to stop processing early but must ensure the source is exhausted so producers can finish and resources can be released.
|
|
246
246
|
|
|
247
247
|
Example — process only the first N items, then discard the rest so the producer can complete:
|
|
248
248
|
|
|
@@ -257,7 +257,8 @@ async for idx, item in enumerate(iter_items()):
|
|
|
257
257
|
break
|
|
258
258
|
print(item)
|
|
259
259
|
# ensure the remaining items are consumed and the producer can finish
|
|
260
|
-
await drain(stream)
|
|
260
|
+
discarded = await drain(stream)
|
|
261
|
+
print(f"discarded {discarded} items")
|
|
261
262
|
```
|
|
262
263
|
### merge_iterables
|
|
263
264
|
|
|
@@ -96,20 +96,26 @@ async def fill_queue(itr: AsyncIterable[T] | Iterable[T], queue: asyncio.Queue[T
|
|
|
96
96
|
await queue.put(it)
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
async def drain(itr: AsyncIterable[T] | Iterable[T]) ->
|
|
100
|
-
"""Consume the remaining items from *itr
|
|
99
|
+
async def drain(itr: AsyncIterable[T] | Iterable[T]) -> int:
|
|
100
|
+
"""Consume the remaining items from *itr* and return the count drained.
|
|
101
101
|
|
|
102
102
|
Accepts both sync and async iterables.
|
|
103
103
|
|
|
104
104
|
Args:
|
|
105
105
|
itr: The iterable (sync or async) to consume.
|
|
106
106
|
|
|
107
|
+
Returns:
|
|
108
|
+
The number of items consumed.
|
|
109
|
+
|
|
107
110
|
Example::
|
|
108
111
|
|
|
109
|
-
await drain(range(10))
|
|
112
|
+
count = await drain(range(10))
|
|
113
|
+
assert count == 10
|
|
110
114
|
"""
|
|
115
|
+
count = 0
|
|
111
116
|
async for _ in asyncify_iterable(itr):
|
|
112
|
-
|
|
117
|
+
count += 1
|
|
118
|
+
return count
|
|
113
119
|
|
|
114
120
|
|
|
115
121
|
@asynccontextmanager
|
|
@@ -144,8 +150,9 @@ async def merge_iterables(
|
|
|
144
150
|
tasks = [tg.create_task(fill_queue(itr, queue)) for itr in itrs]
|
|
145
151
|
|
|
146
152
|
async def join() -> None:
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
if tasks:
|
|
154
|
+
await asyncio.wait(tasks)
|
|
155
|
+
await queue.put(STOP) # type: ignore[arg-type]
|
|
149
156
|
|
|
150
157
|
tg.create_task(join())
|
|
151
158
|
|
|
@@ -141,10 +141,12 @@ async def test_fill_queue_full_queue_blocks_until_space_available() -> None:
|
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
async def test_drain_sync_iterator() -> None:
|
|
144
|
-
|
|
144
|
+
given = [1, 2, 3]
|
|
145
|
+
itr = iter(given)
|
|
145
146
|
|
|
146
|
-
await drain(itr)
|
|
147
|
+
count = await drain(itr)
|
|
147
148
|
|
|
149
|
+
assert count == len(given)
|
|
148
150
|
with pytest.raises(StopIteration):
|
|
149
151
|
next(itr)
|
|
150
152
|
|
|
@@ -156,12 +158,19 @@ async def test_drain_async_iterator() -> None:
|
|
|
156
158
|
|
|
157
159
|
itr = aiter(gen())
|
|
158
160
|
|
|
159
|
-
await drain(itr)
|
|
161
|
+
count = await drain(itr)
|
|
160
162
|
|
|
163
|
+
assert count == 3 # noqa: PLR2004
|
|
161
164
|
with pytest.raises(StopAsyncIteration):
|
|
162
165
|
await anext(itr)
|
|
163
166
|
|
|
164
167
|
|
|
168
|
+
async def test_drain_empty_iterator_returns_zero() -> None:
|
|
169
|
+
count = await drain(iter([]))
|
|
170
|
+
|
|
171
|
+
assert count == 0
|
|
172
|
+
|
|
173
|
+
|
|
165
174
|
# merge_iterables
|
|
166
175
|
|
|
167
176
|
|
|
@@ -197,6 +206,13 @@ async def test_merge_iterables_empty_sources_yields_nothing() -> None:
|
|
|
197
206
|
assert results == []
|
|
198
207
|
|
|
199
208
|
|
|
209
|
+
async def test_merge_iterables_no_sources_yields_nothing() -> None:
|
|
210
|
+
async with merge_iterables() as stream:
|
|
211
|
+
results = [item async for item in stream]
|
|
212
|
+
|
|
213
|
+
assert results == []
|
|
214
|
+
|
|
215
|
+
|
|
200
216
|
async def test_merge_iterables_early_exit_cancels_background_tasks() -> None:
|
|
201
217
|
initial_tasks = len(asyncio.all_tasks())
|
|
202
218
|
itrs = [count(), count(1)]
|
|
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
|