Skip to content

Commit 805d5f3

Browse files
Support the connect_error event in the client (Fixes #344)
1 parent b60bbc0 commit 805d5f3

File tree

9 files changed

+96
-21
lines changed

9 files changed

+96
-21
lines changed

docs/client.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,18 @@ or can also be coroutines::
6565
async def message(data):
6666
print('I received a message!')
6767

68-
The ``connect`` and ``disconnect`` events are special; they are invoked
69-
automatically when a client connects or disconnects from the server::
68+
The ``connect``, ``connect_error`` and ``disconnect`` events are special; they
69+
are invoked automatically when a client connects or disconnects from the
70+
server::
7071

7172
@sio.event
7273
def connect():
7374
print("I'm connected!")
7475

76+
@sio.event
77+
def connect_error():
78+
print("The connection failed!")
79+
7580
@sio.event
7681
def disconnect():
7782
print("I'm disconnected!")

socketio/asyncio_client.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,15 @@ async def _handle_ack(self, namespace, id, data):
348348
else:
349349
callback(*data)
350350

351-
def _handle_error(self, namespace):
351+
async def _handle_error(self, namespace, data):
352352
namespace = namespace or '/'
353353
self.logger.info('Connection to namespace {} was rejected'.format(
354354
namespace))
355+
if data is None:
356+
data = tuple()
357+
elif not isinstance(data, (tuple, list)):
358+
data = (data,)
359+
await self._trigger_event('connect_error', namespace, *data)
355360
if namespace in self.namespaces:
356361
self.namespaces.remove(namespace)
357362
if namespace == '/':
@@ -445,7 +450,7 @@ async def _handle_eio_message(self, data):
445450
pkt.packet_type == packet.BINARY_ACK:
446451
self._binary_packet = pkt
447452
elif pkt.packet_type == packet.ERROR:
448-
self._handle_error(pkt.namespace)
453+
await self._handle_error(pkt.namespace, pkt.data)
449454
else:
450455
raise ValueError('Unknown packet type.')
451456

socketio/asyncio_server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,6 @@ async def _handle_connect(self, sid, namespace):
403403
packet.ERROR, data=fail_reason, namespace=namespace))
404404
if sid in self.environ: # pragma: no cover
405405
del self.environ[sid]
406-
return False
407406
elif not self.always_connect:
408407
await self._send_packet(sid, packet.Packet(packet.CONNECT,
409408
namespace=namespace))

socketio/client.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,10 +504,15 @@ def _handle_ack(self, namespace, id, data):
504504
if callback is not None:
505505
callback(*data)
506506

507-
def _handle_error(self, namespace):
507+
def _handle_error(self, namespace, data):
508508
namespace = namespace or '/'
509509
self.logger.info('Connection to namespace {} was rejected'.format(
510510
namespace))
511+
if data is None:
512+
data = tuple()
513+
elif not isinstance(data, (tuple, list)):
514+
data = (data,)
515+
self._trigger_event('connect_error', namespace, *data)
511516
if namespace in self.namespaces:
512517
self.namespaces.remove(namespace)
513518
if namespace == '/':
@@ -591,7 +596,7 @@ def _handle_eio_message(self, data):
591596
pkt.packet_type == packet.BINARY_ACK:
592597
self._binary_packet = pkt
593598
elif pkt.packet_type == packet.ERROR:
594-
self._handle_error(pkt.namespace)
599+
self._handle_error(pkt.namespace, pkt.data)
595600
else:
596601
raise ValueError('Unknown packet type.')
597602

socketio/exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ConnectionRefusedError(ConnectionError):
1616
def __init__(self, *args):
1717
if len(args) == 0:
1818
self.error_args = None
19-
elif len(args) == 1:
19+
elif len(args) == 1 and not isinstance(args[0], list):
2020
self.error_args = args[0]
2121
else:
2222
self.error_args = args

socketio/server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,6 @@ def _handle_connect(self, sid, namespace):
613613
packet.ERROR, data=fail_reason, namespace=namespace))
614614
if sid in self.environ: # pragma: no cover
615615
del self.environ[sid]
616-
return False
617616
elif not self.always_connect:
618617
self._send_packet(sid, packet.Packet(packet.CONNECT,
619618
namespace=namespace))

