From 0c91e92eb1b8d8d5b5d8de2ad6b45a608e6507aa Mon Sep 17 00:00:00 2001
From: Miguel Grinberg <miguel.grinberg@gmail.com>
Date: Sat, 5 Dec 2020 18:14:40 +0000
Subject: [PATCH] v5 protocol: client unit tests

---
 socketio/asyncio_client.py           |  13 +-
 socketio/client.py                   |  16 +-
 tests/asyncio/test_asyncio_client.py | 221 ++++++++++++------------
 tests/common/test_client.py          | 248 ++++++++++++++-------------
 4 files changed, 259 insertions(+), 239 deletions(-)

diff --git a/socketio/asyncio_client.py b/socketio/asyncio_client.py
index 029a1ea..e8f3013 100644
--- a/socketio/asyncio_client.py
+++ b/socketio/asyncio_client.py
@@ -96,8 +96,10 @@ class AsyncClient(client.Client):
         self.socketio_path = socketio_path
 
         if namespaces is None:
-            namespaces = set(self.handlers.keys()).union(
-                set(self.namespace_handlers.keys()))
+            namespaces = list(set(self.handlers.keys()).union(
+                set(self.namespace_handlers.keys())))
+            if len(namespaces) == 0:
+                namespaces = ['/']
         elif isinstance(namespaces, six.string_types):
             namespaces = [namespaces]
         self.connection_namespaces = namespaces
@@ -293,10 +295,10 @@ class AsyncClient(client.Client):
 
     async def _handle_connect(self, namespace, data):
         namespace = namespace or '/'
-        self.logger.info('Namespace {} is connected'.format(namespace))
         if namespace not in self.namespaces:
+            self.logger.info('Namespace {} is connected'.format(namespace))
             self.namespaces[namespace] = (data or {}).get('sid', self.sid)
-        await self._trigger_event('connect', namespace=namespace)
+            await self._trigger_event('connect', namespace=namespace)
 
     async def _handle_disconnect(self, namespace):
         if not self.connected:
@@ -306,6 +308,7 @@ class AsyncClient(client.Client):
         if namespace in self.namespaces:
             del self.namespaces[namespace]
         if not self.namespaces:
+            self.connected = False
             await self.eio.disconnect(abort=True)
 
     async def _handle_event(self, namespace, id, data):
@@ -351,7 +354,7 @@ class AsyncClient(client.Client):
             data = (data,)
         await self._trigger_event('connect_error', namespace, *data)
         if namespace in self.namespaces:
-            self.namespaces.remove(namespace)
+            del self.namespaces[namespace]
         if namespace == '/':
             self.namespaces = {}
             self.connected = False
diff --git a/socketio/client.py b/socketio/client.py
index 9c5aa12..ab685e8 100644
--- a/socketio/client.py
+++ b/socketio/client.py
@@ -108,8 +108,7 @@ class Client(object):
             self.logger = logger
         else:
             self.logger = default_logger
-            if not logging.root.handlers and \
-                    self.logger.level == logging.NOTSET:
+            if self.logger.level == logging.NOTSET:
                 if logger:
                     self.logger.setLevel(logging.INFO)
                 else:
@@ -119,7 +118,7 @@ class Client(object):
         self.connection_url = None
         self.connection_headers = None
         self.connection_transports = None
-        self.connection_namespaces = None
+        self.connection_namespaces = []
         self.socketio_path = None
         self.sid = None
 
@@ -265,8 +264,10 @@ class Client(object):
         self.socketio_path = socketio_path
 
         if namespaces is None:
-            namespaces = set(self.handlers.keys()).union(
-                set(self.namespace_handlers.keys()))
+            namespaces = list(set(self.handlers.keys()).union(
+                set(self.namespace_handlers.keys())))
+            if len(namespaces) == 0:
+                namespaces = ['/']
         elif isinstance(namespaces, six.string_types):
             namespaces = [namespaces]
         self.connection_namespaces = namespaces
@@ -476,10 +477,10 @@ class Client(object):
 
     def _handle_connect(self, namespace, data):
         namespace = namespace or '/'
-        self.logger.info('Namespace {} is connected'.format(namespace))
         if namespace not in self.namespaces:
+            self.logger.info('Namespace {} is connected'.format(namespace))
             self.namespaces[namespace] = (data or {}).get('sid', self.sid)
-        self._trigger_event('connect', namespace=namespace)
+            self._trigger_event('connect', namespace=namespace)
 
     def _handle_disconnect(self, namespace):
         if not self.connected:
@@ -489,6 +490,7 @@ class Client(object):
         if namespace in self.namespaces:
             del self.namespaces[namespace]
         if not self.namespaces:
+            self.connected = False
             self.eio.disconnect(abort=True)
 
     def _handle_event(self, namespace, id, data):
diff --git a/tests/asyncio/test_asyncio_client.py b/tests/asyncio/test_asyncio_client.py
index 4c4d70e..590b4ea 100644
--- a/tests/asyncio/test_asyncio_client.py
+++ b/tests/asyncio/test_asyncio_client.py
@@ -70,7 +70,6 @@ class TestAsyncClient(unittest.TestCase):
         assert c.connection_transports == 'transports'
         assert c.connection_namespaces == ['/foo', '/', '/bar']
         assert c.socketio_path == 'path'
