Skip to content

Commit

Permalink
Update frozen stubs for latest
Browse files Browse the repository at this point in the history
  • Loading branch information
Josverl committed Jun 29, 2023
1 parent d8d7b95 commit d015a26
Show file tree
Hide file tree
Showing 21 changed files with 1,205 additions and 0 deletions.
31 changes: 31 additions & 0 deletions stubs/micropython-latest-frozen/samd/GENERIC/asyncio/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# MicroPython asyncio module
# MIT license; Copyright (c) 2019 Damien P. George

from .core import *

__version__ = (3, 0, 0)

_attrs = {
"wait_for": "funcs",
"wait_for_ms": "funcs",
"gather": "funcs",
"Event": "event",
"ThreadSafeFlag": "event",
"Lock": "lock",
"open_connection": "stream",
"start_server": "stream",
"StreamReader": "stream",
"StreamWriter": "stream",
}


# Lazy loader, effectively does:
# global attr
# from .mod import attr
def __getattr__(attr):
mod = _attrs.get(attr, None)
if mod is None:
raise AttributeError(attr)
value = getattr(__import__(mod, None, None, True, 1), attr)
globals()[attr] = value
return value
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .core import *
from _typeshed import Incomplete

__version__: Incomplete
_attrs: Incomplete

def __getattr__(attr): ...
302 changes: 302 additions & 0 deletions stubs/micropython-latest-frozen/samd/GENERIC/asyncio/core.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
# MicroPython asyncio module
# MIT license; Copyright (c) 2019 Damien P. George

from time import ticks_ms as ticks, ticks_diff, ticks_add
import sys, select

# Import TaskQueue and Task, preferring built-in C code over Python code
try:
from _asyncio import TaskQueue, Task
except:
from .task import TaskQueue, Task


################################################################################
# Exceptions


class CancelledError(BaseException):
pass


class TimeoutError(Exception):
pass


# Used when calling Loop.call_exception_handler
_exc_context = {"message": "Task exception wasn't retrieved", "exception": None, "future": None}


################################################################################
# Sleep functions


# "Yield" once, then raise StopIteration
class SingletonGenerator:
def __init__(self):
self.state = None
self.exc = StopIteration()

def __iter__(self):
return self

def __next__(self):
if self.state is not None:
_task_queue.push(cur_task, self.state)
self.state = None
return None
else:
self.exc.__traceback__ = None
raise self.exc


# Pause task execution for the given time (integer in milliseconds, uPy extension)
# Use a SingletonGenerator to do it without allocating on the heap
def sleep_ms(t, sgen=SingletonGenerator()):
assert sgen.state is None
sgen.state = ticks_add(ticks(), max(0, t))
return sgen


# Pause task execution for the given time (in seconds)
def sleep(t):
return sleep_ms(int(t * 1000))


################################################################################
# Queue and poller for stream IO


class IOQueue:
def __init__(self):
self.poller = select.poll()
self.map = {} # maps id(stream) to [task_waiting_read, task_waiting_write, stream]

def _enqueue(self, s, idx):
if id(s) not in self.map:
entry = [None, None, s]
entry[idx] = cur_task
self.map[id(s)] = entry
self.poller.register(s, select.POLLIN if idx == 0 else select.POLLOUT)
else:
sm = self.map[id(s)]
assert sm[idx] is None
assert sm[1 - idx] is not None
sm[idx] = cur_task
self.poller.modify(s, select.POLLIN | select.POLLOUT)
# Link task to this IOQueue so it can be removed if needed
cur_task.data = self

def _dequeue(self, s):
del self.map[id(s)]
self.poller.unregister(s)

def queue_read(self, s):
self._enqueue(s, 0)

def queue_write(self, s):
self._enqueue(s, 1)

def remove(self, task):
while True:
del_s = None
for k in self.map: # Iterate without allocating on the heap
q0, q1, s = self.map[k]
if q0 is task or q1 is task:
del_s = s
break
if del_s is not None:
self._dequeue(s)
else:
break

def wait_io_event(self, dt):
for s, ev in self.poller.ipoll(dt):
sm = self.map[id(s)]
# print('poll', s, sm, ev)
if ev & ~select.POLLOUT and sm[0] is not None:
# POLLIN or error
_task_queue.push(sm[0])
sm[0] = None
if ev & ~select.POLLIN and sm[1] is not None:
# POLLOUT or error
_task_queue.push(sm[1])
sm[1] = None
if sm[0] is None and sm[1] is None:
self._dequeue(s)
elif sm[0] is None:
self.poller.modify(s, select.POLLOUT)
else:
self.poller.modify(s, select.POLLIN)


################################################################################
# Main run loop


# Ensure the awaitable is a task
def _promote_to_task(aw):
return aw if isinstance(aw, Task) else create_task(aw)


# Create and schedule a new task from a coroutine
def create_task(coro):
if not hasattr(coro, "send"):
raise TypeError("coroutine expected")
t = Task(coro, globals())
_task_queue.push(t)
return t


