Skip to content

Commit a8b13ab

Browse files
committed
Merge pull request #245 from KeepSafe/multidict-error
Fix multidict error
2 parents a084fde + 39f7122 commit a8b13ab

File tree

9 files changed

+76
-45
lines changed

9 files changed

+76
-45
lines changed

aiohttp/_multidict.pyx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,22 +198,31 @@ cdef class MultiDict(_Base):
198198
" ({} given)".format(name, len(args)))
199199

200200
if args:
201-
if hasattr(args[0], 'items'):
202-
for item in args[0].items():
203-
key, value = item
204-
key = self._upper(key)
201+
arg = args[0]
202+
if isinstance(arg, _Base):
203+
for item in (<_Base>arg)._items:
204+
key = self._upper(item[0])
205+
value = item[1]
206+
if do_add:
207+
self._add(key, value)
208+
else:
209+
self._replace(key, value)
210+
elif hasattr(arg, 'items'):
211+
for item in arg.items():
212+
key = self._upper(item[0])
213+
value = item[1]
205214
if do_add:
206215
self._add(key, value)
207216
else:
208217
self._replace(key, value)
209218
else:
210-
for arg in args[0]:
211-
if not len(arg) == 2:
219+
for i in arg:
220+
if not len(i) == 2:
212221
raise TypeError(
213222
"{} takes either dict or list of (key, value) "
214223
"tuples".format(name))
215-
key, value = arg
216-
key = self._upper(key)
224+
key = self._upper(i[0])
225+
value = i[1]
217226
if do_add:
218227
self._add(key, value)
219228
else:

aiohttp/errors.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'ClientError', 'ClientHttpProcessingError', 'ClientConnectionError',
1111
'ClientOSError', 'ClientTimeoutError', 'ProxyConnectionError',
12-
'ClientRequestError', 'ClientResponseError', 'WebSocketDisconnectedError']
12+
'ClientRequestError', 'ClientResponseError', 'WSClientDisconnectedError']
1313

1414
from asyncio import TimeoutError
1515

@@ -26,8 +26,8 @@ class ServerDisconnectedError(DisconnectedError):
2626
"""Server disconnected."""
2727

2828

29-
class WebSocketDisconnectedError(ClientDisconnectedError):
30-
"""Raised on closing websocket by peer."""
29+
class WSClientDisconnectedError(ClientDisconnectedError):
30+
"""Raised on closing server websocket."""
3131

3232
def __init__(self, code=None, message=None):
3333
super().__init__(code, message)

aiohttp/multidict.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -174,20 +174,26 @@ def _extend(self, args, kwargs, name, method):
174174
raise TypeError("{} takes at most 1 positional argument"
175175
" ({} given)".format(name, len(args)))
176176
if args:
177+
arg = args[0]
177178
if isinstance(args[0], _MultiDictProxy):
178-
items = args[0].items()
179+
items = arg._items
179180
elif isinstance(args[0], _MultiDict):
180-
items = args[0].items()
181-
elif hasattr(args[0], 'items'):
182-
items = args[0].items()
181+
items = arg._items
182+
elif hasattr(arg, 'items'):
183+
items = arg.items()
183184
else:
184-
items = args[0]
185-
186-
for item in items:
187-
method(*item)
188-
189-
for item in kwargs.items():
190-
method(*item)
185+
for item in arg:
186+
if not len(item) == 2:
187+
raise TypeError(
188+
"{} takes either dict or list of (key, value) "
189+
"tuples".format(name))
190+
items = arg
191+
192+
for key, value in items:
193+
method(key, value)
194+
195+
for key, value in kwargs.items():
196+
method(key, value)
191197

192198
def clear(self):
193199
"""Remove all items from MultiDict"""

aiohttp/web.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
from .server import ServerHttpProtocol
2626
from .streams import EOF_MARKER
2727
from .websocket import do_handshake, MSG_BINARY, MSG_CLOSE, MSG_PING, MSG_TEXT
28-
from .errors import HttpProcessingError, WebSocketDisconnectedError
28+
from .errors import HttpProcessingError, WSClientDisconnectedError
2929

3030

