Skip to content

Commit d0d63f1

Browse files
authored
Merge pull request #74 from adafruit/micropython-v127-merge
update to MicroPython v1.27 changes
2 parents 6e1c3f4 + 1f9fee3 commit d0d63f1

File tree

7 files changed

+53
-29
lines changed

7 files changed

+53
-29
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repos:
1010
- id: end-of-file-fixer
1111
- id: trailing-whitespace
1212
- repo: https://github.com/astral-sh/ruff-pre-commit
13-
rev: v0.3.4
13+
rev: v0.15.10
1414
hooks:
1515
- id: ruff-format
1616
- id: ruff

asyncio/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,6 @@ def __getattr__(attr):
4040
mod = _attrs.get(attr, None)
4141
if mod is None:
4242
raise AttributeError(attr)
43-
value = getattr(__import__(mod, None, None, True, 1), attr)
43+
value = getattr(__import__(mod, globals(), None, True, 1), attr)
4444
globals()[attr] = value
4545
return value

asyncio/core.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def __next__(self):
9292
raise self.exc
9393

9494

95-
# Pause task execution for the given time (integer in milliseconds, uPy extension)
95+
# Pause task execution for the given time (integer in milliseconds, MicroPython extension)
9696
# Use a SingletonGenerator to do it without allocating on the heap
9797
def sleep_ms(t, sgen=SingletonGenerator()):
9898
# CIRCUITPY-CHANGE: doc
@@ -267,9 +267,16 @@ def run_until_complete(main_task=None):
267267
# A task waiting on _task_queue; "ph_key" is time to schedule task at
268268
dt = max(0, ticks_diff(t.ph_key, ticks()))
269269
elif not _io_queue.map:
270-
# No tasks can be woken so finished running
270+
# No tasks can be woken
271271
cur_task = None
272-
return
272+
if not main_task or not main_task.state:
273+
# no main_task, or main_task is done so finished running
274+
return
275+
# At this point, there is theoretically nothing that could wake the
276+
# scheduler, but it is not allowed to exit either. We keep the code
277+
# running so that a hypothetical debugger (or other such meta-process)
278+
# can get a view of what is happening and possibly abort.
279+
dt = 3
273280
# print('(poll {})'.format(dt), len(_io_queue.map))
274281
_io_queue.wait_io_event(dt)
275282

@@ -291,31 +298,33 @@ def run_until_complete(main_task=None):
291298
except excs_all as er:
292299
# Check the task is not on any event queue
293300
assert t.data is None
294-
# This task is done, check if it's the main task and then loop should stop
295-
if t is main_task:
301+
# If it's the main task, it is considered as awaited by the caller
302+
awaited = t is main_task
303+
if awaited:
296304
cur_task = None
297-
if isinstance(er, StopIteration):
298-
return er.value
299-
raise er
305+
if not isinstance(er, StopIteration):
306+
t.state = False
307+
raise er
308+
if t.state is None:
309+
t.state = False
300310
if t.state:
301311
# Task was running but is now finished.
302-
waiting = False
303312
if t.state is True:
304313
# "None" indicates that the task is complete and not await'ed on (yet).
305-
t.state = None
314+
t.state = False if awaited else None
306315
elif callable(t.state):
307316
# The task has a callback registered to be called on completion.
308317
t.state(t, er)
309318
t.state = False
310-
waiting = True
319+
awaited = True
311320
else:
312321
# Schedule any other tasks waiting on the completion of this task.
313322
while t.state.peek():
314323
_task_queue.push(t.state.pop())
315-
waiting = True
324+
awaited = True
316325
# "False" indicates that the task is complete and has been await'ed on.
317326
t.state = False
318-
if not waiting and not isinstance(er, excs_stop):
327+
if not awaited and not isinstance(er, excs_stop):
319328
# An exception ended this detached task, so queue it for later
320329
# execution to handle the uncaught exception if no other task retrieves
321330
# the exception in the meantime (this is handled by Task.throw).
@@ -333,6 +342,9 @@ def run_until_complete(main_task=None):
333342
_exc_context["exception"] = exc
334343
_exc_context["future"] = t
335344
Loop.call_exception_handler(_exc_context)
345+
# If it's the main task then the loop should stop
346+
if t is main_task:
347+
return er.value
336348

