Skip to content

Commit b544f2f

Browse files
committed
changes from MicroPython v1.22-release; CIRCUITPY-CHANGES annotations
1 parent 2032ac1 commit b544f2f

File tree

9 files changed

+228
-100
lines changed

9 files changed

+228
-100
lines changed

asyncio/__init__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
# SPDX-FileCopyrightText: 2019 Damien P. George
1+
# CIRCUITPY-CHANGE: SPDX
2+
# SPDX-FileCopyrightText: 2019-2020 Damien P. George
23
#
34
# SPDX-License-Identifier: MIT
4-
#
5-
# MicroPython uasyncio module
5+
6+
# MicroPython asyncio module
67
# MIT license; Copyright (c) 2019 Damien P. George
78
#
9+
# CIRCUITPY-CHANGE
810
# This code comes from MicroPython, and has not been run through black or pylint there.
911
# Altering these files significantly would make merging difficult, so we will not use
1012
# pylint or black.
@@ -13,6 +15,7 @@
1315

1416
from .core import *
1517

18+
# CIRCUITPY-CHANGE: use CircuitPython version
1619
__version__ = "0.0.0+auto.0"
1720
__repo__ = "https://github.com/Adafruit/Adafruit_CircuitPython_asyncio.git"
1821

@@ -29,6 +32,7 @@
2932
"StreamWriter": "stream",
3033
}
3134

35+
3236
# Lazy loader, effectively does:
3337
# global attr
3438
# from .mod import attr

asyncio/core.py

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
# SPDX-FileCopyrightText: 2019 Damien P. George
1+
# CIRCUITPY-CHANGE: SPDX
2+
# SPDX-FileCopyrightText: 2019-2020 Damien P. George
23
#
34
# SPDX-License-Identifier: MIT
4-
#
5-
# MicroPython uasyncio module
5+
6+
# MicroPython asyncio module
67
# MIT license; Copyright (c) 2019 Damien P. George
78
#
9+
# # CIRCUITPY-CHANGE: use CircuitPython version
810
# This code comes from MicroPython, and has not been run through black or pylint there.
911
# Altering these files significantly would make merging difficult, so we will not use
1012
# pylint or black.
1113
# pylint: skip-file
1214
# fmt: off
13-
"""
14-
Core
15-
====
16-
"""
1715

16+
# CIRCUITPY-CHANGE: use our ticks library
1817
from adafruit_ticks import ticks_ms as ticks, ticks_diff, ticks_add
1918
import sys, select
2019

20+
# CIRCUITPY-CHANGE: CircuitPython traceback support
2121
try:
2222
from traceback import print_exception
2323
except:
@@ -26,13 +26,15 @@
2626
# Import TaskQueue and Task, preferring built-in C code over Python code
2727
try:
2828
from _asyncio import TaskQueue, Task
29+
# CIRCUITPY-CHANGE: more specific error checking
2930
except ImportError:
3031
from .task import TaskQueue, Task
3132

3233
################################################################################
3334
# Exceptions
3435

3536

37+
# CIRCUITPY-CHANGE
3638
# Depending on the release of CircuitPython these errors may or may not
3739
# exist in the C implementation of `_asyncio`. However, when they
3840
# do exist, they must be preferred over the Python code.
@@ -50,6 +52,7 @@ class InvalidStateError(Exception):
5052

5153

5254
class TimeoutError(Exception):
55+
# CIRCUITPY-CHANGE: docstring
5356
"""Raised when waiting for a task longer than the specified timeout."""
5457

5558
pass
@@ -62,6 +65,7 @@ class TimeoutError(Exception):
6265
################################################################################
6366
# Sleep functions
6467

68+
6569
# "Yield" once, then raise StopIteration
6670
class SingletonGenerator:
6771
def __init__(self):
@@ -71,11 +75,13 @@ def __init__(self):
7175
def __iter__(self):
7276
return self
7377

78+
# CIRCUITPY-CHANGE: provide await
7479
def __await__(self):
7580
return self
7681

7782
def __next__(self):
7883
if self.state is not None:
84+
# CIRCUITPY-CHANGE: when 8.x support is discontinued, change to .push()
7985
_task_queue.push_sorted(cur_task, self.state)
8086
self.state = None
8187
return None
@@ -87,18 +93,21 @@ def __next__(self):
8793
# Pause task execution for the given time (integer in milliseconds, uPy extension)
8894
# Use a SingletonGenerator to do it without allocating on the heap
8995
def sleep_ms(t, sgen=SingletonGenerator()):
96+
# CIRCUITPY-CHANGE: doc
9097
"""Sleep for *t* milliseconds.
9198
9299
This is a coroutine, and a MicroPython extension.
93100
"""
94101

102+
# CIRCUITPY-CHANGE: add debugging hint
95103
assert sgen.state is None, "Check for a missing `await` in your code"
96104
sgen.state = ticks_add(ticks(), max(0, t))
97105
return sgen
98106

99107