-        assert c.namespaces == ['/foo', '/bar']
         c.eio.connect.mock.assert_called_once_with(
             'url',
             headers='headers',
@@ -95,7 +94,6 @@ class TestAsyncClient(unittest.TestCase):
         assert c.connection_transports == 'transports'
         assert c.connection_namespaces == ['/foo']
         assert c.socketio_path == 'path'
-        assert c.namespaces == ['/foo']
         c.eio.connect.mock.assert_called_once_with(
             'url',
             headers='headers',
@@ -119,9 +117,32 @@ class TestAsyncClient(unittest.TestCase):
         assert c.connection_url == 'url'
         assert c.connection_headers == 'headers'
         assert c.connection_transports == 'transports'
-        assert c.connection_namespaces is None
+        assert c.connection_namespaces == ['/', '/foo'] or \
+            c.connection_namespaces == ['/foo', '/']
+        assert c.socketio_path == 'path'
+        c.eio.connect.mock.assert_called_once_with(
+            'url',
+            headers='headers',
+            transports='transports',
+            engineio_path='path',
+        )
+
+    def test_connect_no_namespaces(self):
+        c = asyncio_client.AsyncClient()
+        c.eio.connect = AsyncMock()
+        _run(
+            c.connect(
+                'url',
+                headers='headers',
+                transports='transports',
+                socketio_path='path',
+            )
+        )
+        assert c.connection_url == 'url'
+        assert c.connection_headers == 'headers'
+        assert c.connection_transports == 'transports'
+        assert c.connection_namespaces == ['/']
         assert c.socketio_path == 'path'
-        assert c.namespaces == ['/foo']
         c.eio.connect.mock.assert_called_once_with(
             'url',
             headers='headers',
@@ -186,11 +207,11 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_emit_no_arguments(self):
         c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
         c._send_packet = AsyncMock()
         _run(c.emit('foo'))
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/', data=['foo'], id=None, binary=False
-        )
+            packet.EVENT, namespace='/', data=['foo'], id=None)
         assert c._send_packet.mock.call_count == 1
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
@@ -199,6 +220,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_emit_one_argument(self):
         c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
         c._send_packet = AsyncMock()
         _run(c.emit('foo', 'bar'))
         expected_packet = packet.Packet(
@@ -206,7 +228,6 @@ class TestAsyncClient(unittest.TestCase):
             namespace='/',
             data=['foo', 'bar'],
             id=None,
-            binary=False,
         )
         assert c._send_packet.mock.call_count == 1
         assert (
@@ -216,6 +237,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_emit_one_argument_list(self):
         c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
         c._send_packet = AsyncMock()
         _run(c.emit('foo', ['bar', 'baz']))
         expected_packet = packet.Packet(
@@ -223,7 +245,6 @@ class TestAsyncClient(unittest.TestCase):
             namespace='/',
             data=['foo', ['bar', 'baz']],
             id=None,
-            binary=False,
         )
         assert c._send_packet.mock.call_count == 1
         assert (
@@ -233,6 +254,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_emit_two_arguments(self):
         c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
         c._send_packet = AsyncMock()
         _run(c.emit('foo', ('bar', 'baz')))
         expected_packet = packet.Packet(
@@ -240,7 +262,6 @@ class TestAsyncClient(unittest.TestCase):
             namespace='/',
             data=['foo', 'bar', 'baz'],
             id=None,
-            binary=False,
         )
         assert c._send_packet.mock.call_count == 1
         assert (
@@ -250,12 +271,11 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_emit_namespace(self):
         c = asyncio_client.AsyncClient()
-        c.namespaces = ['/foo']
+        c.namespaces = {'/foo': '1'}
         c._send_packet = AsyncMock()
         _run(c.emit('foo', namespace='/foo'))
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/foo', data=['foo'], id=None, binary=False
-        )
+            packet.EVENT, namespace='/foo', data=['foo'], id=None)
         assert c._send_packet.mock.call_count == 1
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
@@ -264,7 +284,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_emit_unknown_namespace(self):
         c = asyncio_client.AsyncClient()
-        c.namespaces = ['/foo']
+        c.namespaces = {'/foo': '1'}
         with pytest.raises(exceptions.BadNamespaceError):
             _run(c.emit('foo', namespace='/bar'))
 
@@ -272,10 +292,10 @@ class TestAsyncClient(unittest.TestCase):
         c = asyncio_client.AsyncClient()
         c._send_packet = AsyncMock()
         c._generate_ack_id = mock.MagicMock(return_value=123)
+        c.namespaces = {'/': '1'}
         _run(c.emit('foo', callback='cb'))
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/', data=['foo'], id=123, binary=False
-        )
+            packet.EVENT, namespace='/', data=['foo'], id=123)
         assert c._send_packet.mock.call_count == 1
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
@@ -285,13 +305,12 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_emit_namespace_with_callback(self):
         c = asyncio_client.AsyncClient()
-        c.namespaces = ['/foo']
+        c.namespaces = {'/foo': '1'}
         c._send_packet = AsyncMock()
         c._generate_ack_id = mock.MagicMock(return_value=123)
         _run(c.emit('foo', namespace='/foo', callback='cb'))
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/foo', data=['foo'], id=123, binary=False
-        )
+            packet.EVENT, namespace='/foo', data=['foo'], id=123)
         assert c._send_packet.mock.call_count == 1
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
@@ -300,7 +319,8 @@ class TestAsyncClient(unittest.TestCase):
         c._generate_ack_id.assert_called_once_with('/foo', 'cb')
 
     def test_emit_binary(self):
-        c = asyncio_client.AsyncClient(binary=True)
+        c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
         c._send_packet = AsyncMock()
         _run(c.emit('foo', b'bar'))
         expected_packet = packet.Packet(
@@ -308,7 +328,6 @@ class TestAsyncClient(unittest.TestCase):
             namespace='/',
             data=['foo', b'bar'],
             id=None,
-            binary=True,
         )
         assert c._send_packet.mock.call_count == 1
         assert (
@@ -317,7 +336,8 @@ class TestAsyncClient(unittest.TestCase):
         )
 
     def test_emit_not_binary(self):
-        c = asyncio_client.AsyncClient(binary=False)
+        c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
         c._send_packet = AsyncMock()
         _run(c.emit('foo', 'bar'))
         expected_packet = packet.Packet(
@@ -325,7 +345,6 @@ class TestAsyncClient(unittest.TestCase):
             namespace='/',
             data=['foo', 'bar'],
             id=None,
-            binary=False,
         )
         assert c._send_packet.mock.call_count == 1
         assert (
@@ -351,7 +370,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_call(self):
         c = asyncio_client.AsyncClient()
-
+        c.namespaces = {'/': '1'}
         async def fake_event_wait():
             c._generate_ack_id.call_args_list[0][0][1]('foo', 321)
 
@@ -361,8 +380,7 @@ class TestAsyncClient(unittest.TestCase):
         c.eio.create_event.return_value.wait = fake_event_wait
         assert _run(c.call('foo')) == ('foo', 321)
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/', data=['foo'], id=123, binary=False
-        )
+            packet.EVENT, namespace='/', data=['foo'], id=123)
         assert c._send_packet.mock.call_count == 1
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
@@ -371,6 +389,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_call_with_timeout(self):
         c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
 
         async def fake_event_wait():
             await asyncio.sleep(1)
@@ -382,8 +401,7 @@ class TestAsyncClient(unittest.TestCase):
         with pytest.raises(exceptions.TimeoutError):
             _run(c.call('foo', timeout=0.01))
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/', data=['foo'], id=123, binary=False
-        )
+            packet.EVENT, namespace='/', data=['foo'], id=123)
         assert c._send_packet.mock.call_count == 1
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
@@ -392,6 +410,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_disconnect(self):
         c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
         c._trigger_event = AsyncMock()
         c._send_packet = AsyncMock()
         c.eio = mock.MagicMock()
