ReMe/reme/utils/async_utils.py
xyf2020 2767836b21
feat(sandbox): Add Home AutoBash plugin and path-scoped execution sandboxes (#603)
* Add sandboxed Python execution and home AutoBash plugin

* Harden read-only shell commands and filesystem sandboxes

* Group file sandbox backends in one package

* Fix macOS file sandbox isolation and runtime access

* Refine file sandbox limits and executor checks

* Harden AutoBash policy and macOS sandbox supervision

* fix(home): require ReMe release with file sandbox

* refactor(home): simplify sandbox calls and redundant tests

* fix(execution): bound output and clean up cancelled sandbox startup

* fix(tests): mock Seatbelt platform requirements on Linux

* fix(home): block Git help helpers and harden sandbox cleanup

* Fix sandbox runtime links and subprocess cleanup

* ci: cover Home plugin tests

* test: wait for pipeline descendants to exit after cancellation

* fix: align Home dependencies and preserve cleanup cancellation

Require ReMe 0.4.2.1 and verify isolated Home wheel installation in package CI. Share cancellation-safe cleanup with thread calls, retain AnyIO cancellation semantics, and record Bubblewrap mount targets during argument construction.
2026-10-27 18:08:26 +08:00

32 lines
1 KiB
Python

"""Small asyncio helpers."""
import asyncio
from collections.abc import Awaitable, Callable
from contextlib import suppress
from typing import Any
async def finish_cleanup(operation: Awaitable):
"""Finish cleanup before propagating any cancellation received while waiting."""
task = asyncio.ensure_future(operation)
cancellation: asyncio.CancelledError | None = None
while not task.done():
try:
await asyncio.shield(task)
except asyncio.CancelledError as exc:
if cancellation is None:
cancellation = exc
except Exception:
if cancellation is None:
raise
break
if cancellation is not None:
with suppress(Exception):
task.result()
raise cancellation
return task.result()
async def complete_in_thread(func: Callable[..., Any], /, *args) -> Any:
"""Finish a side-effecting thread call, including through repeated cancellation."""
return await finish_cleanup(asyncio.to_thread(func, *args))