100108
# Pause task execution for the given time (in seconds)
101109
def sleep(t):
110+
# CIRCUITPY-CHANGE: doc
102111
"""Sleep for *t* seconds
103112
104113
This is a coroutine.
@@ -107,6 +116,7 @@ def sleep(t):
107116
return sleep_ms(int(t * 1000))
108117

109118

119+
# CIRCUITPY-CHANGE: see https://github.com/adafruit/Adafruit_CircuitPython_asyncio/pull/30
110120
################################################################################
111121
# "Never schedule" object"
112122
# Don't re-schedule the object that awaits _never().
@@ -166,12 +176,16 @@ def _dequeue(self, s):
166176
del self.map[id(s)]
167177
self.poller.unregister(s)
168178

179+
# CIRCUITPY-CHANGE: async
169180
async def queue_read(self, s):
170181
self._enqueue(s, 0)
182+
# CIRCUITPY-CHANGE: do not reschedule
171183
await _never()
172184

185+
# CIRCUITPY-CHANGE: async
173186
async def queue_write(self, s):
174187
self._enqueue(s, 1)
188+
# CIRCUITPY-CHANGE: do not reschedule
175189
await _never()
176190

177191
def remove(self, task):
@@ -193,10 +207,12 @@ def wait_io_event(self, dt):
193207
# print('poll', s, sm, ev)
194208
if ev & ~select.POLLOUT and sm[0] is not None:
195209
# POLLIN or error
210+
# CIRCUITPY-CHANGE: when 8.x support is discontinued, change to .push()
196211
_task_queue.push_head(sm[0])
197212
sm[0] = None
198213
if ev & ~select.POLLIN and sm[1] is not None:
199214
# POLLOUT or error
215+
# CIRCUITPY-CHANGE: when 8.x support is discontinued, change to .push()
200216
_task_queue.push_head(sm[1])
201217
sm[1] = None
202218
if sm[0] is None and sm[1] is None:
@@ -210,13 +226,15 @@ def wait_io_event(self, dt):
210226
################################################################################
211227
# Main run loop
212228

229+
213230
# Ensure the awaitable is a task
214231
def _promote_to_task(aw):
215232
return aw if isinstance(aw, Task) else create_task(aw)
216233

217234

218235
# Create and schedule a new task from a coroutine
219236
def create_task(coro):
237+
# CIRCUITPY-CHANGE: doc
220238
"""Create a new task from the given coroutine and schedule it to run.
221239
222240
Returns the corresponding `Task` object.
@@ -225,12 +243,14 @@ def create_task(coro):
225243
if not hasattr(coro, "send"):
226244
raise TypeError("coroutine expected")
227245
t = Task(coro, globals())
246+
# CIRCUITPY-CHANGE: when 8.x support is discontinued, change to .push()
228247
_task_queue.push_head(t)
229248
return t
230249

231250

232251
# Keep scheduling tasks until there are none left to schedule
233252
def run_until_complete(main_task=None):
253+
# CIRCUITPY-CHANGE: doc
234254
"""Run the given *main_task* until it completes."""
235255

236256
global cur_task
@@ -247,11 +267,13 @@ def run_until_complete(main_task=None):
247267
dt = max(0, ticks_diff(t.ph_key, ticks()))
248268
elif not _io_queue.map:
249269
# No tasks can be woken so finished running
270+
cur_task = None
250271
return
251272
# print('(poll {})'.format(dt), len(_io_queue.map))
252273
_io_queue.wait_io_event(dt)
253274

254275
# Get next task to run and continue it
276+
# CIRCUITPY-CHANGE: when 8.x support is discontinued, change to .pop()
255277
t = _task_queue.pop_head()
256278
cur_task = t
257279
try:
@@ -271,6 +293,7 @@ def run_until_complete(main_task=None):
271293
assert t.data is None
272294
# This task is done, check if it's the main task and then loop should stop
273295
if t is main_task:
296+
cur_task = None
274297
if isinstance(er, StopIteration):
275298
return er.value
276299
raise er
@@ -288,6 +311,7 @@ def run_until_complete(main_task=None):
288311
else:
289312
# Schedule any other tasks waiting on the completion of this task.
290313
while t.state.peek():
314+
# CIRCUITPY-CHANGE: when 8.x support is discontinued, change to .push() and .pop()
291315
_task_queue.push_head(t.state.pop_head())
292316
waiting = True
293317
# "False" indicates that the task is complete and has been await'ed on.
@@ -296,19 +320,26 @@ def run_until_complete(main_task=None):
296320
# An exception ended this detached task, so queue it for later
297321
# execution to handle the uncaught exception if no other task retrieves
298322
# the exception in the meantime (this is handled by Task.throw).
323+
# CIRCUITPY-CHANGE: when 8.x support is discontinued, change to .push()
299324
_task_queue.push_head(t)
300325
# Save return value of coro to pass up to caller.
301326
t.data = er
302327
elif t.state is None:
303328
# Task is already finished and nothing await'ed on the task,
304329
# so call the exception handler.
330+
331+
# Save exception raised by the coro for later use.
332+
t.data = exc
333+
334+
# Create exception context and call the exception handler.
305335
_exc_context["exception"] = exc
306336
_exc_context["future"] = t
307337
Loop.call_exception_handler(_exc_context)
308338

