8000 uasyncio.queues: Add simple implementation of asynchronous queues for… · micropython/micropython-lib@4dbb10e · GitHub
[go: up one dir, main page]

Skip to content

Commit 4dbb10e

Browse files
nvbnPaul Sokolovsky
authored and
Paul Sokolovsky
committed
uasyncio.queues: Add simple implementation of asynchronous queues for uasyncio
1 parent 1387950 commit 4dbb10e

File tree

4 files changed

+175
-0
lines changed

4 files changed

+175
-0
lines changed

uasyncio.queues/metadata.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
srctype = micropython-lib
2+
type = package
3+
version = 0.1
4+
long_desc = Port of asyncio.queues to uasyncio.
5+
depends = uasyncio.core, collections.deque

uasyncio.queues/setup.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import sys
2+
# Remove current dir from sys.path, otherwise setuptools will peek up our
3+
# module instead of system.
4+
sys.path.pop(0)
5+
from setuptools import setup
6+
7+
8+
setup(name='micropython-uasyncio.queues',
9+
version='0.1',
10+
description='uasyncio.queues module for MicroPython',
11+
long_description='Port of asyncio.queues to uasyncio.',
12+
url='https://github.com/micropython/micropython/issues/405',
13+
author='MicroPython Developers',
14+
author_email='micro-python@googlegroups.com',
15+
maintainer='MicroPython Developers',
16+
maintainer_email='micro-python@googlegroups.com',
17+
license='MIT',
18+
packages=['uasyncio'],
19+
install_requires=['micropython-uasyncio.core', 'micropython-collections.deque'])

uasyncio.queues/tests/test.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from unittest import TestCase, run_class
2+
import sys
3+
sys.path.insert(0, '../uasyncio')
4+
import queues
5+
6+
7+
class QueueTestCase(TestCase):
8+
9+
def _val(self, gen):
10+
"""Returns val from generator."""
11+
while True:
12+
try:
13+
gen.send(None)
14+
except StopIteration as e:
15+
return e.value
16+
17+
def test_get_put(self):
18+
q = queues.Queue(maxsize=1)
19+
self._val(q.put(42))
20+
self.assertEqual(self._val(q.get()), 42)
21+
22+
def test_get_put_nowait(self):
23+
q = queues.Queue(maxsize=1)
24+
q.put_nowait(12)
25+
try:
26+
q.put_nowait(42)
27+
self.assertTrue(False)
28+
except Exception as e:
29+
self.assertEqual(type(e), queues.QueueFull)
30+
self.assertEqual(q.get_nowait(), 12)
31+
try:
32+
q.get_nowait()
33+
self.assertTrue(False)
34+
except Exception as e:
35+
self.assertEqual(type(e), queues.QueueEmpty)
36+
37+
def test_qsize(self):
38+
q = queues.Queue()
39+
for n in range(10):
40+
q.put_nowait(10)
41+
self.assertEqual(q.qsize(), 10)
42+
43+
def test_empty(self):
44+
q = queues.Queue()
45+
self.assertTrue(q.empty())
46+
q.put_nowait(10)
47+
self.assertFalse(q.empty())
48+
49+
def test_full(self):
50+
q = queues.Queue(maxsize=1)
51+
self.assertFalse(q.full())
52+
q.put_nowait(10)
53+
self.assertTrue(q.full())
54+
55+
56+
if __name__ == '__main__':
57+
run_class(QueueTestCase)

uasyncio.queues/uasyncio/queues.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
from collections.deque import deque
2+
from uasyncio.core import sleep
3+
4+
5+
class QueueEmpty(Exception):
6+
"""Exception raised by get_nowait()."""
7+
8+
9+
class QueueFull(Exception):
10+
"""Exception raised by put_nowait()."""
11+
12+
13+
class Queue:
14+
"""A queue, useful for coordinating producer and consumer coroutines.
15+
16+
If maxsize is less than or equal to zero, the queue size is infinite. If it
17+
is an integer greater than 0, then "yield from put()" will block when the
18+
queue reaches maxsize, until an item is removed by get().
19+
20+
Unlike the standard library Queue, you can reliably know this Queue's size
21+
with qsize(), since your single-threaded uasyncio application won't be
22+
interrupted between calling qsize() and doing an operation on the Queue.
23+
"""
24+
_attempt_delay = 0.1
25+
26+
def __init__(self, maxsize=0):
27+
self.maxsize = maxsize
28+
self._queue = deque()
29+
30+
def _get(self):
31+
return self._queue.popleft()
32+
33+
def get(self):
34+
"""Returns generator, which can be used for getting (and removing)
35+
an item from a queue.
36+
37+
Usage::
38+
39+
item = yield from queue.get()
40+
"""
41+
while not self._queue:
42+
yield from sleep(self._attempt_delay)
43+
return self._get()
44+
45+
def get_nowait(self):
46+
"""Remove and return an item from the queue.
47+
48+
Return an item if one is immediately available, else raise QueueEmpty.
49+
"""
50+
if not self._queue:
51+
raise F438 QueueEmpty()
52+
return self._get()
53+
54+
def _put(self, val):
55+
self._queue.append(val)
56+
57+
def put(self, val):
58+
"""Returns generator which can be used for putting item in a queue.
59+
60+
Usage::
61+
62+
yield from queue.put(item)
63+
"""
64+
while self.qsize() > self.maxsize and self.maxsize:
65+
yield from sleep(self._attempt_delay)
66+
self._put(val)
67+
68+
def put_nowait(self, val):
69+
"""Put an item into the queue without blocking.
70+
71+
If no free slot is immediately available, raise QueueFull.
72+
"""
73+
if self.qsize() >= self.maxsize and self.maxsize:
74+
raise QueueFull()
75+
self._put(val)
76+
77+
def qsize(self):
78+
"""Number of items in the queue."""
79+
return len(self._queue)
80+
81+
def empty(self):
82+
"""Return True if the queue is empty, False otherwise."""
83+
return not self._queue
84+
85+
def full(self):
86+
"""Return True if there are maxsize items in the queue.
87+
88+
Note: if the Queue was initialized with maxsize=0 (the default),
89+
then full() is never True.
90+
"""
91+
if self.maxsize <= 0:
92+
return False
93+
else:
94+
return self.qsize() >= self.maxsize

0 commit comments

Comments
 (0)
0