Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-python-socketio for openSUSE:Factory checked in at 2022-01-24 23:10:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-python-socketio (Old) and /work/SRC/openSUSE:Factory/.python-python-socketio.new.1938 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-python-socketio" Mon Jan 24 23:10:12 2022 rev:5 rq:948409 version:5.5.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-python-socketio/python-python-socketio.changes 2021-10-26 20:14:22.950031635 +0200 +++ /work/SRC/openSUSE:Factory/.python-python-socketio.new.1938/python-python-socketio.changes 2022-01-24 23:10:49.614416413 +0100 @@ -1,0 +2,19 @@ +Sun Jan 23 08:34:21 UTC 2022 - Axel Braun <axel.br...@gmx.de> + +- version 5.5.1 + * Support multiple Kafka servers (thanks sparkingdark!) + * Include example code in flake8 pass + * Option to disable the SIGINT handler in the client #792 + * Do not invoke reserved events on a catch-all handler #814 + * Use correct binary packet types in the msgpack packet encoder #811 + * Add missing call() method to namespace classes #800 + * Add missing to argument to namespace emit() and send() methods #810 + * Configure Redis pubsub to skip subscription messages + * Migrate async Redis client manager to aioredis 2 #771 (thanks Sam Mosleh!) + * Update Python supported versions in docs + * Document how to get the connection state in the client #799 + * Improved documentation of start_background_task() function + * Improved documentation of call() method #813 + * Fixed intermittent test failures #572 + +------------------------------------------------------------------- @@ -5,2 +24,2 @@ - * Catch-all event handlers (commit) - * Implement disconnect method for external processes #684 (commit) + * Catch-all event handlers + * Implement disconnect method for external processes #684 Old: ---- python-socketio-5.4.1.tar.gz New: ---- python-socketio-5.5.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-python-socketio.spec ++++++ --- /var/tmp/diff_new_pack.s3Snih/_old 2022-01-24 23:10:50.090413160 +0100 +++ /var/tmp/diff_new_pack.s3Snih/_new 2022-01-24 23:10:50.094413133 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-python-socketio # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python3-%{**}} %define skip_python2 1 Name: python-python-socketio -Version: 5.4.1 +Version: 5.5.1 Release: 0 Summary: SocketIO server License: MIT ++++++ python-socketio-5.4.1.tar.gz -> python-socketio-5.5.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/CHANGES.md new/python-socketio-5.5.1/CHANGES.md --- old/python-socketio-5.4.1/CHANGES.md 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/CHANGES.md 2022-01-11 13:17:25.000000000 +0100 @@ -1,5 +1,25 @@ # python-socketio change log +**Release 5.5.1** - 2022-01-11 + +- Support multiple Kafka servers ([commit](https://github.com/miguelgrinberg/python-socketio/commit/4ee3649514b98c50cc0bf70d3f269389da52772d)) (thanks **sparkingdark**!) +- Include example code in flake8 pass ([commit](https://github.com/miguelgrinberg/python-socketio/commit/273a4b0439c84560d403662d8eba4122c28ba0d8)) + +**Release 5.5.0** - 2021-11-14 + +- Option to disable the SIGINT handler in the client [#792](https://github.com/miguelgrinberg/python-socketio/issues/792) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/ea84b9b1c714b02eaf1081f4e37fd130a3159d8c)) +- Do not invoke reserved events on a catch-all handler [#814](https://github.com/miguelgrinberg/python-socketio/issues/814) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/34f34e53d650dde605f5f4a98d7a70936524a1b8)) +- Use correct binary packet types in the msgpack packet encoder [#811](https://github.com/miguelgrinberg/python-socketio/issues/811) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/60735dd4c2fc87ed863d7dbf7de361500d963dd3)) +- Add missing `call()` method to namespace classes [#800](https://github.com/miguelgrinberg/python-socketio/issues/800) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/32db48d12ceb44d7a02fd9f05047b47c7ed3f4a5)) +- Add missing `to` argument to namespace `emit()` and `send()` methods [#810](https://github.com/miguelgrinberg/python-socketio/issues/810) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/ed08a01e65635160923f3d6d5755df74d53274e1)) +- Configure Redis pubsub to skip subscription messages ([commit](https://github.com/miguelgrinberg/python-socketio/commit/e8fff07b367929794e5e30cecbf252b72d307c16)) +- Migrate async Redis client manager to aioredis 2 [#771](https://github.com/miguelgrinberg/python-socketio/issues/771) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/f245191d86722244a2d3d0529d9f5ff15dfd817a)) (thanks **Sam Mosleh**!) +- Update Python supported versions in docs ([commit](https://github.com/miguelgrinberg/python-socketio/commit/a54152f2466bad4869d9cfdad6be3a5547e0b6bc)) +- Document how to get the connection state in the client [#799](https://github.com/miguelgrinberg/python-socketio/issues/799) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/47c5f45c765ae207f58ba2675f91eaf8c79f8500)) +- Improved documentation of `start_background_task()` function ([commit](https://github.com/miguelgrinberg/python-socketio/commit/4f5bf1e9898154aa1a9896a7016ba22bfb73cdf2)) +- Improved documentation of `call()` method [#813](https://github.com/miguelgrinberg/python-socketio/issues/813) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/8c2a6ac86972bf94acafe687d2e86bdf65119960)) +- Fixed intermittent test failures [#572](https://github.com/miguelgrinberg/python-socketio/issues/572) ([commit](https://github.com/miguelgrinberg/python-socketio/commit/db0565ada6c8891be3230bcc415e5465bd409c09)) + **Release 5.4.1** - 2021-10-14 - Catch-all event handlers ([commit](https://github.com/miguelgrinberg/python-socketio/commit/28569d48ad74d5414a0d2a8f69d7540dbdddf066)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/docs/api.rst new/python-socketio-5.5.1/docs/api.rst --- old/python-socketio-5.4.1/docs/api.rst 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/docs/api.rst 2022-01-11 13:17:25.000000000 +0100 @@ -35,7 +35,7 @@ ``ConnectionRefusedError`` class -------------------------------- -.. autoclass:: ConnectionRefusedError +.. autoclass:: socketio.exceptions.ConnectionRefusedError :members: ``WSGIApp`` class @@ -128,7 +128,7 @@ :members: ``AsyncAioPikaManager`` class ---------------------------- +----------------------------- .. autoclass:: AsyncAioPikaManager :members: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/docs/client.rst new/python-socketio-5.5.1/docs/client.rst --- old/python-socketio-5.4.1/docs/client.rst 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/docs/client.rst 2022-01-11 13:17:25.000000000 +0100 @@ -65,6 +65,9 @@ async def message(data): print('I received a message!') +If the server includes arguments with an event, those are passed to the +handler function as arguments. + Catch-All Event Handlers ------------------------ @@ -72,13 +75,13 @@ event handler. You can define a catch-all handler using ``'*'`` as event name:: @sio.on('*') - def catch_all(event, sid, data): + def catch_all(event, data): pass Asyncio clients can also use a coroutine:: @sio.on('*') - async def catch_all(event, sid, data): + async def catch_all(event, data): pass A catch-all event handler receives the event name as a first argument. The @@ -115,8 +118,8 @@ handler. As soon as the connection is re-established the connect handler will be invoked once again. -If the server includes arguments with an event, those are passed to the -handler function as arguments. +The ``connect``, ``connect_error`` and ``disconnect`` events have to be +defined explicitly and are not invoked on a catch-all event handler. Connecting to a Server ---------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/docs/intro.rst new/python-socketio-5.5.1/docs/intro.rst --- old/python-socketio-5.4.1/docs/intro.rst 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/docs/intro.rst 2022-01-11 13:17:25.000000000 +0100 @@ -103,7 +103,7 @@ - Can connect to other Socket.IO servers that are compatible with the JavaScript Socket.IO 1.x and 2.x releases. Work to support release 3.x is in progress. -- Compatible with Python 3.5+. +- Compatible with Python 3.6+. - Two versions of the client, one for standard Python and another for asyncio. - Uses an event-based architecture implemented with decorators that @@ -183,7 +183,7 @@ - Can connect to servers running other Socket.IO clients that are compatible with the JavaScript client versions 1.x and 2.x. Work to support the 3.x release is in progress. -- Compatible with Python 3.5+. +- Compatible with Python 3.6+. - Two versions of the server, one for standard Python and another for asyncio. - Supports large number of clients even on modest hardware due to being diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/docs/server.rst new/python-socketio-5.5.1/docs/server.rst --- old/python-socketio-5.4.1/docs/server.rst 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/docs/server.rst 2022-01-11 13:17:25.000000000 +0100 @@ -197,6 +197,9 @@ A catch-all event handler receives the event name as a first argument. The remaining arguments are the same as for a regular event handler. +The ``connect`` and ``disconnect`` events have to be defined explicitly and are +not invoked on a catch-all event handler. + Connect and Disconnect Event Handlers ------------------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/aiohttp/app.py new/python-socketio-5.5.1/examples/server/aiohttp/app.py --- old/python-socketio-5.4.1/examples/server/aiohttp/app.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/aiohttp/app.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,5 +1,3 @@ -import asyncio - from aiohttp import web import socketio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/asgi/app.py new/python-socketio-5.5.1/examples/server/asgi/app.py --- old/python-socketio-5.4.1/examples/server/asgi/app.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/asgi/app.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,6 +1,4 @@ #!/usr/bin/env python -import asyncio - import uvicorn import socketio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/sanic/app.py new/python-socketio-5.5.1/examples/server/sanic/app.py --- old/python-socketio-5.4.1/examples/server/sanic/app.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/sanic/app.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,5 +1,3 @@ -import asyncio - from sanic import Sanic from sanic.response import html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/tornado/app.py new/python-socketio-5.5.1/examples/server/tornado/app.py --- old/python-socketio-5.4.1/examples/server/tornado/app.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/tornado/app.py 2022-01-11 13:17:25.000000000 +0100 @@ -42,6 +42,7 @@ await sio.emit('my_response', {'data': 'Entered room: ' + message['room']}, room=sid) + @sio.event async def leave(sid, message): sio.leave_room(sid, message['room']) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/wsgi/app.py new/python-socketio-5.5.1/examples/server/wsgi/app.py --- old/python-socketio-5.4.1/examples/server/wsgi/app.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/wsgi/app.py 2022-01-11 13:17:25.000000000 +0100 @@ -3,7 +3,6 @@ # installed async_mode = None -import time from flask import Flask, render_template import socketio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/wsgi/django_example/django_example/settings.py new/python-socketio-5.5.1/examples/server/wsgi/django_example/django_example/settings.py --- old/python-socketio-5.4.1/examples/server/wsgi/django_example/django_example/settings.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/wsgi/django_example/django_example/settings.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,3 +1,4 @@ +# flake8: noqa """ Django settings for django_example project. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/wsgi/django_example/manage.py new/python-socketio-5.5.1/examples/server/wsgi/django_example/manage.py --- old/python-socketio-5.4.1/examples/server/wsgi/django_example/manage.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/wsgi/django_example/manage.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,4 +1,5 @@ #!/usr/bin/env python +# flake8: noqa import os import sys @@ -11,7 +12,7 @@ # issue is really that Django is missing to avoid masking other # exceptions on Python 2. try: - import django + import django # pragma: F401 except ImportError: raise ImportError( "Couldn't import Django. Are you sure it's installed and " diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/wsgi/django_example/socketio_app/admin.py new/python-socketio-5.5.1/examples/server/wsgi/django_example/socketio_app/admin.py --- old/python-socketio-5.4.1/examples/server/wsgi/django_example/socketio_app/admin.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/wsgi/django_example/socketio_app/admin.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,3 +1,4 @@ +# flake8: noqa from django.contrib import admin # Register your models here. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/wsgi/django_example/socketio_app/models.py new/python-socketio-5.5.1/examples/server/wsgi/django_example/socketio_app/models.py --- old/python-socketio-5.4.1/examples/server/wsgi/django_example/socketio_app/models.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/wsgi/django_example/socketio_app/models.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,3 +1,4 @@ +# flake8: noqa from django.db import models # Create your models here. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/wsgi/django_example/socketio_app/tests.py new/python-socketio-5.5.1/examples/server/wsgi/django_example/socketio_app/tests.py --- old/python-socketio-5.4.1/examples/server/wsgi/django_example/socketio_app/tests.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/wsgi/django_example/socketio_app/tests.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,3 +1,4 @@ +# flake8: noqa from django.test import TestCase # Create your tests here. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/examples/server/wsgi/django_example/socketio_app/views.py new/python-socketio-5.5.1/examples/server/wsgi/django_example/socketio_app/views.py --- old/python-socketio-5.4.1/examples/server/wsgi/django_example/socketio_app/views.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/examples/server/wsgi/django_example/socketio_app/views.py 2022-01-11 13:17:25.000000000 +0100 @@ -80,4 +80,3 @@ @sio.event def disconnect(sid): print('Client disconnected') - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/setup.cfg new/python-socketio-5.5.1/setup.cfg --- old/python-socketio-5.4.1/setup.cfg 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/setup.cfg 2022-01-11 13:17:25.000000000 +0100 @@ -1,6 +1,6 @@ [metadata] name = python-socketio -version = 5.4.1 +version = 5.5.1 author = Miguel Grinberg author_email = miguel.grinb...@gmail.com description = Socket.IO server and client for Python @@ -25,7 +25,7 @@ python_requires = >=3.6 install_requires = bidict >= 0.21.0 - python-engineio >= 4.1.0 + python-engineio >= 4.3.0 [options.packages.find] where = src diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/asyncio_aiopika_manager.py new/python-socketio-5.5.1/src/socketio/asyncio_aiopika_manager.py --- old/python-socketio-5.4.1/src/socketio/asyncio_aiopika_manager.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/asyncio_aiopika_manager.py 2022-01-11 13:17:25.000000000 +0100 @@ -94,7 +94,7 @@ async with self.listener_queue.iterator() as queue_iter: async for message in queue_iter: with message.process(): - return pickle.loads(message.body) + yield pickle.loads(message.body) except Exception: self._get_logger().error('Cannot receive from rabbitmq... ' 'retrying in ' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/asyncio_client.py new/python-socketio-5.5.1/src/socketio/asyncio_client.py --- old/python-socketio-5.4.1/src/socketio/asyncio_client.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/asyncio_client.py 2022-01-11 13:17:25.000000000 +0100 @@ -40,6 +40,11 @@ packets. Custom json modules must have ``dumps`` and ``loads`` functions that are compatible with the standard library versions. + :param handle_sigint: Set to ``True`` to automatically handle disconnection + when the process is interrupted, or to ``False`` to + leave interrupt handling to the calling application. + Interrupt handling can only be enabled when the + client instance is created in the main thread. The Engine.IO configuration supports the following settings: @@ -249,6 +254,12 @@ async def call(self, event, data=None, namespace=None, timeout=60): """Emit a custom event to a client and wait for the response. + This method issues an emit with a callback and waits for the callback + to be invoked before returning. If the callback isn't invoked before + the timeout, then a ``TimeoutError`` exception is raised. If the + Socket.IO connection drops during the wait, this method still waits + until the specified timeout. + :param event: The event name. It can be any string. The event names ``'connect'``, ``'message'`` and ``'disconnect'`` are reserved and should not be used. @@ -311,9 +322,7 @@ :param args: arguments to pass to the function. :param kwargs: keyword arguments to pass to the function. - This function returns an object compatible with the `Thread` class in - the Python standard library. The `start()` method on this object is - already called by this function. + The return value is a ``asyncio.Task`` object. """ return self.eio.start_background_task(target, *args, **kwargs) @@ -422,7 +431,8 @@ handler = None if event in self.handlers[namespace]: handler = self.handlers[namespace][event] - elif '*' in self.handlers[namespace]: + elif event not in self.reserved_events and \ + '*' in self.handlers[namespace]: handler = self.handlers[namespace]['*'] args = (event, *args) if handler: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/asyncio_namespace.py new/python-socketio-5.5.1/src/socketio/asyncio_namespace.py --- old/python-socketio-5.4.1/src/socketio/asyncio_namespace.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/asyncio_namespace.py 2022-01-11 13:17:25.000000000 +0100 @@ -41,7 +41,7 @@ ret = handler(*args) return ret - async def emit(self, event, data=None, room=None, skip_sid=None, + async def emit(self, event, data=None, to=None, room=None, skip_sid=None, namespace=None, callback=None): """Emit a custom event to one or more connected clients. @@ -51,13 +51,13 @@ Note: this method is a coroutine. """ - return await self.server.emit(event, data=data, room=room, + return await self.server.emit(event, data=data, to=to, room=room, skip_sid=skip_sid, namespace=namespace or self.namespace, callback=callback) - async def send(self, data, room=None, skip_sid=None, namespace=None, - callback=None): + async def send(self, data, to=None, room=None, skip_sid=None, + namespace=None, callback=None): """Send a message to one or more connected clients. The only difference with the :func:`socketio.Server.send` method is @@ -66,10 +66,23 @@ Note: this method is a coroutine. """ - return await self.server.send(data, room=room, skip_sid=skip_sid, + return await self.server.send(data, to=to, room=room, + skip_sid=skip_sid, namespace=namespace or self.namespace, callback=callback) + async def call(self, event, data=None, to=None, sid=None, namespace=None, + timeout=None): + """Emit a custom event to a client and wait for the response. + + The only difference with the :func:`socketio.Server.call` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return await self.server.call(event, data=data, to=to, sid=sid, + namespace=namespace or self.namespace, + timeout=timeout) + async def close_room(self, room, namespace=None): """Close a room. @@ -192,6 +205,17 @@ namespace=namespace or self.namespace, callback=callback) + async def call(self, event, data=None, namespace=None, timeout=None): + """Emit a custom event to the server and wait for the response. + + The only difference with the :func:`socketio.Client.call` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return await self.client.call(event, data=data, + namespace=namespace or self.namespace, + timeout=timeout) + async def disconnect(self): """Disconnect a client. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/asyncio_pubsub_manager.py new/python-socketio-5.5.1/src/socketio/asyncio_pubsub_manager.py --- old/python-socketio-5.4.1/src/socketio/asyncio_pubsub_manager.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/asyncio_pubsub_manager.py 2022-01-11 13:17:25.000000000 +0100 @@ -148,35 +148,34 @@ async def _thread(self): while True: try: - message = await self._listen() + async for message in self._listen(): # pragma: no branch + data = None + if isinstance(message, dict): + data = message + 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 + if data and 'method' in data: + self._get_logger().info('pubsub message: {}'.format( + data['method'])) + if data['method'] == 'emit': + await self._handle_emit(data) + elif data['method'] == 'callback': + await self._handle_callback(data) + elif data['method'] == 'disconnect': + await self._handle_disconnect(data) + elif data['method'] == 'close_room': + await self._handle_close_room(data) except asyncio.CancelledError: # pragma: no cover break - except: + except: # pragma: no cover import traceback traceback.print_exc() - break - data = None - if isinstance(message, dict): - data = message - 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 - if data and 'method' in data: - self._get_logger().info('pubsub message: {}'.format( - data['method'])) - if data['method'] == 'emit': - await self._handle_emit(data) - elif data['method'] == 'callback': - await self._handle_callback(data) - elif data['method'] == 'disconnect': - await self._handle_disconnect(data) - elif data['method'] == 'close_room': - await self._handle_close_room(data) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/asyncio_redis_manager.py new/python-socketio-5.5.1/src/socketio/asyncio_redis_manager.py --- old/python-socketio-5.4.1/src/socketio/asyncio_redis_manager.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/asyncio_redis_manager.py 2022-01-11 13:17:25.000000000 +0100 @@ -1,6 +1,5 @@ import asyncio import pickle -from urllib.parse import urlparse try: import aioredis @@ -10,34 +9,18 @@ from .asyncio_pubsub_manager import AsyncPubSubManager -def _parse_redis_url(url): - p = urlparse(url) - if p.scheme not in {'redis', 'rediss'}: - raise ValueError('Invalid redis url') - ssl = p.scheme == 'rediss' - host = p.hostname or 'localhost' - port = p.port or 6379 - password = p.password - if p.path: - db = int(p.path[1:]) - else: - db = 0 - return host, port, password, db, ssl - - class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover """Redis based client manager for asyncio servers. This class implements a Redis backend for event sharing across multiple - processes. Only kept here as one more example of how to build a custom - backend, since the kombu backend is perfectly adequate to support a Redis - message queue. + processes. - To use a Redis backend, initialize the :class:`Server` instance as + To use a Redis backend, initialize the :class:`AsyncServer` instance as follows:: - server = socketio.Server(client_manager=socketio.AsyncRedisManager( - 'redis://hostname:port/0')) + url = 'redis://hostname:port/0' + server = socketio.AsyncServer( + client_manager=socketio.AsyncRedisManager(url)) :param url: The connection URL for the Redis server. For a default Redis store running on the same host, use ``redis://``. To use an @@ -47,62 +30,73 @@ :param write_only: If set to ``True``, only initialize to emit events. The default of ``False`` initializes the class for emitting and receiving. + :param redis_options: additional keyword arguments to be passed to + ``aioredis.from_url()``. """ name = 'aioredis' def __init__(self, url='redis://localhost:6379/0', channel='socketio', - write_only=False, logger=None): + write_only=False, logger=None, redis_options=None): if aioredis is None: raise RuntimeError('Redis package is not installed ' '(Run "pip install aioredis" in your ' 'virtualenv).') - ( - self.host, self.port, self.password, self.db, self.ssl - ) = _parse_redis_url(url) - self.pub = None - self.sub = None + if not hasattr(aioredis.Redis, 'from_url'): + raise RuntimeError('Version 2 of aioredis package is required.') + self.redis_url = url + self.redis_options = redis_options or {} + self._redis_connect() super().__init__(channel=channel, write_only=write_only, logger=logger) + def _redis_connect(self): + self.redis = aioredis.Redis.from_url(self.redis_url, + **self.redis_options) + self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True) + async def _publish(self, data): retry = True while True: try: - if self.pub is None: - self.pub = await aioredis.create_redis( - (self.host, self.port), db=self.db, - password=self.password, ssl=self.ssl - ) - return await self.pub.publish(self.channel, - pickle.dumps(data)) - except (aioredis.RedisError, OSError): + if not retry: + self._redis_connect() + return await self.redis.publish( + self.channel, pickle.dumps(data)) + except aioredis.exceptions.RedisError: if retry: self._get_logger().error('Cannot publish to redis... ' 'retrying') - self.pub = None retry = False else: self._get_logger().error('Cannot publish to redis... ' 'giving up') break - async def _listen(self): + async def _redis_listen_with_retries(self): retry_sleep = 1 + connect = False while True: try: - if self.sub is None: - self.sub = await aioredis.create_redis( - (self.host, self.port), db=self.db, - password=self.password, ssl=self.ssl - ) - self.ch = (await self.sub.subscribe(self.channel))[0] - retry_sleep = 1 - return await self.ch.get() - except (aioredis.RedisError, OSError): + if connect: + self._redis_connect() + await self.pubsub.subscribe(self.channel) + retry_sleep = 1 + async for message in self.pubsub.listen(): + yield message + except aioredis.exceptions.RedisError: self._get_logger().error('Cannot receive from redis... ' 'retrying in ' '{} secs'.format(retry_sleep)) - self.sub = None + connect = True await asyncio.sleep(retry_sleep) retry_sleep *= 2 if retry_sleep > 60: retry_sleep = 60 + + async def _listen(self): + channel = self.channel.encode('utf-8') + await self.pubsub.subscribe(self.channel) + async for message in self._redis_listen_with_retries(): + if message['channel'] == channel and \ + message['type'] == 'message' and 'data' in message: + yield message['data'] + await self.pubsub.unsubscribe(self.channel) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/asyncio_server.py new/python-socketio-5.5.1/src/socketio/asyncio_server.py --- old/python-socketio-5.4.1/src/socketio/asyncio_server.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/asyncio_server.py 2022-01-11 13:17:25.000000000 +0100 @@ -210,6 +210,12 @@ timeout=60, **kwargs): """Emit a custom event to a client and wait for the response. + This method issues an emit with a callback and waits for the callback + to be invoked before returning. If the callback isn't invoked before + the timeout, then a ``TimeoutError`` exception is raised. If the + Socket.IO connection drops during the wait, this method still waits + until the specified timeout. + :param event: The event name. It can be any string. The event names ``'connect'``, ``'message'`` and ``'disconnect'`` are reserved and should not be used. @@ -396,8 +402,6 @@ :param kwargs: keyword arguments to pass to the function. The return value is a ``asyncio.Task`` object. - - Note: this method is a coroutine. """ return self.eio.start_background_task(target, *args, **kwargs) @@ -528,7 +532,8 @@ handler = None if event in self.handlers[namespace]: handler = self.handlers[namespace][event] - elif '*' in self.handlers[namespace]: + elif event not in self.reserved_events and \ + '*' in self.handlers[namespace]: handler = self.handlers[namespace]['*'] args = (event, *args) if handler: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/client.py new/python-socketio-5.5.1/src/socketio/client.py --- old/python-socketio-5.4.1/src/socketio/client.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/client.py 2022-01-11 13:17:25.000000000 +0100 @@ -68,6 +68,11 @@ packets. Custom json modules must have ``dumps`` and ``loads`` functions that are compatible with the standard library versions. + :param handle_sigint: Set to ``True`` to automatically handle disconnection + when the process is interrupted, or to ``False`` to + leave interrupt handling to the calling application. + Interrupt handling can only be enabled when the + client instance is created in the main thread. The Engine.IO configuration supports the following settings: @@ -87,12 +92,14 @@ fatal errors are logged even when ``engineio_logger`` is ``False``. """ + reserved_events = ['connect', 'connect_error', 'disconnect'] + def __init__(self, reconnection=True, reconnection_attempts=0, reconnection_delay=1, reconnection_delay_max=5, randomization_factor=0.5, logger=False, serializer='default', - json=None, **kwargs): + json=None, handle_sigint=True, **kwargs): global original_signal_handler - if original_signal_handler is None and \ + if handle_sigint and original_signal_handler is None and \ threading.current_thread() == threading.main_thread(): original_signal_handler = signal.signal(signal.SIGINT, signal_handler) @@ -101,8 +108,10 @@ self.reconnection_delay = reconnection_delay self.reconnection_delay_max = reconnection_delay_max self.randomization_factor = randomization_factor + self.handle_sigint = handle_sigint engineio_options = kwargs + engineio_options['handle_sigint'] = handle_sigint engineio_logger = engineio_options.pop('engineio_logger', None) if engineio_logger is not None: engineio_options['logger'] = engineio_logger @@ -141,8 +150,8 @@ self.socketio_path = None self.sid = None - self.connected = False - self.namespaces = {} + self.connected = False #: Indicates if the client is connected or not. + self.namespaces = {} #: set of connected namespaces. self.handlers = {} self.namespace_handlers = {} self.callbacks = {} @@ -423,6 +432,12 @@ def call(self, event, data=None, namespace=None, timeout=60): """Emit a custom event to a client and wait for the response. + This method issues an emit with a callback and waits for the callback + to be invoked before returning. If the callback isn't invoked before + the timeout, then a ``TimeoutError`` exception is raised. If the + Socket.IO connection drops during the wait, this method still waits + until the specified timeout. + :param event: The event name. It can be any string. The event names ``'connect'``, ``'message'`` and ``'disconnect'`` are reserved and should not be used. @@ -500,9 +515,9 @@ :param args: arguments to pass to the function. :param kwargs: keyword arguments to pass to the function. - This function returns an object compatible with the `Thread` class in - the Python standard library. The `start()` method on this object is - already called by this function. + This function returns an object that represents the background task, + on which the ``join()`` methond can be invoked to wait for the task to + complete. """ return self.eio.start_background_task(target, *args, **kwargs) @@ -612,7 +627,8 @@ if namespace in self.handlers: if event in self.handlers[namespace]: return self.handlers[namespace][event](*args) - elif '*' in self.handlers[namespace]: + elif event not in self.reserved_events and \ + '*' in self.handlers[namespace]: return self.handlers[namespace]['*'](event, *args) # or else, forward the event to a namespace handler if one exists diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/kafka_manager.py new/python-socketio-5.5.1/src/socketio/kafka_manager.py --- old/python-socketio-5.4.1/src/socketio/kafka_manager.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/kafka_manager.py 2022-01-11 13:17:25.000000000 +0100 @@ -24,7 +24,9 @@ server = socketio.Server(client_manager=socketio.KafkaManager(url)) :param url: The connection URL for the Kafka server. For a default Kafka - store running on the same host, use ``kafka://``. + store running on the same host, use ``kafka://``. For a highly + available deployment of Kafka, pass a list with all the + connection URLs available in your cluster. :param channel: The channel name (topic) on which the server sends and receives notifications. Must be the same in all the servers. @@ -44,10 +46,12 @@ super(KafkaManager, self).__init__(channel=channel, write_only=write_only) - self.kafka_url = url[8:] if url != 'kafka://' else 'localhost:9092' - self.producer = kafka.KafkaProducer(bootstrap_servers=self.kafka_url) + urls = [url] if isinstance(url, str) else url + self.kafka_urls = [url[8:] if url != 'kafka://' else 'localhost:9092' + for url in urls] + self.producer = kafka.KafkaProducer(bootstrap_servers=self.kafka_urls) self.consumer = kafka.KafkaConsumer(self.channel, - bootstrap_servers=self.kafka_url) + bootstrap_servers=self.kafka_urls) def _publish(self, data): self.producer.send(self.channel, value=pickle.dumps(data)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/msgpack_packet.py new/python-socketio-5.5.1/src/socketio/msgpack_packet.py --- old/python-socketio-5.4.1/src/socketio/msgpack_packet.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/msgpack_packet.py 2022-01-11 13:17:25.000000000 +0100 @@ -3,6 +3,8 @@ class MsgPackPacket(packet.Packet): + uses_binary_events = False + def encode(self): """Encode the packet for transmission.""" return msgpack.dumps(self._to_dict()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/namespace.py new/python-socketio-5.5.1/src/socketio/namespace.py --- old/python-socketio-5.4.1/src/socketio/namespace.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/namespace.py 2022-01-11 13:17:25.000000000 +0100 @@ -37,19 +37,20 @@ def _set_server(self, server): self.server = server - def emit(self, event, data=None, room=None, skip_sid=None, namespace=None, - callback=None): + def emit(self, event, data=None, to=None, room=None, skip_sid=None, + namespace=None, callback=None): """Emit a custom event to one or more connected clients. The only difference with the :func:`socketio.Server.emit` method is that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.server.emit(event, data=data, room=room, skip_sid=skip_sid, + return self.server.emit(event, data=data, to=to, room=room, + skip_sid=skip_sid, namespace=namespace or self.namespace, callback=callback) - def send(self, data, room=None, skip_sid=None, namespace=None, + def send(self, data, to=None, room=None, skip_sid=None, namespace=None, callback=None): """Send a message to one or more connected clients. @@ -57,10 +58,22 @@ that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.server.send(data, room=room, skip_sid=skip_sid, + return self.server.send(data, to=to, room=room, skip_sid=skip_sid, namespace=namespace or self.namespace, callback=callback) + def call(self, event, data=None, to=None, sid=None, namespace=None, + timeout=None): + """Emit a custom event to a client and wait for the response. + + The only difference with the :func:`socketio.Server.call` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.server.call(event, data=data, to=to, sid=sid, + namespace=namespace or self.namespace, + timeout=timeout) + def enter_room(self, sid, room, namespace=None): """Enter a room. @@ -170,8 +183,7 @@ namespace=namespace or self.namespace, callback=callback) - def send(self, data, room=None, skip_sid=None, namespace=None, - callback=None): + def send(self, data, room=None, namespace=None, callback=None): """Send a message to the server. The only difference with the :func:`socketio.Client.send` method is @@ -181,6 +193,17 @@ return self.client.send(data, namespace=namespace or self.namespace, callback=callback) + def call(self, event, data=None, namespace=None, timeout=None): + """Emit a custom event to the server and wait for the response. + + The only difference with the :func:`socketio.Client.call` method is + that when the ``namespace`` argument is not given the namespace + associated with the class is used. + """ + return self.client.call(event, data=data, + namespace=namespace or self.namespace, + timeout=timeout) + def disconnect(self): """Disconnect from the server. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/packet.py new/python-socketio-5.5.1/src/socketio/packet.py --- old/python-socketio-5.4.1/src/socketio/packet.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/packet.py 2022-01-11 13:17:25.000000000 +0100 @@ -19,6 +19,7 @@ # id: ASCII encoded, only if id is not None # data: JSON dump of data payload + uses_binary_events = True json = _json def __init__(self, packet_type=EVENT, data=None, namespace=None, id=None, @@ -27,7 +28,9 @@ self.data = data self.namespace = namespace self.id = id - if binary or (binary is None and self._data_is_binary(self.data)): + if self.uses_binary_events and \ + (binary or (binary is None and self._data_is_binary( + self.data))): if self.packet_type == EVENT: self.packet_type = BINARY_EVENT elif self.packet_type == ACK: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/redis_manager.py new/python-socketio-5.5.1/src/socketio/redis_manager.py --- old/python-socketio-5.4.1/src/socketio/redis_manager.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/redis_manager.py 2022-01-11 13:17:25.000000000 +0100 @@ -27,7 +27,8 @@ server = socketio.Server(client_manager=socketio.RedisManager(url)) :param url: The connection URL for the Redis server. For a default Redis - store running on the same host, use ``redis://``. + store running on the same host, use ``redis://``. To use an + SSL connection, use ``rediss://``. :param channel: The channel name on which the server sends and receives notifications. Must be the same in all the servers. :param write_only: If set to ``True``, only initialize to emit events. The @@ -69,7 +70,7 @@ def _redis_connect(self): self.redis = redis.Redis.from_url(self.redis_url, **self.redis_options) - self.pubsub = self.redis.pubsub() + self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True) def _publish(self, data): retry = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/src/socketio/server.py new/python-socketio-5.5.1/src/socketio/server.py --- old/python-socketio-5.4.1/src/socketio/server.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/src/socketio/server.py 2022-01-11 13:17:25.000000000 +0100 @@ -106,6 +106,8 @@ fatal errors are logged even when ``engineio_logger`` is ``False``. """ + reserved_events = ['connect', 'disconnect'] + def __init__(self, client_manager=None, logger=False, serializer='default', json=None, async_handlers=True, always_connect=False, **kwargs): @@ -355,6 +357,12 @@ timeout=60, **kwargs): """Emit a custom event to a client and wait for the response. + This method issues an emit with a callback and waits for the callback + to be invoked before returning. If the callback isn't invoked before + the timeout, then a ``TimeoutError`` exception is raised. If the + Socket.IO connection drops during the wait, this method still waits + until the specified timeout. + :param event: The event name. It can be any string. The event names ``'connect'``, ``'message'`` and ``'disconnect'`` are reserved and should not be used. @@ -599,9 +607,9 @@ :param args: arguments to pass to the function. :param kwargs: keyword arguments to pass to the function. - This function returns an object compatible with the `Thread` class in - the Python standard library. The `start()` method on this object is - already called by this function. + This function returns an object that represents the background task, + on which the ``join()`` methond can be invoked to wait for the task to + complete. """ return self.eio.start_background_task(target, *args, **kwargs) @@ -735,7 +743,8 @@ if namespace in self.handlers: if event in self.handlers[namespace]: return self.handlers[namespace][event](*args) - elif '*' in self.handlers[namespace]: + elif event not in self.reserved_events and \ + '*' in self.handlers[namespace]: return self.handlers[namespace]['*'](event, *args) # or else, forward the event to a namespace handler if one exists diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/tests/asyncio/test_asyncio_client.py new/python-socketio-5.5.1/tests/asyncio/test_asyncio_client.py --- old/python-socketio-5.4.1/tests/asyncio/test_asyncio_client.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/tests/asyncio/test_asyncio_client.py 2022-01-11 13:17:25.000000000 +0100 @@ -838,6 +838,7 @@ c.on('*', catchall_handler) _run(c._trigger_event('foo', '/', 1, '2')) _run(c._trigger_event('bar', '/', 1, '2', 3)) + _run(c._trigger_event('connect', '/')) # should not trigger handler.assert_called_once_with(1, '2') catchall_handler.assert_called_once_with('bar', 1, '2', 3) @@ -891,8 +892,6 @@ side_effect=[ValueError, exceptions.ConnectionError, None] ) _run(c._handle_reconnect()) - print(wait_for.mock.call_count) # logging to debug #572 - print(wait_for.mock.call_args_list) assert wait_for.mock.call_count == 3 assert [x[0][1] for x in asyncio.wait_for.mock.call_args_list] == [ 1.5, @@ -914,8 +913,6 @@ side_effect=[ValueError, exceptions.ConnectionError, None] ) _run(c._handle_reconnect()) - print(wait_for.mock.call_count) # logging to debug #572 - print(wait_for.mock.call_args_list) assert wait_for.mock.call_count == 3 assert [x[0][1] for x in asyncio.wait_for.mock.call_args_list] == [ 1.5, @@ -931,15 +928,12 @@ ) @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) def test_handle_reconnect_max_attempts(self, random, wait_for): - c = asyncio_client.AsyncClient(reconnection_attempts=2) + c = asyncio_client.AsyncClient(reconnection_attempts=2, logger=True) c._reconnect_task = 'foo' c.connect = AsyncMock( side_effect=[ValueError, exceptions.ConnectionError, None] ) _run(c._handle_reconnect()) - print(c.reconnection_attempts) - print(wait_for.mock.call_count) # logging to debug #572 - print(wait_for.mock.call_args_list) assert wait_for.mock.call_count == 2 assert [x[0][1] for x in asyncio.wait_for.mock.call_args_list] == [ 1.5, @@ -954,14 +948,12 @@ ) @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) def test_handle_reconnect_aborted(self, random, wait_for): - c = asyncio_client.AsyncClient() + c = asyncio_client.AsyncClient(logger=True) c._reconnect_task = 'foo' c.connect = AsyncMock( side_effect=[ValueError, exceptions.ConnectionError, None] ) _run(c._handle_reconnect()) - print(wait_for.mock.call_count) # logging to debug #572 - print(wait_for.mock.call_args_list) assert wait_for.mock.call_count == 2 assert [x[0][1] for x in asyncio.wait_for.mock.call_args_list] == [ 1.5, @@ -1065,7 +1057,7 @@ _run(c._handle_eio_message('9')) def test_eio_disconnect(self): - c = asyncio_client.AsyncClient() + c = asyncio_client.AsyncClient(reconnection=False) c.namespaces = {'/': '1'} c.connected = True c._trigger_event = AsyncMock() @@ -1079,7 +1071,7 @@ assert not c.connected def test_eio_disconnect_namespaces(self): - c = asyncio_client.AsyncClient() + c = asyncio_client.AsyncClient(reconnection=False) c.namespaces = {'/foo': '1', '/bar': '2'} c.connected = True c._trigger_event = AsyncMock() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/tests/asyncio/test_asyncio_namespace.py new/python-socketio-5.5.1/tests/asyncio/test_asyncio_namespace.py --- old/python-socketio-5.4.1/tests/asyncio/test_asyncio_namespace.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/tests/asyncio/test_asyncio_namespace.py 2022-01-11 13:17:25.000000000 +0100 @@ -93,13 +93,14 @@ ns._set_server(mock_server) _run( ns.emit( - 'ev', data='data', room='room', skip_sid='skip', callback='cb' + 'ev', data='data', to='room', skip_sid='skip', callback='cb' ) ) ns.server.emit.mock.assert_called_with( 'ev', data='data', - room='room', + to='room', + room=None, skip_sid='skip', namespace='/foo', callback='cb', @@ -117,6 +118,7 @@ ns.server.emit.mock.assert_called_with( 'ev', data='data', + to=None, room='room', skip_sid='skip', namespace='/bar', @@ -128,10 +130,11 @@ mock_server = mock.MagicMock() mock_server.send = AsyncMock() ns._set_server(mock_server) - _run(ns.send(data='data', room='room', skip_sid='skip', callback='cb')) + _run(ns.send(data='data', to='room', skip_sid='skip', callback='cb')) ns.server.send.mock.assert_called_with( 'data', - room='room', + to='room', + room=None, skip_sid='skip', namespace='/foo', callback='cb', @@ -147,12 +150,38 @@ ) ns.server.send.mock.assert_called_with( 'data', + to=None, room='room', skip_sid='skip', namespace='/bar', callback='cb', ) + def test_call(self): + ns = asyncio_namespace.AsyncNamespace('/foo') + mock_server = mock.MagicMock() + mock_server.call = AsyncMock() + ns._set_server(mock_server) + _run(ns.call('ev', data='data', to='sid')) + ns.server.call.mock.assert_called_with( + 'ev', + data='data', + to='sid', + sid=None, + namespace='/foo', + timeout=None, + ) + _run(ns.call('ev', data='data', sid='sid', namespace='/bar', + timeout=45)) + ns.server.call.mock.assert_called_with( + 'ev', + data='data', + to=None, + sid='sid', + namespace='/bar', + timeout=45, + ) + def test_enter_room(self): ns = asyncio_namespace.AsyncNamespace('/foo') ns._set_server(mock.MagicMock()) @@ -294,6 +323,20 @@ 'data', namespace='/bar', callback='cb' ) + def test_call_client(self): + ns = asyncio_namespace.AsyncClientNamespace('/foo') + mock_client = mock.MagicMock() + mock_client.call = AsyncMock() + ns._set_client(mock_client) + _run(ns.call('ev', data='data')) + ns.client.call.mock.assert_called_with( + 'ev', data='data', namespace='/foo', timeout=None + ) + _run(ns.call('ev', data='data', namespace='/bar', timeout=45)) + ns.client.call.mock.assert_called_with( + 'ev', data='data', namespace='/bar', timeout=45 + ) + def test_disconnect_client(self): ns = asyncio_namespace.AsyncClientNamespace('/foo') mock_client = mock.MagicMock() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/tests/asyncio/test_asyncio_pubsub_manager.py new/python-socketio-5.5.1/tests/asyncio/test_asyncio_pubsub_manager.py --- old/python-socketio-5.4.1/tests/asyncio/test_asyncio_pubsub_manager.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/tests/asyncio/test_asyncio_pubsub_manager.py 2022-01-11 13:17:25.000000000 +0100 @@ -417,7 +417,7 @@ self.pm._handle_disconnect = AsyncMock() self.pm._handle_close_room = AsyncMock() - def messages(): + async def messages(): import pickle yield {'method': 'emit', 'value': 'foo'} @@ -428,12 +428,10 @@ yield pickle.dumps({'method': 'close_room', 'value': 'baz'}) yield 'bad json' yield b'bad pickled' + raise asyncio.CancelledError() # force the thread to exit - self.pm._listen = AsyncMock(side_effect=list(messages())) - try: - _run(self.pm._thread()) - except StopIteration: - pass + self.pm._listen = messages + _run(self.pm._thread()) self.pm._handle_emit.mock.assert_called_once_with( {'method': 'emit', 'value': 'foo'} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/tests/asyncio/test_asyncio_redis_manager.py new/python-socketio-5.5.1/tests/asyncio/test_asyncio_redis_manager.py --- old/python-socketio-5.4.1/tests/asyncio/test_asyncio_redis_manager.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/tests/asyncio/test_asyncio_redis_manager.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,73 +0,0 @@ -import sys -import unittest - -import pytest - -from socketio import asyncio_redis_manager - - -@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') -class TestAsyncRedisManager(unittest.TestCase): - def test_default_url(self): - assert asyncio_redis_manager._parse_redis_url('redis://') == ( - 'localhost', - 6379, - None, - 0, - False, - ) - - def test_only_host_url(self): - assert asyncio_redis_manager._parse_redis_url( - 'redis://redis.host' - ) == ('redis.host', 6379, None, 0, False) - - def test_no_db_url(self): - assert asyncio_redis_manager._parse_redis_url( - 'redis://redis.host:123/1' - ) == ('redis.host', 123, None, 1, False) - - def test_no_port_url(self): - assert asyncio_redis_manager._parse_redis_url( - 'redis://redis.host/1' - ) == ('redis.host', 6379, None, 1, False) - - def test_password(self): - assert asyncio_redis_manager._parse_redis_url( - 'redis://:p...@redis.host/1' - ) == ('redis.host', 6379, 'pw', 1, False) - - def test_no_host_url(self): - assert asyncio_redis_manager._parse_redis_url('redis://:123/1') == ( - 'localhost', - 123, - None, - 1, - False, - ) - - def test_no_host_password_url(self): - assert asyncio_redis_manager._parse_redis_url( - 'redis://:pw@:123/1' - ) == ('localhost', 123, 'pw', 1, False) - - def test_bad_port_url(self): - with pytest.raises(ValueError): - asyncio_redis_manager._parse_redis_url('redis://localhost:abc/1') - - def test_bad_db_url(self): - with pytest.raises(ValueError): - asyncio_redis_manager._parse_redis_url('redis://localhost:abc/z') - - def test_bad_scheme_url(self): - with pytest.raises(ValueError): - asyncio_redis_manager._parse_redis_url('http://redis.host:123/1') - - def test_ssl_scheme(self): - assert asyncio_redis_manager._parse_redis_url('rediss://') == ( - 'localhost', - 6379, - None, - 0, - True, - ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/tests/common/test_client.py new/python-socketio-5.5.1/tests/common/test_client.py --- old/python-socketio-5.4.1/tests/common/test_client.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/tests/common/test_client.py 2022-01-11 13:17:25.000000000 +0100 @@ -29,6 +29,7 @@ reconnection_delay=5, reconnection_delay_max=10, randomization_factor=0.2, + handle_sigint=False, foo='bar', ) assert not c.reconnection @@ -36,7 +37,9 @@ assert c.reconnection_delay == 5 assert c.reconnection_delay_max == 10 assert c.randomization_factor == 0.2 - engineio_client_class().assert_called_once_with(foo='bar') + assert not c.handle_sigint + engineio_client_class().assert_called_once_with( + foo='bar', handle_sigint=False) assert c.connection_url is None assert c.connection_headers is None assert c.connection_transports is None @@ -89,7 +92,8 @@ @mock.patch('socketio.client.Client._engineio_client_class') def test_engineio_logger(self, engineio_client_class): client.Client(engineio_logger='foo') - engineio_client_class().assert_called_once_with(logger='foo') + engineio_client_class().assert_called_once_with( + handle_sigint=True, logger='foo') def test_on_event(self): c = client.Client() @@ -939,6 +943,7 @@ c.on('*', catchall_handler) c._trigger_event('foo', '/', 1, '2') c._trigger_event('bar', '/', 1, '2', 3) + c._trigger_event('connect', '/') # should not trigger handler.assert_called_once_with(1, '2') catchall_handler.assert_called_once_with('bar', 1, '2', 3) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/tests/common/test_msgpack_packet.py new/python-socketio-5.5.1/tests/common/test_msgpack_packet.py --- old/python-socketio-5.4.1/tests/common/test_msgpack_packet.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/tests/common/test_msgpack_packet.py 2022-01-11 13:17:25.000000000 +0100 @@ -22,3 +22,15 @@ assert p.data == p2.data assert p.id == p2.id assert p.namespace == p2.namespace + + def test_encode_binary_event_packet(self): + p = msgpack_packet.MsgPackPacket(packet.EVENT, data={'foo': b'bar'}) + assert p.packet_type == packet.EVENT + p2 = msgpack_packet.MsgPackPacket(encoded_packet=p.encode()) + assert p2.data == {'foo': b'bar'} + + def test_encode_binary_ack_packet(self): + p = msgpack_packet.MsgPackPacket(packet.ACK, data={'foo': b'bar'}) + assert p.packet_type == packet.ACK + p2 = msgpack_packet.MsgPackPacket(encoded_packet=p.encode()) + assert p2.data == {'foo': b'bar'} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/tests/common/test_namespace.py new/python-socketio-5.5.1/tests/common/test_namespace.py --- old/python-socketio-5.4.1/tests/common/test_namespace.py 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/tests/common/test_namespace.py 2022-01-11 13:17:25.000000000 +0100 @@ -56,11 +56,12 @@ def test_emit(self): ns = namespace.Namespace('/foo') ns._set_server(mock.MagicMock()) - ns.emit('ev', data='data', room='room', skip_sid='skip', callback='cb') + ns.emit('ev', data='data', to='room', skip_sid='skip', callback='cb') ns.server.emit.assert_called_with( 'ev', data='data', - room='room', + to='room', + room=None, skip_sid='skip', namespace='/foo', callback='cb', @@ -76,6 +77,7 @@ ns.server.emit.assert_called_with( 'ev', data='data', + to=None, room='room', skip_sid='skip', namespace='/bar', @@ -85,10 +87,11 @@ def test_send(self): ns = namespace.Namespace('/foo') ns._set_server(mock.MagicMock()) - ns.send(data='data', room='room', skip_sid='skip', callback='cb') + ns.send(data='data', to='room', skip_sid='skip', callback='cb') ns.server.send.assert_called_with( 'data', - room='room', + to='room', + room=None, skip_sid='skip', namespace='/foo', callback='cb', @@ -102,12 +105,41 @@ ) ns.server.send.assert_called_with( 'data', + to=None, room='room', skip_sid='skip', namespace='/bar', callback='cb', ) + def test_call(self): + ns = namespace.Namespace('/foo') + ns._set_server(mock.MagicMock()) + ns.call('ev', data='data', to='sid') + ns.server.call.assert_called_with( + 'ev', + data='data', + to='sid', + sid=None, + namespace='/foo', + timeout=None, + ) + ns.call( + 'ev', + data='data', + sid='sid', + namespace='/bar', + timeout=45, + ) + ns.server.call.assert_called_with( + 'ev', + data='data', + to=None, + sid='sid', + namespace='/bar', + timeout=45, + ) + def test_enter_room(self): ns = namespace.Namespace('/foo') ns._set_server(mock.MagicMock()) @@ -200,6 +232,17 @@ 'data', namespace='/bar', callback='cb' ) + def test_call_client(self): + ns = namespace.ClientNamespace('/foo') + ns._set_client(mock.MagicMock()) + ns.call('ev', data='data') + ns.client.call.assert_called_with( + 'ev', data='data', namespace='/foo', timeout=None) + ns.call('ev', data='data', namespace='/bar', timeout=45) + ns.client.call.assert_called_with( + 'ev', data='data', namespace='/bar', timeout=45 + ) + def test_disconnect_client(self): ns = namespace.ClientNamespace('/foo') ns._set_client(mock.MagicMock()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-socketio-5.4.1/tox.ini new/python-socketio-5.5.1/tox.ini --- old/python-socketio-5.4.1/tox.ini 2021-10-14 21:19:50.000000000 +0200 +++ new/python-socketio-5.5.1/tox.ini 2022-01-11 13:17:25.000000000 +0100 @@ -23,7 +23,7 @@ deps= flake8 commands= - flake8 --exclude=".*" --ignore=W503,E402,E722 src/socketio tests + flake8 --exclude=".*" --ignore=W503,E402,E722 src/socketio tests examples [testenv:docs] changedir=docs