Skip to content

Commit

Permalink
Sync from aiohttp (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreamsorcerer authored Oct 29, 2024
1 parent 98444cb commit 8887bfa
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 124 deletions.
27 changes: 27 additions & 0 deletions .mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[mypy]
files = pytest_aiohttp, tests
check_untyped_defs = True
follow_imports_for_stubs = True
disallow_any_decorated = True
disallow_any_generics = True
disallow_any_unimported = True
disallow_incomplete_defs = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_decorators = True
disallow_untyped_defs = True
# TODO(PY312): explicit-override
enable_error_code = ignore-without-code, possibly-undefined, redundant-expr, redundant-self, truthy-bool, truthy-iterable, unused-awaitable
extra_checks = True
implicit_reexport = False
no_implicit_optional = True
pretty = True
show_column_numbers = True
show_error_codes = True
show_error_code_links = True
strict_equality = True
warn_incomplete_stub = True
warn_redundant_casts = True
warn_return_any = True
warn_unreachable = True
warn_unused_ignores = True
125 changes: 78 additions & 47 deletions pytest_aiohttp/plugin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,59 @@
import asyncio
import warnings
from typing import Any, Awaitable, Callable, Dict, Generator, Optional, Type, Union
from typing import (
Any,
Awaitable,
Dict,
Iterator,
Optional,
Protocol,
Type,
TypeVar,
Union,
overload,
)

import pytest
import pytest_asyncio
from aiohttp.test_utils import BaseTestServer, RawTestServer, TestClient, TestServer
from aiohttp.web import Application, BaseRequest, StreamResponse
from aiohttp.web import Application, BaseRequest, Request
from aiohttp.web_protocol import _RequestHandler

_Request = TypeVar("_Request", bound=BaseRequest)


AiohttpClient = Callable[[Union[Application, BaseTestServer]], Awaitable[TestClient]]
class AiohttpClient(Protocol):
@overload
async def __call__(
self,
__param: Application,
*,
server_kwargs: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> TestClient[Request, Application]: ...

@overload
async def __call__(
self,
__param: BaseTestServer, # TODO(aiohttp4): BaseTestServer[_Request]
*,
server_kwargs: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> TestClient[_Request, None]: ...


class AiohttpServer(Protocol):
def __call__(
self, app: Application, *, port: Optional[int] = None, **kwargs: Any
) -> Awaitable[TestServer]: ...


class AiohttpRawServer(Protocol):
def __call__(
self,
handler: _RequestHandler, # TODO(aiohttp4): _RequestHandler[BaseRequest]
*,
port: Optional[int] = None,
**kwargs: Any,
) -> Awaitable[RawTestServer]: ...


LEGACY_MODE = DeprecationWarning(
Expand All @@ -28,41 +74,8 @@ def pytest_configure(config) -> None:
config.issue_config_time_warning(LEGACY_MODE, stacklevel=2)


@pytest.fixture
def loop(event_loop: asyncio.AbstractEventLoop) -> asyncio.AbstractEventLoop:
warnings.warn(
"'loop' fixture is deprecated and scheduled for removal, "
"please use 'event_loop' instead",
DeprecationWarning,
)
return event_loop


@pytest.fixture
def proactor_loop(event_loop: asyncio.AbstractEventLoop) -> asyncio.AbstractEventLoop:
warnings.warn(
"'proactor_loop' fixture is deprecated and scheduled for removal, "
"please use 'event_loop' instead",
DeprecationWarning,
)
return event_loop


@pytest.fixture
def aiohttp_unused_port(
unused_tcp_port_factory: Callable[[], int]
) -> Callable[[], int]:
warnings.warn(
"'aiohttp_unused_port' fixture is deprecated "
"and scheduled for removal, "
"please use 'unused_tcp_port_factory' instead",
DeprecationWarning,
)
return unused_tcp_port_factory


@pytest_asyncio.fixture
async def aiohttp_server() -> Callable[..., Awaitable[TestServer]]:
async def aiohttp_server() -> Iterator[AiohttpServer]:
"""Factory to create a TestServer instance, given an app.
aiohttp_server(app, **kwargs)
Expand All @@ -84,15 +97,15 @@ async def go(


@pytest_asyncio.fixture
async def aiohttp_raw_server() -> Callable[..., Awaitable[RawTestServer]]:
async def aiohttp_raw_server() -> Iterator[AiohttpRawServer]:
"""Factory to create a RawTestServer instance, given a web handler.
aiohttp_raw_server(handler, **kwargs)
"""
servers = []

async def go(
handler: Callable[[BaseRequest], Awaitable[StreamResponse]],
handler: _RequestHandler, # TODO(aiohttp4): _RequestHandler[BaseRequest]
*,
port: Optional[int] = None,
**kwargs: Any,
Expand All @@ -108,8 +121,8 @@ async def go(
await servers.pop().close()


@pytest.fixture
def aiohttp_client_cls() -> Type[TestClient]:
@pytest_asyncio.fixture
def aiohttp_client_cls() -> Type[TestClient[Any, Any]]:
"""
Client class to use in ``aiohttp_client`` factory.
Expand Down Expand Up @@ -137,8 +150,8 @@ def test_login(aiohttp_client):

@pytest_asyncio.fixture
async def aiohttp_client(
aiohttp_client_cls: Type[TestClient],
) -> Generator[AiohttpClient, None, None]:
aiohttp_client_cls: Type[TestClient[Any, Any]]
) -> Iterator[AiohttpClient]:
"""Factory to create a TestClient instance.
aiohttp_client(app, **kwargs)
Expand All @@ -147,12 +160,30 @@ async def aiohttp_client(
"""
clients = []

@overload
async def go(
__param: Application,
*,
server_kwargs: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> TestClient[Request, Application]: ...

@overload
async def go(
__param: BaseTestServer, # TODO(aiohttp4): BaseTestServer[_Request]
*,
server_kwargs: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> TestClient[_Request, None]: ...

async def go(
__param: Union[Application, BaseTestServer],
__param: Union[
Application, BaseTestServer
], # TODO(aiohttp4): BaseTestServer[Any]
*,
server_kwargs: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> TestClient:
) -> TestClient[Any, Any]:
if isinstance(__param, Application):
server_kwargs = server_kwargs or {}
server = TestServer(__param, **server_kwargs)
Expand Down
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ setup_requires =

install_requires =
pytest >= 6.1.0
aiohttp >= 3.8.1
aiohttp >= 3.11.0b0
pytest-asyncio >= 0.17.2

[options.extras_require]
testing =
coverage == 6.2
mypy == 0.931
mypy == 1.12.1

[options.entry_points]
pytest11 =
Expand Down
22 changes: 11 additions & 11 deletions tests/test_fixtures.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
from typing import Any
import pytest

pytest_plugins: str = "pytester"
pytest_plugins = "pytester"


def test_aiohttp_plugin(testdir: Any) -> None:
def test_aiohttp_plugin(testdir: pytest.Testdir) -> None:
testdir.makepyfile(
"""\
import pytest
from unittest import mock
from aiohttp import web
value = web.AppKey('value', str)
async def hello(request):
return web.Response(body=b'Hello, world')
Expand Down Expand Up @@ -54,11 +56,11 @@ async def test_noop() -> None:
async def previous(request):
if request.method == 'POST':
with pytest.warns(DeprecationWarning):
request.app['value'] = (await request.post())['value']
with pytest.deprecated_call(): # FIXME: this isn't actually called
request.app[value] = (await request.post())['value']
return web.Response(body=b'thanks for the data')
else:
v = request.app.get('value', 'unknown')
v = request.app.get(value, 'unknown')
return web.Response(body='value: {}'.format(v).encode())
Expand Down Expand Up @@ -100,14 +102,13 @@ async def test_custom_port_test_server(aiohttp_server, unused_tcp_port):
app = await create_app()
server = await aiohttp_server(app, port=unused_tcp_port)
assert server.port == unused_tcp_port
"""
)
result = testdir.runpytest("--asyncio-mode=auto")
result.assert_outcomes(passed=8)


def test_aiohttp_raw_server(testdir: Any) -> None:
def test_aiohttp_raw_server(testdir: pytest.Testdir) -> None:
testdir.makepyfile(
"""\
import pytest
Expand Down Expand Up @@ -135,14 +136,13 @@ async def test_hello(cli) -> None:
assert resp.status == 200
text = await resp.text()
assert 'OK' in text
"""
)
result = testdir.runpytest("--asyncio-mode=auto")
result.assert_outcomes(passed=1)


def test_aiohttp_client_cls_fixture_custom_client_used(testdir: Any) -> None:
def test_aiohttp_client_cls_fixture_custom_client_used(testdir: pytest.Testdir) -> None:
testdir.makepyfile(
"""
import pytest
Expand All @@ -169,7 +169,7 @@ async def test_hello(aiohttp_client) -> None:
result.assert_outcomes(passed=1)


def test_aiohttp_client_cls_fixture_factory(testdir: Any) -> None:
def test_aiohttp_client_cls_fixture_factory(testdir: pytest.Testdir) -> None:
testdir.makeconftest(
"""\
Expand Down
60 changes: 0 additions & 60 deletions tests/test_obsolete_fixtures.py

This file was deleted.

8 changes: 4 additions & 4 deletions tests/test_switch_mode.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Any
import pytest

from pytest_aiohttp.plugin import LEGACY_MODE

pytest_plugins: str = "pytester"


def test_warning_for_legacy_mode(testdir: Any) -> None:
def test_warning_for_legacy_mode(testdir: pytest.Testdir) -> None:
testdir.makepyfile(
"""\
async def test_a():
Expand All @@ -18,7 +18,7 @@ async def test_a():
result.stdout.fnmatch_lines(["*" + str(LEGACY_MODE) + "*"])


def test_auto_mode(testdir: Any) -> None:
def test_auto_mode(testdir: pytest.Testdir) -> None:
testdir.makepyfile(
"""\
async def test_a():
Expand All @@ -31,7 +31,7 @@ async def test_a():
result.stdout.no_fnmatch_line("*" + str(LEGACY_MODE) + "*")


def test_strict_mode(testdir: Any) -> None:
def test_strict_mode(testdir: pytest.Testdir) -> None:
testdir.makepyfile(
"""\
import pytest
Expand Down

0 comments on commit 8887bfa

Please sign in to comment.