python-socketio 5.12.1__tar.gz → 5.13.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. {python_socketio-5.12.1/src/python_socketio.egg-info → python_socketio-5.13.0}/PKG-INFO +3 -2
  2. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/server.rst +0 -6
  3. {python_socketio-5.12.1 → python_socketio-5.13.0}/pyproject.toml +1 -1
  4. {python_socketio-5.12.1 → python_socketio-5.13.0/src/python_socketio.egg-info}/PKG-INFO +3 -2
  5. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/python_socketio.egg-info/SOURCES.txt +1 -0
  6. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_client.py +3 -2
  7. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_redis_manager.py +17 -5
  8. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_simple_client.py +4 -1
  9. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/client.py +2 -2
  10. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/redis_manager.py +43 -5
  11. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/simple_client.py +4 -1
  12. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/async/test_client.py +2 -2
  13. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/async/test_simple_client.py +33 -28
  14. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_client.py +2 -2
  15. python_socketio-5.13.0/tests/common/test_redis_manager.py +38 -0
  16. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_simple_client.py +27 -17
  17. {python_socketio-5.12.1 → python_socketio-5.13.0}/LICENSE +0 -0
  18. {python_socketio-5.12.1 → python_socketio-5.13.0}/MANIFEST.in +0 -0
  19. {python_socketio-5.12.1 → python_socketio-5.13.0}/README.md +0 -0
  20. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/Makefile +0 -0
  21. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/_static/README.md +0 -0
  22. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/_static/custom.css +0 -0
  23. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/api.rst +0 -0
  24. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/client.rst +0 -0
  25. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/conf.py +0 -0
  26. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/index.rst +0 -0
  27. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/intro.rst +0 -0
  28. {python_socketio-5.12.1 → python_socketio-5.13.0}/docs/make.bat +0 -0
  29. {python_socketio-5.12.1 → python_socketio-5.13.0}/setup.cfg +0 -0
  30. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/python_socketio.egg-info/dependency_links.txt +0 -0
  31. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/python_socketio.egg-info/not-zip-safe +0 -0
  32. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/python_socketio.egg-info/requires.txt +0 -0
  33. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/python_socketio.egg-info/top_level.txt +0 -0
  34. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/__init__.py +0 -0
  35. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/admin.py +0 -0
  36. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/asgi.py +0 -0
  37. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_admin.py +0 -0
  38. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_aiopika_manager.py +0 -0
  39. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_manager.py +0 -0
  40. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_namespace.py +0 -0
  41. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_pubsub_manager.py +0 -0
  42. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/async_server.py +0 -0
  43. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/base_client.py +0 -0
  44. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/base_manager.py +0 -0
  45. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/base_namespace.py +0 -0
  46. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/base_server.py +0 -0
  47. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/exceptions.py +0 -0
  48. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/kafka_manager.py +0 -0
  49. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/kombu_manager.py +0 -0
  50. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/manager.py +0 -0
  51. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/middleware.py +0 -0
  52. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/msgpack_packet.py +0 -0
  53. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/namespace.py +0 -0
  54. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/packet.py +0 -0
  55. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/pubsub_manager.py +0 -0
  56. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/server.py +0 -0
  57. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/tornado.py +0 -0
  58. {python_socketio-5.12.1 → python_socketio-5.13.0}/src/socketio/zmq_manager.py +0 -0
  59. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/__init__.py +0 -0
  60. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/async/__init__.py +0 -0
  61. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/async/test_admin.py +0 -0
  62. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/async/test_manager.py +0 -0
  63. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/async/test_namespace.py +0 -0
  64. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/async/test_pubsub_manager.py +0 -0
  65. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/async/test_server.py +0 -0
  66. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/asyncio_web_server.py +0 -0
  67. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/__init__.py +0 -0
  68. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_admin.py +0 -0
  69. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_manager.py +0 -0
  70. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_middleware.py +0 -0
  71. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_msgpack_packet.py +0 -0
  72. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_namespace.py +0 -0
  73. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_packet.py +0 -0
  74. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_pubsub_manager.py +0 -0
  75. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/common/test_server.py +0 -0
  76. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/README.md +0 -0
  77. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/binary_packet.py +0 -0
  78. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/json_packet.py +0 -0
  79. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/namespace_packet.py +0 -0
  80. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/run.sh +0 -0
  81. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/server_receive.py +0 -0
  82. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/server_send.py +0 -0
  83. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/server_send_broadcast.py +0 -0
  84. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/performance/text_packet.py +0 -0
  85. {python_socketio-5.12.1 → python_socketio-5.13.0}/tests/web_server.py +0 -0
  86. {python_socketio-5.12.1 → python_socketio-5.13.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: python-socketio
3
- Version: 5.12.1
3
+ Version: 5.13.0
4
4
  Summary: Socket.IO server and client for Python
5
5
  Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/miguelgrinberg/python-socketio
@@ -22,6 +22,7 @@ Provides-Extra: asyncio-client
22
22
  Requires-Dist: aiohttp>=3.4; extra == "asyncio-client"
23
23
  Provides-Extra: docs
24
24
  Requires-Dist: sphinx; extra == "docs"
25
+ Dynamic: license-file
25
26
 
26
27
  python-socketio
27
28
  ===============
@@ -19,12 +19,6 @@ command::
19
19
 
20
20
  pip install python-socketio
21
21
 
22
- If you plan to build an asynchronous web server based on the ``asyncio``
23
- package, then you can install this package and some additional dependencies
24
- that are needed with::
25
-
26
- pip install "python-socketio[asyncio]"
27
-
28
22
  Creating a Server Instance
29
23
  --------------------------
30
24
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-socketio"
3
- version = "5.12.1"
3
+ version = "5.13.0"
4
4
  authors = [
5
5
  { name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com" },
6
6
  ]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: python-socketio
3
- Version: 5.12.1
3
+ Version: 5.13.0
4
4
  Summary: Socket.IO server and client for Python
5
5
  Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/miguelgrinberg/python-socketio
@@ -22,6 +22,7 @@ Provides-Extra: asyncio-client
22
22
  Requires-Dist: aiohttp>=3.4; extra == "asyncio-client"
23
23
  Provides-Extra: docs
24
24
  Requires-Dist: sphinx; extra == "docs"
25
+ Dynamic: license-file
25
26
 
26
27
  python-socketio
27
28
  ===============
@@ -70,6 +70,7 @@ tests/common/test_msgpack_packet.py
70
70
  tests/common/test_namespace.py
71
71
  tests/common/test_packet.py
72
72
  tests/common/test_pubsub_manager.py
73
+ tests/common/test_redis_manager.py
73
74
  tests/common/test_server.py
74
75
  tests/common/test_simple_client.py
75
76
  tests/performance/README.md
@@ -158,7 +158,7 @@ class AsyncClient(base_client.BaseClient):
158
158
  await self._handle_reconnect()
159
159
  if self.eio.state == 'connected':
160
160
  return
161
- raise exceptions.ConnectionError(exc.args[0]) from None
161
+ raise exceptions.ConnectionError(exc.args[0]) from exc
162
162
 
163
163
  if wait:
164
164
  try:
@@ -191,6 +191,7 @@ class AsyncClient(base_client.BaseClient):
191
191
  if not self._reconnect_task:
192
192
  if self.eio.state == 'connected': # pragma: no cover
193
193
  # connected while sleeping above
194
+ print('oops')
194
195
  continue
195
196
  break
196
197
  await self._reconnect_task
@@ -324,7 +325,7 @@ class AsyncClient(base_client.BaseClient):
324
325
  for n in self.namespaces:
325
326
  await self._send_packet(self.packet_class(packet.DISCONNECT,
326
327
  namespace=n))
327
- await self.eio.disconnect(abort=True)
328
+ await self.eio.disconnect()
328
329
 
329
330
  async def shutdown(self):
330
331
  """Stop the client.
@@ -13,6 +13,7 @@ except ImportError: # pragma: no cover
13
13
  RedisError = None
14
14
 
15
15
  from .async_pubsub_manager import AsyncPubSubManager
16
+ from .redis_manager import parse_redis_sentinel_url
16
17
 
17
18
 
18
19
  class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover
@@ -29,15 +30,18 @@ class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover
29
30
  client_manager=socketio.AsyncRedisManager(url))
30
31
 
31
32
  :param url: The connection URL for the Redis server. For a default Redis
32
- store running on the same host, use ``redis://``. To use an
33
- SSL connection, use ``rediss://``.
33
+ store running on the same host, use ``redis://``. To use a
34
+ TLS connection, use ``rediss://``. To use Redis Sentinel, use
35
+ ``redis+sentinel://`` with a comma-separated list of hosts
36
+ and the service name after the db in the URL path. Example:
37
+ ``redis+sentinel://user:pw@host1:1234,host2:2345/0/myredis``.
34
38
  :param channel: The channel name on which the server sends and receives
35
39
  notifications. Must be the same in all the servers.
36
40
  :param write_only: If set to ``True``, only initialize to emit events. The
37
41
  default of ``False`` initializes the class for emitting
38
42
  and receiving.
39
43
  :param redis_options: additional keyword arguments to be passed to
40
- ``aioredis.from_url()``.
44
+ ``Redis.from_url()`` or ``Sentinel()``.
41
45
  """
42
46
  name = 'aioredis'
43
47
 
@@ -54,8 +58,16 @@ class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover
54
58
  super().__init__(channel=channel, write_only=write_only, logger=logger)
55
59
 
56
60
  def _redis_connect(self):
57
- self.redis = aioredis.Redis.from_url(self.redis_url,
58
- **self.redis_options)
61
+ if not self.redis_url.startswith('redis+sentinel://'):
62
+ self.redis = aioredis.Redis.from_url(self.redis_url,
63
+ **self.redis_options)
64
+ else:
65
+ sentinels, service_name, connection_kwargs = \
66
+ parse_redis_sentinel_url(self.redis_url)
67
+ kwargs = self.redis_options
68
+ kwargs.update(connection_kwargs)
69
+ sentinel = aioredis.sentinel.Sentinel(sentinels, **kwargs)
70
+ self.redis = sentinel.master_for(service_name or self.channel)
59
71
  self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True)
60
72
 
61
73
  async def _publish(self, data):
@@ -12,6 +12,8 @@ class AsyncSimpleClient:
12
12
  The positional and keyword arguments given in the constructor are passed
13
13
  to the underlying :func:`socketio.AsyncClient` object.
14
14
  """
15
+ client_class = AsyncClient
16
+
15
17
  def __init__(self, *args, **kwargs):
16
18
  self.client_args = args
17
19
  self.client_kwargs = kwargs
@@ -60,7 +62,8 @@ class AsyncSimpleClient:
60
62
  self.namespace = namespace
61
63
  self.input_buffer = []
62
64
  self.input_event.clear()
63
- self.client = AsyncClient(*self.client_args, **self.client_kwargs)
65
+ self.client = self.client_class(
66
+ *self.client_args, **self.client_kwargs)
64
67
 
65
68
  @self.client.event(namespace=self.namespace)
66
69
  def connect(): # pragma: no cover
@@ -156,7 +156,7 @@ class Client(base_client.BaseClient):
156
156
  self._handle_reconnect()
157
157
  if self.eio.state == 'connected':
158
158
  return
159
- raise exceptions.ConnectionError(exc.args[0]) from None
159
+ raise exceptions.ConnectionError(exc.args[0]) from exc
160
160
 
161
161
  if wait:
162
162
  while self._connect_event.wait(timeout=wait_timeout):
@@ -306,7 +306,7 @@ class Client(base_client.BaseClient):
306
306
  for n in self.namespaces:
307
307
  self._send_packet(self.packet_class(
308
308
  packet.DISCONNECT, namespace=n))
309
- self.eio.disconnect(abort=True)
309
+ self.eio.disconnect()
310
310
 
311
311
  def shutdown(self):
312
312
  """Stop the client.
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import pickle
3
3
  import time
4
+ from urllib.parse import urlparse
4
5
 
5
6
  try:
6
7
  import redis
@@ -12,6 +13,32 @@ from .pubsub_manager import PubSubManager
12
13
  logger = logging.getLogger('socketio')
13
14
 
14
15
 
16
+ def parse_redis_sentinel_url(url):
17
+ """Parse a Redis Sentinel URL with the format:
18
+ redis+sentinel://[:password]@host1:port1,host2:port2,.../db/service_name
19
+ """
20
+ parsed_url = urlparse(url)
21
+ if parsed_url.scheme != 'redis+sentinel':
22
+ raise ValueError('Invalid Redis Sentinel URL')
23
+ sentinels = []
24
+ for host_port in parsed_url.netloc.split('@')[-1].split(','):
25
+ host, port = host_port.rsplit(':', 1)
26
+ sentinels.append((host, int(port)))
27
+ kwargs = {}
28
+ if parsed_url.username:
29
+ kwargs['username'] = parsed_url.username
30
+ if parsed_url.password:
31
+ kwargs['password'] = parsed_url.password
32
+ service_name = None
33
+ if parsed_url.path:
34
+ parts = parsed_url.path.split('/')
35
+ if len(parts) >= 2 and parts[1] != '':
36
+ kwargs['db'] = int(parts[1])
37
+ if len(parts) >= 3 and parts[2] != '':
38
+ service_name = parts[2]
39
+ return sentinels, service_name, kwargs
40
+
41
+
15
42
  class RedisManager(PubSubManager): # pragma: no cover
16
43
  """Redis based client manager.
17
44
 
@@ -27,15 +54,18 @@ class RedisManager(PubSubManager): # pragma: no cover
27
54
  server = socketio.Server(client_manager=socketio.RedisManager(url))
28
55
 
29
56
  :param url: The connection URL for the Redis server. For a default Redis
30
- store running on the same host, use ``redis://``. To use an
31
- SSL connection, use ``rediss://``.
57
+ store running on the same host, use ``redis://``. To use a
58
+ TLS connection, use ``rediss://``. To use Redis Sentinel, use
59
+ ``redis+sentinel://`` with a comma-separated list of hosts
60
+ and the service name after the db in the URL path. Example:
61
+ ``redis+sentinel://user:pw@host1:1234,host2:2345/0/myredis``.
32
62
  :param channel: The channel name on which the server sends and receives
33
63
  notifications. Must be the same in all the servers.
34
64
  :param write_only: If set to ``True``, only initialize to emit events. The
35
65
  default of ``False`` initializes the class for emitting
36
66
  and receiving.
37
67
  :param redis_options: additional keyword arguments to be passed to
38
- ``Redis.from_url()``.
68
+ ``Redis.from_url()`` or ``Sentinel()``.
39
69
  """
40
70
  name = 'redis'
41
71
 
@@ -66,8 +96,16 @@ class RedisManager(PubSubManager): # pragma: no cover
66
96
  'with ' + self.server.async_mode)