tests/asyncio/test_asyncio_client.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -551,24 +551,50 @@ def test_handle_ack_not_found(self):
551551
def test_handle_error(self):
552552
c = asyncio_client.AsyncClient()
553553
c.connected = True
554+
c._trigger_event = AsyncMock()
555+
c.namespaces = ['/foo', '/bar']
556+
_run(c._handle_error('/', 'error'))
557+
self.assertEqual(c.namespaces, [])
558+
self.assertFalse(c.connected)
559+
c._trigger_event.mock.assert_called_once_with('connect_error', '/',
560+
'error')
561+
562+
def test_handle_error_with_no_arguments(self):
563+
c = asyncio_client.AsyncClient()
564+
c.connected = True
565+
c._trigger_event = AsyncMock()
554566
c.namespaces = ['/foo', '/bar']
555-
c._handle_error('/')
567+
_run(c._handle_error('/', None))
556568
self.assertEqual(c.namespaces, [])
557569
self.assertFalse(c.connected)
570+
c._trigger_event.mock.assert_called_once_with('connect_error', '/')
558571

559572
def test_handle_error_namespace(self):
560573
c = asyncio_client.AsyncClient()
561574
c.connected = True
562575
c.namespaces = ['/foo', '/bar']
563-
c._handle_error('/bar')
576+
c._trigger_event = AsyncMock()
577+
_run(c._handle_error('/bar', ['error', 'message']))
578+
self.assertEqual(c.namespaces, ['/foo'])
579+
self.assertTrue(c.connected)
580+
c._trigger_event.mock.assert_called_once_with('connect_error', '/bar',
581+
'error', 'message')
582+
583+
def test_handle_error_namespace_with_no_arguments(self):
584+
c = asyncio_client.AsyncClient()
585+
c.connected = True
586+
c.namespaces = ['/foo', '/bar']
587+
c._trigger_event = AsyncMock()
588+
_run(c._handle_error('/bar', None))
564589
self.assertEqual(c.namespaces, ['/foo'])
565590
self.assertTrue(c.connected)
591+
c._trigger_event.mock.assert_called_once_with('connect_error', '/bar')
566592

567593
def test_handle_error_unknown_namespace(self):
568594
c = asyncio_client.AsyncClient()
569595
c.connected = True
570596
c.namespaces = ['/foo', '/bar']
571-
c._handle_error('/baz')
597+
_run(c._handle_error('/baz', 'error'))
572598
self.assertEqual(c.namespaces, ['/foo', '/bar'])
573599
self.assertTrue(c.connected)
574600

@@ -685,7 +711,7 @@ def test_handle_eio_message(self):
685711
c._handle_disconnect = AsyncMock()
686712
c._handle_event = AsyncMock()
687713
c._handle_ack = AsyncMock()
688-
c._handle_error = mock.MagicMock()
714+
c._handle_error = AsyncMock()
689715

690716
_run(c._handle_eio_message('0'))
691717
c._handle_connect.mock.assert_called_with(None)
@@ -700,9 +726,15 @@ def test_handle_eio_message(self):
700726
_run(c._handle_eio_message('3/foo,["bar"]'))
701727
c._handle_ack.mock.assert_called_with('/foo', None, ['bar'])
702728
_run(c._handle_eio_message('4'))
703-
c._handle_error.assert_called_with(None)
729+
c._handle_error.mock.assert_called_with(None, None)
730+
_run(c._handle_eio_message('4"foo"'))
731+
c._handle_error.mock.assert_called_with(None, 'foo')
732+
_run(c._handle_eio_message('4["foo"]'))
733+
c._handle_error.mock.assert_called_with(None, ['foo'])
704734
_run(c._handle_eio_message('4/foo'))
705-
c._handle_error.assert_called_with('/foo')
735+
c._handle_error.mock.assert_called_with('/foo', None)
736+
_run(c._handle_eio_message('4/foo,["foo","bar"]'))
737+
c._handle_error.mock.assert_called_with('/foo', ['foo', 'bar'])
706738
_run(c._handle_eio_message('51-{"_placeholder":true,"num":0}'))
707739
self.assertEqual(c._binary_packet.packet_type, packet.BINARY_EVENT)
708740
_run(c._handle_eio_message(b'foo'))

