python-socketio
Advanced tools
+19
-0
@@ -1092,2 +1092,21 @@ The Socket.IO Server | ||
| Deploying the Message Queue for Production | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| For a production deployment there are a few recommendations to keep your | ||
| application secure. | ||
| First of all, the message queue should never be listening on a public network | ||
| interface, to ensure that external clients never connect to it. For a single | ||
| node deployment, the queue should only listen on `localhost`. For a multi-node | ||
| system the use of a private network (VPC), where the communication between | ||
| servers can happen privately is highly recommended. | ||
| In addition, all message queues support authentication and encryption, which | ||
| can strenthen the security of the deployment. Authentication ensures that only | ||
| the Socket.IO servers and related processes have access, while encryption | ||
| prevents data from being collected by a third-party that is listening on the | ||
| network. Access credentials can be included in the connection URLs that are | ||
| passed to the client managers. | ||
| Horizontal Scaling | ||
@@ -1094,0 +1113,0 @@ ~~~~~~~~~~~~~~~~~~ |
+2
-2
| Metadata-Version: 2.4 | ||
| Name: python-socketio | ||
| Version: 5.13.0 | ||
| Version: 5.14.0 | ||
| Summary: Socket.IO server and client for Python | ||
| Author-email: Miguel Grinberg <miguel.grinberg@gmail.com> | ||
| License: MIT | ||
| Project-URL: Homepage, https://github.com/miguelgrinberg/python-socketio | ||
@@ -11,3 +12,2 @@ Project-URL: Bug Tracker, https://github.com/miguelgrinberg/python-socketio/issues | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: License :: OSI Approved :: MIT License | ||
| Classifier: Operating System :: OS Independent | ||
@@ -14,0 +14,0 @@ Requires-Python: >=3.8 |
+2
-2
| [project] | ||
| name = "python-socketio" | ||
| version = "5.13.0" | ||
| version = "5.14.0" | ||
| license = {text = "MIT"} | ||
| authors = [ | ||
@@ -12,3 +13,2 @@ { name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com" }, | ||
| "Programming Language :: Python :: 3", | ||
| "License :: OSI Approved :: MIT License", | ||
| "Operating System :: OS Independent", | ||
@@ -15,0 +15,0 @@ ] |
| Metadata-Version: 2.4 | ||
| Name: python-socketio | ||
| Version: 5.13.0 | ||
| Version: 5.14.0 | ||
| Summary: Socket.IO server and client for Python | ||
| Author-email: Miguel Grinberg <miguel.grinberg@gmail.com> | ||
| License: MIT | ||
| Project-URL: Homepage, https://github.com/miguelgrinberg/python-socketio | ||
@@ -11,3 +12,2 @@ Project-URL: Bug Tracker, https://github.com/miguelgrinberg/python-socketio/issues | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: License :: OSI Approved :: MIT License | ||
| Classifier: Operating System :: OS Independent | ||
@@ -14,0 +14,0 @@ Requires-Python: >=3.8 |
| import asyncio | ||
| import pickle | ||
| from engineio import json | ||
| from .async_pubsub_manager import AsyncPubSubManager | ||
@@ -46,2 +46,3 @@ | ||
| 'virtualenv).') | ||
| super().__init__(channel=channel, write_only=write_only, logger=logger) | ||
| self.url = url | ||
@@ -52,3 +53,2 @@ self._lock = asyncio.Lock() | ||
| self.publisher_exchange = None | ||
| super().__init__(channel=channel, write_only=write_only, logger=logger) | ||
@@ -87,3 +87,3 @@ async def _connection(self): | ||
| aio_pika.Message( | ||
| body=pickle.dumps(data), | ||
| body=json.dumps(data), | ||
| delivery_mode=aio_pika.DeliveryMode.PERSISTENT | ||
@@ -119,3 +119,3 @@ ), routing_key='*', | ||
| async with message.process(): | ||
| yield pickle.loads(message.body) | ||
| yield message.body | ||
| retry_sleep = 1 | ||
@@ -122,0 +122,0 @@ except aio_pika.AMQPException: |
@@ -142,2 +142,3 @@ import asyncio | ||
| self.namespaces = {} | ||
| self.failed_namespaces = [] | ||
| if self._connect_event is None: | ||
@@ -170,3 +171,4 @@ self._connect_event = self.eio.create_event() | ||
| self._connect_event.clear() | ||
| if set(self.namespaces) == set(self.connection_namespaces): | ||
| if len(self.namespaces) + len(self.failed_namespaces) == \ | ||
| len(self.connection_namespaces): | ||
| break | ||
@@ -178,3 +180,4 @@ except asyncio.TimeoutError: | ||
| raise exceptions.ConnectionError( | ||
| 'One or more namespaces failed to connect') | ||
| 'One or more namespaces failed to connect' | ||
| ', '.join(self.failed_namespaces)) | ||
@@ -197,3 +200,2 @@ self.connected = True | ||
| # connected while sleeping above | ||
| print('oops') | ||
| continue | ||
@@ -412,3 +414,3 @@ break | ||
| self.connected = False | ||
| await self.eio.disconnect(abort=True) | ||
| await self.eio.disconnect() | ||
@@ -457,2 +459,3 @@ async def _handle_event(self, namespace, id, data): | ||
| await self._trigger_event('connect_error', namespace, *data) | ||
| self.failed_namespaces.append(namespace) | ||
| self._connect_event.set() | ||
@@ -459,0 +462,0 @@ if namespace in self.namespaces: |
@@ -6,3 +6,2 @@ import asyncio | ||
| from engineio import json | ||
| import pickle | ||
@@ -206,12 +205,6 @@ from .async_manager import AsyncManager | ||
| else: | ||
| if isinstance(message, bytes): # pragma: no cover | ||
| try: | ||
| data = pickle.loads(message) | ||
| except: | ||
| pass | ||
| if data is None: | ||
| try: | ||
| data = json.loads(message) | ||
| except: | ||
| pass | ||
| try: | ||
| data = json.loads(message) | ||
| except: | ||
| pass | ||
| if data and 'method' in data: | ||
@@ -218,0 +211,0 @@ self._get_logger().debug('pubsub message: {}'.format( |
| import asyncio | ||
| import pickle | ||
| from urllib.parse import urlparse | ||
@@ -15,2 +15,10 @@ try: # pragma: no cover | ||
| try: # pragma: no cover | ||
| from valkey import asyncio as valkey | ||
| from valkey.exceptions import ValkeyError | ||
| except ImportError: # pragma: no cover | ||
| valkey = None | ||
| ValkeyError = None | ||
| from engineio import json | ||
| from .async_pubsub_manager import AsyncPubSubManager | ||
@@ -51,17 +59,36 @@ from .redis_manager import parse_redis_sentinel_url | ||
| write_only=False, logger=None, redis_options=None): | ||
| if aioredis is None: | ||
| if aioredis is None and valkey is None: | ||
| raise RuntimeError('Redis package is not installed ' | ||
| '(Run "pip install redis" in your virtualenv).') | ||
| if not hasattr(aioredis.Redis, 'from_url'): | ||
| '(Run "pip install redis" or ' | ||
| '"pip install valkey" ' | ||
| 'in your virtualenv).') | ||
| if aioredis and not hasattr(aioredis.Redis, 'from_url'): | ||
| raise RuntimeError('Version 2 of aioredis package is required.') | ||
| super().__init__(channel=channel, write_only=write_only, logger=logger) | ||
| self.redis_url = url | ||
| self.redis_options = redis_options or {} | ||
| self._redis_connect() | ||
| super().__init__(channel=channel, write_only=write_only, logger=logger) | ||
| def _get_redis_module_and_error(self): | ||
| parsed_url = urlparse(self.redis_url) | ||
| schema = parsed_url.scheme.split('+', 1)[0].lower() | ||
| if schema == 'redis': | ||
| if aioredis is None or RedisError is None: | ||
| raise RuntimeError('Redis package is not installed ' | ||
| '(Run "pip install redis" ' | ||
| 'in your virtualenv).') | ||
| return aioredis, RedisError | ||
| if schema == 'valkey': | ||
| if valkey is None or ValkeyError is None: | ||
| raise RuntimeError('Valkey package is not installed ' | ||
| '(Run "pip install valkey" ' | ||
| 'in your virtualenv).') | ||
| return valkey, ValkeyError | ||
| error_msg = f'Unsupported Redis URL schema: {schema}' | ||
| raise ValueError(error_msg) | ||
| def _redis_connect(self): | ||
| if not self.redis_url.startswith('redis+sentinel://'): | ||
| self.redis = aioredis.Redis.from_url(self.redis_url, | ||
| **self.redis_options) | ||
| else: | ||
| module, _ = self._get_redis_module_and_error() | ||
| parsed_url = urlparse(self.redis_url) | ||
| if parsed_url.scheme in {"redis+sentinel", "valkey+sentinel"}: | ||
| sentinels, service_name, connection_kwargs = \ | ||
@@ -71,4 +98,7 @@ parse_redis_sentinel_url(self.redis_url) | ||
| kwargs.update(connection_kwargs) | ||
| sentinel = aioredis.sentinel.Sentinel(sentinels, **kwargs) | ||
| sentinel = module.sentinel.Sentinel(sentinels, **kwargs) | ||
| self.redis = sentinel.master_for(service_name or self.channel) | ||
| else: | ||
| self.redis = module.Redis.from_url(self.redis_url, | ||
| **self.redis_options) | ||
| self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True) | ||
@@ -78,2 +108,3 @@ | ||
| retry = True | ||
| _, error = self._get_redis_module_and_error() | ||
| while True: | ||
@@ -84,11 +115,16 @@ try: | ||
| return await self.redis.publish( | ||
| self.channel, pickle.dumps(data)) | ||
| except RedisError: | ||
| self.channel, json.dumps(data)) | ||
| except error as exc: | ||
| if retry: | ||
| self._get_logger().error('Cannot publish to redis... ' | ||
| 'retrying') | ||
| self._get_logger().error( | ||
| 'Cannot publish to redis... ' | ||
| 'retrying', | ||
| extra={"redis_exception": str(exc)}) | ||
| retry = False | ||
| else: | ||
| self._get_logger().error('Cannot publish to redis... ' | ||
| 'giving up') | ||
| self._get_logger().error( | ||
| 'Cannot publish to redis... ' | ||
| 'giving up', | ||
| extra={"redis_exception": str(exc)}) | ||
| break | ||
@@ -99,2 +135,3 @@ | ||
| connect = False | ||
| _, error = self._get_redis_module_and_error() | ||
| while True: | ||
@@ -108,6 +145,7 @@ try: | ||
| yield message | ||
| except RedisError: | ||
| except error as exc: | ||
| self._get_logger().error('Cannot receive from redis... ' | ||
| 'retrying in ' | ||
| '{} secs'.format(retry_sleep)) | ||
| f'{retry_sleep} secs', | ||
| extra={"redis_exception": str(exc)}) | ||
| connect = True | ||
@@ -114,0 +152,0 @@ await asyncio.sleep(retry_sleep) |
@@ -376,11 +376,11 @@ import asyncio | ||
| @eio.on('connect') | ||
| def on_connect(sid, environ): | ||
| async def on_connect(sid, environ): | ||
| username = authenticate_user(environ) | ||
| if not username: | ||
| return False | ||
| with eio.session(sid) as session: | ||
| async with eio.session(sid) as session: | ||
| session['username'] = username | ||
| @eio.on('message') | ||
| def on_message(sid, msg): | ||
| async def on_message(sid, msg): | ||
| async with eio.session(sid) as session: | ||
@@ -387,0 +387,0 @@ print('received message from ', session['username']) |
@@ -108,3 +108,3 @@ import asyncio | ||
| """ | ||
| return self.client.transport if self.client else '' | ||
| return self.client.transport() if self.client else '' | ||
@@ -167,2 +167,4 @@ async def emit(self, event, data=None): | ||
| timeout=timeout) | ||
| except TimeoutError: | ||
| raise | ||
| except SocketIOError: | ||
@@ -169,0 +171,0 @@ pass |
@@ -96,2 +96,3 @@ import itertools | ||
| self.namespaces = {} #: set of connected namespaces. | ||
| self.failed_namespaces = [] | ||
| self.handlers = {} | ||
@@ -98,0 +99,0 @@ self.namespace_handlers = {} |
@@ -140,2 +140,3 @@ import random | ||
| self.namespaces = {} | ||
| self.failed_namespaces = [] | ||
| if self._connect_event is None: | ||
@@ -165,3 +166,4 @@ self._connect_event = self.eio.create_event() | ||
| self._connect_event.clear() | ||
| if set(self.namespaces) == set(self.connection_namespaces): | ||
| if len(self.namespaces) + len(self.failed_namespaces) == \ | ||
| len(self.connection_namespaces): | ||
| break | ||
@@ -171,3 +173,4 @@ if set(self.namespaces) != set(self.connection_namespaces): | ||
| raise exceptions.ConnectionError( | ||
| 'One or more namespaces failed to connect') | ||
| 'One or more namespaces failed to connect: ' | ||
| ', '.join(self.failed_namespaces)) | ||
@@ -390,3 +393,3 @@ self.connected = True | ||
| self.connected = False | ||
| self.eio.disconnect(abort=True) | ||
| self.eio.disconnect() | ||
@@ -432,2 +435,3 @@ def _handle_event(self, namespace, id, data): | ||
| self._trigger_event('connect_error', namespace, *data) | ||
| self.failed_namespaces.append(namespace) | ||
| self._connect_event.set() | ||
@@ -447,3 +451,3 @@ if namespace in self.namespaces: | ||
| return handler(*args) | ||
| except TypeError: | ||
| except TypeError: # pragma: no cover | ||
| # the legacy disconnect event does not take a reason argument | ||
@@ -450,0 +454,0 @@ if event == 'disconnect': |
| import logging | ||
| import pickle | ||
@@ -9,2 +8,3 @@ try: | ||
| from engineio import json | ||
| from .pubsub_manager import PubSubManager | ||
@@ -57,3 +57,3 @@ | ||
| def _publish(self, data): | ||
| self.producer.send(self.channel, value=pickle.dumps(data)) | ||
| self.producer.send(self.channel, value=json.dumps(data)) | ||
| self.producer.flush() | ||
@@ -67,2 +67,2 @@ | ||
| if message.topic == self.channel: | ||
| yield pickle.loads(message.value) | ||
| yield message.value |
@@ -1,2 +0,1 @@ | ||
| import pickle | ||
| import time | ||
@@ -10,2 +9,3 @@ import uuid | ||
| from engineio import json | ||
| from .pubsub_manager import PubSubManager | ||
@@ -106,3 +106,3 @@ | ||
| self.publisher_connection) | ||
| producer_publish(pickle.dumps(data)) | ||
| producer_publish(json.dumps(data)) | ||
| break | ||
@@ -109,0 +109,0 @@ except (OSError, kombu.exceptions.KombuError): |
@@ -5,3 +5,2 @@ from functools import partial | ||
| from engineio import json | ||
| import pickle | ||
@@ -200,12 +199,6 @@ from .manager import Manager | ||
| else: | ||
| if isinstance(message, bytes): # pragma: no cover | ||
| try: | ||
| data = pickle.loads(message) | ||
| except: | ||
| pass | ||
| if data is None: | ||
| try: | ||
| data = json.loads(message) | ||
| except: | ||
| pass | ||
| try: | ||
| data = json.loads(message) | ||
| except: | ||
| pass | ||
| if data and 'method' in data: | ||
@@ -212,0 +205,0 @@ self._get_logger().debug('pubsub message: {}'.format( |
| import logging | ||
| import pickle | ||
| import time | ||
| from urllib.parse import urlparse | ||
| try: | ||
| try: # pragma: no cover | ||
| import redis | ||
| from redis.exceptions import RedisError | ||
| except ImportError: | ||
| redis = None | ||
| RedisError = None | ||
| try: # pragma: no cover | ||
| import valkey | ||
| from valkey.exceptions import ValkeyError | ||
| except ImportError: | ||
| valkey = None | ||
| ValkeyError = None | ||
| from engineio import json | ||
| from .pubsub_manager import PubSubManager | ||
@@ -21,3 +30,3 @@ | ||
| parsed_url = urlparse(url) | ||
| if parsed_url.scheme != 'redis+sentinel': | ||
| if parsed_url.scheme not in {'redis+sentinel', 'valkey+sentinel'}: | ||
| raise ValueError('Invalid Redis Sentinel URL') | ||
@@ -75,10 +84,11 @@ sentinels = [] | ||
| write_only=False, logger=None, redis_options=None): | ||
| if redis is None: | ||
| if redis is None and valkey is None: | ||
| raise RuntimeError('Redis package is not installed ' | ||
| '(Run "pip install redis" in your ' | ||
| 'virtualenv).') | ||
| '(Run "pip install redis" ' | ||
| 'or "pip install valkey" ' | ||
| 'in your virtualenv).') | ||
| super().__init__(channel=channel, write_only=write_only, logger=logger) | ||
| self.redis_url = url | ||
| self.redis_options = redis_options or {} | ||
| self._redis_connect() | ||
| super().__init__(channel=channel, write_only=write_only, logger=logger) | ||
@@ -100,7 +110,24 @@ def initialize(self): | ||
| def _get_redis_module_and_error(self): | ||
| parsed_url = urlparse(self.redis_url) | ||
| schema = parsed_url.scheme.split('+', 1)[0].lower() | ||
| if schema == 'redis': | ||
| if redis is None or RedisError is None: | ||
| raise RuntimeError('Redis package is not installed ' | ||
| '(Run "pip install redis" ' | ||
| 'in your virtualenv).') | ||
| return redis, RedisError | ||
| if schema == 'valkey': | ||
| if valkey is None or ValkeyError is None: | ||
| raise RuntimeError('Valkey package is not installed ' | ||
| '(Run "pip install valkey" ' | ||
| 'in your virtualenv).') | ||
| return valkey, ValkeyError | ||
| error_msg = f'Unsupported Redis URL schema: {schema}' | ||
| raise ValueError(error_msg) | ||
| def _redis_connect(self): | ||
| if not self.redis_url.startswith('redis+sentinel://'): | ||
| self.redis = redis.Redis.from_url(self.redis_url, | ||
| **self.redis_options) | ||
| else: | ||
| module, _ = self._get_redis_module_and_error() | ||
| parsed_url = urlparse(self.redis_url) | ||
| if parsed_url.scheme in {"redis+sentinel", "valkey+sentinel"}: | ||
| sentinels, service_name, connection_kwargs = \ | ||
@@ -110,4 +137,7 @@ parse_redis_sentinel_url(self.redis_url) | ||
| kwargs.update(connection_kwargs) | ||
| sentinel = redis.sentinel.Sentinel(sentinels, **kwargs) | ||
| sentinel = module.sentinel.Sentinel(sentinels, **kwargs) | ||
| self.redis = sentinel.master_for(service_name or self.channel) | ||
| else: | ||
| self.redis = module.Redis.from_url(self.redis_url, | ||
| **self.redis_options) | ||
| self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True) | ||
@@ -117,2 +147,3 @@ | ||
| retry = True | ||
| _, error = self._get_redis_module_and_error() | ||
| while True: | ||
@@ -122,9 +153,15 @@ try: | ||
| self._redis_connect() | ||
| return self.redis.publish(self.channel, pickle.dumps(data)) | ||
| except redis.exceptions.RedisError: | ||
| return self.redis.publish(self.channel, json.dumps(data)) | ||
| except error as exc: | ||
| if retry: | ||
| logger.error('Cannot publish to redis... retrying') | ||
| logger.error( | ||
| 'Cannot publish to redis... retrying', | ||
| extra={"redis_exception": str(exc)} | ||
| ) | ||
| retry = False | ||
| else: | ||
| logger.error('Cannot publish to redis... giving up') | ||
| logger.error( | ||
| 'Cannot publish to redis... giving up', | ||
| extra={"redis_exception": str(exc)} | ||
| ) | ||
| break | ||
@@ -135,2 +172,3 @@ | ||
| connect = False | ||
| _, error = self._get_redis_module_and_error() | ||
| while True: | ||
@@ -143,5 +181,6 @@ try: | ||
| yield from self.pubsub.listen() | ||
| except redis.exceptions.RedisError: | ||
| except error as exc: | ||
| logger.error('Cannot receive from redis... ' | ||
| 'retrying in {} secs'.format(retry_sleep)) | ||
| f'retrying in {retry_sleep} secs', | ||
| extra={"redis_exception": str(exc)}) | ||
| connect = True | ||
@@ -148,0 +187,0 @@ time.sleep(retry_sleep) |
@@ -106,3 +106,3 @@ from threading import Event | ||
| """ | ||
| return self.client.transport if self.client else '' | ||
| return self.client.transport() if self.client else '' | ||
@@ -159,2 +159,4 @@ def emit(self, event, data=None): | ||
| timeout=timeout) | ||
| except TimeoutError: | ||
| raise | ||
| except SocketIOError: | ||
@@ -161,0 +163,0 @@ pass |
@@ -1,4 +0,4 @@ | ||
| import pickle | ||
| import re | ||
| from engineio import json | ||
| from .pubsub_manager import PubSubManager | ||
@@ -60,2 +60,3 @@ | ||
| super().__init__(channel=channel, write_only=write_only, logger=logger) | ||
| url = url.replace('zmq+', '') | ||
@@ -76,6 +77,5 @@ (sink_url, sub_port) = url.split('+') | ||
| self.channel = channel | ||
| super().__init__(channel=channel, write_only=write_only, logger=logger) | ||
| def _publish(self, data): | ||
| pickled_data = pickle.dumps( | ||
| packed_data = json.dumps( | ||
| { | ||
@@ -86,4 +86,4 @@ 'type': 'message', | ||
| } | ||
| ) | ||
| return self.sink.send(pickled_data) | ||
| ).encode() | ||
| return self.sink.send(packed_data) | ||
@@ -100,3 +100,3 @@ def zmq_listen(self): | ||
| try: | ||
| message = pickle.loads(message) | ||
| message = json.loads(message) | ||
| except Exception: | ||
@@ -103,0 +103,0 @@ pass |
@@ -110,5 +110,5 @@ from functools import wraps | ||
| def test_admin_connect_with_no_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin') | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
@@ -119,6 +119,6 @@ auth={'foo': 'bar'}) | ||
| def test_admin_connect_with_dict_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'foo': 'bar'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -128,3 +128,3 @@ admin_client.connect( | ||
| auth={'foo': 'baz'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -137,13 +137,13 @@ admin_client.connect( | ||
| def test_admin_connect_with_list_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'foo': 'bar'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'u': 'admin', 'p': 'secret'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
| admin_client.connect('http://localhost:8900', | ||
| namespace='/admin', auth={'foo': 'baz'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -155,10 +155,10 @@ admin_client.connect('http://localhost:8900', | ||
| def test_admin_connect_with_function_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'foo': 'bar'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
| admin_client.connect('http://localhost:8900', | ||
| namespace='/admin', auth={'foo': 'baz'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -170,10 +170,10 @@ admin_client.connect('http://localhost:8900', | ||
| def test_admin_connect_with_async_function_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'foo': 'bar'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
| admin_client.connect('http://localhost:8900', | ||
| namespace='/admin', auth={'foo': 'baz'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -185,3 +185,3 @@ admin_client.connect('http://localhost:8900', | ||
| def test_admin_connect_only_admin(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin') | ||
@@ -211,6 +211,6 @@ sid = admin_client.sid | ||
| def test_admin_connect_with_others(self): | ||
| with socketio.SimpleClient() as client1, \ | ||
| socketio.SimpleClient() as client2, \ | ||
| socketio.SimpleClient() as client3, \ | ||
| socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as client1, \ | ||
| socketio.SimpleClient(reconnection=False) as client2, \ | ||
| socketio.SimpleClient(reconnection=False) as client3, \ | ||
| socketio.SimpleClient(reconnection=False) as admin_client: | ||
| client1.connect('http://localhost:8900') | ||
@@ -262,3 +262,3 @@ client1.emit('enter_room', 'room') | ||
| def test_admin_connect_production(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin') | ||
@@ -284,5 +284,5 @@ events = self._expect({'config': 1, 'server_stats': 2}, | ||
| def test_admin_features(self): | ||
| with socketio.SimpleClient() as client1, \ | ||
| socketio.SimpleClient() as client2, \ | ||
| socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as client1, \ | ||
| socketio.SimpleClient(reconnection=False) as client2, \ | ||
| socketio.SimpleClient(reconnection=False) as admin_client: | ||
| client1.connect('http://localhost:8900') | ||
@@ -289,0 +289,0 @@ client2.connect('http://localhost:8900') |
| import asyncio | ||
| import functools | ||
| import json | ||
| from unittest import mock | ||
@@ -485,4 +486,2 @@ | ||
| async def messages(): | ||
| import pickle | ||
| yield {'method': 'emit', 'value': 'foo', 'host_id': 'x'} | ||
@@ -494,4 +493,4 @@ yield {'missing': 'method', 'host_id': 'x'} | ||
| yield {'method': 'bogus', 'host_id': 'x'} | ||
| yield pickle.dumps({'method': 'close_room', 'value': 'baz', | ||
| 'host_id': 'x'}) | ||
| yield json.dumps({'method': 'close_room', 'value': 'baz', | ||
| 'host_id': 'x'}) | ||
| yield {'method': 'enter_room', 'sid': '123', 'namespace': '/foo', | ||
@@ -502,3 +501,3 @@ 'room': 'room', 'host_id': 'x'} | ||
| yield 'bad json' | ||
| yield b'bad pickled' | ||
| yield b'bad data' | ||
@@ -511,4 +510,4 @@ # these should not publish anything on the queue, as they come from | ||
| 'host_id': host_id} | ||
| yield pickle.dumps({'method': 'close_room', 'value': 'baz', | ||
| 'host_id': host_id}) | ||
| yield json.dumps({'method': 'close_room', 'value': 'baz', | ||
| 'host_id': host_id}) | ||
@@ -515,0 +514,0 @@ self.pm._listen = messages |
@@ -75,3 +75,3 @@ import asyncio | ||
| client = AsyncSimpleClient() | ||
| client.client = mock.MagicMock(transport='websocket') | ||
| client.client = mock.MagicMock(transport=lambda: 'websocket') | ||
| client.client.get_sid.return_value = 'sid' | ||
@@ -146,2 +146,13 @@ client.connected_event.set() | ||
| async def test_call_timeout(self): | ||
| client = AsyncSimpleClient() | ||
| client.connected_event.set() | ||
| client.connected = True | ||
| client.client = mock.MagicMock() | ||
| client.client.call = mock.AsyncMock() | ||
| client.client.call.side_effect = TimeoutError() | ||
| with pytest.raises(TimeoutError): | ||
| await client.call('foo', 'bar') | ||
| async def test_receive_with_input_buffer(self): | ||
@@ -148,0 +159,0 @@ client = AsyncSimpleClient() |
@@ -100,5 +100,5 @@ from functools import wraps | ||
| def test_admin_connect_with_no_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin') | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
@@ -109,6 +109,6 @@ auth={'foo': 'bar'}) | ||
| def test_admin_connect_with_dict_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'foo': 'bar'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -118,3 +118,3 @@ admin_client.connect( | ||
| auth={'foo': 'baz'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -127,13 +127,13 @@ admin_client.connect( | ||
| def test_admin_connect_with_list_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'foo': 'bar'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'u': 'admin', 'p': 'secret'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
| admin_client.connect('http://localhost:8900', | ||
| namespace='/admin', auth={'foo': 'baz'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -145,10 +145,10 @@ admin_client.connect('http://localhost:8900', | ||
| def test_admin_connect_with_function_auth(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin', | ||
| auth={'foo': 'bar'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
| admin_client.connect('http://localhost:8900', | ||
| namespace='/admin', auth={'foo': 'baz'}) | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| with pytest.raises(ConnectionError): | ||
@@ -160,3 +160,3 @@ admin_client.connect('http://localhost:8900', | ||
| def test_admin_connect_only_admin(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin') | ||
@@ -186,6 +186,6 @@ sid = admin_client.sid | ||
| def test_admin_connect_with_others(self): | ||
| with socketio.SimpleClient() as client1, \ | ||
| socketio.SimpleClient() as client2, \ | ||
| socketio.SimpleClient() as client3, \ | ||
| socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as client1, \ | ||
| socketio.SimpleClient(reconnection=False) as client2, \ | ||
| socketio.SimpleClient(reconnection=False) as client3, \ | ||
| socketio.SimpleClient(reconnection=False) as admin_client: | ||
| client1.connect('http://localhost:8900') | ||
@@ -237,3 +237,3 @@ client1.emit('enter_room', 'room') | ||
| def test_admin_connect_production(self): | ||
| with socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as admin_client: | ||
| admin_client.connect('http://localhost:8900', namespace='/admin') | ||
@@ -259,5 +259,5 @@ events = self._expect({'config': 1, 'server_stats': 2}, | ||
| def test_admin_features(self): | ||
| with socketio.SimpleClient() as client1, \ | ||
| socketio.SimpleClient() as client2, \ | ||
| socketio.SimpleClient() as admin_client: | ||
| with socketio.SimpleClient(reconnection=False) as client1, \ | ||
| socketio.SimpleClient(reconnection=False) as client2, \ | ||
| socketio.SimpleClient(reconnection=False) as admin_client: | ||
| client1.connect('http://localhost:8900') | ||
@@ -264,0 +264,0 @@ client2.connect('http://localhost:8900') |
| import functools | ||
| import json | ||
| import logging | ||
@@ -468,4 +469,2 @@ from unittest import mock | ||
| def messages(): | ||
| import pickle | ||
| yield {'method': 'emit', 'value': 'foo', 'host_id': 'x'} | ||
@@ -477,4 +476,4 @@ yield {'missing': 'method', 'host_id': 'x'} | ||
| yield {'method': 'bogus', 'host_id': 'x'} | ||
| yield pickle.dumps({'method': 'close_room', 'value': 'baz', | ||
| 'host_id': 'x'}) | ||
| yield json.dumps({'method': 'close_room', 'value': 'baz', | ||
| 'host_id': 'x'}) | ||
| yield {'method': 'enter_room', 'sid': '123', 'namespace': '/foo', | ||
@@ -485,3 +484,3 @@ 'room': 'room', 'host_id': 'x'} | ||
| yield 'bad json' | ||
| yield b'bad pickled' | ||
| yield b'bad data' | ||
@@ -494,4 +493,4 @@ # these should not publish anything on the queue, as they come from | ||
| 'host_id': host_id} | ||
| yield pickle.dumps({'method': 'close_room', 'value': 'baz', | ||
| 'host_id': host_id}) | ||
| yield json.dumps({'method': 'close_room', 'value': 'baz', | ||
| 'host_id': host_id}) | ||
@@ -498,0 +497,0 @@ self.pm._listen = mock.MagicMock(side_effect=messages) |
@@ -7,8 +7,9 @@ import pytest | ||
| class TestPubSubManager: | ||
| def test_sentinel_url_parser(self): | ||
| @pytest.mark.parametrize('rtype', ['redis', 'valkey']) | ||
| def test_sentinel_url_parser(self, rtype): | ||
| with pytest.raises(ValueError): | ||
| parse_redis_sentinel_url('redis://localhost:6379/0') | ||
| parse_redis_sentinel_url(f'{rtype}://localhost:6379/0') | ||
| assert parse_redis_sentinel_url( | ||
| 'redis+sentinel://localhost:6379' | ||
| f'{rtype}+sentinel://localhost:6379' | ||
| ) == ( | ||
@@ -20,3 +21,3 @@ [('localhost', 6379)], | ||
| assert parse_redis_sentinel_url( | ||
| 'redis+sentinel://192.168.0.1:6379,192.168.0.2:6379/' | ||
| f'{rtype}+sentinel://192.168.0.1:6379,192.168.0.2:6379/' | ||
| ) == ( | ||
@@ -28,3 +29,3 @@ [('192.168.0.1', 6379), ('192.168.0.2', 6379)], | ||
| assert parse_redis_sentinel_url( | ||
| 'redis+sentinel://h1:6379,h2:6379/0' | ||
| f'{rtype}+sentinel://h1:6379,h2:6379/0' | ||
| ) == ( | ||
@@ -36,3 +37,4 @@ [('h1', 6379), ('h2', 6379)], | ||
| assert parse_redis_sentinel_url( | ||
| 'redis+sentinel://user:password@h1:6379,h2:6379,h1:6380/0/myredis' | ||
| f'{rtype}+sentinel://' | ||
| 'user:password@h1:6379,h2:6379,h1:6380/0/myredis' | ||
| ) == ( | ||
@@ -39,0 +41,0 @@ [('h1', 6379), ('h2', 6379), ('h1', 6380)], |
@@ -67,3 +67,3 @@ from unittest import mock | ||
| client = SimpleClient() | ||
| client.client = mock.MagicMock(transport='websocket') | ||
| client.client = mock.MagicMock(transport=lambda: 'websocket') | ||
| client.client.get_sid.return_value = 'sid' | ||
@@ -134,2 +134,12 @@ client.connected_event.set() | ||
| def test_call_timeout(self): | ||
| client = SimpleClient() | ||
| client.connected_event.set() | ||
| client.connected = True | ||
| client.client = mock.MagicMock() | ||
| client.client.call.side_effect = TimeoutError() | ||
| with pytest.raises(TimeoutError): | ||
| client.call('foo', 'bar') | ||
| def test_receive_with_input_buffer(self): | ||
@@ -136,0 +146,0 @@ client = SimpleClient() |
@@ -50,3 +50,3 @@ import threading | ||
| self.httpd = make_server('', port, self._app_wrapper, | ||
| self.httpd = make_server('localhost', port, self._app_wrapper, | ||
| ThreadingWSGIServer, WebSocketRequestHandler) | ||
@@ -53,0 +53,0 @@ self.thread = threading.Thread(target=self.httpd.serve_forever) |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
730623
0.79%13892
0.64%