queutils 0.10.0__tar.gz → 0.11.0__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.
- {queutils-0.10.0 → queutils-0.11.0}/PKG-INFO +6 -7
- {queutils-0.10.0 → queutils-0.11.0}/README.md +5 -6
- {queutils-0.10.0 → queutils-0.11.0}/demos/iterablequeue_demo.py +12 -9
- {queutils-0.10.0 → queutils-0.11.0}/docs/iterablequeue.md +4 -4
- {queutils-0.10.0 → queutils-0.11.0}/pypi.md +5 -6
- {queutils-0.10.0 → queutils-0.11.0}/pyproject.toml +1 -1
- {queutils-0.10.0 → queutils-0.11.0}/src/queutils/iterablequeue.py +14 -3
- {queutils-0.10.0 → queutils-0.11.0}/tests/test_iterablequeue.py +17 -2
- {queutils-0.10.0 → queutils-0.11.0}/.github/workflows/codeql.yml +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/.github/workflows/dependency-review.yml +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/.github/workflows/python-package.yml +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/.github/workflows/python-publish.yml +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/.gitignore +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/LICENSE +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/codecov.yml +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/demos/asyncqueue_demo.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/demos/filequeue_demo.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/docs/asyncqueue.md +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/docs/filequeue.md +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/docs/rm_links +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/src/queutils/__init__.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/src/queutils/asyncqueue.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/src/queutils/awrap.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/src/queutils/countable.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/src/queutils/eventcounterqueue.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/src/queutils/filequeue.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/src/queutils/py.typed +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/tests/test_asyncqueue.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/tests/test_awrap.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/tests/test_demos.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/tests/test_eventcounterqueue.py +0 -0
- {queutils-0.10.0 → queutils-0.11.0}/tests/test_filequeue.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: queutils
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: Handy Python Queue utilies
|
|
5
5
|
Project-URL: Homepage, https://github.com/Jylpah/queutils
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/Jylpah/queutils/issues
|
|
@@ -58,11 +58,10 @@ an `asyncio.Queue` compatible interface to a (non-async) managed `multiprocessin
|
|
|
58
58
|
`IterableQueue` is an `asyncio.Queue` subclass that is `AsyncIterable[T]` i.e. it can be
|
|
59
59
|
iterated in `async for` loop. `IterableQueue` terminates automatically when the queue has been filled and emptied.
|
|
60
60
|
|
|
61
|
-
The `IterableQueue` requires "producers" (functions adding items to the queue) to register themselves with `add_producer()` call
|
|
62
|
-
|
|
63
|
-
producers are "finished", the queue enters into "filled" state and no new items can be added. Once
|
|
64
|
-
|
|
65
|
-
`raise QueueDone` exception.
|
|
61
|
+
The `IterableQueue` requires "producers" (functions adding items to the queue) to register themselves with `add_producer()` call. It keeps count of registered producers. When a producer "finishes" adding items to the queue,
|
|
62
|
+
it needs to unregister itself with `finish_producer()` call. Once all the registered
|
|
63
|
+
producers are "finished", the queue enters into "filled" state and no new items can be added. Once a "filled" queue has been emptied, the queue becomes "done" and
|
|
64
|
+
all new `get()` calls to the queue will `raise QueueDone` exception.
|
|
66
65
|
|
|
67
66
|
## Features
|
|
68
67
|
|
|
@@ -70,7 +69,7 @@ producers are "finished", the queue enters into "filled" state and no new items
|
|
|
70
69
|
- `AsyncIterable` support: `async for item in queue:`
|
|
71
70
|
- Automatic termination of the consumers with `QueueDone` exception when the queue has been emptied
|
|
72
71
|
- Producers must be registered with `add_producer()` and they must notify the queue
|
|
73
|
-
with `
|
|
72
|
+
with `finish_producer()` once they have finished adding items
|
|
74
73
|
- Countable interface to count number of items task_done() through `count` property
|
|
75
74
|
|
|
76
75
|
# EventCounterQueue
|
|
@@ -27,11 +27,10 @@ an `asyncio.Queue` compatible interface to a (non-async) managed `multiprocessin
|
|
|
27
27
|
[`IterableQueue`](docs/iterablequeue.md) is an `asyncio.Queue` subclass that is `AsyncIterable[T]` i.e. it can be
|
|
28
28
|
iterated in `async for` loop. `IterableQueue` terminates automatically when the queue has been filled and emptied.
|
|
29
29
|
|
|
30
|
-
The `IterableQueue` requires "producers" (functions adding items to the queue) to register themselves with `add_producer()` call
|
|
31
|
-
|
|
32
|
-
producers are "finished", the queue enters into "filled" state and no new items can be added. Once
|
|
33
|
-
|
|
34
|
-
`raise QueueDone` exception.
|
|
30
|
+
The `IterableQueue` requires "producers" (functions adding items to the queue) to register themselves with `add_producer()` call. It keeps count of registered producers. When a producer "finishes" adding items to the queue,
|
|
31
|
+
it needs to unregister itself with `finish_producer()` call. Once all the registered
|
|
32
|
+
producers are "finished", the queue enters into "filled" state and no new items can be added. Once a "filled" queue has been emptied, the queue becomes "done" and
|
|
33
|
+
all new `get()` calls to the queue will `raise QueueDone` exception.
|
|
35
34
|
|
|
36
35
|
## Features
|
|
37
36
|
|
|
@@ -39,7 +38,7 @@ producers are "finished", the queue enters into "filled" state and no new items
|
|
|
39
38
|
- `AsyncIterable` support: `async for item in queue:`
|
|
40
39
|
- Automatic termination of the consumers with `QueueDone` exception when the queue has been emptied
|
|
41
40
|
- Producers must be registered with `add_producer()` and they must notify the queue
|
|
42
|
-
with `
|
|
41
|
+
with `finish_producer()` once they have finished adding items
|
|
43
42
|
- Countable interface to count number of items task_done() through `count` property
|
|
44
43
|
|
|
45
44
|
# EventCounterQueue
|
|
@@ -3,14 +3,14 @@ from random import random
|
|
|
3
3
|
from queutils import IterableQueue, QueueDone
|
|
4
4
|
from time import time
|
|
5
5
|
|
|
6
|
-
start
|
|
6
|
+
start: float = time()
|
|
7
|
+
|
|
7
8
|
|
|
8
9
|
def since() -> float:
|
|
9
10
|
return time() - start
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
) -> None:
|
|
12
|
+
|
|
13
|
+
async def producer(Q: IterableQueue[int], N: int, id: int) -> None:
|
|
14
14
|
"""
|
|
15
15
|
Fill the queue with N items
|
|
16
16
|
"""
|
|
@@ -21,11 +21,12 @@ async def producer(
|
|
|
21
21
|
print(f"{since():.2f} producer {id}: awaiting to put {i} to queue")
|
|
22
22
|
await Q.put(i)
|
|
23
23
|
print(f"{since():.2f} producer {id}: put {i} to queue")
|
|
24
|
-
await Q.
|
|
24
|
+
await Q.finish_producer()
|
|
25
25
|
except QueueDone:
|
|
26
26
|
print(f"ERROR: producer {id}, this should not happen")
|
|
27
27
|
return None
|
|
28
28
|
|
|
29
|
+
|
|
29
30
|
async def consumer(Q: IterableQueue[int], id: int = 1):
|
|
30
31
|
"""
|
|
31
32
|
Consume the queue
|
|
@@ -35,19 +36,21 @@ async def consumer(Q: IterableQueue[int], id: int = 1):
|
|
|
35
36
|
await sleep(0.5 * random())
|
|
36
37
|
print(f"{since():.2f} consumer {id}: queue is done")
|
|
37
38
|
|
|
39
|
+
|
|
38
40
|
async def main() -> None:
|
|
39
41
|
"""
|
|
40
|
-
Create a queue with maxsize and have multiple producers to fill it and
|
|
42
|
+
Create a queue with maxsize and have multiple producers to fill it and
|
|
41
43
|
multiple consumers to consume it over async for loop
|
|
42
44
|
"""
|
|
43
|
-
queue
|
|
45
|
+
queue: IterableQueue[int] = IterableQueue(maxsize=5)
|
|
44
46
|
|
|
45
47
|
async with TaskGroup() as tg:
|
|
46
|
-
for i in range(1,3):
|
|
48
|
+
for i in range(1, 3):
|
|
47
49
|
tg.create_task(producer(Q=queue, N=5, id=i))
|
|
48
50
|
await sleep(2)
|
|
49
|
-
for
|
|
51
|
+
for i in range(1, 4):
|
|
50
52
|
tg.create_task(consumer(Q=queue, id=i))
|
|
51
53
|
|
|
54
|
+
|
|
52
55
|
if __name__ == "__main__":
|
|
53
56
|
run(main())
|
|
@@ -9,7 +9,7 @@ iterated in `async for` loop. The great benefit of `IterableQueue` is that it te
|
|
|
9
9
|
- `AsyncIterable` support: `async for item in queue:`
|
|
10
10
|
- Automatic termination of the consumers with `QueueDone` exception when the queue has been emptied
|
|
11
11
|
- Producers must be registered with `add_producer()` and they must notify the queue
|
|
12
|
-
with `
|
|
12
|
+
with `finish_producer()` once they have finished adding items
|
|
13
13
|
- Countable interface to count number of items task_done() through `count` property
|
|
14
14
|
|
|
15
15
|
### Experimental
|
|
@@ -21,7 +21,7 @@ iterated in `async for` loop. The great benefit of `IterableQueue` is that it te
|
|
|
21
21
|
|
|
22
22
|
### Producers fill a queue
|
|
23
23
|
|
|
24
|
-
A *Producer* is "process" that adds items to the queue. A producer needs to be registered to the queue with `add_producer()` coroutine. Once a producer has added all the items it intends to, it notifies the queue with `
|
|
24
|
+
A *Producer* is "process" that adds items to the queue. A producer needs to be registered to the queue with `add_producer()` coroutine. Once a producer has added all the items it intends to, it notifies the queue with `finish_producer()`
|
|
25
25
|
|
|
26
26
|
```python
|
|
27
27
|
from queutils.iterablequeue import IterableQueue
|
|
@@ -37,7 +37,7 @@ async def producer(
|
|
|
37
37
|
await Q.put(i)
|
|
38
38
|
|
|
39
39
|
# notify the queue that this producer does not add more
|
|
40
|
-
await Q.
|
|
40
|
+
await Q.finish_producer()
|
|
41
41
|
|
|
42
42
|
return None
|
|
43
43
|
```
|
|
@@ -88,7 +88,7 @@ async def producer(
|
|
|
88
88
|
print(f"{since():.2f} producer {id}: awaiting to put {i} to queue")
|
|
89
89
|
await Q.put(i)
|
|
90
90
|
print(f"{since():.2f} producer {id}: put {i} to queue")
|
|
91
|
-
await Q.
|
|
91
|
+
await Q.finish_producer()
|
|
92
92
|
except QueueDone:
|
|
93
93
|
print(f"ERROR: producer {id}, this should not happen")
|
|
94
94
|
return None
|
|
@@ -27,11 +27,10 @@ an `asyncio.Queue` compatible interface to a (non-async) managed `multiprocessin
|
|
|
27
27
|
`IterableQueue` is an `asyncio.Queue` subclass that is `AsyncIterable[T]` i.e. it can be
|
|
28
28
|
iterated in `async for` loop. `IterableQueue` terminates automatically when the queue has been filled and emptied.
|
|
29
29
|
|
|
30
|
-
The `IterableQueue` requires "producers" (functions adding items to the queue) to register themselves with `add_producer()` call
|
|
31
|
-
|
|
32
|
-
producers are "finished", the queue enters into "filled" state and no new items can be added. Once
|
|
33
|
-
|
|
34
|
-
`raise QueueDone` exception.
|
|
30
|
+
The `IterableQueue` requires "producers" (functions adding items to the queue) to register themselves with `add_producer()` call. It keeps count of registered producers. When a producer "finishes" adding items to the queue,
|
|
31
|
+
it needs to unregister itself with `finish_producer()` call. Once all the registered
|
|
32
|
+
producers are "finished", the queue enters into "filled" state and no new items can be added. Once a "filled" queue has been emptied, the queue becomes "done" and
|
|
33
|
+
all new `get()` calls to the queue will `raise QueueDone` exception.
|
|
35
34
|
|
|
36
35
|
## Features
|
|
37
36
|
|
|
@@ -39,7 +38,7 @@ producers are "finished", the queue enters into "filled" state and no new items
|
|
|
39
38
|
- `AsyncIterable` support: `async for item in queue:`
|
|
40
39
|
- Automatic termination of the consumers with `QueueDone` exception when the queue has been emptied
|
|
41
40
|
- Producers must be registered with `add_producer()` and they must notify the queue
|
|
42
|
-
with `
|
|
41
|
+
with `finish_producer()` once they have finished adding items
|
|
43
42
|
- Countable interface to count number of items task_done() through `count` property
|
|
44
43
|
|
|
45
44
|
# EventCounterQueue
|
|
@@ -50,7 +50,7 @@ class IterableQueue(Queue[T], AsyncIterable[T], Countable):
|
|
|
50
50
|
- AsyncIterable(): async for item in queue:
|
|
51
51
|
- Automatic termination of the consumers when the queue has been emptied with QueueDone exception
|
|
52
52
|
- Producers must be registered with add_producer() and they must notify the queue
|
|
53
|
-
with
|
|
53
|
+
with finish_producer() once they have finished adding items
|
|
54
54
|
- Countable interface to count number of items task_done() through 'count' property
|
|
55
55
|
|
|
56
56
|
IterableQueue stages:
|
|
@@ -82,6 +82,17 @@ class IterableQueue(Queue[T], AsyncIterable[T], Countable):
|
|
|
82
82
|
|
|
83
83
|
self._empty.clear() # this will be tested only after queue is filled
|
|
84
84
|
|
|
85
|
+
@classmethod
|
|
86
|
+
def from_queue(cls, Q: Queue[Optional[T]]) -> "IterableQueue[T]":
|
|
87
|
+
"""
|
|
88
|
+
Create IterableQueue from existing asyncio.Queue
|
|
89
|
+
"""
|
|
90
|
+
if not isinstance(Q, Queue):
|
|
91
|
+
raise TypeError("Q must be an instance of asyncio.Queue")
|
|
92
|
+
iq: IterableQueue[T] = cls(maxsize=Q.maxsize)
|
|
93
|
+
iq._Q = Q
|
|
94
|
+
return iq
|
|
95
|
+
|
|
85
96
|
@property
|
|
86
97
|
def is_filled(self) -> bool:
|
|
87
98
|
""" "
|
|
@@ -166,7 +177,7 @@ class IterableQueue(Queue[T], AsyncIterable[T], Countable):
|
|
|
166
177
|
"""
|
|
167
178
|
Producer has finished adding items to the queue.
|
|
168
179
|
Once the last producers has finished, the queue is_filled.
|
|
169
|
-
- all:
|
|
180
|
+
- all: finish_producer() queue for all producers at once
|
|
170
181
|
|
|
171
182
|
Return True if the last producer is 'finished'
|
|
172
183
|
"""
|
|
@@ -177,7 +188,7 @@ class IterableQueue(Queue[T], AsyncIterable[T], Countable):
|
|
|
177
188
|
self._producers -= 1
|
|
178
189
|
|
|
179
190
|
if self._producers < 0:
|
|
180
|
-
raise ValueError("Too many
|
|
191
|
+
raise ValueError("Too many finish_producer() calls")
|
|
181
192
|
elif all or self._producers == 0:
|
|
182
193
|
self._filled.set()
|
|
183
194
|
self._producers = 0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import pytest # type: ignore
|
|
2
|
-
from asyncio.queues import QueueEmpty, QueueFull
|
|
2
|
+
from asyncio.queues import QueueEmpty, QueueFull, Queue
|
|
3
3
|
from asyncio import (
|
|
4
4
|
Task,
|
|
5
5
|
create_task,
|
|
@@ -9,6 +9,7 @@ from asyncio import (
|
|
|
9
9
|
TimeoutError,
|
|
10
10
|
CancelledError,
|
|
11
11
|
)
|
|
12
|
+
from typing import Optional
|
|
12
13
|
from random import random
|
|
13
14
|
|
|
14
15
|
from queutils import IterableQueue, QueueDone
|
|
@@ -232,7 +233,7 @@ async def test_6_finish_full_queue(test_interablequeue_int: IterableQueue[int]):
|
|
|
232
233
|
)
|
|
233
234
|
assert Q.is_done, "Queue is not done"
|
|
234
235
|
except TimeoutError:
|
|
235
|
-
assert False, f"await IterableQueue.
|
|
236
|
+
assert False, f"await IterableQueue.finish_producer() failed. qsize={Q.qsize()}"
|
|
236
237
|
await sleep(0.1)
|
|
237
238
|
assert Q.is_done, "Queue is not done"
|
|
238
239
|
producer.cancel()
|
|
@@ -281,3 +282,17 @@ async def test_8_aiter_1_item(test_interablequeue_int: IterableQueue[int]):
|
|
|
281
282
|
)
|
|
282
283
|
except TimeoutError:
|
|
283
284
|
assert False, "await IterableQueue.join() failed with an empty queue finished"
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
@pytest.mark.asyncio
|
|
288
|
+
async def test_9_from_queue():
|
|
289
|
+
"""Test from_queue class method"""
|
|
290
|
+
Q = Queue[Optional[int]](maxsize=QSIZE)
|
|
291
|
+
iq = IterableQueue.from_queue(Q)
|
|
292
|
+
assert iq.maxsize == Q.maxsize, "maxsize does not match"
|
|
293
|
+
assert iq.qsize() == Q.qsize(), "qsize does not match"
|
|
294
|
+
assert iq.empty() == Q.empty(), "empty() does not match"
|
|
295
|
+
assert iq.full() == Q.full(), "full() does not match"
|
|
296
|
+
|
|
297
|
+
with pytest.raises(TypeError):
|
|
298
|
+
IterableQueue.from_queue("not a queue")
|
|
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
|