From e5a1899c7ecbce465d503a09e93480a4e51ca4e3 Mon Sep 17 00:00:00 2001 From: henryruhs Date: Sat, 3 Oct 2026 14:39:23 +0200 Subject: [PATCH] replace anyio with asyncio --- .github/workflows/ci.yml | 2 ++ facefusion/apis/endpoints/session.py | 4 ++-- facefusion/apis/websocket_store.py | 7 +++--- facefusion/types.py | 5 ++-- tests/test_api_stream_manager.py | 4 ++-- tests/test_websocket_store.py | 34 ++++++++++------------------ 6 files changed, 24 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cd98e0f..8de6bd3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,7 @@ jobs: python-version: '3.12' - run: python install.py default --skip-conda - run: pip install pytest + - run: pip install pytest-asyncio - run: pip install pytest-mock - run: pip install httpx - run: pip install python-multipart @@ -55,6 +56,7 @@ jobs: - run: pip install coveralls - run: pip install pytest - run: pip install pytest-cov + - run: pip install pytest-asyncio - run: pip install pytest-mock - run: pip install httpx - run: pip install python-multipart diff --git a/facefusion/apis/endpoints/session.py b/facefusion/apis/endpoints/session.py index 3a553307..f2aee056 100644 --- a/facefusion/apis/endpoints/session.py +++ b/facefusion/apis/endpoints/session.py @@ -1,6 +1,6 @@ +import asyncio import secrets -from starlette.concurrency import run_in_threadpool from starlette.requests import Request from starlette.responses import JSONResponse from starlette.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_401_UNAUTHORIZED, HTTP_404_NOT_FOUND, HTTP_429_TOO_MANY_REQUESTS @@ -106,7 +106,7 @@ async def destroy_session(request : Request) -> JSONResponse: }, status_code = HTTP_404_NOT_FOUND) session_manager.clear_api_session(session_id) - await run_in_threadpool(store_manager.destroy, session_id) + await asyncio.to_thread(store_manager.destroy, session_id) return JSONResponse( { diff --git a/facefusion/apis/websocket_store.py b/facefusion/apis/websocket_store.py index a0f223e9..b5e8908d 100644 --- a/facefusion/apis/websocket_store.py +++ b/facefusion/apis/websocket_store.py @@ -1,5 +1,4 @@ -from anyio.from_thread import run -from anyio.lowlevel import current_token +import asyncio from facefusion import store_creator from facefusion.session_manager import resolve_owner_id @@ -20,7 +19,7 @@ def set_websocket(websocket : Websocket) -> None: store_creator.get_content(WEBSOCKET_STORE, owner_id)[id(websocket)] =\ { 'websocket': websocket, - 'event_loop_token': current_token() + 'event_loop': asyncio.get_running_loop() } @@ -38,4 +37,4 @@ def destroy(session_id : SessionId) -> None: if session_websocket_set: for session_websocket in session_websocket_set.values(): - run(session_websocket.get('websocket').close, token = session_websocket.get('event_loop_token')) + asyncio.run_coroutine_threadsafe(session_websocket.get('websocket').close(), session_websocket.get('event_loop')).result() diff --git a/facefusion/types.py b/facefusion/types.py index e9a57647..419ec482 100755 --- a/facefusion/types.py +++ b/facefusion/types.py @@ -1,3 +1,4 @@ +import asyncio import ctypes import subprocess from collections import namedtuple @@ -159,11 +160,11 @@ Token : TypeAlias = str SessionId : TypeAlias = str Websocket : TypeAlias = Any WebsocketId : TypeAlias = int -EventLoopToken : TypeAlias = Any +EventLoop : TypeAlias = asyncio.AbstractEventLoop SessionWebsocket = TypedDict('SessionWebsocket', { 'websocket' : Websocket, - 'event_loop_token' : EventLoopToken + 'event_loop' : EventLoop }) SessionWebsocketSet : TypeAlias = Dict[WebsocketId, SessionWebsocket] ApiSession = TypedDict('ApiSession', diff --git a/tests/test_api_stream_manager.py b/tests/test_api_stream_manager.py index 36cb9daa..4bb83238 100644 --- a/tests/test_api_stream_manager.py +++ b/tests/test_api_stream_manager.py @@ -43,7 +43,7 @@ def before_each() -> Iterator[None]: set_session_id(local_id) -@pytest.mark.anyio +@pytest.mark.asyncio async def test_process_image() -> None: image_buffer = open(get_test_example_file('source.jpg'), 'rb').read() websocket_mock = AsyncMock() @@ -67,7 +67,7 @@ async def test_process_image() -> None: assert create_hash(websocket_mock.send_bytes.call_args[0][0]) == '0142782f' -@pytest.mark.anyio +@pytest.mark.asyncio async def test_receive_vision_frames() -> None: image_buffer = open(get_test_example_file('source.jpg'), 'rb').read() websocket_mock = AsyncMock() diff --git a/tests/test_websocket_store.py b/tests/test_websocket_store.py index fd58678c..294633e4 100644 --- a/tests/test_websocket_store.py +++ b/tests/test_websocket_store.py @@ -1,13 +1,12 @@ +import asyncio from typing import Iterator from unittest.mock import AsyncMock -import anyio import pytest from facefusion import store_creator from facefusion.apis.websocket_store import WEBSOCKET_STORE, delete_websocket, destroy, init, set_websocket from facefusion.session_context import resolve_local_id, set_session_id -from facefusion.types import SessionId, Websocket @pytest.fixture(scope = 'function', autouse = True) @@ -22,20 +21,6 @@ def before_each() -> Iterator[None]: set_session_id(local_id) -async def set_and_destroy_websocket(websocket : Websocket, session_id : SessionId) -> None: - set_websocket(websocket) - await anyio.to_thread.run_sync(destroy, session_id) - - -async def set_and_delete_websocket(websocket : Websocket) -> None: - set_websocket(websocket) - delete_websocket(websocket) - - -async def set_websocket_in_event_loop(websocket : Websocket) -> None: - set_websocket(websocket) - - def test_init() -> None: set_session_id('session-a') init() @@ -45,28 +30,33 @@ def test_init() -> None: destroy('session-a') -def test_set_websocket() -> None: +@pytest.mark.asyncio +async def test_set_websocket() -> None: websocket_mock = AsyncMock() - anyio.run(set_websocket_in_event_loop, websocket_mock) + set_websocket(websocket_mock) assert store_creator.get_content(WEBSOCKET_STORE, resolve_local_id()).get(id(websocket_mock)).get('websocket') is websocket_mock -def test_delete_websocket() -> None: +@pytest.mark.asyncio +async def test_delete_websocket() -> None: websocket_mock = AsyncMock() - anyio.run(set_and_delete_websocket, websocket_mock) + set_websocket(websocket_mock) + delete_websocket(websocket_mock) assert store_creator.get_content(WEBSOCKET_STORE, resolve_local_id()) == {} -def test_destroy() -> None: +@pytest.mark.asyncio +async def test_destroy() -> None: websocket_mock = AsyncMock() set_session_id('session-a') init() - anyio.run(set_and_destroy_websocket, websocket_mock, 'session-a') + set_websocket(websocket_mock) + await asyncio.to_thread(destroy, 'session-a') websocket_mock.close.assert_awaited_once() assert store_creator.has_content(WEBSOCKET_STORE, 'session-a') is False