309339

310340
# Create a new task from a coroutine and run it until it finishes
311341
def run(coro):
342+
# CIRCUITPY-CHANGE: doc
312343
"""Create a new task from the given coroutine and run it until it completes.
313344
314345
Returns the value returned by *coro*.
@@ -325,20 +356,24 @@ async def _stopper():
325356
pass
326357

327358

359+
cur_task = None
328360
_stop_task = None
329361

330362

331363
class Loop:
364+
# CIRCUITPY-CHANGE: doc
332365
"""Class representing the event loop"""
333366

334367
_exc_handler = None
335368

336369
def create_task(coro):
370+
# CIRCUITPY-CHANGE: doc
337371
"""Create a task from the given *coro* and return the new `Task` object."""
338372

339373
return create_task(coro)
340374

341375
def run_forever():
376+
# CIRCUITPY-CHANGE: doc
342377
"""Run the event loop until `Loop.stop()` is called."""
343378

344379
global _stop_task
@@ -347,47 +382,56 @@ def run_forever():
347382
# TODO should keep running until .stop() is called, even if there're no tasks left
348383

349384
def run_until_complete(aw):
385+
# CIRCUITPY-CHANGE: doc
350386
"""Run the given *awaitable* until it completes. If *awaitable* is not a task then
351387
it will be promoted to one.
352388
"""
353389

354390
return run_until_complete(_promote_to_task(aw))
355391

356392
def stop():
393+
# CIRCUITPY-CHANGE: doc
357394
"""Stop the event loop"""
358395

359396
global _stop_task
360397
if _stop_task is not None:
398+
# CIRCUITPY-CHANGE: when 8.x support is discontinued, change to .push()
361399
_task_queue.push_head(_stop_task)
362400
# If stop() is called again, do nothing
363401
_stop_task = None
364402

365403
def close():
404+
# CIRCUITPY-CHANGE: doc
366405
"""Close the event loop."""
367406

368407
pass
369408

370409
def set_exception_handler(handler):
410+
# CIRCUITPY-CHANGE: doc
371411
"""Set the exception handler to call when a Task raises an exception that is not
372412
caught. The *handler* should accept two arguments: ``(loop, context)``
373413
"""
374414

375415
Loop._exc_handler = handler
376416

377417
def get_exception_handler():
418+
# CIRCUITPY-CHANGE: doc
378419
"""Get the current exception handler. Returns the handler, or ``None`` if no
379420
custom handler is set.
380421
"""
381422

382423
return Loop._exc_handler
383424

384425
def default_exception_handler(loop, context):
426+
# CIRCUITPY-CHANGE: doc
385427
"""The default exception handler that is called."""
386428

429+
# CIRCUITPY_CHANGE: use CircuitPython traceback printing
387430
exc = context["exception"]
388431
print_exception(None, exc, exc.__traceback__)
389432

390433
def call_exception_handler(context):
434+
# CIRCUITPY-CHANGE: doc
391435
"""Call the current exception handler. The argument *context* is passed through
392436
and is a dictionary containing keys:
393437
``'message'``, ``'exception'``, ``'future'``
@@ -397,29 +441,36 @@ def call_exception_handler(context):
397441

398442
# The runq_len and waitq_len arguments are for legacy uasyncio compatibility
399443
def get_event_loop(runq_len=0, waitq_len=0):
400-
"""Return the event loop used to schedule and run tasks. See `Loop`."""
444+
# CIRCUITPY-CHANGE: doc
445+
"""Return the event loop used to schedule and run tasks. See `Loop`. Deprecated and will be removed later."""
401446

402447
return Loop
403448

404449

405450
def current_task():
451+
# CIRCUITPY-CHANGE: doc
406452
"""Return the `Task` object associated with the currently running task."""
407453

454+
if cur_task is None:
455+
raise RuntimeError("no running event loop")
408456
return cur_task
409457

410458

411459
def new_event_loop():
460+
# CIRCUITPY-CHANGE: doc
412461
"""Reset the event loop and return it.
413462
414463
**NOTE**: Since MicroPython only has a single event loop, this function just resets
415464
the loop's state, it does not create a new one
416465
"""
417466

467+
# CIRCUITPY-CHANGE: add _exc_context, cur_task
418468
global _task_queue, _io_queue, _exc_context, cur_task
419469
# TaskQueue of Task instances
420470
_task_queue = TaskQueue()
421471
# Task queue and poller for stream IO
422472
_io_queue = IOQueue()
473+
# CIRCUITPY-CHANGE: exception info
423474
cur_task = None
424475
_exc_context['exception'] = None
425476
_exc_context['future'] = None

0 commit comments

Comments
 (0)