# Keep scheduling tasks until there are none left to schedule
def run_until_complete(main_task=None):
global cur_task
excs_all = (CancelledError, Exception) # To prevent heap allocation in loop
excs_stop = (CancelledError, StopIteration) # To prevent heap allocation in loop
while True:
# Wait until the head of _task_queue is ready to run
dt = 1
while dt > 0:
dt = -1
t = _task_queue.peek()
if t:
# A task waiting on _task_queue; "ph_key" is time to schedule task at
dt = max(0, ticks_diff(t.ph_key, ticks()))
elif not _io_queue.map:
# No tasks can be woken so finished running
return
# print('(poll {})'.format(dt), len(_io_queue.map))
_io_queue.wait_io_event(dt)

# Get next task to run and continue it
t = _task_queue.pop()
cur_task = t
try:
# Continue running the coroutine, it's responsible for rescheduling itself
exc = t.data
if not exc:
t.coro.send(None)
else:
# If the task is finished and on the run queue and gets here, then it
# had an exception and was not await'ed on. Throwing into it now will
# raise StopIteration and the code below will catch this and run the
# call_exception_handler function.
t.data = None
t.coro.throw(exc)
except excs_all as er:
# Check the task is not on any event queue
assert t.data is None
# This task is done, check if it's the main task and then loop should stop
if t is main_task:
if isinstance(er, StopIteration):
return er.value
raise er
if t.state:
# Task was running but is now finished.
waiting = False
if t.state is True:
# "None" indicates that the task is complete and not await'ed on (yet).
t.state = None
elif callable(t.state):
# The task has a callback registered to be called on completion.
t.state(t, er)
t.state = False
waiting = True
else:
# Schedule any other tasks waiting on the completion of this task.
while t.state.peek():
_task_queue.push(t.state.pop())
waiting = True
# "False" indicates that the task is complete and has been await'ed on.
t.state = False
if not waiting and not isinstance(er, excs_stop):
# An exception ended this detached task, so queue it for later
# execution to handle the uncaught exception if no other task retrieves
# the exception in the meantime (this is handled by Task.throw).
_task_queue.push(t)
# Save return value of coro to pass up to caller.
t.data = er
elif t.state is None:
# Task is already finished and nothing await'ed on the task,
# so call the exception handler.
_exc_context["exception"] = exc
_exc_context["future"] = t
Loop.call_exception_handler(_exc_context)


# Create a new task from a coroutine and run it until it finishes
def run(coro):
return run_until_complete(create_task(coro))


################################################################################
# Event loop wrapper


async def _stopper():
pass


_stop_task = None


class Loop:
_exc_handler = None

def create_task(coro):
return create_task(coro)

def run_forever():
global _stop_task
_stop_task = Task(_stopper(), globals())
run_until_complete(_stop_task)
# TODO should keep running until .stop() is called, even if there're no tasks left

def run_until_complete(aw):
return run_until_complete(_promote_to_task(aw))

def stop():
global _stop_task
if _stop_task is not None:
_task_queue.push(_stop_task)
# If stop() is called again, do nothing
_stop_task = None

def close():
pass

def set_exception_handler(handler):
Loop._exc_handler = handler

def get_exception_handler():
return Loop._exc_handler

def default_exception_handler(loop, context):
print(context["message"])
print("future:", context["future"], "coro=", context["future"].coro)
sys.print_exception(context["exception"])

def call_exception_handler(context):
(Loop._exc_handler or Loop.default_exception_handler)(Loop, context)


# The runq_len and waitq_len arguments are for legacy uasyncio compatibility
def get_event_loop(runq_len=0, waitq_len=0):
return Loop


def current_task():
return cur_task


def new_event_loop():
global _task_queue, _io_queue
# TaskQueue of Task instances
_task_queue = TaskQueue()
# Task queue and poller for stream IO
_io_queue = IOQueue()
return Loop


# Initialise default event loop
new_event_loop()
52 changes: 52 additions & 0 deletions stubs/micropython-latest-frozen/samd/GENERIC/asyncio/core.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from .task import Task as Task, TaskQueue as TaskQueue
from _typeshed import Incomplete

class CancelledError(BaseException): ...
class TimeoutError(Exception): ...

_exc_context: Incomplete

class SingletonGenerator:
state: Incomplete
exc: Incomplete
def __init__(self) -> None: ...
def __iter__(self): ...
def __next__(self) -> None: ...

def sleep_ms(t, sgen=...): ...
def sleep(t): ...

class IOQueue:
poller: Incomplete
map: Incomplete
def __init__(self) -> None: ...
def _enqueue(self, s, idx) -> None: ...
def _dequeue(self, s) -> None: ...
def queue_read(self, s) -> None: ...
def queue_write(self, s) -> None: ...
def remove(self, task) -> None: ...
def wait_io_event(self, dt) -> None: ...

def _promote_to_task(aw): ...
def create_task(coro): ...
def run_until_complete(main_task: Incomplete | None = ...): ...
def run(coro): ...
async def _stopper() -> None: ...

_stop_task: Incomplete

class Loop:
_exc_handler: Incomplete
def create_task(coro): ...
def run_forever() -> None: ...
def run_until_complete(aw): ...
def stop() -> None: ...
def close() -> None: ...
def set_exception_handler(handler) -> None: ...
def get_exception_handler(): ...
def default_exception_handler(loop, context) -> None: ...
def call_exception_handler(context) -> None: ...

def get_event_loop(runq_len: int = ..., waitq_len: int = ...): ...
def current_task(): ...
def new_event_loop(): ...
Loading

0 comments on commit d015a26

Please sign in to comment.