Skip to content

Commit

Permalink
Test that start_blocking_portal doesn't deadlock when used by async t…
Browse files Browse the repository at this point in the history
…hreads
  • Loading branch information
gschaffner committed Jan 13, 2023
1 parent 0cbb84b commit cd9deb1
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ test = [
"hypothesis >= 4.0",
"pytest >= 7.0",
"pytest-mock >= 3.6.1",
"pytest-timeout >= 2.0",
"trustme",
"uvloop >= 0.17; platform_python_implementation == 'CPython' and platform_system != 'Windows'",
]
Expand Down
30 changes: 30 additions & 0 deletions tests/test_from_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
from anyio.abc import TaskStatus
from anyio.from_thread import BlockingPortal, start_blocking_portal
from anyio.lowlevel import checkpoint
from anyio.pytest_plugin import anyio_backend_name, anyio_backend_options

from .conftest import anyio_backend

if sys.version_info >= (3, 8):
from typing import Literal
Expand Down Expand Up @@ -63,6 +66,23 @@ def thread_worker_sync(func: Callable[..., T_Retval], *args: Any) -> T_Retval:
return from_thread.run_sync(func, *args)


# Duplicate anyio_backend for BlockingPortal tests that need to be parametrized with
# pairs of backends.
portal_backend = anyio_backend


@pytest.fixture
def portal_backend_name(portal_backend: Any) -> str:
return anyio_backend_name.__wrapped__(portal_backend) # type: ignore[attr-defined]


@pytest.fixture
def portal_backend_options(portal_backend: Any) -> dict[str, Any]:
return anyio_backend_options.__wrapped__( # type: ignore[attr-defined]
portal_backend
)


class TestRunAsyncFromThread:
async def test_run_corofunc_from_thread(self) -> None:
result = await to_thread.run_sync(thread_worker_async, async_add, 1, 2)
Expand Down Expand Up @@ -524,3 +544,13 @@ async def raise_baseexception() -> None:
portal.call(raise_baseexception)

assert exc.value.__context__ is None

@pytest.mark.timeout(1)
async def test_from_async(
self, portal_backend_name: str, portal_backend_options: dict[str, Any]
) -> None:
"""Test that portals don't deadlock when started/used from async code."""
with start_blocking_portal(
portal_backend_name, portal_backend_options
) as portal:
portal.call(checkpoint)

0 comments on commit cd9deb1

Please sign in to comment.