From 95cd442393a4cffd28bcada3a1f6fae2fa5dad2d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Oct 2022 17:08:07 -0500 Subject: [PATCH 1/6] Unconditionally prefer the Python coded versions of TaskQueue, Task --- asyncio/core.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/asyncio/core.py b/asyncio/core.py index 33168e3..14166be 100644 --- a/asyncio/core.py +++ b/asyncio/core.py @@ -18,11 +18,8 @@ from adafruit_ticks import ticks_ms as ticks, ticks_diff, ticks_add import sys, select, traceback -# Import TaskQueue and Task, preferring built-in C code over Python code -try: - from _asyncio import TaskQueue, Task -except: - from .task import TaskQueue, Task +# Import TaskQueue and Task, unconditionally preferring Python code +from .task import TaskQueue, Task ################################################################################ From 04ccb62e1281a751cfa945c274ab34d7f663d033 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Oct 2022 17:08:38 -0500 Subject: [PATCH 2/6] Catch a CancelledError and return it if return_exceptions is set --- asyncio/funcs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asyncio/funcs.py b/asyncio/funcs.py index 2289d33..8718118 100644 --- a/asyncio/funcs.py +++ b/asyncio/funcs.py @@ -106,7 +106,7 @@ async def gather(*aws, return_exceptions=False): # # cancel all waiting tasks # raise er ts[i] = await ts[i] - except Exception as er: + except (core.CancelledError, Exception) as er: if return_exceptions: ts[i] = er else: From c15f5effa9497e997c63b2396106f24277186f43 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 14 Oct 2022 17:09:03 -0500 Subject: [PATCH 3/6] It's not standard Python, but must use 'yield' here for correctness --- asyncio/event.py | 2 +- asyncio/lock.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/asyncio/event.py b/asyncio/event.py index 04f6e15..3d02175 100644 --- a/asyncio/event.py +++ b/asyncio/event.py @@ -62,7 +62,7 @@ async def wait(self): self.waiting.push_head(core.cur_task) # Set calling task's data to the event's queue so it can be removed if needed core.cur_task.data = self.waiting - await core.sleep(0) + yield return True diff --git a/asyncio/lock.py b/asyncio/lock.py index 3b93e6a..5b4fe18 100644 --- a/asyncio/lock.py +++ b/asyncio/lock.py @@ -69,7 +69,7 @@ async def acquire(self): # Set calling task's data to the lock's queue so it can be removed if needed core.cur_task.data = self.waiting try: - await core.sleep(0) + yield except core.CancelledError as er: if self.state == core.cur_task: # Cancelled while pending on resume, schedule next waiting Task From f22e949c0b6c08b45159886bcfbc3a85a0a53778 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 15 Oct 2022 10:48:31 -0500 Subject: [PATCH 4/6] Revert "Unconditionally prefer the Python coded versions of TaskQueue, Task" This reverts commit 95cd442393a4cffd28bcada3a1f6fae2fa5dad2d. --- asyncio/core.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/asyncio/core.py b/asyncio/core.py index 14166be..33168e3 100644 --- a/asyncio/core.py +++ b/asyncio/core.py @@ -18,8 +18,11 @@ from adafruit_ticks import ticks_ms as ticks, ticks_diff, ticks_add import sys, select, traceback -# Import TaskQueue and Task, unconditionally preferring Python code -from .task import TaskQueue, Task +# Import TaskQueue and Task, preferring built-in C code over Python code +try: + from _asyncio import TaskQueue, Task +except: + from .task import TaskQueue, Task ################################################################################ From c98cff8a082cf135346b88a82975d3dd4a603120 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 15 Oct 2022 11:42:01 -0500 Subject: [PATCH 5/6] Introduce, use a 'never' object This can be used in cases where `await SOMETHING` is required, but the task cannot be put back on the queue like `await sleep(0)` would do. This passes the test and the docs build (locally) --- asyncio/core.py | 29 ++++++++++++++++++++++++++++- asyncio/event.py | 3 ++- asyncio/lock.py | 3 ++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/asyncio/core.py b/asyncio/core.py index 33168e3..dcd4b24 100644 --- a/asyncio/core.py +++ b/asyncio/core.py @@ -69,7 +69,6 @@ def __next__(self): 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()): @@ -93,6 +92,34 @@ def sleep(t): return sleep_ms(int(t * 1000)) +################################################################################ +# "Never schedule" object" +# Don't re-schedule the object that awaits the _never singleton. +# For internal use only. Some constructs, like `await event.wait()`, +# work by NOT re-scheduling the task which calls wait(), but by +# having some other task schedule it later. +class _Never: + def __init__(self): + self.state = None + self.exc = StopIteration() + + def __iter__(self): + return self + + def __await__(self): + return self + + def __next__(self): + if self.state is not None: + self.state = None + return None + else: + self.exc.__traceback__ = None + raise self.exc + +_never = _Never() + + ################################################################################ # Queue and poller for stream IO diff --git a/asyncio/event.py b/asyncio/event.py index 3d02175..442c5bb 100644 --- a/asyncio/event.py +++ b/asyncio/event.py @@ -62,7 +62,8 @@ async def wait(self): self.waiting.push_head(core.cur_task) # Set calling task's data to the event's queue so it can be removed if needed core.cur_task.data = self.waiting - yield + core._never.state = False + await core._never return True diff --git a/asyncio/lock.py b/asyncio/lock.py index 5b4fe18..b5080a3 100644 --- a/asyncio/lock.py +++ b/asyncio/lock.py @@ -69,7 +69,8 @@ async def acquire(self): # Set calling task's data to the lock's queue so it can be removed if needed core.cur_task.data = self.waiting try: - yield + core._never.state = False + await core._never except core.CancelledError as er: if self.state == core.cur_task: # Cancelled while pending on resume, schedule next waiting Task From d81e6aa4dc78b847bf2c539d0d1fcbecdcc4cfbc Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 15 Oct 2022 13:41:41 -0500 Subject: [PATCH 6/6] fix build process .. and use a simpler(?) way to invoke sed I don't know why this apparently only started recently, but circuitpython-build-tools creates build_deps/circuitpython with a directory 'nvm.toml' inside. The existing sed command would attempt to run on this directory. `find pattern... -exec command... +` takes the matching items and puts them on the command... commandline, without any concerns about whitespace or quoting. `for $(find...)` has several concerns about whitespace and quoting. It also adds "-type f" to restrict the match to only files, not directories. --- .github/workflows/build.yml | 4 +--- .github/workflows/release.yml | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ad339c3..00ab34d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,8 +70,6 @@ jobs: if: contains(steps.need-pypi.outputs.pyproject-toml, 'pyproject.toml') run: | pip install --upgrade build twine - for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0+auto.0/1.2.3/" $file; - done; + find -type f -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) -exec sed -i -e "s/0.0.0+auto.0/1.2.3/" {} + python -m build twine check dist/* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fe458e2..9e18ad7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,8 +81,6 @@ jobs: TWINE_USERNAME: ${{ secrets.pypi_username }} TWINE_PASSWORD: ${{ secrets.pypi_password }} run: | - for file in $(find -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) ); do - sed -i -e "s/0.0.0+auto.0/${{github.event.release.tag_name}}/" $file; - done; + find -type f -not -path "./.*" -not -path "./docs*" \( -name "*.py" -o -name "*.toml" \) -exec sed -i -e "s/0.0.0+auto.0/${{github.event.release.tag_name}}/" {} + python -m build twine upload dist/*