@@ -409,7 +428,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_disconnect_namespaces(self):
         c = asyncio_client.AsyncClient()
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = AsyncMock()
         c._send_packet = AsyncMock()
         c.eio = mock.MagicMock()
@@ -417,7 +436,7 @@ class TestAsyncClient(unittest.TestCase):
         c.eio.state = 'connected'
         _run(c.disconnect())
         assert c._trigger_event.mock.call_count == 0
-        assert c._send_packet.mock.call_count == 3
+        assert c._send_packet.mock.call_count == 2
         expected_packet = packet.Packet(packet.DISCONNECT, namespace='/foo')
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
@@ -428,11 +447,6 @@ class TestAsyncClient(unittest.TestCase):
             c._send_packet.mock.call_args_list[1][0][0].encode()
             == expected_packet.encode()
         )
-        expected_packet = packet.Packet(packet.DISCONNECT, namespace='/')
-        assert (
-            c._send_packet.mock.call_args_list[2][0][0].encode()
-            == expected_packet.encode()
-        )
 
     def test_start_background_task(self):
         c = asyncio_client.AsyncClient()
@@ -451,67 +465,55 @@ class TestAsyncClient(unittest.TestCase):
     def test_send_packet(self):
         c = asyncio_client.AsyncClient()
         c.eio.send = AsyncMock()
-        _run(c._send_packet(packet.Packet(packet.EVENT, 'foo', binary=False)))
-        c.eio.send.mock.assert_called_once_with('2"foo"', binary=False)
+        _run(c._send_packet(packet.Packet(packet.EVENT, 'foo')))
+        c.eio.send.mock.assert_called_once_with('2"foo"')
 
     def test_send_packet_binary(self):
         c = asyncio_client.AsyncClient()
         c.eio.send = AsyncMock()
-        _run(c._send_packet(packet.Packet(packet.EVENT, b'foo', binary=True)))
+        _run(c._send_packet(packet.Packet(packet.EVENT, b'foo')))
         assert c.eio.send.mock.call_args_list == [
-            mock.call('51-{"_placeholder":true,"num":0}', binary=False),
-            mock.call(b'foo', binary=True),
+            mock.call('51-{"_placeholder":true,"num":0}'),
+            mock.call(b'foo'),
         ] or c.eio.send.mock.call_args_list == [
-            mock.call('51-{"num":0,"_placeholder":true}', binary=False),
-            mock.call(b'foo', binary=True),
+            mock.call('51-{"num":0,"_placeholder":true}'),
+            mock.call(b'foo'),
         ]
 
-    def test_send_packet_default_binary_py3(self):
+    def test_send_packet_default_binary(self):
         c = asyncio_client.AsyncClient()
         c.eio.send = AsyncMock()
         _run(c._send_packet(packet.Packet(packet.EVENT, 'foo')))
-        c.eio.send.mock.assert_called_once_with('2"foo"', binary=False)
+        c.eio.send.mock.assert_called_once_with('2"foo"')
 
     def test_handle_connect(self):
         c = asyncio_client.AsyncClient()
         c._trigger_event = AsyncMock()
         c._send_packet = AsyncMock()
-        _run(c._handle_connect('/'))
+        _run(c._handle_connect('/', {'sid': '123'}))
         c._trigger_event.mock.assert_called_once_with('connect', namespace='/')
         c._send_packet.mock.assert_not_called()
 
     def test_handle_connect_with_namespaces(self):
         c = asyncio_client.AsyncClient()
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = AsyncMock()
         c._send_packet = AsyncMock()
-        _run(c._handle_connect('/'))
+        _run(c._handle_connect('/', {'sid': '3'}))
         c._trigger_event.mock.assert_called_once_with('connect', namespace='/')
-        assert c._send_packet.mock.call_count == 2
-        expected_packet = packet.Packet(packet.CONNECT, namespace='/foo')
-        assert (
-            c._send_packet.mock.call_args_list[0][0][0].encode()
-            == expected_packet.encode()
-        )
-        expected_packet = packet.Packet(packet.CONNECT, namespace='/bar')
-        assert (
-            c._send_packet.mock.call_args_list[1][0][0].encode()
-            == expected_packet.encode()
-        )
+        assert c.namespaces == {'/': '3', '/foo': '1', '/bar': '2'}
 
     def test_handle_connect_namespace(self):
         c = asyncio_client.AsyncClient()
-        c.namespaces = ['/foo']
+        c.namespaces = {'/foo': '1'}
         c._trigger_event = AsyncMock()
         c._send_packet = AsyncMock()
-        _run(c._handle_connect('/foo'))
-        _run(c._handle_connect('/bar'))
-        assert c._trigger_event.mock.call_args_list == [
-            mock.call('connect', namespace='/foo'),
-            mock.call('connect', namespace='/bar'),
-        ]
-        c._send_packet.mock.assert_not_called()
-        assert c.namespaces == ['/foo', '/bar']
+        _run(c._handle_connect('/foo', {'sid': '123'}))
+        _run(c._handle_connect('/bar', {'sid': '2'}))
+        assert c._trigger_event.mock.call_count == 1
+        c._trigger_event.mock.assert_called_once_with(
+            'connect', namespace='/bar')
+        assert c.namespaces == {'/foo': '1', '/bar': '2'}
 
     def test_handle_disconnect(self):
         c = asyncio_client.AsyncClient()
@@ -528,38 +530,36 @@ class TestAsyncClient(unittest.TestCase):
     def test_handle_disconnect_namespace(self):
         c = asyncio_client.AsyncClient()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = AsyncMock()
         _run(c._handle_disconnect('/foo'))
         c._trigger_event.mock.assert_called_once_with(
             'disconnect', namespace='/foo'
         )
-        assert c.namespaces == ['/bar']
+        assert c.namespaces == {'/bar': '2'}
         assert c.connected
 
     def test_handle_disconnect_unknown_namespace(self):
         c = asyncio_client.AsyncClient()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = AsyncMock()
         _run(c._handle_disconnect('/baz'))
         c._trigger_event.mock.assert_called_once_with(
             'disconnect', namespace='/baz'
         )
-        assert c.namespaces == ['/foo', '/bar']
+        assert c.namespaces == {'/foo': '1', '/bar': '2'}
         assert c.connected
 
