import asyncio import contextlib import warnings from collections.abc import Callable import pytest from aiohttp.helpers import PY_37, isasyncgenfunction from aiohttp.web import Application from .test_utils import ( BaseTestServer, RawTestServer, TestClient, TestServer, loop_context, setup_test_loop, teardown_test_loop, unused_port as _unused_port, ) try: import uvloop except ImportError: # pragma: no cover uvloop = None try: import tokio except ImportError: # pragma: no cover tokio = None def pytest_addoption(parser): # type: ignore parser.addoption( "--aiohttp-fast", action="store_true", default=False, help="run tests faster by disabling extra checks", ) parser.addoption( "--aiohttp-loop", action="store", default="pyloop", help="run tests with specific loop: pyloop, uvloop, tokio or all", ) parser.addoption( "--aiohttp-enable-loop-debug", action="store_true", default=False, help="enable event loop debug mode", ) def pytest_fixture_setup(fixturedef): # type: ignore """ Allow fixtures to be coroutines. Run coroutine fixtures in an event loop. """ func = fixturedef.func if isasyncgenfunction(func): # async generator fixture is_async_gen = True elif asyncio.iscoroutinefunction(func): # regular async fixture is_async_gen = False else: # not an async fixture, nothing to do return strip_request = False if "request" not in fixturedef.argnames: fixturedef.argnames += ("request",) strip_request = True def wrapper(*args, **kwargs): # type: ignore request = kwargs["request"] if strip_request: del kwargs["request"] # if neither the fixture nor the test use the 'loop' fixture, # 'getfixturevalue' will fail because the test is not parameterized # (this can be removed someday if 'loop' is no longer parameterized) if "loop" not in request.fixturenames: raise Exception( "Asynchronous fixtures must depend on the 'loop' fixture or " "be used in tests depending from it." ) _loop = request.getfixturevalue("loop") if is_async_gen: # for async generators, we need to advance the generator once, # then advance it again in a finalizer gen = func(*args, **kwargs) def finalizer(): # type: ignore try: return _loop.run_until_complete(gen.__anext__()) except StopAsyncIteration: pass request.addfinalizer(finalizer) return _loop.run_until_complete(gen.__anext__()) else: return _loop.run_until_complete(func(*args, **kwargs)) fixturedef.func = wrapper @pytest.fixture def fast(request): # type: ignore """--fast config option""" return request.config.getoption("--aiohttp-fast") @pytest.fixture def loop_debug(request): # type: ignore """--enable-loop-debug config option""" return request.config.getoption("--aiohttp-enable-loop-debug") @contextlib.contextmanager def _runtime_warning_context(): # type: ignore """ Context manager which checks for RuntimeWarnings, specifically to avoid "coroutine 'X' was never awaited" warnings being missed. If RuntimeWarnings occur in the context a RuntimeError is raised. """ with warnings.catch_warnings(record=True) as _warnings: yield rw = [ "{w.filename}:{w.lineno}:{w.message}".format(w=w) for w in _warnings if w.category == RuntimeWarning ] if rw: raise RuntimeError( "{} Runtime Warning{},\n{}".format( len(rw), "" if len(rw) == 1 else "s", "\n".join(rw) ) ) @contextlib.contextmanager def _passthrough_loop_context(loop, fast=False): # type: ignore """ setups and tears down a loop unless one is passed in via the loop argument when it's passed straight through. """ if loop: # loop already exists, pass it straight through yield loop else: # this shadows loop_context's standard behavior loop = setup_test_loop() yield loop teardown_test_loop(loop, fast=fast) def pytest_pycollect_makeitem(collector, name, obj): # type: ignore """ Fix pytest collecting for coroutines. """ if collector.funcnamefilter(name) and asyncio.iscoroutinefunction(obj): return list(collector._genfunctions(name, obj)) def pytest_pyfunc_call(pyfuncitem): # type: ignore """ Run coroutines in an event loop instead of a normal function call. """ fast = pyfuncitem.config.getoption("--aiohttp-fast") if asyncio.iscoroutinefunction(pyfuncitem.function): existing_loop = pyfuncitem.funcargs.get( "proactor_loop" ) or pyfuncitem.funcargs.get("loop", None) with _runtime_warning_context(): with _passthrough_loop_context(existing_loop, fast=fast) as _loop: testargs = { arg: pyfuncitem.funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames } _loop.run_until_complete(pyfuncitem.obj(**testargs)) return True def pytest_generate_tests(metafunc): # type: ignore if "loop_factory" not in metafunc.fixturenames: return loops = metafunc.config.option.aiohttp_loop avail_factories = {"pyloop": asyncio.DefaultEventLoopPolicy} if uvloop is not None: # pragma: no cover avail_factories["uvloop"] = uvloop.EventLoopPolicy if tokio is not None: # pragma: no cover avail_factories["tokio"] = tokio.EventLoopPolicy if loops == "all": loops = "pyloop,uvloop?,tokio?" factories = {} # type: ignore for name in loops.split(","): required = not name.endswith("?") name = name.strip(" ?") if name not in avail_factories: # pragma: no cover if required: raise ValueError( "Unknown loop '%s', available loops: %s" % (name, list(factories.keys())) ) else: continue factories[name] = avail_factories[name] metafunc.parametrize( "loop_factory", list(factories.values()), ids=list(factories.keys()) ) @pytest.fixture def loop(loop_factory, fast, loop_debug): # type: ignore """Return an instance of the event loop.""" policy = loop_factory() asyncio.set_event_loop_policy(policy) with loop_context(fast=fast) as _loop: if loop_debug: _loop.set_debug(True) # pragma: no cover asyncio.set_event_loop(_loop) yield _loop @pytest.fixture def proactor_loop(): # type: ignore if not PY_37: policy = asyncio.get_event_loop_policy() policy._loop_factory = asyncio.ProactorEventLoop # type: ignore else: policy = asyncio.WindowsProactorEventLoopPolicy() # type: ignore asyncio.set_event_loop_policy(policy) with loop_context(policy.new_event_loop) as _loop: asyncio.set_event_loop(_loop) yield _loop @pytest.fixture def unused_port(aiohttp_unused_port): # type: ignore # pragma: no cover warnings.warn( "Deprecated, use aiohttp_unused_port fixture instead", DeprecationWarning, stacklevel=2, ) return aiohttp_unused_port @pytest.fixture def aiohttp_unused_port(): # type: ignore """Return a port that is unused on the current host.""" return _unused_port @pytest.fixture def aiohttp_server(loop): # type: ignore """Factory to create a TestServer instance, given an app. aiohttp_server(app, **kwargs) """ servers = [] async def go(app, *, port=None, **kwargs): # type: ignore server = TestServer(app, port=port) await server.start_server(loop=loop, **kwargs) servers.append(server) return server yield go async def finalize(): # type: ignore while servers: await servers.pop().close() loop.run_until_complete(finalize()) @pytest.fixture def test_server(aiohttp_server): # type: ignore # pragma: no cover warnings.warn( "Deprecated, use aiohttp_server fixture instead", DeprecationWarning, stacklevel=2, ) return aiohttp_server @pytest.fixture def aiohttp_raw_server(loop): # type: ignore """Factory to create a RawTestServer instance, given a web handler. aiohttp_raw_server(handler, **kwargs) """ servers = [] async def go(handler, *, port=None, **kwargs): # type: ignore server = RawTestServer(handler, port=port) await server.start_server(loop=loop, **kwargs) servers.append(server) return server yield go async def finalize(): # type: ignore while servers: await servers.pop().close() loop.run_until_complete(finalize()) @pytest.fixture def raw_test_server(aiohttp_raw_server): # type: ignore # pragma: no cover warnings.warn( "Deprecated, use aiohttp_raw_server fixture instead", DeprecationWarning, stacklevel=2, ) return aiohttp_raw_server @pytest.fixture def aiohttp_client(loop): # type: ignore """Factory to create a TestClient instance. aiohttp_client(app, **kwargs) aiohttp_client(server, **kwargs) aiohttp_client(raw_server, **kwargs) """ clients = [] async def go(__param, *args, server_kwargs=None, **kwargs): # type: ignore if isinstance(__param, Callable) and not isinstance( # type: ignore __param, (Application, BaseTestServer) ): __param = __param(loop, *args, **kwargs) kwargs = {} else: assert not args, "args should be empty" if isinstance(__param, Application): server_kwargs = server_kwargs or {} server = TestServer(__param, loop=loop, **server_kwargs) client = TestClient(server, loop=loop, **kwargs) elif isinstance(__param, BaseTestServer): client = TestClient(__param, loop=loop, **kwargs) else: raise ValueError("Unknown argument type: %r" % type(__param)) await client.start_server() clients.append(client) return client yield go async def finalize(): # type: ignore while clients: await clients.pop().close() loop.run_until_complete(finalize()) @pytest.fixture def test_client(aiohttp_client): # type: ignore # pragma: no cover warnings.warn( "Deprecated, use aiohttp_client fixture instead", DeprecationWarning, stacklevel=2, ) return aiohttp_client
Name | Type | Size | Permission | Actions |
---|---|---|---|---|
.hash | Folder | 0755 |
|
|
__pycache__ | Folder | 0755 |
|
|
__init__.py | File | 6.77 KB | 0644 |
|
_cparser.pxd | File | 3.87 KB | 0644 |
|
_find_header.c | File | 183.17 KB | 0644 |
|
_find_header.h | File | 170 B | 0644 |
|
_find_header.pxd | File | 68 B | 0644 |
|
_frozenlist.c | File | 287.3 KB | 0644 |
|
_frozenlist.cpython-38-x86_64-linux-gnu.so | File | 337.8 KB | 0755 |
|
_frozenlist.pyx | File | 2.54 KB | 0644 |
|
_headers.pxi | File | 1.96 KB | 0644 |
|
_helpers.c | File | 207.02 KB | 0644 |
|
_helpers.cpython-38-x86_64-linux-gnu.so | File | 223.16 KB | 0755 |
|
_helpers.pyi | File | 202 B | 0644 |
|
_helpers.pyx | File | 1.02 KB | 0644 |
|
_http_parser.c | File | 987.82 KB | 0644 |
|
_http_parser.cpython-38-x86_64-linux-gnu.so | File | 2.17 MB | 0755 |
|
_http_parser.pyx | File | 28.34 KB | 0644 |
|
_http_writer.c | File | 208.03 KB | 0644 |
|
_http_writer.cpython-38-x86_64-linux-gnu.so | File | 199.89 KB | 0755 |
|
_http_writer.pyx | File | 4.1 KB | 0644 |
|
_websocket.c | File | 134.21 KB | 0644 |
|
_websocket.cpython-38-x86_64-linux-gnu.so | File | 98.52 KB | 0755 |
|
_websocket.pyx | File | 1.52 KB | 0644 |
|
abc.py | File | 5.12 KB | 0644 |
|
base_protocol.py | File | 2.64 KB | 0644 |
|
client.py | File | 42.89 KB | 0644 |
|
client_exceptions.py | File | 8.33 KB | 0644 |
|
client_proto.py | File | 7.97 KB | 0644 |
|
client_reqrep.py | File | 35.58 KB | 0644 |
|
client_ws.py | File | 10.05 KB | 0644 |
|
connector.py | File | 41.96 KB | 0644 |
|
cookiejar.py | File | 11.88 KB | 0644 |
|
formdata.py | File | 5.94 KB | 0644 |
|
frozenlist.py | File | 1.68 KB | 0644 |
|
frozenlist.pyi | File | 1.4 KB | 0644 |
|
hdrs.py | File | 3.37 KB | 0644 |
|
helpers.py | File | 22.38 KB | 0644 |
|
http.py | File | 1.78 KB | 0644 |
|
http_exceptions.py | File | 2.53 KB | 0644 |
|
http_parser.py | File | 30.06 KB | 0644 |
|
http_websocket.py | File | 24.51 KB | 0644 |
|
http_writer.py | File | 5.22 KB | 0644 |
|
locks.py | File | 1.19 KB | 0644 |
|
log.py | File | 325 B | 0644 |
|
multipart.py | File | 31.5 KB | 0644 |
|
payload.py | File | 13.02 KB | 0644 |
|
payload_streamer.py | File | 2.05 KB | 0644 |
|
py.typed | File | 7 B | 0644 |
|
pytest_plugin.py | File | 10.75 KB | 0644 |
|
resolver.py | File | 4.5 KB | 0644 |
|
signals.py | File | 852 B | 0644 |
|
signals.pyi | File | 319 B | 0644 |
|
streams.py | File | 20.05 KB | 0644 |
|
tcp_helpers.py | File | 962 B | 0644 |
|
test_utils.py | File | 19.78 KB | 0644 |
|
tracing.py | File | 14.03 KB | 0644 |
|
typedefs.py | File | 1.34 KB | 0644 |
|
web.py | File | 17.46 KB | 0644 |
|
web_app.py | File | 16.65 KB | 0644 |
|
web_exceptions.py | File | 9.87 KB | 0644 |
|
web_fileresponse.py | File | 8.81 KB | 0644 |
|
web_log.py | File | 7.32 KB | 0644 |
|
web_middlewares.py | File | 4.09 KB | 0644 |
|
web_protocol.py | File | 22.71 KB | 0644 |
|
web_request.py | File | 25.83 KB | 0644 |
|
web_response.py | File | 25.59 KB | 0644 |
|
web_routedef.py | File | 5.97 KB | 0644 |
|
web_runner.py | File | 10.93 KB | 0644 |
|
web_server.py | File | 2.01 KB | 0644 |
|
web_urldispatcher.py | File | 38.61 KB | 0644 |
|
web_ws.py | File | 16.39 KB | 0644 |
|
worker.py | File | 7.83 KB | 0644 |
|