3131
__all__ = [
32-
'WebSocketDisconnectedError',
32+
'WSClientDisconnectedError',
3333
'Application',
3434
'HttpVersion',
3535
'RequestHandler',
@@ -831,14 +831,14 @@ def receive_msg(self):
831831

832832
if msg.tp == MSG_CLOSE:
833833
if self._closing:
834-
exc = WebSocketDisconnectedError(msg.data, msg.extra)
834+
exc = WSClientDisconnectedError(msg.data, msg.extra)
835835
self._closing_fut.set_exception(exc)
836836
raise exc
837837
else:
838838
self._closing = True
839839
self._writer.close(msg.data, msg.extra)
840840
yield from self.drain()
841-
exc = WebSocketDisconnectedError(msg.data, msg.extra)
841+
exc = WSClientDisconnectedError(msg.data, msg.extra)
842842
self._closing_fut.set_exception(exc)
843843
raise exc
844844
elif not self._closing:

examples/web_ws.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import asyncio
66
import os
77
from aiohttp.web import (Application, Response,
8-
WebSocketResponse, WebSocketDisconnectedError)
8+
WebSocketResponse, WSClientDisconnectedError)
99

1010
WS_FILE = os.path.join(os.path.dirname(__file__), 'websocket.html')
1111

@@ -31,7 +31,7 @@ def wshandler(request):
3131
for ws in request.app['sockets']:
3232
if ws is not resp:
3333
ws.send_str(msg)
34-
except WebSocketDisconnectedError:
34+
except WSClientDisconnectedError:
3535
if resp not in request.app['sockets']:
3636
return resp
3737
request.app['sockets'].remove(resp)

tests/test_multidict.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class _Root:
2525

2626
proxy_cls = None
2727

28+
upstr_cls = None
29+
2830
def test_exposed_names(self):
2931
name = self.cls.__name__
3032
while name.startswith('_'):
@@ -282,6 +284,16 @@ def test_get(self):
282284
self.assertEqual(1, d['a'])
283285

284286

287+
class _NonProxyCIMultiDict(_CIMultiDictTests):
288+
289+
def test_extend_with_upstr(self):
290+
us = self.upstr_cls('a')
291+
d = self.make_dict()
292+
293+
d.extend([(us, 'val')])
294+
self.assertEqual([('A', 'val')], list(d.items()))
295+
296+
285297
class _TestProxy(_MultiDictTests):
286298

287299
def make_dict(self, *args, **kwargs):
@@ -671,9 +683,11 @@ class PyMutableMultiDictTests(_BaseMutableMultiDictTests, unittest.TestCase):
671683
proxy_cls = _MultiDictProxy
672684

673685

674-
class PyCIMutableMultiDictTests(_CIMutableMultiDictTests, unittest.TestCase):
686+
class PyCIMutableMultiDictTests(_CIMutableMultiDictTests, _NonProxyCIMultiDict,
687+
unittest.TestCase):
675688

676689
cls = _CIMultiDict
690+
upstr_cls = _upstr
677691
proxy_cls = _CIMultiDictProxy
678692

679693

@@ -683,7 +697,7 @@ class TestMultiDictProxy(_TestProxy, unittest.TestCase):
683697
proxy_cls = MultiDictProxy
684698

685699

686-
class TestCIMultiDictProxt(_TestCIProxy, unittest.TestCase):
700+
class TestCIMultiDictProxy(_TestCIProxy, unittest.TestCase):
687701

688702
cls = CIMultiDict
689703
proxy_cls = CIMultiDictProxy
@@ -695,9 +709,11 @@ class MutableMultiDictTests(_BaseMutableMultiDictTests, unittest.TestCase):
695709
proxy_cls = MultiDictProxy
696710

697711

698-
class CIMutableMultiDictTests(_CIMutableMultiDictTests, unittest.TestCase):
712+
class CIMutableMultiDictTests(_CIMutableMultiDictTests, _NonProxyCIMultiDict,
713+
unittest.TestCase):
699714

700715
cls = CIMultiDict
716+
upstr_cls = upstr
701717
proxy_cls = CIMultiDictProxy
702718

703719

tests/test_web_response.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def test_force_compression_no_accept(self, ResponseImpl):
173173
def test_compression(self, ResponseImpl):
174174
req = self.make_request(
175175
'GET', '/',
176-
headers=CIMultiDict({str(hdrs.ACCEPT_ENCODING): 'gzip, deflate'}))
176+
headers=CIMultiDict({hdrs.ACCEPT_ENCODING: 'gzip, deflate'}))
177177
resp = StreamResponse()
178178
self.assertFalse(resp.chunked)
179179

