diff --git a/docs/reference/changelog.rst b/docs/reference/changelog.rst index 11b3d811..4897188c 100644 --- a/docs/reference/changelog.rst +++ b/docs/reference/changelog.rst @@ -5,6 +5,8 @@ Changelog 0.26.0 (UNRELEASED) =================== - Adds configuration option that sets default event loop scope for all testss `#793 `_ +- Improved type annotations for ``pytest_asyncio.fixture`` `#1045 `_ +- Added ``typing-extensions`` as additional dependency for Python ``<3.10`` `#1045 `_ 0.25.2 (2025-01-08) diff --git a/pyproject.toml b/pyproject.toml index b89c24da..c503970e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ dynamic = [ dependencies = [ "pytest>=8.2,<9", + "typing-extensions>=4.12; python_version<'3.10'", ] optional-dependencies.docs = [ "sphinx>=5.3", diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 8f6d91dc..2ec504ff 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -9,6 +9,7 @@ import functools import inspect import socket +import sys import warnings from asyncio import AbstractEventLoop, AbstractEventLoopPolicy from collections.abc import ( @@ -53,17 +54,17 @@ StashKey, ) +if sys.version_info >= (3, 10): + from typing import ParamSpec +else: + from typing_extensions import ParamSpec + + _ScopeName = Literal["session", "package", "module", "class", "function"] _T = TypeVar("_T") - -SimpleFixtureFunction = TypeVar( - "SimpleFixtureFunction", bound=Callable[..., Awaitable[object]] -) -FactoryFixtureFunction = TypeVar( - "FactoryFixtureFunction", bound=Callable[..., AsyncIterator[object]] -) -FixtureFunction = Union[SimpleFixtureFunction, FactoryFixtureFunction] -FixtureFunctionMarker = Callable[[FixtureFunction], FixtureFunction] +_R = TypeVar("_R", bound=Union[Awaitable[Any], AsyncIterator[Any]]) +_P = ParamSpec("_P") +FixtureFunction = Callable[_P, _R] class PytestAsyncioError(Exception): @@ -117,7 +118,7 @@ def pytest_addoption(parser: Parser, pluginmanager: PytestPluginManager) -> None @overload def fixture( - fixture_function: FixtureFunction, + fixture_function: FixtureFunction[_P, _R], *, scope: _ScopeName | Callable[[str, Config], _ScopeName] = ..., loop_scope: _ScopeName | None = ..., @@ -129,7 +130,7 @@ def fixture( | None ) = ..., name: str | None = ..., -) -> FixtureFunction: ... +) -> FixtureFunction[_P, _R]: ... @overload @@ -146,14 +147,17 @@ def fixture( | None ) = ..., name: str | None = None, -) -> FixtureFunctionMarker: ... +) -> Callable[[FixtureFunction[_P, _R]], FixtureFunction[_P, _R]]: ... def fixture( - fixture_function: FixtureFunction | None = None, + fixture_function: FixtureFunction[_P, _R] | None = None, loop_scope: _ScopeName | None = None, **kwargs: Any, -) -> FixtureFunction | FixtureFunctionMarker: +) -> ( + FixtureFunction[_P, _R] + | Callable[[FixtureFunction[_P, _R]], FixtureFunction[_P, _R]] +): if fixture_function is not None: _make_asyncio_fixture_function(fixture_function, loop_scope) return pytest.fixture(fixture_function, **kwargs) @@ -161,7 +165,7 @@ def fixture( else: @functools.wraps(fixture) - def inner(fixture_function: FixtureFunction) -> FixtureFunction: + def inner(fixture_function: FixtureFunction[_P, _R]) -> FixtureFunction[_P, _R]: return fixture(fixture_function, loop_scope=loop_scope, **kwargs) return inner @@ -679,7 +683,7 @@ def pytest_pycollect_makeitem_convert_async_functions_to_subclass( # A stack used to push package-scoped loops during collection of a package # and pop those loops during collection of a Module -__package_loop_stack: list[FixtureFunctionMarker | FixtureFunction] = [] +__package_loop_stack: list[Callable[..., Any]] = [] @pytest.hookimpl