Skip to content

Commit

Permalink
Fix #2363: Forbid synchronous context managers for ClientSession and …
Browse files Browse the repository at this point in the history
…test server/client.
  • Loading branch information
asvetlov committed Nov 20, 2017
1 parent 8e7985a commit e7d3f3c
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 100 deletions.
2 changes: 2 additions & 0 deletions CHANGES/2362.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Forbid synchronous context managers for `ClientSession` and test
server/client.
6 changes: 3 additions & 3 deletions aiohttp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,11 +711,11 @@ def detach(self):
self._connector = None

def __enter__(self):
warnings.warn("Use async with instead", DeprecationWarning)
return self
raise RuntimeError("Use async with instead")

def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
# __exit__ should exist in pair with __enter__ but never executed
pass # pragma: no cover

@asyncio.coroutine
def __aenter__(self):
Expand Down
12 changes: 6 additions & 6 deletions aiohttp/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ async def _close_hook(self):
pass # pragma: no cover

def __enter__(self):
self._loop.run_until_complete(self.start_server(loop=self._loop))
return self
raise RuntimeError("Use async with instead")

def __exit__(self, exc_type, exc_value, traceback):
self._loop.run_until_complete(self.close())
# __exit__ should exist in pair with __enter__ but never executed
pass # pragma: no cover

async def __aenter__(self):
await self.start_server(loop=self._loop)
Expand Down Expand Up @@ -317,11 +317,11 @@ async def close(self):
self._closed = True

def __enter__(self):
self._loop.run_until_complete(self.start_server())
return self
raise RuntimeError("Use async with instead")

def __exit__(self, exc_type, exc_value, traceback):
self._loop.run_until_complete(self.close())
# __exit__ should exist in pair with __enter__ but never executed
pass # pragma: no cover

async def __aenter__(self):
await self.start_server()
Expand Down
18 changes: 2 additions & 16 deletions tests/test_client_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import contextlib
import gc
import re
import types
from http.cookies import SimpleCookie
from unittest import mock

Expand Down Expand Up @@ -352,11 +351,11 @@ def test_del(connector, loop):


def test_context_manager(connector, loop):
with pytest.warns(DeprecationWarning):
with pytest.raises(RuntimeError):
with ClientSession(loop=loop, connector=connector) as session:
pass

assert session.closed
assert session.closed


def test_borrow_connector_loop(connector, create_session, loop):
Expand Down Expand Up @@ -386,19 +385,6 @@ async def create_connection(req, traces=None):
assert e.strerror == err.strerror


async def test_request_ctx_manager_props(loop):
await asyncio.sleep(0, loop=loop) # to make it a task
with pytest.warns(DeprecationWarning):
with aiohttp.ClientSession(loop=loop) as client:
ctx_mgr = client.get('http://example.com')

next(ctx_mgr)
assert isinstance(ctx_mgr.gi_frame, types.FrameType)
assert not ctx_mgr.gi_running
assert isinstance(ctx_mgr.gi_code, types.CodeType)
await asyncio.sleep(0.1, loop=loop)


async def test_cookie_jar_usage(loop, test_client):
req_url = None

Expand Down
96 changes: 21 additions & 75 deletions tests/test_test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ def _create_example_app():
async def hello(request):
return web.Response(body=_hello_world_bytes)

async def gzip_hello(request):
return web.Response(body=_hello_world_gz,
headers={'Content-Encoding': 'gzip'})

async def websocket_handler(request):

ws = web.WebSocketResponse()
Expand All @@ -47,7 +43,6 @@ async def cookie_handler(request):

app = web.Application()
app.router.add_route('*', '/', hello)
app.router.add_route('*', '/gzip_hello', gzip_hello)
app.router.add_route('*', '/websocket', websocket_handler)
app.router.add_route('*', '/cookie', cookie_handler)
return app
Expand All @@ -73,64 +68,18 @@ def test_client(loop, app):
loop.run_until_complete(client.close())


def test_full_server_scenario():
with loop_context() as loop:
app = _create_example_app()
with _TestClient(_TestServer(app, loop=loop), loop=loop) as client:

async def test_get_route():
nonlocal client
resp = await client.request("GET", "/")
assert resp.status == 200
text = await resp.text()
assert _hello_world_str == text

loop.run_until_complete(test_get_route())


def test_auto_gzip_decompress():
with loop_context() as loop:
app = _create_example_app()
with _TestClient(_TestServer(app, loop=loop), loop=loop) as client:

async def test_get_route():
nonlocal client
resp = await client.request("GET", "/gzip_hello")
assert resp.status == 200
data = await resp.read()
assert data == _hello_world_bytes

loop.run_until_complete(test_get_route())


def test_noauto_gzip_decompress():
with loop_context() as loop:
app = _create_example_app()
with _TestClient(_TestServer(app, loop=loop), loop=loop,
auto_decompress=False) as client:

async def test_get_route():
nonlocal client
resp = await client.request("GET", "/gzip_hello")
assert resp.status == 200
data = await resp.read()
assert data == _hello_world_gz

loop.run_until_complete(test_get_route())

def test_with_test_server_fails(loop):
app = _create_example_app()
with pytest.raises(RuntimeError):
with _TestServer(app, loop=loop):
pass

def test_server_with_create_test_teardown():
with loop_context() as loop:
app = _create_example_app()
with _TestClient(_TestServer(app, loop=loop), loop=loop) as client:

async def test_get_route():
resp = await client.request("GET", "/")
assert resp.status == 200
text = await resp.text()
assert _hello_world_str == text

loop.run_until_complete(test_get_route())
def test_with_test_client_fails(loop):
app = _create_example_app()
with pytest.raises(RuntimeError):
with _TestClient(_TestServer(app, loop=loop), loop=loop):
pass


def test_test_client_close_is_idempotent():
Expand Down Expand Up @@ -255,39 +204,36 @@ def test_make_mocked_request_transport():
assert req.transport is transport


def test_test_client_props(loop):
async def test_test_client_props(loop):
app = _create_example_app()
client = _TestClient(_TestServer(app, host='localhost', loop=loop),
loop=loop)
assert client.host == 'localhost'
assert client.port is None
with client:
async with client:
assert isinstance(client.port, int)
assert client.server is not None
assert client.port is None


def test_test_server_context_manager(loop):
async def test_test_server_context_manager(loop):
app = _create_example_app()
with _TestServer(app, loop=loop) as server:
async def go():
client = aiohttp.ClientSession(loop=loop)
resp = await client.head(server.make_url('/'))
assert resp.status == 200
resp.close()
client.close()

loop.run_until_complete(go())
async with _TestServer(app, loop=loop) as server:
client = aiohttp.ClientSession(loop=loop)
resp = await client.head(server.make_url('/'))
assert resp.status == 200
resp.close()
client.close()


def test_client_unsupported_arg():
with pytest.raises(TypeError):
_TestClient('string')


def test_server_make_url_yarl_compatibility(loop):
async def test_server_make_url_yarl_compatibility(loop):
app = _create_example_app()
with _TestServer(app, loop=loop) as server:
async with _TestServer(app, loop=loop) as server:
make_url = server.make_url
assert make_url(URL('/foo')) == make_url('/foo')
with pytest.raises(AssertionError):
Expand Down

0 comments on commit e7d3f3c

Please sign in to comment.