tests/common/test_client.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -660,23 +660,48 @@ def test_handle_error(self):
660660
c = client.Client()
661661
c.connected = True
662662
c.namespaces = ['/foo', '/bar']
663-
c._handle_error('/')
663+
c._trigger_event = mock.MagicMock()
664+
c._handle_error('/', 'error')
665+
self.assertEqual(c.namespaces, [])
666+
self.assertFalse(c.connected)
667+
c._trigger_event.assert_called_once_with('connect_error', '/', 'error')
668+
669+
def test_handle_error_with_no_arguments(self):
670+
c = client.Client()
671+
c.connected = True
672+
c.namespaces = ['/foo', '/bar']
673+
c._trigger_event = mock.MagicMock()
674+
c._handle_error('/', None)
664675
self.assertEqual(c.namespaces, [])
665676
self.assertFalse(c.connected)
677+
c._trigger_event.assert_called_once_with('connect_error', '/')
666678

667679
def test_handle_error_namespace(self):
668680
c = client.Client()
669681
c.connected = True
670682
c.namespaces = ['/foo', '/bar']
671-
c._handle_error('/bar')
683+
c._trigger_event = mock.MagicMock()
684+
c._handle_error('/bar', ['error', 'message'])
685+
self.assertEqual(c.namespaces, ['/foo'])
686+
self.assertTrue(c.connected)
687+
c._trigger_event.assert_called_once_with('connect_error', '/bar',
688+
'error', 'message')
689+
690+
def test_handle_error_namespace_with_no_arguments(self):
691+
c = client.Client()
692+
c.connected = True
693+
c.namespaces = ['/foo', '/bar']
694+
c._trigger_event = mock.MagicMock()
695+
c._handle_error('/bar', None)
672696
self.assertEqual(c.namespaces, ['/foo'])
673697
self.assertTrue(c.connected)
698+
c._trigger_event.assert_called_once_with('connect_error', '/bar')
674699

675700
def test_handle_error_unknown_namespace(self):
676701
c = client.Client()
677702
c.connected = True
678703
c.namespaces = ['/foo', '/bar']
679-
c._handle_error('/baz')
704+
c._handle_error('/baz', 'error')
680705
self.assertEqual(c.namespaces, ['/foo', '/bar'])
681706
self.assertTrue(c.connected)
682707

@@ -809,9 +834,15 @@ def test_handle_eio_message(self):
809834
c._handle_eio_message('3/foo,["bar"]')
810835
c._handle_ack.assert_called_with('/foo', None, ['bar'])
811836
c._handle_eio_message('4')
812-
c._handle_error.assert_called_with(None)
837+
c._handle_error.assert_called_with(None, None)
838+
c._handle_eio_message('4"foo"')
839+
c._handle_error.assert_called_with(None, 'foo')
840+
c._handle_eio_message('4["foo"]')
841+
c._handle_error.assert_called_with(None, ['foo'])
813842
c._handle_eio_message('4/foo')
814-
c._handle_error.assert_called_with('/foo')
843+
c._handle_error.assert_called_with('/foo', None)
844+
c._handle_eio_message('4/foo,["foo","bar"]')
845+
c._handle_error.assert_called_with('/foo', ['foo', 'bar'])
815846
c._handle_eio_message('51-{"_placeholder":true,"num":0}')
816847
self.assertEqual(c._binary_packet.packet_type, packet.BINARY_EVENT)
817848
c._handle_eio_message(b'foo')

tests/common/test_server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,6 @@ def test_handle_connect_namespace_rejected_with_exception(self, eio):
341341
s._handle_eio_message('123', '0/foo')
342342
self.assertEqual(s.manager.connect.call_count, 2)
343343
self.assertEqual(s.manager.disconnect.call_count, 1)
344-
print(s.eio.send.call_args)
345344
s.eio.send.assert_any_call('123', '4/foo,"fail_reason"', binary=False)
346345

347346
def test_handle_disconnect(self, eio):

0 commit comments

Comments
 (0)