Skip to content

Commit 69ae5ae

Browse files
committed
update to MicroPython v1.27 changes
1 parent e69ac03 commit 69ae5ae

File tree

4 files changed

+46
-24
lines changed

4 files changed

+46
-24
lines changed

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: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,14 @@ 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-
elif return_exceptions:
172-
# Get the sub-task exception to return in the list of return values.
173-
ts[i] = ts[i].data
174-
elif isinstance(state, int):
175-
# Raise the sub-task exception, if there is not already an exception to raise.
176-
state = ts[i].data
171+
else:
172+
# Sub-task had an exception.
173+
if return_exceptions:
174+
# Get the sub-task exception to return in the list of return values.
175+
ts[i] = ts[i].data
176+
elif isinstance(state, int):
177+
# Raise the sub-task exception, if there is not already an exception to raise.
178+
state = ts[i].data
177179

178180
# Either this gather was cancelled, or one of the sub-tasks raised an exception with
179181
# return_exceptions==False, so reraise the exception here.

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.

0 commit comments

Comments
 (0)