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.14.1
to
5.14.2
+3
-1
PKG-INFO
Metadata-Version: 2.4
Name: python-socketio
Version: 5.14.1
Version: 5.14.2
Summary: Socket.IO server and client for Python

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

Requires-Dist: aiohttp>=3.4; extra == "asyncio-client"
Provides-Extra: dev
Requires-Dist: tox; extra == "dev"
Provides-Extra: docs

@@ -25,0 +27,0 @@ Requires-Dist: sphinx; extra == "docs"

[project]
name = "python-socketio"
version = "5.14.1"
version = "5.14.2"
license = {text = "MIT"}

@@ -37,2 +37,5 @@ authors = [

]
dev = [
"tox",
]
docs = [

@@ -39,0 +42,0 @@ "sphinx",

Metadata-Version: 2.4
Name: python-socketio
Version: 5.14.1
Version: 5.14.2
Summary: Socket.IO server and client for Python

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

Requires-Dist: aiohttp>=3.4; extra == "asyncio-client"
Provides-Extra: dev
Requires-Dist: tox; extra == "dev"
Provides-Extra: docs

@@ -25,0 +27,0 @@ Requires-Dist: sphinx; extra == "docs"

@@ -11,3 +11,6 @@ bidict>=0.21.0

[dev]
tox
[docs]
sphinx

@@ -178,4 +178,4 @@ import asyncio

raise exceptions.ConnectionError(
'One or more namespaces failed to connect'
', '.join(self.failed_namespaces))
'One or more namespaces failed to connect: '
+ ', '.join(self.failed_namespaces))

@@ -182,0 +182,0 @@ self.connected = True

import asyncio
import base64
from functools import partial

@@ -8,2 +9,3 @@ import uuid

from .async_manager import AsyncManager
from .packet import Packet

@@ -68,4 +70,8 @@

callback = None
binary = Packet.data_is_binary(data)
if binary:
data, attachments = Packet.deconstruct_binary(data)
data = [data, *[base64.b64encode(a).decode() for a in attachments]]
message = {'method': 'emit', 'event': event, 'data': data,
'namespace': namespace, 'room': room,
'binary': binary, 'namespace': namespace, 'room': room,
'skip_sid': skip_sid, 'callback': callback,

@@ -150,3 +156,7 @@ 'host_id': self.host_id}

callback = None
await super().emit(message['event'], message['data'],
data = message['data']
if message.get('binary'):
attachments = [base64.b64decode(a) for a in data[1:]]
data = Packet.reconstruct_binary(data[0], attachments)
await super().emit(message['event'], data,
namespace=message.get('namespace'),

@@ -153,0 +163,0 @@ room=message.get('room'),

@@ -32,3 +32,9 @@ import itertools

def get_participants(self, namespace, room):
"""Return an iterable with the active participants in a room."""
"""Return an iterable with the active participants in a room.
Note that in a multi-server scenario this method only returns the
participants connect to the server in which the method is called. There
is currently no functionality to assemble a complete list of users
across multiple servers.
"""
ns = self.rooms.get(namespace, {})

@@ -35,0 +41,0 @@ if hasattr(room, '__len__') and not isinstance(room, str):

@@ -172,3 +172,3 @@ import random

'One or more namespaces failed to connect: '
', '.join(self.failed_namespaces))
+ ', '.join(self.failed_namespaces))

@@ -175,0 +175,0 @@ self.connected = True

@@ -32,3 +32,3 @@ import functools

