Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StreamResponse and Response implement MutableMapping interface #2494

Merged
merged 11 commits into from
Nov 24, 2017
1 change: 1 addition & 0 deletions CHANGES/2246.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
StreamResponse and Response are now MutableMappings.
19 changes: 18 additions & 1 deletion aiohttp/web_response.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import collections
import datetime
import enum
import json
Expand Down Expand Up @@ -33,7 +34,7 @@ class ContentCoding(enum.Enum):
############################################################


class StreamResponse(HeadersMixin):
class StreamResponse(collections.MutableMapping, HeadersMixin):

_length_check = True

Expand All @@ -49,6 +50,7 @@ def __init__(self, *, status=200, reason=None, headers=None):
self._payload_writer = None
self._eof_sent = False
self._body_length = 0
self._state = {}

if headers is not None:
self._headers = CIMultiDict(headers)
Expand Down Expand Up @@ -439,6 +441,21 @@ def __repr__(self):
return "<{} {} {}>".format(self.__class__.__name__,
self.reason, info)

def __getitem__(self, key):
return self._state[key]

def __setitem__(self, key, value):
self._state[key] = value

def __delitem__(self, key):
del self._state[key]

def __len__(self):
return len(self._state)

def __iter__(self):
return iter(self._state)


class Response(StreamResponse):

Expand Down
11 changes: 11 additions & 0 deletions docs/web_advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,17 @@ This is mostly useful for :ref:`aiohttp-web-middlewares` and
:ref:`aiohttp-web-signals` handlers to store data for further processing by the
next handlers in the chain.

:class:`aiohttp.web.StreamResponse` and :class:`aiohttp.web.Response` objects
also support :class:`collections.abc.MutableMapping` interface. This is useful
when you want to share data with signals and middlewares once all the work in
the handler is done::

async def handler(request):
[ do all the work ]
response['my_metric'] = 123
return response


To avoid clashing with other *aiohttp* users and third-party libraries, please
choose a unique key name for storing data.

Expand Down
10 changes: 10 additions & 0 deletions docs/web_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,16 @@ The common case for sending an answer from
def handler(request):
return Response("All right!")

Response classes are :obj:`dict` like objects,
allowing them to be used for :ref:`sharing
data<aiohttp-web-data-sharing>` among :ref:`aiohttp-web-middlewares`
and :ref:`aiohttp-web-signals` handlers::

resp['key'] = value

.. versionadded:: 3.0

Dict-like interface support.

StreamResponse
^^^^^^^^^^^^^^
Expand Down
29 changes: 29 additions & 0 deletions tests/test_web_response.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import collections
import datetime
import json
import re
Expand Down Expand Up @@ -76,6 +77,34 @@ def test_stream_response_ctor():
assert resp.task is req.task


def test_stream_response_is_mutable_mapping():
resp = StreamResponse()
assert isinstance(resp, collections.MutableMapping)
resp['key'] = 'value'
assert 'value' == resp['key']


def test_stream_response_delitem():
resp = StreamResponse()
resp['key'] = 'value'
del resp['key']
assert 'key' not in resp


def test_stream_response_len():
resp = StreamResponse()
assert len(resp) == 0
resp['key'] = 'value'
assert len(resp) == 1


def test_request_iter():
resp = StreamResponse()
resp['key'] = 'value'
resp['key2'] = 'value2'
assert set(resp) == {'key', 'key2'}


def test_content_length():
resp = StreamResponse()
assert resp.content_length is None
Expand Down