-    def test_handle_disconnect_all_namespaces(self):
+    def test_handle_disconnect_default_namespaces(self):
         c = asyncio_client.AsyncClient()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = AsyncMock()
         _run(c._handle_disconnect('/'))
-        c._trigger_event.mock.assert_any_call('disconnect', namespace='/')
-        c._trigger_event.mock.assert_any_call('disconnect', namespace='/foo')
-        c._trigger_event.mock.assert_any_call('disconnect', namespace='/bar')
-        assert c.namespaces == []
-        assert not c.connected
+        c._trigger_event.mock.assert_called_with('disconnect', namespace='/')
+        assert c.namespaces == {'/foo': '1', '/bar': '2'}
+        assert c.connected
 
     def test_handle_event(self):
         c = asyncio_client.AsyncClient()
@@ -570,7 +570,7 @@ class TestAsyncClient(unittest.TestCase):
         )
 
     def test_handle_event_with_id_no_arguments(self):
-        c = asyncio_client.AsyncClient(binary=True)
+        c = asyncio_client.AsyncClient()
         c._trigger_event = AsyncMock(return_value=None)
         c._send_packet = AsyncMock()
         _run(c._handle_event('/', 123, ['foo', ('bar', 'baz')]))
@@ -579,15 +579,14 @@ class TestAsyncClient(unittest.TestCase):
         )
         assert c._send_packet.mock.call_count == 1
         expected_packet = packet.Packet(
-            packet.ACK, namespace='/', id=123, data=[], binary=None
-        )
+            packet.ACK, namespace='/', id=123, data=[])
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
             == expected_packet.encode()
         )
 
     def test_handle_event_with_id_one_argument(self):
-        c = asyncio_client.AsyncClient(binary=True)
+        c = asyncio_client.AsyncClient()
         c._trigger_event = AsyncMock(return_value='ret')
         c._send_packet = AsyncMock()
         _run(c._handle_event('/', 123, ['foo', ('bar', 'baz')]))
@@ -596,15 +595,14 @@ class TestAsyncClient(unittest.TestCase):
         )
         assert c._send_packet.mock.call_count == 1
         expected_packet = packet.Packet(
-            packet.ACK, namespace='/', id=123, data=['ret'], binary=None
-        )
+            packet.ACK, namespace='/', id=123, data=['ret'])
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
             == expected_packet.encode()
         )
 
     def test_handle_event_with_id_one_list_argument(self):
-        c = asyncio_client.AsyncClient(binary=True)
+        c = asyncio_client.AsyncClient()
         c._trigger_event = AsyncMock(return_value=['a', 'b'])
         c._send_packet = AsyncMock()
         _run(c._handle_event('/', 123, ['foo', ('bar', 'baz')]))
@@ -613,15 +611,14 @@ class TestAsyncClient(unittest.TestCase):
         )
         assert c._send_packet.mock.call_count == 1
         expected_packet = packet.Packet(
-            packet.ACK, namespace='/', id=123, data=[['a', 'b']], binary=None
-        )
+            packet.ACK, namespace='/', id=123, data=[['a', 'b']])
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
             == expected_packet.encode()
         )
 
     def test_handle_event_with_id_two_arguments(self):
-        c = asyncio_client.AsyncClient(binary=True)
+        c = asyncio_client.AsyncClient()
         c._trigger_event = AsyncMock(return_value=('a', 'b'))
         c._send_packet = AsyncMock()
         _run(c._handle_event('/', 123, ['foo', ('bar', 'baz')]))
