pytest-dev/pytest-asyncio

There should be a better workaround for event_loop removal and Deprecation of event loop policies in 3.14

Closed this issue · 3 comments

Seeing this library and having utilized it with a few of my smaller libraries like aiocallback and aiothreading I want to be able to test asyncio's default loop alongside winloop on windows and uvloop on linux and Apple. Now I know of the event loop policies and all of that but the problem is that it's deprecated in 3.14 with removal coming in 3.16 and I would hate to have to use an uncomfortable hack of my own. I wanted to write a solution that doesn't devolve into bringing back event_loop because it was removed #1106 and I think keeping the warning's mouth shut about is a bad approach. So here's what I wanted to bring to the table hence why I am throwing this issue about it first.

Solution

I see fit to make a new autouse fixure for making use of functions that involve using new_event_loop based off winloop/uvloop's new_event_loop function and asyncio's as well. Something like this maybe to get around the different deprecated/removed approches.

@pytest.fixture(scope="session", autouse=True)
def new_event_loop() -> asyncio.AbstractEventLoop:
    """creates different asyncio event loops."""
    return asyncio.new_event_loop()

This fixure or apporch should be easy for anyone to pull off and here's an example of how I would go about using it.

import pytest
import sys
import asyncio

uvloop = pytest.importorskip("winloop" if sys.platform == "win32" else "uvloop", reason="uvloop library not installed")
UVLOOP_MARK = pytest.mark.uvloop_event_loop
ASYNCIO_MARK = pytest.mark.asyncio_event_loop

@pytest.fixture(
    scope="module",
    params=(
        asyncio.new_event_loop,
        pytest.param(
            uvloop.new_event_loop,
            marks=UVLOOP_MARK
        )
    )
)
def new_event_loop(request:pytest.FixtureRequest) -> asyncio.AbstractEventLoop:
    return request.param()

@pytest.mark.asyncio
async def do_test():
    ...
from cyares.aio import DNSResolver
import asyncio
import pytest
import sys

# Only apply to aio and nowhere else...
uvloop = pytest.importorskip("winloop" if sys.platform == "win32" else "uvloop")


@pytest.fixture(
    scope="module", 
    params=(
        "uvloop/winloop",
        "std-asyncio"
    ), 
    # autouse allows us to override allowing multiple 
    # eventloops to be tested at a time.
    autouse=True,
    ids=str
)
def event_loop(request:pytest.FixtureRequest):
    if request.param == "uvloop/winloop":
        loop = uvloop.new_event_loop()
        yield loop 
    else:
        # XXX: DNS Resolver will freeze if we attempt to use 
        # ProactorEventLoop, your better off using winloop 
        # with the dns resolver. 
        if sys.platform == "win32":
            loop = asyncio.SelectorEventLoop()
            asyncio.set_event_loop(loop)
        else:
            loop = asyncio.new_event_loop()
        yield loop
    loop.close()


@pytest.mark.asyncio
async def test_dns_a():
    async with DNSResolver(["8.8.8.8", "8.8.4.4"]) as dns:
        t = await dns.query("google.com", "A")
    assert t

@pytest.mark.asyncio
async def test_dns_aaaa():
    async with DNSResolver(["8.8.8.8", "8.8.4.4"]) as dns:
        t = await dns.query("google.com", "AAAA")
    assert t

Nevermind I seem to have found one. It's not a pretty solution because I've isolated this to one module since the library I'm using this with only needs asyncio for one module, however I stand by my words of proposing updating the documentation to something that is not deprecated. Nope it's still broken.

I'm gonna try migrating to unittest.IsolatedAsyncioTestCase for the time being.