tests/test_web_websocket.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from unittest import mock
44
from aiohttp import CIMultiDict
55
from aiohttp.web import (Request, WebSocketResponse,
6-
WebSocketDisconnectedError,
6+
WSClientDisconnectedError,
77
HTTPMethodNotAllowed, HTTPBadRequest)
88
from aiohttp.protocol import RawRequestMessage, HttpVersion11
99
from aiohttp import websocket
@@ -145,7 +145,7 @@ def test_nested_exception(self):
145145

146146
@asyncio.coroutine
147147
def a():
148-
raise WebSocketDisconnectedError()
148+
raise WSClientDisconnectedError()
149149

150150
@asyncio.coroutine
151151
def b():
@@ -155,7 +155,7 @@ def b():
155155
def c():
156156
yield from b()
157157

158-
with self.assertRaises(WebSocketDisconnectedError):
158+
with self.assertRaises(WSClientDisconnectedError):
159159
self.loop.run_until_complete(c())
160160

161161
def test_can_start_ok(self):

tests/test_web_websocket_functional.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def handler(request):
9292
ws.close()
9393
try:
9494
yield from ws.receive_str()
95-
except web.WebSocketDisconnectedError:
95+
except web.WSClientDisconnectedError:
9696
closed.set_result(None)
9797
return ws
9898

@@ -155,7 +155,7 @@ def handler(request):
155155

156156
try:
157157
yield from ws.receive_str()
158-
except web.WebSocketDisconnectedError as exc:
158+
except web.WSClientDisconnectedError as exc:
159159
self.assertEqual(1, exc.code)
160160
self.assertEqual(b'exit message', exc.message)
161161
closed.set_result(None)
@@ -185,7 +185,7 @@ def handler(request):
185185
ws.ping('data')
186186
try:
187187
yield from ws.receive_str()
188-
except web.WebSocketDisconnectedError as exc:
188+
except web.WSClientDisconnectedError as exc:
189189
self.assertEqual(2, exc.code)
190190
self.assertEqual(b'exit message', exc.message)
191191
closed.set_result(None)
@@ -215,7 +215,7 @@ def handler(request):
215215

216216
try:
217217
yield from ws.receive_str()
218-
except web.WebSocketDisconnectedError:
218+
except web.WSClientDisconnectedError:
219219
closed.set_result(None)
220220
raise
221221

@@ -245,7 +245,7 @@ def handler(request):
245245
ws.pong('data')
246246
try:
247247
yield from ws.receive_str()
248-
except web.WebSocketDisconnectedError as exc:
248+
except web.WSClientDisconnectedError as exc:
249249
self.assertEqual(2, exc.code)
250250
self.assertEqual(b'exit message', exc.message)
251251
closed.set_result(None)
@@ -318,7 +318,7 @@ def handler(request):
318318
ws.close()
319319
try:
320320
yield from ws.receive_str()
321-
except web.WebSocketDisconnectedError:
321+
except web.WSClientDisconnectedError:
322322
closed.set_result(None)
323323
return ws
324324

@@ -344,7 +344,7 @@ def handler(request):
344344
ws.start(request)
345345
try:
346346
yield from ws.receive_str()
347-
except web.WebSocketDisconnectedError:
347+
except web.WSClientDisconnectedError:
348348
closed.set_result(None)
349349
return ws
350350

@@ -370,7 +370,7 @@ def closer(ws):
370370
ws.close()
371371
try:
372372
yield from ws.wait_closed()
373-
except web.WebSocketDisconnectedError:
373+
except web.WSClientDisconnectedError:
374374
closed2.set_result(None)
375375

376376
@asyncio.coroutine
@@ -380,7 +380,7 @@ def handler(request):
380380
asyncio.async(closer(ws), loop=request.app.loop)
381381
try:
382382
yield from ws.receive_str()
383-
except web.WebSocketDisconnectedError:
383+
except web.WSClientDisconnectedError:
384384
closed.set_result(None)
385385
return ws
386386

@@ -407,7 +407,7 @@ def handler(request):
407407
ws.close()
408408
try:
409409
yield from ws.receive_str()
410-
except web.WebSocketDisconnectedError:
410+
except web.WSClientDisconnectedError:
411411
closed.set_result(None)
412412
return ws
413413

0 commit comments

Comments
 (0)