@@ -630,8 +627,7 @@ class TestAsyncClient(unittest.TestCase):
         )
         assert c._send_packet.mock.call_count == 1
         expected_packet = packet.Packet(
-            packet.ACK, namespace='/', id=123, data=['a', 'b'], binary=None
-        )
+            packet.ACK, namespace='/', id=123, data=['a', 'b'])
         assert (
             c._send_packet.mock.call_args_list[0][0][0].encode()
             == expected_packet.encode()
@@ -665,9 +661,9 @@ class TestAsyncClient(unittest.TestCase):
         c = asyncio_client.AsyncClient()
         c.connected = True
         c._trigger_event = AsyncMock()
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         _run(c._handle_error('/', 'error'))
-        assert c.namespaces == []
+        assert c.namespaces == {}
         assert not c.connected
         c._trigger_event.mock.assert_called_once_with(
             'connect_error', '/', 'error'
@@ -677,19 +673,19 @@ class TestAsyncClient(unittest.TestCase):
         c = asyncio_client.AsyncClient()
         c.connected = True
         c._trigger_event = AsyncMock()
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         _run(c._handle_error('/', None))
-        assert c.namespaces == []
+        assert c.namespaces == {}
         assert not c.connected
         c._trigger_event.mock.assert_called_once_with('connect_error', '/')
 
     def test_handle_error_namespace(self):
         c = asyncio_client.AsyncClient()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = AsyncMock()
         _run(c._handle_error('/bar', ['error', 'message']))
-        assert c.namespaces == ['/foo']
+        assert c.namespaces == {'/foo': '1'}
         assert c.connected
         c._trigger_event.mock.assert_called_once_with(
             'connect_error', '/bar', 'error', 'message'
@@ -698,19 +694,19 @@ class TestAsyncClient(unittest.TestCase):
     def test_handle_error_namespace_with_no_arguments(self):
         c = asyncio_client.AsyncClient()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = AsyncMock()
         _run(c._handle_error('/bar', None))
-        assert c.namespaces == ['/foo']
+        assert c.namespaces == {'/foo': '1'}
         assert c.connected
         c._trigger_event.mock.assert_called_once_with('connect_error', '/bar')
 
     def test_handle_error_unknown_namespace(self):
         c = asyncio_client.AsyncClient()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         _run(c._handle_error('/baz', 'error'))
-        assert c.namespaces == ['/foo', '/bar']
+        assert c.namespaces == {'/foo': '1', '/bar': '2'}
         assert c.connected
 
     def test_trigger_event(self):
@@ -839,10 +835,23 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_eio_connect(self):
         c = asyncio_client.AsyncClient()
+        c.connection_namespaces = ['/', '/foo']
+        c._send_packet = AsyncMock()
         c.eio.sid = 'foo'
         assert c.sid is None
-        c._handle_eio_connect()
+        _run(c._handle_eio_connect())
         assert c.sid == 'foo'
+        assert c._send_packet.mock.call_count == 2
+        expected_packet = packet.Packet(packet.CONNECT, namespace='/')
+        assert (
+            c._send_packet.mock.call_args_list[0][0][0].encode()
+            == expected_packet.encode()
+        )
+        expected_packet = packet.Packet(packet.CONNECT, namespace='/foo')
+        assert (
+            c._send_packet.mock.call_args_list[1][0][0].encode()
+            == expected_packet.encode()
+        )
 
     def test_handle_eio_message(self):
         c = asyncio_client.AsyncClient()
@@ -852,10 +861,10 @@ class TestAsyncClient(unittest.TestCase):
         c._handle_ack = AsyncMock()
         c._handle_error = AsyncMock()
 
-        _run(c._handle_eio_message('0'))
-        c._handle_connect.mock.assert_called_with(None)
-        _run(c._handle_eio_message('0/foo'))
-        c._handle_connect.mock.assert_called_with('/foo')
+        _run(c._handle_eio_message('0{"sid":"123"}'))
+        c._handle_connect.mock.assert_called_with(None, {'sid': '123'})
+        _run(c._handle_eio_message('0/foo,{"sid":"123"}'))
+        c._handle_connect.mock.assert_called_with('/foo', {'sid': '123'})
         _run(c._handle_eio_message('1'))
         c._handle_disconnect.mock.assert_called_with(None)
         _run(c._handle_eio_message('1/foo'))
@@ -895,6 +904,7 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_eio_disconnect(self):
         c = asyncio_client.AsyncClient()
+        c.namespaces = {'/': '1'}
         c.connected = True
         c._trigger_event = AsyncMock()
         c.sid = 'foo'
@@ -908,15 +918,14 @@ class TestAsyncClient(unittest.TestCase):
 
     def test_eio_disconnect_namespaces(self):
         c = asyncio_client.AsyncClient()
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
         c._trigger_event = AsyncMock()
         c.sid = 'foo'
         c.eio.state = 'connected'
         _run(c._handle_eio_disconnect())
         c._trigger_event.mock.assert_any_call('disconnect', namespace='/foo')
         c._trigger_event.mock.assert_any_call('disconnect', namespace='/bar')
-        c._trigger_event.mock.assert_any_call('disconnect', namespace='/')
         assert c.sid is None
         assert not c.connected
 
diff --git a/tests/common/test_client.py b/tests/common/test_client.py
index b20ed01..7e2a037 100644
--- a/tests/common/test_client.py
+++ b/tests/common/test_client.py
@@ -37,7 +37,6 @@ class TestClient(unittest.TestCase):
             reconnection_delay=5,
             reconnection_delay_max=10,
             randomization_factor=0.2,
-            binary=True,
             foo='bar',
         )
         assert not c.reconnection
@@ -45,16 +44,15 @@ class TestClient(unittest.TestCase):
         assert c.reconnection_delay == 5
         assert c.reconnection_delay_max == 10
         assert c.randomization_factor == 0.2
-        assert c.binary
         engineio_client_class().assert_called_once_with(foo='bar')
         assert c.connection_url is None
         assert c.connection_headers is None
         assert c.connection_transports is None
-        assert c.connection_namespaces is None
+        assert c.connection_namespaces == []
         assert c.socketio_path is None
         assert c.sid is None
 
-        assert c.namespaces == []
+        assert c.namespaces == {}
         assert c.handlers == {}
         assert c.namespace_handlers == {}
         assert c.callbacks == {}
@@ -174,7 +172,6 @@ class TestClient(unittest.TestCase):
         assert c.connection_transports == 'transports'
         assert c.connection_namespaces == ['/foo', '/', '/bar']
         assert c.socketio_path == 'path'
-        assert c.namespaces == ['/foo', '/bar']
         c.eio.connect.assert_called_once_with(
             'url',
             headers='headers',
@@ -197,7 +194,6 @@ class TestClient(unittest.TestCase):
         assert c.connection_transports == 'transports'
         assert c.connection_namespaces == ['/foo']
         assert c.socketio_path == 'path'
-        assert c.namespaces == ['/foo']
         c.eio.connect.assert_called_once_with(
             'url',
             headers='headers',
@@ -219,9 +215,30 @@ class TestClient(unittest.TestCase):
         assert c.connection_url == 'url'
         assert c.connection_headers == 'headers'
         assert c.connection_transports == 'transports'
-        assert c.connection_namespaces is None
+        assert c.connection_namespaces == ['/foo', '/'] or \
+            c.connection_namespaces == ['/', '/foo']
+        assert c.socketio_path == 'path'
+        c.eio.connect.assert_called_once_with(
+            'url',
+            headers='headers',
+            transports='transports',
+            engineio_path='path',
+        )
+
+    def test_connect_no_namespaces(self):
+        c = client.Client()
+        c.eio.connect = mock.MagicMock()
+        c.connect(
+            'url',
+            headers='headers',
+            transports='transports',
+            socketio_path='path',
+        )
+        assert c.connection_url == 'url'
+        assert c.connection_headers == 'headers'
+        assert c.connection_transports == 'transports'
+        assert c.connection_namespaces == ['/']
         assert c.socketio_path == 'path'
-        assert c.namespaces == ['/foo']
         c.eio.connect.assert_called_once_with(
             'url',
             headers='headers',
@@ -283,13 +300,21 @@ class TestClient(unittest.TestCase):
         assert c.eio.wait.call_count == 2
         assert c.sleep.call_count == 2
 
+    def test_get_sid(self):
+        c = client.Client()
+        c.namespaces = {'/': '1', '/foo': '2'}
+        assert c.get_sid() == '1'
+        assert c.get_sid('/') == '1'
+        assert c.get_sid('/foo') == '2'
+        assert c.get_sid('/bar') is None
+
     def test_emit_no_arguments(self):
         c = client.Client()
+        c.namespaces = {'/': '1'}
         c._send_packet = mock.MagicMock()
         c.emit('foo')
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/', data=['foo'], id=None, binary=False
-        )
+            packet.EVENT, namespace='/', data=['foo'], id=None)
         assert c._send_packet.call_count == 1
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
@@ -298,6 +323,7 @@ class TestClient(unittest.TestCase):
 
     def test_emit_one_argument(self):
         c = client.Client()
+        c.namespaces = {'/': '1'}
         c._send_packet = mock.MagicMock()
         c.emit('foo', 'bar')
         expected_packet = packet.Packet(
@@ -305,7 +331,6 @@ class TestClient(unittest.TestCase):
             namespace='/',
             data=['foo', 'bar'],
             id=None,
-            binary=False,
         )
         assert c._send_packet.call_count == 1
         assert (
@@ -315,6 +340,7 @@ class TestClient(unittest.TestCase):
 
     def test_emit_one_argument_list(self):
         c = client.Client()
+        c.namespaces = {'/': '1'}
         c._send_packet = mock.MagicMock()
         c.emit('foo', ['bar', 'baz'])
         expected_packet = packet.Packet(
@@ -322,7 +348,6 @@ class TestClient(unittest.TestCase):
             namespace='/',
             data=['foo', ['bar', 'baz']],
             id=None,
-            binary=False,
         )
         assert c._send_packet.call_count == 1
         assert (
@@ -332,6 +357,7 @@ class TestClient(unittest.TestCase):
 
     def test_emit_two_arguments(self):
         c = client.Client()
+        c.namespaces = {'/': '1'}
         c._send_packet = mock.MagicMock()
         c.emit('foo', ('bar', 'baz'))
         expected_packet = packet.Packet(
@@ -339,7 +365,6 @@ class TestClient(unittest.TestCase):
             namespace='/',
             data=['foo', 'bar', 'baz'],
             id=None,
-            binary=False,
         )
         assert c._send_packet.call_count == 1
         assert (
@@ -353,8 +378,7 @@ class TestClient(unittest.TestCase):
         c._send_packet = mock.MagicMock()
         c.emit('foo', namespace='/foo')
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/foo', data=['foo'], id=None, binary=False
-        )
+            packet.EVENT, namespace='/foo', data=['foo'], id=None)
         assert c._send_packet.call_count == 1
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
@@ -369,12 +393,12 @@ class TestClient(unittest.TestCase):
 
     def test_emit_with_callback(self):
         c = client.Client()
+        c.namespaces = {'/': '1'}
         c._send_packet = mock.MagicMock()
         c._generate_ack_id = mock.MagicMock(return_value=123)
         c.emit('foo', callback='cb')
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/', data=['foo'], id=123, binary=False
-        )
+            packet.EVENT, namespace='/', data=['foo'], id=123)
         assert c._send_packet.call_count == 1
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
@@ -384,13 +408,12 @@ class TestClient(unittest.TestCase):
 
     def test_emit_namespace_with_callback(self):
         c = client.Client()
-        c.namespaces = ['/foo']
+        c.namespaces = {'/foo': '1'}
         c._send_packet = mock.MagicMock()
         c._generate_ack_id = mock.MagicMock(return_value=123)
         c.emit('foo', namespace='/foo', callback='cb')
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/foo', data=['foo'], id=123, binary=False
-        )
+            packet.EVENT, namespace='/foo', data=['foo'], id=123)
         assert c._send_packet.call_count == 1
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
@@ -399,7 +422,8 @@ class TestClient(unittest.TestCase):
         c._generate_ack_id.assert_called_once_with('/foo', 'cb')
 
     def test_emit_binary(self):
