New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

python-socketio

Package Overview
Dependencies
Maintainers
1
Versions
107
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

python-socketio - pypi Package Compare versions

Comparing version
5.12.1
to
5.13.0
+38
tests/common/test_redis_manager.py
import pytest
from socketio.redis_manager import parse_redis_sentinel_url
class TestPubSubManager:
def test_sentinel_url_parser(self):
with pytest.raises(ValueError):
parse_redis_sentinel_url('redis://localhost:6379/0')
assert parse_redis_sentinel_url(
'redis+sentinel://localhost:6379'
) == (
[('localhost', 6379)],
None,
{}
)
assert parse_redis_sentinel_url(
'redis+sentinel://192.168.0.1:6379,192.168.0.2:6379/'
) == (
[('192.168.0.1', 6379), ('192.168.0.2', 6379)],
None,
{}
)
assert parse_redis_sentinel_url(
'redis+sentinel://h1:6379,h2:6379/0'
) == (
[('h1', 6379), ('h2', 6379)],
None,
{'db': 0}
)
assert parse_redis_sentinel_url(
'redis+sentinel://user:password@h1:6379,h2:6379,h1:6380/0/myredis'
) == (
[('h1', 6379), ('h2', 6379), ('h1', 6380)],
'myredis',
{'username': 'user', 'password': 'password', 'db': 0}
)
+0
-6

@@ -22,8 +22,2 @@ The Socket.IO Server

If you plan to build an asynchronous web server based on the ``asyncio``
package, then you can install this package and some additional dependencies
that are needed with::
pip install "python-socketio[asyncio]"
Creating a Server Instance

@@ -30,0 +24,0 @@ --------------------------

@@ -1,4 +0,4 @@

Metadata-Version: 2.1
Metadata-Version: 2.4
Name: python-socketio
Version: 5.12.1
Version: 5.13.0
Summary: Socket.IO server and client for Python

@@ -25,2 +25,3 @@ Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>

Requires-Dist: sphinx; extra == "docs"
Dynamic: license-file

@@ -27,0 +28,0 @@ python-socketio

+1
-1
[project]
name = "python-socketio"
version = "5.12.1"
version = "5.13.0"
authors = [

@@ -5,0 +5,0 @@ { name = "Miguel Grinberg", email = "miguel.grinberg@gmail.com" },

@@ -1,4 +0,4 @@

Metadata-Version: 2.1
Metadata-Version: 2.4
Name: python-socketio
Version: 5.12.1
Version: 5.13.0
Summary: Socket.IO server and client for Python

@@ -25,2 +25,3 @@ Author-email: Miguel Grinberg <miguel.grinberg@gmail.com>

Requires-Dist: sphinx; extra == "docs"
Dynamic: license-file

@@ -27,0 +28,0 @@ python-socketio

@@ -73,2 +73,3 @@ LICENSE

tests/common/test_pubsub_manager.py
tests/common/test_redis_manager.py
tests/common/test_server.py

@@ -75,0 +76,0 @@ tests/common/test_simple_client.py

@@ -161,3 +161,3 @@ import asyncio

return
raise exceptions.ConnectionError(exc.args[0]) from None
raise exceptions.ConnectionError(exc.args[0]) from exc

@@ -195,2 +195,3 @@ if wait:

# connected while sleeping above
print('oops')
continue

@@ -329,3 +330,3 @@ break

namespace=n))
await self.eio.disconnect(abort=True)
await self.eio.disconnect()

@@ -332,0 +333,0 @@ async def shutdown(self):

@@ -16,2 +16,3 @@ import asyncio

from .async_pubsub_manager import AsyncPubSubManager
from .redis_manager import parse_redis_sentinel_url

@@ -33,4 +34,7 @@

:param url: The connection URL for the Redis server. For a default Redis
store running on the same host, use ``redis://``. To use an
SSL connection, use ``rediss://``.
store running on the same host, use ``redis://``. To use a
TLS connection, use ``rediss://``. To use Redis Sentinel, use
``redis+sentinel://`` with a comma-separated list of hosts
and the service name after the db in the URL path. Example:
``redis+sentinel://user:pw@host1:1234,host2:2345/0/myredis``.
:param channel: The channel name on which the server sends and receives

@@ -42,3 +46,3 @@ notifications. Must be the same in all the servers.

:param redis_options: additional keyword arguments to be passed to
``aioredis.from_url()``.
``Redis.from_url()`` or ``Sentinel()``.
"""

@@ -60,4 +64,12 @@ name = 'aioredis'

def _redis_connect(self):
self.redis = aioredis.Redis.from_url(self.redis_url,
**self.redis_options)
if not self.redis_url.startswith('redis+sentinel://'):
self.redis = aioredis.Redis.from_url(self.redis_url,
**self.redis_options)
else:
sentinels, service_name, connection_kwargs = \
parse_redis_sentinel_url(self.redis_url)
kwargs = self.redis_options
kwargs.update(connection_kwargs)
sentinel = aioredis.sentinel.Sentinel(sentinels, **kwargs)
self.redis = sentinel.master_for(service_name or self.channel)
self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True)

@@ -64,0 +76,0 @@

@@ -15,2 +15,4 @@ import asyncio

"""
client_class = AsyncClient
def __init__(self, *args, **kwargs):

