Previous to Python 3.5.3,
asyncio.get_event_loop() was not reliable, so users were
forced to explicitly pass the event loop instance everywhere.
If a future object were created for one event loop
(e.g. the default loop) but a coroutine was run by another loop, the coroutine
was never awaited. As a result, the task would hang.

Keep in mind that every internal await expression either passed
instantly or paused, waiting for a future.

It’s extremely important that all tasks (coroutine runners) and
futures use the same event loop.

asyncdefecho_handler(request):ws=web.WebSocketResponse()user_id=authenticate_user(request)awaitws.prepare(request)request.app['websockets'][user_id].add(ws)try:asyncformsginws:ws.send_str(msg.data)finally:request.app['websockets'][user_id].remove(ws)returnwsasyncdeflogout_handler(request):user_id=authenticate_user(request)ws_closers=[ws.close()forwsinrequest.app['websockets'][user_id]ifnotws.closed]# Watch out, this will keep us from returing the response# until all are closedws_closersandawaitasyncio.gather(*ws_closers)returnweb.Response(text='OK')defmain():loop=asyncio.get_event_loop()app=web.Application(loop=loop)app.router.add_route('GET','/echo',echo_handler)app.router.add_route('POST','/logout',logout_handler)app['websockets']=defaultdict(set)web.run_app(app,host='localhost',port=8080)

Obsolete attributes and methods are marked as deprecated in the
documentation and raise DeprecationWarning upon usage.

Assume aiohttp X.Y.Z where X is major version,
Y is minor version and Z is bugfix number.

For example, if the latest released version is aiohttp==3.0.6:

3.0.7 fixes some bugs but have no new features.

3.1.0 introduces new features and can deprecate some API but never
remove it, also all bug fixes from previous release are merged.

4.0.0 removes all deprecations collected from 3.Y versions
except deprecations from the last3.Y release. These
deprecations will be removed by 5.0.0.

Unfortunately we may have to break these rules when a security
vulnerability is found.
If a security problem cannot be fixed without breaking backward
compatibility, a bugfix release may break compatibility. This is unlikely, but
possible.

All backward incompatible changes are explicitly marked in
the changelog.

aiohttp.ClientSession should be created once for the lifetime
of the server in order to benefit from connection pooling.

Sessions save cookies internally. If you don’t need cookie processing,
use aiohttp.DummyCookieJar. If you need separate cookies
for different http calls but process them in logical chains, use a single
aiohttp.TCPConnector with separate
client sessions and own_connector=False.

Middlewares can be written to handle post-response operations, but
they run after every request. You can explicitly send the response by
calling aiohttp.web.Response.write_eof(), which starts sending
before the handler returns, giving you a chance to execute follow-up
operations:

Sometimes your middleware handlers might need to send a custom response.
This is just fine as long as you always create a new
aiohttp.web.Response object when required.

The response object is a Finite State Machine. Once it has been dispatched
by the server, it will reach its final state and cannot be used again.

The following middleware will make the server hang, once it serves the second
response:

fromaiohttpimportwebdefmisbehaved_middleware():# don't do this!cached=web.Response(status=200,text='Hi, I am cached!')@web.middlewareasyncdefmiddleware(request,handler):# ignoring response for the sake of this example_res=handler(request)returncachedreturnmiddleware

Short answer is: life-cycle of all asyncio objects should be shorter
than life-cycle of event loop.

Full explanation is longer. All asyncio object should be correctly
finished/disconnected/closed before event loop shutdown. Otherwise
user can get unexpected behavior. In the best case it is a warning
about unclosed resource, in the worst case the program just hangs,
awaiting for coroutine is never resumed etc.

The code is broken: session is bound to default asyncio loop
on import time but the loop is changed after the import by
set_event_loop(). As result fetch() call hangs.

To avoid import dependency hell aiohttp encourages creation of
ClientSession from async function. The same policy works for
web.Application too.

Another use case is unit test writing. Very many test libraries
(aiohttp test tools first) creates a new loop instance for every
test function execution. It’s done for sake of tests isolation.
Otherwise pending activity (timers, network packets etc.) from
previous test may interfere with current one producing very cryptic
and unstable test failure.

Note: class variables are hidden globals actually. The following
code has the same problem as mod.py example, session variable
is the hidden global object: