MagicStack / MagicStack/uvloop

Python 3.12

オープン
#643 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

主要言語
Cython
スター
11.9k
フォーク
616
PR マージ指標
30日以内にマージされた PR はありません

説明

  • uvloop version:
  • Python version: 3.12
  • Platform: ubuntu
  • Can you reproduce the bug with PYTHONASYNCIODEBUG in env?: Not tested
  • Does uvloop behave differently from vanilla asyncio? How?:

Tried to reproduce this: Replacing the LoopPolicy with Uvloop leads to the following error.
The error only occurs in Ubuntu + Python 3.12 combination. (3.9, 3.10, 3.11 work)

https://github.com/michaelfeil/infinity/actions/runs/11773635831/job/32790872907

 ______________________ ERROR at setup of test_classifier _______________________
fut = <coroutine object AsyncioEvent.wait at 0x7f3384fbd600>, timeout = 5
    async def wait_for(fut, timeout):
        """Wait for the single Future or coroutine to complete, with timeout.
    
        Coroutine will be wrapped in Task.
    
        Returns result of the Future or coroutine.  When a timeout occurs,
        it cancels the task and raises TimeoutError.  To avoid the task
        cancellation, wrap it in shield().
    
        If the wait is cancelled, the task is also cancelled.
    
        If the task suppresses the cancellation and returns a value instead,
        that value is returned.
    
        This function is a coroutine.
        """
        # The special case for timeout <= 0 is for the following case:
        #
        # async def test_waitfor():
        #     func_started = False
        #
        #     async def func():
        #         nonlocal func_started
        #         func_started = True
        #
        #     try:
        #         await asyncio.wait_for(func(), 0)
        #     except asyncio.TimeoutError:
        #         assert not func_started
        #     else:
        #         assert False
        #
        # asyncio.run(test_waitfor())
    
    
        if timeout is not None and timeout <= 0:
            fut = ensure_future(fut)
    
            if fut.done():
                return fut.result()
    
            await _cancel_and_wait(fut)
            try:
                return fut.result()
            except exceptions.CancelledError as exc:
                raise TimeoutError from exc
    
        async with timeouts.timeout(timeout):
>           return await fut
/opt/hostedtoolcache/Python/3.12.7/x64/lib/python3.12/asyncio/tasks.py:520: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.venv/lib/python3.12/site-packages/asgi_lifespan/_concurrency/asyncio.py:17: in wait
    await self._event.wait()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <asyncio.locks.Event object at 0x7f3374ad88c0 [set]>
    async def wait(self):
        """Block until the internal flag is true.
    
        If the internal flag is true on entry, return True
        immediately.  Otherwise, block until another coroutine calls
        set() to set the flag to true, then return True.
        """
        if self._value:
            return True
    
        fut = self._get_loop().create_future()
        self._waiters.append(fut)
        try:
>           await fut
E           asyncio.exceptions.CancelledError
/opt/hostedtoolcache/Python/3.12.7/x64/lib/python3.12/asyncio/locks.py:212: CancelledError
The above exception was the direct cause of the following exception:
self = <asgi_lifespan._concurrency.asyncio.AsyncioBackend object at 0x7f3374ad8e30>
seconds = 5
coroutine = <bound method AsyncioEvent.wait of <asgi_lifespan._concurrency.asyncio.AsyncioEvent object at 0x7f3374ad97c0>>
    async def run_and_fail_after(
        self,
        seconds: typing.Optional[float],
        coroutine: typing.Callable[[], typing.Awaitable[None]],
    ) -> None:
        try:
>           await asyncio.wait_for(coroutine(), timeout=seconds)
.venv/lib/python3.12/site-packages/asgi_lifespan/_concurrency/asyncio.py:44: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.12.7/x64/lib/python3.12/asyncio/tasks.py:519: in wait_for
    async with timeouts.timeout(timeout):
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <Timeout [expired]>
exc_type = <class 'asyncio.exceptions.CancelledError'>
exc_val = CancelledError(), exc_tb = <traceback object at 0x7f339419fac0>
    async def __aexit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_val: Optional[BaseException],
        exc_tb: Optional[TracebackType],
    ) -> Optional[bool]:
        assert self._state in (_State.ENTERED, _State.EXPIRING)
    
        if self._timeout_handler is not None:
            self._timeout_handler.cancel()
            self._timeout_handler = None
    
        if self._state is _State.EXPIRING:
            self._state = _State.EXPIRED
    
            if self._task.uncancel() <= self._cancelling and exc_type is exceptions.CancelledError:
                # Since there are no new cancel requests, we're
                # handling this.
>               raise TimeoutError from exc_val
E               TimeoutError
/opt/hostedtoolcache/Python/3.12.7/x64/lib/python3.12/asyncio/timeouts.py:115: TimeoutError
During handling of the above exception, another exception occurred:
    @pytest.fixture()
    async def client():
>       async with AsyncClient(app=app, base_url="http://test", timeout=20) as client, LifespanManager(
            app
        ):
tests/end_to_end/test_torch_classify.py:35: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.venv/lib/python3.12/site-packages/asgi_lifespan/_manager.py:99: in __aenter__
    await self.startup()
.venv/lib/python3.12/site-packages/asgi_lifespan/_manager.py:40: in startup
    await self._concurrency_backend.run_and_fail_after(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <asgi_lifespan._concurrency.asyncio.AsyncioBackend object at 0x7f3374ad8e30>
seconds = 5
coroutine = <bound method AsyncioEvent.wait of <asgi_lifespan._concurrency.asyncio.AsyncioEvent object at 0x7f3374ad97c0>>
    async def run_and_fail_after(
        self,
        seconds: typing.Optional[float],
        coroutine: typing.Callable[[], typing.Awaitable[None]],
    ) -> None:
        try:
            await asyncio.wait_for(coroutine(), timeout=seconds)
        except asyncio.TimeoutError:
>           raise TimeoutError
E           TimeoutError

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、リンクされている infinity GitHub Actions ジョブを Ubuntu 上で Python 3.12 と uvloop を使って再現し、次に vanilla asyncio を使って同じテストを比較します。traceback は tests/end_to_end/test_torch_classify.py と asyncio のイベント待機パスを指しています。uvloop 固有の原因を特定し、その失敗に対するリグレッションテストを追加すれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python, ubuntu
領域
backend, networking
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
説明が足りない
初心者へのやさしさ
28/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。