@@ -64,3 +66,4 @@ self.client_args = args

self.input_event.clear()
self.client = AsyncClient(*self.client_args, **self.client_kwargs)
self.client = self.client_class(
*self.client_args, **self.client_kwargs)

@@ -67,0 +70,0 @@ @self.client.event(namespace=self.namespace)

@@ -159,3 +159,3 @@ import random

return
raise exceptions.ConnectionError(exc.args[0]) from None
raise exceptions.ConnectionError(exc.args[0]) from exc

@@ -310,3 +310,3 @@ if wait:

packet.DISCONNECT, namespace=n))
self.eio.disconnect(abort=True)
self.eio.disconnect()

@@ -313,0 +313,0 @@ def shutdown(self):

import logging
import pickle
import time
from urllib.parse import urlparse

@@ -15,2 +16,28 @@ try:

def parse_redis_sentinel_url(url):
"""Parse a Redis Sentinel URL with the format:
redis+sentinel://[:password]@host1:port1,host2:port2,.../db/service_name
"""
parsed_url = urlparse(url)
if parsed_url.scheme != 'redis+sentinel':
raise ValueError('Invalid Redis Sentinel URL')
sentinels = []
for host_port in parsed_url.netloc.split('@')[-1].split(','):
host, port = host_port.rsplit(':', 1)
sentinels.append((host, int(port)))
kwargs = {}
if parsed_url.username:
kwargs['username'] = parsed_url.username
if parsed_url.password:
kwargs['password'] = parsed_url.password
service_name = None
if parsed_url.path:
parts = parsed_url.path.split('/')
if len(parts) >= 2 and parts[1] != '':
kwargs['db'] = int(parts[1])
if len(parts) >= 3 and parts[2] != '':
service_name = parts[2]
return sentinels, service_name, kwargs
class RedisManager(PubSubManager): # pragma: no cover

@@ -31,4 +58,7 @@ """Redis based client manager.

:param url: The connection URL for the Redis server. For a default Redis
store running on the same host, use ``redis://``. To use an
SSL connection, use ``rediss://``.
store running on the same host, use ``redis://``. To use a
TLS connection, use ``rediss://``. To use Redis Sentinel, use
``redis+sentinel://`` with a comma-separated list of hosts
and the service name after the db in the URL path. Example:
``redis+sentinel://user:pw@host1:1234,host2:2345/0/myredis``.
:param channel: The channel name on which the server sends and receives

@@ -40,3 +70,3 @@ notifications. Must be the same in all the servers.

:param redis_options: additional keyword arguments to be passed to
``Redis.from_url()``.
``Redis.from_url()`` or ``Sentinel()``.
"""

@@ -72,4 +102,12 @@ name = 'redis'

def _redis_connect(self):
self.redis = redis.Redis.from_url(self.redis_url,
**self.redis_options)
if not self.redis_url.startswith('redis+sentinel://'):
self.redis = redis.Redis.from_url(self.redis_url,
**self.redis_options)
else:
sentinels, service_name, connection_kwargs = \
parse_redis_sentinel_url(self.redis_url)
kwargs = self.redis_options
kwargs.update(connection_kwargs)
sentinel = redis.sentinel.Sentinel(sentinels, **kwargs)
self.redis = sentinel.master_for(service_name or self.channel)
self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True)

@@ -76,0 +114,0 @@

@@ -15,2 +15,4 @@ from threading import Event

