cpython-uasyncio: uasyncio compatibility module for CPython.

Implements scheduling a coroutine by yielding it.

Related discussion:
https://groups.google.com/d/msg/python-tulip/emU4_qyPVQM/eS8G0bnmBIEJ
pull/20/merge
Paul Sokolovsky 2015-01-02 21:17:11 +02:00
rodzic d4968384ad
commit 083ad0e94c
5 zmienionych plików z 149 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,21 @@
import uasyncio as asyncio
def run1():
for i in range(1):
print('Hello World')
yield from asyncio.sleep(2)
print("run1 finished")
def run2():
for i in range(3):
print('bar')
yield run1()
yield from asyncio.sleep(1)
import logging
logging.basicConfig(level=logging.INFO)
loop = asyncio.get_event_loop()
loop.create_task(run2())
loop.run_forever()

Wyświetl plik

@ -0,0 +1,3 @@
srctype = cpython-backport
type = module
version = 0.1

Wyświetl plik

@ -0,0 +1,27 @@
This patch shows changes done to asyncio.tasks.Task._step() from CPython 3.4.2.
--- tasks.py 2015-01-01 10:51:40.707114866 +0200
+++ uasyncio.py 2015-01-01 10:54:20.172402890 +0200
@@ -46,13 +55,16 @@
# Bare yield relinquishes control for one event loop iteration.
self._loop.call_soon(self._step)
elif inspect.isgenerator(result):
+ #print("Scheduling", result)
+ self._loop.create_task(result)
+ self._loop.call_soon(self._step)
# Yielding a generator is just wrong.
- self._loop.call_soon(
- self._step, None,
- RuntimeError(
- 'yield was used instead of yield from for '
- 'generator in task {!r} with {}'.format(
- self, result)))
+# self._loop.call_soon(
+# self._step, None,
+# RuntimeError(
+# 'yield was used instead of yield from for '
+# 'generator in task {!r} with {}'.format(
+# self, result)))
else:
# Yielding something else is an error.
self._loop.call_soon(

Wyświetl plik

@ -0,0 +1,18 @@
import sys
# Remove current dir from sys.path, otherwise setuptools will peek up our
# module instead of system.
sys.path.pop(0)
from setuptools import setup
setup(name='micropython-cpython-uasyncio',
version='0.1',
description='MicroPython module uasyncio ported to CPython',
long_description='This is MicroPython compatibility module, allowing applications using\nMicroPython-specific features to run on CPython.\n',
url='https://github.com/micropython/micropython/issues/405',
author='MicroPython Developers',
author_email='micro-python@googlegroups.com',
maintainer='MicroPython Developers',
maintainer_email='micro-python@googlegroups.com',
license='Python',
py_modules=['uasyncio'])

Wyświetl plik

@ -0,0 +1,80 @@
import inspect
import asyncio
import asyncio.futures as futures
from asyncio import *
OrgTask = Task
class Task(OrgTask):
def _step(self, value=None, exc=None):
assert not self.done(), \
'_step(): already done: {!r}, {!r}, {!r}'.format(self, value, exc)
if self._must_cancel:
if not isinstance(exc, futures.CancelledError):
exc = futures.CancelledError()
self._must_cancel = False
coro = self._coro
self._fut_waiter = None
self.__class__._current_tasks[self._loop] = self
# Call either coro.throw(exc) or coro.send(value).
try:
if exc is not None:
result = coro.throw(exc)
elif value is not None:
result = coro.send(value)
else:
result = next(coro)
except StopIteration as exc:
self.set_result(exc.value)
except futures.CancelledError as exc:
super().cancel() # I.e., Future.cancel(self).
except Exception as exc:
self.set_exception(exc)
except BaseException as exc:
self.set_exception(exc)
raise
else:
if isinstance(result, futures.Future):
# Yielded Future must come from Future.__iter__().
if result._blocking:
result._blocking = False
result.add_done_callback(self._wakeup)
self._fut_waiter = result
if self._must_cancel:
if self._fut_waiter.cancel():
self._must_cancel = False
else:
self._loop.call_soon(
self._step, None,
RuntimeError(
'yield was used instead of yield from '
'in task {!r} with {!r}'.format(self, result)))
elif result is None:
# Bare yield relinquishes control for one event loop iteration.
self._loop.call_soon(self._step)
elif inspect.isgenerator(result):
#print("Scheduling", result)
self._loop.create_task(result)
self._loop.call_soon(self._step)
# Yielding a generator is just wrong.
# self._loop.call_soon(
# self._step, None,
# RuntimeError(
# 'yield was used instead of yield from for '
# 'generator in task {!r} with {}'.format(
# self, result)))
else:
# Yielding something else is an error.
self._loop.call_soon(
self._step, None,
RuntimeError(
'Task got bad yield: {!r}'.format(result)))
finally:
self.__class__._current_tasks.pop(self._loop)
self = None # Needed to break cycles when an exception occurs.
asyncio.tasks.Task = Task