Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-Flask-SocketIO for openSUSE:Factory checked in at 2023-06-22 23:26:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Flask-SocketIO (Old) and /work/SRC/openSUSE:Factory/.python-Flask-SocketIO.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Flask-SocketIO" Thu Jun 22 23:26:07 2023 rev:3 rq:1094493 version:5.3.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Flask-SocketIO/python-Flask-SocketIO.changes 2021-10-27 22:21:45.147215476 +0200 +++ /work/SRC/openSUSE:Factory/.python-Flask-SocketIO.new.15902/python-Flask-SocketIO.changes 2023-06-22 23:26:31.181981912 +0200 @@ -1,0 +2,11 @@ +Wed Jun 21 21:36:05 UTC 2023 - Matej Cepl <mc...@suse.com> + +- Clean up SPEC file, make rpmlint happy. + +------------------------------------------------------------------- +Wed Jun 21 19:56:26 UTC 2023 - Axel Braun <axel.br...@gmx.de> + +- update to version 5.3.4 + * For a full changelog see https://github.com/miguelgrinberg/Flask-SocketIO/blob/main/CHANGES.md + +------------------------------------------------------------------- Old: ---- Flask-SocketIO-5.1.1.tar.gz New: ---- Flask-SocketIO-5.3.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Flask-SocketIO.spec ++++++ --- /var/tmp/diff_new_pack.p8vss1/_old 2023-06-22 23:26:31.825985197 +0200 +++ /var/tmp/diff_new_pack.p8vss1/_new 2023-06-22 23:26:31.829985217 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-Flask-SocketIO # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,24 +16,24 @@ # -%{?!python_module:%define python_module() python3-%{**}} %define skip_python2 1 Name: python-Flask-SocketIO -Version: 5.1.1 +Version: 5.3.4 Release: 0 -License: MIT Summary: SocketIO integration for Flask applications -URL: http://github.com/miguelgrinberg/Flask-SocketIO/ +License: MIT Group: Development/Languages/Python +URL: https://github.com/miguelgrinberg/Flask-SocketIO/ Source: https://files.pythonhosted.org/packages/source/F/Flask-SocketIO/Flask-SocketIO-%{version}.tar.gz Source1: https://raw.githubusercontent.com/miguelgrinberg/Flask-SocketIO/v%{version}/test_socketio.py BuildRequires: %{python_module Flask >= 0.9} +BuildRequires: %{python_module pip} BuildRequires: %{python_module python-socketio >= 5.0.2} -BuildRequires: %{python_module setuptools} +BuildRequires: %{python_module redis} +BuildRequires: %{python_module wheel} BuildRequires: fdupes Requires: python-Flask >= 0.9 Requires: python-python-socketio >= 5.0.2 - BuildArch: noarch %python_subpackages @@ -42,13 +42,13 @@ %prep %setup -q -n Flask-SocketIO-%{version} -cp %{S:1} . +cp %{SOURCE1} . %build -%python_build +%pyproject_wheel %install -%python_install +%pyproject_install %python_expand %fdupes %{buildroot}%{$python_sitelib} %check @@ -57,6 +57,7 @@ %files %{python_files} %doc README.md %license LICENSE -%{python_sitelib}/* +%{python_sitelib}/flask_socketio +%{python_sitelib}/Flask_SocketIO-%{version}*-info %changelog ++++++ Flask-SocketIO-5.1.1.tar.gz -> Flask-SocketIO-5.3.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-SocketIO-5.1.1/PKG-INFO new/Flask-SocketIO-5.3.4/PKG-INFO --- old/Flask-SocketIO-5.1.1/PKG-INFO 2021-08-02 01:17:34.347939500 +0200 +++ new/Flask-SocketIO-5.3.4/PKG-INFO 2023-05-03 12:34:08.560571200 +0200 @@ -1,13 +1,11 @@ Metadata-Version: 2.1 Name: Flask-SocketIO -Version: 5.1.1 +Version: 5.3.4 Summary: Socket.IO integration for Flask applications Home-page: https://github.com/miguelgrinberg/flask-socketio Author: Miguel Grinberg Author-email: miguel.grinb...@gmail.com -License: UNKNOWN Project-URL: Bug Tracker, https://github.com/miguelgrinberg/flask-socketio/issues -Platform: UNKNOWN Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python :: 3 @@ -73,5 +71,3 @@ - [Change Log](https://github.com/miguelgrinberg/Flask-SocketIO/blob/main/CHANGES.md) - Questions? See the [questions](https://stackoverflow.com/questions/tagged/flask-socketio) others have asked on Stack Overflow, or [ask](https://stackoverflow.com/questions/ask?tags=python+flask-socketio+python-socketio) your own question. - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-SocketIO-5.1.1/setup.cfg new/Flask-SocketIO-5.3.4/setup.cfg --- old/Flask-SocketIO-5.1.1/setup.cfg 2021-08-02 01:17:34.348511000 +0200 +++ new/Flask-SocketIO-5.3.4/setup.cfg 2023-05-03 12:34:08.561552300 +0200 @@ -1,6 +1,6 @@ [metadata] name = Flask-SocketIO -version = 5.1.1 +version = 5.3.4 author = Miguel Grinberg author_email = miguel.grinb...@gmail.com description = Socket.IO integration for Flask applications diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-SocketIO-5.1.1/src/Flask_SocketIO.egg-info/PKG-INFO new/Flask-SocketIO-5.3.4/src/Flask_SocketIO.egg-info/PKG-INFO --- old/Flask-SocketIO-5.1.1/src/Flask_SocketIO.egg-info/PKG-INFO 2021-08-02 01:17:34.000000000 +0200 +++ new/Flask-SocketIO-5.3.4/src/Flask_SocketIO.egg-info/PKG-INFO 2023-05-03 12:34:08.000000000 +0200 @@ -1,13 +1,11 @@ Metadata-Version: 2.1 Name: Flask-SocketIO -Version: 5.1.1 +Version: 5.3.4 Summary: Socket.IO integration for Flask applications Home-page: https://github.com/miguelgrinberg/flask-socketio Author: Miguel Grinberg Author-email: miguel.grinb...@gmail.com -License: UNKNOWN Project-URL: Bug Tracker, https://github.com/miguelgrinberg/flask-socketio/issues -Platform: UNKNOWN Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python :: 3 @@ -73,5 +71,3 @@ - [Change Log](https://github.com/miguelgrinberg/Flask-SocketIO/blob/main/CHANGES.md) - Questions? See the [questions](https://stackoverflow.com/questions/tagged/flask-socketio) others have asked on Stack Overflow, or [ask](https://stackoverflow.com/questions/ask?tags=python+flask-socketio+python-socketio) your own question. - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-SocketIO-5.1.1/src/flask_socketio/__init__.py new/Flask-SocketIO-5.3.4/src/flask_socketio/__init__.py --- old/Flask-SocketIO-5.1.1/src/flask_socketio/__init__.py 2021-07-18 18:30:40.000000000 +0200 +++ new/Flask-SocketIO-5.3.4/src/flask_socketio/__init__.py 2023-03-21 20:59:26.000000000 +0100 @@ -16,7 +16,7 @@ sys.exit(1) import flask -from flask import _request_ctx_stack, has_request_context, json as flask_json +from flask import has_request_context, json as flask_json from flask.sessions import SessionMixin import socketio from socketio.exceptions import ConnectionRefusedError # noqa: F401 @@ -197,8 +197,8 @@ self.manage_session = self.server_options.pop('manage_session', self.manage_session) - if 'client_manager' not in self.server_options: - url = self.server_options.pop('message_queue', None) + if 'client_manager' not in kwargs: + url = self.server_options.get('message_queue', None) channel = self.server_options.pop('channel', 'flask-socketio') write_only = app is None if url: @@ -248,7 +248,7 @@ self.server.register_namespace(namespace_handler) if app is not None: - # here we attach the SocketIO middlware to the SocketIO object so + # here we attach the SocketIO middleware to the SocketIO object so # it can be referenced later if debug middleware needs to be # inserted self.sockio_mw = _SocketIOMiddleware(self.server, app, @@ -416,9 +416,9 @@ :param args: A dictionary with the JSON data to send as payload. :param namespace: The namespace under which the message is to be sent. Defaults to the global namespace. - :param to: Send the message to all the users in the given room. If - this parameter is not included, the event is sent to all - connected users. + :param to: Send the message to all the users in the given room, or to + the user with the given session ID. If this parameter is not + included, the event is sent to all connected users. :param include_self: ``True`` to include the sender when broadcasting or addressing a room, or ``False`` to send to everyone but the sender. @@ -434,7 +434,7 @@ only be used when addressing an individual client. """ namespace = kwargs.pop('namespace', '/') - to = kwargs.pop('to', kwargs.pop('room', None)) + to = kwargs.pop('to', None) or kwargs.pop('room', None) include_self = kwargs.pop('include_self', True) skip_sid = kwargs.pop('skip_sid', None) if not include_self and not skip_sid: @@ -443,13 +443,15 @@ if callback: # wrap the callback so that it sets app app and request contexts sid = None + original_callback = callback + original_namespace = namespace if has_request_context(): sid = getattr(flask.request, 'sid', None) - original_callback = callback + original_namespace = getattr(flask.request, 'namespace', None) def _callback_wrapper(*args): - return self._handle_event(original_callback, None, namespace, - sid, *args) + return self._handle_event(original_callback, None, + original_namespace, sid, *args) if sid: # the callback wrapper above will install a request context @@ -460,6 +462,41 @@ self.server.emit(event, *args, namespace=namespace, to=to, skip_sid=skip_sid, callback=callback, **kwargs) + def call(self, event, *args, **kwargs): # pragma: no cover + """Emit a SocketIO event and wait for the response. + + This method issues an emit with a callback and waits for the callback + to be invoked by the client 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. Example:: + + def get_status(client, data): + status = call('status', {'data': data}, to=client) + + :param event: The name of the user event to emit. + :param args: A dictionary with the JSON data to send as payload. + :param namespace: The namespace under which the message is to be sent. + Defaults to the global namespace. + :param to: The session ID of the recipient client. + :param timeout: The waiting timeout. If the timeout is reached before + the client acknowledges the event, then a + ``TimeoutError`` exception is raised. The default is 60 + seconds. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + client directly, without going through the queue. + This is more efficient, but only works when a + single server process is used, or when there is a + single addressee. It is recommended to always + leave this parameter with its default value of + ``False``. + """ + namespace = kwargs.pop('namespace', '/') + to = kwargs.pop('to', None) or kwargs.pop('room', None) + return self.server.call(event, *args, namespace=namespace, to=to, + **kwargs) + def send(self, data, json=False, namespace=None, to=None, callback=None, include_self=True, skip_sid=None, **kwargs): """Send a server-generated SocketIO message. @@ -475,9 +512,9 @@ otherwise. :param namespace: The namespace under which the message is to be sent. Defaults to the global namespace. - :param to: Send the message only to the users in the given room. If - this parameter is not included, the message is sent to all - connected users. + :param to: Send the message to all the users in the given room, or to + the user with the given session ID. If this parameter is not + included, the event is sent to all connected users. :param include_self: ``True`` to include the sender when broadcasting or addressing a room, or ``False`` to send to everyone but the sender. @@ -536,6 +573,10 @@ Defaults to ``True`` in debug mode, ``False`` in normal mode. Unused when the threading async mode is used. + :param allow_unsafe_werkzeug: Set to ``True`` to allow the use of the + Werkzeug web server in a production + setting. Default is ``False``. Set to + ``True`` at your own risk. :param kwargs: Additional web server options. The web server options are specific to the server used in each of the supported async modes. Note that options provided here will @@ -593,6 +634,20 @@ from werkzeug._internal import _log _log('warning', 'WebSocket transport not available. Install ' 'simple-websocket for improved performance.') + allow_unsafe_werkzeug = kwargs.pop('allow_unsafe_werkzeug', + False) + if not sys.stdin or not sys.stdin.isatty(): # pragma: no cover + if not allow_unsafe_werkzeug: + raise RuntimeError('The Werkzeug web server is not ' + 'designed to run in production. Pass ' + 'allow_unsafe_werkzeug=True to the ' + 'run() method to disable this error.') + else: + from werkzeug._internal import _log + _log('warning', ('Werkzeug appears to be used in a ' + 'production deployment. Consider ' + 'switching to a production web server ' + 'instead.')) app.run(host=host, port=port, threaded=True, use_reloader=use_reloader, **reloader_options, **kwargs) elif self.server.eio.async_mode == 'eventlet': @@ -690,9 +745,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()`` method can be invoked to wait for the task to + complete. """ return self.server.start_background_task(target, *args, **kwargs) @@ -744,6 +799,14 @@ if 'saved_session' not in environ: environ['saved_session'] = _ManagedSession(flask.session) session_obj = environ['saved_session'] + if hasattr(flask, 'globals') and \ + hasattr(flask.globals, 'request_ctx'): + # update session for Flask >= 2.2 + ctx = flask.globals.request_ctx._get_current_object() + else: # pragma: no cover + # update session for Flask < 2.2 + ctx = flask._request_ctx_stack.top + ctx.session = session_obj else: # let Flask handle the user session # for cookie based sessions, this effectively freezes the @@ -751,7 +814,6 @@ # for server-side sessions, this allows HTTP and Socket.IO to # share the session, with both having read/write access to it session_obj = flask.session._get_current_object() - _request_ctx_stack.top.session = session_obj flask.request.sid = sid flask.request.namespace = namespace flask.request.event = {'message': message, 'args': args} @@ -764,6 +826,8 @@ ret = handler() else: ret = handler(*args) + except ConnectionRefusedError: + raise # let this error bubble up to python-socketio except: err_handler = self.exception_handlers.get( namespace, self.default_exception_handler) @@ -802,9 +866,10 @@ acknowledgement. :param broadcast: ``True`` to send the message to all clients, or ``False`` to only reply to the sender of the originating event. - :param to: Send the message to all the users in the given room. If this - argument is not set and ``broadcast`` is ``False``, then the - message is sent only to the originating user. + :param to: Send the message to all the users in the given room, or to the + user with the given session ID. If this argument is not set and + ``broadcast`` is ``False``, then the message is sent only to the + originating user. :param include_self: ``True`` to include the sender when broadcasting or addressing a room, or ``False`` to send to everyone but the sender. @@ -827,7 +892,7 @@ namespace = flask.request.namespace callback = kwargs.get('callback') broadcast = kwargs.get('broadcast') - to = kwargs.pop('to', kwargs.pop('room', None)) + to = kwargs.pop('to', None) or kwargs.pop('room', None) if to is None and not broadcast: to = flask.request.sid include_self = kwargs.get('include_self', True) @@ -840,6 +905,52 @@ callback=callback, ignore_queue=ignore_queue) +def call(event, *args, **kwargs): # pragma: no cover + """Emit a SocketIO event and wait for the response. + + This function issues an emit with a callback and waits for the callback to + be invoked by the client 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. Example:: + + def get_status(client, data): + status = call('status', {'data': data}, to=client) + + :param event: The name of the user event to emit. + :param args: A dictionary with the JSON data to send as payload. + :param namespace: The namespace under which the message is to be sent. + Defaults to the namespace used by the originating event. + A ``'/'`` can be used to explicitly specify the global + namespace. + :param to: The session ID of the recipient client. If this argument is not + given, the event is sent to the originating client. + :param timeout: The waiting timeout. If the timeout is reached before the + client acknowledges the event, then a ``TimeoutError`` + exception is raised. The default is 60 seconds. + :param ignore_queue: Only used when a message queue is configured. If + set to ``True``, the event is emitted to the + client directly, without going through the queue. + This is more efficient, but only works when a + single server process is used, or when there is a + single addressee. It is recommended to always leave + this parameter with its default value of ``False``. + """ + if 'namespace' in kwargs: + namespace = kwargs['namespace'] + else: + namespace = flask.request.namespace + to = kwargs.pop('to', None) or kwargs.pop('room', None) + if to is None: + to = flask.request.sid + timeout = kwargs.get('timeout', 60) + ignore_queue = kwargs.get('ignore_queue', False) + + socketio = flask.current_app.extensions['socketio'] + return socketio.call(event, *args, namespace=namespace, to=to, + ignore_queue=ignore_queue, timeout=timeout) + + def send(message, **kwargs): """Send a SocketIO message. @@ -859,9 +970,10 @@ :param broadcast: ``True`` to send the message to all connected clients, or ``False`` to only reply to the sender of the originating event. - :param to: Send the message to all the users in the given room. If this - argument is not set and ``broadcast`` is ``False``, then the - message is sent only to the originating user. + :param to: Send the message to all the users in the given room, or to the + user with the given session ID. If this argument is not set and + ``broadcast`` is ``False``, then the message is sent only to the + originating user. :param include_self: ``True`` to include the sender when broadcasting or addressing a room, or ``False`` to send to everyone but the sender. @@ -885,7 +997,7 @@ namespace = flask.request.namespace callback = kwargs.get('callback') broadcast = kwargs.get('broadcast') - to = kwargs.pop('to', kwargs.pop('room', None)) + to = kwargs.pop('to', None) or kwargs.pop('room', None) if to is None and not broadcast: to = flask.request.sid include_self = kwargs.get('include_self', True) @@ -910,7 +1022,7 @@ username = session['username'] room = data['room'] join_room(room) - send(username + ' has entered the room.', room=room) + send(username + ' has entered the room.', to=room) :param room: The name of the room to join. :param sid: The session id of the client. If not provided, the client is @@ -935,7 +1047,7 @@ username = session['username'] room = data['room'] leave_room(room) - send(username + ' has left the room.', room=room) + send(username + ' has left the room.', to=room) :param room: The name of the room to leave. :param sid: The session id of the client. If not provided, the client is diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Flask-SocketIO-5.1.1/src/flask_socketio/test_client.py new/Flask-SocketIO-5.3.4/src/flask_socketio/test_client.py --- old/Flask-SocketIO-5.1.1/src/flask_socketio/test_client.py 2021-06-13 17:46:50.000000000 +0200 +++ new/Flask-SocketIO-5.3.4/src/flask_socketio/test_client.py 2023-05-03 12:28:48.000000000 +0200 @@ -24,8 +24,7 @@ cookies set in HTTP routes accessible from Socket.IO events. """ - queue = {} - acks = {} + clients = {} def __init__(self, app, socketio, namespace=None, query_string=None, headers=None, auth=None, flask_test_client=None): @@ -38,35 +37,37 @@ pkt = packet.Packet(encoded_packet=epkt[0]) for att in epkt[1:]: pkt.add_attachment(att) + client = self.clients.get(eio_sid) + if not client: + return if pkt.packet_type == packet.EVENT or \ pkt.packet_type == packet.BINARY_EVENT: - if eio_sid not in self.queue: - self.queue[eio_sid] = [] if pkt.data[0] == 'message' or pkt.data[0] == 'json': - self.queue[eio_sid].append({ + client.queue.append({ 'name': pkt.data[0], 'args': pkt.data[1], 'namespace': pkt.namespace or '/'}) else: - self.queue[eio_sid].append({ + client.queue.append({ 'name': pkt.data[0], 'args': pkt.data[1:], 'namespace': pkt.namespace or '/'}) elif pkt.packet_type == packet.ACK or \ pkt.packet_type == packet.BINARY_ACK: - self.acks[eio_sid] = {'args': pkt.data, - 'namespace': pkt.namespace or '/'} + client.acks = {'args': pkt.data, + 'namespace': pkt.namespace or '/'} elif pkt.packet_type in [packet.DISCONNECT, packet.CONNECT_ERROR]: - self.connected[pkt.namespace or '/'] = False + client.connected[pkt.namespace or '/'] = False self.app = app self.flask_test_client = flask_test_client self.eio_sid = uuid.uuid4().hex - self.acks[self.eio_sid] = None - self.queue[self.eio_sid] = [] + self.clients[self.eio_sid] = self self.callback_counter = 0 self.socketio = socketio self.connected = {} + self.queue = [] + self.acks = None socketio.server._send_packet = _mock_send_packet socketio.server.environ[self.eio_sid] = {} socketio.server.async_handlers = False # easier to test when @@ -113,12 +114,15 @@ environ['flask.app'] = self.app if self.flask_test_client: # inject cookies from Flask - self.flask_test_client.cookie_jar.inject_wsgi(environ) + if hasattr(self.flask_test_client, '_add_cookies_to_wsgi'): + # flask >= 2.3 + self.flask_test_client._add_cookies_to_wsgi(environ) + else: # pragma: no cover + # flask < 2.3 + self.flask_test_client.cookie_jar.inject_wsgi(environ) self.socketio.server._handle_eio_connect(self.eio_sid, environ) pkt = packet.Packet(packet.CONNECT, auth, namespace=namespace) - with self.app.app_context(): - self.socketio.server._handle_eio_message(self.eio_sid, - pkt.encode()) + self.socketio.server._handle_eio_message(self.eio_sid, pkt.encode()) sid = self.socketio.server.manager.sid_from_eio_sid(self.eio_sid, namespace) if sid: @@ -133,9 +137,7 @@ if not self.is_connected(namespace): raise RuntimeError('not connected') pkt = packet.Packet(packet.DISCONNECT, namespace=namespace) - with self.app.app_context(): - self.socketio.server._handle_eio_message(self.eio_sid, - pkt.encode()) + self.socketio.server._handle_eio_message(self.eio_sid, pkt.encode()) del self.connected[namespace or '/'] def emit(self, event, *args, **kwargs): @@ -163,17 +165,15 @@ id = self.callback_counter pkt = packet.Packet(packet.EVENT, data=[event] + list(args), namespace=namespace, id=id) - with self.app.app_context(): - encoded_pkt = pkt.encode() - if isinstance(encoded_pkt, list): - for epkt in encoded_pkt: - self.socketio.server._handle_eio_message(self.eio_sid, - epkt) - else: - self.socketio.server._handle_eio_message(self.eio_sid, - encoded_pkt) - ack = self.acks.pop(self.eio_sid, None) - if ack is not None: + encoded_pkt = pkt.encode() + if isinstance(encoded_pkt, list): + for epkt in encoded_pkt: + self.socketio.server._handle_eio_message(self.eio_sid, epkt) + else: + self.socketio.server._handle_eio_message(self.eio_sid, encoded_pkt) + if self.acks is not None: + ack = self.acks + self.acks = None return ack['args'][0] if len(ack['args']) == 1 \ else ack['args'] @@ -213,8 +213,6 @@ if not self.is_connected(namespace): raise RuntimeError('not connected') namespace = namespace or '/' - r = [pkt for pkt in self.queue[self.eio_sid] - if pkt['namespace'] == namespace] - self.queue[self.eio_sid] = [ - pkt for pkt in self.queue[self.eio_sid] if pkt not in r] + r = [pkt for pkt in self.queue if pkt['namespace'] == namespace] + self.queue = [pkt for pkt in self.queue if pkt not in r] return r ++++++ test_socketio.py ++++++ --- /var/tmp/diff_new_pack.p8vss1/_old 2023-06-22 23:26:32.021986196 +0200 +++ /var/tmp/diff_new_pack.p8vss1/_new 2023-06-22 23:26:32.021986196 +0200 @@ -3,7 +3,7 @@ from flask import Flask, session, request, json as flask_json from flask_socketio import SocketIO, send, emit, join_room, leave_room, \ - Namespace, disconnect + Namespace, disconnect, ConnectionRefusedError app = Flask(__name__) app.config['SECRET_KEY'] = 'secret' @@ -16,11 +16,12 @@ if auth != {'foo': 'bar'}: # pragma: no cover return False if request.args.get('fail'): - return False + raise ConnectionRefusedError('failed!') send('connected') send(json.dumps(request.args.to_dict(flat=False))) send(json.dumps({h: request.headers[h] for h in request.headers.keys() if h not in ['Host', 'Content-Type', 'Content-Length']})) + emit('dummy', to='nobody') @socketio.on('disconnect') @@ -47,7 +48,12 @@ def message(message): send(message) if message == 'test session': - session['a'] = 'b' + if not socketio.manage_session and 'a' in session: + raise RuntimeError('session is being stored') + if 'a' not in session: + session['a'] = 'b' + else: + session['a'] = 'c' if message not in "test noackargs": return message @@ -345,6 +351,25 @@ client.disconnect('/test') self.assertEqual(disconnected, '/test') + def test_message_queue_options(self): + app = Flask(__name__) + socketio = SocketIO(app, message_queue='redis://') + self.assertFalse(socketio.server_options['client_manager'].write_only) + + app = Flask(__name__) + socketio = SocketIO(app) + socketio.init_app(app, message_queue='redis://') + self.assertFalse(socketio.server_options['client_manager'].write_only) + + app = Flask(__name__) + socketio = SocketIO(message_queue='redis://') + self.assertTrue(socketio.server_options['client_manager'].write_only) + + app = Flask(__name__) + socketio = SocketIO() + socketio.init_app(None, message_queue='redis://') + self.assertTrue(socketio.server_options['client_manager'].write_only) + def test_send(self): client = socketio.test_client(app, auth={'foo': 'bar'}) client.get_received() @@ -454,7 +479,7 @@ self.assertEqual(received[0]['args'][0]['a'], 'b') self.assertEqual(len(client3.get_received()), 0) - def test_session(self): + def test_managed_session(self): flask_client = app.test_client() flask_client.get('/session') client = socketio.test_client(app, flask_test_client=flask_client, @@ -468,6 +493,21 @@ self.assertEqual( socketio.server.environ[client.eio_sid]['saved_session'], {'a': 'b', 'foo': 'bar'}) + client.send('test session') + self.assertEqual( + socketio.server.environ[client.eio_sid]['saved_session'], + {'a': 'c', 'foo': 'bar'}) + + def test_unmanaged_session(self): + socketio.manage_session = False + flask_client = app.test_client() + flask_client.get('/session') + client = socketio.test_client(app, flask_test_client=flask_client, + auth={'foo': 'bar'}) + client.get_received() + client.send('test session') + client.send('test session') + socketio.manage_session = True def test_room(self): client1 = socketio.test_client(app, auth={'foo': 'bar'}) @@ -647,11 +687,18 @@ def test_server_disconnected(self): client = socketio.test_client(app, namespace='/ns') + client2 = socketio.test_client(app, namespace='/ns') client.get_received('/ns') + client2.get_received('/ns') client.emit('exit', {}, namespace='/ns') self.assertFalse(client.is_connected('/ns')) + self.assertTrue(client2.is_connected('/ns')) with self.assertRaises(RuntimeError): client.emit('hello', {}, namespace='/ns') + client2.emit('exit', {}, namespace='/ns') + self.assertFalse(client2.is_connected('/ns')) + with self.assertRaises(RuntimeError): + client2.emit('hello', {}, namespace='/ns') def test_emit_class_based(self): client = socketio.test_client(app, namespace='/ns')