67
97
 
68
98
  def _redis_connect(self):
69
- self.redis = redis.Redis.from_url(self.redis_url,
70
- **self.redis_options)
99
+ if not self.redis_url.startswith('redis+sentinel://'):
100
+ self.redis = redis.Redis.from_url(self.redis_url,
101
+ **self.redis_options)
102
+ else:
103
+ sentinels, service_name, connection_kwargs = \
104
+ parse_redis_sentinel_url(self.redis_url)
105
+ kwargs = self.redis_options
106
+ kwargs.update(connection_kwargs)
107
+ sentinel = redis.sentinel.Sentinel(sentinels, **kwargs)
108
+ self.redis = sentinel.master_for(service_name or self.channel)
71
109
  self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True)
72
110
 
73
111
  def _publish(self, data):
@@ -12,6 +12,8 @@ class SimpleClient:
12
12
  The positional and keyword arguments given in the constructor are passed
13
13
  to the underlying :func:`socketio.Client` object.
14
14
  """
15
+ client_class = Client
16
+
15
17
  def __init__(self, *args, **kwargs):
16
18
  self.client_args = args
17
19
  self.client_kwargs = kwargs
@@ -58,7 +60,8 @@ class SimpleClient:
58
60
  self.namespace = namespace
59
61
  self.input_buffer = []
60
62
  self.input_event.clear()
61
- self.client = Client(*self.client_args, **self.client_kwargs)
63
+ self.client = self.client_class(
64
+ *self.client_args, **self.client_kwargs)
62
65
 
63
66
  @self.client.event(namespace=self.namespace)
64
67
  def connect(): # pragma: no cover
@@ -475,7 +475,7 @@ class TestAsyncClient:
475
475
  c._send_packet.await_args_list[0][0][0].encode()
476
476
  == expected_packet.encode()
477
477
  )
478
- c.eio.disconnect.assert_awaited_once_with(abort=True)
478
+ c.eio.disconnect.assert_awaited_once_with()
479
479
 
480
480
  async def test_disconnect_namespaces(self):
481
481
  c = async_client.AsyncClient()
@@ -993,7 +993,7 @@ class TestAsyncClient:
993
993
  c._send_packet.await_args_list[0][0][0].encode()
994
994
  == expected_packet.encode()
995
995
  )
996
- c.eio.disconnect.assert_awaited_once_with(abort=True)
996
+ c.eio.disconnect.assert_awaited_once_with()
997
997
 
998
998
  async def test_shutdown_disconnect_namespaces(self):
999
999
  c = async_client.AsyncClient()
@@ -16,46 +16,51 @@ class TestAsyncAsyncSimpleClient:
16
16
  assert not client.connected
17
17
 
18
18
  async def test_connect(self):
19
+ mock_client = mock.MagicMock()
20
+ original_client_class = AsyncSimpleClient.client_class
21
+ AsyncSimpleClient.client_class = mock_client
22
+
19
23
  client = AsyncSimpleClient(123, a='b')
20
- with mock.patch('socketio.async_simple_client.AsyncClient') \
21
- as mock_client:
24
+ mock_client.return_value.connect = mock.AsyncMock()
25
+
26
+ await client.connect('url', headers='h', auth='a', transports='t',
27
+ namespace='n', socketio_path='s',
28
+ wait_timeout='w')
29
+ mock_client.assert_called_once_with(123, a='b')
30
+ assert client.client == mock_client()
31
+ mock_client().connect.assert_awaited_once_with(
32
+ 'url', headers='h', auth='a', transports='t',
33
+ namespaces=['n'], socketio_path='s', wait_timeout='w')
34
+ mock_client().event.call_count == 3
35
+ mock_client().on.assert_called_once_with('*', namespace='n')
36
+ assert client.namespace == 'n'
37
+ assert not client.input_event.is_set()
38
+
39
+ AsyncSimpleClient.client_class = original_client_class
40
+
41
+ async def test_connect_context_manager(self):
42
+ mock_client = mock.MagicMock()
43
+ original_client_class = AsyncSimpleClient.client_class
44
+ AsyncSimpleClient.client_class = mock_client
45
+
46
+ async with AsyncSimpleClient(123, a='b') as client:
22
47
  mock_client.return_value.connect = mock.AsyncMock()
23
48
 
24
- await client.connect('url', headers='h', auth='a', transports='t',
25
- namespace='n', socketio_path='s',
26
- wait_timeout='w')
49
+ await client.connect('url', headers='h', auth='a',
50
+ transports='t', namespace='n',
51
+ socketio_path='s', wait_timeout='w')
27
52
  mock_client.assert_called_once_with(123, a='b')
28
53
  assert client.client == mock_client()
29
54
  mock_client().connect.assert_awaited_once_with(
30
55
  'url', headers='h', auth='a', transports='t',
31
56
  namespaces=['n'], socketio_path='s', wait_timeout='w')
32
57
  mock_client().event.call_count == 3
33
- mock_client().on.assert_called_once_with('*', namespace='n')
58
+ mock_client().on.assert_called_once_with(
59
+ '*', namespace='n')
34
60
  assert client.namespace == 'n'
35
61
  assert not client.input_event.is_set()
36
62
 
37
- async def test_connect_context_manager(self):
38
- async def _t():
39
- async with AsyncSimpleClient(123, a='b') as client:
40
- with mock.patch('socketio.async_simple_client.AsyncClient') \
41
- as mock_client:
42
- mock_client.return_value.connect = mock.AsyncMock()
43
-
44
- await client.connect('url', headers='h', auth='a',
45
- transports='t', namespace='n',
46
- socketio_path='s', wait_timeout='w')
47
- mock_client.assert_called_once_with(123, a='b')
48
- assert client.client == mock_client()
49
- mock_client().connect.assert_awaited_once_with(
50
- 'url', headers='h', auth='a', transports='t',
51
- namespaces=['n'], socketio_path='s', wait_timeout='w')
52
- mock_client().event.call_count == 3
53
- mock_client().on.assert_called_once_with(
54
- '*', namespace='n')
55
- assert client.namespace == 'n'
56
- assert not client.input_event.is_set()
57
-
58
- await _t()
63
+ AsyncSimpleClient.client_class = original_client_class
59
64
 
60
65
  async def test_connect_twice(self):
61
66
  client = AsyncSimpleClient(123, a='b')
@@ -633,7 +633,7 @@ class TestClient:
633
633
  c._send_packet.call_args_list[0][0][0].encode()
634
634
  == expected_packet.encode()
635
635
  )
636
- c.eio.disconnect.assert_called_once_with(abort=True)
636
+ c.eio.disconnect.assert_called_once_with()
637
637
 
638
638
  def test_disconnect_namespaces(self):
639
639
  c = client.Client()
@@ -1138,7 +1138,7 @@ class TestClient:
1138
1138
  c._send_packet.call_args_list[0][0][0].encode()
1139
1139
  == expected_packet.encode()
1140
1140
  )
1141
- c.eio.disconnect.assert_called_once_with(abort=True)
1141
+ c.eio.disconnect.assert_called_once_with()
1142
1142
 
1143
1143
  def test_shutdown_disconnect_namespaces(self):
1144
1144
  c = client.Client()
@@ -0,0 +1,38 @@
1
+ import pytest
2
+
3
+ from socketio.redis_manager import parse_redis_sentinel_url
4
+
5
+
6
+ class TestPubSubManager:
7
+ def test_sentinel_url_parser(self):
8
+ with pytest.raises(ValueError):
9
+ parse_redis_sentinel_url('redis://localhost:6379/0')
10
+
11
+ assert parse_redis_sentinel_url(
12
+ 'redis+sentinel://localhost:6379'
13
+ ) == (
14
+ [('localhost', 6379)],
15
+ None,
16
+ {}
17
+ )
18
+ assert parse_redis_sentinel_url(
19
+ 'redis+sentinel://192.168.0.1:6379,192.168.0.2:6379/'
20
+ ) == (
21
+ [('192.168.0.1', 6379), ('192.168.0.2', 6379)],
22
+ None,
23
+ {}
24
+ )
25
+ assert parse_redis_sentinel_url(
26
+ 'redis+sentinel://h1:6379,h2:6379/0'
27
+ ) == (
28
+ [('h1', 6379), ('h2', 6379)],
29
+ None,
30
+ {'db': 0}
31
+ )
32
+ assert parse_redis_sentinel_url(
33
+ 'redis+sentinel://user:password@h1:6379,h2:6379,h1:6380/0/myredis'
34
+ ) == (
35
+ [('h1', 6379), ('h2', 6379), ('h1', 6380)],
36
+ 'myredis',
37
+ {'username': 'user', 'password': 'password', 'db': 0}
38
+ )
@@ -14,10 +14,34 @@ class TestSimpleClient:
14
14
  assert not client.connected
15
15
 
16
16
  def test_connect(self):
17
+ mock_client = mock.MagicMock()
18
+ original_client_class = SimpleClient.client_class
19
+ SimpleClient.client_class = mock_client
20
+
17
21
  client = SimpleClient(123, a='b')
18
- with mock.patch('socketio.simple_client.Client') as mock_client:
22
+ client.connect('url', headers='h', auth='a', transports='t',
23
+ namespace='n', socketio_path='s', wait_timeout='w')
24
+ mock_client.assert_called_once_with(123, a='b')
25
+ assert client.client == mock_client()
26
+ mock_client().connect.assert_called_once_with(
27
+ 'url', headers='h', auth='a', transports='t',
28
+ namespaces=['n'], socketio_path='s', wait_timeout='w')
29
+ mock_client().event.call_count == 3
30
+ mock_client().on.assert_called_once_with('*', namespace='n')
31
+ assert client.namespace == 'n'
32
+ assert not client.input_event.is_set()
33
+
34
+ SimpleClient.client_class = original_client_class
35
+
36
+ def test_connect_context_manager(self):
37
+ mock_client = mock.MagicMock()
38
+ original_client_class = SimpleClient.client_class
39
+ SimpleClient.client_class = mock_client
40
+
41
+ with SimpleClient(123, a='b') as client:
19
42
  client.connect('url', headers='h', auth='a', transports='t',
20
- namespace='n', socketio_path='s', wait_timeout='w')
43
+ namespace='n', socketio_path='s',
44
+ wait_timeout='w')
21
45
  mock_client.assert_called_once_with(123, a='b')
22
46
  assert client.client == mock_client()
23
47
  mock_client().connect.assert_called_once_with(
@@ -28,21 +52,7 @@ class TestSimpleClient:
28
52
  assert client.namespace == 'n'
29
53
  assert not client.input_event.is_set()
30
54
 
31
- def test_connect_context_manager(self):
32
- with SimpleClient(123, a='b') as client:
33
- with mock.patch('socketio.simple_client.Client') as mock_client:
34
- client.connect('url', headers='h', auth='a', transports='t',
35
- namespace='n', socketio_path='s',
36
- wait_timeout='w')
37
- mock_client.assert_called_once_with(123, a='b')
38
- assert client.client == mock_client()
39
- mock_client().connect.assert_called_once_with(
40
- 'url', headers='h', auth='a', transports='t',
41
- namespaces=['n'], socketio_path='s', wait_timeout='w')
42
- mock_client().event.call_count == 3
43
- mock_client().on.assert_called_once_with('*', namespace='n')
44
- assert client.namespace == 'n'
45
- assert not client.input_event.is_set()
55
+ SimpleClient.client_class = original_client_class
46
56
 
47
57
  def test_connect_twice(self):
48
58
  client = SimpleClient(123, a='b')