-        c = client.Client(binary=True)
+        c = client.Client()
+        c.namespaces = {'/': '1'}
         c._send_packet = mock.MagicMock()
         c.emit('foo', b'bar')
         expected_packet = packet.Packet(
@@ -407,7 +431,6 @@ class TestClient(unittest.TestCase):
             namespace='/',
             data=['foo', b'bar'],
             id=None,
-            binary=True,
         )
         assert c._send_packet.call_count == 1
         assert (
@@ -416,7 +439,8 @@ class TestClient(unittest.TestCase):
         )
 
     def test_emit_not_binary(self):
-        c = client.Client(binary=False)
+        c = client.Client()
+        c.namespaces = {'/': '1'}
         c._send_packet = mock.MagicMock()
         c.emit('foo', 'bar')
         expected_packet = packet.Packet(
@@ -424,7 +448,6 @@ class TestClient(unittest.TestCase):
             namespace='/',
             data=['foo', 'bar'],
             id=None,
-            binary=False,
         )
         assert c._send_packet.call_count == 1
         assert (
@@ -450,7 +473,7 @@ class TestClient(unittest.TestCase):
 
     def test_call(self):
         c = client.Client()
-
+        c.namespaces = {'/': '1'}
         def fake_event_wait(timeout=None):
             assert timeout == 60
             c._generate_ack_id.call_args_list[0][0][1]('foo', 321)
@@ -462,8 +485,7 @@ class TestClient(unittest.TestCase):
         c.eio.create_event.return_value.wait = fake_event_wait
         assert c.call('foo') == ('foo', 321)
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/', data=['foo'], id=123, binary=False
-        )
+            packet.EVENT, namespace='/', data=['foo'], id=123)
         assert c._send_packet.call_count == 1
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
@@ -472,7 +494,7 @@ class TestClient(unittest.TestCase):
 
     def test_call_with_timeout(self):
         c = client.Client()
-
+        c.namespaces = {'/': '1'}
         def fake_event_wait(timeout=None):
             assert timeout == 12
             return False
@@ -484,8 +506,7 @@ class TestClient(unittest.TestCase):
         with pytest.raises(exceptions.TimeoutError):
             c.call('foo', timeout=12)
         expected_packet = packet.Packet(
-            packet.EVENT, namespace='/', data=['foo'], id=123, binary=False
-        )
+            packet.EVENT, namespace='/', data=['foo'], id=123)
         assert c._send_packet.call_count == 1
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
@@ -494,6 +515,7 @@ class TestClient(unittest.TestCase):
 
     def test_disconnect(self):
         c = client.Client()
+        c.namespaces = {'/': '1'}
         c._trigger_event = mock.MagicMock()
         c._send_packet = mock.MagicMock()
         c.eio = mock.MagicMock()
@@ -510,14 +532,14 @@ class TestClient(unittest.TestCase):
 
     def test_disconnect_namespaces(self):
         c = client.Client()
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._send_packet = mock.MagicMock()
         c.eio = mock.MagicMock()
         c.eio.state = 'connected'
         c.disconnect()
         assert c._trigger_event.call_count == 0
-        assert c._send_packet.call_count == 3
+        assert c._send_packet.call_count == 2
         expected_packet = packet.Packet(packet.DISCONNECT, namespace='/foo')
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
@@ -528,11 +550,6 @@ class TestClient(unittest.TestCase):
             c._send_packet.call_args_list[1][0][0].encode()
             == expected_packet.encode()
         )
-        expected_packet = packet.Packet(packet.DISCONNECT, namespace='/')
-        assert (
-            c._send_packet.call_args_list[2][0][0].encode()
-            == expected_packet.encode()
-        )
 
     def test_transport(self):
         c = client.Client()