337349

338350
# Create a new task from a coroutine and run it until it finishes

asyncio/funcs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ def done(t, er):
168168
elif isinstance(ts[i].data, StopIteration):
169169
# Sub-task ran to completion, get its return value.
170170
ts[i] = ts[i].data.value
171+
# Sub-task had an exception.
171172
elif return_exceptions:
172173
# Get the sub-task exception to return in the list of return values.
173174
ts[i] = ts[i].data

asyncio/stream.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ async def readline(self):
102102
# CIRCUITPY-CHANGE: await, not yield
103103
await core._io_queue.queue_read(self.s)
104104
l2 = self.s.readline() # may do multiple reads but won't block
105+
if l2 is None:
106+
continue
105107
l += l2
106108
if not l2 or l[-1] == 10: # \n (check l in case l2 is str)
107109
return l
@@ -126,7 +128,10 @@ async def drain(self):
126128
# CIRCUITPY-CHANGE: doc
127129
"""Drain (write) all buffered output data out to the stream.
128130
"""
129-
131+
if not self.out_buf:
132+
# Drain must always yield, so a tight loop of write+drain can't block the scheduler.
133+
# CIRCUITPYTHON-CHANGE: await
134+
return (await core.sleep_ms(0))
130135
mv = memoryview(self.out_buf)
131136
off = 0
132137
while off < len(mv):
@@ -199,6 +204,9 @@ def close(self):
199204
# CIRCUITPY-CHANGE: doc
200205
"""Close the server."""
201206

207+
# Note: the _serve task must have already started by now due to the sleep
208+
# in start_server, so `state` won't be clobbered at the start of _serve.
209+
self.state = True
202210
self.task.cancel()
203211

204212
async def wait_closed(self):
@@ -255,11 +263,11 @@ async def start_server(cb, host, port, backlog=5):
255263
import socket
256264

257265
# Create and bind server socket.
258-
host = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
259-
s = socket.socket()
266+
addr_info = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
267+
s = socket.socket(addr_info[0]) # Use address family from getaddrinfo
260268
s.setblocking(False)
261269
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
262-
s.bind(host[-1])
270+
s.bind(addr_info[-1])
263271
s.listen(backlog)
264272

265273
# Create and return server object and task.

asyncio/task.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -198,16 +198,18 @@ def cancel(self):
198198
if self is core.cur_task:
199199
raise RuntimeError("can't cancel self")
200200
# If Task waits on another task then forward the cancel to the one it's waiting on.
201-
while isinstance(self.data, Task):
202-
self = self.data
201+
# CIRCUITPY-CHANGE: don't reassign self
202+
task = self
203+
while isinstance(task.data, Task):
204+
task = task.data
203205
# Reschedule Task as a cancelled task.
204-
if hasattr(self.data, "remove"):
206+
if hasattr(task.data, "remove"):
205207
# Not on the main running queue, remove the task from the queue it's on.
206-
self.data.remove(self)
207-
core._task_queue.push(self)
208-
elif core.ticks_diff(self.ph_key, core.ticks()) > 0:
208+
task.data.remove(task)
209+
core._task_queue.push(task)
210+
elif core.ticks_diff(task.ph_key, core.ticks()) > 0:
209211
# On the main running queue but scheduled in the future, so bring it forward to now.
210-
core._task_queue.remove(self)
211-
core._task_queue.push(self)
212-
self.data = core.CancelledError
212+
core._task_queue.remove(task)
213+
core._task_queue.push(task)
214+
task.data = core.CancelledError
213215
return True

asyncio/traceback.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def _print_traceback(traceback, limit=None, file=sys.stderr) -> List[str]:
2929
name = frame_code.co_name
3030
print(f' File "{filename}", line {line_number}, in {name}', file=file)
3131
traceback = traceback.tb_next
32-
n = n + 1
32+
# CIRCUITPY-CHANGE: use +=
33+
n += 1
3334
if limit is not None and n >= limit:
3435
break
3536

0 commit comments

Comments
 (0)