"""
client_class = Client
def __init__(self, *args, **kwargs):

@@ -62,3 +64,4 @@ self.client_args = args

self.input_event.clear()
self.client = Client(*self.client_args, **self.client_kwargs)
self.client = self.client_class(
*self.client_args, **self.client_kwargs)

@@ -65,0 +68,0 @@ @self.client.event(namespace=self.namespace)

@@ -478,3 +478,3 @@ import asyncio

)
c.eio.disconnect.assert_awaited_once_with(abort=True)
c.eio.disconnect.assert_awaited_once_with()

@@ -997,3 +997,3 @@ async def test_disconnect_namespaces(self):

)
c.eio.disconnect.assert_awaited_once_with(abort=True)
c.eio.disconnect.assert_awaited_once_with()

@@ -1000,0 +1000,0 @@ async def test_shutdown_disconnect_namespaces(self):

@@ -19,10 +19,35 @@ import asyncio

async def test_connect(self):
mock_client = mock.MagicMock()
original_client_class = AsyncSimpleClient.client_class
AsyncSimpleClient.client_class = mock_client
client = AsyncSimpleClient(123, a='b')
with mock.patch('socketio.async_simple_client.AsyncClient') \
as mock_client:
mock_client.return_value.connect = mock.AsyncMock()
await client.connect('url', headers='h', auth='a', transports='t',
namespace='n', socketio_path='s',
wait_timeout='w')
mock_client.assert_called_once_with(123, a='b')
assert client.client == mock_client()
mock_client().connect.assert_awaited_once_with(
'url', headers='h', auth='a', transports='t',
namespaces=['n'], socketio_path='s', wait_timeout='w')
mock_client().event.call_count == 3
mock_client().on.assert_called_once_with('*', namespace='n')
assert client.namespace == 'n'
assert not client.input_event.is_set()
AsyncSimpleClient.client_class = original_client_class
async def test_connect_context_manager(self):
mock_client = mock.MagicMock()
original_client_class = AsyncSimpleClient.client_class
AsyncSimpleClient.client_class = mock_client
async with AsyncSimpleClient(123, a='b') as client:
mock_client.return_value.connect = mock.AsyncMock()
await client.connect('url', headers='h', auth='a', transports='t',
namespace='n', socketio_path='s',
wait_timeout='w')
await client.connect('url', headers='h', auth='a',
transports='t', namespace='n',
socketio_path='s', wait_timeout='w')
mock_client.assert_called_once_with(123, a='b')

@@ -34,29 +59,9 @@ assert client.client == mock_client()

mock_client().event.call_count == 3
mock_client().on.assert_called_once_with('*', namespace='n')
mock_client().on.assert_called_once_with(
'*', namespace='n')
assert client.namespace == 'n'
assert not client.input_event.is_set()
async def test_connect_context_manager(self):
async def _t():
async with AsyncSimpleClient(123, a='b') as client:
with mock.patch('socketio.async_simple_client.AsyncClient') \
as mock_client:
mock_client.return_value.connect = mock.AsyncMock()
AsyncSimpleClient.client_class = original_client_class
await client.connect('url', headers='h', auth='a',
transports='t', namespace='n',
socketio_path='s', wait_timeout='w')
mock_client.assert_called_once_with(123, a='b')
assert client.client == mock_client()
mock_client().connect.assert_awaited_once_with(
'url', headers='h', auth='a', transports='t',
namespaces=['n'], socketio_path='s', wait_timeout='w')
mock_client().event.call_count == 3
mock_client().on.assert_called_once_with(
'*', namespace='n')
assert client.namespace == 'n'
assert not client.input_event.is_set()
await _t()
async def test_connect_twice(self):

@@ -63,0 +68,0 @@ client = AsyncSimpleClient(123, a='b')

@@ -636,3 +636,3 @@ import logging

)
c.eio.disconnect.assert_called_once_with(abort=True)
c.eio.disconnect.assert_called_once_with()

@@ -1142,3 +1142,3 @@ def test_disconnect_namespaces(self):

)
c.eio.disconnect.assert_called_once_with(abort=True)
c.eio.disconnect.assert_called_once_with()

@@ -1145,0 +1145,0 @@ def test_shutdown_disconnect_namespaces(self):

@@ -17,6 +17,30 @@ from unittest import mock

def test_connect(self):
mock_client = mock.MagicMock()
original_client_class = SimpleClient.client_class
SimpleClient.client_class = mock_client
client = SimpleClient(123, a='b')
with mock.patch('socketio.simple_client.Client') as mock_client:
client.connect('url', headers='h', auth='a', transports='t',
namespace='n', socketio_path='s', wait_timeout='w')
mock_client.assert_called_once_with(123, a='b')
assert client.client == mock_client()
mock_client().connect.assert_called_once_with(
'url', headers='h', auth='a', transports='t',
namespaces=['n'], socketio_path='s', wait_timeout='w')
mock_client().event.call_count == 3
mock_client().on.assert_called_once_with('*', namespace='n')
assert client.namespace == 'n'
assert not client.input_event.is_set()
SimpleClient.client_class = original_client_class
def test_connect_context_manager(self):
mock_client = mock.MagicMock()
original_client_class = SimpleClient.client_class
SimpleClient.client_class = mock_client
with SimpleClient(123, a='b') as client:
client.connect('url', headers='h', auth='a', transports='t',
namespace='n', socketio_path='s', wait_timeout='w')
namespace='n', socketio_path='s',
wait_timeout='w')
mock_client.assert_called_once_with(123, a='b')

@@ -32,17 +56,3 @@ assert client.client == mock_client()

def test_connect_context_manager(self):
with SimpleClient(123, a='b') as client:
with mock.patch('socketio.simple_client.Client') as mock_client:
client.connect('url', headers='h', auth='a', transports='t',
namespace='n', socketio_path='s',
wait_timeout='w')
mock_client.assert_called_once_with(123, a='b')
assert client.client == mock_client()
mock_client().connect.assert_called_once_with(
'url', headers='h', auth='a', transports='t',
namespaces=['n'], socketio_path='s', wait_timeout='w')
mock_client().event.call_count == 3
mock_client().on.assert_called_once_with('*', namespace='n')
assert client.namespace == 'n'
assert not client.input_event.is_set()
SimpleClient.client_class = original_client_class

@@ -49,0 +59,0 @@ def test_connect_twice(self):