@@ -557,40 +574,26 @@ class TestClient(unittest.TestCase):
     def test_send_packet(self):
         c = client.Client()
         c.eio.send = mock.MagicMock()
-        c._send_packet(packet.Packet(packet.EVENT, 'foo', binary=False))
-        c.eio.send.assert_called_once_with('2"foo"', binary=False)
+        c._send_packet(packet.Packet(packet.EVENT, 'foo'))
+        c.eio.send.assert_called_once_with('2"foo"')
 
     def test_send_packet_binary(self):
         c = client.Client()
         c.eio.send = mock.MagicMock()
-        c._send_packet(packet.Packet(packet.EVENT, b'foo', binary=True))
+        c._send_packet(packet.Packet(packet.EVENT, b'foo'))
         assert c.eio.send.call_args_list == [
-            mock.call('51-{"_placeholder":true,"num":0}', binary=False),
-            mock.call(b'foo', binary=True),
+            mock.call('51-{"_placeholder":true,"num":0}'),
+            mock.call(b'foo'),
         ] or c.eio.send.call_args_list == [
-            mock.call('51-{"num":0,"_placeholder":true}', binary=False),
-            mock.call(b'foo', binary=True),
+            mock.call('51-{"num":0,"_placeholder":true}'),
+            mock.call(b'foo'),
         ]
 
-    @unittest.skipIf(sys.version_info < (3, 0), 'only for Python 3')
-    def test_send_packet_default_binary_py3(self):
-        c = client.Client()
-        c.eio.send = mock.MagicMock()
-        c._send_packet(packet.Packet(packet.EVENT, 'foo'))
-        c.eio.send.assert_called_once_with('2"foo"', binary=False)
-
-    @unittest.skipIf(sys.version_info >= (3, 0), 'only for Python 2')
-    def test_send_packet_default_binary_py2(self):
+    def test_send_packet_default_binary(self):
         c = client.Client()
         c.eio.send = mock.MagicMock()
         c._send_packet(packet.Packet(packet.EVENT, 'foo'))
-        assert c.eio.send.call_args_list == [
-            mock.call('51-{"_placeholder":true,"num":0}', binary=False),
-            mock.call(b'foo', binary=True),
-        ] or c.eio.send.call_args_list == [
-            mock.call('51-{"num":0,"_placeholder":true}', binary=False),
-            mock.call(b'foo', binary=True),
-        ]
+        c.eio.send.assert_called_once_with('2"foo"')
 
     def test_generate_ack_id(self):
         c = client.Client()
@@ -606,45 +609,34 @@ class TestClient(unittest.TestCase):
         c = client.Client()
         c._trigger_event = mock.MagicMock()
         c._send_packet = mock.MagicMock()
-        c._handle_connect('/')
+        c._handle_connect('/', {'sid': '123'})
+        assert c.namespaces == {'/': '123'}
         c._trigger_event.assert_called_once_with('connect', namespace='/')
         c._send_packet.assert_not_called()
 
     def test_handle_connect_with_namespaces(self):
         c = client.Client()
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._send_packet = mock.MagicMock()
-        c._handle_connect('/')
+        c._handle_connect('/', {'sid': '3'})
         c._trigger_event.assert_called_once_with('connect', namespace='/')
-        assert c._send_packet.call_count == 2
-        expected_packet = packet.Packet(packet.CONNECT, namespace='/foo')
-        assert (
-            c._send_packet.call_args_list[0][0][0].encode()
-            == expected_packet.encode()
-        )
-        expected_packet = packet.Packet(packet.CONNECT, namespace='/bar')
-        assert (
-            c._send_packet.call_args_list[1][0][0].encode()
-            == expected_packet.encode()
-        )
+        assert c.namespaces == {'/': '3', '/foo': '1', '/bar': '2'}
 
     def test_handle_connect_namespace(self):
         c = client.Client()
-        c.namespaces = ['/foo']
+        c.namespaces = {'/foo': '1'}
         c._trigger_event = mock.MagicMock()
         c._send_packet = mock.MagicMock()
-        c._handle_connect('/foo')
-        c._handle_connect('/bar')
-        assert c._trigger_event.call_args_list == [
-            mock.call('connect', namespace='/foo'),
-            mock.call('connect', namespace='/bar'),
-        ]
-        c._send_packet.assert_not_called()
-        assert c.namespaces == ['/foo', '/bar']
+        c._handle_connect('/foo', {'sid': '123'})
+        c._handle_connect('/bar', {'sid': '2'})
+        assert c._trigger_event.call_count == 1
+        c._trigger_event.assert_called_once_with('connect', namespace='/bar')
+        assert c.namespaces == {'/foo': '1', '/bar': '2'}
 
     def test_handle_disconnect(self):
         c = client.Client()
+        c.namespace = {'/': '1'}
         c.connected = True
         c._trigger_event = mock.MagicMock()
         c._handle_disconnect('/')
@@ -656,38 +648,42 @@ class TestClient(unittest.TestCase):
     def test_handle_disconnect_namespace(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._handle_disconnect('/foo')
         c._trigger_event.assert_called_once_with(
             'disconnect', namespace='/foo'
         )
-        assert c.namespaces == ['/bar']
+        assert c.namespaces == {'/bar': '2'}
         assert c.connected
+        c._handle_disconnect('/bar')
+        c._trigger_event.assert_called_with(
+            'disconnect', namespace='/bar'
+        )
+        assert c.namespaces == {}
+        assert not c.connected
 
     def test_handle_disconnect_unknown_namespace(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._handle_disconnect('/baz')
         c._trigger_event.assert_called_once_with(
             'disconnect', namespace='/baz'
         )
-        assert c.namespaces == ['/foo', '/bar']
+        assert c.namespaces == {'/foo': '1', '/bar': '2'}
         assert c.connected
 
-    def test_handle_disconnect_all_namespaces(self):
+    def test_handle_disconnect_default_namespace(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._handle_disconnect('/')
-        c._trigger_event.assert_any_call('disconnect', namespace='/')
-        c._trigger_event.assert_any_call('disconnect', namespace='/foo')
-        c._trigger_event.assert_any_call('disconnect', namespace='/bar')
-        assert c.namespaces == []
-        assert not c.connected
+        c._trigger_event.assert_called_with('disconnect', namespace='/')
+        assert c.namespaces == {'/foo': '1', '/bar': '2'}
+        assert c.connected
 
     def test_handle_event(self):
         c = client.Client()
@@ -696,60 +692,56 @@ class TestClient(unittest.TestCase):
         c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz'))
 
     def test_handle_event_with_id_no_arguments(self):
-        c = client.Client(binary=True)
+        c = client.Client()
         c._trigger_event = mock.MagicMock(return_value=None)
         c._send_packet = mock.MagicMock()
         c._handle_event('/', 123, ['foo', ('bar', 'baz')])
         c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz'))
         assert c._send_packet.call_count == 1
         expected_packet = packet.Packet(
-            packet.ACK, namespace='/', id=123, data=[], binary=None
-        )
+            packet.ACK, namespace='/', id=123, data=[])
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
             == expected_packet.encode()
         )
 
     def test_handle_event_with_id_one_argument(self):
-        c = client.Client(binary=True)
+        c = client.Client()
         c._trigger_event = mock.MagicMock(return_value='ret')
         c._send_packet = mock.MagicMock()
         c._handle_event('/', 123, ['foo', ('bar', 'baz')])
         c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz'))
         assert c._send_packet.call_count == 1
         expected_packet = packet.Packet(
-            packet.ACK, namespace='/', id=123, data=['ret'], binary=None
-        )
+            packet.ACK, namespace='/', id=123, data=['ret'])
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
             == expected_packet.encode()
         )
 
     def test_handle_event_with_id_one_list_argument(self):