if self.uses_binary_events and \
(binary or (binary is None and self._data_is_binary(
(binary or (binary is None and self.data_is_binary(
self.data))):

@@ -55,3 +55,3 @@ if self.packet_type == EVENT:

if self.packet_type == BINARY_EVENT or self.packet_type == BINARY_ACK:
data, attachments = self._deconstruct_binary(self.data)
data, attachments = self.deconstruct_binary(self.data)
encoded_packet += str(len(attachments)) + '-'

@@ -124,16 +124,17 @@ else:

if self.attachment_count == len(self.attachments):
self.reconstruct_binary(self.attachments)
self.data = self.reconstruct_binary(self.data, self.attachments)
return True
return False
def reconstruct_binary(self, attachments):
@classmethod
def reconstruct_binary(cls, data, attachments):
"""Reconstruct a decoded packet using the given list of binary
attachments.
"""
self.data = self._reconstruct_binary_internal(self.data,
self.attachments)
return cls._reconstruct_binary_internal(data, attachments)
def _reconstruct_binary_internal(self, data, attachments):
@classmethod
def _reconstruct_binary_internal(cls, data, attachments):
if isinstance(data, list):
return [self._reconstruct_binary_internal(item, attachments)
return [cls._reconstruct_binary_internal(item, attachments)
for item in data]

@@ -144,4 +145,4 @@ elif isinstance(data, dict):

else:
return {key: self._reconstruct_binary_internal(value,
attachments)
return {key: cls._reconstruct_binary_internal(value,
attachments)
for key, value in data.items()}

@@ -151,9 +152,11 @@ else:

def _deconstruct_binary(self, data):
@classmethod
def deconstruct_binary(cls, data):
"""Extract binary components in the packet."""
attachments = []
data = self._deconstruct_binary_internal(data, attachments)
data = cls._deconstruct_binary_internal(data, attachments)
return data, attachments
def _deconstruct_binary_internal(self, data, attachments):
@classmethod
def _deconstruct_binary_internal(cls, data, attachments):
if isinstance(data, bytes):

@@ -163,6 +166,6 @@ attachments.append(data)

elif isinstance(data, list):
return [self._deconstruct_binary_internal(item, attachments)
return [cls._deconstruct_binary_internal(item, attachments)
for item in data]
elif isinstance(data, dict):
return {key: self._deconstruct_binary_internal(value, attachments)
return {key: cls._deconstruct_binary_internal(value, attachments)
for key, value in data.items()}

@@ -172,3 +175,4 @@ else:

def _data_is_binary(self, data):
@classmethod
def data_is_binary(cls, data):
"""Check if the data contains binary components."""

@@ -179,7 +183,7 @@ if isinstance(data, bytes):

return functools.reduce(
lambda a, b: a or b, [self._data_is_binary(item)
lambda a, b: a or b, [cls.data_is_binary(item)
for item in data], False)
elif isinstance(data, dict):
return functools.reduce(
lambda a, b: a or b, [self._data_is_binary(item)
lambda a, b: a or b, [cls.data_is_binary(item)
for item in data.values()],

@@ -186,0 +190,0 @@ False)

@@ -0,1 +1,2 @@

import base64
from functools import partial

@@ -7,2 +8,3 @@ import uuid

from .manager import Manager
from .packet import Packet

@@ -65,4 +67,8 @@

callback = None
binary = Packet.data_is_binary(data)
if binary:
data, attachments = Packet.deconstruct_binary(data)
data = [data, *[base64.b64encode(a).decode() for a in attachments]]
message = {'method': 'emit', 'event': event, 'data': data,
'namespace': namespace, 'room': room,
'binary': binary, 'namespace': namespace, 'room': room,
'skip_sid': skip_sid, 'callback': callback,

@@ -146,3 +152,7 @@ 'host_id': self.host_id}

callback = None
super().emit(message['event'], message['data'],
data = message['data']
if message.get('binary'):
attachments = [base64.b64decode(a) for a in data[1:]]
data = Packet.reconstruct_binary(data[0], attachments)
super().emit(message['event'], data,
namespace=message.get('namespace'),

@@ -149,0 +159,0 @@ room=message.get('room'),

@@ -206,2 +206,56 @@ import asyncio

async def test_connect_wait_one_namespaces_error(self):
c = async_client.AsyncClient()
c.eio.connect = mock.AsyncMock()
c._connect_event = mock.MagicMock()
async def mock_connect():
if c.failed_namespaces == []:
c.failed_namespaces = ['/foo']
return True
return False
c._connect_event.wait = mock_connect
with pytest.raises(exceptions.ConnectionError,
match='failed to connect: /foo'):
await c.connect(
'url',
namespaces=['/foo'],
wait=True,
wait_timeout=0.01,
)
assert c.connected is False
assert c.namespaces == {}
assert c.failed_namespaces == ['/foo']
async def test_connect_wait_three_namespaces_error(self):
c = async_client.AsyncClient()
c.eio.connect = mock.AsyncMock()
c._connect_event = mock.MagicMock()
async def mock_connect():
if c.namespaces == {}:
c.namespaces = {'/bar': '123'}
return True
elif c.namespaces == {'/bar': '123'} and c.failed_namespaces == []:
c.failed_namespaces = ['/baz']
return True
elif c.failed_namespaces == ['/baz']:
c.failed_namespaces = ['/baz', '/foo']
return True
return False
c._connect_event.wait = mock_connect
with pytest.raises(exceptions.ConnectionError,
match='failed to connect: /baz, /foo'):
await c.connect(
'url',
namespaces=['/foo', '/bar', '/baz'],
wait=True,
wait_timeout=0.01,
)
assert c.connected is False
assert c.namespaces == {'/bar': '123'}
assert c.failed_namespaces == ['/baz', '/foo']
async def test_connect_timeout(self):

@@ -208,0 +262,0 @@ c = async_client.AsyncClient()

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

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -70,2 +71,32 @@ 'namespace': '/',

async def test_emit_binary(self):
await self.pm.emit('foo', b'bar')
self.pm._publish.assert_awaited_once_with(
{
'method': 'emit',
'event': 'foo',
'binary': True,
'data': [{'_placeholder': True, 'num': 0}, 'YmFy'],
'namespace': '/',
'room': None,
'skip_sid': None,
'callback': None,
'host_id': '123456',
}
)
await self.pm.emit('foo', {'foo': b'bar'})
self.pm._publish.assert_awaited_with(
{
'method': 'emit',
'event': 'foo',
'binary': True,
'data': [{'foo': {'_placeholder': True, 'num': 0}}, 'YmFy'],
'namespace': '/',
'room': None,
'skip_sid': None,
'callback': None,
'host_id': '123456',
}
)
async def test_emit_with_to(self):

@@ -78,2 +109,3 @@ sid = 'room-mate'

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -94,2 +126,3 @@ 'namespace': '/',

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -110,2 +143,3 @@ 'namespace': '/baz',

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -126,2 +160,3 @@ 'namespace': '/',

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -145,2 +180,3 @@ 'namespace': '/',

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -251,2 +287,33 @@ 'namespace': '/',

async def test_handle_emit_binary(self):
with mock.patch.object(
async_manager.AsyncManager, 'emit'
) as super_emit:
await self.pm._handle_emit({
'event': 'foo',
'binary': True,
'data': [{'_placeholder': True, 'num': 0}, 'YmFy'],
})
super_emit.assert_awaited_once_with(
'foo',
b'bar',
namespace=None,
room=None,
skip_sid=None,
callback=None,
)
await self.pm._handle_emit({
'event': 'foo',
'binary': True,
'data': [{'foo': {'_placeholder': True, 'num': 0}}, 'YmFy'],
})
super_emit.assert_awaited_with(
'foo',
{'foo': b'bar'},
namespace=None,
room=None,
skip_sid=None,
callback=None,
)
async def test_handle_emit_with_namespace(self):

@@ -253,0 +320,0 @@ with mock.patch.object(

@@ -353,2 +353,58 @@ import logging

def test_connect_wait_one_namespaces_error(self):
c = client.Client()
c.eio.connect = mock.MagicMock()
c._connect_event = mock.MagicMock()
def mock_connect(timeout):
assert timeout == 0.01
if c.failed_namespaces == []:
c.failed_namespaces = ['/foo']
return True
return False
c._connect_event.wait = mock_connect
with pytest.raises(exceptions.ConnectionError,
match='failed to connect: /foo'):
c.connect(
'url',
namespaces=['/foo'],
wait=True,
wait_timeout=0.01,
)
assert c.connected is False
assert c.namespaces == {}
assert c.failed_namespaces == ['/foo']
def test_connect_wait_three_namespaces_error(self):
c = client.Client()
c.eio.connect = mock.MagicMock()
c._connect_event = mock.MagicMock()
def mock_connect(timeout):
assert timeout == 0.01
if c.namespaces == {}:
c.namespaces = {'/bar': '123'}
return True
elif c.namespaces == {'/bar': '123'} and c.failed_namespaces == []:
c.failed_namespaces = ['/baz']
return True
elif c.failed_namespaces == ['/baz']:
c.failed_namespaces = ['/baz', '/foo']
return True
return False
c._connect_event.wait = mock_connect
with pytest.raises(exceptions.ConnectionError,
match='failed to connect: /baz, /foo'):
c.connect(
'url',
namespaces=['/foo', '/bar', '/baz'],
wait=True,
wait_timeout=0.01,
)
assert c.connected is False
assert c.namespaces == {'/bar': '123'}
assert c.failed_namespaces == ['/baz', '/foo']
def test_connect_timeout(self):

@@ -355,0 +411,0 @@ c = client.Client()

@@ -269,14 +269,22 @@ import pytest

def test_deconstruct_binary(self):
datas = [b'foo', [b'foo', b'bar'], ['foo', b'bar'], {'foo': b'bar'},
{'foo': 'bar', 'baz': b'qux'}, {'foo': [b'bar']}]
for data in datas:
bdata, attachments = packet.Packet.deconstruct_binary(data)
rdata = packet.Packet.reconstruct_binary(bdata, attachments)
assert data == rdata
def test_data_is_binary_list(self):
pkt = packet.Packet()
assert not pkt._data_is_binary(['foo'])
assert not pkt._data_is_binary([])
assert pkt._data_is_binary([b'foo'])
assert pkt._data_is_binary(['foo', b'bar'])
assert not pkt.data_is_binary(['foo'])
assert not pkt.data_is_binary([])
assert pkt.data_is_binary([b'foo'])
assert pkt.data_is_binary(['foo', b'bar'])
def test_data_is_binary_dict(self):
pkt = packet.Packet()
assert not pkt._data_is_binary({'a': 'foo'})
assert not pkt._data_is_binary({})
assert pkt._data_is_binary({'a': b'foo'})
assert pkt._data_is_binary({'a': 'foo', 'b': b'bar'})
assert not pkt.data_is_binary({'a': 'foo'})
assert not pkt.data_is_binary({})
assert pkt.data_is_binary({'a': b'foo'})
assert pkt.data_is_binary({'a': 'foo', 'b': b'bar'})

@@ -72,2 +72,3 @@ import functools

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -82,2 +83,32 @@ 'namespace': '/',

def test_emit_binary(self):
self.pm.emit('foo', b'bar')
self.pm._publish.assert_called_once_with(
{
'method': 'emit',
'event': 'foo',
'binary': True,
'data': [{'_placeholder': True, 'num': 0}, 'YmFy'],
'namespace': '/',
'room': None,
'skip_sid': None,
'callback': None,
'host_id': '123456',
}
)
self.pm.emit('foo', {'foo': b'bar'})
self.pm._publish.assert_called_with(
{
'method': 'emit',
'event': 'foo',
'binary': True,
'data': [{'foo': {'_placeholder': True, 'num': 0}}, 'YmFy'],
'namespace': '/',
'room': None,
'skip_sid': None,
'callback': None,
'host_id': '123456',
}
)
def test_emit_with_to(self):

@@ -90,2 +121,3 @@ sid = "ferris"

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -106,2 +138,3 @@ 'namespace': '/',

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -122,2 +155,3 @@ 'namespace': '/baz',

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -138,2 +172,3 @@ 'namespace': '/',

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -157,2 +192,3 @@ 'namespace': '/',

'event': 'foo',
'binary': False,
'data': 'bar',

@@ -260,2 +296,31 @@ 'namespace': '/',

def test_handle_emit_binary(self):
with mock.patch.object(manager.Manager, 'emit') as super_emit:
self.pm._handle_emit({
'event': 'foo',
'binary': True,
'data': [{'_placeholder': True, 'num': 0}, 'YmFy'],
})
super_emit.assert_called_once_with(
'foo',
b'bar',
namespace=None,
room=None,
skip_sid=None,
callback=None,
)
self.pm._handle_emit({
'event': 'foo',
'binary': True,
'data': [{'foo': {'_placeholder': True, 'num': 0}}, 'YmFy'],
})
super_emit.assert_called_with(
'foo',
{'foo': b'bar'},
namespace=None,
room=None,
skip_sid=None,
callback=None,
)
def test_handle_emit_with_namespace(self):

@@ -262,0 +327,0 @@ with mock.patch.object(manager.Manager, 'emit') as super_emit:

[tox]
envlist=flake8,py{38,39,310,311,312,313},docs
envlist=flake8,py{38,39,310,311,312,313,314},docs
skip_missing_interpreters=True

@@ -13,2 +13,3 @@

3.13: py313
3.14: py314
pypy-3: pypy3

@@ -15,0 +16,0 @@