-        c = client.Client(binary=True)
+        c = client.Client()
         c._trigger_event = mock.MagicMock(return_value=['a', 'b'])
         c._send_packet = mock.MagicMock()
         c._handle_event('/', 123, ['foo', ('bar', 'baz')])
         c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz'))
         assert c._send_packet.call_count == 1
         expected_packet = packet.Packet(
-            packet.ACK, namespace='/', id=123, data=[['a', 'b']], binary=None
-        )
+            packet.ACK, namespace='/', id=123, data=[['a', 'b']])
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
             == expected_packet.encode()
         )
 
     def test_handle_event_with_id_two_arguments(self):
-        c = client.Client(binary=True)
+        c = client.Client()
         c._trigger_event = mock.MagicMock(return_value=('a', 'b'))
         c._send_packet = mock.MagicMock()
         c._handle_event('/', 123, ['foo', ('bar', 'baz')])
         c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz'))
         assert c._send_packet.call_count == 1
         expected_packet = packet.Packet(
-            packet.ACK, namespace='/', id=123, data=['a', 'b'], binary=None
-        )
+            packet.ACK, namespace='/', id=123, data=['a', 'b'])
         assert (
             c._send_packet.call_args_list[0][0][0].encode()
             == expected_packet.encode()
@@ -774,30 +766,30 @@ class TestClient(unittest.TestCase):
     def test_handle_error(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._handle_error('/', 'error')
-        assert c.namespaces == []
+        assert c.namespaces == {}
         assert not c.connected
         c._trigger_event.assert_called_once_with('connect_error', '/', 'error')
 
     def test_handle_error_with_no_arguments(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._handle_error('/', None)
-        assert c.namespaces == []
+        assert c.namespaces == {}
         assert not c.connected
         c._trigger_event.assert_called_once_with('connect_error', '/')
 
     def test_handle_error_namespace(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._handle_error('/bar', ['error', 'message'])
-        assert c.namespaces == ['/foo']
+        assert c.namespaces == {'/foo': '1'}
         assert c.connected
         c._trigger_event.assert_called_once_with(
             'connect_error', '/bar', 'error', 'message'
@@ -806,19 +798,19 @@ class TestClient(unittest.TestCase):
     def test_handle_error_namespace_with_no_arguments(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._trigger_event = mock.MagicMock()
         c._handle_error('/bar', None)
-        assert c.namespaces == ['/foo']
+        assert c.namespaces == {'/foo': '1'}
         assert c.connected
         c._trigger_event.assert_called_once_with('connect_error', '/bar')
 
     def test_handle_error_unknown_namespace(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/foo': '1', '/bar': '2'}
         c._handle_error('/baz', 'error')
-        assert c.namespaces == ['/foo', '/bar']
+        assert c.namespaces == {'/foo': '1', '/bar': '2'}
         assert c.connected
 
     def test_trigger_event(self):
@@ -927,10 +919,23 @@ class TestClient(unittest.TestCase):
 
     def test_handle_eio_connect(self):
         c = client.Client()
+        c.connection_namespaces = ['/', '/foo']
+        c._send_packet = mock.MagicMock()
         c.eio.sid = 'foo'
         assert c.sid is None
         c._handle_eio_connect()
         assert c.sid == 'foo'
+        assert c._send_packet.call_count == 2
+        expected_packet = packet.Packet(packet.CONNECT, namespace='/')
+        assert (
+            c._send_packet.call_args_list[0][0][0].encode()
+            == expected_packet.encode()
+        )
+        expected_packet = packet.Packet(packet.CONNECT, namespace='/foo')
+        assert (
+            c._send_packet.call_args_list[1][0][0].encode()
+            == expected_packet.encode()
+        )
 
     def test_handle_eio_message(self):
         c = client.Client()
@@ -940,10 +945,10 @@ class TestClient(unittest.TestCase):
         c._handle_ack = mock.MagicMock()
         c._handle_error = mock.MagicMock()
 
-        c._handle_eio_message('0')
-        c._handle_connect.assert_called_with(None)
-        c._handle_eio_message('0/foo')
-        c._handle_connect.assert_called_with('/foo')
+        c._handle_eio_message('0{"sid":"123"}')
+        c._handle_connect.assert_called_with(None, {'sid': '123'})
+        c._handle_eio_message('0/foo,{"sid":"123"}')
+        c._handle_connect.assert_called_with('/foo', {'sid': '123'})
         c._handle_eio_message('1')
         c._handle_disconnect.assert_called_with(None)
         c._handle_eio_message('1/foo')
@@ -981,6 +986,7 @@ class TestClient(unittest.TestCase):
 
     def test_eio_disconnect(self):
         c = client.Client()
+        c.namespaces = {'/': '1'}
         c.connected = True
         c._trigger_event = mock.MagicMock()
         c.start_background_task = mock.MagicMock()
@@ -994,7 +1000,7 @@ class TestClient(unittest.TestCase):
     def test_eio_disconnect_namespaces(self):
         c = client.Client()
         c.connected = True
-        c.namespaces = ['/foo', '/bar']
+        c.namespaces = {'/': '1', '/foo': '2', '/bar': '3'}
         c._trigger_event = mock.MagicMock()
         c.start_background_task = mock.MagicMock()
         c.sid = 'foo'