From 03c711b41876792e834e283259ca8bc52a325ebc Mon Sep 17 00:00:00 2001 From: Placeless Date: Wed, 27 Dec 2023 19:31:49 +0900 Subject: [PATCH] fix and format by ruff --- docs/conf.py | 72 +- examples/client/async/fiddle_client.py | 8 +- examples/client/async/latency_client.py | 10 +- examples/client/sync/fiddle_client.py | 8 +- examples/client/sync/latency_client.py | 10 +- examples/server/aiohttp/app.py | 47 +- examples/server/aiohttp/fiddle.py | 18 +- examples/server/aiohttp/latency.py | 14 +- examples/server/asgi/app.py | 83 +- examples/server/asgi/fastapi-fiddle.py | 22 +- examples/server/asgi/fiddle.py | 23 +- examples/server/asgi/latency.py | 19 +- examples/server/asgi/litestar-fiddle.py | 26 +- examples/server/sanic/app.py | 49 +- examples/server/sanic/fiddle.py | 16 +- examples/server/sanic/latency.py | 13 +- examples/server/tornado/app.py | 37 +- examples/server/tornado/fiddle.py | 8 +- examples/server/tornado/latency.py | 4 +- examples/server/wsgi/app.py | 85 +- .../django_socketio/django_socketio/asgi.py | 2 +- .../django_socketio/settings.py | 74 +- .../django_socketio/django_socketio/urls.py | 4 +- .../django_socketio/django_socketio/wsgi.py | 2 +- .../server/wsgi/django_socketio/manage.py | 4 +- .../django_socketio/socketio_app/admin.py | 2 - .../wsgi/django_socketio/socketio_app/apps.py | 4 +- .../django_socketio/socketio_app/models.py | 2 - .../django_socketio/socketio_app/tests.py | 2 - .../wsgi/django_socketio/socketio_app/urls.py | 2 +- .../django_socketio/socketio_app/views.py | 35 +- examples/server/wsgi/fiddle.py | 42 +- examples/server/wsgi/latency.py | 38 +- examples/simple-client/async/fiddle_client.py | 4 +- .../simple-client/async/latency_client.py | 10 +- examples/simple-client/sync/fiddle_client.py | 4 +- examples/simple-client/sync/latency_client.py | 10 +- src/socketio/__init__.py | 32 +- src/socketio/admin.py | 400 ++++---- src/socketio/asgi.py | 25 +- src/socketio/async_admin.py | 399 ++++---- src/socketio/async_aiopika_manager.py | 52 +- src/socketio/async_client.py | 186 ++-- src/socketio/async_manager.py | 30 +- src/socketio/async_namespace.py | 125 ++- src/socketio/async_pubsub_manager.py | 210 ++-- src/socketio/async_redis_manager.py | 54 +- src/socketio/async_server.py | 306 +++--- src/socketio/async_simple_client.py | 48 +- src/socketio/base_client.py | 69 +- src/socketio/base_manager.py | 18 +- src/socketio/base_namespace.py | 2 +- src/socketio/base_server.py | 59 +- src/socketio/client.py | 178 ++-- src/socketio/exceptions.py | 11 +- src/socketio/kafka_manager.py | 28 +- src/socketio/kombu_manager.py | 69 +- src/socketio/manager.py | 20 +- src/socketio/middleware.py | 18 +- src/socketio/msgpack_packet.py | 8 +- src/socketio/namespace.py | 120 ++- src/socketio/packet.py | 124 ++- src/socketio/pubsub_manager.py | 192 ++-- src/socketio/redis_manager.py | 63 +- src/socketio/server.py | 273 ++++-- src/socketio/simple_client.py | 42 +- src/socketio/tornado.py | 6 +- src/socketio/zmq_manager.py | 58 +- tests/async/test_admin.py | 263 ++--- tests/async/test_client.py | 688 +++++++------- tests/async/test_manager.py | 450 ++++----- tests/async/test_namespace.py | 296 +++--- tests/async/test_pubsub_manager.py | 555 ++++++----- tests/async/test_server.py | 899 +++++++++--------- tests/async/test_simple_client.py | 132 +-- tests/asyncio_web_server.py | 20 +- tests/common/test_admin.py | 247 ++--- tests/common/test_client.py | 798 ++++++++-------- tests/common/test_manager.py | 391 ++++---- tests/common/test_middleware.py | 18 +- tests/common/test_msgpack_packet.py | 14 +- tests/common/test_namespace.py | 263 +++-- tests/common/test_packet.py | 162 ++-- tests/common/test_pubsub_manager.py | 539 ++++++----- tests/common/test_server.py | 867 +++++++++-------- tests/common/test_simple_client.py | 124 ++- tests/performance/binary_packet.py | 6 +- tests/performance/json_packet.py | 6 +- tests/performance/namespace_packet.py | 6 +- tests/performance/server_receive.py | 10 +- tests/performance/server_send.py | 10 +- tests/performance/server_send_broadcast.py | 10 +- tests/performance/text_packet.py | 6 +- tests/web_server.py | 21 +- 94 files changed, 5776 insertions(+), 5063 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index b5d242b..f7c2f5b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,14 +19,14 @@ # -- Project information ----------------------------------------------------- -project = 'python-socketio' -copyright = '2018, Miguel Grinberg' -author = 'Miguel Grinberg' +project = "python-socketio" +copyright = "2018, Miguel Grinberg" +author = "Miguel Grinberg" # The short X.Y version -version = '' +version = "" # The full version, including alpha/beta/rc tags -release = '' +release = "" # -- General configuration --------------------------------------------------- @@ -39,34 +39,34 @@ release = '' # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', + "sphinx.ext.autodoc", ] -autodoc_member_order = 'alphabetical' +autodoc_member_order = "alphabetical" # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'en' +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None @@ -77,26 +77,25 @@ pygments_style = None # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = "alabaster" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = { - 'github_user': 'miguelgrinberg', - 'github_repo': 'python-socketio', - 'github_banner': True, - 'github_button': True, - 'github_type': 'star', - 'fixed_sidebar': True, - + "github_user": "miguelgrinberg", + "github_repo": "python-socketio", + "github_banner": True, + "github_button": True, + "github_type": "star", + "fixed_sidebar": True, } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -112,7 +111,7 @@ html_static_path = ['_static'] # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'python-socketiodoc' +htmlhelp_basename = "python-socketiodoc" # -- Options for LaTeX output ------------------------------------------------ @@ -121,15 +120,12 @@ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -139,8 +135,13 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'python-socketio.tex', 'python-socketio Documentation', - 'Miguel Grinberg', 'manual'), + ( + master_doc, + "python-socketio.tex", + "python-socketio Documentation", + "Miguel Grinberg", + "manual", + ), ] @@ -149,8 +150,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'python-socketio', 'python-socketio Documentation', - [author], 1) + (master_doc, "python-socketio", "python-socketio Documentation", [author], 1) ] @@ -160,9 +160,15 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'python-socketio', 'python-socketio Documentation', - author, 'python-socketio', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "python-socketio", + "python-socketio Documentation", + author, + "python-socketio", + "One line description of project.", + "Miscellaneous", + ), ] @@ -181,7 +187,7 @@ epub_title = project # epub_uid = '' # A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] +epub_exclude_files = ["search.html"] # -- Extension configuration ------------------------------------------------- diff --git a/examples/client/async/fiddle_client.py b/examples/client/async/fiddle_client.py index 5b43dcc..0659445 100644 --- a/examples/client/async/fiddle_client.py +++ b/examples/client/async/fiddle_client.py @@ -6,12 +6,12 @@ sio = socketio.AsyncClient() @sio.event async def connect(): - print('connected to server') + print("connected to server") @sio.event async def disconnect(): - print('disconnected from server') + print("disconnected from server") @sio.event @@ -20,9 +20,9 @@ def hello(a, b, c): async def start_server(): - await sio.connect('http://localhost:5000', auth={'token': 'my-token'}) + await sio.connect("http://localhost:5000", auth={"token": "my-token"}) await sio.wait() -if __name__ == '__main__': +if __name__ == "__main__": asyncio.run(start_server()) diff --git a/examples/client/async/latency_client.py b/examples/client/async/latency_client.py index 00d2539..860ba3c 100644 --- a/examples/client/async/latency_client.py +++ b/examples/client/async/latency_client.py @@ -10,12 +10,12 @@ start_timer = None async def send_ping(): global start_timer start_timer = time.time() - await sio.emit('ping_from_client') + await sio.emit("ping_from_client") @sio.event async def connect(): - print('connected to server') + print("connected to server") await send_ping() @@ -23,16 +23,16 @@ async def connect(): async def pong_from_server(): global start_timer latency = time.time() - start_timer - print('latency is {0:.2f} ms'.format(latency * 1000)) + print("latency is {0:.2f} ms".format(latency * 1000)) await sio.sleep(1) if sio.connected: await send_ping() async def start_server(): - await sio.connect('http://localhost:5000') + await sio.connect("http://localhost:5000") await sio.wait() -if __name__ == '__main__': +if __name__ == "__main__": loop.run_until_complete(start_server()) diff --git a/examples/client/sync/fiddle_client.py b/examples/client/sync/fiddle_client.py index 50f5e2a..8adb1a1 100644 --- a/examples/client/sync/fiddle_client.py +++ b/examples/client/sync/fiddle_client.py @@ -5,12 +5,12 @@ sio = socketio.Client() @sio.event def connect(): - print('connected to server') + print("connected to server") @sio.event def disconnect(): - print('disconnected from server') + print("disconnected from server") @sio.event @@ -18,6 +18,6 @@ def hello(a, b, c): print(a, b, c) -if __name__ == '__main__': - sio.connect('http://localhost:5000', auth={'token': 'my-token'}) +if __name__ == "__main__": + sio.connect("http://localhost:5000", auth={"token": "my-token"}) sio.wait() diff --git a/examples/client/sync/latency_client.py b/examples/client/sync/latency_client.py index 0328d10..e00726c 100644 --- a/examples/client/sync/latency_client.py +++ b/examples/client/sync/latency_client.py @@ -8,12 +8,12 @@ start_timer = None def send_ping(): global start_timer start_timer = time.time() - sio.emit('ping_from_client') + sio.emit("ping_from_client") @sio.event def connect(): - print('connected to server') + print("connected to server") send_ping() @@ -21,12 +21,12 @@ def connect(): def pong_from_server(): global start_timer latency = time.time() - start_timer - print('latency is {0:.2f} ms'.format(latency * 1000)) + print("latency is {0:.2f} ms".format(latency * 1000)) sio.sleep(1) if sio.connected: send_ping() -if __name__ == '__main__': - sio.connect('http://localhost:5000') +if __name__ == "__main__": + sio.connect("http://localhost:5000") sio.wait() diff --git a/examples/server/aiohttp/app.py b/examples/server/aiohttp/app.py index cba5193..0817307 100644 --- a/examples/server/aiohttp/app.py +++ b/examples/server/aiohttp/app.py @@ -2,7 +2,7 @@ from aiohttp import web import socketio -sio = socketio.AsyncServer(async_mode='aiohttp') +sio = socketio.AsyncServer(async_mode="aiohttp") app = web.Application() sio.attach(app) @@ -13,50 +13,51 @@ async def background_task(): while True: await sio.sleep(10) count += 1 - await sio.emit('my_response', {'data': 'Server generated event'}) + await sio.emit("my_response", {"data": "Server generated event"}) async def index(request): - with open('app.html') as f: - return web.Response(text=f.read(), content_type='text/html') + with open("app.html") as f: + return web.Response(text=f.read(), content_type="text/html") @sio.event async def my_event(sid, message): - await sio.emit('my_response', {'data': message['data']}, room=sid) + await sio.emit("my_response", {"data": message["data"]}, room=sid) @sio.event async def my_broadcast_event(sid, message): - await sio.emit('my_response', {'data': message['data']}) + await sio.emit("my_response", {"data": message["data"]}) @sio.event async def join(sid, message): - await sio.enter_room(sid, message['room']) - await sio.emit('my_response', {'data': 'Entered room: ' + message['room']}, - room=sid) + await sio.enter_room(sid, message["room"]) + await sio.emit( + "my_response", {"data": "Entered room: " + message["room"]}, room=sid + ) @sio.event async def leave(sid, message): - await sio.leave_room(sid, message['room']) - await sio.emit('my_response', {'data': 'Left room: ' + message['room']}, - room=sid) + await sio.leave_room(sid, message["room"]) + await sio.emit("my_response", {"data": "Left room: " + message["room"]}, room=sid) @sio.event async def close_room(sid, message): - await sio.emit('my_response', - {'data': 'Room ' + message['room'] + ' is closing.'}, - room=message['room']) - await sio.close_room(message['room']) + await sio.emit( + "my_response", + {"data": "Room " + message["room"] + " is closing."}, + room=message["room"], + ) + await sio.close_room(message["room"]) @sio.event async def my_room_event(sid, message): - await sio.emit('my_response', {'data': message['data']}, - room=message['room']) + await sio.emit("my_response", {"data": message["data"]}, room=message["room"]) @sio.event @@ -66,16 +67,16 @@ async def disconnect_request(sid): @sio.event async def connect(sid, environ): - await sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) + await sio.emit("my_response", {"data": "Connected", "count": 0}, room=sid) @sio.event def disconnect(sid): - print('Client disconnected') + print("Client disconnected") -app.router.add_static('/static', 'static') -app.router.add_get('/', index) +app.router.add_static("/static", "static") +app.router.add_get("/", index) async def init_app(): @@ -83,5 +84,5 @@ async def init_app(): return app -if __name__ == '__main__': +if __name__ == "__main__": web.run_app(init_app()) diff --git a/examples/server/aiohttp/fiddle.py b/examples/server/aiohttp/fiddle.py index dfde8e1..93c835b 100644 --- a/examples/server/aiohttp/fiddle.py +++ b/examples/server/aiohttp/fiddle.py @@ -2,30 +2,30 @@ from aiohttp import web import socketio -sio = socketio.AsyncServer(async_mode='aiohttp') +sio = socketio.AsyncServer(async_mode="aiohttp") app = web.Application() sio.attach(app) async def index(request): - with open('fiddle.html') as f: - return web.Response(text=f.read(), content_type='text/html') + with open("fiddle.html") as f: + return web.Response(text=f.read(), content_type="text/html") @sio.event async def connect(sid, environ, auth): - print(f'connected auth={auth} sid={sid}') - await sio.emit('hello', (1, 2, {'hello': 'you'}), to=sid) + print(f"connected auth={auth} sid={sid}") + await sio.emit("hello", (1, 2, {"hello": "you"}), to=sid) @sio.event def disconnect(sid): - print('disconnected', sid) + print("disconnected", sid) -app.router.add_static('/static', 'static') -app.router.add_get('/', index) +app.router.add_static("/static", "static") +app.router.add_get("/", index) -if __name__ == '__main__': +if __name__ == "__main__": web.run_app(app) diff --git a/examples/server/aiohttp/latency.py b/examples/server/aiohttp/latency.py index 7e1f03c..ea11f0c 100644 --- a/examples/server/aiohttp/latency.py +++ b/examples/server/aiohttp/latency.py @@ -2,24 +2,24 @@ from aiohttp import web import socketio -sio = socketio.AsyncServer(async_mode='aiohttp') +sio = socketio.AsyncServer(async_mode="aiohttp") app = web.Application() sio.attach(app) async def index(request): - with open('latency.html') as f: - return web.Response(text=f.read(), content_type='text/html') + with open("latency.html") as f: + return web.Response(text=f.read(), content_type="text/html") @sio.event async def ping_from_client(sid): - await sio.emit('pong_from_server', room=sid) + await sio.emit("pong_from_server", room=sid) -app.router.add_static('/static', 'static') -app.router.add_get('/', index) +app.router.add_static("/static", "static") +app.router.add_get("/", index) -if __name__ == '__main__': +if __name__ == "__main__": web.run_app(app) diff --git a/examples/server/asgi/app.py b/examples/server/asgi/app.py index 36af85f..1947746 100644 --- a/examples/server/asgi/app.py +++ b/examples/server/asgi/app.py @@ -4,25 +4,31 @@ # Admin UI hosted at https://admin.socket.io instrument = False admin_login = { - 'username': 'admin', - 'password': 'python', # change this to a strong secret for production use! + "username": "admin", + "password": "python", # change this to a strong secret for production use! } import uvicorn import socketio sio = socketio.AsyncServer( - async_mode='asgi', - cors_allowed_origins=None if not instrument else [ - 'http://localhost:5000', - 'https://admin.socket.io', # edit the allowed origins if necessary - ]) + async_mode="asgi", + cors_allowed_origins=None + if not instrument + else [ + "http://localhost:5000", + "https://admin.socket.io", # edit the allowed origins if necessary + ], +) if instrument: sio.instrument(auth=admin_login) -app = socketio.ASGIApp(sio, static_files={ - '/': 'app.html', -}) +app = socketio.ASGIApp( + sio, + static_files={ + "/": "app.html", + }, +) background_task_started = False @@ -32,65 +38,66 @@ async def background_task(): while True: await sio.sleep(10) count += 1 - await sio.emit('my_response', {'data': 'Server generated event'}) + await sio.emit("my_response", {"data": "Server generated event"}) -@sio.on('my_event') +@sio.on("my_event") async def test_message(sid, message): - await sio.emit('my_response', {'data': message['data']}, room=sid) + await sio.emit("my_response", {"data": message["data"]}, room=sid) -@sio.on('my_broadcast_event') +@sio.on("my_broadcast_event") async def test_broadcast_message(sid, message): - await sio.emit('my_response', {'data': message['data']}) + await sio.emit("my_response", {"data": message["data"]}) -@sio.on('join') +@sio.on("join") async def join(sid, message): - await sio.enter_room(sid, message['room']) - await sio.emit('my_response', {'data': 'Entered room: ' + message['room']}, - room=sid) + await sio.enter_room(sid, message["room"]) + await sio.emit( + "my_response", {"data": "Entered room: " + message["room"]}, room=sid + ) -@sio.on('leave') +@sio.on("leave") async def leave(sid, message): - await sio.leave_room(sid, message['room']) - await sio.emit('my_response', {'data': 'Left room: ' + message['room']}, - room=sid) + await sio.leave_room(sid, message["room"]) + await sio.emit("my_response", {"data": "Left room: " + message["room"]}, room=sid) -@sio.on('close room') +@sio.on("close room") async def close(sid, message): - await sio.emit('my_response', - {'data': 'Room ' + message['room'] + ' is closing.'}, - room=message['room']) - await sio.close_room(message['room']) + await sio.emit( + "my_response", + {"data": "Room " + message["room"] + " is closing."}, + room=message["room"], + ) + await sio.close_room(message["room"]) -@sio.on('my_room_event') +@sio.on("my_room_event") async def send_room_message(sid, message): - await sio.emit('my_response', {'data': message['data']}, - room=message['room']) + await sio.emit("my_response", {"data": message["data"]}, room=message["room"]) -@sio.on('disconnect request') +@sio.on("disconnect request") async def disconnect_request(sid): await sio.disconnect(sid) -@sio.on('connect') +@sio.on("connect") async def test_connect(sid, environ): global background_task_started if not background_task_started: sio.start_background_task(background_task) background_task_started = True - await sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) + await sio.emit("my_response", {"data": "Connected", "count": 0}, room=sid) -@sio.on('disconnect') +@sio.on("disconnect") def test_disconnect(sid): - print('Client disconnected') + print("Client disconnected") -if __name__ == '__main__': - uvicorn.run(app, host='127.0.0.1', port=5000) +if __name__ == "__main__": + uvicorn.run(app, host="127.0.0.1", port=5000) diff --git a/examples/server/asgi/fastapi-fiddle.py b/examples/server/asgi/fastapi-fiddle.py index b6902e0..089a3f2 100644 --- a/examples/server/asgi/fastapi-fiddle.py +++ b/examples/server/asgi/fastapi-fiddle.py @@ -6,32 +6,32 @@ import socketio import uvicorn app = FastAPI() -app.mount('/static', StaticFiles(directory='static'), name='static') +app.mount("/static", StaticFiles(directory="static"), name="static") -sio = socketio.AsyncServer(async_mode='asgi') +sio = socketio.AsyncServer(async_mode="asgi") combined_asgi_app = socketio.ASGIApp(sio, app) -@app.get('/') +@app.get("/") async def index(): - return FileResponse('fiddle.html') + return FileResponse("fiddle.html") -@app.get('/hello') +@app.get("/hello") async def hello(): - return {'message': 'Hello, World!'} + return {"message": "Hello, World!"} @sio.event async def connect(sid, environ, auth): - print(f'connected auth={auth} sid={sid}') - await sio.emit('hello', (1, 2, {'hello': 'you'}), to=sid) + print(f"connected auth={auth} sid={sid}") + await sio.emit("hello", (1, 2, {"hello": "you"}), to=sid) @sio.event def disconnect(sid): - print('disconnected', sid) + print("disconnected", sid) -if __name__ == '__main__': - uvicorn.run(combined_asgi_app, host='127.0.0.1', port=5000) +if __name__ == "__main__": + uvicorn.run(combined_asgi_app, host="127.0.0.1", port=5000) diff --git a/examples/server/asgi/fiddle.py b/examples/server/asgi/fiddle.py index 6899ed1..d9c3d8d 100644 --- a/examples/server/asgi/fiddle.py +++ b/examples/server/asgi/fiddle.py @@ -3,23 +3,26 @@ import uvicorn import socketio -sio = socketio.AsyncServer(async_mode='asgi') -app = socketio.ASGIApp(sio, static_files={ - '/': 'fiddle.html', - '/static': 'static', -}) +sio = socketio.AsyncServer(async_mode="asgi") +app = socketio.ASGIApp( + sio, + static_files={ + "/": "fiddle.html", + "/static": "static", + }, +) @sio.event async def connect(sid, environ, auth): - print(f'connected auth={auth} sid={sid}') - await sio.emit('hello', (1, 2, {'hello': 'you'}), to=sid) + print(f"connected auth={auth} sid={sid}") + await sio.emit("hello", (1, 2, {"hello": "you"}), to=sid) @sio.event def disconnect(sid): - print('disconnected', sid) + print("disconnected", sid) -if __name__ == '__main__': - uvicorn.run(app, host='127.0.0.1', port=5000) +if __name__ == "__main__": + uvicorn.run(app, host="127.0.0.1", port=5000) diff --git a/examples/server/asgi/latency.py b/examples/server/asgi/latency.py index 3a9d2de..ee25192 100644 --- a/examples/server/asgi/latency.py +++ b/examples/server/asgi/latency.py @@ -3,17 +3,20 @@ import uvicorn import socketio -sio = socketio.AsyncServer(async_mode='asgi') -app = socketio.ASGIApp(sio, static_files={ - '/': 'latency.html', - '/static': 'static', -}) +sio = socketio.AsyncServer(async_mode="asgi") +app = socketio.ASGIApp( + sio, + static_files={ + "/": "latency.html", + "/static": "static", + }, +) @sio.event async def ping_from_client(sid): - await sio.emit('pong_from_server', room=sid) + await sio.emit("pong_from_server", room=sid) -if __name__ == '__main__': - uvicorn.run(app, host='127.0.0.1', port=5000) +if __name__ == "__main__": + uvicorn.run(app, host="127.0.0.1", port=5000) diff --git a/examples/server/asgi/litestar-fiddle.py b/examples/server/asgi/litestar-fiddle.py index 9cd9a8a..31fe296 100644 --- a/examples/server/asgi/litestar-fiddle.py +++ b/examples/server/asgi/litestar-fiddle.py @@ -5,34 +5,36 @@ from litestar.static_files.config import StaticFilesConfig import socketio import uvicorn -sio = socketio.AsyncServer(async_mode='asgi') +sio = socketio.AsyncServer(async_mode="asgi") -@get('/', media_type=MediaType.HTML) +@get("/", media_type=MediaType.HTML) async def index() -> File: - return File('fiddle.html', content_disposition_type='inline') + return File("fiddle.html", content_disposition_type="inline") -@get('/hello') +@get("/hello") async def hello() -> dict: - return {'message': 'Hello, World!'} + return {"message": "Hello, World!"} @sio.event async def connect(sid, environ, auth): - print(f'connected auth={auth} sid={sid}') - await sio.emit('hello', (1, 2, {'hello': 'you'}), to=sid) + print(f"connected auth={auth} sid={sid}") + await sio.emit("hello", (1, 2, {"hello": "you"}), to=sid) @sio.event def disconnect(sid): - print('disconnected', sid) + print("disconnected", sid) -app = Litestar([index, hello], static_files_config=[ - StaticFilesConfig('static', directories=['static'])]) +app = Litestar( + [index, hello], + static_files_config=[StaticFilesConfig("static", directories=["static"])], +) combined_asgi_app = socketio.ASGIApp(sio, app) -if __name__ == '__main__': - uvicorn.run(combined_asgi_app, host='127.0.0.1', port=5000) +if __name__ == "__main__": + uvicorn.run(combined_asgi_app, host="127.0.0.1", port=5000) diff --git a/examples/server/sanic/app.py b/examples/server/sanic/app.py index e10d764..b6c0863 100644 --- a/examples/server/sanic/app.py +++ b/examples/server/sanic/app.py @@ -3,8 +3,8 @@ from sanic.response import html import socketio -sio = socketio.AsyncServer(async_mode='sanic') -app = Sanic(name='sanic_application') +sio = socketio.AsyncServer(async_mode="sanic") +app = Sanic(name="sanic_application") sio.attach(app) @@ -14,56 +14,57 @@ async def background_task(): while True: await sio.sleep(10) count += 1 - await sio.emit('my_response', {'data': 'Server generated event'}) + await sio.emit("my_response", {"data": "Server generated event"}) -@app.listener('before_server_start') +@app.listener("before_server_start") def before_server_start(sanic, loop): sio.start_background_task(background_task) -@app.route('/') +@app.route("/") async def index(request): - with open('app.html') as f: + with open("app.html") as f: return html(f.read()) @sio.event async def my_event(sid, message): - await sio.emit('my_response', {'data': message['data']}, room=sid) + await sio.emit("my_response", {"data": message["data"]}, room=sid) @sio.event async def my_broadcast_event(sid, message): - await sio.emit('my_response', {'data': message['data']}) + await sio.emit("my_response", {"data": message["data"]}) @sio.event async def join(sid, message): - await sio.enter_room(sid, message['room']) - await sio.emit('my_response', {'data': 'Entered room: ' + message['room']}, - room=sid) + await sio.enter_room(sid, message["room"]) + await sio.emit( + "my_response", {"data": "Entered room: " + message["room"]}, room=sid + ) @sio.event async def leave(sid, message): - await sio.leave_room(sid, message['room']) - await sio.emit('my_response', {'data': 'Left room: ' + message['room']}, - room=sid) + await sio.leave_room(sid, message["room"]) + await sio.emit("my_response", {"data": "Left room: " + message["room"]}, room=sid) @sio.event async def close_room(sid, message): - await sio.emit('my_response', - {'data': 'Room ' + message['room'] + ' is closing.'}, - room=message['room']) - await sio.close_room(message['room']) + await sio.emit( + "my_response", + {"data": "Room " + message["room"] + " is closing."}, + room=message["room"], + ) + await sio.close_room(message["room"]) @sio.event async def my_room_event(sid, message): - await sio.emit('my_response', {'data': message['data']}, - room=message['room']) + await sio.emit("my_response", {"data": message["data"]}, room=message["room"]) @sio.event @@ -73,16 +74,16 @@ async def disconnect_request(sid): @sio.event async def connect(sid, environ): - await sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) + await sio.emit("my_response", {"data": "Connected", "count": 0}, room=sid) @sio.event def disconnect(sid): - print('Client disconnected') + print("Client disconnected") -app.static('/static', './static') +app.static("/static", "./static") -if __name__ == '__main__': +if __name__ == "__main__": app.run() diff --git a/examples/server/sanic/fiddle.py b/examples/server/sanic/fiddle.py index 8fe4db8..2542f7d 100644 --- a/examples/server/sanic/fiddle.py +++ b/examples/server/sanic/fiddle.py @@ -3,30 +3,30 @@ from sanic.response import html import socketio -sio = socketio.AsyncServer(async_mode='sanic') +sio = socketio.AsyncServer(async_mode="sanic") app = Sanic() sio.attach(app) -@app.route('/') +@app.route("/") def index(request): - with open('fiddle.html') as f: + with open("fiddle.html") as f: return html(f.read()) @sio.event async def connect(sid, environ, auth): - print(f'connected auth={auth} sid={sid}') - await sio.emit('hello', (1, 2, {'hello': 'you'}), to=sid) + print(f"connected auth={auth} sid={sid}") + await sio.emit("hello", (1, 2, {"hello": "you"}), to=sid) @sio.event def disconnect(sid): - print('disconnected', sid) + print("disconnected", sid) -app.static('/static', './static') +app.static("/static", "./static") -if __name__ == '__main__': +if __name__ == "__main__": app.run() diff --git a/examples/server/sanic/latency.py b/examples/server/sanic/latency.py index a231d6e..d6e62a7 100644 --- a/examples/server/sanic/latency.py +++ b/examples/server/sanic/latency.py @@ -3,23 +3,24 @@ from sanic.response import html import socketio -sio = socketio.AsyncServer(async_mode='sanic') +sio = socketio.AsyncServer(async_mode="sanic") app = Sanic() sio.attach(app) -@app.route('/') +@app.route("/") def index(request): - with open('latency.html') as f: + with open("latency.html") as f: return html(f.read()) @sio.event async def ping_from_client(sid): - await sio.emit('pong_from_server', room=sid) + await sio.emit("pong_from_server", room=sid) -app.static('/static', './static') +app.static("/static", "./static") -if __name__ == '__main__': + +if __name__ == "__main__": app.run() diff --git a/examples/server/tornado/app.py b/examples/server/tornado/app.py index 16f7a19..4078a0f 100644 --- a/examples/server/tornado/app.py +++ b/examples/server/tornado/app.py @@ -9,7 +9,7 @@ import socketio define("port", default=5000, help="run on the given port", type=int) define("debug", default=False, help="run in debug mode") -sio = socketio.AsyncServer(async_mode='tornado') +sio = socketio.AsyncServer(async_mode="tornado") async def background_task(): @@ -18,7 +18,7 @@ async def background_task(): while True: await sio.sleep(10) count += 1 - await sio.emit('my_response', {'data': 'Server generated event'}) + await sio.emit("my_response", {"data": "Server generated event"}) class MainHandler(tornado.web.RequestHandler): @@ -28,40 +28,41 @@ class MainHandler(tornado.web.RequestHandler): @sio.event async def my_event(sid, message): - await sio.emit('my_response', {'data': message['data']}, room=sid) + await sio.emit("my_response", {"data": message["data"]}, room=sid) @sio.event async def my_broadcast_event(sid, message): - await sio.emit('my_response', {'data': message['data']}) + await sio.emit("my_response", {"data": message["data"]}) @sio.event async def join(sid, message): - await sio.enter_room(sid, message['room']) - await sio.emit('my_response', {'data': 'Entered room: ' + message['room']}, - room=sid) + await sio.enter_room(sid, message["room"]) + await sio.emit( + "my_response", {"data": "Entered room: " + message["room"]}, room=sid + ) @sio.event async def leave(sid, message): - await sio.leave_room(sid, message['room']) - await sio.emit('my_response', {'data': 'Left room: ' + message['room']}, - room=sid) + await sio.leave_room(sid, message["room"]) + await sio.emit("my_response", {"data": "Left room: " + message["room"]}, room=sid) @sio.event async def close_room(sid, message): - await sio.emit('my_response', - {'data': 'Room ' + message['room'] + ' is closing.'}, - room=message['room']) - await sio.close_room(message['room']) + await sio.emit( + "my_response", + {"data": "Room " + message["room"] + " is closing."}, + room=message["room"], + ) + await sio.close_room(message["room"]) @sio.event async def my_room_event(sid, message): - await sio.emit('my_response', {'data': message['data']}, - room=message['room']) + await sio.emit("my_response", {"data": message["data"]}, room=message["room"]) @sio.event @@ -71,12 +72,12 @@ async def disconnect_request(sid): @sio.event async def connect(sid, environ): - await sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) + await sio.emit("my_response", {"data": "Connected", "count": 0}, room=sid) @sio.event def disconnect(sid): - print('Client disconnected') + print("Client disconnected") def main(): diff --git a/examples/server/tornado/fiddle.py b/examples/server/tornado/fiddle.py index 1e7e927..f043443 100644 --- a/examples/server/tornado/fiddle.py +++ b/examples/server/tornado/fiddle.py @@ -9,7 +9,7 @@ import socketio define("port", default=5000, help="run on the given port", type=int) define("debug", default=False, help="run in debug mode") -sio = socketio.AsyncServer(async_mode='tornado') +sio = socketio.AsyncServer(async_mode="tornado") class MainHandler(tornado.web.RequestHandler): @@ -19,13 +19,13 @@ class MainHandler(tornado.web.RequestHandler): @sio.event async def connect(sid, environ, auth): - print(f'connected auth={auth} sid={sid}') - await sio.emit('hello', (1, 2, {'hello': 'you'}), to=sid) + print(f"connected auth={auth} sid={sid}") + await sio.emit("hello", (1, 2, {"hello": "you"}), to=sid) @sio.event def disconnect(sid): - print('disconnected', sid) + print("disconnected", sid) def main(): diff --git a/examples/server/tornado/latency.py b/examples/server/tornado/latency.py index 571050b..7dd3a4a 100644 --- a/examples/server/tornado/latency.py +++ b/examples/server/tornado/latency.py @@ -9,7 +9,7 @@ import socketio define("port", default=5000, help="run on the given port", type=int) define("debug", default=False, help="run in debug mode") -sio = socketio.AsyncServer(async_mode='tornado') +sio = socketio.AsyncServer(async_mode="tornado") class MainHandler(tornado.web.RequestHandler): @@ -19,7 +19,7 @@ class MainHandler(tornado.web.RequestHandler): @sio.event async def ping_from_client(sid): - await sio.emit('pong_from_server', room=sid) + await sio.emit("pong_from_server", room=sid) def main(): diff --git a/examples/server/wsgi/app.py b/examples/server/wsgi/app.py index 7b019fd..09f7ec3 100644 --- a/examples/server/wsgi/app.py +++ b/examples/server/wsgi/app.py @@ -7,8 +7,8 @@ async_mode = None # Admin UI hosted at https://admin.socket.io instrument = False admin_login = { - 'username': 'admin', - 'password': 'python', # change this to a strong secret for production use! + "username": "admin", + "password": "python", # change this to a strong secret for production use! } from flask import Flask, render_template @@ -16,16 +16,19 @@ import socketio sio = socketio.Server( async_mode=async_mode, - cors_allowed_origins=None if not instrument else [ - 'http://localhost:5000', - 'https://admin.socket.io', # edit the allowed origins if necessary - ]) + cors_allowed_origins=None + if not instrument + else [ + "http://localhost:5000", + "https://admin.socket.io", # edit the allowed origins if necessary + ], +) if instrument: sio.instrument(auth=admin_login) app = Flask(__name__) app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app) -app.config['SECRET_KEY'] = 'secret!' +app.config["SECRET_KEY"] = "secret!" thread = None @@ -35,52 +38,52 @@ def background_thread(): while True: sio.sleep(10) count += 1 - sio.emit('my_response', {'data': 'Server generated event'}) + sio.emit("my_response", {"data": "Server generated event"}) -@app.route('/') +@app.route("/") def index(): global thread if thread is None: thread = sio.start_background_task(background_thread) - return render_template('index.html') + return render_template("index.html") @sio.event def my_event(sid, message): - sio.emit('my_response', {'data': message['data']}, room=sid) + sio.emit("my_response", {"data": message["data"]}, room=sid) @sio.event def my_broadcast_event(sid, message): - sio.emit('my_response', {'data': message['data']}) + sio.emit("my_response", {"data": message["data"]}) @sio.event def join(sid, message): - sio.enter_room(sid, message['room']) - sio.emit('my_response', {'data': 'Entered room: ' + message['room']}, - room=sid) + sio.enter_room(sid, message["room"]) + sio.emit("my_response", {"data": "Entered room: " + message["room"]}, room=sid) @sio.event def leave(sid, message): - sio.leave_room(sid, message['room']) - sio.emit('my_response', {'data': 'Left room: ' + message['room']}, - room=sid) + sio.leave_room(sid, message["room"]) + sio.emit("my_response", {"data": "Left room: " + message["room"]}, room=sid) @sio.event def close_room(sid, message): - sio.emit('my_response', - {'data': 'Room ' + message['room'] + ' is closing.'}, - room=message['room']) - sio.close_room(message['room']) + sio.emit( + "my_response", + {"data": "Room " + message["room"] + " is closing."}, + room=message["room"], + ) + sio.close_room(message["room"]) @sio.event def my_room_event(sid, message): - sio.emit('my_response', {'data': message['data']}, room=message['room']) + sio.emit("my_response", {"data": message["data"]}, room=message["room"]) @sio.event @@ -90,39 +93,45 @@ def disconnect_request(sid): @sio.event def connect(sid, environ): - sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) + sio.emit("my_response", {"data": "Connected", "count": 0}, room=sid) @sio.event def disconnect(sid): - print('Client disconnected') + print("Client disconnected") -if __name__ == '__main__': - if sio.async_mode == 'threading': +if __name__ == "__main__": + if sio.async_mode == "threading": # deploy with Werkzeug app.run(threaded=True) - elif sio.async_mode == 'eventlet': + elif sio.async_mode == "eventlet": # deploy with eventlet import eventlet import eventlet.wsgi - eventlet.wsgi.server(eventlet.listen(('', 5000)), app) - elif sio.async_mode == 'gevent': + + eventlet.wsgi.server(eventlet.listen(("", 5000)), app) + elif sio.async_mode == "gevent": # deploy with gevent from gevent import pywsgi + try: from geventwebsocket.handler import WebSocketHandler + websocket = True except ImportError: websocket = False if websocket: - pywsgi.WSGIServer(('', 5000), app, - handler_class=WebSocketHandler).serve_forever() + pywsgi.WSGIServer( + ("", 5000), app, handler_class=WebSocketHandler + ).serve_forever() else: - pywsgi.WSGIServer(('', 5000), app).serve_forever() - elif sio.async_mode == 'gevent_uwsgi': - print('Start the application through the uwsgi server. Example:') - print('uwsgi --http :5000 --gevent 1000 --http-websockets --master ' - '--wsgi-file app.py --callable app') + pywsgi.WSGIServer(("", 5000), app).serve_forever() + elif sio.async_mode == "gevent_uwsgi": + print("Start the application through the uwsgi server. Example:") + print( + "uwsgi --http :5000 --gevent 1000 --http-websockets --master " + "--wsgi-file app.py --callable app" + ) else: - print('Unknown async_mode: ' + sio.async_mode) + print("Unknown async_mode: " + sio.async_mode) diff --git a/examples/server/wsgi/django_socketio/django_socketio/asgi.py b/examples/server/wsgi/django_socketio/django_socketio/asgi.py index 234d2d9..2c1e775 100644 --- a/examples/server/wsgi/django_socketio/django_socketio/asgi.py +++ b/examples/server/wsgi/django_socketio/django_socketio/asgi.py @@ -11,6 +11,6 @@ import os from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_socketio.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_socketio.settings") application = get_asgi_application() diff --git a/examples/server/wsgi/django_socketio/django_socketio/settings.py b/examples/server/wsgi/django_socketio/django_socketio/settings.py index 313462d..83cd23d 100644 --- a/examples/server/wsgi/django_socketio/django_socketio/settings.py +++ b/examples/server/wsgi/django_socketio/django_socketio/settings.py @@ -20,7 +20,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-&@-nkbrpe@%1_%ljh#oe@sw)6+k(&yn#r_)!5p)$22c^u#0@lj' +SECRET_KEY = "django-insecure-&@-nkbrpe@%1_%ljh#oe@sw)6+k(&yn#r_)!5p)$22c^u#0@lj" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -31,53 +31,53 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'socketio_app', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "socketio_app", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'django_socketio.urls' +ROOT_URLCONF = "django_socketio.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'django_socketio.wsgi.application' +WSGI_APPLICATION = "django_socketio.wsgi.application" # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", } } @@ -87,16 +87,16 @@ DATABASES = { AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -104,9 +104,9 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/4.0/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -116,9 +116,9 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.0/howto/static-files/ -STATIC_URL = 'static/' +STATIC_URL = "static/" # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/examples/server/wsgi/django_socketio/django_socketio/urls.py b/examples/server/wsgi/django_socketio/django_socketio/urls.py index c156551..1ac758d 100644 --- a/examples/server/wsgi/django_socketio/django_socketio/urls.py +++ b/examples/server/wsgi/django_socketio/django_socketio/urls.py @@ -18,6 +18,6 @@ from django.urls import path from django.conf.urls import include urlpatterns = [ - path('admin/', admin.site.urls), - path(r'', include('socketio_app.urls')), + path("admin/", admin.site.urls), + path(r"", include("socketio_app.urls")), ] diff --git a/examples/server/wsgi/django_socketio/django_socketio/wsgi.py b/examples/server/wsgi/django_socketio/django_socketio/wsgi.py index 771cae2..33a921f 100644 --- a/examples/server/wsgi/django_socketio/django_socketio/wsgi.py +++ b/examples/server/wsgi/django_socketio/django_socketio/wsgi.py @@ -14,7 +14,7 @@ import socketio from socketio_app.views import sio -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_socketio.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_socketio.settings") django_app = get_wsgi_application() application = socketio.WSGIApp(sio, django_app) diff --git a/examples/server/wsgi/django_socketio/manage.py b/examples/server/wsgi/django_socketio/manage.py index 35ef79b..25bfba4 100755 --- a/examples/server/wsgi/django_socketio/manage.py +++ b/examples/server/wsgi/django_socketio/manage.py @@ -6,7 +6,7 @@ import sys def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_socketio.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_socketio.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -18,5 +18,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/examples/server/wsgi/django_socketio/socketio_app/admin.py b/examples/server/wsgi/django_socketio/socketio_app/admin.py index 8c38f3f..846f6b4 100644 --- a/examples/server/wsgi/django_socketio/socketio_app/admin.py +++ b/examples/server/wsgi/django_socketio/socketio_app/admin.py @@ -1,3 +1 @@ -from django.contrib import admin - # Register your models here. diff --git a/examples/server/wsgi/django_socketio/socketio_app/apps.py b/examples/server/wsgi/django_socketio/socketio_app/apps.py index e8e83ea..4f8c8dc 100644 --- a/examples/server/wsgi/django_socketio/socketio_app/apps.py +++ b/examples/server/wsgi/django_socketio/socketio_app/apps.py @@ -2,5 +2,5 @@ from django.apps import AppConfig class SocketioAppConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'socketio_app' + default_auto_field = "django.db.models.BigAutoField" + name = "socketio_app" diff --git a/examples/server/wsgi/django_socketio/socketio_app/models.py b/examples/server/wsgi/django_socketio/socketio_app/models.py index 71a8362..6b20219 100644 --- a/examples/server/wsgi/django_socketio/socketio_app/models.py +++ b/examples/server/wsgi/django_socketio/socketio_app/models.py @@ -1,3 +1 @@ -from django.db import models - # Create your models here. diff --git a/examples/server/wsgi/django_socketio/socketio_app/tests.py b/examples/server/wsgi/django_socketio/socketio_app/tests.py index 7ce503c..a39b155 100644 --- a/examples/server/wsgi/django_socketio/socketio_app/tests.py +++ b/examples/server/wsgi/django_socketio/socketio_app/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/examples/server/wsgi/django_socketio/socketio_app/urls.py b/examples/server/wsgi/django_socketio/socketio_app/urls.py index eddc173..d98c635 100644 --- a/examples/server/wsgi/django_socketio/socketio_app/urls.py +++ b/examples/server/wsgi/django_socketio/socketio_app/urls.py @@ -3,5 +3,5 @@ from django.urls import path from . import views urlpatterns = [ - path(r'', views.index, name='index'), + path(r"", views.index, name="index"), ] diff --git a/examples/server/wsgi/django_socketio/socketio_app/views.py b/examples/server/wsgi/django_socketio/socketio_app/views.py index 854c0fb..8c04603 100644 --- a/examples/server/wsgi/django_socketio/socketio_app/views.py +++ b/examples/server/wsgi/django_socketio/socketio_app/views.py @@ -17,7 +17,7 @@ def index(request): global thread if thread is None: thread = sio.start_background_task(background_thread) - return HttpResponse(open(os.path.join(basedir, 'static/index.html'))) + return HttpResponse(open(os.path.join(basedir, "static/index.html"))) def background_thread(): @@ -26,45 +26,44 @@ def background_thread(): while True: sio.sleep(10) count += 1 - sio.emit('my_response', {'data': 'Server generated event'}, - namespace='/test') + sio.emit("my_response", {"data": "Server generated event"}, namespace="/test") @sio.event def my_event(sid, message): - sio.emit('my_response', {'data': message['data']}, room=sid) + sio.emit("my_response", {"data": message["data"]}, room=sid) @sio.event def my_broadcast_event(sid, message): - sio.emit('my_response', {'data': message['data']}) + sio.emit("my_response", {"data": message["data"]}) @sio.event def join(sid, message): - sio.enter_room(sid, message['room']) - sio.emit('my_response', {'data': 'Entered room: ' + message['room']}, - room=sid) + sio.enter_room(sid, message["room"]) + sio.emit("my_response", {"data": "Entered room: " + message["room"]}, room=sid) @sio.event def leave(sid, message): - sio.leave_room(sid, message['room']) - sio.emit('my_response', {'data': 'Left room: ' + message['room']}, - room=sid) + sio.leave_room(sid, message["room"]) + sio.emit("my_response", {"data": "Left room: " + message["room"]}, room=sid) @sio.event def close_room(sid, message): - sio.emit('my_response', - {'data': 'Room ' + message['room'] + ' is closing.'}, - room=message['room']) - sio.close_room(message['room']) + sio.emit( + "my_response", + {"data": "Room " + message["room"] + " is closing."}, + room=message["room"], + ) + sio.close_room(message["room"]) @sio.event def my_room_event(sid, message): - sio.emit('my_response', {'data': message['data']}, room=message['room']) + sio.emit("my_response", {"data": message["data"]}, room=message["room"]) @sio.event @@ -74,9 +73,9 @@ def disconnect_request(sid): @sio.event def connect(sid, environ): - sio.emit('my_response', {'data': 'Connected', 'count': 0}, room=sid) + sio.emit("my_response", {"data": "Connected", "count": 0}, room=sid) @sio.event def disconnect(sid): - print('Client disconnected') + print("Client disconnected") diff --git a/examples/server/wsgi/fiddle.py b/examples/server/wsgi/fiddle.py index 247751b..9515755 100644 --- a/examples/server/wsgi/fiddle.py +++ b/examples/server/wsgi/fiddle.py @@ -11,47 +11,53 @@ app = Flask(__name__) app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app) -@app.route('/') +@app.route("/") def index(): - return render_template('fiddle.html') + return render_template("fiddle.html") @sio.event def connect(sid, environ, auth): - print(f'connected auth={auth} sid={sid}') - sio.emit('hello', (1, 2, {'hello': 'you'}), to=sid) + print(f"connected auth={auth} sid={sid}") + sio.emit("hello", (1, 2, {"hello": "you"}), to=sid) @sio.event def disconnect(sid): - print('disconnected', sid) + print("disconnected", sid) -if __name__ == '__main__': - if sio.async_mode == 'threading': +if __name__ == "__main__": + if sio.async_mode == "threading": # deploy with Werkzeug app.run(threaded=True) - elif sio.async_mode == 'eventlet': + elif sio.async_mode == "eventlet": # deploy with eventlet import eventlet import eventlet.wsgi - eventlet.wsgi.server(eventlet.listen(('', 5000)), app) - elif sio.async_mode == 'gevent': + + eventlet.wsgi.server(eventlet.listen(("", 5000)), app) + elif sio.async_mode == "gevent": # deploy with gevent from gevent import pywsgi + try: from geventwebsocket.handler import WebSocketHandler + websocket = True except ImportError: websocket = False if websocket: - pywsgi.WSGIServer(('', 5000), app, - handler_class=WebSocketHandler).serve_forever() + pywsgi.WSGIServer( + ("", 5000), app, handler_class=WebSocketHandler + ).serve_forever() else: - pywsgi.WSGIServer(('', 5000), app).serve_forever() - elif sio.async_mode == 'gevent_uwsgi': - print('Start the application through the uwsgi server. Example:') - print('uwsgi --http :5000 --gevent 1000 --http-websockets --master ' - '--wsgi-file latency.py --callable app') + pywsgi.WSGIServer(("", 5000), app).serve_forever() + elif sio.async_mode == "gevent_uwsgi": + print("Start the application through the uwsgi server. Example:") + print( + "uwsgi --http :5000 --gevent 1000 --http-websockets --master " + "--wsgi-file latency.py --callable app" + ) else: - print('Unknown async_mode: ' + sio.async_mode) + print("Unknown async_mode: " + sio.async_mode) diff --git a/examples/server/wsgi/latency.py b/examples/server/wsgi/latency.py index 5f9ff88..45b7176 100644 --- a/examples/server/wsgi/latency.py +++ b/examples/server/wsgi/latency.py @@ -11,41 +11,47 @@ app = Flask(__name__) app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app) -@app.route('/') +@app.route("/") def index(): - return render_template('latency.html') + return render_template("latency.html") @sio.event def ping_from_client(sid): - sio.emit('pong_from_server', room=sid) + sio.emit("pong_from_server", room=sid) -if __name__ == '__main__': - if sio.async_mode == 'threading': +if __name__ == "__main__": + if sio.async_mode == "threading": # deploy with Werkzeug app.run(threaded=True) - elif sio.async_mode == 'eventlet': + elif sio.async_mode == "eventlet": # deploy with eventlet import eventlet import eventlet.wsgi - eventlet.wsgi.server(eventlet.listen(('', 5000)), app) - elif sio.async_mode == 'gevent': + + eventlet.wsgi.server(eventlet.listen(("", 5000)), app) + elif sio.async_mode == "gevent": # deploy with gevent from gevent import pywsgi + try: from geventwebsocket.handler import WebSocketHandler + websocket = True except ImportError: websocket = False if websocket: - pywsgi.WSGIServer(('', 5000), app, - handler_class=WebSocketHandler).serve_forever() + pywsgi.WSGIServer( + ("", 5000), app, handler_class=WebSocketHandler + ).serve_forever() else: - pywsgi.WSGIServer(('', 5000), app).serve_forever() - elif sio.async_mode == 'gevent_uwsgi': - print('Start the application through the uwsgi server. Example:') - print('uwsgi --http :5000 --gevent 1000 --http-websockets --master ' - '--wsgi-file latency.py --callable app') + pywsgi.WSGIServer(("", 5000), app).serve_forever() + elif sio.async_mode == "gevent_uwsgi": + print("Start the application through the uwsgi server. Example:") + print( + "uwsgi --http :5000 --gevent 1000 --http-websockets --master " + "--wsgi-file latency.py --callable app" + ) else: - print('Unknown async_mode: ' + sio.async_mode) + print("Unknown async_mode: " + sio.async_mode) diff --git a/examples/simple-client/async/fiddle_client.py b/examples/simple-client/async/fiddle_client.py index d974480..26e67a6 100644 --- a/examples/simple-client/async/fiddle_client.py +++ b/examples/simple-client/async/fiddle_client.py @@ -4,9 +4,9 @@ import socketio async def main(): async with socketio.AsyncSimpleClient() as sio: - await sio.connect('http://localhost:5000', auth={'token': 'my-token'}) + await sio.connect("http://localhost:5000", auth={"token": "my-token"}) print(await sio.receive()) -if __name__ == '__main__': +if __name__ == "__main__": asyncio.run(main()) diff --git a/examples/simple-client/async/latency_client.py b/examples/simple-client/async/latency_client.py index 96387c6..18968aa 100644 --- a/examples/simple-client/async/latency_client.py +++ b/examples/simple-client/async/latency_client.py @@ -5,17 +5,17 @@ import socketio async def main(): async with socketio.AsyncSimpleClient() as sio: - await sio.connect('http://localhost:5000') + await sio.connect("http://localhost:5000") while True: start_timer = time.time() - await sio.emit('ping_from_client') - while (await sio.receive()) != ['pong_from_server']: + await sio.emit("ping_from_client") + while (await sio.receive()) != ["pong_from_server"]: pass latency = time.time() - start_timer - print('latency is {0:.2f} ms'.format(latency * 1000)) + print("latency is {0:.2f} ms".format(latency * 1000)) await asyncio.sleep(1) -if __name__ == '__main__': +if __name__ == "__main__": asyncio.run(main()) diff --git a/examples/simple-client/sync/fiddle_client.py b/examples/simple-client/sync/fiddle_client.py index 1be759c..7a48144 100644 --- a/examples/simple-client/sync/fiddle_client.py +++ b/examples/simple-client/sync/fiddle_client.py @@ -3,9 +3,9 @@ import socketio def main(): with socketio.SimpleClient() as sio: - sio.connect('http://localhost:5000', auth={'token': 'my-token'}) + sio.connect("http://localhost:5000", auth={"token": "my-token"}) print(sio.receive()) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/examples/simple-client/sync/latency_client.py b/examples/simple-client/sync/latency_client.py index d5cd853..70efb75 100644 --- a/examples/simple-client/sync/latency_client.py +++ b/examples/simple-client/sync/latency_client.py @@ -4,17 +4,17 @@ import socketio def main(): with socketio.SimpleClient() as sio: - sio.connect('http://localhost:5000') + sio.connect("http://localhost:5000") while True: start_timer = time.time() - sio.emit('ping_from_client') - while sio.receive() != ['pong_from_server']: + sio.emit("ping_from_client") + while sio.receive() != ["pong_from_server"]: pass latency = time.time() - start_timer - print('latency is {0:.2f} ms'.format(latency * 1000)) + print("latency is {0:.2f} ms".format(latency * 1000)) time.sleep(1) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/socketio/__init__.py b/src/socketio/__init__.py index 95642f4..e92983d 100644 --- a/src/socketio/__init__.py +++ b/src/socketio/__init__.py @@ -19,10 +19,28 @@ from .async_redis_manager import AsyncRedisManager from .async_aiopika_manager import AsyncAioPikaManager from .asgi import ASGIApp -__all__ = ['SimpleClient', 'Client', 'Server', 'Manager', 'PubSubManager', - 'KombuManager', 'RedisManager', 'ZmqManager', 'KafkaManager', - 'Namespace', 'ClientNamespace', 'WSGIApp', 'Middleware', - 'AsyncSimpleClient', 'AsyncClient', 'AsyncServer', - 'AsyncNamespace', 'AsyncClientNamespace', 'AsyncManager', - 'AsyncRedisManager', 'ASGIApp', 'get_tornado_handler', - 'AsyncAioPikaManager'] +__all__ = [ + "SimpleClient", + "Client", + "Server", + "Manager", + "PubSubManager", + "KombuManager", + "RedisManager", + "ZmqManager", + "KafkaManager", + "Namespace", + "ClientNamespace", + "WSGIApp", + "Middleware", + "AsyncSimpleClient", + "AsyncClient", + "AsyncServer", + "AsyncNamespace", + "AsyncClientNamespace", + "AsyncManager", + "AsyncRedisManager", + "ASGIApp", + "get_tornado_handler", + "AsyncAioPikaManager", +] diff --git a/src/socketio/admin.py b/src/socketio/admin.py index f317ea2..b56d6b4 100644 --- a/src/socketio/admin.py +++ b/src/socketio/admin.py @@ -16,15 +16,15 @@ class EventBuffer: def push(self, type, count=1): timestamp = int(time.time()) * 1000 - key = '{};{}'.format(timestamp, type) + key = "{};{}".format(timestamp, type) if key not in self.buffer: self.buffer[key] = { - 'timestamp': timestamp, - 'type': type, - 'count': count, + "timestamp": timestamp, + "type": type, + "count": count, } else: - self.buffer[key]['count'] += count + self.buffer[key]["count"] += count def get_and_clear(self): buffer = self.buffer @@ -33,19 +33,28 @@ class EventBuffer: class InstrumentedServer: - def __init__(self, sio, auth=None, mode='development', read_only=False, - server_id=None, namespace='/admin', server_stats_interval=2): + def __init__( + self, + sio, + auth=None, + mode="development", + read_only=False, + server_id=None, + namespace="/admin", + server_stats_interval=2, + ): """Instrument the Socket.IO server for monitoring with the `Socket.IO Admin UI `_. """ if auth is None: - raise ValueError('auth must be specified') + raise ValueError("auth must be specified") self.sio = sio self.auth = auth self.admin_namespace = namespace self.read_only = read_only self.server_id = server_id or ( - self.sio.manager.host_id if hasattr(self.sio.manager, 'host_id') + self.sio.manager.host_id + if hasattr(self.sio.manager, "host_id") else HOSTNAME ) self.mode = mode @@ -60,19 +69,20 @@ class InstrumentedServer: self.instrument() def instrument(self): - self.sio.on('connect', self.admin_connect, - namespace=self.admin_namespace) + self.sio.on("connect", self.admin_connect, namespace=self.admin_namespace) - if self.mode == 'development': + if self.mode == "development": if not self.read_only: # pragma: no branch - self.sio.on('emit', self.admin_emit, - namespace=self.admin_namespace) - self.sio.on('join', self.admin_enter_room, - namespace=self.admin_namespace) - self.sio.on('leave', self.admin_leave_room, - namespace=self.admin_namespace) - self.sio.on('_disconnect', self.admin_disconnect, - namespace=self.admin_namespace) + self.sio.on("emit", self.admin_emit, namespace=self.admin_namespace) + self.sio.on( + "join", self.admin_enter_room, namespace=self.admin_namespace + ) + self.sio.on( + "leave", self.admin_leave_room, namespace=self.admin_namespace + ) + self.sio.on( + "_disconnect", self.admin_disconnect, namespace=self.admin_namespace + ) # track socket connection times self.sio.manager._timestamps = {} @@ -86,13 +96,11 @@ class InstrumentedServer: self.sio.manager.disconnect = self._disconnect # report join rooms - self.sio.manager.__basic_enter_room = \ - self.sio.manager.basic_enter_room + self.sio.manager.__basic_enter_room = self.sio.manager.basic_enter_room self.sio.manager.basic_enter_room = self._basic_enter_room # report leave rooms - self.sio.manager.__basic_leave_room = \ - self.sio.manager.basic_leave_room + self.sio.manager.__basic_leave_room = self.sio.manager.basic_leave_room self.sio.manager.basic_leave_room = self._basic_leave_room # report emit events @@ -104,44 +112,47 @@ class InstrumentedServer: self.sio._handle_event_internal = self._handle_event_internal # report engine.io connections - self.sio.eio.on('connect', self._handle_eio_connect) - self.sio.eio.on('disconnect', self._handle_eio_disconnect) + self.sio.eio.on("connect", self._handle_eio_connect) + self.sio.eio.on("disconnect", self._handle_eio_disconnect) # report polling packets from engineio.socket import Socket + self.sio.eio.__ok = self.sio.eio._ok self.sio.eio._ok = self._eio_http_response Socket.__handle_post_request = Socket.handle_post_request Socket.handle_post_request = functools.partialmethod( - self.__class__._eio_handle_post_request, self) + self.__class__._eio_handle_post_request, self + ) # report websocket packets Socket.__websocket_handler = Socket._websocket_handler Socket._websocket_handler = functools.partialmethod( - self.__class__._eio_websocket_handler, self) + self.__class__._eio_websocket_handler, self + ) # report connected sockets with each ping - if self.mode == 'development': + if self.mode == "development": Socket.__send_ping = Socket._send_ping Socket._send_ping = functools.partialmethod( - self.__class__._eio_send_ping, self) + self.__class__._eio_send_ping, self + ) def uninstrument(self): # pragma: no cover - if self.mode == 'development': + if self.mode == "development": self.sio.manager.connect = self.sio.manager.__connect self.sio.manager.disconnect = self.sio.manager.__disconnect - self.sio.manager.basic_enter_room = \ - self.sio.manager.__basic_enter_room - self.sio.manager.basic_leave_room = \ - self.sio.manager.__basic_leave_room + self.sio.manager.basic_enter_room = self.sio.manager.__basic_enter_room + self.sio.manager.basic_leave_room = self.sio.manager.__basic_leave_room self.sio.manager.emit = self.sio.manager.__emit self.sio._handle_event_internal = self.sio.__handle_event_internal self.sio.eio._ok = self.sio.eio.__ok from engineio.socket import Socket + Socket.handle_post_request = Socket.__handle_post_request Socket._websocket_handler = Socket.__websocket_handler - if self.mode == 'development': + if self.mode == "development": Socket._send_ping = Socket.__send_ping def admin_connect(self, sid, environ, client_auth): @@ -154,31 +165,41 @@ class InstrumentedServer: else: authenticated = self.auth(client_auth) if not authenticated: - raise ConnectionRefusedError('authentication failed') + raise ConnectionRefusedError("authentication failed") def config(sid): self.sio.sleep(0.1) # supported features - features = ['AGGREGATED_EVENTS'] + features = ["AGGREGATED_EVENTS"] if not self.read_only: - features += ['EMIT', 'JOIN', 'LEAVE', 'DISCONNECT', 'MJOIN', - 'MLEAVE', 'MDISCONNECT'] - if self.mode == 'development': - features.append('ALL_EVENTS') - self.sio.emit('config', {'supportedFeatures': features}, - to=sid, namespace=self.admin_namespace) + features += [ + "EMIT", + "JOIN", + "LEAVE", + "DISCONNECT", + "MJOIN", + "MLEAVE", + "MDISCONNECT", + ] + if self.mode == "development": + features.append("ALL_EVENTS") + self.sio.emit( + "config", + {"supportedFeatures": features}, + to=sid, + namespace=self.admin_namespace, + ) # send current sockets - if self.mode == 'development': + if self.mode == "development": all_sockets = [] for nsp in self.sio.manager.get_namespaces(): - for sid, eio_sid in self.sio.manager.get_participants( - nsp, None): - all_sockets.append( - self.serialize_socket(sid, nsp, eio_sid)) - self.sio.emit('all_sockets', all_sockets, to=sid, - namespace=self.admin_namespace) + for sid, eio_sid in self.sio.manager.get_participants(nsp, None): + all_sockets.append(self.serialize_socket(sid, nsp, eio_sid)) + self.sio.emit( + "all_sockets", all_sockets, to=sid, namespace=self.admin_namespace + ) self.sio.start_background_task(config, sid) @@ -186,18 +207,15 @@ class InstrumentedServer: self.sio.emit(event, data, to=room_filter, namespace=namespace) def admin_enter_room(self, _, namespace, room, room_filter=None): - for sid, _ in self.sio.manager.get_participants( - namespace, room_filter): + for sid, _ in self.sio.manager.get_participants(namespace, room_filter): self.sio.enter_room(sid, room, namespace=namespace) def admin_leave_room(self, _, namespace, room, room_filter=None): - for sid, _ in self.sio.manager.get_participants( - namespace, room_filter): + for sid, _ in self.sio.manager.get_participants(namespace, room_filter): self.sio.leave_room(sid, room, namespace=namespace) def admin_disconnect(self, _, namespace, close, room_filter=None): - for sid, _ in self.sio.manager.get_participants( - namespace, room_filter): + for sid, _ in self.sio.manager.get_participants(namespace, room_filter): self.sio.disconnect(sid, namespace=namespace) def shutdown(self): @@ -210,20 +228,28 @@ class InstrumentedServer: t = time.time() self.sio.manager._timestamps[sid] = t serialized_socket = self.serialize_socket(sid, namespace, eio_sid) - self.sio.emit('socket_connected', ( - serialized_socket, - datetime.utcfromtimestamp(t).isoformat() + 'Z', - ), namespace=self.admin_namespace) + self.sio.emit( + "socket_connected", + ( + serialized_socket, + datetime.utcfromtimestamp(t).isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return sid def _disconnect(self, sid, namespace, **kwargs): del self.sio.manager._timestamps[sid] - self.sio.emit('socket_disconnected', ( - namespace, - sid, - 'N/A', - datetime.utcnow().isoformat() + 'Z', - ), namespace=self.admin_namespace) + self.sio.emit( + "socket_disconnected", + ( + namespace, + sid, + "N/A", + datetime.utcnow().isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return self.sio.manager.__disconnect(sid, namespace, **kwargs) def _check_for_upgrade(self, eio_sid, sid, namespace): # pragma: no cover @@ -231,106 +257,130 @@ class InstrumentedServer: self.sio.sleep(5) try: if self.sio.eio._get_socket(eio_sid).upgraded: - self.sio.emit('socket_updated', { - 'id': sid, - 'nsp': namespace, - 'transport': 'websocket', - }, namespace=self.admin_namespace) + self.sio.emit( + "socket_updated", + { + "id": sid, + "nsp": namespace, + "transport": "websocket", + }, + namespace=self.admin_namespace, + ) break except KeyError: pass def _basic_enter_room(self, sid, namespace, room, eio_sid=None): - ret = self.sio.manager.__basic_enter_room(sid, namespace, room, - eio_sid) + ret = self.sio.manager.__basic_enter_room(sid, namespace, room, eio_sid) if room: - self.sio.emit('room_joined', ( - namespace, - room, - sid, - datetime.utcnow().isoformat() + 'Z', - ), namespace=self.admin_namespace) + self.sio.emit( + "room_joined", + ( + namespace, + room, + sid, + datetime.utcnow().isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return ret def _basic_leave_room(self, sid, namespace, room): if room: - self.sio.emit('room_left', ( - namespace, - room, - sid, - datetime.utcnow().isoformat() + 'Z', - ), namespace=self.admin_namespace) + self.sio.emit( + "room_left", + ( + namespace, + room, + sid, + datetime.utcnow().isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return self.sio.manager.__basic_leave_room(sid, namespace, room) - def _emit(self, event, data, namespace, room=None, skip_sid=None, - callback=None, **kwargs): - ret = self.sio.manager.__emit(event, data, namespace, room=room, - skip_sid=skip_sid, callback=callback, - **kwargs) + def _emit( + self, event, data, namespace, room=None, skip_sid=None, callback=None, **kwargs + ): + ret = self.sio.manager.__emit( + event, + data, + namespace, + room=room, + skip_sid=skip_sid, + callback=callback, + **kwargs, + ) if namespace != self.admin_namespace: - event_data = [event] + list(data) if isinstance(data, tuple) \ - else [data] + event_data = [event] + list(data) if isinstance(data, tuple) else [data] if not isinstance(skip_sid, list): # pragma: no branch skip_sid = [skip_sid] for sid, _ in self.sio.manager.get_participants(namespace, room): if sid not in skip_sid: - self.sio.emit('event_sent', ( - namespace, - sid, - event_data, - datetime.utcnow().isoformat() + 'Z', - ), namespace=self.admin_namespace) + self.sio.emit( + "event_sent", + ( + namespace, + sid, + event_data, + datetime.utcnow().isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return ret - def _handle_event_internal(self, server, sid, eio_sid, data, namespace, - id): - ret = self.sio.__handle_event_internal(server, sid, eio_sid, data, - namespace, id) - self.sio.emit('event_received', ( - namespace, - sid, - data, - datetime.utcnow().isoformat() + 'Z', - ), namespace=self.admin_namespace) + def _handle_event_internal(self, server, sid, eio_sid, data, namespace, id): + ret = self.sio.__handle_event_internal( + server, sid, eio_sid, data, namespace, id + ) + self.sio.emit( + "event_received", + ( + namespace, + sid, + data, + datetime.utcnow().isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return ret def _handle_eio_connect(self, eio_sid, environ): if self.stop_stats_event is None: self.stop_stats_event = self.sio.eio.create_event() - self.stats_task = self.sio.start_background_task( - self._emit_server_stats) + self.stats_task = self.sio.start_background_task(self._emit_server_stats) - self.event_buffer.push('rawConnection') + self.event_buffer.push("rawConnection") return self.sio._handle_eio_connect(eio_sid, environ) def _handle_eio_disconnect(self, eio_sid): - self.event_buffer.push('rawDisconnection') + self.event_buffer.push("rawDisconnection") return self.sio._handle_eio_disconnect(eio_sid) def _eio_http_response(self, packets=None, headers=None, jsonp_index=None): - ret = self.sio.eio.__ok(packets=packets, headers=headers, - jsonp_index=jsonp_index) - self.event_buffer.push('packetsOut') - self.event_buffer.push('bytesOut', len(ret['response'])) + ret = self.sio.eio.__ok( + packets=packets, headers=headers, jsonp_index=jsonp_index + ) + self.event_buffer.push("packetsOut") + self.event_buffer.push("bytesOut", len(ret["response"])) return ret def _eio_handle_post_request(socket, self, environ): ret = socket.__handle_post_request(environ) - self.event_buffer.push('packetsIn') - self.event_buffer.push( - 'bytesIn', int(environ.get('CONTENT_LENGTH', 0))) + self.event_buffer.push("packetsIn") + self.event_buffer.push("bytesIn", int(environ.get("CONTENT_LENGTH", 0))) return ret def _eio_websocket_handler(socket, self, ws): def _send(ws, data, *args, **kwargs): - self.event_buffer.push('packetsOut') - self.event_buffer.push('bytesOut', len(data)) + self.event_buffer.push("packetsOut") + self.event_buffer.push("bytesOut", len(data)) return ws.__send(data, *args, **kwargs) def _wait(ws): ret = ws.__wait() - self.event_buffer.push('packetsIn') - self.event_buffer.push('bytesIn', len(ret or '')) + self.event_buffer.push("packetsIn") + self.event_buffer.push("bytesIn", len(ret or "")) return ret ws.__send = ws.send @@ -345,12 +395,15 @@ class InstrumentedServer: for namespace in self.sio.manager.get_namespaces(): sid = self.sio.manager.sid_from_eio_sid(eio_sid, namespace) if sid: - serialized_socket = self.serialize_socket(sid, namespace, - eio_sid) - self.sio.emit('socket_connected', ( - serialized_socket, - datetime.utcfromtimestamp(t).isoformat() + 'Z', - ), namespace=self.admin_namespace) + serialized_socket = self.serialize_socket(sid, namespace, eio_sid) + self.sio.emit( + "socket_connected", + ( + serialized_socket, + datetime.utcfromtimestamp(t).isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return socket.__send_ping() def _emit_server_stats(self): @@ -359,47 +412,64 @@ class InstrumentedServer: namespaces.sort() while not self.stop_stats_event.is_set(): self.sio.sleep(self.server_stats_interval) - self.sio.emit('server_stats', { - 'serverId': self.server_id, - 'hostname': HOSTNAME, - 'pid': PID, - 'uptime': time.time() - start_time, - 'clientsCount': len(self.sio.eio.sockets), - 'pollingClientsCount': len( - [s for s in self.sio.eio.sockets.values() - if not s.upgraded]), - 'aggregatedEvents': self.event_buffer.get_and_clear(), - 'namespaces': [{ - 'name': nsp, - 'socketsCount': len(self.sio.manager.rooms.get( - nsp, {None: []}).get(None, [])) - } for nsp in namespaces], - }, namespace=self.admin_namespace) + self.sio.emit( + "server_stats", + { + "serverId": self.server_id, + "hostname": HOSTNAME, + "pid": PID, + "uptime": time.time() - start_time, + "clientsCount": len(self.sio.eio.sockets), + "pollingClientsCount": len( + [s for s in self.sio.eio.sockets.values() if not s.upgraded] + ), + "aggregatedEvents": self.event_buffer.get_and_clear(), + "namespaces": [ + { + "name": nsp, + "socketsCount": len( + self.sio.manager.rooms.get(nsp, {None: []}).get( + None, [] + ) + ), + } + for nsp in namespaces + ], + }, + namespace=self.admin_namespace, + ) def serialize_socket(self, sid, namespace, eio_sid=None): if eio_sid is None: # pragma: no cover eio_sid = self.sio.manager.eio_sid_from_sid(sid) socket = self.sio.eio._get_socket(eio_sid) environ = self.sio.environ.get(eio_sid, {}) - tm = self.sio.manager._timestamps[sid] if sid in \ - self.sio.manager._timestamps else 0 + tm = ( + self.sio.manager._timestamps[sid] + if sid in self.sio.manager._timestamps + else 0 + ) return { - 'id': sid, - 'clientId': eio_sid, - 'transport': 'websocket' if socket.upgraded else 'polling', - 'nsp': namespace, - 'data': {}, - 'handshake': { - 'address': environ.get('REMOTE_ADDR', ''), - 'headers': {k[5:].lower(): v for k, v in environ.items() - if k.startswith('HTTP_')}, - 'query': {k: v[0] if len(v) == 1 else v for k, v in parse_qs( - environ.get('QUERY_STRING', '')).items()}, - 'secure': environ.get('wsgi.url_scheme', '') == 'https', - 'url': environ.get('PATH_INFO', ''), - 'issued': tm * 1000, - 'time': datetime.utcfromtimestamp(tm).isoformat() + 'Z' - if tm else '', + "id": sid, + "clientId": eio_sid, + "transport": "websocket" if socket.upgraded else "polling", + "nsp": namespace, + "data": {}, + "handshake": { + "address": environ.get("REMOTE_ADDR", ""), + "headers": { + k[5:].lower(): v + for k, v in environ.items() + if k.startswith("HTTP_") + }, + "query": { + k: v[0] if len(v) == 1 else v + for k, v in parse_qs(environ.get("QUERY_STRING", "")).items() + }, + "secure": environ.get("wsgi.url_scheme", "") == "https", + "url": environ.get("PATH_INFO", ""), + "issued": tm * 1000, + "time": datetime.utcfromtimestamp(tm).isoformat() + "Z" if tm else "", }, - 'rooms': self.sio.manager.get_rooms(sid, namespace), + "rooms": self.sio.manager.get_rooms(sid, namespace), } diff --git a/src/socketio/asgi.py b/src/socketio/asgi.py index 2394ee1..0d707af 100644 --- a/src/socketio/asgi.py +++ b/src/socketio/asgi.py @@ -33,10 +33,21 @@ class ASGIApp(engineio.ASGIApp): # pragma: no cover }) uvicorn.run(app, host='127.0.0.1', port=5000) """ - def __init__(self, socketio_server, other_asgi_app=None, - static_files=None, socketio_path='socket.io', - on_startup=None, on_shutdown=None): - super().__init__(socketio_server, other_asgi_app, - static_files=static_files, - engineio_path=socketio_path, on_startup=on_startup, - on_shutdown=on_shutdown) + + def __init__( + self, + socketio_server, + other_asgi_app=None, + static_files=None, + socketio_path="socket.io", + on_startup=None, + on_shutdown=None, + ): + super().__init__( + socketio_server, + other_asgi_app, + static_files=static_files, + engineio_path=socketio_path, + on_startup=on_startup, + on_shutdown=on_shutdown, + ) diff --git a/src/socketio/async_admin.py b/src/socketio/async_admin.py index 162c566..5e4e919 100644 --- a/src/socketio/async_admin.py +++ b/src/socketio/async_admin.py @@ -13,19 +13,28 @@ PID = os.getpid() class InstrumentedAsyncServer: - def __init__(self, sio, auth=None, namespace='/admin', read_only=False, - server_id=None, mode='development', server_stats_interval=2): + def __init__( + self, + sio, + auth=None, + namespace="/admin", + read_only=False, + server_id=None, + mode="development", + server_stats_interval=2, + ): """Instrument the Socket.IO server for monitoring with the `Socket.IO Admin UI `_. """ if auth is None: - raise ValueError('auth must be specified') + raise ValueError("auth must be specified") self.sio = sio self.auth = auth self.admin_namespace = namespace self.read_only = read_only self.server_id = server_id or ( - self.sio.manager.host_id if hasattr(self.sio.manager, 'host_id') + self.sio.manager.host_id + if hasattr(self.sio.manager, "host_id") else HOSTNAME ) self.mode = mode @@ -41,19 +50,20 @@ class InstrumentedAsyncServer: self.instrument() def instrument(self): - self.sio.on('connect', self.admin_connect, - namespace=self.admin_namespace) + self.sio.on("connect", self.admin_connect, namespace=self.admin_namespace) - if self.mode == 'development': + if self.mode == "development": if not self.read_only: # pragma: no branch - self.sio.on('emit', self.admin_emit, - namespace=self.admin_namespace) - self.sio.on('join', self.admin_enter_room, - namespace=self.admin_namespace) - self.sio.on('leave', self.admin_leave_room, - namespace=self.admin_namespace) - self.sio.on('_disconnect', self.admin_disconnect, - namespace=self.admin_namespace) + self.sio.on("emit", self.admin_emit, namespace=self.admin_namespace) + self.sio.on( + "join", self.admin_enter_room, namespace=self.admin_namespace + ) + self.sio.on( + "leave", self.admin_leave_room, namespace=self.admin_namespace + ) + self.sio.on( + "_disconnect", self.admin_disconnect, namespace=self.admin_namespace + ) # track socket connection times self.sio.manager._timestamps = {} @@ -67,13 +77,11 @@ class InstrumentedAsyncServer: self.sio.manager.disconnect = self._disconnect # report join rooms - self.sio.manager.__basic_enter_room = \ - self.sio.manager.basic_enter_room + self.sio.manager.__basic_enter_room = self.sio.manager.basic_enter_room self.sio.manager.basic_enter_room = self._basic_enter_room # report leave rooms - self.sio.manager.__basic_leave_room = \ - self.sio.manager.basic_leave_room + self.sio.manager.__basic_leave_room = self.sio.manager.basic_leave_room self.sio.manager.basic_leave_room = self._basic_leave_room # report emit events @@ -85,44 +93,47 @@ class InstrumentedAsyncServer: self.sio._handle_event_internal = self._handle_event_internal # report engine.io connections - self.sio.eio.on('connect', self._handle_eio_connect) - self.sio.eio.on('disconnect', self._handle_eio_disconnect) + self.sio.eio.on("connect", self._handle_eio_connect) + self.sio.eio.on("disconnect", self._handle_eio_disconnect) # report polling packets from engineio.async_socket import AsyncSocket + self.sio.eio.__ok = self.sio.eio._ok self.sio.eio._ok = self._eio_http_response AsyncSocket.__handle_post_request = AsyncSocket.handle_post_request AsyncSocket.handle_post_request = functools.partialmethod( - self.__class__._eio_handle_post_request, self) + self.__class__._eio_handle_post_request, self + ) # report websocket packets AsyncSocket.__websocket_handler = AsyncSocket._websocket_handler AsyncSocket._websocket_handler = functools.partialmethod( - self.__class__._eio_websocket_handler, self) + self.__class__._eio_websocket_handler, self + ) # report connected sockets with each ping - if self.mode == 'development': + if self.mode == "development": AsyncSocket.__send_ping = AsyncSocket._send_ping AsyncSocket._send_ping = functools.partialmethod( - self.__class__._eio_send_ping, self) + self.__class__._eio_send_ping, self + ) def uninstrument(self): # pragma: no cover - if self.mode == 'development': + if self.mode == "development": self.sio.manager.connect = self.sio.manager.__connect self.sio.manager.disconnect = self.sio.manager.__disconnect - self.sio.manager.basic_enter_room = \ - self.sio.manager.__basic_enter_room - self.sio.manager.basic_leave_room = \ - self.sio.manager.__basic_leave_room + self.sio.manager.basic_enter_room = self.sio.manager.__basic_enter_room + self.sio.manager.basic_leave_room = self.sio.manager.__basic_leave_room self.sio.manager.emit = self.sio.manager.__emit self.sio._handle_event_internal = self.sio.__handle_event_internal self.sio.eio._ok = self.sio.eio.__ok from engineio.async_socket import AsyncSocket + AsyncSocket.handle_post_request = AsyncSocket.__handle_post_request AsyncSocket._websocket_handler = AsyncSocket.__websocket_handler - if self.mode == 'development': + if self.mode == "development": AsyncSocket._send_ping = AsyncSocket.__send_ping async def admin_connect(self, sid, environ, client_auth): @@ -139,53 +150,59 @@ class InstrumentedAsyncServer: else: authenticated = self.auth(client_auth) if not authenticated: - raise ConnectionRefusedError('authentication failed') + raise ConnectionRefusedError("authentication failed") async def config(sid): await self.sio.sleep(0.1) # supported features - features = ['AGGREGATED_EVENTS'] + features = ["AGGREGATED_EVENTS"] if not self.read_only: - features += ['EMIT', 'JOIN', 'LEAVE', 'DISCONNECT', 'MJOIN', - 'MLEAVE', 'MDISCONNECT'] - if self.mode == 'development': - features.append('ALL_EVENTS') - await self.sio.emit('config', {'supportedFeatures': features}, - to=sid, namespace=self.admin_namespace) + features += [ + "EMIT", + "JOIN", + "LEAVE", + "DISCONNECT", + "MJOIN", + "MLEAVE", + "MDISCONNECT", + ] + if self.mode == "development": + features.append("ALL_EVENTS") + await self.sio.emit( + "config", + {"supportedFeatures": features}, + to=sid, + namespace=self.admin_namespace, + ) # send current sockets - if self.mode == 'development': + if self.mode == "development": all_sockets = [] for nsp in self.sio.manager.get_namespaces(): - for sid, eio_sid in self.sio.manager.get_participants( - nsp, None): - all_sockets.append( - self.serialize_socket(sid, nsp, eio_sid)) - await self.sio.emit('all_sockets', all_sockets, to=sid, - namespace=self.admin_namespace) + for sid, eio_sid in self.sio.manager.get_participants(nsp, None): + all_sockets.append(self.serialize_socket(sid, nsp, eio_sid)) + await self.sio.emit( + "all_sockets", all_sockets, to=sid, namespace=self.admin_namespace + ) self.sio.start_background_task(config, sid) self.stop_stats_event = self.sio.eio.create_event() - self.stats_task = self.sio.start_background_task( - self._emit_server_stats) + self.stats_task = self.sio.start_background_task(self._emit_server_stats) async def admin_emit(self, _, namespace, room_filter, event, *data): await self.sio.emit(event, data, to=room_filter, namespace=namespace) async def admin_enter_room(self, _, namespace, room, room_filter=None): - for sid, _ in self.sio.manager.get_participants( - namespace, room_filter): + for sid, _ in self.sio.manager.get_participants(namespace, room_filter): await self.sio.enter_room(sid, room, namespace=namespace) async def admin_leave_room(self, _, namespace, room, room_filter=None): - for sid, _ in self.sio.manager.get_participants( - namespace, room_filter): + for sid, _ in self.sio.manager.get_participants(namespace, room_filter): await self.sio.leave_room(sid, room, namespace=namespace) async def admin_disconnect(self, _, namespace, close, room_filter=None): - for sid, _ in self.sio.manager.get_participants( - namespace, room_filter): + for sid, _ in self.sio.manager.get_participants(namespace, room_filter): await self.sio.disconnect(sid, namespace=namespace) async def shutdown(self): @@ -198,128 +215,161 @@ class InstrumentedAsyncServer: t = time.time() self.sio.manager._timestamps[sid] = t serialized_socket = self.serialize_socket(sid, namespace, eio_sid) - await self.sio.emit('socket_connected', ( - serialized_socket, - datetime.utcfromtimestamp(t).isoformat() + 'Z', - ), namespace=self.admin_namespace) + await self.sio.emit( + "socket_connected", + ( + serialized_socket, + datetime.utcfromtimestamp(t).isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return sid async def _disconnect(self, sid, namespace, **kwargs): del self.sio.manager._timestamps[sid] - await self.sio.emit('socket_disconnected', ( - namespace, - sid, - 'N/A', - datetime.utcnow().isoformat() + 'Z', - ), namespace=self.admin_namespace) + await self.sio.emit( + "socket_disconnected", + ( + namespace, + sid, + "N/A", + datetime.utcnow().isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return await self.sio.manager.__disconnect(sid, namespace, **kwargs) - async def _check_for_upgrade(self, eio_sid, sid, - namespace): # pragma: no cover + async def _check_for_upgrade(self, eio_sid, sid, namespace): # pragma: no cover for _ in range(5): await self.sio.sleep(5) try: if self.sio.eio._get_socket(eio_sid).upgraded: - await self.sio.emit('socket_updated', { - 'id': sid, - 'nsp': namespace, - 'transport': 'websocket', - }, namespace=self.admin_namespace) + await self.sio.emit( + "socket_updated", + { + "id": sid, + "nsp": namespace, + "transport": "websocket", + }, + namespace=self.admin_namespace, + ) break except KeyError: pass def _basic_enter_room(self, sid, namespace, room, eio_sid=None): - ret = self.sio.manager.__basic_enter_room(sid, namespace, room, - eio_sid) + ret = self.sio.manager.__basic_enter_room(sid, namespace, room, eio_sid) if room: - self.admin_queue.append(('room_joined', ( - namespace, - room, - sid, - datetime.utcnow().isoformat() + 'Z', - ))) + self.admin_queue.append( + ( + "room_joined", + ( + namespace, + room, + sid, + datetime.utcnow().isoformat() + "Z", + ), + ) + ) return ret def _basic_leave_room(self, sid, namespace, room): if room: - self.admin_queue.append(('room_left', ( - namespace, - room, - sid, - datetime.utcnow().isoformat() + 'Z', - ))) + self.admin_queue.append( + ( + "room_left", + ( + namespace, + room, + sid, + datetime.utcnow().isoformat() + "Z", + ), + ) + ) return self.sio.manager.__basic_leave_room(sid, namespace, room) - async def _emit(self, event, data, namespace, room=None, skip_sid=None, - callback=None, **kwargs): + async def _emit( + self, event, data, namespace, room=None, skip_sid=None, callback=None, **kwargs + ): ret = await self.sio.manager.__emit( - event, data, namespace, room=room, skip_sid=skip_sid, - callback=callback, **kwargs) + event, + data, + namespace, + room=room, + skip_sid=skip_sid, + callback=callback, + **kwargs, + ) if namespace != self.admin_namespace: - event_data = [event] + list(data) if isinstance(data, tuple) \ - else [data] + event_data = [event] + list(data) if isinstance(data, tuple) else [data] if not isinstance(skip_sid, list): # pragma: no branch skip_sid = [skip_sid] for sid, _ in self.sio.manager.get_participants(namespace, room): if sid not in skip_sid: - await self.sio.emit('event_sent', ( - namespace, - sid, - event_data, - datetime.utcnow().isoformat() + 'Z', - ), namespace=self.admin_namespace) + await self.sio.emit( + "event_sent", + ( + namespace, + sid, + event_data, + datetime.utcnow().isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return ret - async def _handle_event_internal(self, server, sid, eio_sid, data, - namespace, id): - ret = await self.sio.__handle_event_internal(server, sid, eio_sid, - data, namespace, id) - await self.sio.emit('event_received', ( - namespace, - sid, - data, - datetime.utcnow().isoformat() + 'Z', - ), namespace=self.admin_namespace) + async def _handle_event_internal(self, server, sid, eio_sid, data, namespace, id): + ret = await self.sio.__handle_event_internal( + server, sid, eio_sid, data, namespace, id + ) + await self.sio.emit( + "event_received", + ( + namespace, + sid, + data, + datetime.utcnow().isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return ret async def _handle_eio_connect(self, eio_sid, environ): if self.stop_stats_event is None: self.stop_stats_event = self.sio.eio.create_event() - self.stats_task = self.sio.start_background_task( - self._emit_server_stats) + self.stats_task = self.sio.start_background_task(self._emit_server_stats) - self.event_buffer.push('rawConnection') + self.event_buffer.push("rawConnection") return await self.sio._handle_eio_connect(eio_sid, environ) async def _handle_eio_disconnect(self, eio_sid): - self.event_buffer.push('rawDisconnection') + self.event_buffer.push("rawDisconnection") return await self.sio._handle_eio_disconnect(eio_sid) def _eio_http_response(self, packets=None, headers=None, jsonp_index=None): - ret = self.sio.eio.__ok(packets=packets, headers=headers, - jsonp_index=jsonp_index) - self.event_buffer.push('packetsOut') - self.event_buffer.push('bytesOut', len(ret['response'])) + ret = self.sio.eio.__ok( + packets=packets, headers=headers, jsonp_index=jsonp_index + ) + self.event_buffer.push("packetsOut") + self.event_buffer.push("bytesOut", len(ret["response"])) return ret async def _eio_handle_post_request(socket, self, environ): ret = await socket.__handle_post_request(environ) - self.event_buffer.push('packetsIn') - self.event_buffer.push( - 'bytesIn', int(environ.get('CONTENT_LENGTH', 0))) + self.event_buffer.push("packetsIn") + self.event_buffer.push("bytesIn", int(environ.get("CONTENT_LENGTH", 0))) return ret async def _eio_websocket_handler(socket, self, ws): async def _send(ws, data): - self.event_buffer.push('packetsOut') - self.event_buffer.push('bytesOut', len(data)) + self.event_buffer.push("packetsOut") + self.event_buffer.push("bytesOut", len(data)) return await ws.__send(data) async def _wait(ws): ret = await ws.__wait() - self.event_buffer.push('packetsIn') - self.event_buffer.push('bytesIn', len(ret or '')) + self.event_buffer.push("packetsIn") + self.event_buffer.push("bytesIn", len(ret or "")) return ret ws.__send = ws.send @@ -334,12 +384,15 @@ class InstrumentedAsyncServer: for namespace in self.sio.manager.get_namespaces(): sid = self.sio.manager.sid_from_eio_sid(eio_sid, namespace) if sid: - serialized_socket = self.serialize_socket(sid, namespace, - eio_sid) - await self.sio.emit('socket_connected', ( - serialized_socket, - datetime.utcfromtimestamp(t).isoformat() + 'Z', - ), namespace=self.admin_namespace) + serialized_socket = self.serialize_socket(sid, namespace, eio_sid) + await self.sio.emit( + "socket_connected", + ( + serialized_socket, + datetime.utcfromtimestamp(t).isoformat() + "Z", + ), + namespace=self.admin_namespace, + ) return await socket.__send_ping() async def _emit_server_stats(self): @@ -348,51 +401,67 @@ class InstrumentedAsyncServer: namespaces.sort() while not self.stop_stats_event.is_set(): await self.sio.sleep(self.server_stats_interval) - await self.sio.emit('server_stats', { - 'serverId': self.server_id, - 'hostname': HOSTNAME, - 'pid': PID, - 'uptime': time.time() - start_time, - 'clientsCount': len(self.sio.eio.sockets), - 'pollingClientsCount': len( - [s for s in self.sio.eio.sockets.values() - if not s.upgraded]), - 'aggregatedEvents': self.event_buffer.get_and_clear(), - 'namespaces': [{ - 'name': nsp, - 'socketsCount': len(self.sio.manager.rooms.get( - nsp, {None: []}).get(None, [])) - } for nsp in namespaces], - }, namespace=self.admin_namespace) + await self.sio.emit( + "server_stats", + { + "serverId": self.server_id, + "hostname": HOSTNAME, + "pid": PID, + "uptime": time.time() - start_time, + "clientsCount": len(self.sio.eio.sockets), + "pollingClientsCount": len( + [s for s in self.sio.eio.sockets.values() if not s.upgraded] + ), + "aggregatedEvents": self.event_buffer.get_and_clear(), + "namespaces": [ + { + "name": nsp, + "socketsCount": len( + self.sio.manager.rooms.get(nsp, {None: []}).get( + None, [] + ) + ), + } + for nsp in namespaces + ], + }, + namespace=self.admin_namespace, + ) while self.admin_queue: event, args = self.admin_queue.pop(0) - await self.sio.emit(event, args, - namespace=self.admin_namespace) + await self.sio.emit(event, args, namespace=self.admin_namespace) def serialize_socket(self, sid, namespace, eio_sid=None): if eio_sid is None: # pragma: no cover eio_sid = self.sio.manager.eio_sid_from_sid(sid) socket = self.sio.eio._get_socket(eio_sid) environ = self.sio.environ.get(eio_sid, {}) - tm = self.sio.manager._timestamps[sid] if sid in \ - self.sio.manager._timestamps else 0 + tm = ( + self.sio.manager._timestamps[sid] + if sid in self.sio.manager._timestamps + else 0 + ) return { - 'id': sid, - 'clientId': eio_sid, - 'transport': 'websocket' if socket.upgraded else 'polling', - 'nsp': namespace, - 'data': {}, - 'handshake': { - 'address': environ.get('REMOTE_ADDR', ''), - 'headers': {k[5:].lower(): v for k, v in environ.items() - if k.startswith('HTTP_')}, - 'query': {k: v[0] if len(v) == 1 else v for k, v in parse_qs( - environ.get('QUERY_STRING', '')).items()}, - 'secure': environ.get('wsgi.url_scheme', '') == 'https', - 'url': environ.get('PATH_INFO', ''), - 'issued': tm * 1000, - 'time': datetime.utcfromtimestamp(tm).isoformat() + 'Z' - if tm else '', + "id": sid, + "clientId": eio_sid, + "transport": "websocket" if socket.upgraded else "polling", + "nsp": namespace, + "data": {}, + "handshake": { + "address": environ.get("REMOTE_ADDR", ""), + "headers": { + k[5:].lower(): v + for k, v in environ.items() + if k.startswith("HTTP_") + }, + "query": { + k: v[0] if len(v) == 1 else v + for k, v in parse_qs(environ.get("QUERY_STRING", "")).items() + }, + "secure": environ.get("wsgi.url_scheme", "") == "https", + "url": environ.get("PATH_INFO", ""), + "issued": tm * 1000, + "time": datetime.utcfromtimestamp(tm).isoformat() + "Z" if tm else "", }, - 'rooms': self.sio.manager.get_rooms(sid, namespace), + "rooms": self.sio.manager.get_rooms(sid, namespace), } diff --git a/src/socketio/async_aiopika_manager.py b/src/socketio/async_aiopika_manager.py index b6f09b8..cf92595 100644 --- a/src/socketio/async_aiopika_manager.py +++ b/src/socketio/async_aiopika_manager.py @@ -35,14 +35,21 @@ class AsyncAioPikaManager(AsyncPubSubManager): # pragma: no cover and receiving. """ - name = 'asyncaiopika' - - def __init__(self, url='amqp://guest:guest@localhost:5672//', - channel='socketio', write_only=False, logger=None): + name = "asyncaiopika" + + def __init__( + self, + url="amqp://guest:guest@localhost:5672//", + channel="socketio", + write_only=False, + logger=None, + ): if aio_pika is None: - raise RuntimeError('aio_pika package is not installed ' - '(Run "pip install aio_pika" in your ' - 'virtualenv).') + raise RuntimeError( + "aio_pika package is not installed " + '(Run "pip install aio_pika" in your ' + "virtualenv)." + ) self.url = url self._lock = asyncio.Lock() self.publisher_connection = None @@ -57,12 +64,14 @@ class AsyncAioPikaManager(AsyncPubSubManager): # pragma: no cover return await connection.channel() async def _exchange(self, channel): - return await channel.declare_exchange(self.channel, - aio_pika.ExchangeType.FANOUT) + return await channel.declare_exchange( + self.channel, aio_pika.ExchangeType.FANOUT + ) async def _queue(self, channel, exchange): - queue = await channel.declare_queue(durable=False, - arguments={'x-expires': 300000}) + queue = await channel.declare_queue( + durable=False, arguments={"x-expires": 300000} + ) await queue.bind(exchange) return queue @@ -83,25 +92,26 @@ class AsyncAioPikaManager(AsyncPubSubManager): # pragma: no cover await self.publisher_exchange.publish( aio_pika.Message( body=pickle.dumps(data), - delivery_mode=aio_pika.DeliveryMode.PERSISTENT - ), routing_key='*', + delivery_mode=aio_pika.DeliveryMode.PERSISTENT, + ), + routing_key="*", ) break except aio_pika.AMQPException: if retry: - self._get_logger().error('Cannot publish to rabbitmq... ' - 'retrying') + self._get_logger().error( + "Cannot publish to rabbitmq... " "retrying" + ) retry = False else: - self._get_logger().error( - 'Cannot publish to rabbitmq... giving up') + self._get_logger().error("Cannot publish to rabbitmq... giving up") break except aio_pika.exceptions.ChannelInvalidStateError: # aio_pika raises this exception when the task is cancelled raise asyncio.CancelledError() async def _listen(self): - async with (await self._connection()) as connection: + async with await self._connection() as connection: channel = await self._channel(connection) await channel.set_qos(prefetch_count=1) exchange = await self._exchange(channel) @@ -117,8 +127,10 @@ class AsyncAioPikaManager(AsyncPubSubManager): # pragma: no cover retry_sleep = 1 except aio_pika.AMQPException: self._get_logger().error( - 'Cannot receive from rabbitmq... ' - 'retrying in {} secs'.format(retry_sleep)) + "Cannot receive from rabbitmq... " "retrying in {} secs".format( + retry_sleep + ) + ) await asyncio.sleep(retry_sleep) retry_sleep = min(retry_sleep * 2, 60) except aio_pika.exceptions.ChannelInvalidStateError: diff --git a/src/socketio/async_client.py b/src/socketio/async_client.py index 88a6c4c..8bfe15e 100644 --- a/src/socketio/async_client.py +++ b/src/socketio/async_client.py @@ -8,7 +8,7 @@ from . import base_client from . import exceptions from . import packet -default_logger = logging.getLogger('socketio.client') +default_logger = logging.getLogger("socketio.client") class AsyncClient(base_client.BaseClient): @@ -64,12 +64,21 @@ class AsyncClient(base_client.BaseClient): fatal errors are logged even when ``engineio_logger`` is ``False``. """ + def is_asyncio_based(self): return True - async def connect(self, url, headers={}, auth=None, transports=None, - namespaces=None, socketio_path='socket.io', wait=True, - wait_timeout=1): + async def connect( + self, + url, + headers={}, + auth=None, + transports=None, + namespaces=None, + socketio_path="socket.io", + wait=True, + wait_timeout=1, + ): """Connect to a Socket.IO server. :param url: The URL of the Socket.IO server. It can include custom @@ -114,7 +123,7 @@ class AsyncClient(base_client.BaseClient): sio.connect('http://localhost:5000') """ if self.connected: - raise exceptions.ConnectionError('Already connected') + raise exceptions.ConnectionError("Already connected") self.connection_url = url self.connection_headers = headers @@ -124,10 +133,11 @@ class AsyncClient(base_client.BaseClient): self.socketio_path = socketio_path if namespaces is None: - namespaces = list(set(self.handlers.keys()).union( - set(self.namespace_handlers.keys()))) + namespaces = list( + set(self.handlers.keys()).union(set(self.namespace_handlers.keys())) + ) if len(namespaces) == 0: - namespaces = ['/'] + namespaces = ["/"] elif isinstance(namespaces, str): namespaces = [namespaces] self.connection_namespaces = namespaces @@ -139,21 +149,25 @@ class AsyncClient(base_client.BaseClient): real_url = await self._get_real_value(self.connection_url) real_headers = await self._get_real_value(self.connection_headers) try: - await self.eio.connect(real_url, headers=real_headers, - transports=transports, - engineio_path=socketio_path) + await self.eio.connect( + real_url, + headers=real_headers, + transports=transports, + engineio_path=socketio_path, + ) except engineio.exceptions.ConnectionError as exc: for n in self.connection_namespaces: await self._trigger_event( - 'connect_error', n, - exc.args[1] if len(exc.args) > 1 else exc.args[0]) + "connect_error", + n, + exc.args[1] if len(exc.args) > 1 else exc.args[0], + ) raise exceptions.ConnectionError(exc.args[0]) from None if wait: try: while True: - await asyncio.wait_for(self._connect_event.wait(), - wait_timeout) + await asyncio.wait_for(self._connect_event.wait(), wait_timeout) self._connect_event.clear() if set(self.namespaces) == set(self.connection_namespaces): break @@ -162,7 +176,8 @@ class AsyncClient(base_client.BaseClient): if set(self.namespaces) != set(self.connection_namespaces): await self.disconnect() raise exceptions.ConnectionError( - 'One or more namespaces failed to connect') + "One or more namespaces failed to connect" + ) self.connected = True @@ -180,7 +195,7 @@ class AsyncClient(base_client.BaseClient): if not self._reconnect_task: break await self._reconnect_task - if self.eio.state != 'connected': + if self.eio.state != "connected": break async def emit(self, event, data=None, namespace=None, callback=None): @@ -209,10 +224,11 @@ class AsyncClient(base_client.BaseClient): Note 2: this method is a coroutine. """ - namespace = namespace or '/' + namespace = namespace or "/" if namespace not in self.namespaces: raise exceptions.BadNamespaceError( - namespace + ' is not a connected namespace.') + namespace + " is not a connected namespace." + ) self.logger.info('Emitting event "%s" [%s]', event, namespace) if callback is not None: id = self._generate_ack_id(namespace, callback) @@ -226,8 +242,11 @@ class AsyncClient(base_client.BaseClient): data = [data] else: data = [] - await self._send_packet(self.packet_class( - packet.EVENT, namespace=namespace, data=[event] + data, id=id)) + await self._send_packet( + self.packet_class( + packet.EVENT, namespace=namespace, data=[event] + data, id=id + ) + ) async def send(self, data, namespace=None, callback=None): """Send a message to the server. @@ -249,8 +268,7 @@ class AsyncClient(base_client.BaseClient): Note: this method is a coroutine. """ - await self.emit('message', data=data, namespace=namespace, - callback=callback) + await self.emit("message", data=data, namespace=namespace, callback=callback) async def call(self, event, data=None, namespace=None, timeout=60): """Emit a custom event to the server and wait for the response. @@ -290,15 +308,18 @@ class AsyncClient(base_client.BaseClient): callback_args.append(args) callback_event.set() - await self.emit(event, data=data, namespace=namespace, - callback=event_callback) + await self.emit(event, data=data, namespace=namespace, callback=event_callback) try: await asyncio.wait_for(callback_event.wait(), timeout) except asyncio.TimeoutError: raise exceptions.TimeoutError() from None - return callback_args[0] if len(callback_args[0]) > 1 \ - else callback_args[0][0] if len(callback_args[0]) == 1 \ + return ( + callback_args[0] + if len(callback_args[0]) > 1 + else callback_args[0][0] + if len(callback_args[0]) == 1 else None + ) async def disconnect(self): """Disconnect from the server. @@ -308,8 +329,7 @@ class AsyncClient(base_client.BaseClient): # here we just request the disconnection # later in _handle_eio_disconnect we invoke the disconnect handler for n in self.namespaces: - await self._send_packet(self.packet_class(packet.DISCONNECT, - namespace=n)) + await self._send_packet(self.packet_class(packet.DISCONNECT, namespace=n)) await self.eio.disconnect(abort=True) def start_background_task(self, target, *args, **kwargs): @@ -358,19 +378,19 @@ class AsyncClient(base_client.BaseClient): await self.eio.send(encoded_packet) async def _handle_connect(self, namespace, data): - namespace = namespace or '/' + namespace = namespace or "/" if namespace not in self.namespaces: - self.logger.info('Namespace {} is connected'.format(namespace)) - self.namespaces[namespace] = (data or {}).get('sid', self.sid) - await self._trigger_event('connect', namespace=namespace) + self.logger.info("Namespace {} is connected".format(namespace)) + self.namespaces[namespace] = (data or {}).get("sid", self.sid) + await self._trigger_event("connect", namespace=namespace) self._connect_event.set() async def _handle_disconnect(self, namespace): if not self.connected: return - namespace = namespace or '/' - await self._trigger_event('disconnect', namespace=namespace) - await self._trigger_event('__disconnect_final', namespace=namespace) + namespace = namespace or "/" + await self._trigger_event("disconnect", namespace=namespace) + await self._trigger_event("__disconnect_final", namespace=namespace) if namespace in self.namespaces: del self.namespaces[namespace] if not self.namespaces: @@ -378,7 +398,7 @@ class AsyncClient(base_client.BaseClient): await self.eio.disconnect(abort=True) async def _handle_event(self, namespace, id, data): - namespace = namespace or '/' + namespace = namespace or "/" self.logger.info('Received event "%s" [%s]', data[0], namespace) r = await self._trigger_event(data[0], namespace, *data[1:]) if id is not None: @@ -390,18 +410,19 @@ class AsyncClient(base_client.BaseClient): data = list(r) else: data = [r] - await self._send_packet(self.packet_class( - packet.ACK, namespace=namespace, id=id, data=data)) + await self._send_packet( + self.packet_class(packet.ACK, namespace=namespace, id=id, data=data) + ) async def _handle_ack(self, namespace, id, data): - namespace = namespace or '/' - self.logger.info('Received ack [%s]', namespace) + namespace = namespace or "/" + self.logger.info("Received ack [%s]", namespace) callback = None try: callback = self.callbacks[namespace][id] except KeyError: # if we get an unknown callback we just ignore it - self.logger.warning('Unknown callback received, ignoring.') + self.logger.warning("Unknown callback received, ignoring.") else: del self.callbacks[namespace][id] if callback is not None: @@ -411,18 +432,17 @@ class AsyncClient(base_client.BaseClient): callback(*data) async def _handle_error(self, namespace, data): - namespace = namespace or '/' - self.logger.info('Connection to namespace {} was rejected'.format( - namespace)) + namespace = namespace or "/" + self.logger.info("Connection to namespace {} was rejected".format(namespace)) if data is None: data = tuple() elif not isinstance(data, (tuple, list)): data = (data,) - await self._trigger_event('connect_error', namespace, *data) + await self._trigger_event("connect_error", namespace, *data) self._connect_event.set() if namespace in self.namespaces: del self.namespaces[namespace] - if namespace == '/': + if namespace == "/": self.namespaces = {} self.connected = False @@ -433,9 +453,8 @@ class AsyncClient(base_client.BaseClient): handler = None if event in self.handlers[namespace]: handler = self.handlers[namespace][event] - elif event not in self.reserved_events and \ - '*' in self.handlers[namespace]: - handler = self.handlers[namespace]['*'] + elif event not in self.reserved_events and "*" in self.handlers[namespace]: + handler = self.handlers[namespace]["*"] args = (event, *args) if handler: if asyncio.iscoroutinefunction(handler): @@ -449,8 +468,7 @@ class AsyncClient(base_client.BaseClient): # or else, forward the event to a namepsace handler if one exists elif namespace in self.namespace_handlers: - return await self.namespace_handlers[namespace].trigger_event( - event, *args) + return await self.namespace_handlers[namespace].trigger_event(event, *args) async def _handle_reconnect(self): if self._reconnect_abort is None: # pragma: no cover @@ -466,49 +484,51 @@ class AsyncClient(base_client.BaseClient): delay = self.reconnection_delay_max delay += self.randomization_factor * (2 * random.random() - 1) self.logger.info( - 'Connection failed, new attempt in {:.02f} seconds'.format( - delay)) + "Connection failed, new attempt in {:.02f} seconds".format(delay) + ) try: await asyncio.wait_for(self._reconnect_abort.wait(), delay) - self.logger.info('Reconnect task aborted') + self.logger.info("Reconnect task aborted") for n in self.connection_namespaces: - await self._trigger_event('__disconnect_final', - namespace=n) + await self._trigger_event("__disconnect_final", namespace=n) break except (asyncio.TimeoutError, asyncio.CancelledError): pass attempt_count += 1 try: - await self.connect(self.connection_url, - headers=self.connection_headers, - auth=self.connection_auth, - transports=self.connection_transports, - namespaces=self.connection_namespaces, - socketio_path=self.socketio_path) + await self.connect( + self.connection_url, + headers=self.connection_headers, + auth=self.connection_auth, + transports=self.connection_transports, + namespaces=self.connection_namespaces, + socketio_path=self.socketio_path, + ) except (exceptions.ConnectionError, ValueError): pass else: - self.logger.info('Reconnection successful') + self.logger.info("Reconnection successful") self._reconnect_task = None break - if self.reconnection_attempts and \ - attempt_count >= self.reconnection_attempts: - self.logger.info( - 'Maximum reconnection attempts reached, giving up') + if ( + self.reconnection_attempts + and attempt_count >= self.reconnection_attempts + ): + self.logger.info("Maximum reconnection attempts reached, giving up") for n in self.connection_namespaces: - await self._trigger_event('__disconnect_final', - namespace=n) + await self._trigger_event("__disconnect_final", namespace=n) break base_client.reconnecting_clients.remove(self) async def _handle_eio_connect(self): """Handle the Engine.IO connection event.""" - self.logger.info('Engine.IO connection established') + self.logger.info("Engine.IO connection established") self.sid = self.eio.sid real_auth = await self._get_real_value(self.connection_auth) or {} for n in self.connection_namespaces: - await self._send_packet(self.packet_class( - packet.CONNECT, data=real_auth, namespace=n)) + await self._send_packet( + self.packet_class(packet.CONNECT, data=real_auth, namespace=n) + ) async def _handle_eio_message(self, data): """Dispatch Engine.IO messages.""" @@ -530,32 +550,32 @@ class AsyncClient(base_client.BaseClient): await self._handle_event(pkt.namespace, pkt.id, pkt.data) elif pkt.packet_type == packet.ACK: await self._handle_ack(pkt.namespace, pkt.id, pkt.data) - elif pkt.packet_type == packet.BINARY_EVENT or \ - pkt.packet_type == packet.BINARY_ACK: + elif ( + pkt.packet_type == packet.BINARY_EVENT + or pkt.packet_type == packet.BINARY_ACK + ): self._binary_packet = pkt elif pkt.packet_type == packet.CONNECT_ERROR: await self._handle_error(pkt.namespace, pkt.data) else: - raise ValueError('Unknown packet type.') + raise ValueError("Unknown packet type.") async def _handle_eio_disconnect(self): """Handle the Engine.IO disconnection event.""" - self.logger.info('Engine.IO connection dropped') - will_reconnect = self.reconnection and self.eio.state == 'connected' + self.logger.info("Engine.IO connection dropped") + will_reconnect = self.reconnection and self.eio.state == "connected" if self.connected: for n in self.namespaces: - await self._trigger_event('disconnect', namespace=n) + await self._trigger_event("disconnect", namespace=n) if not will_reconnect: - await self._trigger_event('__disconnect_final', - namespace=n) + await self._trigger_event("__disconnect_final", namespace=n) self.namespaces = {} self.connected = False self.callbacks = {} self._binary_packet = None self.sid = None if will_reconnect: - self._reconnect_task = self.start_background_task( - self._handle_reconnect) + self._reconnect_task = self.start_background_task(self._handle_reconnect) def _engineio_client_class(self): return engineio.AsyncClient diff --git a/src/socketio/async_manager.py b/src/socketio/async_manager.py index dcf79cf..ce11da8 100644 --- a/src/socketio/async_manager.py +++ b/src/socketio/async_manager.py @@ -7,11 +7,13 @@ from .base_manager import BaseManager class AsyncManager(BaseManager): """Manage a client list for an asyncio server.""" + async def can_disconnect(self, sid, namespace): return self.is_connected(sid, namespace) - async def emit(self, event, data, namespace, room=None, skip_sid=None, - callback=None, **kwargs): + async def emit( + self, event, data, namespace, room=None, skip_sid=None, callback=None, **kwargs + ): """Emit a message to a single client, a room, or all the clients connected to the namespace. @@ -34,17 +36,20 @@ class AsyncManager(BaseManager): # when callbacks aren't used the packets sent to each recipient are # identical, so they can be generated once and reused pkt = self.server.packet_class( - packet.EVENT, namespace=namespace, data=[event] + data) + packet.EVENT, namespace=namespace, data=[event] + data + ) encoded_packet = pkt.encode() if not isinstance(encoded_packet, list): encoded_packet = [encoded_packet] - eio_pkt = [eio_packet.Packet(eio_packet.MESSAGE, p) - for p in encoded_packet] + eio_pkt = [eio_packet.Packet(eio_packet.MESSAGE, p) for p in encoded_packet] for sid, eio_sid in self.get_participants(namespace, room): if sid not in skip_sid: for p in eio_pkt: - tasks.append(asyncio.create_task( - self.server._send_eio_packet(eio_sid, p))) + tasks.append( + asyncio.create_task( + self.server._send_eio_packet(eio_sid, p) + ) + ) else: # callbacks are used, so each recipient must be sent a packet that # contains a unique callback id @@ -54,10 +59,11 @@ class AsyncManager(BaseManager): if sid not in skip_sid: # pragma: no branch id = self._generate_ack_id(sid, callback) pkt = self.server.packet_class( - packet.EVENT, namespace=namespace, data=[event] + data, - id=id) - tasks.append(asyncio.create_task( - self.server._send_packet(eio_sid, pkt))) + packet.EVENT, namespace=namespace, data=[event] + data, id=id + ) + tasks.append( + asyncio.create_task(self.server._send_packet(eio_sid, pkt)) + ) if tasks == []: # pragma: no cover return await asyncio.wait(tasks) @@ -107,7 +113,7 @@ class AsyncManager(BaseManager): callback = self.callbacks[sid][id] except KeyError: # if we get an unknown callback we just ignore it - self._get_logger().warning('Unknown callback received, ignoring.') + self._get_logger().warning("Unknown callback received, ignoring.") else: del self.callbacks[sid][id] if callback is not None: diff --git a/src/socketio/async_namespace.py b/src/socketio/async_namespace.py index 0a2e051..a6b7a37 100644 --- a/src/socketio/async_namespace.py +++ b/src/socketio/async_namespace.py @@ -16,6 +16,7 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): handlers defined in this class. If this argument is omitted, the default namespace is used. """ + def is_asyncio_based(self): return True @@ -29,7 +30,7 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ - handler_name = 'on_' + event + handler_name = "on_" + event if hasattr(self, handler_name): handler = getattr(self, handler_name) if asyncio.iscoroutinefunction(handler) is True: @@ -41,8 +42,17 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): ret = handler(*args) return ret - async def emit(self, event, data=None, to=None, room=None, skip_sid=None, - namespace=None, callback=None, ignore_queue=False): + async def emit( + self, + event, + data=None, + to=None, + room=None, + skip_sid=None, + namespace=None, + callback=None, + ignore_queue=False, + ): """Emit a custom event to one or more connected clients. The only difference with the :func:`socketio.Server.emit` method is @@ -51,14 +61,27 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ - return await self.server.emit(event, data=data, to=to, room=room, - skip_sid=skip_sid, - namespace=namespace or self.namespace, - callback=callback, - ignore_queue=ignore_queue) - - async def send(self, data, to=None, room=None, skip_sid=None, - namespace=None, callback=None, ignore_queue=False): + return await self.server.emit( + event, + data=data, + to=to, + room=room, + skip_sid=skip_sid, + namespace=namespace or self.namespace, + callback=callback, + ignore_queue=ignore_queue, + ) + + async def send( + self, + data, + to=None, + room=None, + skip_sid=None, + namespace=None, + callback=None, + ignore_queue=False, + ): """Send a message to one or more connected clients. The only difference with the :func:`socketio.Server.send` method is @@ -67,24 +90,41 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ - return await self.server.send(data, to=to, room=room, - skip_sid=skip_sid, - namespace=namespace or self.namespace, - callback=callback, - ignore_queue=ignore_queue) - - async def call(self, event, data=None, to=None, sid=None, namespace=None, - timeout=None, ignore_queue=False): + return await self.server.send( + data, + to=to, + room=room, + skip_sid=skip_sid, + namespace=namespace or self.namespace, + callback=callback, + ignore_queue=ignore_queue, + ) + + async def call( + self, + event, + data=None, + to=None, + sid=None, + namespace=None, + timeout=None, + ignore_queue=False, + ): """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, - ignore_queue=ignore_queue) + return await self.server.call( + event, + data=data, + to=to, + sid=sid, + namespace=namespace or self.namespace, + timeout=timeout, + ignore_queue=ignore_queue, + ) async def enter_room(self, sid, room, namespace=None): """Enter a room. @@ -96,7 +136,8 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ return await self.server.enter_room( - sid, room, namespace=namespace or self.namespace) + sid, room, namespace=namespace or self.namespace + ) async def leave_room(self, sid, room, namespace=None): """Leave a room. @@ -108,7 +149,8 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ return await self.server.leave_room( - sid, room, namespace=namespace or self.namespace) + sid, room, namespace=namespace or self.namespace + ) async def close_room(self, room, namespace=None): """Close a room. @@ -119,8 +161,7 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ - return await self.server.close_room( - room, namespace=namespace or self.namespace) + return await self.server.close_room(room, namespace=namespace or self.namespace) async def get_session(self, sid, namespace=None): """Return the user session for a client. @@ -131,8 +172,7 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ - return await self.server.get_session( - sid, namespace=namespace or self.namespace) + return await self.server.get_session(sid, namespace=namespace or self.namespace) async def save_session(self, sid, session, namespace=None): """Store the user session for a client. @@ -144,7 +184,8 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ return await self.server.save_session( - sid, session, namespace=namespace or self.namespace) + sid, session, namespace=namespace or self.namespace + ) def session(self, sid, namespace=None): """Return the user session for a client with context manager syntax. @@ -164,8 +205,7 @@ class AsyncNamespace(base_namespace.BaseServerNamespace): Note: this method is a coroutine. """ - return await self.server.disconnect( - sid, namespace=namespace or self.namespace) + return await self.server.disconnect(sid, namespace=namespace or self.namespace) class AsyncClientNamespace(base_namespace.BaseClientNamespace): @@ -181,6 +221,7 @@ class AsyncClientNamespace(base_namespace.BaseClientNamespace): handlers defined in this class. If this argument is omitted, the default namespace is used. """ + def is_asyncio_based(self): return True @@ -194,7 +235,7 @@ class AsyncClientNamespace(base_namespace.BaseClientNamespace): Note: this method is a coroutine. """ - handler_name = 'on_' + event + handler_name = "on_" + event if hasattr(self, handler_name): handler = getattr(self, handler_name) if asyncio.iscoroutinefunction(handler) is True: @@ -215,9 +256,9 @@ class AsyncClientNamespace(base_namespace.BaseClientNamespace): Note: this method is a coroutine. """ - return await self.client.emit(event, data=data, - namespace=namespace or self.namespace, - callback=callback) + return await self.client.emit( + event, data=data, namespace=namespace or self.namespace, callback=callback + ) async def send(self, data, namespace=None, callback=None): """Send a message to the server. @@ -228,9 +269,9 @@ class AsyncClientNamespace(base_namespace.BaseClientNamespace): Note: this method is a coroutine. """ - return await self.client.send(data, - namespace=namespace or self.namespace, - callback=callback) + return await self.client.send( + data, 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. @@ -239,9 +280,9 @@ class AsyncClientNamespace(base_namespace.BaseClientNamespace): 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) + return await self.client.call( + event, data=data, namespace=namespace or self.namespace, timeout=timeout + ) async def disconnect(self): """Disconnect a client. diff --git a/src/socketio/async_pubsub_manager.py b/src/socketio/async_pubsub_manager.py index c9d00b0..5799c00 100644 --- a/src/socketio/async_pubsub_manager.py +++ b/src/socketio/async_pubsub_manager.py @@ -22,9 +22,10 @@ class AsyncPubSubManager(AsyncManager): :param channel: The channel name on which the server sends and receives notifications. """ - name = 'asyncpubsub' - def __init__(self, channel='socketio', write_only=False, logger=None): + name = "asyncpubsub" + + def __init__(self, channel="socketio", write_only=False, logger=None): super().__init__() self.channel = channel self.write_only = write_only @@ -35,10 +36,18 @@ class AsyncPubSubManager(AsyncManager): super().initialize() if not self.write_only: self.thread = self.server.start_background_task(self._thread) - self._get_logger().info(self.name + ' backend initialized.') + self._get_logger().info(self.name + " backend initialized.") - async def emit(self, event, data, namespace=None, room=None, skip_sid=None, - callback=None, **kwargs): + async def emit( + self, + event, + data, + namespace=None, + room=None, + skip_sid=None, + callback=None, + **kwargs, + ): """Emit a message to a single client, a room, or all the clients connected to the namespace. @@ -49,25 +58,37 @@ class AsyncPubSubManager(AsyncManager): Note: this method is a coroutine. """ - if kwargs.get('ignore_queue'): + if kwargs.get("ignore_queue"): return await super().emit( - event, data, namespace=namespace, room=room, skip_sid=skip_sid, - callback=callback) - namespace = namespace or '/' + event, + data, + namespace=namespace, + room=room, + skip_sid=skip_sid, + callback=callback, + ) + namespace = namespace or "/" if callback is not None: if self.server is None: - raise RuntimeError('Callbacks can only be issued from the ' - 'context of a server.') + raise RuntimeError( + "Callbacks can only be issued from the " "context of a server." + ) if room is None: - raise ValueError('Cannot use callback without a room set.') + raise ValueError("Cannot use callback without a room set.") id = self._generate_ack_id(room, callback) callback = (room, namespace, id) else: callback = None - message = {'method': 'emit', 'event': event, 'data': data, - 'namespace': namespace, 'room': room, - 'skip_sid': skip_sid, 'callback': callback, - 'host_id': self.host_id} + message = { + "method": "emit", + "event": event, + "data": data, + "namespace": namespace, + "room": room, + "skip_sid": skip_sid, + "callback": callback, + "host_id": self.host_id, + } await self._handle_emit(message) # handle in this host await self._publish(message) # notify other hosts @@ -77,27 +98,39 @@ class AsyncPubSubManager(AsyncManager): return await super().can_disconnect(sid, namespace) else: # client is in another server, so we post request to the queue - await self._publish({'method': 'disconnect', 'sid': sid, - 'namespace': namespace or '/', - 'host_id': self.host_id}) + await self._publish( + { + "method": "disconnect", + "sid": sid, + "namespace": namespace or "/", + "host_id": self.host_id, + } + ) async def disconnect(self, sid, namespace, **kwargs): - if kwargs.get('ignore_queue'): - return await super().disconnect( - sid, namespace=namespace) - message = {'method': 'disconnect', 'sid': sid, - 'namespace': namespace or '/', 'host_id': self.host_id} + if kwargs.get("ignore_queue"): + return await super().disconnect(sid, namespace=namespace) + message = { + "method": "disconnect", + "sid": sid, + "namespace": namespace or "/", + "host_id": self.host_id, + } await self._handle_disconnect(message) # handle in this host await self._publish(message) # notify other hosts async def enter_room(self, sid, namespace, room, eio_sid=None): if self.is_connected(sid, namespace): # client is in this server, so we can disconnect directly - return await super().enter_room(sid, namespace, room, - eio_sid=eio_sid) + return await super().enter_room(sid, namespace, room, eio_sid=eio_sid) else: - message = {'method': 'enter_room', 'sid': sid, 'room': room, - 'namespace': namespace or '/', 'host_id': self.host_id} + message = { + "method": "enter_room", + "sid": sid, + "room": room, + "namespace": namespace or "/", + "host_id": self.host_id, + } await self._publish(message) # notify other hosts async def leave_room(self, sid, namespace, room): @@ -105,13 +138,22 @@ class AsyncPubSubManager(AsyncManager): # client is in this server, so we can disconnect directly return await super().leave_room(sid, namespace, room) else: - message = {'method': 'leave_room', 'sid': sid, 'room': room, - 'namespace': namespace or '/', 'host_id': self.host_id} + message = { + "method": "leave_room", + "sid": sid, + "room": room, + "namespace": namespace or "/", + "host_id": self.host_id, + } await self._publish(message) # notify other hosts async def close_room(self, room, namespace=None): - message = {'method': 'close_room', 'room': room, - 'namespace': namespace or '/', 'host_id': self.host_id} + message = { + "method": "close_room", + "room": room, + "namespace": namespace or "/", + "host_id": self.host_id, + } await self._handle_close_room(message) # handle in this host await self._publish(message) # notify other hosts @@ -121,8 +163,9 @@ class AsyncPubSubManager(AsyncManager): This method needs to be implemented by the different subclasses that support pub/sub backends. """ - raise NotImplementedError('This method must be implemented in a ' - 'subclass.') # pragma: no cover + raise NotImplementedError( + "This method must be implemented in a " "subclass." + ) # pragma: no cover async def _listen(self): """Return the next message published on the Socket.IO channel, @@ -131,67 +174,79 @@ class AsyncPubSubManager(AsyncManager): This method needs to be implemented by the different subclasses that support pub/sub backends. """ - raise NotImplementedError('This method must be implemented in a ' - 'subclass.') # pragma: no cover + raise NotImplementedError( + "This method must be implemented in a " "subclass." + ) # pragma: no cover async def _handle_emit(self, message): # Events with callbacks are very tricky to handle across hosts # Here in the receiving end we set up a local callback that preserves # the callback host and id from the sender - remote_callback = message.get('callback') - remote_host_id = message.get('host_id') + remote_callback = message.get("callback") + remote_host_id = message.get("host_id") if remote_callback is not None and len(remote_callback) == 3: - callback = partial(self._return_callback, remote_host_id, - *remote_callback) + callback = partial(self._return_callback, remote_host_id, *remote_callback) else: callback = None - await super().emit(message['event'], message['data'], - namespace=message.get('namespace'), - room=message.get('room'), - skip_sid=message.get('skip_sid'), - callback=callback) + await super().emit( + message["event"], + message["data"], + namespace=message.get("namespace"), + room=message.get("room"), + skip_sid=message.get("skip_sid"), + callback=callback, + ) async def _handle_callback(self, message): - if self.host_id == message.get('host_id'): + if self.host_id == message.get("host_id"): try: - sid = message['sid'] - id = message['id'] - args = message['args'] + sid = message["sid"] + id = message["id"] + args = message["args"] except KeyError: return await self.trigger_callback(sid, id, args) - async def _return_callback(self, host_id, sid, namespace, callback_id, - *args): + async def _return_callback(self, host_id, sid, namespace, callback_id, *args): # When an event callback is received, the callback is returned back # the sender, which is identified by the host_id if host_id == self.host_id: await self.trigger_callback(sid, callback_id, args) else: - await self._publish({'method': 'callback', 'host_id': host_id, - 'sid': sid, 'namespace': namespace, - 'id': callback_id, 'args': args}) + await self._publish( + { + "method": "callback", + "host_id": host_id, + "sid": sid, + "namespace": namespace, + "id": callback_id, + "args": args, + } + ) async def _handle_disconnect(self, message): - await self.server.disconnect(sid=message.get('sid'), - namespace=message.get('namespace'), - ignore_queue=True) + await self.server.disconnect( + sid=message.get("sid"), + namespace=message.get("namespace"), + ignore_queue=True, + ) async def _handle_enter_room(self, message): - sid = message.get('sid') - namespace = message.get('namespace') + sid = message.get("sid") + namespace = message.get("namespace") if self.is_connected(sid, namespace): - await super().enter_room(sid, namespace, message.get('room')) + await super().enter_room(sid, namespace, message.get("room")) async def _handle_leave_room(self, message): - sid = message.get('sid') - namespace = message.get('namespace') + sid = message.get("sid") + namespace = message.get("namespace") if self.is_connected(sid, namespace): - await super().leave_room(sid, namespace, message.get('room')) + await super().leave_room(sid, namespace, message.get("room")) async def _handle_close_room(self, message): - await super().close_room(room=message.get('room'), - namespace=message.get('namespace')) + await super().close_room( + room=message.get("room"), namespace=message.get("namespace") + ) async def _thread(self): while True: @@ -211,30 +266,33 @@ class AsyncPubSubManager(AsyncManager): data = json.loads(message) except: pass - if data and 'method' in data: - self._get_logger().debug('pubsub message: {}'.format( - data['method'])) + if data and "method" in data: + self._get_logger().debug( + "pubsub message: {}".format(data["method"]) + ) try: - if data['method'] == 'callback': + if data["method"] == "callback": await self._handle_callback(data) - elif data.get('host_id') != self.host_id: - if data['method'] == 'emit': + elif data.get("host_id") != self.host_id: + if data["method"] == "emit": await self._handle_emit(data) - elif data['method'] == 'disconnect': + elif data["method"] == "disconnect": await self._handle_disconnect(data) - elif data['method'] == 'enter_room': + elif data["method"] == "enter_room": await self._handle_enter_room(data) - elif data['method'] == 'leave_room': + elif data["method"] == "leave_room": await self._handle_leave_room(data) - elif data['method'] == 'close_room': + elif data["method"] == "close_room": await self._handle_close_room(data) except asyncio.CancelledError: raise # let the outer try/except handle it except: self.server.logger.exception( - 'Unknown error in pubsub listening task') + "Unknown error in pubsub listening task" + ) except asyncio.CancelledError: # pragma: no cover break except: # pragma: no cover import traceback + traceback.print_exc() diff --git a/src/socketio/async_redis_manager.py b/src/socketio/async_redis_manager.py index e039c6e..ffabad1 100644 --- a/src/socketio/async_redis_manager.py +++ b/src/socketio/async_redis_manager.py @@ -39,23 +39,31 @@ class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover :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, redis_options=None): + name = "aioredis" + + def __init__( + self, + url="redis://localhost:6379/0", + channel="socketio", + write_only=False, + logger=None, + redis_options=None, + ): if aioredis is None: - raise RuntimeError('Redis package is not installed ' - '(Run "pip install redis" in your virtualenv).') - if not hasattr(aioredis.Redis, 'from_url'): - raise RuntimeError('Version 2 of aioredis package is required.') + raise RuntimeError( + "Redis package is not installed " + '(Run "pip install redis" in your virtualenv).' + ) + 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.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): @@ -64,16 +72,13 @@ class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover try: if not retry: self._redis_connect() - return await self.redis.publish( - self.channel, pickle.dumps(data)) + return await self.redis.publish(self.channel, pickle.dumps(data)) except RedisError: if retry: - self._get_logger().error('Cannot publish to redis... ' - 'retrying') + self._get_logger().error("Cannot publish to redis... " "retrying") retry = False else: - self._get_logger().error('Cannot publish to redis... ' - 'giving up') + self._get_logger().error("Cannot publish to redis... " "giving up") break async def _redis_listen_with_retries(self): @@ -88,9 +93,11 @@ class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover async for message in self.pubsub.listen(): yield message except RedisError: - self._get_logger().error('Cannot receive from redis... ' - 'retrying in ' - '{} secs'.format(retry_sleep)) + self._get_logger().error( + "Cannot receive from redis... " "retrying in " "{} secs".format( + retry_sleep + ) + ) connect = True await asyncio.sleep(retry_sleep) retry_sleep *= 2 @@ -98,10 +105,13 @@ class AsyncRedisManager(AsyncPubSubManager): # pragma: no cover retry_sleep = 60 async def _listen(self): - channel = self.channel.encode('utf-8') + 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'] + if ( + message["channel"] == channel + and message["type"] == "message" + and "data" in message + ): + yield message["data"] await self.pubsub.unsubscribe(self.channel) diff --git a/src/socketio/async_server.py b/src/socketio/async_server.py index 99af067..f07e7c1 100644 --- a/src/socketio/async_server.py +++ b/src/socketio/async_server.py @@ -101,23 +101,45 @@ class AsyncServer(base_server.BaseServer): fatal errors are logged even when ``engineio_logger`` is ``False``. """ - def __init__(self, client_manager=None, logger=False, json=None, - async_handlers=True, namespaces=None, **kwargs): + + def __init__( + self, + client_manager=None, + logger=False, + json=None, + async_handlers=True, + namespaces=None, + **kwargs, + ): if client_manager is None: client_manager = async_manager.AsyncManager() - super().__init__(client_manager=client_manager, logger=logger, - json=json, async_handlers=async_handlers, - namespaces=namespaces, **kwargs) + super().__init__( + client_manager=client_manager, + logger=logger, + json=json, + async_handlers=async_handlers, + namespaces=namespaces, + **kwargs, + ) def is_asyncio_based(self): return True - def attach(self, app, socketio_path='socket.io'): + def attach(self, app, socketio_path="socket.io"): """Attach the Socket.IO server to an application.""" self.eio.attach(app, socketio_path) - async def emit(self, event, data=None, to=None, room=None, skip_sid=None, - namespace=None, callback=None, ignore_queue=False): + async def emit( + self, + event, + data=None, + to=None, + room=None, + skip_sid=None, + namespace=None, + callback=None, + ignore_queue=False, + ): """Emit a custom event to one or more connected clients. :param event: The event name. It can be any string. The event names @@ -161,16 +183,31 @@ class AsyncServer(base_server.BaseServer): Note 2: this method is a coroutine. """ - namespace = namespace or '/' + namespace = namespace or "/" room = to or room - self.logger.info('emitting event "%s" to %s [%s]', event, - room or 'all', namespace) - await self.manager.emit(event, data, namespace, room=room, - skip_sid=skip_sid, callback=callback, - ignore_queue=ignore_queue) - - async def send(self, data, to=None, room=None, skip_sid=None, - namespace=None, callback=None, ignore_queue=False): + self.logger.info( + 'emitting event "%s" to %s [%s]', event, room or "all", namespace + ) + await self.manager.emit( + event, + data, + namespace, + room=room, + skip_sid=skip_sid, + callback=callback, + ignore_queue=ignore_queue, + ) + + async def send( + self, + data, + to=None, + room=None, + skip_sid=None, + namespace=None, + callback=None, + ignore_queue=False, + ): """Send a message to one or more connected clients. This function emits an event with the name ``'message'``. Use @@ -208,12 +245,27 @@ class AsyncServer(base_server.BaseServer): Note: this method is a coroutine. """ - await self.emit('message', data=data, to=to, room=room, - skip_sid=skip_sid, namespace=namespace, - callback=callback, ignore_queue=ignore_queue) - - async def call(self, event, data=None, to=None, sid=None, namespace=None, - timeout=60, ignore_queue=False): + await self.emit( + "message", + data=data, + to=to, + room=room, + skip_sid=skip_sid, + namespace=namespace, + callback=callback, + ignore_queue=ignore_queue, + ) + + async def call( + self, + event, + data=None, + to=None, + sid=None, + namespace=None, + timeout=60, + ignore_queue=False, + ): """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 @@ -254,10 +306,9 @@ class AsyncServer(base_server.BaseServer): Note 2: this method is a coroutine. """ if to is None and sid is None: - raise ValueError('Cannot use call() to broadcast.') + raise ValueError("Cannot use call() to broadcast.") if not self.async_handlers: - raise RuntimeError( - 'Cannot use call() when async_handlers is False.') + raise RuntimeError("Cannot use call() when async_handlers is False.") callback_event = self.eio.create_event() callback_args = [] @@ -265,15 +316,25 @@ class AsyncServer(base_server.BaseServer): callback_args.append(args) callback_event.set() - await self.emit(event, data=data, room=to or sid, namespace=namespace, - callback=event_callback, ignore_queue=ignore_queue) + await self.emit( + event, + data=data, + room=to or sid, + namespace=namespace, + callback=event_callback, + ignore_queue=ignore_queue, + ) try: await asyncio.wait_for(callback_event.wait(), timeout) except asyncio.TimeoutError: raise exceptions.TimeoutError() from None - return callback_args[0] if len(callback_args[0]) > 1 \ - else callback_args[0][0] if len(callback_args[0]) == 1 \ + return ( + callback_args[0] + if len(callback_args[0]) > 1 + else callback_args[0][0] + if len(callback_args[0]) == 1 else None + ) async def enter_room(self, sid, room, namespace=None): """Enter a room. @@ -289,8 +350,8 @@ class AsyncServer(base_server.BaseServer): Note: this method is a coroutine. """ - namespace = namespace or '/' - self.logger.info('%s is entering room %s [%s]', sid, room, namespace) + namespace = namespace or "/" + self.logger.info("%s is entering room %s [%s]", sid, room, namespace) await self.manager.enter_room(sid, namespace, room) async def leave_room(self, sid, room, namespace=None): @@ -305,8 +366,8 @@ class AsyncServer(base_server.BaseServer): Note: this method is a coroutine. """ - namespace = namespace or '/' - self.logger.info('%s is leaving room %s [%s]', sid, room, namespace) + namespace = namespace or "/" + self.logger.info("%s is leaving room %s [%s]", sid, room, namespace) await self.manager.leave_room(sid, namespace, room) async def close_room(self, room, namespace=None): @@ -320,8 +381,8 @@ class AsyncServer(base_server.BaseServer): Note: this method is a coroutine. """ - namespace = namespace or '/' - self.logger.info('room %s is closing [%s]', room, namespace) + namespace = namespace or "/" + self.logger.info("room %s is closing [%s]", room, namespace) await self.manager.close_room(room, namespace) async def get_session(self, sid, namespace=None): @@ -335,7 +396,7 @@ class AsyncServer(base_server.BaseServer): dictionary are not guaranteed to be preserved. If you want to modify the user session, use the ``session`` context manager instead. """ - namespace = namespace or '/' + namespace = namespace or "/" eio_sid = self.manager.eio_sid_from_sid(sid, namespace) eio_session = await self.eio.get_session(eio_sid) return eio_session.setdefault(namespace, {}) @@ -348,7 +409,7 @@ class AsyncServer(base_server.BaseServer): :param namespace: The Socket.IO namespace. If this argument is omitted the default namespace is used. """ - namespace = namespace or '/' + namespace = namespace or "/" eio_sid = self.manager.eio_sid_from_sid(sid, namespace) eio_session = await self.eio.get_session(eio_sid) eio_session[namespace] = session @@ -375,6 +436,7 @@ class AsyncServer(base_server.BaseServer): async with eio.session(sid) as session: print('received message from ', session['username']) """ + class _session_context_manager(object): def __init__(self, server, sid, namespace): self.server = server @@ -384,12 +446,14 @@ class AsyncServer(base_server.BaseServer): async def __aenter__(self): self.session = await self.server.get_session( - sid, namespace=self.namespace) + sid, namespace=self.namespace + ) return self.session async def __aexit__(self, *args): - await self.server.save_session(sid, self.session, - namespace=self.namespace) + await self.server.save_session( + sid, self.session, namespace=self.namespace + ) return _session_context_manager(self, sid, namespace) @@ -407,19 +471,19 @@ class AsyncServer(base_server.BaseServer): Note: this method is a coroutine. """ - namespace = namespace or '/' + namespace = namespace or "/" if ignore_queue: delete_it = self.manager.is_connected(sid, namespace) else: delete_it = await self.manager.can_disconnect(sid, namespace) if delete_it: - self.logger.info('Disconnecting %s [%s]', sid, namespace) + self.logger.info("Disconnecting %s [%s]", sid, namespace) eio_sid = self.manager.pre_disconnect(sid, namespace=namespace) - await self._send_packet(eio_sid, self.packet_class( - packet.DISCONNECT, namespace=namespace)) - await self._trigger_event('disconnect', namespace, sid) - await self.manager.disconnect(sid, namespace=namespace, - ignore_queue=True) + await self._send_packet( + eio_sid, self.packet_class(packet.DISCONNECT, namespace=namespace) + ) + await self._trigger_event("disconnect", namespace, sid) + await self.manager.disconnect(sid, namespace=namespace, ignore_queue=True) async def shutdown(self): """Stop Socket.IO background tasks. @@ -427,7 +491,7 @@ class AsyncServer(base_server.BaseServer): This method stops all background activity initiated by the Socket.IO server. It must be called before shutting down the web server. """ - self.logger.info('Socket.IO is shutting down') + self.logger.info("Socket.IO is shutting down") await self.eio.shutdown() async def handle_request(self, *args, **kwargs): @@ -467,9 +531,15 @@ class AsyncServer(base_server.BaseServer): """ return await self.eio.sleep(seconds) - def instrument(self, auth=None, mode='development', read_only=False, - server_id=None, namespace='/admin', - server_stats_interval=2): + def instrument( + self, + auth=None, + mode="development", + read_only=False, + server_id=None, + namespace="/admin", + server_stats_interval=2, + ): """Instrument the Socket.IO server for monitoring with the `Socket.IO Admin UI `_. @@ -501,10 +571,16 @@ class AsyncServer(base_server.BaseServer): connected admins. """ from .async_admin import InstrumentedAsyncServer + return InstrumentedAsyncServer( - self, auth=auth, mode=mode, read_only=read_only, - server_id=server_id, namespace=namespace, - server_stats_interval=server_stats_interval) + self, + auth=auth, + mode=mode, + read_only=read_only, + server_id=server_id, + namespace=namespace, + server_stats_interval=server_stats_interval, + ) async def _send_packet(self, eio_sid, pkt): """Send a Socket.IO packet to a client.""" @@ -521,32 +597,44 @@ class AsyncServer(base_server.BaseServer): async def _handle_connect(self, eio_sid, namespace, data): """Handle a client connection request.""" - namespace = namespace or '/' + namespace = namespace or "/" sid = None - if namespace in self.handlers or namespace in self.namespace_handlers \ - or self.namespaces == '*' or namespace in self.namespaces: + if ( + namespace in self.handlers + or namespace in self.namespace_handlers + or self.namespaces == "*" + or namespace in self.namespaces + ): sid = await self.manager.connect(eio_sid, namespace) if sid is None: - await self._send_packet(eio_sid, self.packet_class( - packet.CONNECT_ERROR, data='Unable to connect', - namespace=namespace)) + await self._send_packet( + eio_sid, + self.packet_class( + packet.CONNECT_ERROR, data="Unable to connect", namespace=namespace + ), + ) return if self.always_connect: - await self._send_packet(eio_sid, self.packet_class( - packet.CONNECT, {'sid': sid}, namespace=namespace)) + await self._send_packet( + eio_sid, + self.packet_class(packet.CONNECT, {"sid": sid}, namespace=namespace), + ) fail_reason = exceptions.ConnectionRefusedError().error_args try: if data: success = await self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid], data) + "connect", namespace, sid, self.environ[eio_sid], data + ) else: try: success = await self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid]) + "connect", namespace, sid, self.environ[eio_sid] + ) except TypeError: success = await self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid], None) + "connect", namespace, sid, self.environ[eio_sid], None + ) except exceptions.ConnectionRefusedError as exc: fail_reason = exc.error_args success = False @@ -554,46 +642,52 @@ class AsyncServer(base_server.BaseServer): if success is False: if self.always_connect: self.manager.pre_disconnect(sid, namespace) - await self._send_packet(eio_sid, self.packet_class( - packet.DISCONNECT, data=fail_reason, namespace=namespace)) + await self._send_packet( + eio_sid, + self.packet_class( + packet.DISCONNECT, data=fail_reason, namespace=namespace + ), + ) else: - await self._send_packet(eio_sid, self.packet_class( - packet.CONNECT_ERROR, data=fail_reason, - namespace=namespace)) + await self._send_packet( + eio_sid, + self.packet_class( + packet.CONNECT_ERROR, data=fail_reason, namespace=namespace + ), + ) await self.manager.disconnect(sid, namespace, ignore_queue=True) elif not self.always_connect: - await self._send_packet(eio_sid, self.packet_class( - packet.CONNECT, {'sid': sid}, namespace=namespace)) + await self._send_packet( + eio_sid, + self.packet_class(packet.CONNECT, {"sid": sid}, namespace=namespace), + ) async def _handle_disconnect(self, eio_sid, namespace): """Handle a client disconnect.""" - namespace = namespace or '/' + namespace = namespace or "/" sid = self.manager.sid_from_eio_sid(eio_sid, namespace) if not self.manager.is_connected(sid, namespace): # pragma: no cover return self.manager.pre_disconnect(sid, namespace=namespace) - await self._trigger_event('disconnect', namespace, sid) + await self._trigger_event("disconnect", namespace, sid) await self.manager.disconnect(sid, namespace, ignore_queue=True) async def _handle_event(self, eio_sid, namespace, id, data): """Handle an incoming client event.""" - namespace = namespace or '/' + namespace = namespace or "/" sid = self.manager.sid_from_eio_sid(eio_sid, namespace) - self.logger.info('received event "%s" from %s [%s]', data[0], sid, - namespace) + self.logger.info('received event "%s" from %s [%s]', data[0], sid, namespace) if not self.manager.is_connected(sid, namespace): - self.logger.warning('%s is not connected to namespace %s', - sid, namespace) + self.logger.warning("%s is not connected to namespace %s", sid, namespace) return if self.async_handlers: - self.start_background_task(self._handle_event_internal, self, sid, - eio_sid, data, namespace, id) + self.start_background_task( + self._handle_event_internal, self, sid, eio_sid, data, namespace, id + ) else: - await self._handle_event_internal(self, sid, eio_sid, data, - namespace, id) + await self._handle_event_internal(self, sid, eio_sid, data, namespace, id) - async def _handle_event_internal(self, server, sid, eio_sid, data, - namespace, id): + async def _handle_event_internal(self, server, sid, eio_sid, data, namespace, id): r = await server._trigger_event(data[0], namespace, sid, *data[1:]) if r != self.not_handled and id is not None: # send ACK packet with the response returned by the handler @@ -604,14 +698,16 @@ class AsyncServer(base_server.BaseServer): data = list(r) else: data = [r] - await server._send_packet(eio_sid, self.packet_class( - packet.ACK, namespace=namespace, id=id, data=data)) + await server._send_packet( + eio_sid, + self.packet_class(packet.ACK, namespace=namespace, id=id, data=data), + ) async def _handle_ack(self, eio_sid, namespace, id, data): """Handle ACK packets from the client.""" - namespace = namespace or '/' + namespace = namespace or "/" sid = self.manager.sid_from_eio_sid(eio_sid, namespace) - self.logger.info('received ack from %s [%s]', sid, namespace) + self.logger.info("received ack from %s [%s]", sid, namespace) await self.manager.trigger_callback(sid, id, data) async def _trigger_event(self, event, namespace, *args): @@ -621,9 +717,8 @@ class AsyncServer(base_server.BaseServer): handler = None if event in self.handlers[namespace]: handler = self.handlers[namespace][event] - elif event not in self.reserved_events and \ - '*' in self.handlers[namespace]: - handler = self.handlers[namespace]['*'] + elif event not in self.reserved_events and "*" in self.handlers[namespace]: + handler = self.handlers[namespace]["*"] args = (event, *args) if handler: if asyncio.iscoroutinefunction(handler): @@ -639,8 +734,7 @@ class AsyncServer(base_server.BaseServer): # or else, forward the event to a namepsace handler if one exists elif namespace in self.namespace_handlers: # pragma: no branch - return await self.namespace_handlers[namespace].trigger_event( - event, *args) + return await self.namespace_handlers[namespace].trigger_event(event, *args) async def _handle_eio_connect(self, eio_sid, environ): """Handle the Engine.IO connection event.""" @@ -656,11 +750,9 @@ class AsyncServer(base_server.BaseServer): if pkt.add_attachment(data): del self._binary_packet[eio_sid] if pkt.packet_type == packet.BINARY_EVENT: - await self._handle_event(eio_sid, pkt.namespace, pkt.id, - pkt.data) + await self._handle_event(eio_sid, pkt.namespace, pkt.id, pkt.data) else: - await self._handle_ack(eio_sid, pkt.namespace, pkt.id, - pkt.data) + await self._handle_ack(eio_sid, pkt.namespace, pkt.id, pkt.data) else: pkt = self.packet_class(encoded_packet=data) if pkt.packet_type == packet.CONNECT: @@ -668,18 +760,18 @@ class AsyncServer(base_server.BaseServer): elif pkt.packet_type == packet.DISCONNECT: await self._handle_disconnect(eio_sid, pkt.namespace) elif pkt.packet_type == packet.EVENT: - await self._handle_event(eio_sid, pkt.namespace, pkt.id, - pkt.data) + await self._handle_event(eio_sid, pkt.namespace, pkt.id, pkt.data) elif pkt.packet_type == packet.ACK: - await self._handle_ack(eio_sid, pkt.namespace, pkt.id, - pkt.data) - elif pkt.packet_type == packet.BINARY_EVENT or \ - pkt.packet_type == packet.BINARY_ACK: + await self._handle_ack(eio_sid, pkt.namespace, pkt.id, pkt.data) + elif ( + pkt.packet_type == packet.BINARY_EVENT + or pkt.packet_type == packet.BINARY_ACK + ): self._binary_packet[eio_sid] = pkt elif pkt.packet_type == packet.CONNECT_ERROR: - raise ValueError('Unexpected CONNECT_ERROR packet.') + raise ValueError("Unexpected CONNECT_ERROR packet.") else: - raise ValueError('Unknown packet type.') + raise ValueError("Unknown packet type.") async def _handle_eio_disconnect(self, eio_sid): """Handle Engine.IO disconnect event.""" diff --git a/src/socketio/async_simple_client.py b/src/socketio/async_simple_client.py index db90784..55740e4 100644 --- a/src/socketio/async_simple_client.py +++ b/src/socketio/async_simple_client.py @@ -12,19 +12,27 @@ class AsyncSimpleClient: Th positional and keyword arguments given in the constructor are passed to the underlying :func:`socketio.AsyncClient` object. """ + def __init__(self, *args, **kwargs): self.client_args = args self.client_kwargs = kwargs self.client = None - self.namespace = '/' + self.namespace = "/" self.connected_event = asyncio.Event() self.connected = False self.input_event = asyncio.Event() self.input_buffer = [] - async def connect(self, url, headers={}, auth=None, transports=None, - namespace='/', socketio_path='socket.io', - wait_timeout=5): + async def connect( + self, + url, + headers={}, + auth=None, + transports=None, + namespace="/", + socketio_path="socket.io", + wait_timeout=5, + ): """Connect to a Socket.IO server. :param url: The URL of the Socket.IO server. It can include custom @@ -56,7 +64,7 @@ class AsyncSimpleClient: Note: this method is a coroutine. """ if self.connected: - raise RuntimeError('Already connected') + raise RuntimeError("Already connected") self.namespace = namespace self.input_buffer = [] self.input_event.clear() @@ -76,15 +84,20 @@ class AsyncSimpleClient: self.connected = False self.connected_event.set() - @self.client.on('*', namespace=self.namespace) + @self.client.on("*", namespace=self.namespace) def on_event(event, *args): # pragma: no cover self.input_buffer.append([event, *args]) self.input_event.set() await self.client.connect( - url, headers=headers, auth=auth, transports=transports, - namespaces=[namespace], socketio_path=socketio_path, - wait_timeout=wait_timeout) + url, + headers=headers, + auth=auth, + transports=transports, + namespaces=[namespace], + socketio_path=socketio_path, + wait_timeout=wait_timeout, + ) @property def sid(self): @@ -102,7 +115,7 @@ class AsyncSimpleClient: The transport is returned as a string and can be one of ``polling`` and ``websocket``. """ - return self.client.transport if self.client else '' + return self.client.transport if self.client else "" async def emit(self, event, data=None): """Emit an event to the server. @@ -127,8 +140,7 @@ class AsyncSimpleClient: if not self.connected: raise DisconnectedError() try: - return await self.client.emit(event, data, - namespace=self.namespace) + return await self.client.emit(event, data, namespace=self.namespace) except SocketIOError: pass @@ -157,9 +169,9 @@ class AsyncSimpleClient: if not self.connected: raise DisconnectedError() try: - return await self.client.call(event, data, - namespace=self.namespace, - timeout=timeout) + return await self.client.call( + event, data, namespace=self.namespace, timeout=timeout + ) except SocketIOError: pass @@ -178,15 +190,13 @@ class AsyncSimpleClient: """ while not self.input_buffer: try: - await asyncio.wait_for(self.connected_event.wait(), - timeout=timeout) + await asyncio.wait_for(self.connected_event.wait(), timeout=timeout) except asyncio.TimeoutError: # pragma: no cover raise TimeoutError() if not self.connected: raise DisconnectedError() try: - await asyncio.wait_for(self.input_event.wait(), - timeout=timeout) + await asyncio.wait_for(self.input_event.wait(), timeout=timeout) except asyncio.TimeoutError: raise TimeoutError() self.input_event.clear() diff --git a/src/socketio/base_client.py b/src/socketio/base_client.py index 95fea1e..0b5a3a9 100644 --- a/src/socketio/base_client.py +++ b/src/socketio/base_client.py @@ -6,7 +6,7 @@ import threading from . import base_namespace from . import packet -default_logger = logging.getLogger('socketio.client') +default_logger = logging.getLogger("socketio.client") reconnecting_clients = [] @@ -29,18 +29,28 @@ original_signal_handler = None class BaseClient: - reserved_events = ['connect', 'connect_error', 'disconnect', - '__disconnect_final'] - - 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, handle_sigint=True, **kwargs): + reserved_events = ["connect", "connect_error", "disconnect", "__disconnect_final"] + + 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, + handle_sigint=True, + **kwargs, + ): global original_signal_handler - 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) + 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) self.reconnection = reconnection self.reconnection_attempts = reconnection_attempts self.reconnection_delay = reconnection_delay @@ -49,25 +59,26 @@ class BaseClient: self.handle_sigint = handle_sigint engineio_options = kwargs - engineio_options['handle_sigint'] = handle_sigint - engineio_logger = engineio_options.pop('engineio_logger', None) + 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 - if serializer == 'default': + engineio_options["logger"] = engineio_logger + if serializer == "default": self.packet_class = packet.Packet - elif serializer == 'msgpack': + elif serializer == "msgpack": from . import msgpack_packet + self.packet_class = msgpack_packet.MsgPackPacket else: self.packet_class = serializer if json is not None: self.packet_class.json = json - engineio_options['json'] = json + engineio_options["json"] = json self.eio = self._engineio_client_class()(**engineio_options) - self.eio.on('connect', self._handle_eio_connect) - self.eio.on('message', self._handle_eio_message) - self.eio.on('disconnect', self._handle_eio_disconnect) + self.eio.on("connect", self._handle_eio_connect) + self.eio.on("message", self._handle_eio_message) + self.eio.on("disconnect", self._handle_eio_disconnect) if not isinstance(logger, bool): self.logger = logger @@ -134,7 +145,7 @@ class BaseClient: function if it exists. The ``'disconnect'`` handler does not take arguments. """ - namespace = namespace or '/' + namespace = namespace or "/" def set_handler(handler): if namespace not in self.handlers: @@ -188,14 +199,12 @@ class BaseClient: subclass that handles all the event traffic for a namespace. """ - if not isinstance(namespace_handler, - base_namespace.BaseClientNamespace): - raise ValueError('Not a namespace instance') + if not isinstance(namespace_handler, base_namespace.BaseClientNamespace): + raise ValueError("Not a namespace instance") if self.is_asyncio_based() != namespace_handler.is_asyncio_based(): - raise ValueError('Not a valid namespace class for this client') + raise ValueError("Not a valid namespace class for this client") namespace_handler._set_client(self) - self.namespace_handlers[namespace_handler.namespace] = \ - namespace_handler + self.namespace_handlers[namespace_handler.namespace] = namespace_handler def get_sid(self, namespace=None): """Return the ``sid`` associated with a connection. @@ -209,7 +218,7 @@ class BaseClient: This method returns the ``sid`` for the requested namespace as a string. """ - return self.namespaces.get(namespace or '/') + return self.namespaces.get(namespace or "/") def transport(self): """Return the name of the transport used by the client. @@ -221,7 +230,7 @@ class BaseClient: def _generate_ack_id(self, namespace, callback): """Generate a unique identifier for an ACK packet.""" - namespace = namespace or '/' + namespace = namespace or "/" if namespace not in self.callbacks: self.callbacks[namespace] = {0: itertools.count(1)} id = next(self.callbacks[namespace][0]) diff --git a/src/socketio/base_manager.py b/src/socketio/base_manager.py index ca4b0b9..6ec688f 100644 --- a/src/socketio/base_manager.py +++ b/src/socketio/base_manager.py @@ -3,7 +3,7 @@ import logging from bidict import bidict, ValueDuplicationError -default_logger = logging.getLogger('socketio') +default_logger = logging.getLogger("socketio") class BaseManager: @@ -31,7 +31,7 @@ class BaseManager: def get_participants(self, namespace, room): """Return an iterable with the active participants in a room.""" ns = self.rooms.get(namespace, {}) - if hasattr(room, '__len__') and not isinstance(room, str): + if hasattr(room, "__len__") and not isinstance(room, str): participants = ns[room[0]]._fwdm.copy() if room[0] in ns else {} for r in room[1:]: participants.update(ns[r]._fwdm if r in ns else {}) @@ -52,8 +52,10 @@ class BaseManager: return sid def is_connected(self, sid, namespace): - if namespace in self.pending_disconnect and \ - sid in self.pending_disconnect[namespace]: + if ( + namespace in self.pending_disconnect + and sid in self.pending_disconnect[namespace] + ): # the client is in the process of being disconnected return False try: @@ -95,15 +97,17 @@ class BaseManager: self.basic_leave_room(sid, namespace, room) if sid in self.callbacks: del self.callbacks[sid] - if namespace in self.pending_disconnect and \ - sid in self.pending_disconnect[namespace]: + if ( + namespace in self.pending_disconnect + and sid in self.pending_disconnect[namespace] + ): self.pending_disconnect[namespace].remove(sid) if len(self.pending_disconnect[namespace]) == 0: del self.pending_disconnect[namespace] def basic_enter_room(self, sid, namespace, room, eio_sid=None): if eio_sid is None and namespace not in self.rooms: - raise ValueError('sid is not connected to requested namespace') + raise ValueError("sid is not connected to requested namespace") if namespace not in self.rooms: self.rooms[namespace] = {} if room not in self.rooms[namespace]: diff --git a/src/socketio/base_namespace.py b/src/socketio/base_namespace.py index 354f75a..abfbdd5 100644 --- a/src/socketio/base_namespace.py +++ b/src/socketio/base_namespace.py @@ -1,6 +1,6 @@ class BaseNamespace(object): def __init__(self, namespace=None): - self.namespace = namespace or '/' + self.namespace = namespace or "/" def is_asyncio_based(self): return False diff --git a/src/socketio/base_server.py b/src/socketio/base_server.py index f8c9000..39bc9c7 100644 --- a/src/socketio/base_server.py +++ b/src/socketio/base_server.py @@ -4,34 +4,43 @@ from . import manager from . import base_namespace from . import packet -default_logger = logging.getLogger('socketio.server') +default_logger = logging.getLogger("socketio.server") class BaseServer: - reserved_events = ['connect', 'disconnect'] - - def __init__(self, client_manager=None, logger=False, serializer='default', - json=None, async_handlers=True, always_connect=False, - namespaces=None, **kwargs): + reserved_events = ["connect", "disconnect"] + + def __init__( + self, + client_manager=None, + logger=False, + serializer="default", + json=None, + async_handlers=True, + always_connect=False, + namespaces=None, + **kwargs, + ): engineio_options = kwargs - engineio_logger = engineio_options.pop('engineio_logger', None) + engineio_logger = engineio_options.pop("engineio_logger", None) if engineio_logger is not None: - engineio_options['logger'] = engineio_logger - if serializer == 'default': + engineio_options["logger"] = engineio_logger + if serializer == "default": self.packet_class = packet.Packet - elif serializer == 'msgpack': + elif serializer == "msgpack": from . import msgpack_packet + self.packet_class = msgpack_packet.MsgPackPacket else: self.packet_class = serializer if json is not None: self.packet_class.json = json - engineio_options['json'] = json - engineio_options['async_handlers'] = False + engineio_options["json"] = json + engineio_options["async_handlers"] = False self.eio = self._engineio_server_class()(**engineio_options) - self.eio.on('connect', self._handle_eio_connect) - self.eio.on('message', self._handle_eio_message) - self.eio.on('disconnect', self._handle_eio_disconnect) + self.eio.on("connect", self._handle_eio_connect) + self.eio.on("message", self._handle_eio_message) + self.eio.on("disconnect", self._handle_eio_disconnect) self.environ = {} self.handlers = {} @@ -59,7 +68,7 @@ class BaseServer: self.async_handlers = async_handlers self.always_connect = always_connect - self.namespaces = namespaces or ['/'] + self.namespaces = namespaces or ["/"] self.async_mode = self.eio.async_mode @@ -103,7 +112,7 @@ class BaseServer: client's acknowledgement callback function if it exists. The ``'disconnect'`` handler does not take a second argument. """ - namespace = namespace or '/' + namespace = namespace or "/" def set_handler(handler): if namespace not in self.handlers: @@ -157,14 +166,12 @@ class BaseServer: subclass that handles all the event traffic for a namespace. """ - if not isinstance(namespace_handler, - base_namespace.BaseServerNamespace): - raise ValueError('Not a namespace instance') + if not isinstance(namespace_handler, base_namespace.BaseServerNamespace): + raise ValueError("Not a namespace instance") if self.is_asyncio_based() != namespace_handler.is_asyncio_based(): - raise ValueError('Not a valid namespace class for this server') + raise ValueError("Not a valid namespace class for this server") namespace_handler._set_server(self) - self.namespace_handlers[namespace_handler.namespace] = \ - namespace_handler + self.namespace_handlers[namespace_handler.namespace] = namespace_handler def rooms(self, sid, namespace=None): """Return the rooms a client is in. @@ -173,7 +180,7 @@ class BaseServer: :param namespace: The Socket.IO namespace for the event. If this argument is omitted the default namespace is used. """ - namespace = namespace or '/' + namespace = namespace or "/" return self.manager.get_rooms(sid, namespace) def transport(self, sid): @@ -193,7 +200,7 @@ class BaseServer: :param namespace: The Socket.IO namespace. If this argument is omitted the default namespace is used. """ - eio_sid = self.manager.eio_sid_from_sid(sid, namespace or '/') + eio_sid = self.manager.eio_sid_from_sid(sid, namespace or "/") return self.environ.get(eio_sid) def _handle_eio_connect(self): # pragma: no cover @@ -206,4 +213,4 @@ class BaseServer: raise NotImplementedError() def _engineio_server_class(self): # pragma: no cover - raise NotImplementedError('Must be implemented in subclasses') + raise NotImplementedError("Must be implemented in subclasses") diff --git a/src/socketio/client.py b/src/socketio/client.py index 9f730a7..5ccf5e0 100644 --- a/src/socketio/client.py +++ b/src/socketio/client.py @@ -67,9 +67,18 @@ class Client(base_client.BaseClient): fatal errors are logged even when ``engineio_logger`` is ``False``. """ - def connect(self, url, headers={}, auth=None, transports=None, - namespaces=None, socketio_path='socket.io', wait=True, - wait_timeout=1): + + def connect( + self, + url, + headers={}, + auth=None, + transports=None, + namespaces=None, + socketio_path="socket.io", + wait=True, + wait_timeout=1, + ): """Connect to a Socket.IO server. :param url: The URL of the Socket.IO server. It can include custom @@ -112,7 +121,7 @@ class Client(base_client.BaseClient): sio.connect('http://localhost:5000') """ if self.connected: - raise exceptions.ConnectionError('Already connected') + raise exceptions.ConnectionError("Already connected") self.connection_url = url self.connection_headers = headers @@ -122,10 +131,11 @@ class Client(base_client.BaseClient): self.socketio_path = socketio_path if namespaces is None: - namespaces = list(set(self.handlers.keys()).union( - set(self.namespace_handlers.keys()))) + namespaces = list( + set(self.handlers.keys()).union(set(self.namespace_handlers.keys())) + ) if len(namespaces) == 0: - namespaces = ['/'] + namespaces = ["/"] elif isinstance(namespaces, str): namespaces = [namespaces] self.connection_namespaces = namespaces @@ -137,14 +147,19 @@ class Client(base_client.BaseClient): real_url = self._get_real_value(self.connection_url) real_headers = self._get_real_value(self.connection_headers) try: - self.eio.connect(real_url, headers=real_headers, - transports=transports, - engineio_path=socketio_path) + self.eio.connect( + real_url, + headers=real_headers, + transports=transports, + engineio_path=socketio_path, + ) except engineio.exceptions.ConnectionError as exc: for n in self.connection_namespaces: self._trigger_event( - 'connect_error', n, - exc.args[1] if len(exc.args) > 1 else exc.args[0]) + "connect_error", + n, + exc.args[1] if len(exc.args) > 1 else exc.args[0], + ) raise exceptions.ConnectionError(exc.args[0]) from None if wait: @@ -155,7 +170,8 @@ class Client(base_client.BaseClient): if set(self.namespaces) != set(self.connection_namespaces): self.disconnect() raise exceptions.ConnectionError( - 'One or more namespaces failed to connect') + "One or more namespaces failed to connect" + ) self.connected = True @@ -171,7 +187,7 @@ class Client(base_client.BaseClient): if not self._reconnect_task: break self._reconnect_task.join() - if self.eio.state != 'connected': + if self.eio.state != "connected": break def emit(self, event, data=None, namespace=None, callback=None): @@ -198,10 +214,11 @@ class Client(base_client.BaseClient): standard concurrency solutions (such as a Lock object) to prevent this situation. """ - namespace = namespace or '/' + namespace = namespace or "/" if namespace not in self.namespaces: raise exceptions.BadNamespaceError( - namespace + ' is not a connected namespace.') + namespace + " is not a connected namespace." + ) self.logger.info('Emitting event "%s" [%s]', event, namespace) if callback is not None: id = self._generate_ack_id(namespace, callback) @@ -215,8 +232,11 @@ class Client(base_client.BaseClient): data = [data] else: data = [] - self._send_packet(self.packet_class(packet.EVENT, namespace=namespace, - data=[event] + data, id=id)) + self._send_packet( + self.packet_class( + packet.EVENT, namespace=namespace, data=[event] + data, id=id + ) + ) def send(self, data, namespace=None, callback=None): """Send a message to the server. @@ -236,8 +256,7 @@ class Client(base_client.BaseClient): that will be passed to the function are those provided by the server. """ - self.emit('message', data=data, namespace=namespace, - callback=callback) + self.emit("message", data=data, namespace=namespace, callback=callback) def call(self, event, data=None, namespace=None, timeout=60): """Emit a custom event to the server and wait for the response. @@ -275,21 +294,23 @@ class Client(base_client.BaseClient): callback_args.append(args) callback_event.set() - self.emit(event, data=data, namespace=namespace, - callback=event_callback) + self.emit(event, data=data, namespace=namespace, callback=event_callback) if not callback_event.wait(timeout=timeout): raise exceptions.TimeoutError() - return callback_args[0] if len(callback_args[0]) > 1 \ - else callback_args[0][0] if len(callback_args[0]) == 1 \ + return ( + callback_args[0] + if len(callback_args[0]) > 1 + else callback_args[0][0] + if len(callback_args[0]) == 1 else None + ) def disconnect(self): """Disconnect from the server.""" # here we just request the disconnection # later in _handle_eio_disconnect we invoke the disconnect handler for n in self.namespaces: - self._send_packet(self.packet_class( - packet.DISCONNECT, namespace=n)) + self._send_packet(self.packet_class(packet.DISCONNECT, namespace=n)) self.eio.disconnect(abort=True) def start_background_task(self, target, *args, **kwargs): @@ -336,19 +357,19 @@ class Client(base_client.BaseClient): self.eio.send(encoded_packet) def _handle_connect(self, namespace, data): - namespace = namespace or '/' + namespace = namespace or "/" if namespace not in self.namespaces: - self.logger.info('Namespace {} is connected'.format(namespace)) - self.namespaces[namespace] = (data or {}).get('sid', self.sid) - self._trigger_event('connect', namespace=namespace) + self.logger.info("Namespace {} is connected".format(namespace)) + self.namespaces[namespace] = (data or {}).get("sid", self.sid) + self._trigger_event("connect", namespace=namespace) self._connect_event.set() def _handle_disconnect(self, namespace): if not self.connected: return - namespace = namespace or '/' - self._trigger_event('disconnect', namespace=namespace) - self._trigger_event('__disconnect_final', namespace=namespace) + namespace = namespace or "/" + self._trigger_event("disconnect", namespace=namespace) + self._trigger_event("__disconnect_final", namespace=namespace) if namespace in self.namespaces: del self.namespaces[namespace] if not self.namespaces: @@ -356,7 +377,7 @@ class Client(base_client.BaseClient): self.eio.disconnect(abort=True) def _handle_event(self, namespace, id, data): - namespace = namespace or '/' + namespace = namespace or "/" self.logger.info('Received event "%s" [%s]', data[0], namespace) r = self._trigger_event(data[0], namespace, *data[1:]) if id is not None: @@ -368,36 +389,36 @@ class Client(base_client.BaseClient): data = list(r) else: data = [r] - self._send_packet(self.packet_class( - packet.ACK, namespace=namespace, id=id, data=data)) + self._send_packet( + self.packet_class(packet.ACK, namespace=namespace, id=id, data=data) + ) def _handle_ack(self, namespace, id, data): - namespace = namespace or '/' - self.logger.info('Received ack [%s]', namespace) + namespace = namespace or "/" + self.logger.info("Received ack [%s]", namespace) callback = None try: callback = self.callbacks[namespace][id] except KeyError: # if we get an unknown callback we just ignore it - self.logger.warning('Unknown callback received, ignoring.') + self.logger.warning("Unknown callback received, ignoring.") else: del self.callbacks[namespace][id] if callback is not None: callback(*data) def _handle_error(self, namespace, data): - namespace = namespace or '/' - self.logger.info('Connection to namespace {} was rejected'.format( - namespace)) + namespace = namespace or "/" + self.logger.info("Connection to namespace {} was rejected".format(namespace)) if data is None: data = tuple() elif not isinstance(data, (tuple, list)): data = (data,) - self._trigger_event('connect_error', namespace, *data) + self._trigger_event("connect_error", namespace, *data) self._connect_event.set() if namespace in self.namespaces: del self.namespaces[namespace] - if namespace == '/': + if namespace == "/": self.namespaces = {} self.connected = False @@ -407,14 +428,12 @@ class Client(base_client.BaseClient): if namespace in self.handlers: if event in self.handlers[namespace]: return self.handlers[namespace][event](*args) - elif event not in self.reserved_events and \ - '*' in self.handlers[namespace]: - return self.handlers[namespace]['*'](event, *args) + 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 elif namespace in self.namespace_handlers: - return self.namespace_handlers[namespace].trigger_event( - event, *args) + return self.namespace_handlers[namespace].trigger_event(event, *args) def _handle_reconnect(self): if self._reconnect_abort is None: # pragma: no cover @@ -430,44 +449,48 @@ class Client(base_client.BaseClient): delay = self.reconnection_delay_max delay += self.randomization_factor * (2 * random.random() - 1) self.logger.info( - 'Connection failed, new attempt in {:.02f} seconds'.format( - delay)) + "Connection failed, new attempt in {:.02f} seconds".format(delay) + ) if self._reconnect_abort.wait(delay): - self.logger.info('Reconnect task aborted') + self.logger.info("Reconnect task aborted") for n in self.connection_namespaces: - self._trigger_event('__disconnect_final', namespace=n) + self._trigger_event("__disconnect_final", namespace=n) break attempt_count += 1 try: - self.connect(self.connection_url, - headers=self.connection_headers, - auth=self.connection_auth, - transports=self.connection_transports, - namespaces=self.connection_namespaces, - socketio_path=self.socketio_path) + self.connect( + self.connection_url, + headers=self.connection_headers, + auth=self.connection_auth, + transports=self.connection_transports, + namespaces=self.connection_namespaces, + socketio_path=self.socketio_path, + ) except (exceptions.ConnectionError, ValueError): pass else: - self.logger.info('Reconnection successful') + self.logger.info("Reconnection successful") self._reconnect_task = None break - if self.reconnection_attempts and \ - attempt_count >= self.reconnection_attempts: - self.logger.info( - 'Maximum reconnection attempts reached, giving up') + if ( + self.reconnection_attempts + and attempt_count >= self.reconnection_attempts + ): + self.logger.info("Maximum reconnection attempts reached, giving up") for n in self.connection_namespaces: - self._trigger_event('__disconnect_final', namespace=n) + self._trigger_event("__disconnect_final", namespace=n) break base_client.reconnecting_clients.remove(self) def _handle_eio_connect(self): """Handle the Engine.IO connection event.""" - self.logger.info('Engine.IO connection established') + self.logger.info("Engine.IO connection established") self.sid = self.eio.sid real_auth = self._get_real_value(self.connection_auth) or {} for n in self.connection_namespaces: - self._send_packet(self.packet_class( - packet.CONNECT, data=real_auth, namespace=n)) + self._send_packet( + self.packet_class(packet.CONNECT, data=real_auth, namespace=n) + ) def _handle_eio_message(self, data): """Dispatch Engine.IO messages.""" @@ -489,31 +512,32 @@ class Client(base_client.BaseClient): self._handle_event(pkt.namespace, pkt.id, pkt.data) elif pkt.packet_type == packet.ACK: self._handle_ack(pkt.namespace, pkt.id, pkt.data) - elif pkt.packet_type == packet.BINARY_EVENT or \ - pkt.packet_type == packet.BINARY_ACK: + elif ( + pkt.packet_type == packet.BINARY_EVENT + or pkt.packet_type == packet.BINARY_ACK + ): self._binary_packet = pkt elif pkt.packet_type == packet.CONNECT_ERROR: self._handle_error(pkt.namespace, pkt.data) else: - raise ValueError('Unknown packet type.') + raise ValueError("Unknown packet type.") def _handle_eio_disconnect(self): """Handle the Engine.IO disconnection event.""" - self.logger.info('Engine.IO connection dropped') - will_reconnect = self.reconnection and self.eio.state == 'connected' + self.logger.info("Engine.IO connection dropped") + will_reconnect = self.reconnection and self.eio.state == "connected" if self.connected: for n in self.namespaces: - self._trigger_event('disconnect', namespace=n) + self._trigger_event("disconnect", namespace=n) if not will_reconnect: - self._trigger_event('__disconnect_final', namespace=n) + self._trigger_event("__disconnect_final", namespace=n) self.namespaces = {} self.connected = False self.callbacks = {} self._binary_packet = None self.sid = None if will_reconnect: - self._reconnect_task = self.start_background_task( - self._handle_reconnect) + self._reconnect_task = self.start_background_task(self._handle_reconnect) def _engineio_client_class(self): return engineio.Client diff --git a/src/socketio/exceptions.py b/src/socketio/exceptions.py index 19d6e39..475e74a 100644 --- a/src/socketio/exceptions.py +++ b/src/socketio/exceptions.py @@ -13,17 +13,18 @@ class ConnectionRefusedError(ConnectionError): is not accepted. The positional arguments provided with the exception are returned with the error packet to the client. """ + def __init__(self, *args): if len(args) == 0: - self.error_args = {'message': 'Connection rejected by server'} + self.error_args = {"message": "Connection rejected by server"} elif len(args) == 1: - self.error_args = {'message': str(args[0])} + self.error_args = {"message": str(args[0])} else: - self.error_args = {'message': str(args[0])} + self.error_args = {"message": str(args[0])} if len(args) == 2: - self.error_args['data'] = args[1] + self.error_args["data"] = args[1] else: - self.error_args['data'] = args[1:] + self.error_args["data"] = args[1:] class TimeoutError(SocketIOError): diff --git a/src/socketio/kafka_manager.py b/src/socketio/kafka_manager.py index 4d87d46..2becc65 100644 --- a/src/socketio/kafka_manager.py +++ b/src/socketio/kafka_manager.py @@ -8,7 +8,7 @@ except ImportError: from .pubsub_manager import PubSubManager -logger = logging.getLogger('socketio') +logger = logging.getLogger("socketio") class KafkaManager(PubSubManager): # pragma: no cover @@ -34,23 +34,29 @@ class KafkaManager(PubSubManager): # pragma: no cover default of ``False`` initializes the class for emitting and receiving. """ - name = 'kafka' - def __init__(self, url='kafka://localhost:9092', channel='socketio', - write_only=False): + name = "kafka" + + def __init__( + self, url="kafka://localhost:9092", channel="socketio", write_only=False + ): if kafka is None: - raise RuntimeError('kafka-python package is not installed ' - '(Run "pip install kafka-python" in your ' - 'virtualenv).') + raise RuntimeError( + "kafka-python package is not installed " + '(Run "pip install kafka-python" in your ' + "virtualenv)." + ) super().__init__(channel=channel, write_only=write_only) urls = [url] if isinstance(url, str) else url - self.kafka_urls = [url[8:] if url != 'kafka://' else 'localhost:9092' - for url in urls] + 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_urls) + self.consumer = kafka.KafkaConsumer( + self.channel, bootstrap_servers=self.kafka_urls + ) def _publish(self, data): self.producer.send(self.channel, value=pickle.dumps(data)) diff --git a/src/socketio/kombu_manager.py b/src/socketio/kombu_manager.py index 0a63bc2..4f99c4e 100644 --- a/src/socketio/kombu_manager.py +++ b/src/socketio/kombu_manager.py @@ -44,16 +44,26 @@ class KombuManager(PubSubManager): # pragma: no cover :param producer_options: additional keyword arguments to be passed to ``kombu.Producer()``. """ - name = 'kombu' - def __init__(self, url='amqp://guest:guest@localhost:5672//', - channel='socketio', write_only=False, logger=None, - connection_options=None, exchange_options=None, - queue_options=None, producer_options=None): + name = "kombu" + + def __init__( + self, + url="amqp://guest:guest@localhost:5672//", + channel="socketio", + write_only=False, + logger=None, + connection_options=None, + exchange_options=None, + queue_options=None, + producer_options=None, + ): if kombu is None: - raise RuntimeError('Kombu package is not installed ' - '(Run "pip install kombu" in your ' - 'virtualenv).') + raise RuntimeError( + "Kombu package is not installed " + '(Run "pip install kombu" in your ' + "virtualenv)." + ) super().__init__(channel=channel, write_only=write_only, logger=logger) self.url = url self.connection_options = connection_options or {} @@ -66,52 +76,55 @@ class KombuManager(PubSubManager): # pragma: no cover super().initialize() monkey_patched = True - if self.server.async_mode == 'eventlet': + if self.server.async_mode == "eventlet": from eventlet.patcher import is_monkey_patched - monkey_patched = is_monkey_patched('socket') - elif 'gevent' in self.server.async_mode: + + monkey_patched = is_monkey_patched("socket") + elif "gevent" in self.server.async_mode: from gevent.monkey import is_module_patched - monkey_patched = is_module_patched('socket') + + monkey_patched = is_module_patched("socket") if not monkey_patched: raise RuntimeError( - 'Kombu requires a monkey patched socket library to work ' - 'with ' + self.server.async_mode) + "Kombu requires a monkey patched socket library to work " + "with " + self.server.async_mode + ) def _connection(self): return kombu.Connection(self.url, **self.connection_options) def _exchange(self): - options = {'type': 'fanout', 'durable': False} + options = {"type": "fanout", "durable": False} options.update(self.exchange_options) return kombu.Exchange(self.channel, **options) def _queue(self): - queue_name = 'flask-socketio.' + str(uuid.uuid4()) - options = {'durable': False, 'queue_arguments': {'x-expires': 300000}} + queue_name = "flask-socketio." + str(uuid.uuid4()) + options = {"durable": False, "queue_arguments": {"x-expires": 300000}} options.update(self.queue_options) return kombu.Queue(queue_name, self._exchange(), **options) def _producer_publish(self, connection): - producer = connection.Producer(exchange=self._exchange(), - **self.producer_options) + producer = connection.Producer( + exchange=self._exchange(), **self.producer_options + ) return connection.ensure(producer, producer.publish) def _publish(self, data): retry = True while True: try: - producer_publish = self._producer_publish( - self.publisher_connection) + producer_publish = self._producer_publish(self.publisher_connection) producer_publish(pickle.dumps(data)) break except (OSError, kombu.exceptions.KombuError): if retry: - self._get_logger().error('Cannot publish to rabbitmq... ' - 'retrying') + self._get_logger().error( + "Cannot publish to rabbitmq... " "retrying" + ) retry = False else: - self._get_logger().error( - 'Cannot publish to rabbitmq... giving up') + self._get_logger().error("Cannot publish to rabbitmq... giving up") break def _listen(self): @@ -128,7 +141,9 @@ class KombuManager(PubSubManager): # pragma: no cover retry_sleep = 1 except (OSError, kombu.exceptions.KombuError): self._get_logger().error( - 'Cannot receive from rabbitmq... ' - 'retrying in {} secs'.format(retry_sleep)) + "Cannot receive from rabbitmq... " "retrying in {} secs".format( + retry_sleep + ) + ) time.sleep(retry_sleep) retry_sleep = min(retry_sleep * 2, 60) diff --git a/src/socketio/manager.py b/src/socketio/manager.py index 813c4af..fe1f90f 100644 --- a/src/socketio/manager.py +++ b/src/socketio/manager.py @@ -4,7 +4,7 @@ from engineio import packet as eio_packet from . import base_manager from . import packet -default_logger = logging.getLogger('socketio') +default_logger = logging.getLogger("socketio") class Manager(base_manager.BaseManager): @@ -16,11 +16,13 @@ class Manager(base_manager.BaseManager): services. More sophisticated storage backends can be implemented by subclasses. """ + def can_disconnect(self, sid, namespace): return self.is_connected(sid, namespace) - def emit(self, event, data, namespace, room=None, skip_sid=None, - callback=None, **kwargs): + def emit( + self, event, data, namespace, room=None, skip_sid=None, callback=None, **kwargs + ): """Emit a message to a single client, a room, or all the clients connected to the namespace.""" if namespace not in self.rooms: @@ -39,12 +41,12 @@ class Manager(base_manager.BaseManager): # when callbacks aren't used the packets sent to each recipient are # identical, so they can be generated once and reused pkt = self.server.packet_class( - packet.EVENT, namespace=namespace, data=[event] + data) + packet.EVENT, namespace=namespace, data=[event] + data + ) encoded_packet = pkt.encode() if not isinstance(encoded_packet, list): encoded_packet = [encoded_packet] - eio_pkt = [eio_packet.Packet(eio_packet.MESSAGE, p) - for p in encoded_packet] + eio_pkt = [eio_packet.Packet(eio_packet.MESSAGE, p) for p in encoded_packet] for sid, eio_sid in self.get_participants(namespace, room): if sid not in skip_sid: for p in eio_pkt: @@ -58,8 +60,8 @@ class Manager(base_manager.BaseManager): if sid not in skip_sid: # pragma: no branch id = self._generate_ack_id(sid, callback) pkt = self.server.packet_class( - packet.EVENT, namespace=namespace, data=[event] + data, - id=id) + packet.EVENT, namespace=namespace, data=[event] + data, id=id + ) self.server._send_packet(eio_sid, pkt) def disconnect(self, sid, namespace, **kwargs): @@ -85,7 +87,7 @@ class Manager(base_manager.BaseManager): callback = self.callbacks[sid][id] except KeyError: # if we get an unknown callback we just ignore it - self._get_logger().warning('Unknown callback received, ignoring.') + self._get_logger().warning("Unknown callback received, ignoring.") else: del self.callbacks[sid][id] if callback is not None: diff --git a/src/socketio/middleware.py b/src/socketio/middleware.py index acc8ffd..ce72a37 100644 --- a/src/socketio/middleware.py +++ b/src/socketio/middleware.py @@ -27,14 +27,20 @@ class WSGIApp(engineio.WSGIApp): app = socketio.WSGIApp(sio, wsgi_app) eventlet.wsgi.server(eventlet.listen(('', 8000)), app) """ - def __init__(self, socketio_app, wsgi_app=None, static_files=None, - socketio_path='socket.io'): - super().__init__(socketio_app, wsgi_app, static_files=static_files, - engineio_path=socketio_path) + + def __init__( + self, socketio_app, wsgi_app=None, static_files=None, socketio_path="socket.io" + ): + super().__init__( + socketio_app, + wsgi_app, + static_files=static_files, + engineio_path=socketio_path, + ) class Middleware(WSGIApp): """This class has been renamed to WSGIApp and is now deprecated.""" - def __init__(self, socketio_app, wsgi_app=None, - socketio_path='socket.io'): + + def __init__(self, socketio_app, wsgi_app=None, socketio_path="socket.io"): super().__init__(socketio_app, wsgi_app, socketio_path=socketio_path) diff --git a/src/socketio/msgpack_packet.py b/src/socketio/msgpack_packet.py index 2746263..5014a43 100644 --- a/src/socketio/msgpack_packet.py +++ b/src/socketio/msgpack_packet.py @@ -12,7 +12,7 @@ class MsgPackPacket(packet.Packet): def decode(self, encoded_packet): """Decode a transmitted package.""" decoded = msgpack.loads(encoded_packet) - self.packet_type = decoded['type'] - self.data = decoded.get('data') - self.id = decoded.get('id') - self.namespace = decoded['nsp'] + self.packet_type = decoded["type"] + self.data = decoded.get("data") + self.id = decoded.get("id") + self.namespace = decoded["nsp"] diff --git a/src/socketio/namespace.py b/src/socketio/namespace.py index ab4f69f..ce753d4 100644 --- a/src/socketio/namespace.py +++ b/src/socketio/namespace.py @@ -13,6 +13,7 @@ class Namespace(base_namespace.BaseServerNamespace): handlers defined in this class. If this argument is omitted, the default namespace is used. """ + def trigger_event(self, event, *args): """Dispatch an event to the proper handler method. @@ -21,46 +22,89 @@ class Namespace(base_namespace.BaseServerNamespace): method can be overridden if special dispatching rules are needed, or if having a single method that catches all events is desired. """ - handler_name = 'on_' + event + handler_name = "on_" + event if hasattr(self, handler_name): return getattr(self, handler_name)(*args) - def emit(self, event, data=None, to=None, room=None, skip_sid=None, - namespace=None, callback=None, ignore_queue=False): + def emit( + self, + event, + data=None, + to=None, + room=None, + skip_sid=None, + namespace=None, + callback=None, + ignore_queue=False, + ): """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, to=to, room=room, - skip_sid=skip_sid, - namespace=namespace or self.namespace, - callback=callback, ignore_queue=ignore_queue) - - def send(self, data, to=None, room=None, skip_sid=None, namespace=None, - callback=None, ignore_queue=False): + return self.server.emit( + event, + data=data, + to=to, + room=room, + skip_sid=skip_sid, + namespace=namespace or self.namespace, + callback=callback, + ignore_queue=ignore_queue, + ) + + def send( + self, + data, + to=None, + room=None, + skip_sid=None, + namespace=None, + callback=None, + ignore_queue=False, + ): """Send a message to one or more connected clients. The only difference with the :func:`socketio.Server.send` method is that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.server.send(data, to=to, room=room, skip_sid=skip_sid, - namespace=namespace or self.namespace, - callback=callback, ignore_queue=ignore_queue) - - def call(self, event, data=None, to=None, sid=None, namespace=None, - timeout=None, ignore_queue=False): + return self.server.send( + data, + to=to, + room=room, + skip_sid=skip_sid, + namespace=namespace or self.namespace, + callback=callback, + ignore_queue=ignore_queue, + ) + + def call( + self, + event, + data=None, + to=None, + sid=None, + namespace=None, + timeout=None, + ignore_queue=False, + ): """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, ignore_queue=ignore_queue) + return self.server.call( + event, + data=data, + to=to, + sid=sid, + namespace=namespace or self.namespace, + timeout=timeout, + ignore_queue=ignore_queue, + ) def enter_room(self, sid, room, namespace=None): """Enter a room. @@ -69,8 +113,7 @@ class Namespace(base_namespace.BaseServerNamespace): is that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.server.enter_room(sid, room, - namespace=namespace or self.namespace) + return self.server.enter_room(sid, room, namespace=namespace or self.namespace) def leave_room(self, sid, room, namespace=None): """Leave a room. @@ -79,8 +122,7 @@ class Namespace(base_namespace.BaseServerNamespace): is that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.server.leave_room(sid, room, - namespace=namespace or self.namespace) + return self.server.leave_room(sid, room, namespace=namespace or self.namespace) def close_room(self, room, namespace=None): """Close a room. @@ -89,8 +131,7 @@ class Namespace(base_namespace.BaseServerNamespace): is that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.server.close_room(room, - namespace=namespace or self.namespace) + return self.server.close_room(room, namespace=namespace or self.namespace) def get_session(self, sid, namespace=None): """Return the user session for a client. @@ -99,8 +140,7 @@ class Namespace(base_namespace.BaseServerNamespace): method is that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.server.get_session( - sid, namespace=namespace or self.namespace) + return self.server.get_session(sid, namespace=namespace or self.namespace) def save_session(self, sid, session, namespace=None): """Store the user session for a client. @@ -110,7 +150,8 @@ class Namespace(base_namespace.BaseServerNamespace): namespace associated with the class is used. """ return self.server.save_session( - sid, session, namespace=namespace or self.namespace) + sid, session, namespace=namespace or self.namespace + ) def session(self, sid, namespace=None): """Return the user session for a client with context manager syntax. @@ -128,8 +169,7 @@ class Namespace(base_namespace.BaseServerNamespace): is that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.server.disconnect(sid, - namespace=namespace or self.namespace) + return self.server.disconnect(sid, namespace=namespace or self.namespace) class ClientNamespace(base_namespace.BaseClientNamespace): @@ -144,6 +184,7 @@ class ClientNamespace(base_namespace.BaseClientNamespace): handlers defined in this class. If this argument is omitted, the default namespace is used. """ + def trigger_event(self, event, *args): """Dispatch an event to the proper handler method. @@ -152,7 +193,7 @@ class ClientNamespace(base_namespace.BaseClientNamespace): method can be overridden if special dispatching rules are needed, or if having a single method that catches all events is desired. """ - handler_name = 'on_' + event + handler_name = "on_" + event if hasattr(self, handler_name): return getattr(self, handler_name)(*args) @@ -163,9 +204,9 @@ class ClientNamespace(base_namespace.BaseClientNamespace): that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.client.emit(event, data=data, - namespace=namespace or self.namespace, - callback=callback) + return self.client.emit( + event, data=data, namespace=namespace or self.namespace, callback=callback + ) def send(self, data, room=None, namespace=None, callback=None): """Send a message to the server. @@ -174,8 +215,9 @@ class ClientNamespace(base_namespace.BaseClientNamespace): that when the ``namespace`` argument is not given the namespace associated with the class is used. """ - return self.client.send(data, namespace=namespace or self.namespace, - callback=callback) + 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. @@ -184,9 +226,9 @@ class ClientNamespace(base_namespace.BaseClientNamespace): 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) + return self.client.call( + event, data=data, namespace=namespace or self.namespace, timeout=timeout + ) def disconnect(self): """Disconnect from the server. diff --git a/src/socketio/packet.py b/src/socketio/packet.py index 1830769..d196598 100644 --- a/src/socketio/packet.py +++ b/src/socketio/packet.py @@ -1,10 +1,24 @@ import functools from engineio import json as _json -(CONNECT, DISCONNECT, EVENT, ACK, CONNECT_ERROR, BINARY_EVENT, BINARY_ACK) = \ - (0, 1, 2, 3, 4, 5, 6) -packet_names = ['CONNECT', 'DISCONNECT', 'EVENT', 'ACK', 'CONNECT_ERROR', - 'BINARY_EVENT', 'BINARY_ACK'] +(CONNECT, DISCONNECT, EVENT, ACK, CONNECT_ERROR, BINARY_EVENT, BINARY_ACK) = ( + 0, + 1, + 2, + 3, + 4, + 5, + 6, +) +packet_names = [ + "CONNECT", + "DISCONNECT", + "EVENT", + "ACK", + "CONNECT_ERROR", + "BINARY_EVENT", + "BINARY_ACK", +] class Packet(object): @@ -22,21 +36,28 @@ class Packet(object): uses_binary_events = True json = _json - def __init__(self, packet_type=EVENT, data=None, namespace=None, id=None, - binary=None, encoded_packet=None): + def __init__( + self, + packet_type=EVENT, + data=None, + namespace=None, + id=None, + binary=None, + encoded_packet=None, + ): self.packet_type = packet_type self.data = data self.namespace = namespace self.id = id - if self.uses_binary_events and \ - (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: self.packet_type = BINARY_ACK else: - raise ValueError('Packet does not support binary payload.') + raise ValueError("Packet does not support binary payload.") self.attachment_count = 0 self.attachments = [] if encoded_packet: @@ -52,16 +73,16 @@ class Packet(object): encoded_packet = str(self.packet_type) if self.packet_type == BINARY_EVENT or self.packet_type == BINARY_ACK: data, attachments = self._deconstruct_binary(self.data) - encoded_packet += str(len(attachments)) + '-' + encoded_packet += str(len(attachments)) + "-" else: data = self.data attachments = None - if self.namespace is not None and self.namespace != '/': - encoded_packet += self.namespace + ',' + if self.namespace is not None and self.namespace != "/": + encoded_packet += self.namespace + "," if self.id is not None: encoded_packet += str(self.id) if data is not None: - encoded_packet += self.json.dumps(data, separators=(',', ':')) + encoded_packet += self.json.dumps(data, separators=(",", ":")) if attachments is not None: encoded_packet = [encoded_packet] + attachments return encoded_packet @@ -77,26 +98,26 @@ class Packet(object): self.packet_type = int(ep[0:1]) except TypeError: self.packet_type = ep - ep = '' + ep = "" self.namespace = None self.data = None ep = ep[1:] - dash = ep.find('-') + dash = ep.find("-") attachment_count = 0 if dash > 0 and ep[0:dash].isdigit(): if dash > 10: - raise ValueError('too many attachments') + raise ValueError("too many attachments") attachment_count = int(ep[0:dash]) - ep = ep[dash + 1:] - if ep and ep[0:1] == '/': - sep = ep.find(',') + ep = ep[dash + 1 :] + if ep and ep[0:1] == "/": + sep = ep.find(",") if sep == -1: self.namespace = ep - ep = '' + ep = "" else: self.namespace = ep[0:sep] - ep = ep[sep + 1:] - q = self.namespace.find('?') + ep = ep[sep + 1 :] + q = self.namespace.find("?") if q != -1: self.namespace = self.namespace[0:q] if ep and ep[0].isdigit(): @@ -109,14 +130,14 @@ class Packet(object): self.id = int(ep[:i]) ep = ep[i:] if len(ep) > 0 and ep[0].isdigit(): - raise ValueError('id field is too long') + raise ValueError("id field is too long") if ep: self.data = self.json.loads(ep) return attachment_count def add_attachment(self, attachment): if self.attachment_count <= len(self.attachments): - raise ValueError('Unexpected binary attachment') + raise ValueError("Unexpected binary attachment") self.attachments.append(attachment) if self.attachment_count == len(self.attachments): self.reconstruct_binary(self.attachments) @@ -127,20 +148,21 @@ class Packet(object): """Reconstruct a decoded packet using the given list of binary attachments. """ - self.data = self._reconstruct_binary_internal(self.data, - self.attachments) + self.data = self._reconstruct_binary_internal(self.data, self.attachments) def _reconstruct_binary_internal(self, data, attachments): if isinstance(data, list): - return [self._reconstruct_binary_internal(item, attachments) - for item in data] + return [ + self._reconstruct_binary_internal(item, attachments) for item in data + ] elif isinstance(data, dict): - if data.get('_placeholder') and 'num' in data: - return attachments[data['num']] + if data.get("_placeholder") and "num" in data: + return attachments[data["num"]] else: - return {key: self._reconstruct_binary_internal(value, - attachments) - for key, value in data.items()} + return { + key: self._reconstruct_binary_internal(value, attachments) + for key, value in data.items() + } else: return data @@ -153,13 +175,16 @@ class Packet(object): def _deconstruct_binary_internal(self, data, attachments): if isinstance(data, bytes): attachments.append(data) - return {'_placeholder': True, 'num': len(attachments) - 1} + return {"_placeholder": True, "num": len(attachments) - 1} elif isinstance(data, list): - return [self._deconstruct_binary_internal(item, attachments) - for item in data] + return [ + self._deconstruct_binary_internal(item, attachments) for item in data + ] elif isinstance(data, dict): - return {key: self._deconstruct_binary_internal(value, attachments) - for key, value in data.items()} + return { + key: self._deconstruct_binary_internal(value, attachments) + for key, value in data.items() + } else: return data @@ -169,22 +194,25 @@ class Packet(object): return True elif isinstance(data, list): return functools.reduce( - lambda a, b: a or b, [self._data_is_binary(item) - for item in data], False) + lambda a, b: a or b, + [self._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) - for item in data.values()], - False) + lambda a, b: a or b, + [self._data_is_binary(item) for item in data.values()], + False, + ) else: return False def _to_dict(self): d = { - 'type': self.packet_type, - 'data': self.data, - 'nsp': self.namespace, + "type": self.packet_type, + "data": self.data, + "nsp": self.namespace, } if self.id: - d['id'] = self.id + d["id"] = self.id return d diff --git a/src/socketio/pubsub_manager.py b/src/socketio/pubsub_manager.py index 62eb336..984a256 100644 --- a/src/socketio/pubsub_manager.py +++ b/src/socketio/pubsub_manager.py @@ -21,9 +21,10 @@ class PubSubManager(Manager): :param channel: The channel name on which the server sends and receives notifications. """ - name = 'pubsub' - def __init__(self, channel='socketio', write_only=False, logger=None): + name = "pubsub" + + def __init__(self, channel="socketio", write_only=False, logger=None): super().__init__() self.channel = channel self.write_only = write_only @@ -34,10 +35,18 @@ class PubSubManager(Manager): super().initialize() if not self.write_only: self.thread = self.server.start_background_task(self._thread) - self._get_logger().info(self.name + ' backend initialized.') + self._get_logger().info(self.name + " backend initialized.") - def emit(self, event, data, namespace=None, room=None, skip_sid=None, - callback=None, **kwargs): + def emit( + self, + event, + data, + namespace=None, + room=None, + skip_sid=None, + callback=None, + **kwargs, + ): """Emit a message to a single client, a room, or all the clients connected to the namespace. @@ -46,25 +55,37 @@ class PubSubManager(Manager): The parameters are the same as in :meth:`.Server.emit`. """ - if kwargs.get('ignore_queue'): + if kwargs.get("ignore_queue"): return super().emit( - event, data, namespace=namespace, room=room, skip_sid=skip_sid, - callback=callback) - namespace = namespace or '/' + event, + data, + namespace=namespace, + room=room, + skip_sid=skip_sid, + callback=callback, + ) + namespace = namespace or "/" if callback is not None: if self.server is None: - raise RuntimeError('Callbacks can only be issued from the ' - 'context of a server.') + raise RuntimeError( + "Callbacks can only be issued from the " "context of a server." + ) if room is None: - raise ValueError('Cannot use callback without a room set.') + raise ValueError("Cannot use callback without a room set.") id = self._generate_ack_id(room, callback) callback = (room, namespace, id) else: callback = None - message = {'method': 'emit', 'event': event, 'data': data, - 'namespace': namespace, 'room': room, - 'skip_sid': skip_sid, 'callback': callback, - 'host_id': self.host_id} + message = { + "method": "emit", + "event": event, + "data": data, + "namespace": namespace, + "room": room, + "skip_sid": skip_sid, + "callback": callback, + "host_id": self.host_id, + } self._handle_emit(message) # handle in this host self._publish(message) # notify other hosts @@ -74,16 +95,24 @@ class PubSubManager(Manager): return super().can_disconnect(sid, namespace) else: # client is in another server, so we post request to the queue - message = {'method': 'disconnect', 'sid': sid, - 'namespace': namespace or '/', 'host_id': self.host_id} + message = { + "method": "disconnect", + "sid": sid, + "namespace": namespace or "/", + "host_id": self.host_id, + } self._handle_disconnect(message) # handle in this host self._publish(message) # notify other hosts def disconnect(self, sid, namespace=None, **kwargs): - if kwargs.get('ignore_queue'): + if kwargs.get("ignore_queue"): return super().disconnect(sid, namespace=namespace) - message = {'method': 'disconnect', 'sid': sid, - 'namespace': namespace or '/', 'host_id': self.host_id} + message = { + "method": "disconnect", + "sid": sid, + "namespace": namespace or "/", + "host_id": self.host_id, + } self._handle_disconnect(message) # handle in this host self._publish(message) # notify other hosts @@ -92,8 +121,13 @@ class PubSubManager(Manager): # client is in this server, so we can add to the room directly return super().enter_room(sid, namespace, room, eio_sid=eio_sid) else: - message = {'method': 'enter_room', 'sid': sid, 'room': room, - 'namespace': namespace or '/', 'host_id': self.host_id} + message = { + "method": "enter_room", + "sid": sid, + "room": room, + "namespace": namespace or "/", + "host_id": self.host_id, + } self._publish(message) # notify other hosts def leave_room(self, sid, namespace, room): @@ -101,13 +135,22 @@ class PubSubManager(Manager): # client is in this server, so we can remove from the room directly return super().leave_room(sid, namespace, room) else: - message = {'method': 'leave_room', 'sid': sid, 'room': room, - 'namespace': namespace or '/', 'host_id': self.host_id} + message = { + "method": "leave_room", + "sid": sid, + "room": room, + "namespace": namespace or "/", + "host_id": self.host_id, + } self._publish(message) # notify other hosts def close_room(self, room, namespace=None): - message = {'method': 'close_room', 'room': room, - 'namespace': namespace or '/', 'host_id': self.host_id} + message = { + "method": "close_room", + "room": room, + "namespace": namespace or "/", + "host_id": self.host_id, + } self._handle_close_room(message) # handle in this host self._publish(message) # notify other hosts @@ -117,8 +160,9 @@ class PubSubManager(Manager): This method needs to be implemented by the different subclasses that support pub/sub backends. """ - raise NotImplementedError('This method must be implemented in a ' - 'subclass.') # pragma: no cover + raise NotImplementedError( + "This method must be implemented in a " "subclass." + ) # pragma: no cover def _listen(self): """Return the next message published on the Socket.IO channel, @@ -127,31 +171,35 @@ class PubSubManager(Manager): This method needs to be implemented by the different subclasses that support pub/sub backends. """ - raise NotImplementedError('This method must be implemented in a ' - 'subclass.') # pragma: no cover + raise NotImplementedError( + "This method must be implemented in a " "subclass." + ) # pragma: no cover def _handle_emit(self, message): # Events with callbacks are very tricky to handle across hosts # Here in the receiving end we set up a local callback that preserves # the callback host and id from the sender - remote_callback = message.get('callback') - remote_host_id = message.get('host_id') + remote_callback = message.get("callback") + remote_host_id = message.get("host_id") if remote_callback is not None and len(remote_callback) == 3: - callback = partial(self._return_callback, remote_host_id, - *remote_callback) + callback = partial(self._return_callback, remote_host_id, *remote_callback) else: callback = None - super().emit(message['event'], message['data'], - namespace=message.get('namespace'), - room=message.get('room'), - skip_sid=message.get('skip_sid'), callback=callback) + super().emit( + message["event"], + message["data"], + namespace=message.get("namespace"), + room=message.get("room"), + skip_sid=message.get("skip_sid"), + callback=callback, + ) def _handle_callback(self, message): - if self.host_id == message.get('host_id'): + if self.host_id == message.get("host_id"): try: - sid = message['sid'] - id = message['id'] - args = message['args'] + sid = message["sid"] + id = message["id"] + args = message["args"] except KeyError: return self.trigger_callback(sid, id, args) @@ -162,30 +210,38 @@ class PubSubManager(Manager): if host_id == self.host_id: self.trigger_callback(sid, callback_id, args) else: - self._publish({'method': 'callback', 'host_id': host_id, - 'sid': sid, 'namespace': namespace, - 'id': callback_id, 'args': args}) + self._publish( + { + "method": "callback", + "host_id": host_id, + "sid": sid, + "namespace": namespace, + "id": callback_id, + "args": args, + } + ) def _handle_disconnect(self, message): - self.server.disconnect(sid=message.get('sid'), - namespace=message.get('namespace'), - ignore_queue=True) + self.server.disconnect( + sid=message.get("sid"), + namespace=message.get("namespace"), + ignore_queue=True, + ) def _handle_enter_room(self, message): - sid = message.get('sid') - namespace = message.get('namespace') + sid = message.get("sid") + namespace = message.get("namespace") if self.is_connected(sid, namespace): - super().enter_room(sid, namespace, message.get('room')) + super().enter_room(sid, namespace, message.get("room")) def _handle_leave_room(self, message): - sid = message.get('sid') - namespace = message.get('namespace') + sid = message.get("sid") + namespace = message.get("namespace") if self.is_connected(sid, namespace): - super().leave_room(sid, namespace, message.get('room')) + super().leave_room(sid, namespace, message.get("room")) def _handle_close_room(self, message): - super().close_room(room=message.get('room'), - namespace=message.get('namespace')) + super().close_room(room=message.get("room"), namespace=message.get("namespace")) def _thread(self): for message in self._listen(): @@ -203,23 +259,23 @@ class PubSubManager(Manager): data = json.loads(message) except: pass - if data and 'method' in data: - self._get_logger().debug('pubsub message: {}'.format( - data['method'])) + if data and "method" in data: + self._get_logger().debug("pubsub message: {}".format(data["method"])) try: - if data['method'] == 'callback': + if data["method"] == "callback": self._handle_callback(data) - elif data.get('host_id') != self.host_id: - if data['method'] == 'emit': + elif data.get("host_id") != self.host_id: + if data["method"] == "emit": self._handle_emit(data) - elif data['method'] == 'disconnect': + elif data["method"] == "disconnect": self._handle_disconnect(data) - elif data['method'] == 'enter_room': + elif data["method"] == "enter_room": self._handle_enter_room(data) - elif data['method'] == 'leave_room': + elif data["method"] == "leave_room": self._handle_leave_room(data) - elif data['method'] == 'close_room': + elif data["method"] == "close_room": self._handle_close_room(data) except: self.server.logger.exception( - 'Unknown error in pubsub listening thread') + "Unknown error in pubsub listening thread" + ) diff --git a/src/socketio/redis_manager.py b/src/socketio/redis_manager.py index ae9fa29..8e28405 100644 --- a/src/socketio/redis_manager.py +++ b/src/socketio/redis_manager.py @@ -9,7 +9,7 @@ except ImportError: from .pubsub_manager import PubSubManager -logger = logging.getLogger('socketio') +logger = logging.getLogger("socketio") class RedisManager(PubSubManager): # pragma: no cover @@ -37,14 +37,23 @@ class RedisManager(PubSubManager): # pragma: no cover :param redis_options: additional keyword arguments to be passed to ``Redis.from_url()``. """ - name = 'redis' - def __init__(self, url='redis://localhost:6379/0', channel='socketio', - write_only=False, logger=None, redis_options=None): + name = "redis" + + def __init__( + self, + url="redis://localhost:6379/0", + channel="socketio", + write_only=False, + logger=None, + redis_options=None, + ): if redis is None: - raise RuntimeError('Redis package is not installed ' - '(Run "pip install redis" in your ' - 'virtualenv).') + raise RuntimeError( + "Redis package is not installed " + '(Run "pip install redis" in your ' + "virtualenv)." + ) self.redis_url = url self.redis_options = redis_options or {} self._redis_connect() @@ -54,20 +63,22 @@ class RedisManager(PubSubManager): # pragma: no cover super().initialize() monkey_patched = True - if self.server.async_mode == 'eventlet': + if self.server.async_mode == "eventlet": from eventlet.patcher import is_monkey_patched - monkey_patched = is_monkey_patched('socket') - elif 'gevent' in self.server.async_mode: + + monkey_patched = is_monkey_patched("socket") + elif "gevent" in self.server.async_mode: from gevent.monkey import is_module_patched - monkey_patched = is_module_patched('socket') + + monkey_patched = is_module_patched("socket") if not monkey_patched: raise RuntimeError( - 'Redis requires a monkey patched socket library to work ' - 'with ' + self.server.async_mode) + "Redis requires a monkey patched socket library to work " + "with " + self.server.async_mode + ) def _redis_connect(self): - self.redis = redis.Redis.from_url(self.redis_url, - **self.redis_options) + self.redis = redis.Redis.from_url(self.redis_url, **self.redis_options) self.pubsub = self.redis.pubsub(ignore_subscribe_messages=True) def _publish(self, data): @@ -79,10 +90,10 @@ class RedisManager(PubSubManager): # pragma: no cover return self.redis.publish(self.channel, pickle.dumps(data)) except redis.exceptions.RedisError: if retry: - logger.error('Cannot publish to redis... retrying') + logger.error("Cannot publish to redis... retrying") retry = False else: - logger.error('Cannot publish to redis... giving up') + logger.error("Cannot publish to redis... giving up") break def _redis_listen_with_retries(self): @@ -97,8 +108,11 @@ class RedisManager(PubSubManager): # pragma: no cover for message in self.pubsub.listen(): yield message except redis.exceptions.RedisError: - logger.error('Cannot receive from redis... ' - 'retrying in {} secs'.format(retry_sleep)) + logger.error( + "Cannot receive from redis... " "retrying in {} secs".format( + retry_sleep + ) + ) connect = True time.sleep(retry_sleep) retry_sleep *= 2 @@ -106,10 +120,13 @@ class RedisManager(PubSubManager): # pragma: no cover retry_sleep = 60 def _listen(self): - channel = self.channel.encode('utf-8') + channel = self.channel.encode("utf-8") self.pubsub.subscribe(self.channel) for message in self._redis_listen_with_retries(): - if message['channel'] == channel and \ - message['type'] == 'message' and 'data' in message: - yield message['data'] + if ( + message["channel"] == channel + and message["type"] == "message" + and "data" in message + ): + yield message["data"] self.pubsub.unsubscribe(self.channel) diff --git a/src/socketio/server.py b/src/socketio/server.py index 2081337..11123ed 100644 --- a/src/socketio/server.py +++ b/src/socketio/server.py @@ -6,7 +6,7 @@ from . import base_server from . import exceptions from . import packet -default_logger = logging.getLogger('socketio.server') +default_logger = logging.getLogger("socketio.server") class Server(base_server.BaseServer): @@ -110,8 +110,18 @@ class Server(base_server.BaseServer): fatal errors are logged even when ``engineio_logger`` is ``False``. """ - def emit(self, event, data=None, to=None, room=None, skip_sid=None, - namespace=None, callback=None, ignore_queue=False): + + def emit( + self, + event, + data=None, + to=None, + room=None, + skip_sid=None, + namespace=None, + callback=None, + ignore_queue=False, + ): """Emit a custom event to one or more connected clients. :param event: The event name. It can be any string. The event names @@ -154,16 +164,31 @@ class Server(base_server.BaseServer): standard concurrency solutions (such as a Lock object) to prevent this situation. """ - namespace = namespace or '/' + namespace = namespace or "/" room = to or room - self.logger.info('emitting event "%s" to %s [%s]', event, - room or 'all', namespace) - self.manager.emit(event, data, namespace, room=room, - skip_sid=skip_sid, callback=callback, - ignore_queue=ignore_queue) - - def send(self, data, to=None, room=None, skip_sid=None, namespace=None, - callback=None, ignore_queue=False): + self.logger.info( + 'emitting event "%s" to %s [%s]', event, room or "all", namespace + ) + self.manager.emit( + event, + data, + namespace, + room=room, + skip_sid=skip_sid, + callback=callback, + ignore_queue=ignore_queue, + ) + + def send( + self, + data, + to=None, + room=None, + skip_sid=None, + namespace=None, + callback=None, + ignore_queue=False, + ): """Send a message to one or more connected clients. This function emits an event with the name ``'message'``. Use @@ -200,12 +225,27 @@ class Server(base_server.BaseServer): to always leave this parameter with its default value of ``False``. """ - self.emit('message', data=data, to=to, room=room, skip_sid=skip_sid, - namespace=namespace, callback=callback, - ignore_queue=ignore_queue) - - def call(self, event, data=None, to=None, sid=None, namespace=None, - timeout=60, ignore_queue=False): + self.emit( + "message", + data=data, + to=to, + room=room, + skip_sid=skip_sid, + namespace=namespace, + callback=callback, + ignore_queue=ignore_queue, + ) + + def call( + self, + event, + data=None, + to=None, + sid=None, + namespace=None, + timeout=60, + ignore_queue=False, + ): """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 @@ -244,10 +284,9 @@ class Server(base_server.BaseServer): situation. """ if to is None and sid is None: - raise ValueError('Cannot use call() to broadcast.') + raise ValueError("Cannot use call() to broadcast.") if not self.async_handlers: - raise RuntimeError( - 'Cannot use call() when async_handlers is False.') + raise RuntimeError("Cannot use call() when async_handlers is False.") callback_event = self.eio.create_event() callback_args = [] @@ -255,13 +294,23 @@ class Server(base_server.BaseServer): callback_args.append(args) callback_event.set() - self.emit(event, data=data, room=to or sid, namespace=namespace, - callback=event_callback, ignore_queue=ignore_queue) + self.emit( + event, + data=data, + room=to or sid, + namespace=namespace, + callback=event_callback, + ignore_queue=ignore_queue, + ) if not callback_event.wait(timeout=timeout): raise exceptions.TimeoutError() - return callback_args[0] if len(callback_args[0]) > 1 \ - else callback_args[0][0] if len(callback_args[0]) == 1 \ + return ( + callback_args[0] + if len(callback_args[0]) > 1 + else callback_args[0][0] + if len(callback_args[0]) == 1 else None + ) def enter_room(self, sid, room, namespace=None): """Enter a room. @@ -275,8 +324,8 @@ class Server(base_server.BaseServer): :param namespace: The Socket.IO namespace for the event. If this argument is omitted the default namespace is used. """ - namespace = namespace or '/' - self.logger.info('%s is entering room %s [%s]', sid, room, namespace) + namespace = namespace or "/" + self.logger.info("%s is entering room %s [%s]", sid, room, namespace) self.manager.enter_room(sid, namespace, room) def leave_room(self, sid, room, namespace=None): @@ -289,8 +338,8 @@ class Server(base_server.BaseServer): :param namespace: The Socket.IO namespace for the event. If this argument is omitted the default namespace is used. """ - namespace = namespace or '/' - self.logger.info('%s is leaving room %s [%s]', sid, room, namespace) + namespace = namespace or "/" + self.logger.info("%s is leaving room %s [%s]", sid, room, namespace) self.manager.leave_room(sid, namespace, room) def close_room(self, room, namespace=None): @@ -302,8 +351,8 @@ class Server(base_server.BaseServer): :param namespace: The Socket.IO namespace for the event. If this argument is omitted the default namespace is used. """ - namespace = namespace or '/' - self.logger.info('room %s is closing [%s]', room, namespace) + namespace = namespace or "/" + self.logger.info("room %s is closing [%s]", room, namespace) self.manager.close_room(room, namespace) def get_session(self, sid, namespace=None): @@ -318,7 +367,7 @@ class Server(base_server.BaseServer): ``save_session()`` is called, or when the ``session`` context manager is used. """ - namespace = namespace or '/' + namespace = namespace or "/" eio_sid = self.manager.eio_sid_from_sid(sid, namespace) eio_session = self.eio.get_session(eio_sid) return eio_session.setdefault(namespace, {}) @@ -331,7 +380,7 @@ class Server(base_server.BaseServer): :param namespace: The Socket.IO namespace. If this argument is omitted the default namespace is used. """ - namespace = namespace or '/' + namespace = namespace or "/" eio_sid = self.manager.eio_sid_from_sid(sid, namespace) eio_session = self.eio.get_session(eio_sid) eio_session[namespace] = session @@ -358,6 +407,7 @@ class Server(base_server.BaseServer): with sio.session(sid) as session: print('received message from ', session['username']) """ + class _session_context_manager(object): def __init__(self, server, sid, namespace): self.server = server @@ -366,13 +416,11 @@ class Server(base_server.BaseServer): self.session = None def __enter__(self): - self.session = self.server.get_session(sid, - namespace=namespace) + self.session = self.server.get_session(sid, namespace=namespace) return self.session def __exit__(self, *args): - self.server.save_session(sid, self.session, - namespace=namespace) + self.server.save_session(sid, self.session, namespace=namespace) return _session_context_manager(self, sid, namespace) @@ -388,19 +436,19 @@ class Server(base_server.BaseServer): recommended to always leave this parameter with its default value of ``False``. """ - namespace = namespace or '/' + namespace = namespace or "/" if ignore_queue: delete_it = self.manager.is_connected(sid, namespace) else: delete_it = self.manager.can_disconnect(sid, namespace) if delete_it: - self.logger.info('Disconnecting %s [%s]', sid, namespace) + self.logger.info("Disconnecting %s [%s]", sid, namespace) eio_sid = self.manager.pre_disconnect(sid, namespace=namespace) - self._send_packet(eio_sid, self.packet_class( - packet.DISCONNECT, namespace=namespace)) - self._trigger_event('disconnect', namespace, sid) - self.manager.disconnect(sid, namespace=namespace, - ignore_queue=True) + self._send_packet( + eio_sid, self.packet_class(packet.DISCONNECT, namespace=namespace) + ) + self._trigger_event("disconnect", namespace, sid) + self.manager.disconnect(sid, namespace=namespace, ignore_queue=True) def shutdown(self): """Stop Socket.IO background tasks. @@ -408,7 +456,7 @@ class Server(base_server.BaseServer): This method stops all background activity initiated by the Socket.IO server. It must be called before shutting down the web server. """ - self.logger.info('Socket.IO is shutting down') + self.logger.info("Socket.IO is shutting down") self.eio.shutdown() def handle_request(self, environ, start_response): @@ -454,9 +502,15 @@ class Server(base_server.BaseServer): """ return self.eio.sleep(seconds) - def instrument(self, auth=None, mode='development', read_only=False, - server_id=None, namespace='/admin', - server_stats_interval=2): + def instrument( + self, + auth=None, + mode="development", + read_only=False, + server_id=None, + namespace="/admin", + server_stats_interval=2, + ): """Instrument the Socket.IO server for monitoring with the `Socket.IO Admin UI `_. @@ -488,10 +542,16 @@ class Server(base_server.BaseServer): connected admins. """ from .admin import InstrumentedServer + return InstrumentedServer( - self, auth=auth, mode=mode, read_only=read_only, - server_id=server_id, namespace=namespace, - server_stats_interval=server_stats_interval) + self, + auth=auth, + mode=mode, + read_only=read_only, + server_id=server_id, + namespace=namespace, + server_stats_interval=server_stats_interval, + ) def _send_packet(self, eio_sid, pkt): """Send a Socket.IO packet to a client.""" @@ -508,32 +568,44 @@ class Server(base_server.BaseServer): def _handle_connect(self, eio_sid, namespace, data): """Handle a client connection request.""" - namespace = namespace or '/' + namespace = namespace or "/" sid = None - if namespace in self.handlers or namespace in self.namespace_handlers \ - or self.namespaces == '*' or namespace in self.namespaces: + if ( + namespace in self.handlers + or namespace in self.namespace_handlers + or self.namespaces == "*" + or namespace in self.namespaces + ): sid = self.manager.connect(eio_sid, namespace) if sid is None: - self._send_packet(eio_sid, self.packet_class( - packet.CONNECT_ERROR, data='Unable to connect', - namespace=namespace)) + self._send_packet( + eio_sid, + self.packet_class( + packet.CONNECT_ERROR, data="Unable to connect", namespace=namespace + ), + ) return if self.always_connect: - self._send_packet(eio_sid, self.packet_class( - packet.CONNECT, {'sid': sid}, namespace=namespace)) + self._send_packet( + eio_sid, + self.packet_class(packet.CONNECT, {"sid": sid}, namespace=namespace), + ) fail_reason = exceptions.ConnectionRefusedError().error_args try: if data: success = self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid], data) + "connect", namespace, sid, self.environ[eio_sid], data + ) else: try: success = self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid]) + "connect", namespace, sid, self.environ[eio_sid] + ) except TypeError: success = self._trigger_event( - 'connect', namespace, sid, self.environ[eio_sid], None) + "connect", namespace, sid, self.environ[eio_sid], None + ) except exceptions.ConnectionRefusedError as exc: fail_reason = exc.error_args success = False @@ -541,46 +613,52 @@ class Server(base_server.BaseServer): if success is False: if self.always_connect: self.manager.pre_disconnect(sid, namespace) - self._send_packet(eio_sid, self.packet_class( - packet.DISCONNECT, data=fail_reason, namespace=namespace)) + self._send_packet( + eio_sid, + self.packet_class( + packet.DISCONNECT, data=fail_reason, namespace=namespace + ), + ) else: - self._send_packet(eio_sid, self.packet_class( - packet.CONNECT_ERROR, data=fail_reason, - namespace=namespace)) + self._send_packet( + eio_sid, + self.packet_class( + packet.CONNECT_ERROR, data=fail_reason, namespace=namespace + ), + ) self.manager.disconnect(sid, namespace, ignore_queue=True) elif not self.always_connect: - self._send_packet(eio_sid, self.packet_class( - packet.CONNECT, {'sid': sid}, namespace=namespace)) + self._send_packet( + eio_sid, + self.packet_class(packet.CONNECT, {"sid": sid}, namespace=namespace), + ) def _handle_disconnect(self, eio_sid, namespace): """Handle a client disconnect.""" - namespace = namespace or '/' + namespace = namespace or "/" sid = self.manager.sid_from_eio_sid(eio_sid, namespace) if not self.manager.is_connected(sid, namespace): # pragma: no cover return self.manager.pre_disconnect(sid, namespace=namespace) - self._trigger_event('disconnect', namespace, sid) + self._trigger_event("disconnect", namespace, sid) self.manager.disconnect(sid, namespace, ignore_queue=True) def _handle_event(self, eio_sid, namespace, id, data): """Handle an incoming client event.""" - namespace = namespace or '/' + namespace = namespace or "/" sid = self.manager.sid_from_eio_sid(eio_sid, namespace) - self.logger.info('received event "%s" from %s [%s]', data[0], sid, - namespace) + self.logger.info('received event "%s" from %s [%s]', data[0], sid, namespace) if not self.manager.is_connected(sid, namespace): - self.logger.warning('%s is not connected to namespace %s', - sid, namespace) + self.logger.warning("%s is not connected to namespace %s", sid, namespace) return if self.async_handlers: - self.start_background_task(self._handle_event_internal, self, sid, - eio_sid, data, namespace, id) + self.start_background_task( + self._handle_event_internal, self, sid, eio_sid, data, namespace, id + ) else: - self._handle_event_internal(self, sid, eio_sid, data, namespace, - id) + self._handle_event_internal(self, sid, eio_sid, data, namespace, id) - def _handle_event_internal(self, server, sid, eio_sid, data, namespace, - id): + def _handle_event_internal(self, server, sid, eio_sid, data, namespace, id): r = server._trigger_event(data[0], namespace, sid, *data[1:]) if r != self.not_handled and id is not None: # send ACK packet with the response returned by the handler @@ -591,14 +669,16 @@ class Server(base_server.BaseServer): data = list(r) else: data = [r] - server._send_packet(eio_sid, self.packet_class( - packet.ACK, namespace=namespace, id=id, data=data)) + server._send_packet( + eio_sid, + self.packet_class(packet.ACK, namespace=namespace, id=id, data=data), + ) def _handle_ack(self, eio_sid, namespace, id, data): """Handle ACK packets from the client.""" - namespace = namespace or '/' + namespace = namespace or "/" sid = self.manager.sid_from_eio_sid(eio_sid, namespace) - self.logger.info('received ack from %s [%s]', sid, namespace) + self.logger.info("received ack from %s [%s]", sid, namespace) self.manager.trigger_callback(sid, id, data) def _trigger_event(self, event, namespace, *args): @@ -607,16 +687,14 @@ class Server(base_server.BaseServer): if namespace in self.handlers: if event in self.handlers[namespace]: return self.handlers[namespace][event](*args) - elif event not in self.reserved_events and \ - '*' in self.handlers[namespace]: - return self.handlers[namespace]['*'](event, *args) + elif event not in self.reserved_events and "*" in self.handlers[namespace]: + return self.handlers[namespace]["*"](event, *args) else: return self.not_handled # or else, forward the event to a namespace handler if one exists elif namespace in self.namespace_handlers: # pragma: no branch - return self.namespace_handlers[namespace].trigger_event( - event, *args) + return self.namespace_handlers[namespace].trigger_event(event, *args) def _handle_eio_connect(self, eio_sid, environ): """Handle the Engine.IO connection event.""" @@ -632,8 +710,7 @@ class Server(base_server.BaseServer): if pkt.add_attachment(data): del self._binary_packet[eio_sid] if pkt.packet_type == packet.BINARY_EVENT: - self._handle_event(eio_sid, pkt.namespace, pkt.id, - pkt.data) + self._handle_event(eio_sid, pkt.namespace, pkt.id, pkt.data) else: self._handle_ack(eio_sid, pkt.namespace, pkt.id, pkt.data) else: @@ -646,13 +723,15 @@ class Server(base_server.BaseServer): self._handle_event(eio_sid, pkt.namespace, pkt.id, pkt.data) elif pkt.packet_type == packet.ACK: self._handle_ack(eio_sid, pkt.namespace, pkt.id, pkt.data) - elif pkt.packet_type == packet.BINARY_EVENT or \ - pkt.packet_type == packet.BINARY_ACK: + elif ( + pkt.packet_type == packet.BINARY_EVENT + or pkt.packet_type == packet.BINARY_ACK + ): self._binary_packet[eio_sid] = pkt elif pkt.packet_type == packet.CONNECT_ERROR: - raise ValueError('Unexpected CONNECT_ERROR packet.') + raise ValueError("Unexpected CONNECT_ERROR packet.") else: - raise ValueError('Unknown packet type.') + raise ValueError("Unknown packet type.") def _handle_eio_disconnect(self, eio_sid): """Handle Engine.IO disconnect event.""" diff --git a/src/socketio/simple_client.py b/src/socketio/simple_client.py index ce3a1c5..af1d28f 100644 --- a/src/socketio/simple_client.py +++ b/src/socketio/simple_client.py @@ -12,18 +12,27 @@ class SimpleClient: Th positional and keyword arguments given in the constructor are passed to the underlying :func:`socketio.Client` object. """ + def __init__(self, *args, **kwargs): self.client_args = args self.client_kwargs = kwargs self.client = None - self.namespace = '/' + self.namespace = "/" self.connected_event = Event() self.connected = False self.input_event = Event() self.input_buffer = [] - def connect(self, url, headers={}, auth=None, transports=None, - namespace='/', socketio_path='socket.io', wait_timeout=5): + def connect( + self, + url, + headers={}, + auth=None, + transports=None, + namespace="/", + socketio_path="socket.io", + wait_timeout=5, + ): """Connect to a Socket.IO server. :param url: The URL of the Socket.IO server. It can include custom @@ -54,7 +63,7 @@ class SimpleClient: seconds. """ if self.connected: - raise RuntimeError('Already connected') + raise RuntimeError("Already connected") self.namespace = namespace self.input_buffer = [] self.input_event.clear() @@ -74,15 +83,20 @@ class SimpleClient: self.connected = False self.connected_event.set() - @self.client.on('*', namespace=self.namespace) + @self.client.on("*", namespace=self.namespace) def on_event(event, *args): # pragma: no cover self.input_buffer.append([event, *args]) self.input_event.set() - self.client.connect(url, headers=headers, auth=auth, - transports=transports, namespaces=[namespace], - socketio_path=socketio_path, - wait_timeout=wait_timeout) + self.client.connect( + url, + headers=headers, + auth=auth, + transports=transports, + namespaces=[namespace], + socketio_path=socketio_path, + wait_timeout=wait_timeout, + ) @property def sid(self): @@ -100,7 +114,7 @@ class SimpleClient: The transport is returned as a string and can be one of ``polling`` and ``websocket``. """ - return self.client.transport if self.client else '' + return self.client.transport if self.client else "" def emit(self, event, data=None): """Emit an event to the server. @@ -150,8 +164,9 @@ class SimpleClient: if not self.connected: raise DisconnectedError() try: - return self.client.call(event, data, namespace=self.namespace, - timeout=timeout) + return self.client.call( + event, data, namespace=self.namespace, timeout=timeout + ) except SocketIOError: pass @@ -167,8 +182,7 @@ class SimpleClient: additional list elements. """ while not self.input_buffer: - if not self.connected_event.wait( - timeout=timeout): # pragma: no cover + if not self.connected_event.wait(timeout=timeout): # pragma: no cover raise TimeoutError() if not self.connected: raise DisconnectedError() diff --git a/src/socketio/tornado.py b/src/socketio/tornado.py index 5b2e6f6..7d69ff8 100644 --- a/src/socketio/tornado.py +++ b/src/socketio/tornado.py @@ -1,8 +1,10 @@ import sys + if sys.version_info >= (3, 5): try: - from engineio.async_drivers.tornado import get_tornado_handler as \ - get_engineio_handler + from engineio.async_drivers.tornado import ( + get_tornado_handler as get_engineio_handler, + ) except ImportError: # pragma: no cover get_engineio_handler = None diff --git a/src/socketio/zmq_manager.py b/src/socketio/zmq_manager.py index 760fbc3..82ab282 100644 --- a/src/socketio/zmq_manager.py +++ b/src/socketio/zmq_manager.py @@ -40,33 +40,39 @@ class ZmqManager(PubSubManager): # pragma: no cover while True: publisher.send(receiver.recv()) """ - name = 'zmq' - def __init__(self, url='zmq+tcp://localhost:5555+5556', - channel='socketio', - write_only=False, - logger=None): + name = "zmq" + + def __init__( + self, + url="zmq+tcp://localhost:5555+5556", + channel="socketio", + write_only=False, + logger=None, + ): try: from eventlet.green import zmq except ImportError: - raise RuntimeError('zmq package is not installed ' - '(Run "pip install pyzmq" in your ' - 'virtualenv).') - - r = re.compile(r':\d+\+\d+$') - if not (url.startswith('zmq+tcp://') and r.search(url)): - raise RuntimeError('unexpected connection string: ' + url) - - url = url.replace('zmq+', '') - (sink_url, sub_port) = url.split('+') - sink_port = sink_url.split(':')[-1] + raise RuntimeError( + "zmq package is not installed " + '(Run "pip install pyzmq" in your ' + "virtualenv)." + ) + + r = re.compile(r":\d+\+\d+$") + if not (url.startswith("zmq+tcp://") and r.search(url)): + raise RuntimeError("unexpected connection string: " + url) + + url = url.replace("zmq+", "") + (sink_url, sub_port) = url.split("+") + sink_port = sink_url.split(":")[-1] sub_url = sink_url.replace(sink_port, sub_port) sink = zmq.Context().socket(zmq.PUSH) sink.connect(sink_url) sub = zmq.Context().socket(zmq.SUB) - sub.setsockopt_string(zmq.SUBSCRIBE, u'') + sub.setsockopt_string(zmq.SUBSCRIBE, "") sub.connect(sub_url) self.sink = sink @@ -76,11 +82,7 @@ class ZmqManager(PubSubManager): # pragma: no cover def _publish(self, data): pickled_data = pickle.dumps( - { - 'type': 'message', - 'channel': self.channel, - 'data': data - } + {"type": "message", "channel": self.channel, "data": data} ) return self.sink.send(pickled_data) @@ -97,9 +99,11 @@ class ZmqManager(PubSubManager): # pragma: no cover message = pickle.loads(message) except Exception: pass - if isinstance(message, dict) and \ - message['type'] == 'message' and \ - message['channel'] == self.channel and \ - 'data' in message: - yield message['data'] + if ( + isinstance(message, dict) + and message["type"] == "message" + and message["channel"] == self.channel + and "data" in message + ): + yield message["data"] return diff --git a/tests/async/test_admin.py b/tests/async/test_admin.py index 95b8fef..4603769 100644 --- a/tests/async/test_admin.py +++ b/tests/async/test_admin.py @@ -4,6 +4,7 @@ import time from unittest import mock import unittest import pytest + try: from engineio.async_socket import AsyncSocket as EngineIOSocket except ImportError: @@ -20,10 +21,11 @@ def with_instrumented_server(auth=False, **ikwargs): Admin UI project. The arguments passed to the decorator are passed directly to the ``instrument()`` method of the server. """ + def decorator(f): @wraps(f) def wrapped(self, *args, **kwargs): - sio = socketio.AsyncServer(async_mode='asgi') + sio = socketio.AsyncServer(async_mode="asgi") @sio.event async def enter_room(sid, data): @@ -33,7 +35,7 @@ def with_instrumented_server(auth=False, **ikwargs): async def emit(sid, event): await sio.emit(event, skip_sid=sid) - @sio.event(namespace='/foo') + @sio.event(namespace="/foo") def connect(sid, environ, auth): pass @@ -41,8 +43,8 @@ def with_instrumented_server(auth=False, **ikwargs): await instrumented_server.shutdown() await sio.shutdown() - if 'server_stats_interval' not in ikwargs: - ikwargs['server_stats_interval'] = 0.25 + if "server_stats_interval" not in ikwargs: + ikwargs["server_stats_interval"] = 0.25 instrumented_server = sio.instrument(auth=auth, **ikwargs) server = SocketIOWebServer(sio, on_shutdown=shutdown) @@ -68,107 +70,115 @@ def with_instrumented_server(auth=False, **ikwargs): # logging.getLogger('socketio.client').setLevel(logging.NOTSET) return ret + return wrapped + return decorator def _custom_auth(auth): - return auth == {'foo': 'bar'} + return auth == {"foo": "bar"} async def _async_custom_auth(auth): - return auth == {'foo': 'bar'} + return auth == {"foo": "bar"} class TestAsyncAdmin(unittest.TestCase): def setUp(self): - print('threads at start:', threading.enumerate()) + print("threads at start:", threading.enumerate()) self.thread_count = threading.active_count() def tearDown(self): - print('threads at end:', threading.enumerate()) + print("threads at end:", threading.enumerate()) assert self.thread_count == threading.active_count() def test_missing_auth(self): - sio = socketio.AsyncServer(async_mode='asgi') + sio = socketio.AsyncServer(async_mode="asgi") with pytest.raises(ValueError): sio.instrument() @with_instrumented_server(auth=False) def test_admin_connect_with_no_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) - @with_instrumented_server(auth={'foo': 'bar'}) + @with_instrumented_server(auth={"foo": "bar"}) def test_admin_connect_with_dict_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): admin_client.connect( - 'http://localhost:8900', namespace='/admin', - auth={'foo': 'baz'}) + "http://localhost:8900", namespace="/admin", auth={"foo": "baz"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect( - 'http://localhost:8900', namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") - @with_instrumented_server(auth=[{'foo': 'bar'}, - {'u': 'admin', 'p': 'secret'}]) + @with_instrumented_server(auth=[{"foo": "bar"}, {"u": "admin", "p": "secret"}]) def test_admin_connect_with_list_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'u': 'admin', 'p': 'secret'}) + admin_client.connect( + "http://localhost:8900", + namespace="/admin", + auth={"u": "admin", "p": "secret"}, + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin', auth={'foo': 'baz'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "baz"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") @with_instrumented_server(auth=_custom_auth) def test_admin_connect_with_function_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin', auth={'foo': 'baz'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "baz"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") @with_instrumented_server(auth=_async_custom_auth) def test_admin_connect_with_async_function_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin', auth={'foo': 'baz'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "baz"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") @with_instrumented_server() def test_admin_connect_only_admin(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") sid = admin_client.sid - expected = ['config', 'all_sockets', 'server_stats'] + expected = ["config", "all_sockets", "server_stats"] events = {} while expected: data = admin_client.receive(timeout=5) @@ -176,46 +186,45 @@ class TestAsyncAdmin(unittest.TestCase): events[data[0]] = data[1] expected.remove(data[0]) - assert 'supportedFeatures' in events['config'] - assert 'ALL_EVENTS' in events['config']['supportedFeatures'] - assert 'AGGREGATED_EVENTS' in events['config']['supportedFeatures'] - assert 'EMIT' in events['config']['supportedFeatures'] - assert len(events['all_sockets']) == 1 - assert events['all_sockets'][0]['id'] == sid - assert events['all_sockets'][0]['rooms'] == [sid] - assert events['server_stats']['clientsCount'] == 1 - assert events['server_stats']['pollingClientsCount'] == 0 - assert len(events['server_stats']['namespaces']) == 3 - assert {'name': '/', 'socketsCount': 0} in \ - events['server_stats']['namespaces'] - assert {'name': '/foo', 'socketsCount': 0} in \ - events['server_stats']['namespaces'] - assert {'name': '/admin', 'socketsCount': 1} in \ - events['server_stats']['namespaces'] + assert "supportedFeatures" in events["config"] + assert "ALL_EVENTS" in events["config"]["supportedFeatures"] + assert "AGGREGATED_EVENTS" in events["config"]["supportedFeatures"] + assert "EMIT" in events["config"]["supportedFeatures"] + assert len(events["all_sockets"]) == 1 + assert events["all_sockets"][0]["id"] == sid + assert events["all_sockets"][0]["rooms"] == [sid] + assert events["server_stats"]["clientsCount"] == 1 + assert events["server_stats"]["pollingClientsCount"] == 0 + assert len(events["server_stats"]["namespaces"]) == 3 + assert {"name": "/", "socketsCount": 0} in events["server_stats"]["namespaces"] + assert {"name": "/foo", "socketsCount": 0} in events["server_stats"][ + "namespaces" + ] + assert {"name": "/admin", "socketsCount": 1} in events["server_stats"][ + "namespaces" + ] @with_instrumented_server() def test_admin_connect_with_others(self, isvr): - with socketio.SimpleClient() as client1, \ - socketio.SimpleClient() as client2, \ - socketio.SimpleClient() as client3, \ - socketio.SimpleClient() as admin_client: - client1.connect('http://localhost:8900') - client1.emit('enter_room', 'room') + with socketio.SimpleClient() as client1, socketio.SimpleClient() as client2, socketio.SimpleClient() as client3, socketio.SimpleClient() as admin_client: + client1.connect("http://localhost:8900") + client1.emit("enter_room", "room") sid1 = client1.sid saved_check_for_upgrade = isvr._check_for_upgrade isvr._check_for_upgrade = AsyncMock() - client2.connect('http://localhost:8900', namespace='/foo', - transports=['polling']) + client2.connect( + "http://localhost:8900", namespace="/foo", transports=["polling"] + ) sid2 = client2.sid isvr._check_for_upgrade = saved_check_for_upgrade - client3.connect('http://localhost:8900', namespace='/admin') + client3.connect("http://localhost:8900", namespace="/admin") sid3 = client3.sid - admin_client.connect('http://localhost:8900', namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") sid = admin_client.sid - expected = ['config', 'all_sockets', 'server_stats'] + expected = ["config", "all_sockets", "server_stats"] events = {} while expected: data = admin_client.receive(timeout=5) @@ -223,36 +232,37 @@ class TestAsyncAdmin(unittest.TestCase): events[data[0]] = data[1] expected.remove(data[0]) - assert 'supportedFeatures' in events['config'] - assert 'ALL_EVENTS' in events['config']['supportedFeatures'] - assert 'AGGREGATED_EVENTS' in events['config']['supportedFeatures'] - assert 'EMIT' in events['config']['supportedFeatures'] - assert len(events['all_sockets']) == 4 - assert events['server_stats']['clientsCount'] == 4 - assert events['server_stats']['pollingClientsCount'] == 1 - assert len(events['server_stats']['namespaces']) == 3 - assert {'name': '/', 'socketsCount': 1} in \ - events['server_stats']['namespaces'] - assert {'name': '/foo', 'socketsCount': 1} in \ - events['server_stats']['namespaces'] - assert {'name': '/admin', 'socketsCount': 2} in \ - events['server_stats']['namespaces'] - - for socket in events['all_sockets']: - if socket['id'] == sid: - assert socket['rooms'] == [sid] - elif socket['id'] == sid1: - assert socket['rooms'] == [sid1, 'room'] - elif socket['id'] == sid2: - assert socket['rooms'] == [sid2] - elif socket['id'] == sid3: - assert socket['rooms'] == [sid3] - - @with_instrumented_server(mode='production', read_only=True) + assert "supportedFeatures" in events["config"] + assert "ALL_EVENTS" in events["config"]["supportedFeatures"] + assert "AGGREGATED_EVENTS" in events["config"]["supportedFeatures"] + assert "EMIT" in events["config"]["supportedFeatures"] + assert len(events["all_sockets"]) == 4 + assert events["server_stats"]["clientsCount"] == 4 + assert events["server_stats"]["pollingClientsCount"] == 1 + assert len(events["server_stats"]["namespaces"]) == 3 + assert {"name": "/", "socketsCount": 1} in events["server_stats"]["namespaces"] + assert {"name": "/foo", "socketsCount": 1} in events["server_stats"][ + "namespaces" + ] + assert {"name": "/admin", "socketsCount": 2} in events["server_stats"][ + "namespaces" + ] + + for socket in events["all_sockets"]: + if socket["id"] == sid: + assert socket["rooms"] == [sid] + elif socket["id"] == sid1: + assert socket["rooms"] == [sid1, "room"] + elif socket["id"] == sid2: + assert socket["rooms"] == [sid2] + elif socket["id"] == sid3: + assert socket["rooms"] == [sid3] + + @with_instrumented_server(mode="production", read_only=True) def test_admin_connect_production(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin') - expected = ['config', 'server_stats'] + admin_client.connect("http://localhost:8900", namespace="/admin") + expected = ["config", "server_stats"] events = {} while expected: data = admin_client.receive(timeout=5) @@ -260,50 +270,49 @@ class TestAsyncAdmin(unittest.TestCase): events[data[0]] = data[1] expected.remove(data[0]) - assert 'supportedFeatures' in events['config'] - assert 'ALL_EVENTS' not in events['config']['supportedFeatures'] - assert 'AGGREGATED_EVENTS' in events['config']['supportedFeatures'] - assert 'EMIT' not in events['config']['supportedFeatures'] - assert events['server_stats']['clientsCount'] == 1 - assert events['server_stats']['pollingClientsCount'] == 0 - assert len(events['server_stats']['namespaces']) == 3 - assert {'name': '/', 'socketsCount': 0} in \ - events['server_stats']['namespaces'] - assert {'name': '/foo', 'socketsCount': 0} in \ - events['server_stats']['namespaces'] - assert {'name': '/admin', 'socketsCount': 1} in \ - events['server_stats']['namespaces'] + assert "supportedFeatures" in events["config"] + assert "ALL_EVENTS" not in events["config"]["supportedFeatures"] + assert "AGGREGATED_EVENTS" in events["config"]["supportedFeatures"] + assert "EMIT" not in events["config"]["supportedFeatures"] + assert events["server_stats"]["clientsCount"] == 1 + assert events["server_stats"]["pollingClientsCount"] == 0 + assert len(events["server_stats"]["namespaces"]) == 3 + assert {"name": "/", "socketsCount": 0} in events["server_stats"]["namespaces"] + assert {"name": "/foo", "socketsCount": 0} in events["server_stats"][ + "namespaces" + ] + assert {"name": "/admin", "socketsCount": 1} in events["server_stats"][ + "namespaces" + ] @with_instrumented_server() def test_admin_features(self, isvr): - with socketio.SimpleClient() as client1, \ - socketio.SimpleClient() as client2, \ - socketio.SimpleClient() as admin_client: - client1.connect('http://localhost:8900') - client2.connect('http://localhost:8900') - admin_client.connect('http://localhost:8900', namespace='/admin') + with socketio.SimpleClient() as client1, socketio.SimpleClient() as client2, socketio.SimpleClient() as admin_client: + client1.connect("http://localhost:8900") + client2.connect("http://localhost:8900") + admin_client.connect("http://localhost:8900", namespace="/admin") # emit from admin admin_client.emit( - 'emit', ('/', client1.sid, 'foo', {'bar': 'baz'}, 'extra')) + "emit", ("/", client1.sid, "foo", {"bar": "baz"}, "extra") + ) data = client1.receive(timeout=5) - assert data == ['foo', {'bar': 'baz'}, 'extra'] + assert data == ["foo", {"bar": "baz"}, "extra"] # emit from regular client - client1.emit('emit', 'foo') + client1.emit("emit", "foo") data = client2.receive(timeout=5) - assert data == ['foo'] + assert data == ["foo"] # join and leave - admin_client.emit('join', ('/', 'room', client1.sid)) - admin_client.emit( - 'emit', ('/', 'room', 'foo', {'bar': 'baz'})) + admin_client.emit("join", ("/", "room", client1.sid)) + admin_client.emit("emit", ("/", "room", "foo", {"bar": "baz"})) data = client1.receive(timeout=5) - assert data == ['foo', {'bar': 'baz'}] - admin_client.emit('leave', ('/', 'room')) + assert data == ["foo", {"bar": "baz"}] + admin_client.emit("leave", ("/", "room")) # disconnect - admin_client.emit('_disconnect', ('/', False, client1.sid)) + admin_client.emit("_disconnect", ("/", False, client1.sid)) for _ in range(10): if not client1.connected: break diff --git a/tests/async/test_client.py b/tests/async/test_client.py index 548b71c..654ca0e 100644 --- a/tests/async/test_client.py +++ b/tests/async/test_client.py @@ -13,7 +13,7 @@ from socketio import packet from .helpers import AsyncMock, _run -@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') +@unittest.skipIf(sys.version_info < (3, 5), "only for Python 3.5+") class TestAsyncClient(unittest.TestCase): def test_is_asyncio_based(self): c = async_client.AsyncClient() @@ -24,50 +24,50 @@ class TestAsyncClient(unittest.TestCase): c.eio.connect = AsyncMock() _run( c.connect( - 'url', - headers='headers', - auth='auth', - transports='transports', - namespaces=['/foo', '/', '/bar'], - socketio_path='path', + "url", + headers="headers", + auth="auth", + transports="transports", + namespaces=["/foo", "/", "/bar"], + socketio_path="path", wait=False, ) ) - assert c.connection_url == 'url' - assert c.connection_headers == 'headers' - assert c.connection_auth == 'auth' - assert c.connection_transports == 'transports' - assert c.connection_namespaces == ['/foo', '/', '/bar'] - assert c.socketio_path == 'path' + assert c.connection_url == "url" + assert c.connection_headers == "headers" + assert c.connection_auth == "auth" + assert c.connection_transports == "transports" + assert c.connection_namespaces == ["/foo", "/", "/bar"] + assert c.socketio_path == "path" c.eio.connect.mock.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_functions(self): async def headers(): - return 'headers' + return "headers" c = async_client.AsyncClient() c.eio.connect = AsyncMock() _run( c.connect( - lambda: 'url', + lambda: "url", headers=headers, - auth='auth', - transports='transports', - namespaces=['/foo', '/', '/bar'], - socketio_path='path', + auth="auth", + transports="transports", + namespaces=["/foo", "/", "/bar"], + socketio_path="path", wait=False, ) ) c.eio.connect.mock.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_one_namespace(self): @@ -75,51 +75,53 @@ class TestAsyncClient(unittest.TestCase): c.eio.connect = AsyncMock() _run( c.connect( - 'url', - headers='headers', - transports='transports', - namespaces='/foo', - socketio_path='path', + "url", + headers="headers", + transports="transports", + namespaces="/foo", + socketio_path="path", wait=False, ) ) - assert c.connection_url == 'url' - assert c.connection_headers == 'headers' - assert c.connection_transports == 'transports' - assert c.connection_namespaces == ['/foo'] - assert c.socketio_path == 'path' + assert c.connection_url == "url" + assert c.connection_headers == "headers" + assert c.connection_transports == "transports" + assert c.connection_namespaces == ["/foo"] + assert c.socketio_path == "path" c.eio.connect.mock.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_default_namespaces(self): c = async_client.AsyncClient() c.eio.connect = AsyncMock() - c.on('foo', mock.MagicMock(), namespace='/foo') - c.on('bar', mock.MagicMock(), namespace='/') + c.on("foo", mock.MagicMock(), namespace="/foo") + c.on("bar", mock.MagicMock(), namespace="/") _run( c.connect( - 'url', - headers='headers', - transports='transports', - socketio_path='path', + "url", + headers="headers", + transports="transports", + socketio_path="path", wait=False, ) ) - assert c.connection_url == 'url' - assert c.connection_headers == 'headers' - assert c.connection_transports == 'transports' - assert c.connection_namespaces == ['/', '/foo'] or \ - c.connection_namespaces == ['/foo', '/'] - assert c.socketio_path == 'path' + assert c.connection_url == "url" + assert c.connection_headers == "headers" + assert c.connection_transports == "transports" + assert c.connection_namespaces == ["/", "/foo"] or c.connection_namespaces == [ + "/foo", + "/", + ] + assert c.socketio_path == "path" c.eio.connect.mock.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_no_namespaces(self): @@ -127,39 +129,39 @@ class TestAsyncClient(unittest.TestCase): c.eio.connect = AsyncMock() _run( c.connect( - 'url', - headers='headers', - transports='transports', - socketio_path='path', + "url", + headers="headers", + transports="transports", + socketio_path="path", wait=False, ) ) - assert c.connection_url == 'url' - assert c.connection_headers == 'headers' - assert c.connection_transports == 'transports' - assert c.connection_namespaces == ['/'] - assert c.socketio_path == 'path' + assert c.connection_url == "url" + assert c.connection_headers == "headers" + assert c.connection_transports == "transports" + assert c.connection_namespaces == ["/"] + assert c.socketio_path == "path" c.eio.connect.mock.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_error(self): c = async_client.AsyncClient() c.eio.connect = AsyncMock( - side_effect=engineio_exceptions.ConnectionError('foo') + side_effect=engineio_exceptions.ConnectionError("foo") ) - c.on('foo', mock.MagicMock(), namespace='/foo') - c.on('bar', mock.MagicMock(), namespace='/') + c.on("foo", mock.MagicMock(), namespace="/foo") + c.on("bar", mock.MagicMock(), namespace="/") with pytest.raises(exceptions.ConnectionError): _run( c.connect( - 'url', - headers='headers', - transports='transports', - socketio_path='path', + "url", + headers="headers", + transports="transports", + socketio_path="path", wait=False, ) ) @@ -169,14 +171,14 @@ class TestAsyncClient(unittest.TestCase): c.eio.connect = AsyncMock() _run( c.connect( - 'url', + "url", wait=False, ) ) with pytest.raises(exceptions.ConnectionError): _run( c.connect( - 'url', + "url", wait=False, ) ) @@ -187,13 +189,13 @@ class TestAsyncClient(unittest.TestCase): c._connect_event = mock.MagicMock() async def mock_connect(): - c.namespaces = {'/': '123'} + c.namespaces = {"/": "123"} return True c._connect_event.wait = mock_connect _run( c.connect( - 'url', + "url", wait=True, wait_timeout=0.01, ) @@ -207,24 +209,24 @@ class TestAsyncClient(unittest.TestCase): async def mock_connect(): if c.namespaces == {}: - c.namespaces = {'/bar': '123'} + c.namespaces = {"/bar": "123"} return True - elif c.namespaces == {'/bar': '123'}: - c.namespaces = {'/bar': '123', '/foo': '456'} + elif c.namespaces == {"/bar": "123"}: + c.namespaces = {"/bar": "123", "/foo": "456"} return True return False c._connect_event.wait = mock_connect _run( c.connect( - 'url', - namespaces=['/foo', '/bar'], + "url", + namespaces=["/foo", "/bar"], wait=True, wait_timeout=0.01, ) ) assert c.connected is True - assert c.namespaces == {'/bar': '123', '/foo': '456'} + assert c.namespaces == {"/bar": "123", "/foo": "456"} def test_connect_timeout(self): c = async_client.AsyncClient() @@ -233,7 +235,7 @@ class TestAsyncClient(unittest.TestCase): with pytest.raises(exceptions.ConnectionError): _run( c.connect( - 'url', + "url", wait=True, wait_timeout=0.01, ) @@ -253,7 +255,7 @@ class TestAsyncClient(unittest.TestCase): c = async_client.AsyncClient() c.eio.wait = AsyncMock() c.sleep = AsyncMock() - states = ['disconnected'] + states = ["disconnected"] async def fake_wait(): c.eio.state = states.pop(0) @@ -267,7 +269,7 @@ class TestAsyncClient(unittest.TestCase): c = async_client.AsyncClient() c.eio.wait = AsyncMock() c.sleep = AsyncMock() - states = ['connected', 'disconnected'] + states = ["connected", "disconnected"] async def fake_wait(): c.eio.state = states.pop(0) @@ -280,11 +282,12 @@ class TestAsyncClient(unittest.TestCase): def test_emit_no_arguments(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = AsyncMock() - _run(c.emit('foo')) + _run(c.emit("foo")) expected_packet = packet.Packet( - packet.EVENT, namespace='/', data=['foo'], id=None) + packet.EVENT, namespace="/", data=["foo"], id=None + ) assert c._send_packet.mock.call_count == 1 assert ( c._send_packet.mock.call_args_list[0][0][0].encode() @@ -293,13 +296,13 @@ class TestAsyncClient(unittest.TestCase): def test_emit_one_argument(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = AsyncMock() - _run(c.emit('foo', 'bar')) + _run(c.emit("foo", "bar")) expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', 'bar'], + namespace="/", + data=["foo", "bar"], id=None, ) assert c._send_packet.mock.call_count == 1 @@ -310,13 +313,13 @@ class TestAsyncClient(unittest.TestCase): def test_emit_one_argument_list(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = AsyncMock() - _run(c.emit('foo', ['bar', 'baz'])) + _run(c.emit("foo", ["bar", "baz"])) expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', ['bar', 'baz']], + namespace="/", + data=["foo", ["bar", "baz"]], id=None, ) assert c._send_packet.mock.call_count == 1 @@ -327,13 +330,13 @@ class TestAsyncClient(unittest.TestCase): def test_emit_two_arguments(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = AsyncMock() - _run(c.emit('foo', ('bar', 'baz'))) + _run(c.emit("foo", ("bar", "baz"))) expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', 'bar', 'baz'], + namespace="/", + data=["foo", "bar", "baz"], id=None, ) assert c._send_packet.mock.call_count == 1 @@ -344,11 +347,12 @@ class TestAsyncClient(unittest.TestCase): def test_emit_namespace(self): c = async_client.AsyncClient() - c.namespaces = {'/foo': '1'} + c.namespaces = {"/foo": "1"} c._send_packet = AsyncMock() - _run(c.emit('foo', namespace='/foo')) + _run(c.emit("foo", namespace="/foo")) expected_packet = packet.Packet( - packet.EVENT, namespace='/foo', data=['foo'], id=None) + packet.EVENT, namespace="/foo", data=["foo"], id=None + ) assert c._send_packet.mock.call_count == 1 assert ( c._send_packet.mock.call_args_list[0][0][0].encode() @@ -357,49 +361,51 @@ class TestAsyncClient(unittest.TestCase): def test_emit_unknown_namespace(self): c = async_client.AsyncClient() - c.namespaces = {'/foo': '1'} + c.namespaces = {"/foo": "1"} with pytest.raises(exceptions.BadNamespaceError): - _run(c.emit('foo', namespace='/bar')) + _run(c.emit("foo", namespace="/bar")) def test_emit_with_callback(self): c = async_client.AsyncClient() c._send_packet = AsyncMock() c._generate_ack_id = mock.MagicMock(return_value=123) - c.namespaces = {'/': '1'} - _run(c.emit('foo', callback='cb')) + c.namespaces = {"/": "1"} + _run(c.emit("foo", callback="cb")) expected_packet = packet.Packet( - packet.EVENT, namespace='/', data=['foo'], id=123) + packet.EVENT, namespace="/", data=["foo"], id=123 + ) assert c._send_packet.mock.call_count == 1 assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() ) - c._generate_ack_id.assert_called_once_with('/', 'cb') + c._generate_ack_id.assert_called_once_with("/", "cb") def test_emit_namespace_with_callback(self): c = async_client.AsyncClient() - c.namespaces = {'/foo': '1'} + c.namespaces = {"/foo": "1"} c._send_packet = AsyncMock() c._generate_ack_id = mock.MagicMock(return_value=123) - _run(c.emit('foo', namespace='/foo', callback='cb')) + _run(c.emit("foo", namespace="/foo", callback="cb")) expected_packet = packet.Packet( - packet.EVENT, namespace='/foo', data=['foo'], id=123) + packet.EVENT, namespace="/foo", data=["foo"], id=123 + ) assert c._send_packet.mock.call_count == 1 assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() ) - c._generate_ack_id.assert_called_once_with('/foo', 'cb') + c._generate_ack_id.assert_called_once_with("/foo", "cb") def test_emit_binary(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = AsyncMock() - _run(c.emit('foo', b'bar')) + _run(c.emit("foo", b"bar")) expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', b'bar'], + namespace="/", + data=["foo", b"bar"], id=None, ) assert c._send_packet.mock.call_count == 1 @@ -410,13 +416,13 @@ class TestAsyncClient(unittest.TestCase): def test_emit_not_binary(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = AsyncMock() - _run(c.emit('foo', 'bar')) + _run(c.emit("foo", "bar")) expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', 'bar'], + namespace="/", + data=["foo", "bar"], id=None, ) assert c._send_packet.mock.call_count == 1 @@ -428,33 +434,34 @@ class TestAsyncClient(unittest.TestCase): def test_send(self): c = async_client.AsyncClient() c.emit = AsyncMock() - _run(c.send('data', 'namespace', 'callback')) + _run(c.send("data", "namespace", "callback")) c.emit.mock.assert_called_once_with( - 'message', data='data', namespace='namespace', callback='callback' + "message", data="data", namespace="namespace", callback="callback" ) def test_send_with_defaults(self): c = async_client.AsyncClient() c.emit = AsyncMock() - _run(c.send('data')) + _run(c.send("data")) c.emit.mock.assert_called_once_with( - 'message', data='data', namespace=None, callback=None + "message", data="data", namespace=None, callback=None ) def test_call(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} async def fake_event_wait(): - c._generate_ack_id.call_args_list[0][0][1]('foo', 321) + c._generate_ack_id.call_args_list[0][0][1]("foo", 321) c._send_packet = AsyncMock() c._generate_ack_id = mock.MagicMock(return_value=123) c.eio = mock.MagicMock() c.eio.create_event.return_value.wait = fake_event_wait - assert _run(c.call('foo')) == ('foo', 321) + assert _run(c.call("foo")) == ("foo", 321) expected_packet = packet.Packet( - packet.EVENT, namespace='/', data=['foo'], id=123) + packet.EVENT, namespace="/", data=["foo"], id=123 + ) assert c._send_packet.mock.call_count == 1 assert ( c._send_packet.mock.call_args_list[0][0][0].encode() @@ -463,7 +470,7 @@ class TestAsyncClient(unittest.TestCase): def test_call_with_timeout(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} async def fake_event_wait(): await asyncio.sleep(1) @@ -473,9 +480,10 @@ class TestAsyncClient(unittest.TestCase): c.eio = mock.MagicMock() c.eio.create_event.return_value.wait = fake_event_wait with pytest.raises(exceptions.TimeoutError): - _run(c.call('foo', timeout=0.01)) + _run(c.call("foo", timeout=0.01)) expected_packet = packet.Packet( - packet.EVENT, namespace='/', data=['foo'], id=123) + packet.EVENT, namespace="/", data=["foo"], id=123 + ) assert c._send_packet.mock.call_count == 1 assert ( c._send_packet.mock.call_args_list[0][0][0].encode() @@ -485,17 +493,17 @@ class TestAsyncClient(unittest.TestCase): def test_disconnect(self): c = async_client.AsyncClient() c.connected = True - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._trigger_event = AsyncMock() c._send_packet = AsyncMock() c.eio = mock.MagicMock() c.eio.disconnect = AsyncMock() - c.eio.state = 'connected' + c.eio.state = "connected" _run(c.disconnect()) assert c.connected assert c._trigger_event.mock.call_count == 0 assert c._send_packet.mock.call_count == 1 - expected_packet = packet.Packet(packet.DISCONNECT, namespace='/') + expected_packet = packet.Packet(packet.DISCONNECT, namespace="/") assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() @@ -504,21 +512,21 @@ class TestAsyncClient(unittest.TestCase): def test_disconnect_namespaces(self): c = async_client.AsyncClient() - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = AsyncMock() c._send_packet = AsyncMock() c.eio = mock.MagicMock() c.eio.disconnect = AsyncMock() - c.eio.state = 'connected' + c.eio.state = "connected" _run(c.disconnect()) assert c._trigger_event.mock.call_count == 0 assert c._send_packet.mock.call_count == 2 - expected_packet = packet.Packet(packet.DISCONNECT, namespace='/foo') + expected_packet = packet.Packet(packet.DISCONNECT, namespace="/foo") assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() ) - expected_packet = packet.Packet(packet.DISCONNECT, namespace='/bar') + expected_packet = packet.Packet(packet.DISCONNECT, namespace="/bar") assert ( c._send_packet.mock.call_args_list[1][0][0].encode() == expected_packet.encode() @@ -526,11 +534,9 @@ class TestAsyncClient(unittest.TestCase): def test_start_background_task(self): c = async_client.AsyncClient() - c.eio.start_background_task = mock.MagicMock(return_value='foo') - assert c.start_background_task('foo', 'bar', baz='baz') == 'foo' - c.eio.start_background_task.assert_called_once_with( - 'foo', 'bar', baz='baz' - ) + c.eio.start_background_task = mock.MagicMock(return_value="foo") + assert c.start_background_task("foo", "bar", baz="baz") == "foo" + c.eio.start_background_task.assert_called_once_with("foo", "bar", baz="baz") def test_sleep(self): c = async_client.AsyncClient() @@ -541,25 +547,25 @@ class TestAsyncClient(unittest.TestCase): def test_send_packet(self): c = async_client.AsyncClient() c.eio.send = AsyncMock() - _run(c._send_packet(packet.Packet(packet.EVENT, 'foo'))) + _run(c._send_packet(packet.Packet(packet.EVENT, "foo"))) c.eio.send.mock.assert_called_once_with('2"foo"') def test_send_packet_binary(self): c = async_client.AsyncClient() c.eio.send = AsyncMock() - _run(c._send_packet(packet.Packet(packet.EVENT, b'foo'))) + _run(c._send_packet(packet.Packet(packet.EVENT, b"foo"))) assert c.eio.send.mock.call_args_list == [ mock.call('51-{"_placeholder":true,"num":0}'), - mock.call(b'foo'), + mock.call(b"foo"), ] or c.eio.send.mock.call_args_list == [ mock.call('51-{"num":0,"_placeholder":true}'), - mock.call(b'foo'), + mock.call(b"foo"), ] def test_send_packet_default_binary(self): c = async_client.AsyncClient() c.eio.send = AsyncMock() - _run(c._send_packet(packet.Packet(packet.EVENT, 'foo'))) + _run(c._send_packet(packet.Packet(packet.EVENT, "foo"))) c.eio.send.mock.assert_called_once_with('2"foo"') def test_handle_connect(self): @@ -567,121 +573,98 @@ class TestAsyncClient(unittest.TestCase): c._connect_event = mock.MagicMock() c._trigger_event = AsyncMock() c._send_packet = AsyncMock() - _run(c._handle_connect('/', {'sid': '123'})) + _run(c._handle_connect("/", {"sid": "123"})) c._connect_event.set.assert_called_once_with() - c._trigger_event.mock.assert_called_once_with('connect', namespace='/') + c._trigger_event.mock.assert_called_once_with("connect", namespace="/") c._send_packet.mock.assert_not_called() def test_handle_connect_with_namespaces(self): c = async_client.AsyncClient() - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = AsyncMock() c._send_packet = AsyncMock() - _run(c._handle_connect('/', {'sid': '3'})) + _run(c._handle_connect("/", {"sid": "3"})) c._connect_event.set.assert_called_once_with() - c._trigger_event.mock.assert_called_once_with('connect', namespace='/') - assert c.namespaces == {'/': '3', '/foo': '1', '/bar': '2'} + c._trigger_event.mock.assert_called_once_with("connect", namespace="/") + assert c.namespaces == {"/": "3", "/foo": "1", "/bar": "2"} def test_handle_connect_namespace(self): c = async_client.AsyncClient() - c.namespaces = {'/foo': '1'} + c.namespaces = {"/foo": "1"} c._connect_event = mock.MagicMock() c._trigger_event = AsyncMock() c._send_packet = AsyncMock() - _run(c._handle_connect('/foo', {'sid': '123'})) - _run(c._handle_connect('/bar', {'sid': '2'})) + _run(c._handle_connect("/foo", {"sid": "123"})) + _run(c._handle_connect("/bar", {"sid": "2"})) assert c._trigger_event.mock.call_count == 1 c._connect_event.set.assert_called_once_with() - c._trigger_event.mock.assert_called_once_with( - 'connect', namespace='/bar') - assert c.namespaces == {'/foo': '1', '/bar': '2'} + c._trigger_event.mock.assert_called_once_with("connect", namespace="/bar") + assert c.namespaces == {"/foo": "1", "/bar": "2"} def test_handle_disconnect(self): c = async_client.AsyncClient() c.connected = True c._trigger_event = AsyncMock() - _run(c._handle_disconnect('/')) - c._trigger_event.mock.assert_any_call( - 'disconnect', namespace='/' - ) - c._trigger_event.mock.assert_any_call( - '__disconnect_final', namespace='/' - ) + _run(c._handle_disconnect("/")) + c._trigger_event.mock.assert_any_call("disconnect", namespace="/") + c._trigger_event.mock.assert_any_call("__disconnect_final", namespace="/") assert not c.connected - _run(c._handle_disconnect('/')) + _run(c._handle_disconnect("/")) assert c._trigger_event.mock.call_count == 2 def test_handle_disconnect_namespace(self): c = async_client.AsyncClient() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = AsyncMock() - _run(c._handle_disconnect('/foo')) - c._trigger_event.mock.assert_any_call( - 'disconnect', namespace='/foo' - ) - c._trigger_event.mock.assert_any_call( - '__disconnect_final', namespace='/foo' - ) - assert c.namespaces == {'/bar': '2'} + _run(c._handle_disconnect("/foo")) + c._trigger_event.mock.assert_any_call("disconnect", namespace="/foo") + c._trigger_event.mock.assert_any_call("__disconnect_final", namespace="/foo") + assert c.namespaces == {"/bar": "2"} assert c.connected - _run(c._handle_disconnect('/bar')) - c._trigger_event.mock.assert_any_call( - 'disconnect', namespace='/bar' - ) - c._trigger_event.mock.assert_any_call( - '__disconnect_final', namespace='/bar' - ) + _run(c._handle_disconnect("/bar")) + c._trigger_event.mock.assert_any_call("disconnect", namespace="/bar") + c._trigger_event.mock.assert_any_call("__disconnect_final", namespace="/bar") assert c.namespaces == {} assert not c.connected def test_handle_disconnect_unknown_namespace(self): c = async_client.AsyncClient() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = AsyncMock() - _run(c._handle_disconnect('/baz')) - c._trigger_event.mock.assert_any_call( - 'disconnect', namespace='/baz' - ) - c._trigger_event.mock.assert_any_call( - '__disconnect_final', namespace='/baz' - ) - assert c.namespaces == {'/foo': '1', '/bar': '2'} + _run(c._handle_disconnect("/baz")) + c._trigger_event.mock.assert_any_call("disconnect", namespace="/baz") + c._trigger_event.mock.assert_any_call("__disconnect_final", namespace="/baz") + assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected def test_handle_disconnect_default_namespaces(self): c = async_client.AsyncClient() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = AsyncMock() - _run(c._handle_disconnect('/')) - c._trigger_event.mock.assert_any_call('disconnect', namespace='/') - c._trigger_event.mock.assert_any_call('__disconnect_final', - namespace='/') - assert c.namespaces == {'/foo': '1', '/bar': '2'} + _run(c._handle_disconnect("/")) + c._trigger_event.mock.assert_any_call("disconnect", namespace="/") + c._trigger_event.mock.assert_any_call("__disconnect_final", namespace="/") + assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected def test_handle_event(self): c = async_client.AsyncClient() c._trigger_event = AsyncMock() - _run(c._handle_event('/', None, ['foo', ('bar', 'baz')])) - c._trigger_event.mock.assert_called_once_with( - 'foo', '/', ('bar', 'baz') - ) + _run(c._handle_event("/", None, ["foo", ("bar", "baz")])) + c._trigger_event.mock.assert_called_once_with("foo", "/", ("bar", "baz")) def test_handle_event_with_id_no_arguments(self): c = async_client.AsyncClient() c._trigger_event = AsyncMock(return_value=None) c._send_packet = AsyncMock() - _run(c._handle_event('/', 123, ['foo', ('bar', 'baz')])) - c._trigger_event.mock.assert_called_once_with( - 'foo', '/', ('bar', 'baz') - ) + _run(c._handle_event("/", 123, ["foo", ("bar", "baz")])) + c._trigger_event.mock.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.mock.call_count == 1 - expected_packet = packet.Packet( - packet.ACK, namespace='/', id=123, data=[]) + expected_packet = packet.Packet(packet.ACK, namespace="/", id=123, data=[]) assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() @@ -689,15 +672,12 @@ class TestAsyncClient(unittest.TestCase): def test_handle_event_with_id_one_argument(self): c = async_client.AsyncClient() - c._trigger_event = AsyncMock(return_value='ret') + c._trigger_event = AsyncMock(return_value="ret") c._send_packet = AsyncMock() - _run(c._handle_event('/', 123, ['foo', ('bar', 'baz')])) - c._trigger_event.mock.assert_called_once_with( - 'foo', '/', ('bar', 'baz') - ) + _run(c._handle_event("/", 123, ["foo", ("bar", "baz")])) + c._trigger_event.mock.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.mock.call_count == 1 - expected_packet = packet.Packet( - packet.ACK, namespace='/', id=123, data=['ret']) + expected_packet = packet.Packet(packet.ACK, namespace="/", id=123, data=["ret"]) assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() @@ -705,15 +685,14 @@ class TestAsyncClient(unittest.TestCase): def test_handle_event_with_id_one_list_argument(self): c = async_client.AsyncClient() - c._trigger_event = AsyncMock(return_value=['a', 'b']) + c._trigger_event = AsyncMock(return_value=["a", "b"]) c._send_packet = AsyncMock() - _run(c._handle_event('/', 123, ['foo', ('bar', 'baz')])) - c._trigger_event.mock.assert_called_once_with( - 'foo', '/', ('bar', 'baz') - ) + _run(c._handle_event("/", 123, ["foo", ("bar", "baz")])) + c._trigger_event.mock.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.mock.call_count == 1 expected_packet = packet.Packet( - packet.ACK, namespace='/', id=123, data=[['a', 'b']]) + packet.ACK, namespace="/", id=123, data=[["a", "b"]] + ) assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() @@ -721,15 +700,14 @@ class TestAsyncClient(unittest.TestCase): def test_handle_event_with_id_two_arguments(self): c = async_client.AsyncClient() - c._trigger_event = AsyncMock(return_value=('a', 'b')) + c._trigger_event = AsyncMock(return_value=("a", "b")) c._send_packet = AsyncMock() - _run(c._handle_event('/', 123, ['foo', ('bar', 'baz')])) - c._trigger_event.mock.assert_called_once_with( - 'foo', '/', ('bar', 'baz') - ) + _run(c._handle_event("/", 123, ["foo", ("bar", "baz")])) + c._trigger_event.mock.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.mock.call_count == 1 expected_packet = packet.Packet( - packet.ACK, namespace='/', id=123, data=['a', 'b']) + packet.ACK, namespace="/", id=123, data=["a", "b"] + ) assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() @@ -738,86 +716,84 @@ class TestAsyncClient(unittest.TestCase): def test_handle_ack(self): c = async_client.AsyncClient() mock_cb = mock.MagicMock() - c.callbacks['/foo'] = {123: mock_cb} - _run(c._handle_ack('/foo', 123, ['bar', 'baz'])) - mock_cb.assert_called_once_with('bar', 'baz') - assert 123 not in c.callbacks['/foo'] + c.callbacks["/foo"] = {123: mock_cb} + _run(c._handle_ack("/foo", 123, ["bar", "baz"])) + mock_cb.assert_called_once_with("bar", "baz") + assert 123 not in c.callbacks["/foo"] def test_handle_ack_async(self): c = async_client.AsyncClient() mock_cb = AsyncMock() - c.callbacks['/foo'] = {123: mock_cb} - _run(c._handle_ack('/foo', 123, ['bar', 'baz'])) - mock_cb.mock.assert_called_once_with('bar', 'baz') - assert 123 not in c.callbacks['/foo'] + c.callbacks["/foo"] = {123: mock_cb} + _run(c._handle_ack("/foo", 123, ["bar", "baz"])) + mock_cb.mock.assert_called_once_with("bar", "baz") + assert 123 not in c.callbacks["/foo"] def test_handle_ack_not_found(self): c = async_client.AsyncClient() mock_cb = mock.MagicMock() - c.callbacks['/foo'] = {123: mock_cb} - _run(c._handle_ack('/foo', 124, ['bar', 'baz'])) + c.callbacks["/foo"] = {123: mock_cb} + _run(c._handle_ack("/foo", 124, ["bar", "baz"])) mock_cb.assert_not_called() - assert 123 in c.callbacks['/foo'] + assert 123 in c.callbacks["/foo"] def test_handle_error(self): c = async_client.AsyncClient() c.connected = True c._connect_event = mock.MagicMock() c._trigger_event = AsyncMock() - c.namespaces = {'/foo': '1', '/bar': '2'} - _run(c._handle_error('/', 'error')) + c.namespaces = {"/foo": "1", "/bar": "2"} + _run(c._handle_error("/", "error")) assert c.namespaces == {} assert not c.connected c._connect_event.set.assert_called_once_with() - c._trigger_event.mock.assert_called_once_with( - 'connect_error', '/', 'error' - ) + c._trigger_event.mock.assert_called_once_with("connect_error", "/", "error") def test_handle_error_with_no_arguments(self): c = async_client.AsyncClient() c.connected = True c._connect_event = mock.MagicMock() c._trigger_event = AsyncMock() - c.namespaces = {'/foo': '1', '/bar': '2'} - _run(c._handle_error('/', None)) + c.namespaces = {"/foo": "1", "/bar": "2"} + _run(c._handle_error("/", None)) assert c.namespaces == {} assert not c.connected c._connect_event.set.assert_called_once_with() - c._trigger_event.mock.assert_called_once_with('connect_error', '/') + c._trigger_event.mock.assert_called_once_with("connect_error", "/") def test_handle_error_namespace(self): c = async_client.AsyncClient() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = AsyncMock() - _run(c._handle_error('/bar', ['error', 'message'])) - assert c.namespaces == {'/foo': '1'} + _run(c._handle_error("/bar", ["error", "message"])) + assert c.namespaces == {"/foo": "1"} assert c.connected c._connect_event.set.assert_called_once_with() c._trigger_event.mock.assert_called_once_with( - 'connect_error', '/bar', 'error', 'message' + "connect_error", "/bar", "error", "message" ) def test_handle_error_namespace_with_no_arguments(self): c = async_client.AsyncClient() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = AsyncMock() - _run(c._handle_error('/bar', None)) - assert c.namespaces == {'/foo': '1'} + _run(c._handle_error("/bar", None)) + assert c.namespaces == {"/foo": "1"} assert c.connected c._connect_event.set.assert_called_once_with() - c._trigger_event.mock.assert_called_once_with('connect_error', '/bar') + c._trigger_event.mock.assert_called_once_with("connect_error", "/bar") def test_handle_error_unknown_namespace(self): c = async_client.AsyncClient() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() - _run(c._handle_error('/baz', 'error')) - assert c.namespaces == {'/foo': '1', '/bar': '2'} + _run(c._handle_error("/baz", "error")) + assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected c._connect_event.set.assert_called_once_with() @@ -825,24 +801,24 @@ class TestAsyncClient(unittest.TestCase): c = async_client.AsyncClient() handler = mock.MagicMock() catchall_handler = mock.MagicMock() - c.on('foo', handler) - 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) + c.on("foo", handler) + 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) def test_trigger_event_namespace(self): c = async_client.AsyncClient() handler = AsyncMock() catchall_handler = AsyncMock() - c.on('foo', handler, namespace='/bar') - c.on('*', catchall_handler, namespace='/bar') - _run(c._trigger_event('foo', '/bar', 1, '2')) - _run(c._trigger_event('bar', '/bar', 1, '2', 3)) - handler.mock.assert_called_once_with(1, '2') - catchall_handler.mock.assert_called_once_with('bar', 1, '2', 3) + c.on("foo", handler, namespace="/bar") + c.on("*", catchall_handler, namespace="/bar") + _run(c._trigger_event("foo", "/bar", 1, "2")) + _run(c._trigger_event("bar", "/bar", 1, "2", 3)) + handler.mock.assert_called_once_with(1, "2") + catchall_handler.mock.assert_called_once_with("bar", 1, "2", 3) def test_trigger_event_class_namespace(self): c = async_client.AsyncClient() @@ -853,9 +829,9 @@ class TestAsyncClient(unittest.TestCase): result.append(a) result.append(b) - c.register_namespace(MyNamespace('/')) - _run(c._trigger_event('foo', '/', 1, '2')) - assert result == [1, '2'] + c.register_namespace(MyNamespace("/")) + _run(c._trigger_event("foo", "/", 1, "2")) + assert result == [1, "2"] def test_trigger_event_unknown_namespace(self): c = async_client.AsyncClient() @@ -866,19 +842,19 @@ class TestAsyncClient(unittest.TestCase): result.append(a) result.append(b) - c.register_namespace(MyNamespace('/')) - _run(c._trigger_event('foo', '/bar', 1, '2')) + c.register_namespace(MyNamespace("/")) + _run(c._trigger_event("foo", "/bar", 1, "2")) assert result == [] @mock.patch( - 'asyncio.wait_for', + "asyncio.wait_for", new_callable=AsyncMock, side_effect=asyncio.TimeoutError, ) - @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) + @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect(self, random, wait_for): c = async_client.AsyncClient() - c._reconnect_task = 'foo' + c._reconnect_task = "foo" c.connect = AsyncMock( side_effect=[ValueError, exceptions.ConnectionError, None] ) @@ -892,14 +868,14 @@ class TestAsyncClient(unittest.TestCase): assert c._reconnect_task is None @mock.patch( - 'asyncio.wait_for', + "asyncio.wait_for", new_callable=AsyncMock, side_effect=asyncio.TimeoutError, ) - @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) + @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_max_delay(self, random, wait_for): c = async_client.AsyncClient(reconnection_delay_max=3) - c._reconnect_task = 'foo' + c._reconnect_task = "foo" c.connect = AsyncMock( side_effect=[ValueError, exceptions.ConnectionError, None] ) @@ -913,15 +889,15 @@ class TestAsyncClient(unittest.TestCase): assert c._reconnect_task is None @mock.patch( - 'asyncio.wait_for', + "asyncio.wait_for", new_callable=AsyncMock, side_effect=asyncio.TimeoutError, ) - @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) + @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_max_attempts(self, random, wait_for): c = async_client.AsyncClient(reconnection_attempts=2, logger=True) - c.connection_namespaces = ['/'] - c._reconnect_task = 'foo' + c.connection_namespaces = ["/"] + c._reconnect_task = "foo" c._trigger_event = AsyncMock() c.connect = AsyncMock( side_effect=[ValueError, exceptions.ConnectionError, None] @@ -932,20 +908,21 @@ class TestAsyncClient(unittest.TestCase): 1.5, 1.5, ] - assert c._reconnect_task == 'foo' - c._trigger_event.mock.assert_called_once_with('__disconnect_final', - namespace='/') + assert c._reconnect_task == "foo" + c._trigger_event.mock.assert_called_once_with( + "__disconnect_final", namespace="/" + ) @mock.patch( - 'asyncio.wait_for', + "asyncio.wait_for", new_callable=AsyncMock, side_effect=[asyncio.TimeoutError, None], ) - @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) + @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_aborted(self, random, wait_for): c = async_client.AsyncClient(logger=True) - c.connection_namespaces = ['/'] - c._reconnect_task = 'foo' + c.connection_namespaces = ["/"] + c._reconnect_task = "foo" c._trigger_event = AsyncMock() c.connect = AsyncMock( side_effect=[ValueError, exceptions.ConnectionError, None] @@ -956,28 +933,27 @@ class TestAsyncClient(unittest.TestCase): 1.5, 1.5, ] - assert c._reconnect_task == 'foo' - c._trigger_event.mock.assert_called_once_with('__disconnect_final', - namespace='/') + assert c._reconnect_task == "foo" + c._trigger_event.mock.assert_called_once_with( + "__disconnect_final", namespace="/" + ) def test_handle_eio_connect(self): c = async_client.AsyncClient() - c.connection_namespaces = ['/', '/foo'] - c.connection_auth = 'auth' + c.connection_namespaces = ["/", "/foo"] + c.connection_auth = "auth" c._send_packet = AsyncMock() - c.eio.sid = 'foo' + c.eio.sid = "foo" assert c.sid is None _run(c._handle_eio_connect()) - assert c.sid == 'foo' + assert c.sid == "foo" assert c._send_packet.mock.call_count == 2 - expected_packet = packet.Packet( - packet.CONNECT, data='auth', namespace='/') + expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/") assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() ) - expected_packet = packet.Packet( - packet.CONNECT, data='auth', namespace='/foo') + expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/foo") assert ( c._send_packet.mock.call_args_list[1][0][0].encode() == expected_packet.encode() @@ -985,22 +961,20 @@ class TestAsyncClient(unittest.TestCase): def test_handle_eio_connect_function(self): c = async_client.AsyncClient() - c.connection_namespaces = ['/', '/foo'] - c.connection_auth = lambda: 'auth' + c.connection_namespaces = ["/", "/foo"] + c.connection_auth = lambda: "auth" c._send_packet = AsyncMock() - c.eio.sid = 'foo' + c.eio.sid = "foo" assert c.sid is None _run(c._handle_eio_connect()) - assert c.sid == 'foo' + assert c.sid == "foo" assert c._send_packet.mock.call_count == 2 - expected_packet = packet.Packet( - packet.CONNECT, data='auth', namespace='/') + expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/") assert ( c._send_packet.mock.call_args_list[0][0][0].encode() == expected_packet.encode() ) - expected_packet = packet.Packet( - packet.CONNECT, data='auth', namespace='/foo') + expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/foo") assert ( c._send_packet.mock.call_args_list[1][0][0].encode() == expected_packet.encode() @@ -1015,31 +989,31 @@ class TestAsyncClient(unittest.TestCase): c._handle_error = AsyncMock() _run(c._handle_eio_message('0{"sid":"123"}')) - c._handle_connect.mock.assert_called_with(None, {'sid': '123'}) + c._handle_connect.mock.assert_called_with(None, {"sid": "123"}) _run(c._handle_eio_message('0/foo,{"sid":"123"}')) - c._handle_connect.mock.assert_called_with('/foo', {'sid': '123'}) - _run(c._handle_eio_message('1')) + c._handle_connect.mock.assert_called_with("/foo", {"sid": "123"}) + _run(c._handle_eio_message("1")) c._handle_disconnect.mock.assert_called_with(None) - _run(c._handle_eio_message('1/foo')) - c._handle_disconnect.mock.assert_called_with('/foo') + _run(c._handle_eio_message("1/foo")) + c._handle_disconnect.mock.assert_called_with("/foo") _run(c._handle_eio_message('2["foo"]')) - c._handle_event.mock.assert_called_with(None, None, ['foo']) + c._handle_event.mock.assert_called_with(None, None, ["foo"]) _run(c._handle_eio_message('3/foo,["bar"]')) - c._handle_ack.mock.assert_called_with('/foo', None, ['bar']) - _run(c._handle_eio_message('4')) + c._handle_ack.mock.assert_called_with("/foo", None, ["bar"]) + _run(c._handle_eio_message("4")) c._handle_error.mock.assert_called_with(None, None) _run(c._handle_eio_message('4"foo"')) - c._handle_error.mock.assert_called_with(None, 'foo') + c._handle_error.mock.assert_called_with(None, "foo") _run(c._handle_eio_message('4["foo"]')) - c._handle_error.mock.assert_called_with(None, ['foo']) - _run(c._handle_eio_message('4/foo')) - c._handle_error.mock.assert_called_with('/foo', None) + c._handle_error.mock.assert_called_with(None, ["foo"]) + _run(c._handle_eio_message("4/foo")) + c._handle_error.mock.assert_called_with("/foo", None) _run(c._handle_eio_message('4/foo,["foo","bar"]')) - c._handle_error.mock.assert_called_with('/foo', ['foo', 'bar']) + c._handle_error.mock.assert_called_with("/foo", ["foo", "bar"]) _run(c._handle_eio_message('51-{"_placeholder":true,"num":0}')) assert c._binary_packet.packet_type == packet.BINARY_EVENT - _run(c._handle_eio_message(b'foo')) - c._handle_event.mock.assert_called_with(None, None, b'foo') + _run(c._handle_eio_message(b"foo")) + c._handle_event.mock.assert_called_with(None, None, b"foo") _run( c._handle_eio_message( '62-/foo,{"1":{"_placeholder":true,"num":1},' @@ -1047,71 +1021,63 @@ class TestAsyncClient(unittest.TestCase): ) ) assert c._binary_packet.packet_type == packet.BINARY_ACK - _run(c._handle_eio_message(b'bar')) - _run(c._handle_eio_message(b'foo')) - c._handle_ack.mock.assert_called_with( - '/foo', None, {'1': b'foo', '2': b'bar'} - ) + _run(c._handle_eio_message(b"bar")) + _run(c._handle_eio_message(b"foo")) + c._handle_ack.mock.assert_called_with("/foo", None, {"1": b"foo", "2": b"bar"}) with pytest.raises(ValueError): - _run(c._handle_eio_message('9')) + _run(c._handle_eio_message("9")) def test_eio_disconnect(self): c = async_client.AsyncClient() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c.connected = True c._trigger_event = AsyncMock() c.start_background_task = mock.MagicMock() - c.sid = 'foo' - c.eio.state = 'connected' + c.sid = "foo" + c.eio.state = "connected" _run(c._handle_eio_disconnect()) - c._trigger_event.mock.assert_called_once_with( - 'disconnect', namespace='/' - ) + c._trigger_event.mock.assert_called_once_with("disconnect", namespace="/") assert c.sid is None assert not c.connected def test_eio_disconnect_namespaces(self): c = async_client.AsyncClient(reconnection=False) - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c.connected = True c._trigger_event = AsyncMock() - c.sid = 'foo' - c.eio.state = 'connected' + c.sid = "foo" + c.eio.state = "connected" _run(c._handle_eio_disconnect()) - c._trigger_event.mock.assert_any_call('disconnect', namespace='/foo') - c._trigger_event.mock.assert_any_call('disconnect', namespace='/bar') + c._trigger_event.mock.assert_any_call("disconnect", namespace="/foo") + c._trigger_event.mock.assert_any_call("disconnect", namespace="/bar") assert c.sid is None assert not c.connected def test_eio_disconnect_reconnect(self): c = async_client.AsyncClient(reconnection=True) c.start_background_task = mock.MagicMock() - c.eio.state = 'connected' + c.eio.state = "connected" _run(c._handle_eio_disconnect()) c.start_background_task.assert_called_once_with(c._handle_reconnect) def test_eio_disconnect_self_disconnect(self): c = async_client.AsyncClient(reconnection=True) c.start_background_task = mock.MagicMock() - c.eio.state = 'disconnected' + c.eio.state = "disconnected" _run(c._handle_eio_disconnect()) c.start_background_task.assert_not_called() def test_eio_disconnect_no_reconnect(self): c = async_client.AsyncClient(reconnection=False) - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c.connected = True c._trigger_event = AsyncMock() c.start_background_task = mock.MagicMock() - c.sid = 'foo' - c.eio.state = 'connected' + c.sid = "foo" + c.eio.state = "connected" _run(c._handle_eio_disconnect()) - c._trigger_event.mock.assert_any_call( - 'disconnect', namespace='/' - ) - c._trigger_event.mock.assert_any_call( - '__disconnect_final', namespace='/' - ) + c._trigger_event.mock.assert_any_call("disconnect", namespace="/") + c._trigger_event.mock.assert_any_call("__disconnect_final", namespace="/") assert c.sid is None assert not c.connected c.start_background_task.assert_not_called() diff --git a/tests/async/test_manager.py b/tests/async/test_manager.py index 0b2fc93..a1b0ae2 100644 --- a/tests/async/test_manager.py +++ b/tests/async/test_manager.py @@ -7,7 +7,7 @@ from socketio import packet from .helpers import AsyncMock, _run -@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') +@unittest.skipIf(sys.version_info < (3, 5), "only for Python 3.5+") class TestAsyncManager(unittest.TestCase): def setUp(self): id = 0 @@ -27,383 +27,327 @@ class TestAsyncManager(unittest.TestCase): self.bm.initialize() def test_connect(self): - sid = _run(self.bm.connect('123', '/foo')) - assert None in self.bm.rooms['/foo'] - assert sid in self.bm.rooms['/foo'] - assert sid in self.bm.rooms['/foo'][None] - assert sid in self.bm.rooms['/foo'][sid] - assert dict(self.bm.rooms['/foo'][None]) == {sid: '123'} - assert dict(self.bm.rooms['/foo'][sid]) == {sid: '123'} - assert self.bm.sid_from_eio_sid('123', '/foo') == sid + sid = _run(self.bm.connect("123", "/foo")) + assert None in self.bm.rooms["/foo"] + assert sid in self.bm.rooms["/foo"] + assert sid in self.bm.rooms["/foo"][None] + assert sid in self.bm.rooms["/foo"][sid] + assert dict(self.bm.rooms["/foo"][None]) == {sid: "123"} + assert dict(self.bm.rooms["/foo"][sid]) == {sid: "123"} + assert self.bm.sid_from_eio_sid("123", "/foo") == sid def test_pre_disconnect(self): - sid1 = _run(self.bm.connect('123', '/foo')) - sid2 = _run(self.bm.connect('456', '/foo')) - assert self.bm.is_connected(sid1, '/foo') - assert self.bm.pre_disconnect(sid1, '/foo') == '123' - assert self.bm.pending_disconnect == {'/foo': [sid1]} - assert not self.bm.is_connected(sid1, '/foo') - assert self.bm.pre_disconnect(sid2, '/foo') == '456' - assert self.bm.pending_disconnect == {'/foo': [sid1, sid2]} - assert not self.bm.is_connected(sid2, '/foo') - _run(self.bm.disconnect(sid1, '/foo')) - assert self.bm.pending_disconnect == {'/foo': [sid2]} - _run(self.bm.disconnect(sid2, '/foo')) + sid1 = _run(self.bm.connect("123", "/foo")) + sid2 = _run(self.bm.connect("456", "/foo")) + assert self.bm.is_connected(sid1, "/foo") + assert self.bm.pre_disconnect(sid1, "/foo") == "123" + assert self.bm.pending_disconnect == {"/foo": [sid1]} + assert not self.bm.is_connected(sid1, "/foo") + assert self.bm.pre_disconnect(sid2, "/foo") == "456" + assert self.bm.pending_disconnect == {"/foo": [sid1, sid2]} + assert not self.bm.is_connected(sid2, "/foo") + _run(self.bm.disconnect(sid1, "/foo")) + assert self.bm.pending_disconnect == {"/foo": [sid2]} + _run(self.bm.disconnect(sid2, "/foo")) assert self.bm.pending_disconnect == {} def test_disconnect(self): - sid1 = _run(self.bm.connect('123', '/foo')) - sid2 = _run(self.bm.connect('456', '/foo')) - _run(self.bm.enter_room(sid1, '/foo', 'bar')) - _run(self.bm.enter_room(sid2, '/foo', 'baz')) - _run(self.bm.disconnect(sid1, '/foo')) - assert dict(self.bm.rooms['/foo'][None]) == {sid2: '456'} - assert dict(self.bm.rooms['/foo'][sid2]) == {sid2: '456'} - assert dict(self.bm.rooms['/foo']['baz']) == {sid2: '456'} + sid1 = _run(self.bm.connect("123", "/foo")) + sid2 = _run(self.bm.connect("456", "/foo")) + _run(self.bm.enter_room(sid1, "/foo", "bar")) + _run(self.bm.enter_room(sid2, "/foo", "baz")) + _run(self.bm.disconnect(sid1, "/foo")) + assert dict(self.bm.rooms["/foo"][None]) == {sid2: "456"} + assert dict(self.bm.rooms["/foo"][sid2]) == {sid2: "456"} + assert dict(self.bm.rooms["/foo"]["baz"]) == {sid2: "456"} def test_disconnect_default_namespace(self): - sid1 = _run(self.bm.connect('123', '/')) - sid2 = _run(self.bm.connect('123', '/foo')) - sid3 = _run(self.bm.connect('456', '/')) - sid4 = _run(self.bm.connect('456', '/foo')) - assert self.bm.is_connected(sid1, '/') - assert self.bm.is_connected(sid2, '/foo') - assert not self.bm.is_connected(sid2, '/') - assert not self.bm.is_connected(sid1, '/foo') - _run(self.bm.disconnect(sid1, '/')) - assert not self.bm.is_connected(sid1, '/') - assert self.bm.is_connected(sid2, '/foo') - _run(self.bm.disconnect(sid2, '/foo')) - assert not self.bm.is_connected(sid2, '/foo') - assert dict(self.bm.rooms['/'][None]) == {sid3: '456'} - assert dict(self.bm.rooms['/'][sid3]) == {sid3: '456'} - assert dict(self.bm.rooms['/foo'][None]) == {sid4: '456'} - assert dict(self.bm.rooms['/foo'][sid4]) == {sid4: '456'} + sid1 = _run(self.bm.connect("123", "/")) + sid2 = _run(self.bm.connect("123", "/foo")) + sid3 = _run(self.bm.connect("456", "/")) + sid4 = _run(self.bm.connect("456", "/foo")) + assert self.bm.is_connected(sid1, "/") + assert self.bm.is_connected(sid2, "/foo") + assert not self.bm.is_connected(sid2, "/") + assert not self.bm.is_connected(sid1, "/foo") + _run(self.bm.disconnect(sid1, "/")) + assert not self.bm.is_connected(sid1, "/") + assert self.bm.is_connected(sid2, "/foo") + _run(self.bm.disconnect(sid2, "/foo")) + assert not self.bm.is_connected(sid2, "/foo") + assert dict(self.bm.rooms["/"][None]) == {sid3: "456"} + assert dict(self.bm.rooms["/"][sid3]) == {sid3: "456"} + assert dict(self.bm.rooms["/foo"][None]) == {sid4: "456"} + assert dict(self.bm.rooms["/foo"][sid4]) == {sid4: "456"} def test_disconnect_twice(self): - sid1 = _run(self.bm.connect('123', '/')) - sid2 = _run(self.bm.connect('123', '/foo')) - sid3 = _run(self.bm.connect('456', '/')) - sid4 = _run(self.bm.connect('456', '/foo')) - _run(self.bm.disconnect(sid1, '/')) - _run(self.bm.disconnect(sid2, '/foo')) - _run(self.bm.disconnect(sid1, '/')) - _run(self.bm.disconnect(sid2, '/foo')) - assert dict(self.bm.rooms['/'][None]) == {sid3: '456'} - assert dict(self.bm.rooms['/'][sid3]) == {sid3: '456'} - assert dict(self.bm.rooms['/foo'][None]) == {sid4: '456'} - assert dict(self.bm.rooms['/foo'][sid4]) == {sid4: '456'} + sid1 = _run(self.bm.connect("123", "/")) + sid2 = _run(self.bm.connect("123", "/foo")) + sid3 = _run(self.bm.connect("456", "/")) + sid4 = _run(self.bm.connect("456", "/foo")) + _run(self.bm.disconnect(sid1, "/")) + _run(self.bm.disconnect(sid2, "/foo")) + _run(self.bm.disconnect(sid1, "/")) + _run(self.bm.disconnect(sid2, "/foo")) + assert dict(self.bm.rooms["/"][None]) == {sid3: "456"} + assert dict(self.bm.rooms["/"][sid3]) == {sid3: "456"} + assert dict(self.bm.rooms["/foo"][None]) == {sid4: "456"} + assert dict(self.bm.rooms["/foo"][sid4]) == {sid4: "456"} def test_disconnect_all(self): - sid1 = _run(self.bm.connect('123', '/foo')) - sid2 = _run(self.bm.connect('456', '/foo')) - _run(self.bm.enter_room(sid1, '/foo', 'bar')) - _run(self.bm.enter_room(sid2, '/foo', 'baz')) - _run(self.bm.disconnect(sid1, '/foo')) - _run(self.bm.disconnect(sid2, '/foo')) + sid1 = _run(self.bm.connect("123", "/foo")) + sid2 = _run(self.bm.connect("456", "/foo")) + _run(self.bm.enter_room(sid1, "/foo", "bar")) + _run(self.bm.enter_room(sid2, "/foo", "baz")) + _run(self.bm.disconnect(sid1, "/foo")) + _run(self.bm.disconnect(sid2, "/foo")) assert self.bm.rooms == {} def test_disconnect_with_callbacks(self): - sid1 = _run(self.bm.connect('123', '/')) - sid2 = _run(self.bm.connect('123', '/foo')) - sid3 = _run(self.bm.connect('456', '/foo')) - self.bm._generate_ack_id(sid1, 'f') - self.bm._generate_ack_id(sid2, 'g') - self.bm._generate_ack_id(sid3, 'h') - _run(self.bm.disconnect(sid2, '/foo')) + sid1 = _run(self.bm.connect("123", "/")) + sid2 = _run(self.bm.connect("123", "/foo")) + sid3 = _run(self.bm.connect("456", "/foo")) + self.bm._generate_ack_id(sid1, "f") + self.bm._generate_ack_id(sid2, "g") + self.bm._generate_ack_id(sid3, "h") + _run(self.bm.disconnect(sid2, "/foo")) assert sid2 not in self.bm.callbacks - _run(self.bm.disconnect(sid1, '/')) + _run(self.bm.disconnect(sid1, "/")) assert sid1 not in self.bm.callbacks assert sid3 in self.bm.callbacks def test_trigger_sync_callback(self): - sid1 = _run(self.bm.connect('123', '/')) - sid2 = _run(self.bm.connect('123', '/foo')) + sid1 = _run(self.bm.connect("123", "/")) + sid2 = _run(self.bm.connect("123", "/foo")) cb = mock.MagicMock() id1 = self.bm._generate_ack_id(sid1, cb) id2 = self.bm._generate_ack_id(sid2, cb) - _run(self.bm.trigger_callback(sid1, id1, ['foo'])) - _run(self.bm.trigger_callback(sid2, id2, ['bar', 'baz'])) + _run(self.bm.trigger_callback(sid1, id1, ["foo"])) + _run(self.bm.trigger_callback(sid2, id2, ["bar", "baz"])) assert cb.call_count == 2 - cb.assert_any_call('foo') - cb.assert_any_call('bar', 'baz') + cb.assert_any_call("foo") + cb.assert_any_call("bar", "baz") def test_trigger_async_callback(self): - sid1 = _run(self.bm.connect('123', '/')) - sid2 = _run(self.bm.connect('123', '/foo')) + sid1 = _run(self.bm.connect("123", "/")) + sid2 = _run(self.bm.connect("123", "/foo")) cb = AsyncMock() id1 = self.bm._generate_ack_id(sid1, cb) id2 = self.bm._generate_ack_id(sid2, cb) - _run(self.bm.trigger_callback(sid1, id1, ['foo'])) - _run(self.bm.trigger_callback(sid2, id2, ['bar', 'baz'])) + _run(self.bm.trigger_callback(sid1, id1, ["foo"])) + _run(self.bm.trigger_callback(sid2, id2, ["bar", "baz"])) assert cb.mock.call_count == 2 - cb.mock.assert_any_call('foo') - cb.mock.assert_any_call('bar', 'baz') + cb.mock.assert_any_call("foo") + cb.mock.assert_any_call("bar", "baz") def test_invalid_callback(self): - sid = _run(self.bm.connect('123', '/')) + sid = _run(self.bm.connect("123", "/")) cb = mock.MagicMock() id = self.bm._generate_ack_id(sid, cb) # these should not raise an exception - _run(self.bm.trigger_callback('xxx', id, ['foo'])) - _run(self.bm.trigger_callback(sid, id + 1, ['foo'])) + _run(self.bm.trigger_callback("xxx", id, ["foo"])) + _run(self.bm.trigger_callback(sid, id + 1, ["foo"])) assert cb.mock.call_count == 0 def test_get_namespaces(self): assert list(self.bm.get_namespaces()) == [] - _run(self.bm.connect('123', '/')) - _run(self.bm.connect('123', '/foo')) + _run(self.bm.connect("123", "/")) + _run(self.bm.connect("123", "/foo")) namespaces = list(self.bm.get_namespaces()) assert len(namespaces) == 2 - assert '/' in namespaces - assert '/foo' in namespaces + assert "/" in namespaces + assert "/foo" in namespaces def test_get_participants(self): - sid1 = _run(self.bm.connect('123', '/')) - sid2 = _run(self.bm.connect('456', '/')) - sid3 = _run(self.bm.connect('789', '/')) - _run(self.bm.disconnect(sid3, '/')) - assert sid3 not in self.bm.rooms['/'][None] - participants = list(self.bm.get_participants('/', None)) + sid1 = _run(self.bm.connect("123", "/")) + sid2 = _run(self.bm.connect("456", "/")) + sid3 = _run(self.bm.connect("789", "/")) + _run(self.bm.disconnect(sid3, "/")) + assert sid3 not in self.bm.rooms["/"][None] + participants = list(self.bm.get_participants("/", None)) assert len(participants) == 2 - assert (sid1, '123') in participants - assert (sid2, '456') in participants - assert (sid3, '789') not in participants + assert (sid1, "123") in participants + assert (sid2, "456") in participants + assert (sid3, "789") not in participants def test_leave_invalid_room(self): - sid = _run(self.bm.connect('123', '/foo')) - _run(self.bm.leave_room(sid, '/foo', 'baz')) - _run(self.bm.leave_room(sid, '/bar', 'baz')) + sid = _run(self.bm.connect("123", "/foo")) + _run(self.bm.leave_room(sid, "/foo", "baz")) + _run(self.bm.leave_room(sid, "/bar", "baz")) def test_no_room(self): - rooms = self.bm.get_rooms('123', '/foo') + rooms = self.bm.get_rooms("123", "/foo") assert [] == rooms def test_close_room(self): - sid = _run(self.bm.connect('123', '/foo')) - _run(self.bm.connect('456', '/foo')) - _run(self.bm.connect('789', '/foo')) - _run(self.bm.enter_room(sid, '/foo', 'bar')) - _run(self.bm.enter_room(sid, '/foo', 'bar')) - _run(self.bm.close_room('bar', '/foo')) + sid = _run(self.bm.connect("123", "/foo")) + _run(self.bm.connect("456", "/foo")) + _run(self.bm.connect("789", "/foo")) + _run(self.bm.enter_room(sid, "/foo", "bar")) + _run(self.bm.enter_room(sid, "/foo", "bar")) + _run(self.bm.close_room("bar", "/foo")) from pprint import pprint + pprint(self.bm.rooms) - assert 'bar' not in self.bm.rooms['/foo'] + assert "bar" not in self.bm.rooms["/foo"] def test_close_invalid_room(self): - self.bm.close_room('bar', '/foo') + self.bm.close_room("bar", "/foo") def test_rooms(self): - sid = _run(self.bm.connect('123', '/foo')) - _run(self.bm.enter_room(sid, '/foo', 'bar')) - r = self.bm.get_rooms(sid, '/foo') + sid = _run(self.bm.connect("123", "/foo")) + _run(self.bm.enter_room(sid, "/foo", "bar")) + r = self.bm.get_rooms(sid, "/foo") assert len(r) == 2 assert sid in r - assert 'bar' in r + assert "bar" in r def test_emit_to_sid(self): - sid = _run(self.bm.connect('123', '/foo')) - _run(self.bm.connect('456', '/foo')) - _run( - self.bm.emit( - 'my event', {'foo': 'bar'}, namespace='/foo', room=sid - ) - ) + sid = _run(self.bm.connect("123", "/foo")) + _run(self.bm.connect("456", "/foo")) + _run(self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", room=sid)) assert self.bm.server._send_eio_packet.mock.call_count == 1 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_room(self): - sid1 = _run(self.bm.connect('123', '/foo')) - _run(self.bm.enter_room(sid1, '/foo', 'bar')) - sid2 = _run(self.bm.connect('456', '/foo')) - _run(self.bm.enter_room(sid2, '/foo', 'bar')) - _run(self.bm.connect('789', '/foo')) - _run( - self.bm.emit( - 'my event', {'foo': 'bar'}, namespace='/foo', room='bar' - ) - ) + sid1 = _run(self.bm.connect("123", "/foo")) + _run(self.bm.enter_room(sid1, "/foo", "bar")) + sid2 = _run(self.bm.connect("456", "/foo")) + _run(self.bm.enter_room(sid2, "/foo", "bar")) + _run(self.bm.connect("789", "/foo")) + _run(self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", room="bar")) assert self.bm.server._send_eio_packet.mock.call_count == 2 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] \ - == '456' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] == "456" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] \ - == pkt + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] == pkt assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_rooms(self): - sid1 = _run(self.bm.connect('123', '/foo')) - _run(self.bm.enter_room(sid1, '/foo', 'bar')) - sid2 = _run(self.bm.connect('456', '/foo')) - _run(self.bm.enter_room(sid2, '/foo', 'bar')) - _run(self.bm.enter_room(sid2, '/foo', 'baz')) - sid3 = _run(self.bm.connect('789', '/foo')) - _run(self.bm.enter_room(sid3, '/foo', 'baz')) + sid1 = _run(self.bm.connect("123", "/foo")) + _run(self.bm.enter_room(sid1, "/foo", "bar")) + sid2 = _run(self.bm.connect("456", "/foo")) + _run(self.bm.enter_room(sid2, "/foo", "bar")) + _run(self.bm.enter_room(sid2, "/foo", "baz")) + sid3 = _run(self.bm.connect("789", "/foo")) + _run(self.bm.enter_room(sid3, "/foo", "baz")) _run( - self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo', - room=['bar', 'baz']) + self.bm.emit( + "my event", {"foo": "bar"}, namespace="/foo", room=["bar", "baz"] + ) ) assert self.bm.server._send_eio_packet.mock.call_count == 3 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] \ - == '456' - assert self.bm.server._send_eio_packet.mock.call_args_list[2][0][0] \ - == '789' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] == "456" + assert self.bm.server._send_eio_packet.mock.call_args_list[2][0][0] == "789" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] \ - == pkt - assert self.bm.server._send_eio_packet.mock.call_args_list[2][0][1] \ - == pkt + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] == pkt + assert self.bm.server._send_eio_packet.mock.call_args_list[2][0][1] == pkt assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_all(self): - sid1 = _run(self.bm.connect('123', '/foo')) - _run(self.bm.enter_room(sid1, '/foo', 'bar')) - sid2 = _run(self.bm.connect('456', '/foo')) - _run(self.bm.enter_room(sid2, '/foo', 'bar')) - _run(self.bm.connect('789', '/foo')) - _run(self.bm.connect('abc', '/bar')) - _run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo')) + sid1 = _run(self.bm.connect("123", "/foo")) + _run(self.bm.enter_room(sid1, "/foo", "bar")) + sid2 = _run(self.bm.connect("456", "/foo")) + _run(self.bm.enter_room(sid2, "/foo", "bar")) + _run(self.bm.connect("789", "/foo")) + _run(self.bm.connect("abc", "/bar")) + _run(self.bm.emit("my event", {"foo": "bar"}, namespace="/foo")) assert self.bm.server._send_eio_packet.mock.call_count == 3 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] \ - == '456' - assert self.bm.server._send_eio_packet.mock.call_args_list[2][0][0] \ - == '789' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] == "456" + assert self.bm.server._send_eio_packet.mock.call_args_list[2][0][0] == "789" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] \ - == pkt - assert self.bm.server._send_eio_packet.mock.call_args_list[2][0][1] \ - == pkt + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] == pkt + assert self.bm.server._send_eio_packet.mock.call_args_list[2][0][1] == pkt assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_all_skip_one(self): - sid1 = _run(self.bm.connect('123', '/foo')) - _run(self.bm.enter_room(sid1, '/foo', 'bar')) - sid2 = _run(self.bm.connect('456', '/foo')) - _run(self.bm.enter_room(sid2, '/foo', 'bar')) - _run(self.bm.connect('789', '/foo')) - _run(self.bm.connect('abc', '/bar')) - _run( - self.bm.emit( - 'my event', {'foo': 'bar'}, namespace='/foo', skip_sid=sid2 - ) - ) + sid1 = _run(self.bm.connect("123", "/foo")) + _run(self.bm.enter_room(sid1, "/foo", "bar")) + sid2 = _run(self.bm.connect("456", "/foo")) + _run(self.bm.enter_room(sid2, "/foo", "bar")) + _run(self.bm.connect("789", "/foo")) + _run(self.bm.connect("abc", "/bar")) + _run(self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", skip_sid=sid2)) assert self.bm.server._send_eio_packet.mock.call_count == 2 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] \ - == '789' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] == "789" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] \ - == pkt + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] == pkt assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_all_skip_two(self): - sid1 = _run(self.bm.connect('123', '/foo')) - _run(self.bm.enter_room(sid1, '/foo', 'bar')) - sid2 = _run(self.bm.connect('456', '/foo')) - _run(self.bm.enter_room(sid2, '/foo', 'bar')) - sid3 = _run(self.bm.connect('789', '/foo')) - _run(self.bm.connect('abc', '/bar')) + sid1 = _run(self.bm.connect("123", "/foo")) + _run(self.bm.enter_room(sid1, "/foo", "bar")) + sid2 = _run(self.bm.connect("456", "/foo")) + _run(self.bm.enter_room(sid2, "/foo", "bar")) + sid3 = _run(self.bm.connect("789", "/foo")) + _run(self.bm.connect("abc", "/bar")) _run( self.bm.emit( - 'my event', - {'foo': 'bar'}, - namespace='/foo', + "my event", + {"foo": "bar"}, + namespace="/foo", skip_sid=[sid1, sid3], ) ) assert self.bm.server._send_eio_packet.mock.call_count == 1 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '456' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "456" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_with_callback(self): - sid = _run(self.bm.connect('123', '/foo')) + sid = _run(self.bm.connect("123", "/foo")) self.bm._generate_ack_id = mock.MagicMock() self.bm._generate_ack_id.return_value = 11 - _run( - self.bm.emit( - 'my event', {'foo': 'bar'}, namespace='/foo', callback='cb' - ) - ) - self.bm._generate_ack_id.assert_called_once_with(sid, 'cb') + _run(self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", callback="cb")) + self.bm._generate_ack_id.assert_called_once_with(sid, "cb") assert self.bm.server._send_packet.mock.call_count == 1 - assert self.bm.server._send_packet.mock.call_args_list[0][0][0] \ - == '123' + assert self.bm.server._send_packet.mock.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_packet.mock.call_args_list[0][0][1] assert pkt.encode() == '2/foo,11["my event",{"foo":"bar"}]' def test_emit_to_invalid_room(self): - _run( - self.bm.emit('my event', {'foo': 'bar'}, namespace='/', room='123') - ) + _run(self.bm.emit("my event", {"foo": "bar"}, namespace="/", room="123")) def test_emit_to_invalid_namespace(self): - _run(self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo')) + _run(self.bm.emit("my event", {"foo": "bar"}, namespace="/foo")) def test_emit_with_tuple(self): - sid = _run(self.bm.connect('123', '/foo')) - _run( - self.bm.emit( - 'my event', ('foo', 'bar'), namespace='/foo', room=sid - ) - ) + sid = _run(self.bm.connect("123", "/foo")) + _run(self.bm.emit("my event", ("foo", "bar"), namespace="/foo", room=sid)) assert self.bm.server._send_eio_packet.mock.call_count == 1 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event","foo","bar"]' def test_emit_with_list(self): - sid = _run(self.bm.connect('123', '/foo')) - _run( - self.bm.emit( - 'my event', ['foo', 'bar'], namespace='/foo', room=sid - ) - ) + sid = _run(self.bm.connect("123", "/foo")) + _run(self.bm.emit("my event", ["foo", "bar"], namespace="/foo", room=sid)) assert self.bm.server._send_eio_packet.mock.call_count == 1 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event",["foo","bar"]]' def test_emit_with_none(self): - sid = _run(self.bm.connect('123', '/foo')) - _run( - self.bm.emit( - 'my event', None, namespace='/foo', room=sid - ) - ) + sid = _run(self.bm.connect("123", "/foo")) + _run(self.bm.emit("my event", None, namespace="/foo", room=sid)) assert self.bm.server._send_eio_packet.mock.call_count == 1 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event"]' def test_emit_binary(self): - sid = _run(self.bm.connect('123', '/')) - _run( - self.bm.emit( - u'my event', b'my binary data', namespace='/', room=sid - ) - ) + sid = _run(self.bm.connect("123", "/")) + _run(self.bm.emit("my event", b"my binary data", namespace="/", room=sid)) assert self.bm.server._send_eio_packet.mock.call_count == 2 - assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' + assert self.bm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.mock.call_args_list[0][0][1] assert pkt.encode() == '451-["my event",{"_placeholder":true,"num":0}]' - assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] \ - == '123' + assert self.bm.server._send_eio_packet.mock.call_args_list[1][0][0] == "123" pkt = self.bm.server._send_eio_packet.mock.call_args_list[1][0][1] - assert pkt.encode() == b'my binary data' + assert pkt.encode() == b"my binary data" diff --git a/tests/async/test_namespace.py b/tests/async/test_namespace.py index 6043003..c1afe89 100644 --- a/tests/async/test_namespace.py +++ b/tests/async/test_namespace.py @@ -6,335 +6,323 @@ from socketio import async_namespace from .helpers import AsyncMock, _run -@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') +@unittest.skipIf(sys.version_info < (3, 5), "only for Python 3.5+") class TestAsyncNamespace(unittest.TestCase): def test_connect_event(self): result = {} class MyNamespace(async_namespace.AsyncNamespace): async def on_connect(self, sid, environ): - result['result'] = (sid, environ) + result["result"] = (sid, environ) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - _run(ns.trigger_event('connect', 'sid', {'foo': 'bar'})) - assert result['result'] == ('sid', {'foo': 'bar'}) + _run(ns.trigger_event("connect", "sid", {"foo": "bar"})) + assert result["result"] == ("sid", {"foo": "bar"}) def test_disconnect_event(self): result = {} class MyNamespace(async_namespace.AsyncNamespace): async def on_disconnect(self, sid): - result['result'] = sid + result["result"] = sid - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - _run(ns.trigger_event('disconnect', 'sid')) - assert result['result'] == 'sid' + _run(ns.trigger_event("disconnect", "sid")) + assert result["result"] == "sid" def test_sync_event(self): result = {} class MyNamespace(async_namespace.AsyncNamespace): def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - _run(ns.trigger_event('custom_message', 'sid', {'data': 'data'})) - assert result['result'] == ('sid', {'data': 'data'}) + _run(ns.trigger_event("custom_message", "sid", {"data": "data"})) + assert result["result"] == ("sid", {"data": "data"}) def test_async_event(self): result = {} class MyNamespace(async_namespace.AsyncNamespace): async def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - _run(ns.trigger_event('custom_message', 'sid', {'data': 'data'})) - assert result['result'] == ('sid', {'data': 'data'}) + _run(ns.trigger_event("custom_message", "sid", {"data": "data"})) + assert result["result"] == ("sid", {"data": "data"}) def test_event_not_found(self): result = {} class MyNamespace(async_namespace.AsyncNamespace): async def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - _run( - ns.trigger_event('another_custom_message', 'sid', {'data': 'data'}) - ) + _run(ns.trigger_event("another_custom_message", "sid", {"data": "data"})) assert result == {} def test_emit(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") mock_server = mock.MagicMock() mock_server.emit = AsyncMock() ns._set_server(mock_server) - _run( - ns.emit( - 'ev', data='data', to='room', skip_sid='skip', callback='cb' - ) - ) + _run(ns.emit("ev", data="data", to="room", skip_sid="skip", callback="cb")) ns.server.emit.mock.assert_called_with( - 'ev', - data='data', - to='room', + "ev", + data="data", + to="room", room=None, - skip_sid='skip', - namespace='/foo', - callback='cb', + skip_sid="skip", + namespace="/foo", + callback="cb", ignore_queue=False, ) _run( ns.emit( - 'ev', - data='data', - room='room', - skip_sid='skip', - namespace='/bar', - callback='cb', + "ev", + data="data", + room="room", + skip_sid="skip", + namespace="/bar", + callback="cb", ignore_queue=True, ) ) ns.server.emit.mock.assert_called_with( - 'ev', - data='data', + "ev", + data="data", to=None, - room='room', - skip_sid='skip', - namespace='/bar', - callback='cb', + room="room", + skip_sid="skip", + namespace="/bar", + callback="cb", ignore_queue=True, ) def test_send(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") mock_server = mock.MagicMock() mock_server.send = AsyncMock() ns._set_server(mock_server) - _run(ns.send(data='data', to='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', - to='room', + "data", + to="room", room=None, - skip_sid='skip', - namespace='/foo', - callback='cb', + skip_sid="skip", + namespace="/foo", + callback="cb", ignore_queue=False, ) _run( ns.send( - data='data', - room='room', - skip_sid='skip', - namespace='/bar', - callback='cb', + data="data", + room="room", + skip_sid="skip", + namespace="/bar", + callback="cb", ignore_queue=True, ) ) ns.server.send.mock.assert_called_with( - 'data', + "data", to=None, - room='room', - skip_sid='skip', - namespace='/bar', - callback='cb', + room="room", + skip_sid="skip", + namespace="/bar", + callback="cb", ignore_queue=True, ) def test_call(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") mock_server = mock.MagicMock() mock_server.call = AsyncMock() ns._set_server(mock_server) - _run(ns.call('ev', data='data', to='sid')) + _run(ns.call("ev", data="data", to="sid")) ns.server.call.mock.assert_called_with( - 'ev', - data='data', - to='sid', + "ev", + data="data", + to="sid", sid=None, - namespace='/foo', + namespace="/foo", timeout=None, ignore_queue=False, ) - _run(ns.call('ev', data='data', sid='sid', namespace='/bar', - timeout=45, ignore_queue=True)) + _run( + ns.call( + "ev", + data="data", + sid="sid", + namespace="/bar", + timeout=45, + ignore_queue=True, + ) + ) ns.server.call.mock.assert_called_with( - 'ev', - data='data', + "ev", + data="data", to=None, - sid='sid', - namespace='/bar', + sid="sid", + namespace="/bar", timeout=45, ignore_queue=True, ) def test_enter_room(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") mock_server = mock.MagicMock() mock_server.enter_room = AsyncMock() ns._set_server(mock_server) - _run(ns.enter_room('sid', 'room')) - ns.server.enter_room.mock.assert_called_with( - 'sid', 'room', namespace='/foo' - ) - _run(ns.enter_room('sid', 'room', namespace='/bar')) - ns.server.enter_room.mock.assert_called_with( - 'sid', 'room', namespace='/bar' - ) + _run(ns.enter_room("sid", "room")) + ns.server.enter_room.mock.assert_called_with("sid", "room", namespace="/foo") + _run(ns.enter_room("sid", "room", namespace="/bar")) + ns.server.enter_room.mock.assert_called_with("sid", "room", namespace="/bar") def test_leave_room(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") mock_server = mock.MagicMock() mock_server.leave_room = AsyncMock() ns._set_server(mock_server) - _run(ns.leave_room('sid', 'room')) - ns.server.leave_room.mock.assert_called_with( - 'sid', 'room', namespace='/foo' - ) - _run(ns.leave_room('sid', 'room', namespace='/bar')) - ns.server.leave_room.mock.assert_called_with( - 'sid', 'room', namespace='/bar' - ) + _run(ns.leave_room("sid", "room")) + ns.server.leave_room.mock.assert_called_with("sid", "room", namespace="/foo") + _run(ns.leave_room("sid", "room", namespace="/bar")) + ns.server.leave_room.mock.assert_called_with("sid", "room", namespace="/bar") def test_close_room(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") mock_server = mock.MagicMock() mock_server.close_room = AsyncMock() ns._set_server(mock_server) - _run(ns.close_room('room')) - ns.server.close_room.mock.assert_called_with('room', namespace='/foo') - _run(ns.close_room('room', namespace='/bar')) - ns.server.close_room.mock.assert_called_with('room', namespace='/bar') + _run(ns.close_room("room")) + ns.server.close_room.mock.assert_called_with("room", namespace="/foo") + _run(ns.close_room("room", namespace="/bar")) + ns.server.close_room.mock.assert_called_with("room", namespace="/bar") def test_rooms(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") ns._set_server(mock.MagicMock()) - ns.rooms('sid') - ns.server.rooms.assert_called_with('sid', namespace='/foo') - ns.rooms('sid', namespace='/bar') - ns.server.rooms.assert_called_with('sid', namespace='/bar') + ns.rooms("sid") + ns.server.rooms.assert_called_with("sid", namespace="/foo") + ns.rooms("sid", namespace="/bar") + ns.server.rooms.assert_called_with("sid", namespace="/bar") def test_session(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") mock_server = mock.MagicMock() mock_server.get_session = AsyncMock() mock_server.save_session = AsyncMock() ns._set_server(mock_server) - _run(ns.get_session('sid')) - ns.server.get_session.mock.assert_called_with('sid', namespace='/foo') - _run(ns.get_session('sid', namespace='/bar')) - ns.server.get_session.mock.assert_called_with('sid', namespace='/bar') - _run(ns.save_session('sid', {'a': 'b'})) + _run(ns.get_session("sid")) + ns.server.get_session.mock.assert_called_with("sid", namespace="/foo") + _run(ns.get_session("sid", namespace="/bar")) + ns.server.get_session.mock.assert_called_with("sid", namespace="/bar") + _run(ns.save_session("sid", {"a": "b"})) ns.server.save_session.mock.assert_called_with( - 'sid', {'a': 'b'}, namespace='/foo' + "sid", {"a": "b"}, namespace="/foo" ) - _run(ns.save_session('sid', {'a': 'b'}, namespace='/bar')) + _run(ns.save_session("sid", {"a": "b"}, namespace="/bar")) ns.server.save_session.mock.assert_called_with( - 'sid', {'a': 'b'}, namespace='/bar' + "sid", {"a": "b"}, namespace="/bar" ) - ns.session('sid') - ns.server.session.assert_called_with('sid', namespace='/foo') - ns.session('sid', namespace='/bar') - ns.server.session.assert_called_with('sid', namespace='/bar') + ns.session("sid") + ns.server.session.assert_called_with("sid", namespace="/foo") + ns.session("sid", namespace="/bar") + ns.server.session.assert_called_with("sid", namespace="/bar") def test_disconnect(self): - ns = async_namespace.AsyncNamespace('/foo') + ns = async_namespace.AsyncNamespace("/foo") mock_server = mock.MagicMock() mock_server.disconnect = AsyncMock() ns._set_server(mock_server) - _run(ns.disconnect('sid')) - ns.server.disconnect.mock.assert_called_with('sid', namespace='/foo') - _run(ns.disconnect('sid', namespace='/bar')) - ns.server.disconnect.mock.assert_called_with('sid', namespace='/bar') + _run(ns.disconnect("sid")) + ns.server.disconnect.mock.assert_called_with("sid", namespace="/foo") + _run(ns.disconnect("sid", namespace="/bar")) + ns.server.disconnect.mock.assert_called_with("sid", namespace="/bar") def test_sync_event_client(self): result = {} class MyNamespace(async_namespace.AsyncClientNamespace): def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_client(mock.MagicMock()) - _run(ns.trigger_event('custom_message', 'sid', {'data': 'data'})) - assert result['result'] == ('sid', {'data': 'data'}) + _run(ns.trigger_event("custom_message", "sid", {"data": "data"})) + assert result["result"] == ("sid", {"data": "data"}) def test_async_event_client(self): result = {} class MyNamespace(async_namespace.AsyncClientNamespace): async def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_client(mock.MagicMock()) - _run(ns.trigger_event('custom_message', 'sid', {'data': 'data'})) - assert result['result'] == ('sid', {'data': 'data'}) + _run(ns.trigger_event("custom_message", "sid", {"data": "data"})) + assert result["result"] == ("sid", {"data": "data"}) def test_event_not_found_client(self): result = {} class MyNamespace(async_namespace.AsyncClientNamespace): async def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_client(mock.MagicMock()) - _run( - ns.trigger_event('another_custom_message', 'sid', {'data': 'data'}) - ) + _run(ns.trigger_event("another_custom_message", "sid", {"data": "data"})) assert result == {} def test_emit_client(self): - ns = async_namespace.AsyncClientNamespace('/foo') + ns = async_namespace.AsyncClientNamespace("/foo") mock_client = mock.MagicMock() mock_client.emit = AsyncMock() ns._set_client(mock_client) - _run(ns.emit('ev', data='data', callback='cb')) + _run(ns.emit("ev", data="data", callback="cb")) ns.client.emit.mock.assert_called_with( - 'ev', data='data', namespace='/foo', callback='cb' + "ev", data="data", namespace="/foo", callback="cb" ) - _run(ns.emit('ev', data='data', namespace='/bar', callback='cb')) + _run(ns.emit("ev", data="data", namespace="/bar", callback="cb")) ns.client.emit.mock.assert_called_with( - 'ev', data='data', namespace='/bar', callback='cb' + "ev", data="data", namespace="/bar", callback="cb" ) def test_send_client(self): - ns = async_namespace.AsyncClientNamespace('/foo') + ns = async_namespace.AsyncClientNamespace("/foo") mock_client = mock.MagicMock() mock_client.send = AsyncMock() ns._set_client(mock_client) - _run(ns.send(data='data', callback='cb')) - ns.client.send.mock.assert_called_with( - 'data', namespace='/foo', callback='cb' - ) - _run(ns.send(data='data', namespace='/bar', callback='cb')) - ns.client.send.mock.assert_called_with( - 'data', namespace='/bar', callback='cb' - ) + _run(ns.send(data="data", callback="cb")) + ns.client.send.mock.assert_called_with("data", namespace="/foo", callback="cb") + _run(ns.send(data="data", namespace="/bar", callback="cb")) + ns.client.send.mock.assert_called_with("data", namespace="/bar", callback="cb") def test_call_client(self): - ns = async_namespace.AsyncClientNamespace('/foo') + ns = async_namespace.AsyncClientNamespace("/foo") mock_client = mock.MagicMock() mock_client.call = AsyncMock() ns._set_client(mock_client) - _run(ns.call('ev', data='data')) + _run(ns.call("ev", data="data")) ns.client.call.mock.assert_called_with( - 'ev', data='data', namespace='/foo', timeout=None + "ev", data="data", namespace="/foo", timeout=None ) - _run(ns.call('ev', data='data', namespace='/bar', timeout=45)) + _run(ns.call("ev", data="data", namespace="/bar", timeout=45)) ns.client.call.mock.assert_called_with( - 'ev', data='data', namespace='/bar', timeout=45 + "ev", data="data", namespace="/bar", timeout=45 ) def test_disconnect_client(self): - ns = async_namespace.AsyncClientNamespace('/foo') + ns = async_namespace.AsyncClientNamespace("/foo") mock_client = mock.MagicMock() mock_client.disconnect = AsyncMock() ns._set_client(mock_client) diff --git a/tests/async/test_pubsub_manager.py b/tests/async/test_pubsub_manager.py index 48a71aa..5eae105 100644 --- a/tests/async/test_pubsub_manager.py +++ b/tests/async/test_pubsub_manager.py @@ -12,7 +12,7 @@ from socketio import packet from .helpers import AsyncMock, _run -@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') +@unittest.skipIf(sys.version_info < (3, 5), "only for Python 3.5+") class TestAsyncPubSubManager(unittest.TestCase): def setUp(self): id = 0 @@ -31,18 +31,16 @@ class TestAsyncPubSubManager(unittest.TestCase): self.pm = async_pubsub_manager.AsyncPubSubManager() self.pm._publish = AsyncMock() self.pm.set_server(mock_server) - self.pm.host_id = '123456' + self.pm.host_id = "123456" self.pm.initialize() def test_default_init(self): - assert self.pm.channel == 'socketio' - self.pm.server.start_background_task.assert_called_once_with( - self.pm._thread - ) + assert self.pm.channel == "socketio" + self.pm.server.start_background_task.assert_called_once_with(self.pm._thread) def test_custom_init(self): - pubsub = async_pubsub_manager.AsyncPubSubManager(channel='foo') - assert pubsub.channel == 'foo' + pubsub = async_pubsub_manager.AsyncPubSubManager(channel="foo") + assert pubsub.channel == "foo" assert len(pubsub.host_id) == 32 def test_write_only_init(self): @@ -50,181 +48,198 @@ class TestAsyncPubSubManager(unittest.TestCase): pm = async_pubsub_manager.AsyncPubSubManager(write_only=True) pm.set_server(mock_server) pm.initialize() - assert pm.channel == 'socketio' + assert pm.channel == "socketio" assert len(pm.host_id) == 32 assert pm.server.start_background_task.call_count == 0 def test_emit(self): - _run(self.pm.emit('foo', 'bar')) + _run(self.pm.emit("foo", "bar")) self.pm._publish.mock.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/', - 'room': None, - 'skip_sid': None, - 'callback': None, - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/", + "room": None, + "skip_sid": None, + "callback": None, + "host_id": "123456", } ) def test_emit_with_namespace(self): - _run(self.pm.emit('foo', 'bar', namespace='/baz')) + _run(self.pm.emit("foo", "bar", namespace="/baz")) self.pm._publish.mock.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/baz', - 'room': None, - 'skip_sid': None, - 'callback': None, - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/baz", + "room": None, + "skip_sid": None, + "callback": None, + "host_id": "123456", } ) def test_emit_with_room(self): - _run(self.pm.emit('foo', 'bar', room='baz')) + _run(self.pm.emit("foo", "bar", room="baz")) self.pm._publish.mock.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/', - 'room': 'baz', - 'skip_sid': None, - 'callback': None, - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/", + "room": "baz", + "skip_sid": None, + "callback": None, + "host_id": "123456", } ) def test_emit_with_skip_sid(self): - _run(self.pm.emit('foo', 'bar', skip_sid='baz')) + _run(self.pm.emit("foo", "bar", skip_sid="baz")) self.pm._publish.mock.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/', - 'room': None, - 'skip_sid': 'baz', - 'callback': None, - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/", + "room": None, + "skip_sid": "baz", + "callback": None, + "host_id": "123456", } ) def test_emit_with_callback(self): - with mock.patch.object( - self.pm, '_generate_ack_id', return_value='123' - ): - _run(self.pm.emit('foo', 'bar', room='baz', callback='cb')) + with mock.patch.object(self.pm, "_generate_ack_id", return_value="123"): + _run(self.pm.emit("foo", "bar", room="baz", callback="cb")) self.pm._publish.mock.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/', - 'room': 'baz', - 'skip_sid': None, - 'callback': ('baz', '/', '123'), - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/", + "room": "baz", + "skip_sid": None, + "callback": ("baz", "/", "123"), + "host_id": "123456", } ) def test_emit_with_callback_without_server(self): standalone_pm = async_pubsub_manager.AsyncPubSubManager() with pytest.raises(RuntimeError): - _run(standalone_pm.emit('foo', 'bar', callback='cb')) + _run(standalone_pm.emit("foo", "bar", callback="cb")) def test_emit_with_callback_missing_room(self): - with mock.patch.object( - self.pm, '_generate_ack_id', return_value='123' - ): + with mock.patch.object(self.pm, "_generate_ack_id", return_value="123"): with pytest.raises(ValueError): - _run(self.pm.emit('foo', 'bar', callback='cb')) + _run(self.pm.emit("foo", "bar", callback="cb")) def test_emit_with_ignore_queue(self): - sid = _run(self.pm.connect('123', '/')) - _run( - self.pm.emit( - 'foo', 'bar', room=sid, namespace='/', ignore_queue=True - ) - ) + sid = _run(self.pm.connect("123", "/")) + _run(self.pm.emit("foo", "bar", room=sid, namespace="/", ignore_queue=True)) self.pm._publish.mock.assert_not_called() assert self.pm.server._send_eio_packet.mock.call_count == 1 - assert self.pm.server._send_eio_packet.mock.call_args_list[0][0][0] \ - == '123' + assert self.pm.server._send_eio_packet.mock.call_args_list[0][0][0] == "123" pkt = self.pm.server._send_eio_packet.mock.call_args_list[0][0][1] assert pkt.encode() == '42["foo","bar"]' def test_can_disconnect(self): - sid = _run(self.pm.connect('123', '/')) - assert _run(self.pm.can_disconnect(sid, '/')) is True - _run(self.pm.can_disconnect(sid, '/foo')) + sid = _run(self.pm.connect("123", "/")) + assert _run(self.pm.can_disconnect(sid, "/")) is True + _run(self.pm.can_disconnect(sid, "/foo")) self.pm._publish.mock.assert_called_once_with( - {'method': 'disconnect', 'sid': sid, 'namespace': '/foo', - 'host_id': '123456'} + { + "method": "disconnect", + "sid": sid, + "namespace": "/foo", + "host_id": "123456", + } ) def test_disconnect(self): - _run(self.pm.disconnect('foo', '/')) + _run(self.pm.disconnect("foo", "/")) self.pm._publish.mock.assert_called_once_with( - {'method': 'disconnect', 'sid': 'foo', 'namespace': '/', - 'host_id': '123456'} + { + "method": "disconnect", + "sid": "foo", + "namespace": "/", + "host_id": "123456", + } ) def test_disconnect_ignore_queue(self): - sid = _run(self.pm.connect('123', '/')) - self.pm.pre_disconnect(sid, '/') - _run(self.pm.disconnect(sid, '/', ignore_queue=True)) + sid = _run(self.pm.connect("123", "/")) + self.pm.pre_disconnect(sid, "/") + _run(self.pm.disconnect(sid, "/", ignore_queue=True)) self.pm._publish.mock.assert_not_called() - assert self.pm.is_connected(sid, '/') is False + assert self.pm.is_connected(sid, "/") is False def test_enter_room(self): - sid = _run(self.pm.connect('123', '/')) - _run(self.pm.enter_room(sid, '/', 'foo')) - _run(self.pm.enter_room('456', '/', 'foo')) - assert sid in self.pm.rooms['/']['foo'] - assert self.pm.rooms['/']['foo'][sid] == '123' + sid = _run(self.pm.connect("123", "/")) + _run(self.pm.enter_room(sid, "/", "foo")) + _run(self.pm.enter_room("456", "/", "foo")) + assert sid in self.pm.rooms["/"]["foo"] + assert self.pm.rooms["/"]["foo"][sid] == "123" self.pm._publish.mock.assert_called_once_with( - {'method': 'enter_room', 'sid': '456', 'room': 'foo', - 'namespace': '/', 'host_id': '123456'} + { + "method": "enter_room", + "sid": "456", + "room": "foo", + "namespace": "/", + "host_id": "123456", + } ) def test_leave_room(self): - sid = _run(self.pm.connect('123', '/')) - _run(self.pm.leave_room(sid, '/', 'foo')) - _run(self.pm.leave_room('456', '/', 'foo')) - assert 'foo' not in self.pm.rooms['/'] + sid = _run(self.pm.connect("123", "/")) + _run(self.pm.leave_room(sid, "/", "foo")) + _run(self.pm.leave_room("456", "/", "foo")) + assert "foo" not in self.pm.rooms["/"] self.pm._publish.mock.assert_called_once_with( - {'method': 'leave_room', 'sid': '456', 'room': 'foo', - 'namespace': '/', 'host_id': '123456'} + { + "method": "leave_room", + "sid": "456", + "room": "foo", + "namespace": "/", + "host_id": "123456", + } ) def test_close_room(self): - _run(self.pm.close_room('foo')) + _run(self.pm.close_room("foo")) self.pm._publish.mock.assert_called_once_with( - {'method': 'close_room', 'room': 'foo', 'namespace': '/', - 'host_id': '123456'} + { + "method": "close_room", + "room": "foo", + "namespace": "/", + "host_id": "123456", + } ) def test_close_room_with_namespace(self): - _run(self.pm.close_room('foo', '/bar')) + _run(self.pm.close_room("foo", "/bar")) self.pm._publish.mock.assert_called_once_with( - {'method': 'close_room', 'room': 'foo', 'namespace': '/bar', - 'host_id': '123456'} + { + "method": "close_room", + "room": "foo", + "namespace": "/bar", + "host_id": "123456", + } ) def test_handle_emit(self): with mock.patch.object( - async_manager.AsyncManager, 'emit', new=AsyncMock() + async_manager.AsyncManager, "emit", new=AsyncMock() ) as super_emit: - _run(self.pm._handle_emit({'event': 'foo', 'data': 'bar'})) + _run(self.pm._handle_emit({"event": "foo", "data": "bar"})) super_emit.mock.assert_called_once_with( self.pm, - 'foo', - 'bar', + "foo", + "bar", namespace=None, room=None, skip_sid=None, @@ -233,18 +248,18 @@ class TestAsyncPubSubManager(unittest.TestCase): def test_handle_emit_with_namespace(self): with mock.patch.object( - async_manager.AsyncManager, 'emit', new=AsyncMock() + async_manager.AsyncManager, "emit", new=AsyncMock() ) as super_emit: _run( self.pm._handle_emit( - {'event': 'foo', 'data': 'bar', 'namespace': '/baz'} + {"event": "foo", "data": "bar", "namespace": "/baz"} ) ) super_emit.mock.assert_called_once_with( self.pm, - 'foo', - 'bar', - namespace='/baz', + "foo", + "bar", + namespace="/baz", room=None, skip_sid=None, callback=None, @@ -252,135 +267,125 @@ class TestAsyncPubSubManager(unittest.TestCase): def test_handle_emit_with_room(self): with mock.patch.object( - async_manager.AsyncManager, 'emit', new=AsyncMock() + async_manager.AsyncManager, "emit", new=AsyncMock() ) as super_emit: - _run( - self.pm._handle_emit( - {'event': 'foo', 'data': 'bar', 'room': 'baz'} - ) - ) + _run(self.pm._handle_emit({"event": "foo", "data": "bar", "room": "baz"})) super_emit.mock.assert_called_once_with( self.pm, - 'foo', - 'bar', + "foo", + "bar", namespace=None, - room='baz', + room="baz", skip_sid=None, callback=None, ) def test_handle_emit_with_skip_sid(self): with mock.patch.object( - async_manager.AsyncManager, 'emit', new=AsyncMock() + async_manager.AsyncManager, "emit", new=AsyncMock() ) as super_emit: _run( - self.pm._handle_emit( - {'event': 'foo', 'data': 'bar', 'skip_sid': '123'} - ) + self.pm._handle_emit({"event": "foo", "data": "bar", "skip_sid": "123"}) ) super_emit.mock.assert_called_once_with( self.pm, - 'foo', - 'bar', + "foo", + "bar", namespace=None, room=None, - skip_sid='123', + skip_sid="123", callback=None, ) def test_handle_emit_with_remote_callback(self): with mock.patch.object( - async_manager.AsyncManager, 'emit', new=AsyncMock() + async_manager.AsyncManager, "emit", new=AsyncMock() ) as super_emit: _run( self.pm._handle_emit( { - 'event': 'foo', - 'data': 'bar', - 'namespace': '/baz', - 'callback': ('sid', '/baz', 123), - 'host_id': 'x', + "event": "foo", + "data": "bar", + "namespace": "/baz", + "callback": ("sid", "/baz", 123), + "host_id": "x", } ) ) assert super_emit.mock.call_count == 1 - assert super_emit.mock.call_args[0] == (self.pm, 'foo', 'bar') - assert super_emit.mock.call_args[1]['namespace'] == '/baz' - assert super_emit.mock.call_args[1]['room'] is None - assert super_emit.mock.call_args[1]['skip_sid'] is None + assert super_emit.mock.call_args[0] == (self.pm, "foo", "bar") + assert super_emit.mock.call_args[1]["namespace"] == "/baz" + assert super_emit.mock.call_args[1]["room"] is None + assert super_emit.mock.call_args[1]["skip_sid"] is None assert isinstance( - super_emit.mock.call_args[1]['callback'], functools.partial + super_emit.mock.call_args[1]["callback"], functools.partial ) - _run(super_emit.mock.call_args[1]['callback']('one', 2, 'three')) + _run(super_emit.mock.call_args[1]["callback"]("one", 2, "three")) self.pm._publish.mock.assert_called_once_with( { - 'method': 'callback', - 'host_id': 'x', - 'sid': 'sid', - 'namespace': '/baz', - 'id': 123, - 'args': ('one', 2, 'three'), + "method": "callback", + "host_id": "x", + "sid": "sid", + "namespace": "/baz", + "id": 123, + "args": ("one", 2, "three"), } ) def test_handle_emit_with_local_callback(self): with mock.patch.object( - async_manager.AsyncManager, 'emit', new=AsyncMock() + async_manager.AsyncManager, "emit", new=AsyncMock() ) as super_emit: _run( self.pm._handle_emit( { - 'event': 'foo', - 'data': 'bar', - 'namespace': '/baz', - 'callback': ('sid', '/baz', 123), - 'host_id': self.pm.host_id, + "event": "foo", + "data": "bar", + "namespace": "/baz", + "callback": ("sid", "/baz", 123), + "host_id": self.pm.host_id, } ) ) assert super_emit.mock.call_count == 1 - assert super_emit.mock.call_args[0] == (self.pm, 'foo', 'bar') - assert super_emit.mock.call_args[1]['namespace'] == '/baz' - assert super_emit.mock.call_args[1]['room'] is None - assert super_emit.mock.call_args[1]['skip_sid'] is None + assert super_emit.mock.call_args[0] == (self.pm, "foo", "bar") + assert super_emit.mock.call_args[1]["namespace"] == "/baz" + assert super_emit.mock.call_args[1]["room"] is None + assert super_emit.mock.call_args[1]["skip_sid"] is None assert isinstance( - super_emit.mock.call_args[1]['callback'], functools.partial + super_emit.mock.call_args[1]["callback"], functools.partial ) - _run(super_emit.mock.call_args[1]['callback']('one', 2, 'three')) + _run(super_emit.mock.call_args[1]["callback"]("one", 2, "three")) self.pm._publish.mock.assert_not_called() def test_handle_callback(self): host_id = self.pm.host_id - with mock.patch.object( - self.pm, 'trigger_callback', new=AsyncMock() - ) as trigger: + with mock.patch.object(self.pm, "trigger_callback", new=AsyncMock()) as trigger: _run( self.pm._handle_callback( { - 'method': 'callback', - 'host_id': host_id, - 'sid': 'sid', - 'namespace': '/', - 'id': 123, - 'args': ('one', 2), + "method": "callback", + "host_id": host_id, + "sid": "sid", + "namespace": "/", + "id": 123, + "args": ("one", 2), } ) ) - trigger.mock.assert_called_once_with('sid', 123, ('one', 2)) + trigger.mock.assert_called_once_with("sid", 123, ("one", 2)) def test_handle_callback_bad_host_id(self): - with mock.patch.object( - self.pm, 'trigger_callback', new=AsyncMock() - ) as trigger: + with mock.patch.object(self.pm, "trigger_callback", new=AsyncMock()) as trigger: _run( self.pm._handle_callback( { - 'method': 'callback', - 'host_id': 'bad', - 'sid': 'sid', - 'namespace': '/', - 'id': 123, - 'args': ('one', 2), + "method": "callback", + "host_id": "bad", + "sid": "sid", + "namespace": "/", + "id": 123, + "args": ("one", 2), } ) ) @@ -388,122 +393,124 @@ class TestAsyncPubSubManager(unittest.TestCase): def test_handle_callback_missing_args(self): host_id = self.pm.host_id - with mock.patch.object( - self.pm, 'trigger_callback', new=AsyncMock() - ) as trigger: + with mock.patch.object(self.pm, "trigger_callback", new=AsyncMock()) as trigger: _run( self.pm._handle_callback( { - 'method': 'callback', - 'host_id': host_id, - 'sid': 'sid', - 'namespace': '/', - 'id': 123, + "method": "callback", + "host_id": host_id, + "sid": "sid", + "namespace": "/", + "id": 123, } ) ) _run( self.pm._handle_callback( { - 'method': 'callback', - 'host_id': host_id, - 'sid': 'sid', - 'namespace': '/', + "method": "callback", + "host_id": host_id, + "sid": "sid", + "namespace": "/", } ) ) _run( self.pm._handle_callback( - {'method': 'callback', 'host_id': host_id, 'sid': 'sid'} - ) - ) - _run( - self.pm._handle_callback( - {'method': 'callback', 'host_id': host_id} + {"method": "callback", "host_id": host_id, "sid": "sid"} ) ) + _run(self.pm._handle_callback({"method": "callback", "host_id": host_id})) assert trigger.mock.call_count == 0 def test_handle_disconnect(self): _run( self.pm._handle_disconnect( - {'method': 'disconnect', 'sid': '123', 'namespace': '/foo'} + {"method": "disconnect", "sid": "123", "namespace": "/foo"} ) ) self.pm.server.disconnect.mock.assert_called_once_with( - sid='123', namespace='/foo', ignore_queue=True + sid="123", namespace="/foo", ignore_queue=True ) def test_handle_enter_room(self): - sid = _run(self.pm.connect('123', '/')) + sid = _run(self.pm.connect("123", "/")) with mock.patch.object( - async_manager.AsyncManager, 'enter_room', new=AsyncMock() + async_manager.AsyncManager, "enter_room", new=AsyncMock() ) as super_enter_room: _run( self.pm._handle_enter_room( - {'method': 'enter_room', 'sid': sid, 'namespace': '/', - 'room': 'foo'} + { + "method": "enter_room", + "sid": sid, + "namespace": "/", + "room": "foo", + } ) ) _run( self.pm._handle_enter_room( - {'method': 'enter_room', 'sid': '456', 'namespace': '/', - 'room': 'foo'} + { + "method": "enter_room", + "sid": "456", + "namespace": "/", + "room": "foo", + } ) ) - super_enter_room.mock.assert_called_once_with( - self.pm, sid, '/', 'foo' - ) + super_enter_room.mock.assert_called_once_with(self.pm, sid, "/", "foo") def test_handle_leave_room(self): - sid = _run(self.pm.connect('123', '/')) + sid = _run(self.pm.connect("123", "/")) with mock.patch.object( - async_manager.AsyncManager, 'leave_room', new=AsyncMock() + async_manager.AsyncManager, "leave_room", new=AsyncMock() ) as super_leave_room: _run( self.pm._handle_leave_room( - {'method': 'leave_room', 'sid': sid, 'namespace': '/', - 'room': 'foo'} + { + "method": "leave_room", + "sid": sid, + "namespace": "/", + "room": "foo", + } ) ) _run( self.pm._handle_leave_room( - {'method': 'leave_room', 'sid': '456', 'namespace': '/', - 'room': 'foo'} + { + "method": "leave_room", + "sid": "456", + "namespace": "/", + "room": "foo", + } ) ) - super_leave_room.mock.assert_called_once_with( - self.pm, sid, '/', 'foo' - ) + super_leave_room.mock.assert_called_once_with(self.pm, sid, "/", "foo") def test_handle_close_room(self): with mock.patch.object( - async_manager.AsyncManager, 'close_room', new=AsyncMock() + async_manager.AsyncManager, "close_room", new=AsyncMock() ) as super_close_room: - _run( - self.pm._handle_close_room( - {'method': 'close_room', 'room': 'foo'} - ) - ) + _run(self.pm._handle_close_room({"method": "close_room", "room": "foo"})) super_close_room.mock.assert_called_once_with( - self.pm, room='foo', namespace=None + self.pm, room="foo", namespace=None ) def test_handle_close_room_with_namespace(self): with mock.patch.object( - async_manager.AsyncManager, 'close_room', new=AsyncMock() + async_manager.AsyncManager, "close_room", new=AsyncMock() ) as super_close_room: _run( self.pm._handle_close_room( { - 'method': 'close_room', - 'room': 'foo', - 'namespace': '/bar', + "method": "close_room", + "room": "foo", + "namespace": "/bar", } ) ) super_close_room.mock.assert_called_once_with( - self.pm, room='foo', namespace='/bar' + self.pm, room="foo", namespace="/bar" ) def test_background_thread(self): @@ -518,73 +525,101 @@ class TestAsyncPubSubManager(unittest.TestCase): async def messages(): import pickle - yield {'method': 'emit', 'value': 'foo', 'host_id': 'x'} - yield {'missing': 'method', 'host_id': 'x'} + yield {"method": "emit", "value": "foo", "host_id": "x"} + yield {"missing": "method", "host_id": "x"} yield '{"method": "callback", "value": "bar", "host_id": "x"}' - yield {'method': 'disconnect', 'sid': '123', 'namespace': '/foo', - 'host_id': 'x'} - yield {'method': 'bogus', 'host_id': 'x'} - yield pickle.dumps({'method': 'close_room', 'value': 'baz', - 'host_id': 'x'}) - yield {'method': 'enter_room', 'sid': '123', 'namespace': '/foo', - 'room': 'room', 'host_id': 'x'} - yield {'method': 'leave_room', 'sid': '123', 'namespace': '/foo', - 'room': 'room', 'host_id': 'x'} - yield 'bad json' - yield b'bad pickled' + yield { + "method": "disconnect", + "sid": "123", + "namespace": "/foo", + "host_id": "x", + } + yield {"method": "bogus", "host_id": "x"} + yield pickle.dumps({"method": "close_room", "value": "baz", "host_id": "x"}) + yield { + "method": "enter_room", + "sid": "123", + "namespace": "/foo", + "room": "room", + "host_id": "x", + } + yield { + "method": "leave_room", + "sid": "123", + "namespace": "/foo", + "room": "room", + "host_id": "x", + } + yield "bad json" + yield b"bad pickled" # these should not publish anything on the queue, as they come from # the same host - yield {'method': 'emit', 'value': 'foo', 'host_id': host_id} - yield {'method': 'callback', 'value': 'bar', 'host_id': host_id} - yield {'method': 'disconnect', 'sid': '123', 'namespace': '/foo', - 'host_id': host_id} - yield pickle.dumps({'method': 'close_room', 'value': 'baz', - 'host_id': host_id}) + yield {"method": "emit", "value": "foo", "host_id": host_id} + yield {"method": "callback", "value": "bar", "host_id": host_id} + yield { + "method": "disconnect", + "sid": "123", + "namespace": "/foo", + "host_id": host_id, + } + yield pickle.dumps( + {"method": "close_room", "value": "baz", "host_id": host_id} + ) raise asyncio.CancelledError() # force the thread to exit self.pm._listen = messages _run(self.pm._thread()) self.pm._handle_emit.mock.assert_called_once_with( - {'method': 'emit', 'value': 'foo', 'host_id': 'x'} + {"method": "emit", "value": "foo", "host_id": "x"} ) self.pm._handle_callback.mock.assert_any_call( - {'method': 'callback', 'value': 'bar', 'host_id': 'x'} + {"method": "callback", "value": "bar", "host_id": "x"} ) self.pm._handle_callback.mock.assert_any_call( - {'method': 'callback', 'value': 'bar', 'host_id': host_id} + {"method": "callback", "value": "bar", "host_id": host_id} ) self.pm._handle_disconnect.mock.assert_called_once_with( - {'method': 'disconnect', 'sid': '123', 'namespace': '/foo', - 'host_id': 'x'} + {"method": "disconnect", "sid": "123", "namespace": "/foo", "host_id": "x"} ) self.pm._handle_enter_room.mock.assert_called_once_with( - {'method': 'enter_room', 'sid': '123', 'namespace': '/foo', - 'room': 'room', 'host_id': 'x'} + { + "method": "enter_room", + "sid": "123", + "namespace": "/foo", + "room": "room", + "host_id": "x", + } ) self.pm._handle_leave_room.mock.assert_called_once_with( - {'method': 'leave_room', 'sid': '123', 'namespace': '/foo', - 'room': 'room', 'host_id': 'x'} + { + "method": "leave_room", + "sid": "123", + "namespace": "/foo", + "room": "room", + "host_id": "x", + } ) self.pm._handle_close_room.mock.assert_called_once_with( - {'method': 'close_room', 'value': 'baz', 'host_id': 'x'} + {"method": "close_room", "value": "baz", "host_id": "x"} ) def test_background_thread_exception(self): - self.pm._handle_emit = AsyncMock(side_effect=[ValueError(), - asyncio.CancelledError]) + self.pm._handle_emit = AsyncMock( + side_effect=[ValueError(), asyncio.CancelledError] + ) async def messages(): - yield {'method': 'emit', 'value': 'foo', 'host_id': 'x'} - yield {'method': 'emit', 'value': 'bar', 'host_id': 'x'} + yield {"method": "emit", "value": "foo", "host_id": "x"} + yield {"method": "emit", "value": "bar", "host_id": "x"} self.pm._listen = messages _run(self.pm._thread()) self.pm._handle_emit.mock.assert_any_call( - {'method': 'emit', 'value': 'foo', 'host_id': 'x'} + {"method": "emit", "value": "foo", "host_id": "x"} ) self.pm._handle_emit.mock.assert_called_with( - {'method': 'emit', 'value': 'bar', 'host_id': 'x'} + {"method": "emit", "value": "bar", "host_id": "x"} ) diff --git a/tests/async/test_server.py b/tests/async/test_server.py index 2f84b5f..1522c65 100644 --- a/tests/async/test_server.py +++ b/tests/async/test_server.py @@ -16,10 +16,14 @@ from socketio import packet from .helpers import AsyncMock, _run -@unittest.skipIf(sys.version_info < (3, 5), 'only for Python 3.5+') -@mock.patch('socketio.server.engineio.AsyncServer', **{ - 'return_value.generate_id.side_effect': [str(i) for i in range(1, 10)], - 'return_value.send_packet': AsyncMock()}) +@unittest.skipIf(sys.version_info < (3, 5), "only for Python 3.5+") +@mock.patch( + "socketio.server.engineio.AsyncServer", + **{ + "return_value.generate_id.side_effect": [str(i) for i in range(1, 10)], + "return_value.send_packet": AsyncMock(), + }, +) class TestAsyncServer(unittest.TestCase): def tearDown(self): # restore JSON encoder, in case a test changed it @@ -38,78 +42,76 @@ class TestAsyncServer(unittest.TestCase): def test_create(self, eio): eio.return_value.handle_request = AsyncMock() mgr = self._get_mock_manager() - s = async_server.AsyncServer( - client_manager=mgr, async_handlers=True, foo='bar' - ) + s = async_server.AsyncServer(client_manager=mgr, async_handlers=True, foo="bar") _run(s.handle_request({})) _run(s.handle_request({})) - eio.assert_called_once_with(**{'foo': 'bar', 'async_handlers': False}) + eio.assert_called_once_with(**{"foo": "bar", "async_handlers": False}) assert s.manager == mgr assert s.eio.on.call_count == 3 assert s.async_handlers def test_attach(self, eio): s = async_server.AsyncServer() - s.attach('app', 'path') - eio.return_value.attach.assert_called_once_with('app', 'path') + s.attach("app", "path") + eio.return_value.attach.assert_called_once_with("app", "path") def test_on_event(self, eio): s = async_server.AsyncServer() - @s.on('connect') + @s.on("connect") def foo(): pass def bar(): pass - s.on('disconnect', bar) - s.on('disconnect', bar, namespace='/foo') + s.on("disconnect", bar) + s.on("disconnect", bar, namespace="/foo") - assert s.handlers['/']['connect'] == foo - assert s.handlers['/']['disconnect'] == bar - assert s.handlers['/foo']['disconnect'] == bar + assert s.handlers["/"]["connect"] == foo + assert s.handlers["/"]["disconnect"] == bar + assert s.handlers["/foo"]["disconnect"] == bar def test_emit(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) _run( s.emit( - 'my event', - {'foo': 'bar'}, - to='room', - skip_sid='123', - namespace='/foo', - callback='cb', + "my event", + {"foo": "bar"}, + to="room", + skip_sid="123", + namespace="/foo", + callback="cb", ) ) s.manager.emit.mock.assert_called_once_with( - 'my event', - {'foo': 'bar'}, - '/foo', - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + "/foo", + room="room", + skip_sid="123", + callback="cb", ignore_queue=False, ) _run( s.emit( - 'my event', - {'foo': 'bar'}, - room='room', - skip_sid='123', - namespace='/foo', - callback='cb', + "my event", + {"foo": "bar"}, + room="room", + skip_sid="123", + namespace="/foo", + callback="cb", ignore_queue=True, ) ) s.manager.emit.mock.assert_called_with( - 'my event', - {'foo': 'bar'}, - '/foo', - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + "/foo", + room="room", + skip_sid="123", + callback="cb", ignore_queue=True, ) @@ -118,39 +120,39 @@ class TestAsyncServer(unittest.TestCase): s = async_server.AsyncServer(client_manager=mgr) _run( s.emit( - 'my event', - {'foo': 'bar'}, - to='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + to="room", + skip_sid="123", + callback="cb", ) ) s.manager.emit.mock.assert_called_once_with( - 'my event', - {'foo': 'bar'}, - '/', - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + "/", + room="room", + skip_sid="123", + callback="cb", ignore_queue=False, ) _run( s.emit( - 'my event', - {'foo': 'bar'}, - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + room="room", + skip_sid="123", + callback="cb", ignore_queue=True, ) ) s.manager.emit.mock.assert_called_with( - 'my event', - {'foo': 'bar'}, - '/', - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + "/", + room="room", + skip_sid="123", + callback="cb", ignore_queue=True, ) @@ -159,39 +161,39 @@ class TestAsyncServer(unittest.TestCase): s = async_server.AsyncServer(client_manager=mgr) _run( s.send( - 'foo', - to='room', - skip_sid='123', - namespace='/foo', - callback='cb', + "foo", + to="room", + skip_sid="123", + namespace="/foo", + callback="cb", ) ) s.manager.emit.mock.assert_called_once_with( - 'message', - 'foo', - '/foo', - room='room', - skip_sid='123', - callback='cb', + "message", + "foo", + "/foo", + room="room", + skip_sid="123", + callback="cb", ignore_queue=False, ) _run( s.send( - 'foo', - room='room', - skip_sid='123', - namespace='/foo', - callback='cb', + "foo", + room="room", + skip_sid="123", + namespace="/foo", + callback="cb", ignore_queue=True, ) ) s.manager.emit.mock.assert_called_with( - 'message', - 'foo', - '/foo', - room='room', - skip_sid='123', - callback='cb', + "message", + "foo", + "/foo", + room="room", + skip_sid="123", + callback="cb", ignore_queue=True, ) @@ -200,11 +202,11 @@ class TestAsyncServer(unittest.TestCase): s = async_server.AsyncServer(client_manager=mgr) async def fake_event_wait(): - s.manager.emit.mock.call_args_list[0][1]['callback']('foo', 321) + s.manager.emit.mock.call_args_list[0][1]["callback"]("foo", 321) return True s.eio.create_event.return_value.wait = fake_event_wait - assert _run(s.call('foo', sid='123')) == ('foo', 321) + assert _run(s.call("foo", sid="123")) == ("foo", 321) def test_call_with_timeout(self, eio): mgr = self._get_mock_manager() @@ -215,118 +217,115 @@ class TestAsyncServer(unittest.TestCase): s.eio.create_event.return_value.wait = fake_event_wait with pytest.raises(exceptions.TimeoutError): - _run(s.call('foo', sid='123', timeout=0.01)) + _run(s.call("foo", sid="123", timeout=0.01)) def test_call_with_broadcast(self, eio): s = async_server.AsyncServer() with pytest.raises(ValueError): - _run(s.call('foo')) + _run(s.call("foo")) def test_call_without_async_handlers(self, eio): mgr = self._get_mock_manager() - s = async_server.AsyncServer( - client_manager=mgr, async_handlers=False - ) + s = async_server.AsyncServer(client_manager=mgr, async_handlers=False) with pytest.raises(RuntimeError): - _run(s.call('foo', sid='123', timeout=12)) + _run(s.call("foo", sid="123", timeout=12)) def test_enter_room(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - _run(s.enter_room('123', 'room', namespace='/foo')) - s.manager.enter_room.mock.assert_called_once_with('123', '/foo', - 'room') + _run(s.enter_room("123", "room", namespace="/foo")) + s.manager.enter_room.mock.assert_called_once_with("123", "/foo", "room") def test_enter_room_default_namespace(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - _run(s.enter_room('123', 'room')) - s.manager.enter_room.mock.assert_called_once_with('123', '/', 'room') + _run(s.enter_room("123", "room")) + s.manager.enter_room.mock.assert_called_once_with("123", "/", "room") def test_leave_room(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - _run(s.leave_room('123', 'room', namespace='/foo')) - s.manager.leave_room.mock.assert_called_once_with('123', '/foo', - 'room') + _run(s.leave_room("123", "room", namespace="/foo")) + s.manager.leave_room.mock.assert_called_once_with("123", "/foo", "room") def test_leave_room_default_namespace(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - _run(s.leave_room('123', 'room')) - s.manager.leave_room.mock.assert_called_once_with('123', '/', 'room') + _run(s.leave_room("123", "room")) + s.manager.leave_room.mock.assert_called_once_with("123", "/", "room") def test_close_room(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - _run(s.close_room('room', namespace='/foo')) - s.manager.close_room.mock.assert_called_once_with('room', '/foo') + _run(s.close_room("room", namespace="/foo")) + s.manager.close_room.mock.assert_called_once_with("room", "/foo") def test_close_room_default_namespace(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - _run(s.close_room('room')) - s.manager.close_room.mock.assert_called_once_with('room', '/') + _run(s.close_room("room")) + s.manager.close_room.mock.assert_called_once_with("room", "/") def test_rooms(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - s.rooms('123', namespace='/foo') - s.manager.get_rooms.assert_called_once_with('123', '/foo') + s.rooms("123", namespace="/foo") + s.manager.get_rooms.assert_called_once_with("123", "/foo") def test_rooms_default_namespace(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - s.rooms('123') - s.manager.get_rooms.assert_called_once_with('123', '/') + s.rooms("123") + s.manager.get_rooms.assert_called_once_with("123", "/") def test_handle_request(self, eio): eio.return_value.handle_request = AsyncMock() s = async_server.AsyncServer() - _run(s.handle_request('environ')) - s.eio.handle_request.mock.assert_called_once_with('environ') + _run(s.handle_request("environ")) + s.eio.handle_request.mock.assert_called_once_with("environ") def test_send_packet(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - _run(s._send_packet('123', packet.Packet( - packet.EVENT, ['my event', 'my data'], namespace='/foo'))) - s.eio.send.mock.assert_called_once_with( - '123', '2/foo,["my event","my data"]' + _run( + s._send_packet( + "123", + packet.Packet(packet.EVENT, ["my event", "my data"], namespace="/foo"), + ) ) + s.eio.send.mock.assert_called_once_with("123", '2/foo,["my event","my data"]') def test_send_eio_packet(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - _run(s._send_eio_packet('123', eio_packet.Packet( - eio_packet.MESSAGE, 'hello'))) + _run(s._send_eio_packet("123", eio_packet.Packet(eio_packet.MESSAGE, "hello"))) assert s.eio.send_packet.mock.call_count == 1 - assert s.eio.send_packet.mock.call_args_list[0][0][0] == '123' + assert s.eio.send_packet.mock.call_args_list[0][0][0] == "123" pkt = s.eio.send_packet.mock.call_args_list[0][0][1] - assert pkt.encode() == '4hello' + assert pkt.encode() == "4hello" def test_transport(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - s.eio.transport = mock.MagicMock(return_value='polling') - _run(s._handle_eio_connect('foo', 'environ')) - assert s.transport('foo') == 'polling' - s.eio.transport.assert_called_once_with('foo') + s.eio.transport = mock.MagicMock(return_value="polling") + _run(s._handle_eio_connect("foo", "environ")) + assert s.transport("foo") == "polling" + s.eio.transport.assert_called_once_with("foo") def test_handle_connect(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() s.manager.initialize = mock.MagicMock() handler = mock.MagicMock() - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - assert s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - s.eio.send.mock.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + assert s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + s.eio.send.mock.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - _run(s._handle_eio_connect('456', 'environ')) - _run(s._handle_eio_message('456', '0')) + _run(s._handle_eio_connect("456", "environ")) + _run(s._handle_eio_message("456", "0")) assert s.manager.initialize.call_count == 1 def test_handle_connect_with_auth(self, eio): @@ -334,15 +333,15 @@ class TestAsyncServer(unittest.TestCase): s = async_server.AsyncServer() s.manager.initialize = mock.MagicMock() handler = mock.MagicMock() - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0{"token":"abc"}')) - assert s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ', {'token': 'abc'}) - s.eio.send.mock.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", '0{"token":"abc"}')) + assert s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ", {"token": "abc"}) + s.eio.send.mock.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - _run(s._handle_eio_connect('456', 'environ')) - _run(s._handle_eio_message('456', '0')) + _run(s._handle_eio_connect("456", "environ")) + _run(s._handle_eio_message("456", "0")) assert s.manager.initialize.call_count == 1 def test_handle_connect_with_auth_none(self, eio): @@ -350,15 +349,15 @@ class TestAsyncServer(unittest.TestCase): s = async_server.AsyncServer() s.manager.initialize = mock.MagicMock() handler = mock.MagicMock(side_effect=[TypeError, None, None]) - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - assert s.manager.is_connected('1', '/') - handler.assert_called_with('1', 'environ', None) - s.eio.send.mock.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + assert s.manager.is_connected("1", "/") + handler.assert_called_with("1", "environ", None) + s.eio.send.mock.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - _run(s._handle_eio_connect('456', 'environ')) - _run(s._handle_eio_message('456', '0')) + _run(s._handle_eio_connect("456", "environ")) + _run(s._handle_eio_message("456", "0")) assert s.manager.initialize.call_count == 1 def test_handle_connect_async(self, eio): @@ -366,450 +365,450 @@ class TestAsyncServer(unittest.TestCase): s = async_server.AsyncServer() s.manager.initialize = mock.MagicMock() handler = AsyncMock() - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - assert s.manager.is_connected('1', '/') - handler.mock.assert_called_once_with('1', 'environ') - s.eio.send.mock.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + assert s.manager.is_connected("1", "/") + handler.mock.assert_called_once_with("1", "environ") + s.eio.send.mock.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - _run(s._handle_eio_connect('456', 'environ')) - _run(s._handle_eio_message('456', '0')) + _run(s._handle_eio_connect("456", "environ")) + _run(s._handle_eio_message("456", "0")) assert s.manager.initialize.call_count == 1 def test_handle_connect_with_default_implied_namespaces(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - _run(s._handle_eio_message('123', '0/foo,')) - assert s.manager.is_connected('1', '/') - assert not s.manager.is_connected('2', '/foo') + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + _run(s._handle_eio_message("123", "0/foo,")) + assert s.manager.is_connected("1", "/") + assert not s.manager.is_connected("2", "/foo") def test_handle_connect_with_implied_namespaces(self, eio): eio.return_value.send = AsyncMock() - s = async_server.AsyncServer(namespaces=['/foo']) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - _run(s._handle_eio_message('123', '0/foo,')) - assert not s.manager.is_connected('1', '/') - assert s.manager.is_connected('1', '/foo') + s = async_server.AsyncServer(namespaces=["/foo"]) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + _run(s._handle_eio_message("123", "0/foo,")) + assert not s.manager.is_connected("1", "/") + assert s.manager.is_connected("1", "/foo") def test_handle_connect_with_all_implied_namespaces(self, eio): eio.return_value.send = AsyncMock() - s = async_server.AsyncServer(namespaces='*') - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - _run(s._handle_eio_message('123', '0/foo,')) - assert s.manager.is_connected('1', '/') - assert s.manager.is_connected('2', '/foo') + s = async_server.AsyncServer(namespaces="*") + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + _run(s._handle_eio_message("123", "0/foo,")) + assert s.manager.is_connected("1", "/") + assert s.manager.is_connected("2", "/foo") def test_handle_connect_namespace(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() handler = mock.MagicMock() - s.on('connect', handler, namespace='/foo') - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - assert s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') - s.eio.send.mock.assert_called_once_with('123', '0/foo,{"sid":"1"}') + s.on("connect", handler, namespace="/foo") + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + assert s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") + s.eio.send.mock.assert_called_once_with("123", '0/foo,{"sid":"1"}') def test_handle_connect_always_connect(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(always_connect=True) s.manager.initialize = mock.MagicMock() handler = mock.MagicMock() - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - assert s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - s.eio.send.mock.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + assert s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + s.eio.send.mock.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - _run(s._handle_eio_connect('456', 'environ')) - _run(s._handle_eio_message('456', '0')) + _run(s._handle_eio_connect("456", "environ")) + _run(s._handle_eio_message("456", "0")) assert s.manager.initialize.call_count == 1 def test_handle_connect_rejected(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() handler = mock.MagicMock(return_value=False) - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - assert not s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + assert not s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") s.eio.send.mock.assert_called_once_with( - '123', '4{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '4{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_namespace_rejected(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() handler = mock.MagicMock(return_value=False) - s.on('connect', handler, namespace='/foo') - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - assert not s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') + s.on("connect", handler, namespace="/foo") + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + assert not s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") s.eio.send.mock.assert_any_call( - '123', '4/foo,{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '4/foo,{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_rejected_always_connect(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(always_connect=True) handler = mock.MagicMock(return_value=False) - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - assert not s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - s.eio.send.mock.assert_any_call('123', '0{"sid":"1"}') + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + assert not s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + s.eio.send.mock.assert_any_call("123", '0{"sid":"1"}') s.eio.send.mock.assert_any_call( - '123', '1{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '1{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_namespace_rejected_always_connect(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(always_connect=True) handler = mock.MagicMock(return_value=False) - s.on('connect', handler, namespace='/foo') - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - assert not s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') - s.eio.send.mock.assert_any_call('123', '0/foo,{"sid":"1"}') + s.on("connect", handler, namespace="/foo") + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + assert not s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") + s.eio.send.mock.assert_any_call("123", '0/foo,{"sid":"1"}') s.eio.send.mock.assert_any_call( - '123', '1/foo,{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '1/foo,{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_rejected_with_exception(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() handler = mock.MagicMock( - side_effect=exceptions.ConnectionRefusedError('fail_reason') + side_effect=exceptions.ConnectionRefusedError("fail_reason") ) - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - assert not s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - s.eio.send.mock.assert_called_once_with( - '123', '4{"message":"fail_reason"}') - assert s.environ == {'123': 'environ'} + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + assert not s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + s.eio.send.mock.assert_called_once_with("123", '4{"message":"fail_reason"}') + assert s.environ == {"123": "environ"} def test_handle_connect_rejected_with_empty_exception(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - handler = mock.MagicMock( - side_effect=exceptions.ConnectionRefusedError() - ) - s.on('connect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - assert not s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') + handler = mock.MagicMock(side_effect=exceptions.ConnectionRefusedError()) + s.on("connect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + assert not s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") s.eio.send.mock.assert_called_once_with( - '123', '4{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '4{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_namespace_rejected_with_exception(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() handler = mock.MagicMock( - side_effect=exceptions.ConnectionRefusedError( - 'fail_reason', 1, '2') + side_effect=exceptions.ConnectionRefusedError("fail_reason", 1, "2") ) - s.on('connect', handler, namespace='/foo') - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - assert not s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') + s.on("connect", handler, namespace="/foo") + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + assert not s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") s.eio.send.mock.assert_called_once_with( - '123', '4/foo,{"message":"fail_reason","data":[1,"2"]}') - assert s.environ == {'123': 'environ'} + "123", '4/foo,{"message":"fail_reason","data":[1,"2"]}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_namespace_rejected_with_empty_exception(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - handler = mock.MagicMock( - side_effect=exceptions.ConnectionRefusedError() - ) - s.on('connect', handler, namespace='/foo') - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - assert not s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') + handler = mock.MagicMock(side_effect=exceptions.ConnectionRefusedError()) + s.on("connect", handler, namespace="/foo") + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + assert not s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") s.eio.send.mock.assert_called_once_with( - '123', '4/foo,{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '4/foo,{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_disconnect(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() s.manager.disconnect = AsyncMock() handler = mock.MagicMock() - s.on('disconnect', handler) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - _run(s._handle_eio_disconnect('123')) - handler.assert_called_once_with('1') - s.manager.disconnect.mock.assert_called_once_with( - '1', '/', ignore_queue=True) + s.on("disconnect", handler) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + _run(s._handle_eio_disconnect("123")) + handler.assert_called_once_with("1") + s.manager.disconnect.mock.assert_called_once_with("1", "/", ignore_queue=True) assert s.environ == {} def test_handle_disconnect_namespace(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() handler = mock.MagicMock() - s.on('disconnect', handler) + s.on("disconnect", handler) handler_namespace = mock.MagicMock() - s.on('disconnect', handler_namespace, namespace='/foo') - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - _run(s._handle_eio_disconnect('123')) + s.on("disconnect", handler_namespace, namespace="/foo") + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + _run(s._handle_eio_disconnect("123")) handler.assert_not_called() - handler_namespace.assert_called_once_with('1') + handler_namespace.assert_called_once_with("1") assert s.environ == {} def test_handle_disconnect_only_namespace(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() handler = mock.MagicMock() - s.on('disconnect', handler) + s.on("disconnect", handler) handler_namespace = mock.MagicMock() - s.on('disconnect', handler_namespace, namespace='/foo') - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - _run(s._handle_eio_message('123', '1/foo,')) + s.on("disconnect", handler_namespace, namespace="/foo") + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + _run(s._handle_eio_message("123", "1/foo,")) assert handler.call_count == 0 - handler_namespace.assert_called_once_with('1') - assert s.environ == {'123': 'environ'} + handler_namespace.assert_called_once_with("1") + assert s.environ == {"123": "environ"} def test_handle_disconnect_unknown_client(self, eio): mgr = self._get_mock_manager() s = async_server.AsyncServer(client_manager=mgr) - _run(s._handle_eio_disconnect('123')) + _run(s._handle_eio_disconnect("123")) def test_handle_event(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - sid = _run(s.manager.connect('123', '/')) + sid = _run(s.manager.connect("123", "/")) handler = AsyncMock() catchall_handler = AsyncMock() - s.on('msg', handler) - s.on('*', catchall_handler) - _run(s._handle_eio_message('123', '2["msg","a","b"]')) - _run(s._handle_eio_message('123', '2["my message","a","b","c"]')) - handler.mock.assert_called_once_with(sid, 'a', 'b') - catchall_handler.mock.assert_called_once_with( - 'my message', sid, 'a', 'b', 'c') + s.on("msg", handler) + s.on("*", catchall_handler) + _run(s._handle_eio_message("123", '2["msg","a","b"]')) + _run(s._handle_eio_message("123", '2["my message","a","b","c"]')) + handler.mock.assert_called_once_with(sid, "a", "b") + catchall_handler.mock.assert_called_once_with("my message", sid, "a", "b", "c") def test_handle_event_with_namespace(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - sid = _run(s.manager.connect('123', '/foo')) + sid = _run(s.manager.connect("123", "/foo")) handler = mock.MagicMock() catchall_handler = mock.MagicMock() - s.on('msg', handler, namespace='/foo') - s.on('*', catchall_handler, namespace='/foo') - _run(s._handle_eio_message('123', '2/foo,["msg","a","b"]')) - _run(s._handle_eio_message('123', '2/foo,["my message","a","b","c"]')) - handler.assert_called_once_with(sid, 'a', 'b') - catchall_handler.assert_called_once_with( - 'my message', sid, 'a', 'b', 'c') + s.on("msg", handler, namespace="/foo") + s.on("*", catchall_handler, namespace="/foo") + _run(s._handle_eio_message("123", '2/foo,["msg","a","b"]')) + _run(s._handle_eio_message("123", '2/foo,["my message","a","b","c"]')) + handler.assert_called_once_with(sid, "a", "b") + catchall_handler.assert_called_once_with("my message", sid, "a", "b", "c") def test_handle_event_with_disconnected_namespace(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - _run(s.manager.connect('123', '/foo')) + _run(s.manager.connect("123", "/foo")) handler = mock.MagicMock() - s.on('my message', handler, namespace='/bar') - _run(s._handle_eio_message('123', '2/bar,["my message","a","b","c"]')) + s.on("my message", handler, namespace="/bar") + _run(s._handle_eio_message("123", '2/bar,["my message","a","b","c"]')) handler.assert_not_called() def test_handle_event_binary(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - sid = _run(s.manager.connect('123', '/')) + sid = _run(s.manager.connect("123", "/")) handler = mock.MagicMock() - s.on('my message', handler) + s.on("my message", handler) _run( s._handle_eio_message( - '123', + "123", '52-["my message","a",' '{"_placeholder":true,"num":1},' '{"_placeholder":true,"num":0}]', ) ) - _run(s._handle_eio_message('123', b'foo')) - _run(s._handle_eio_message('123', b'bar')) - handler.assert_called_once_with(sid, 'a', b'bar', b'foo') + _run(s._handle_eio_message("123", b"foo")) + _run(s._handle_eio_message("123", b"bar")) + handler.assert_called_once_with(sid, "a", b"bar", b"foo") def test_handle_event_binary_ack(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) s.manager.trigger_callback = AsyncMock() - sid = _run(s.manager.connect('123', '/')) + sid = _run(s.manager.connect("123", "/")) _run( s._handle_eio_message( - '123', + "123", '61-321["my message","a",' '{"_placeholder":true,"num":0}]', ) ) - _run(s._handle_eio_message('123', b'foo')) + _run(s._handle_eio_message("123", b"foo")) s.manager.trigger_callback.mock.assert_called_once_with( - sid, 321, ['my message', 'a', b'foo'] + sid, 321, ["my message", "a", b"foo"] ) def test_handle_event_with_ack(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - sid = _run(s.manager.connect('123', '/')) - handler = mock.MagicMock(return_value='foo') - s.on('my message', handler) - _run(s._handle_eio_message('123', '21000["my message","foo"]')) - handler.assert_called_once_with(sid, 'foo') - s.eio.send.mock.assert_called_once_with( - '123', '31000["foo"]' - ) + sid = _run(s.manager.connect("123", "/")) + handler = mock.MagicMock(return_value="foo") + s.on("my message", handler) + _run(s._handle_eio_message("123", '21000["my message","foo"]')) + handler.assert_called_once_with(sid, "foo") + s.eio.send.mock.assert_called_once_with("123", '31000["foo"]') def test_handle_unknown_event_with_ack(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - _run(s.manager.connect('123', '/')) - handler = mock.MagicMock(return_value='foo') - s.on('my message', handler) - _run(s._handle_eio_message('123', '21000["another message","foo"]')) + _run(s.manager.connect("123", "/")) + handler = mock.MagicMock(return_value="foo") + s.on("my message", handler) + _run(s._handle_eio_message("123", '21000["another message","foo"]')) s.eio.send.mock.assert_not_called() def test_handle_event_with_ack_none(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - sid = _run(s.manager.connect('123', '/')) + sid = _run(s.manager.connect("123", "/")) handler = mock.MagicMock(return_value=None) - s.on('my message', handler) - _run(s._handle_eio_message('123', '21000["my message","foo"]')) - handler.assert_called_once_with(sid, 'foo') - s.eio.send.mock.assert_called_once_with('123', '31000[]') + s.on("my message", handler) + _run(s._handle_eio_message("123", '21000["my message","foo"]')) + handler.assert_called_once_with(sid, "foo") + s.eio.send.mock.assert_called_once_with("123", "31000[]") def test_handle_event_with_ack_tuple(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - sid = _run(s.manager.connect('123', '/')) - handler = mock.MagicMock(return_value=(1, '2', True)) - s.on('my message', handler) - _run(s._handle_eio_message('123', '21000["my message","a","b","c"]')) - handler.assert_called_once_with(sid, 'a', 'b', 'c') - s.eio.send.mock.assert_called_once_with( - '123', '31000[1,"2",true]' - ) + sid = _run(s.manager.connect("123", "/")) + handler = mock.MagicMock(return_value=(1, "2", True)) + s.on("my message", handler) + _run(s._handle_eio_message("123", '21000["my message","a","b","c"]')) + handler.assert_called_once_with(sid, "a", "b", "c") + s.eio.send.mock.assert_called_once_with("123", '31000[1,"2",true]') def test_handle_event_with_ack_list(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - sid = _run(s.manager.connect('123', '/')) - handler = mock.MagicMock(return_value=[1, '2', True]) - s.on('my message', handler) - _run(s._handle_eio_message('123', '21000["my message","a","b","c"]')) - handler.assert_called_once_with(sid, 'a', 'b', 'c') - s.eio.send.mock.assert_called_once_with( - '123', '31000[[1,"2",true]]' - ) + sid = _run(s.manager.connect("123", "/")) + handler = mock.MagicMock(return_value=[1, "2", True]) + s.on("my message", handler) + _run(s._handle_eio_message("123", '21000["my message","a","b","c"]')) + handler.assert_called_once_with(sid, "a", "b", "c") + s.eio.send.mock.assert_called_once_with("123", '31000[[1,"2",true]]') def test_handle_event_with_ack_binary(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer(async_handlers=False) - sid = _run(s.manager.connect('123', '/')) - handler = mock.MagicMock(return_value=b'foo') - s.on('my message', handler) - _run(s._handle_eio_message('123', '21000["my message","foo"]')) - handler.assert_any_call(sid, 'foo') + sid = _run(s.manager.connect("123", "/")) + handler = mock.MagicMock(return_value=b"foo") + s.on("my message", handler) + _run(s._handle_eio_message("123", '21000["my message","foo"]')) + handler.assert_any_call(sid, "foo") def test_handle_error_packet(self, eio): s = async_server.AsyncServer() with pytest.raises(ValueError): - _run(s._handle_eio_message('123', '4')) + _run(s._handle_eio_message("123", "4")) def test_handle_invalid_packet(self, eio): s = async_server.AsyncServer() with pytest.raises(ValueError): - _run(s._handle_eio_message('123', '9')) + _run(s._handle_eio_message("123", "9")) def test_send_with_ack(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - s.handlers['/'] = {} - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) + s.handlers["/"] = {} + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) cb = mock.MagicMock() - id1 = s.manager._generate_ack_id('1', cb) - id2 = s.manager._generate_ack_id('1', cb) - _run(s._send_packet('123', packet.Packet( - packet.EVENT, ['my event', 'foo'], id=id1))) - _run(s._send_packet('123', packet.Packet( - packet.EVENT, ['my event', 'bar'], id=id2))) - _run(s._handle_eio_message('123', '31["foo",2]')) - cb.assert_called_once_with('foo', 2) + id1 = s.manager._generate_ack_id("1", cb) + id2 = s.manager._generate_ack_id("1", cb) + _run( + s._send_packet( + "123", packet.Packet(packet.EVENT, ["my event", "foo"], id=id1) + ) + ) + _run( + s._send_packet( + "123", packet.Packet(packet.EVENT, ["my event", "bar"], id=id2) + ) + ) + _run(s._handle_eio_message("123", '31["foo",2]')) + cb.assert_called_once_with("foo", 2) def test_send_with_ack_namespace(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - s.handlers['/foo'] = {} - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) + s.handlers["/foo"] = {} + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) cb = mock.MagicMock() - id = s.manager._generate_ack_id('1', cb) + id = s.manager._generate_ack_id("1", cb) _run( s._send_packet( - '123', packet.Packet(packet.EVENT, ['my event', 'foo'], - namespace='/foo', id=id) + "123", + packet.Packet( + packet.EVENT, ["my event", "foo"], namespace="/foo", id=id + ), ) ) - _run(s._handle_eio_message('123', '3/foo,1["foo",2]')) - cb.assert_called_once_with('foo', 2) + _run(s._handle_eio_message("123", '3/foo,1["foo",2]')) + cb.assert_called_once_with("foo", 2) def test_session(self, eio): fake_session = {} async def fake_get_session(eio_sid): - assert eio_sid == '123' + assert eio_sid == "123" return fake_session async def fake_save_session(eio_sid, session): global fake_session - assert eio_sid == '123' + assert eio_sid == "123" fake_session = session eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - s.handlers['/'] = {} - s.handlers['/ns'] = {} + s.handlers["/"] = {} + s.handlers["/ns"] = {} s.eio.get_session = fake_get_session s.eio.save_session = fake_save_session async def _test(): - await s._handle_eio_connect('123', 'environ') - await s._handle_eio_message('123', '0') - await s._handle_eio_message('123', '0/ns') - sid = s.manager.sid_from_eio_sid('123', '/') - sid2 = s.manager.sid_from_eio_sid('123', '/ns') - await s.save_session(sid, {'foo': 'bar'}) + await s._handle_eio_connect("123", "environ") + await s._handle_eio_message("123", "0") + await s._handle_eio_message("123", "0/ns") + sid = s.manager.sid_from_eio_sid("123", "/") + sid2 = s.manager.sid_from_eio_sid("123", "/ns") + await s.save_session(sid, {"foo": "bar"}) async with s.session(sid) as session: - assert session == {'foo': 'bar'} - session['foo'] = 'baz' - session['bar'] = 'foo' - assert await s.get_session(sid) == {'foo': 'baz', 'bar': 'foo'} - assert fake_session == {'/': {'foo': 'baz', 'bar': 'foo'}} - async with s.session(sid2, namespace='/ns') as session: + assert session == {"foo": "bar"} + session["foo"] = "baz" + session["bar"] = "foo" + assert await s.get_session(sid) == {"foo": "baz", "bar": "foo"} + assert fake_session == {"/": {"foo": "baz", "bar": "foo"}} + async with s.session(sid2, namespace="/ns") as session: assert session == {} - session['a'] = 'b' - assert await s.get_session(sid2, namespace='/ns') == {'a': 'b'} + session["a"] = "b" + assert await s.get_session(sid2, namespace="/ns") == {"a": "b"} assert fake_session == { - '/': {'foo': 'baz', 'bar': 'foo'}, - '/ns': {'a': 'b'}, + "/": {"foo": "baz", "bar": "foo"}, + "/ns": {"a": "b"}, } _run(_test()) @@ -818,56 +817,56 @@ class TestAsyncServer(unittest.TestCase): eio.return_value.send = AsyncMock() eio.return_value.disconnect = AsyncMock() s = async_server.AsyncServer() - s.handlers['/'] = {} - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - _run(s.disconnect('1')) - s.eio.send.mock.assert_any_call('123', '1') - assert not s.manager.is_connected('1', '/') + s.handlers["/"] = {} + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + _run(s.disconnect("1")) + s.eio.send.mock.assert_any_call("123", "1") + assert not s.manager.is_connected("1", "/") def test_disconnect_ignore_queue(self, eio): eio.return_value.send = AsyncMock() eio.return_value.disconnect = AsyncMock() s = async_server.AsyncServer() - s.handlers['/'] = {} - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - _run(s.disconnect('1', ignore_queue=True)) - s.eio.send.mock.assert_any_call('123', '1') - assert not s.manager.is_connected('1', '/') + s.handlers["/"] = {} + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + _run(s.disconnect("1", ignore_queue=True)) + s.eio.send.mock.assert_any_call("123", "1") + assert not s.manager.is_connected("1", "/") def test_disconnect_namespace(self, eio): eio.return_value.send = AsyncMock() eio.return_value.disconnect = AsyncMock() s = async_server.AsyncServer() - s.handlers['/foo'] = {} - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - _run(s.disconnect('1', namespace='/foo')) - s.eio.send.mock.assert_any_call('123', '1/foo,') - assert not s.manager.is_connected('1', '/foo') + s.handlers["/foo"] = {} + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + _run(s.disconnect("1", namespace="/foo")) + s.eio.send.mock.assert_any_call("123", "1/foo,") + assert not s.manager.is_connected("1", "/foo") def test_disconnect_twice(self, eio): eio.return_value.send = AsyncMock() eio.return_value.disconnect = AsyncMock() s = async_server.AsyncServer() - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0')) - _run(s.disconnect('1')) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0")) + _run(s.disconnect("1")) calls = s.eio.send.mock.call_count - assert not s.manager.is_connected('1', '/') - _run(s.disconnect('1')) + assert not s.manager.is_connected("1", "/") + _run(s.disconnect("1")) assert calls == s.eio.send.mock.call_count def test_disconnect_twice_namespace(self, eio): eio.return_value.send = AsyncMock() s = async_server.AsyncServer() - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - _run(s.disconnect('1', namespace='/foo')) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + _run(s.disconnect("1", namespace="/foo")) calls = s.eio.send.mock.call_count - assert not s.manager.is_connected('1', '/foo') - _run(s.disconnect('1', namespace='/foo')) + assert not s.manager.is_connected("1", "/foo") + _run(s.disconnect("1", namespace="/foo")) assert calls == s.eio.send.mock.call_count def test_namespace_handler(self, eio): @@ -876,33 +875,33 @@ class TestAsyncServer(unittest.TestCase): class MyNamespace(async_namespace.AsyncNamespace): def on_connect(self, sid, environ): - result['result'] = (sid, environ) + result["result"] = (sid, environ) async def on_disconnect(self, sid): - result['result'] = ('disconnect', sid) + result["result"] = ("disconnect", sid) async def on_foo(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) def on_bar(self, sid): - result['result'] = 'bar' + result["result"] = "bar" async def on_baz(self, sid, data1, data2): - result['result'] = (data1, data2) + result["result"] = (data1, data2) s = async_server.AsyncServer(async_handlers=False) - s.register_namespace(MyNamespace('/foo')) - _run(s._handle_eio_connect('123', 'environ')) - _run(s._handle_eio_message('123', '0/foo,')) - assert result['result'] == ('1', 'environ') - _run(s._handle_eio_message('123', '2/foo,["foo","a"]')) - assert result['result'] == ('1', 'a') - _run(s._handle_eio_message('123', '2/foo,["bar"]')) - assert result['result'] == 'bar' - _run(s._handle_eio_message('123', '2/foo,["baz","a","b"]')) - assert result['result'] == ('a', 'b') - _run(s.disconnect('1', '/foo')) - assert result['result'] == ('disconnect', '1') + s.register_namespace(MyNamespace("/foo")) + _run(s._handle_eio_connect("123", "environ")) + _run(s._handle_eio_message("123", "0/foo,")) + assert result["result"] == ("1", "environ") + _run(s._handle_eio_message("123", '2/foo,["foo","a"]')) + assert result["result"] == ("1", "a") + _run(s._handle_eio_message("123", '2/foo,["bar"]')) + assert result["result"] == "bar" + _run(s._handle_eio_message("123", '2/foo,["baz","a","b"]')) + assert result["result"] == ("a", "b") + _run(s.disconnect("1", "/foo")) + assert result["result"] == ("disconnect", "1") def test_bad_namespace_handler(self, eio): class Dummy(object): @@ -933,14 +932,12 @@ class TestAsyncServer(unittest.TestCase): s = async_server.AsyncServer(logger=True) assert s.logger.getEffectiveLevel() == logging.WARNING s.logger.setLevel(logging.NOTSET) - s = async_server.AsyncServer(logger='foo') - assert s.logger == 'foo' + s = async_server.AsyncServer(logger="foo") + assert s.logger == "foo" def test_engineio_logger(self, eio): - async_server.AsyncServer(engineio_logger='foo') - eio.assert_called_once_with( - **{'logger': 'foo', 'async_handlers': False} - ) + async_server.AsyncServer(engineio_logger="foo") + eio.assert_called_once_with(**{"logger": "foo", "async_handlers": False}) def test_custom_json(self, eio): # Warning: this test cannot run in parallel with other tests, as it @@ -949,39 +946,37 @@ class TestAsyncServer(unittest.TestCase): class CustomJSON(object): @staticmethod def dumps(*args, **kwargs): - return '*** encoded ***' + return "*** encoded ***" @staticmethod def loads(*args, **kwargs): - return '+++ decoded +++' + return "+++ decoded +++" async_server.AsyncServer(json=CustomJSON) - eio.assert_called_once_with( - **{'json': CustomJSON, 'async_handlers': False} - ) + eio.assert_called_once_with(**{"json": CustomJSON, "async_handlers": False}) pkt = packet.Packet( packet_type=packet.EVENT, - data={'foo': 'bar'}, + data={"foo": "bar"}, ) - assert pkt.encode() == '2*** encoded ***' + assert pkt.encode() == "2*** encoded ***" pkt2 = packet.Packet(encoded_packet=pkt.encode()) - assert pkt2.data == '+++ decoded +++' + assert pkt2.data == "+++ decoded +++" # restore the default JSON module packet.Packet.json = json def test_async_handlers(self, eio): s = async_server.AsyncServer(async_handlers=True) - _run(s.manager.connect('123', '/')) - _run(s._handle_eio_message('123', '2["my message","a","b","c"]')) + _run(s.manager.connect("123", "/")) + _run(s._handle_eio_message("123", '2["my message","a","b","c"]')) s.eio.start_background_task.assert_called_once_with( s._handle_event_internal, s, - '1', - '123', - ['my message', 'a', 'b', 'c'], - '/', + "1", + "123", + ["my message", "a", "b", "c"], + "/", None, ) @@ -993,10 +988,8 @@ class TestAsyncServer(unittest.TestCase): def test_start_background_task(self, eio): s = async_server.AsyncServer() - s.start_background_task('foo', 'bar', baz='baz') - s.eio.start_background_task.assert_called_once_with( - 'foo', 'bar', baz='baz' - ) + s.start_background_task("foo", "bar", baz="baz") + s.eio.start_background_task.assert_called_once_with("foo", "bar", baz="baz") def test_sleep(self, eio): eio.return_value.sleep = AsyncMock() diff --git a/tests/async/test_simple_client.py b/tests/async/test_simple_client.py index 08b2ea6..6003209 100644 --- a/tests/async/test_simple_client.py +++ b/tests/async/test_simple_client.py @@ -10,91 +10,115 @@ from .helpers import AsyncMock, _run class TestAsyncAsyncSimpleClient(unittest.TestCase): def test_constructor(self): - client = AsyncSimpleClient(1, '2', a='3', b=4) - assert client.client_args == (1, '2') - assert client.client_kwargs == {'a': '3', 'b': 4} + client = AsyncSimpleClient(1, "2", a="3", b=4) + assert client.client_args == (1, "2") + assert client.client_kwargs == {"a": "3", "b": 4} assert client.client is None assert client.input_buffer == [] assert not client.connected def test_connect(self): - client = AsyncSimpleClient(123, a='b') - with mock.patch('socketio.async_simple_client.AsyncClient') \ - as mock_client: + client = AsyncSimpleClient(123, a="b") + with mock.patch("socketio.async_simple_client.AsyncClient") as mock_client: mock_client.return_value.connect = AsyncMock() - _run(client.connect('url', headers='h', auth='a', transports='t', - namespace='n', socketio_path='s', - wait_timeout='w')) - mock_client.assert_called_once_with(123, a='b') + _run( + client.connect( + "url", + headers="h", + auth="a", + transports="t", + namespace="n", + socketio_path="s", + wait_timeout="w", + ) + ) + mock_client.assert_called_once_with(123, a="b") assert client.client == mock_client() mock_client().connect.mock.assert_called_once_with( - 'url', headers='h', auth='a', transports='t', - namespaces=['n'], socketio_path='s', wait_timeout='w') + "url", + headers="h", + auth="a", + transports="t", + namespaces=["n"], + socketio_path="s", + wait_timeout="w", + ) mock_client().event.call_count == 3 - mock_client().on.assert_called_once_with('*', namespace='n') - assert client.namespace == 'n' + mock_client().on.assert_called_once_with("*", namespace="n") + assert client.namespace == "n" assert not client.input_event.is_set() def test_connect_context_manager(self): async def _t(): - async with AsyncSimpleClient(123, a='b') as client: - with mock.patch('socketio.async_simple_client.AsyncClient') \ - as mock_client: + async with AsyncSimpleClient(123, a="b") as client: + with mock.patch( + "socketio.async_simple_client.AsyncClient" + ) as mock_client: mock_client.return_value.connect = AsyncMock() - await client.connect('url', headers='h', auth='a', - transports='t', namespace='n', - socketio_path='s', wait_timeout='w') - mock_client.assert_called_once_with(123, a='b') + await client.connect( + "url", + headers="h", + auth="a", + transports="t", + namespace="n", + socketio_path="s", + wait_timeout="w", + ) + mock_client.assert_called_once_with(123, a="b") assert client.client == mock_client() mock_client().connect.mock.assert_called_once_with( - 'url', headers='h', auth='a', transports='t', - namespaces=['n'], socketio_path='s', wait_timeout='w') + "url", + headers="h", + auth="a", + transports="t", + namespaces=["n"], + socketio_path="s", + wait_timeout="w", + ) mock_client().event.call_count == 3 - mock_client().on.assert_called_once_with( - '*', namespace='n') - assert client.namespace == 'n' + mock_client().on.assert_called_once_with("*", namespace="n") + assert client.namespace == "n" assert not client.input_event.is_set() _run(_t()) def test_connect_twice(self): - client = AsyncSimpleClient(123, a='b') + client = AsyncSimpleClient(123, a="b") client.client = mock.MagicMock() client.connected = True with pytest.raises(RuntimeError): - _run(client.connect('url')) + _run(client.connect("url")) def test_properties(self): client = AsyncSimpleClient() - client.client = mock.MagicMock(transport='websocket') - client.client.get_sid.return_value = 'sid' + client.client = mock.MagicMock(transport="websocket") + client.client.get_sid.return_value = "sid" client.connected_event.set() client.connected = True - assert client.sid == 'sid' - assert client.transport == 'websocket' + assert client.sid == "sid" + assert client.transport == "websocket" def test_emit(self): client = AsyncSimpleClient() client.client = mock.MagicMock() client.client.emit = AsyncMock() - client.namespace = '/ns' + client.namespace = "/ns" client.connected_event.set() client.connected = True - _run(client.emit('foo', 'bar')) - client.client.emit.mock.assert_called_once_with('foo', 'bar', - namespace='/ns') + _run(client.emit("foo", "bar")) + client.client.emit.mock.assert_called_once_with("foo", "bar", namespace="/ns") def test_emit_disconnected(self): client = AsyncSimpleClient() client.connected_event.set() client.connected = False with pytest.raises(DisconnectedError): - _run(client.emit('foo', 'bar')) + _run(client.emit("foo", "bar")) def test_emit_retries(self): client = AsyncSimpleClient() @@ -104,28 +128,29 @@ class TestAsyncAsyncSimpleClient(unittest.TestCase): client.client.emit = AsyncMock() client.client.emit.mock.side_effect = [SocketIOError(), None] - _run(client.emit('foo', 'bar')) - client.client.emit.mock.assert_called_with('foo', 'bar', namespace='/') + _run(client.emit("foo", "bar")) + client.client.emit.mock.assert_called_with("foo", "bar", namespace="/") def test_call(self): client = AsyncSimpleClient() client.client = mock.MagicMock() client.client.call = AsyncMock() - client.client.call.mock.return_value = 'result' - client.namespace = '/ns' + client.client.call.mock.return_value = "result" + client.namespace = "/ns" client.connected_event.set() client.connected = True - assert _run(client.call('foo', 'bar')) == 'result' + assert _run(client.call("foo", "bar")) == "result" client.client.call.mock.assert_called_once_with( - 'foo', 'bar', namespace='/ns', timeout=60) + "foo", "bar", namespace="/ns", timeout=60 + ) def test_call_disconnected(self): client = AsyncSimpleClient() client.connected_event.set() client.connected = False with pytest.raises(DisconnectedError): - _run(client.call('foo', 'bar')) + _run(client.call("foo", "bar")) def test_call_retries(self): client = AsyncSimpleClient() @@ -133,17 +158,18 @@ class TestAsyncAsyncSimpleClient(unittest.TestCase): client.connected = True client.client = mock.MagicMock() client.client.call = AsyncMock() - client.client.call.mock.side_effect = [SocketIOError(), 'result'] + client.client.call.mock.side_effect = [SocketIOError(), "result"] - assert _run(client.call('foo', 'bar')) == 'result' - client.client.call.mock.assert_called_with('foo', 'bar', namespace='/', - timeout=60) + assert _run(client.call("foo", "bar")) == "result" + client.client.call.mock.assert_called_with( + "foo", "bar", namespace="/", timeout=60 + ) def test_receive_with_input_buffer(self): client = AsyncSimpleClient() - client.input_buffer = ['foo', 'bar'] - assert _run(client.receive()) == 'foo' - assert _run(client.receive()) == 'bar' + client.input_buffer = ["foo", "bar"] + assert _run(client.receive()) == "foo" + assert _run(client.receive()) == "bar" def test_receive_without_input_buffer(self): client = AsyncSimpleClient() @@ -152,11 +178,11 @@ class TestAsyncAsyncSimpleClient(unittest.TestCase): client.input_event = mock.MagicMock() async def fake_wait(timeout=None): - client.input_buffer = ['foo'] + client.input_buffer = ["foo"] return True client.input_event.wait = fake_wait - assert _run(client.receive()) == 'foo' + assert _run(client.receive()) == "foo" def test_receive_with_timeout(self): client = AsyncSimpleClient() diff --git a/tests/asyncio_web_server.py b/tests/asyncio_web_server.py index 8b2046c..353c6af 100644 --- a/tests/asyncio_web_server.py +++ b/tests/asyncio_web_server.py @@ -13,16 +13,20 @@ class SocketIOWebServer: Note 1: This class is not production-ready and is intended for testing. Note 2: This class only supports the "asgi" async_mode. """ + def __init__(self, sio, on_shutdown=None): - if sio.async_mode != 'asgi': + if sio.async_mode != "asgi": raise ValueError('The async_mode must be "asgi"') async def http_app(scope, receive, send): - await send({'type': 'http.response.start', - 'status': 200, - 'headers': [('Content-Type', 'text/plain')]}) - await send({'type': 'http.response.body', - 'body': b'OK'}) + await send( + { + "type": "http.response.start", + "status": 200, + "headers": [("Content-Type", "text/plain")], + } + ) + await send({"type": "http.response.body", "body": b"OK"}) self.sio = sio self.app = socketio.ASGIApp(sio, http_app, on_shutdown=on_shutdown) @@ -43,9 +47,9 @@ class SocketIOWebServer: # wait for the server to start while True: try: - r = requests.get(f'http://localhost:{port}/') + r = requests.get(f"http://localhost:{port}/") r.raise_for_status() - if r.text == 'OK': + if r.text == "OK": break except: time.sleep(0.1) diff --git a/tests/common/test_admin.py b/tests/common/test_admin.py index c4e2ec8..a8eccb9 100644 --- a/tests/common/test_admin.py +++ b/tests/common/test_admin.py @@ -16,10 +16,11 @@ def with_instrumented_server(auth=False, **ikwargs): Admin UI project. The arguments passed to the decorator are passed directly to the ``instrument()`` method of the server. """ + def decorator(f): @wraps(f) def wrapped(self, *args, **kwargs): - sio = socketio.Server(async_mode='threading') + sio = socketio.Server(async_mode="threading") @sio.event def enter_room(sid, data): @@ -29,12 +30,12 @@ def with_instrumented_server(auth=False, **ikwargs): def emit(sid, event): sio.emit(event, skip_sid=sid) - @sio.event(namespace='/foo') + @sio.event(namespace="/foo") def connect(sid, environ, auth): pass - if 'server_stats_interval' not in ikwargs: - ikwargs['server_stats_interval'] = 0.25 + if "server_stats_interval" not in ikwargs: + ikwargs["server_stats_interval"] = 0.25 instrumented_server = sio.instrument(auth=auth, **ikwargs) server = SocketIOWebServer(sio) @@ -61,89 +62,96 @@ def with_instrumented_server(auth=False, **ikwargs): # logging.getLogger('socketio.client').setLevel(logging.NOTSET) return ret + return wrapped + return decorator def _custom_auth(auth): - return auth == {'foo': 'bar'} + return auth == {"foo": "bar"} class TestAdmin(unittest.TestCase): def setUp(self): - print('threads at start:', threading.enumerate()) + print("threads at start:", threading.enumerate()) self.thread_count = threading.active_count() def tearDown(self): - print('threads at end:', threading.enumerate()) + print("threads at end:", threading.enumerate()) assert self.thread_count == threading.active_count() def test_missing_auth(self): - sio = socketio.Server(async_mode='threading') + sio = socketio.Server(async_mode="threading") with pytest.raises(ValueError): sio.instrument() @with_instrumented_server(auth=False) def test_admin_connect_with_no_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) - @with_instrumented_server(auth={'foo': 'bar'}) + @with_instrumented_server(auth={"foo": "bar"}) def test_admin_connect_with_dict_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): admin_client.connect( - 'http://localhost:8900', namespace='/admin', - auth={'foo': 'baz'}) + "http://localhost:8900", namespace="/admin", auth={"foo": "baz"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect( - 'http://localhost:8900', namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") - @with_instrumented_server(auth=[{'foo': 'bar'}, - {'u': 'admin', 'p': 'secret'}]) + @with_instrumented_server(auth=[{"foo": "bar"}, {"u": "admin", "p": "secret"}]) def test_admin_connect_with_list_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'u': 'admin', 'p': 'secret'}) + admin_client.connect( + "http://localhost:8900", + namespace="/admin", + auth={"u": "admin", "p": "secret"}, + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin', auth={'foo': 'baz'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "baz"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") @with_instrumented_server(auth=_custom_auth) def test_admin_connect_with_function_auth(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin', - auth={'foo': 'bar'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "bar"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin', auth={'foo': 'baz'}) + admin_client.connect( + "http://localhost:8900", namespace="/admin", auth={"foo": "baz"} + ) with socketio.SimpleClient() as admin_client: with pytest.raises(ConnectionError): - admin_client.connect('http://localhost:8900', - namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") @with_instrumented_server() def test_admin_connect_only_admin(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") sid = admin_client.sid - expected = ['config', 'all_sockets', 'server_stats'] + expected = ["config", "all_sockets", "server_stats"] events = {} while expected: data = admin_client.receive(timeout=5) @@ -151,46 +159,45 @@ class TestAdmin(unittest.TestCase): events[data[0]] = data[1] expected.remove(data[0]) - assert 'supportedFeatures' in events['config'] - assert 'ALL_EVENTS' in events['config']['supportedFeatures'] - assert 'AGGREGATED_EVENTS' in events['config']['supportedFeatures'] - assert 'EMIT' in events['config']['supportedFeatures'] - assert len(events['all_sockets']) == 1 - assert events['all_sockets'][0]['id'] == sid - assert events['all_sockets'][0]['rooms'] == [sid] - assert events['server_stats']['clientsCount'] == 1 - assert events['server_stats']['pollingClientsCount'] == 0 - assert len(events['server_stats']['namespaces']) == 3 - assert {'name': '/', 'socketsCount': 0} in \ - events['server_stats']['namespaces'] - assert {'name': '/foo', 'socketsCount': 0} in \ - events['server_stats']['namespaces'] - assert {'name': '/admin', 'socketsCount': 1} in \ - events['server_stats']['namespaces'] + assert "supportedFeatures" in events["config"] + assert "ALL_EVENTS" in events["config"]["supportedFeatures"] + assert "AGGREGATED_EVENTS" in events["config"]["supportedFeatures"] + assert "EMIT" in events["config"]["supportedFeatures"] + assert len(events["all_sockets"]) == 1 + assert events["all_sockets"][0]["id"] == sid + assert events["all_sockets"][0]["rooms"] == [sid] + assert events["server_stats"]["clientsCount"] == 1 + assert events["server_stats"]["pollingClientsCount"] == 0 + assert len(events["server_stats"]["namespaces"]) == 3 + assert {"name": "/", "socketsCount": 0} in events["server_stats"]["namespaces"] + assert {"name": "/foo", "socketsCount": 0} in events["server_stats"][ + "namespaces" + ] + assert {"name": "/admin", "socketsCount": 1} in events["server_stats"][ + "namespaces" + ] @with_instrumented_server() def test_admin_connect_with_others(self, isvr): - with socketio.SimpleClient() as client1, \ - socketio.SimpleClient() as client2, \ - socketio.SimpleClient() as client3, \ - socketio.SimpleClient() as admin_client: - client1.connect('http://localhost:8900') - client1.emit('enter_room', 'room') + with socketio.SimpleClient() as client1, socketio.SimpleClient() as client2, socketio.SimpleClient() as client3, socketio.SimpleClient() as admin_client: + client1.connect("http://localhost:8900") + client1.emit("enter_room", "room") sid1 = client1.sid saved_check_for_upgrade = isvr._check_for_upgrade isvr._check_for_upgrade = mock.MagicMock() - client2.connect('http://localhost:8900', namespace='/foo', - transports=['polling']) + client2.connect( + "http://localhost:8900", namespace="/foo", transports=["polling"] + ) sid2 = client2.sid isvr._check_for_upgrade = saved_check_for_upgrade - client3.connect('http://localhost:8900', namespace='/admin') + client3.connect("http://localhost:8900", namespace="/admin") sid3 = client3.sid - admin_client.connect('http://localhost:8900', namespace='/admin') + admin_client.connect("http://localhost:8900", namespace="/admin") sid = admin_client.sid - expected = ['config', 'all_sockets', 'server_stats'] + expected = ["config", "all_sockets", "server_stats"] events = {} while expected: data = admin_client.receive(timeout=5) @@ -198,36 +205,37 @@ class TestAdmin(unittest.TestCase): events[data[0]] = data[1] expected.remove(data[0]) - assert 'supportedFeatures' in events['config'] - assert 'ALL_EVENTS' in events['config']['supportedFeatures'] - assert 'AGGREGATED_EVENTS' in events['config']['supportedFeatures'] - assert 'EMIT' in events['config']['supportedFeatures'] - assert len(events['all_sockets']) == 4 - assert events['server_stats']['clientsCount'] == 4 - assert events['server_stats']['pollingClientsCount'] == 1 - assert len(events['server_stats']['namespaces']) == 3 - assert {'name': '/', 'socketsCount': 1} in \ - events['server_stats']['namespaces'] - assert {'name': '/foo', 'socketsCount': 1} in \ - events['server_stats']['namespaces'] - assert {'name': '/admin', 'socketsCount': 2} in \ - events['server_stats']['namespaces'] - - for socket in events['all_sockets']: - if socket['id'] == sid: - assert socket['rooms'] == [sid] - elif socket['id'] == sid1: - assert socket['rooms'] == [sid1, 'room'] - elif socket['id'] == sid2: - assert socket['rooms'] == [sid2] - elif socket['id'] == sid3: - assert socket['rooms'] == [sid3] - - @with_instrumented_server(mode='production', read_only=True) + assert "supportedFeatures" in events["config"] + assert "ALL_EVENTS" in events["config"]["supportedFeatures"] + assert "AGGREGATED_EVENTS" in events["config"]["supportedFeatures"] + assert "EMIT" in events["config"]["supportedFeatures"] + assert len(events["all_sockets"]) == 4 + assert events["server_stats"]["clientsCount"] == 4 + assert events["server_stats"]["pollingClientsCount"] == 1 + assert len(events["server_stats"]["namespaces"]) == 3 + assert {"name": "/", "socketsCount": 1} in events["server_stats"]["namespaces"] + assert {"name": "/foo", "socketsCount": 1} in events["server_stats"][ + "namespaces" + ] + assert {"name": "/admin", "socketsCount": 2} in events["server_stats"][ + "namespaces" + ] + + for socket in events["all_sockets"]: + if socket["id"] == sid: + assert socket["rooms"] == [sid] + elif socket["id"] == sid1: + assert socket["rooms"] == [sid1, "room"] + elif socket["id"] == sid2: + assert socket["rooms"] == [sid2] + elif socket["id"] == sid3: + assert socket["rooms"] == [sid3] + + @with_instrumented_server(mode="production", read_only=True) def test_admin_connect_production(self, isvr): with socketio.SimpleClient() as admin_client: - admin_client.connect('http://localhost:8900', namespace='/admin') - expected = ['config', 'server_stats'] + admin_client.connect("http://localhost:8900", namespace="/admin") + expected = ["config", "server_stats"] events = {} while expected: data = admin_client.receive(timeout=5) @@ -235,50 +243,49 @@ class TestAdmin(unittest.TestCase): events[data[0]] = data[1] expected.remove(data[0]) - assert 'supportedFeatures' in events['config'] - assert 'ALL_EVENTS' not in events['config']['supportedFeatures'] - assert 'AGGREGATED_EVENTS' in events['config']['supportedFeatures'] - assert 'EMIT' not in events['config']['supportedFeatures'] - assert events['server_stats']['clientsCount'] == 1 - assert events['server_stats']['pollingClientsCount'] == 0 - assert len(events['server_stats']['namespaces']) == 3 - assert {'name': '/', 'socketsCount': 0} in \ - events['server_stats']['namespaces'] - assert {'name': '/foo', 'socketsCount': 0} in \ - events['server_stats']['namespaces'] - assert {'name': '/admin', 'socketsCount': 1} in \ - events['server_stats']['namespaces'] + assert "supportedFeatures" in events["config"] + assert "ALL_EVENTS" not in events["config"]["supportedFeatures"] + assert "AGGREGATED_EVENTS" in events["config"]["supportedFeatures"] + assert "EMIT" not in events["config"]["supportedFeatures"] + assert events["server_stats"]["clientsCount"] == 1 + assert events["server_stats"]["pollingClientsCount"] == 0 + assert len(events["server_stats"]["namespaces"]) == 3 + assert {"name": "/", "socketsCount": 0} in events["server_stats"]["namespaces"] + assert {"name": "/foo", "socketsCount": 0} in events["server_stats"][ + "namespaces" + ] + assert {"name": "/admin", "socketsCount": 1} in events["server_stats"][ + "namespaces" + ] @with_instrumented_server() def test_admin_features(self, isvr): - with socketio.SimpleClient() as client1, \ - socketio.SimpleClient() as client2, \ - socketio.SimpleClient() as admin_client: - client1.connect('http://localhost:8900') - client2.connect('http://localhost:8900') - admin_client.connect('http://localhost:8900', namespace='/admin') + with socketio.SimpleClient() as client1, socketio.SimpleClient() as client2, socketio.SimpleClient() as admin_client: + client1.connect("http://localhost:8900") + client2.connect("http://localhost:8900") + admin_client.connect("http://localhost:8900", namespace="/admin") # emit from admin admin_client.emit( - 'emit', ('/', client1.sid, 'foo', {'bar': 'baz'}, 'extra')) + "emit", ("/", client1.sid, "foo", {"bar": "baz"}, "extra") + ) data = client1.receive(timeout=5) - assert data == ['foo', {'bar': 'baz'}, 'extra'] + assert data == ["foo", {"bar": "baz"}, "extra"] # emit from regular client - client1.emit('emit', 'foo') + client1.emit("emit", "foo") data = client2.receive(timeout=5) - assert data == ['foo'] + assert data == ["foo"] # join and leave - admin_client.emit('join', ('/', 'room', client1.sid)) - admin_client.emit( - 'emit', ('/', 'room', 'foo', {'bar': 'baz'})) + admin_client.emit("join", ("/", "room", client1.sid)) + admin_client.emit("emit", ("/", "room", "foo", {"bar": "baz"})) data = client1.receive(timeout=5) - assert data == ['foo', {'bar': 'baz'}] - admin_client.emit('leave', ('/', 'room')) + assert data == ["foo", {"bar": "baz"}] + admin_client.emit("leave", ("/", "room")) # disconnect - admin_client.emit('_disconnect', ('/', False, client1.sid)) + admin_client.emit("_disconnect", ("/", False, client1.sid)) for _ in range(10): if not client1.connected: break diff --git a/tests/common/test_client.py b/tests/common/test_client.py index 791cb43..de7f40a 100644 --- a/tests/common/test_client.py +++ b/tests/common/test_client.py @@ -21,7 +21,7 @@ class TestClient(unittest.TestCase): c = client.Client() assert not c.is_asyncio_based() - @mock.patch('socketio.client.Client._engineio_client_class') + @mock.patch("socketio.client.Client._engineio_client_class") def test_create(self, engineio_client_class): c = client.Client( reconnection=False, @@ -30,7 +30,7 @@ class TestClient(unittest.TestCase): reconnection_delay_max=10, randomization_factor=0.2, handle_sigint=False, - foo='bar', + foo="bar", ) assert not c.reconnection assert c.reconnection_attempts == 123 @@ -38,8 +38,7 @@ class TestClient(unittest.TestCase): assert c.reconnection_delay_max == 10 assert c.randomization_factor == 0.2 assert not c.handle_sigint - engineio_client_class().assert_called_once_with( - foo='bar', handle_sigint=False) + 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 @@ -56,7 +55,7 @@ class TestClient(unittest.TestCase): assert c.packet_class == packet.Packet def test_msgpack(self): - c = client.Client(serializer='msgpack') + c = client.Client(serializer="msgpack") assert c.packet_class == msgpack_packet.MsgPackPacket def test_custom_serializer(self): @@ -70,9 +69,9 @@ class TestClient(unittest.TestCase): client.Client() assert packet.Packet.json == json assert engineio_packet.Packet.json == json - client.Client(json='foo') - assert packet.Packet.json == 'foo' - assert engineio_packet.Packet.json == 'foo' + client.Client(json="foo") + assert packet.Packet.json == "foo" + assert engineio_packet.Packet.json == "foo" packet.Packet.json = json def test_logger(self): @@ -85,32 +84,33 @@ class TestClient(unittest.TestCase): c = client.Client(logger=True) assert c.logger.getEffectiveLevel() == logging.WARNING c.logger.setLevel(logging.NOTSET) - my_logger = logging.Logger('foo') + my_logger = logging.Logger("foo") c = client.Client(logger=my_logger) assert c.logger == my_logger - @mock.patch('socketio.client.Client._engineio_client_class') + @mock.patch("socketio.client.Client._engineio_client_class") def test_engineio_logger(self, engineio_client_class): - client.Client(engineio_logger='foo') + client.Client(engineio_logger="foo") engineio_client_class().assert_called_once_with( - handle_sigint=True, logger='foo') + handle_sigint=True, logger="foo" + ) def test_on_event(self): c = client.Client() - @c.on('connect') + @c.on("connect") def foo(): pass def bar(): pass - c.on('disconnect', bar) - c.on('disconnect', bar, namespace='/foo') + c.on("disconnect", bar) + c.on("disconnect", bar, namespace="/foo") - assert c.handlers['/']['connect'] == foo - assert c.handlers['/']['disconnect'] == bar - assert c.handlers['/foo']['disconnect'] == bar + assert c.handlers["/"]["connect"] == foo + assert c.handlers["/"]["disconnect"] == bar + assert c.handlers["/foo"]["disconnect"] == bar def test_event(self): c = client.Client() @@ -127,23 +127,23 @@ class TestClient(unittest.TestCase): def bar(): pass - @c.event(namespace='/foo') + @c.event(namespace="/foo") def disconnect(): pass - assert c.handlers['/']['connect'] == connect - assert c.handlers['/']['foo'] == foo - assert c.handlers['/']['bar'] == bar - assert c.handlers['/foo']['disconnect'] == disconnect + assert c.handlers["/"]["connect"] == connect + assert c.handlers["/"]["foo"] == foo + assert c.handlers["/"]["bar"] == bar + assert c.handlers["/foo"]["disconnect"] == disconnect def test_namespace_handler(self): class MyNamespace(namespace.ClientNamespace): pass c = client.Client() - n = MyNamespace('/foo') + n = MyNamespace("/foo") c.register_namespace(n) - assert c.namespace_handlers['/foo'] == n + assert c.namespace_handlers["/foo"] == n def test_namespace_handler_wrong_class(self): class MyNamespace(object): @@ -151,17 +151,17 @@ class TestClient(unittest.TestCase): pass c = client.Client() - n = MyNamespace('/foo') + n = MyNamespace("/foo") with pytest.raises(ValueError): c.register_namespace(n) - @unittest.skipIf(sys.version_info < (3, 0), 'only for Python 3') + @unittest.skipIf(sys.version_info < (3, 0), "only for Python 3") def test_namespace_handler_wrong_async(self): class MyNamespace(async_namespace.AsyncClientNamespace): pass c = client.Client() - n = MyNamespace('/foo') + n = MyNamespace("/foo") with pytest.raises(ValueError): c.register_namespace(n) @@ -169,129 +169,131 @@ class TestClient(unittest.TestCase): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( - 'url', - headers='headers', - auth='auth', - transports='transports', - namespaces=['/foo', '/', '/bar'], - socketio_path='path', + "url", + headers="headers", + auth="auth", + transports="transports", + namespaces=["/foo", "/", "/bar"], + socketio_path="path", wait=False, ) - assert c.connection_url == 'url' - assert c.connection_headers == 'headers' - assert c.connection_auth == 'auth' - assert c.connection_transports == 'transports' - assert c.connection_namespaces == ['/foo', '/', '/bar'] - assert c.socketio_path == 'path' + assert c.connection_url == "url" + assert c.connection_headers == "headers" + assert c.connection_auth == "auth" + assert c.connection_transports == "transports" + assert c.connection_namespaces == ["/foo", "/", "/bar"] + assert c.socketio_path == "path" c.eio.connect.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_functions(self): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( - lambda: 'url', - headers=lambda: 'headers', - auth='auth', - transports='transports', - namespaces=['/foo', '/', '/bar'], - socketio_path='path', + lambda: "url", + headers=lambda: "headers", + auth="auth", + transports="transports", + namespaces=["/foo", "/", "/bar"], + socketio_path="path", wait=False, ) c.eio.connect.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_one_namespace(self): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( - 'url', - headers='headers', - transports='transports', - namespaces='/foo', - socketio_path='path', + "url", + headers="headers", + transports="transports", + namespaces="/foo", + socketio_path="path", wait=False, ) - assert c.connection_url == 'url' - assert c.connection_headers == 'headers' - assert c.connection_transports == 'transports' - assert c.connection_namespaces == ['/foo'] - assert c.socketio_path == 'path' + assert c.connection_url == "url" + assert c.connection_headers == "headers" + assert c.connection_transports == "transports" + assert c.connection_namespaces == ["/foo"] + assert c.socketio_path == "path" c.eio.connect.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_default_namespaces(self): c = client.Client() c.eio.connect = mock.MagicMock() - c.on('foo', mock.MagicMock(), namespace='/foo') - c.on('bar', mock.MagicMock(), namespace='/') + c.on("foo", mock.MagicMock(), namespace="/foo") + c.on("bar", mock.MagicMock(), namespace="/") c.connect( - 'url', - headers='headers', - transports='transports', - socketio_path='path', + "url", + headers="headers", + transports="transports", + socketio_path="path", wait=False, ) - assert c.connection_url == 'url' - assert c.connection_headers == 'headers' - assert c.connection_transports == 'transports' - assert c.connection_namespaces == ['/foo', '/'] or \ - c.connection_namespaces == ['/', '/foo'] - assert c.socketio_path == 'path' + assert c.connection_url == "url" + assert c.connection_headers == "headers" + assert c.connection_transports == "transports" + assert c.connection_namespaces == ["/foo", "/"] or c.connection_namespaces == [ + "/", + "/foo", + ] + assert c.socketio_path == "path" c.eio.connect.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_no_namespaces(self): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( - 'url', - headers='headers', - transports='transports', - socketio_path='path', + "url", + headers="headers", + transports="transports", + socketio_path="path", wait=False, ) - assert c.connection_url == 'url' - assert c.connection_headers == 'headers' - assert c.connection_transports == 'transports' - assert c.connection_namespaces == ['/'] - assert c.socketio_path == 'path' + assert c.connection_url == "url" + assert c.connection_headers == "headers" + assert c.connection_transports == "transports" + assert c.connection_namespaces == ["/"] + assert c.socketio_path == "path" c.eio.connect.assert_called_once_with( - 'url', - headers='headers', - transports='transports', - engineio_path='path', + "url", + headers="headers", + transports="transports", + engineio_path="path", ) def test_connect_error(self): c = client.Client() c.eio.connect = mock.MagicMock( - side_effect=engineio_exceptions.ConnectionError('foo') + side_effect=engineio_exceptions.ConnectionError("foo") ) - c.on('foo', mock.MagicMock(), namespace='/foo') - c.on('bar', mock.MagicMock(), namespace='/') + c.on("foo", mock.MagicMock(), namespace="/foo") + c.on("bar", mock.MagicMock(), namespace="/") with pytest.raises(exceptions.ConnectionError): c.connect( - 'url', - headers='headers', - transports='transports', - socketio_path='path', + "url", + headers="headers", + transports="transports", + socketio_path="path", wait=False, ) @@ -299,12 +301,12 @@ class TestClient(unittest.TestCase): c = client.Client() c.eio.connect = mock.MagicMock() c.connect( - 'url', + "url", wait=False, ) with pytest.raises(exceptions.ConnectionError): c.connect( - 'url', + "url", wait=False, ) @@ -315,12 +317,12 @@ class TestClient(unittest.TestCase): def mock_connect(timeout): assert timeout == 0.01 - c.namespaces = {'/': '123'} + c.namespaces = {"/": "123"} return True c._connect_event.wait = mock_connect c.connect( - 'url', + "url", wait=True, wait_timeout=0.01, ) @@ -334,22 +336,22 @@ class TestClient(unittest.TestCase): def mock_connect(timeout): assert timeout == 0.01 if c.namespaces == {}: - c.namespaces = {'/bar': '123'} + c.namespaces = {"/bar": "123"} return True - elif c.namespaces == {'/bar': '123'}: - c.namespaces = {'/bar': '123', '/foo': '456'} + elif c.namespaces == {"/bar": "123"}: + c.namespaces = {"/bar": "123", "/foo": "456"} return True return False c._connect_event.wait = mock_connect c.connect( - 'url', - namespaces=['/foo', '/bar'], + "url", + namespaces=["/foo", "/bar"], wait=True, wait_timeout=0.01, ) assert c.connected is True - assert c.namespaces == {'/bar': '123', '/foo': '456'} + assert c.namespaces == {"/bar": "123", "/foo": "456"} def test_connect_timeout(self): c = client.Client() @@ -357,7 +359,7 @@ class TestClient(unittest.TestCase): c.disconnect = mock.MagicMock() with pytest.raises(exceptions.ConnectionError): c.connect( - 'url', + "url", wait=True, wait_timeout=0.01, ) @@ -377,7 +379,7 @@ class TestClient(unittest.TestCase): c.eio.wait = mock.MagicMock() c.sleep = mock.MagicMock() c._reconnect_task = mock.MagicMock() - states = ['disconnected'] + states = ["disconnected"] def fake_join(): c.eio.state = states.pop(0) @@ -392,7 +394,7 @@ class TestClient(unittest.TestCase): c.eio.wait = mock.MagicMock() c.sleep = mock.MagicMock() c._reconnect_task = mock.MagicMock() - states = ['connected', 'disconnected'] + states = ["connected", "disconnected"] def fake_join(): c.eio.state = states.pop(0) @@ -404,200 +406,195 @@ class TestClient(unittest.TestCase): def test_get_sid(self): c = client.Client() - c.namespaces = {'/': '1', '/foo': '2'} - assert c.get_sid() == '1' - assert c.get_sid('/') == '1' - assert c.get_sid('/foo') == '2' - assert c.get_sid('/bar') is None + c.namespaces = {"/": "1", "/foo": "2"} + assert c.get_sid() == "1" + assert c.get_sid("/") == "1" + assert c.get_sid("/foo") == "2" + assert c.get_sid("/bar") is None def test_emit_no_arguments(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() - c.emit('foo') + c.emit("foo") expected_packet = packet.Packet( - packet.EVENT, namespace='/', data=['foo'], id=None) + packet.EVENT, namespace="/", data=["foo"], id=None + ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_one_argument(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() - c.emit('foo', 'bar') + c.emit("foo", "bar") expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', 'bar'], + namespace="/", + data=["foo", "bar"], id=None, ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_one_argument_list(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() - c.emit('foo', ['bar', 'baz']) + c.emit("foo", ["bar", "baz"]) expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', ['bar', 'baz']], + namespace="/", + data=["foo", ["bar", "baz"]], id=None, ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_two_arguments(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() - c.emit('foo', ('bar', 'baz')) + c.emit("foo", ("bar", "baz")) expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', 'bar', 'baz'], + namespace="/", + data=["foo", "bar", "baz"], id=None, ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_namespace(self): c = client.Client() - c.namespaces = ['/foo'] + c.namespaces = ["/foo"] c._send_packet = mock.MagicMock() - c.emit('foo', namespace='/foo') + c.emit("foo", namespace="/foo") expected_packet = packet.Packet( - packet.EVENT, namespace='/foo', data=['foo'], id=None) + packet.EVENT, namespace="/foo", data=["foo"], id=None + ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_unknown_namespace(self): c = client.Client() - c.namespaces = ['/foo'] + c.namespaces = ["/foo"] with pytest.raises(exceptions.BadNamespaceError): - c.emit('foo', namespace='/bar') + c.emit("foo", namespace="/bar") def test_emit_with_callback(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() c._generate_ack_id = mock.MagicMock(return_value=123) - c.emit('foo', callback='cb') + c.emit("foo", callback="cb") expected_packet = packet.Packet( - packet.EVENT, namespace='/', data=['foo'], id=123) + packet.EVENT, namespace="/", data=["foo"], id=123 + ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) - c._generate_ack_id.assert_called_once_with('/', 'cb') + c._generate_ack_id.assert_called_once_with("/", "cb") def test_emit_namespace_with_callback(self): c = client.Client() - c.namespaces = {'/foo': '1'} + c.namespaces = {"/foo": "1"} c._send_packet = mock.MagicMock() c._generate_ack_id = mock.MagicMock(return_value=123) - c.emit('foo', namespace='/foo', callback='cb') + c.emit("foo", namespace="/foo", callback="cb") expected_packet = packet.Packet( - packet.EVENT, namespace='/foo', data=['foo'], id=123) + packet.EVENT, namespace="/foo", data=["foo"], id=123 + ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) - c._generate_ack_id.assert_called_once_with('/foo', 'cb') + c._generate_ack_id.assert_called_once_with("/foo", "cb") def test_emit_binary(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() - c.emit('foo', b'bar') + c.emit("foo", b"bar") expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', b'bar'], + namespace="/", + data=["foo", b"bar"], id=None, ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_emit_not_binary(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._send_packet = mock.MagicMock() - c.emit('foo', 'bar') + c.emit("foo", "bar") expected_packet = packet.Packet( packet.EVENT, - namespace='/', - data=['foo', 'bar'], + namespace="/", + data=["foo", "bar"], id=None, ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_send(self): c = client.Client() c.emit = mock.MagicMock() - c.send('data', 'namespace', 'callback') + c.send("data", "namespace", "callback") c.emit.assert_called_once_with( - 'message', data='data', namespace='namespace', callback='callback' + "message", data="data", namespace="namespace", callback="callback" ) def test_send_with_defaults(self): c = client.Client() c.emit = mock.MagicMock() - c.send('data') + c.send("data") c.emit.assert_called_once_with( - 'message', data='data', namespace=None, callback=None + "message", data="data", namespace=None, callback=None ) def test_call(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} def fake_event_wait(timeout=None): assert timeout == 60 - c._generate_ack_id.call_args_list[0][0][1]('foo', 321) + c._generate_ack_id.call_args_list[0][0][1]("foo", 321) return True c._send_packet = mock.MagicMock() c._generate_ack_id = mock.MagicMock(return_value=123) c.eio = mock.MagicMock() c.eio.create_event.return_value.wait = fake_event_wait - assert c.call('foo') == ('foo', 321) + assert c.call("foo") == ("foo", 321) expected_packet = packet.Packet( - packet.EVENT, namespace='/', data=['foo'], id=123) + packet.EVENT, namespace="/", data=["foo"], id=123 + ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_call_with_timeout(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} def fake_event_wait(timeout=None): assert timeout == 12 @@ -608,68 +605,63 @@ class TestClient(unittest.TestCase): c.eio = mock.MagicMock() c.eio.create_event.return_value.wait = fake_event_wait with pytest.raises(exceptions.TimeoutError): - c.call('foo', timeout=12) + c.call("foo", timeout=12) expected_packet = packet.Packet( - packet.EVENT, namespace='/', data=['foo'], id=123) + packet.EVENT, namespace="/", data=["foo"], id=123 + ) assert c._send_packet.call_count == 1 assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_disconnect(self): c = client.Client() c.connected = True - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c.eio = mock.MagicMock() - c.eio.state = 'connected' + c.eio.state = "connected" c.disconnect() assert c.connected assert c._trigger_event.call_count == 0 assert c._send_packet.call_count == 1 - expected_packet = packet.Packet(packet.DISCONNECT, namespace='/') + expected_packet = packet.Packet(packet.DISCONNECT, namespace="/") assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) c.eio.disconnect.assert_called_once_with(abort=True) def test_disconnect_namespaces(self): c = client.Client() - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() c.eio = mock.MagicMock() - c.eio.state = 'connected' + c.eio.state = "connected" c.disconnect() assert c._trigger_event.call_count == 0 assert c._send_packet.call_count == 2 - expected_packet = packet.Packet(packet.DISCONNECT, namespace='/foo') + expected_packet = packet.Packet(packet.DISCONNECT, namespace="/foo") assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) - expected_packet = packet.Packet(packet.DISCONNECT, namespace='/bar') + expected_packet = packet.Packet(packet.DISCONNECT, namespace="/bar") assert ( - c._send_packet.call_args_list[1][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[1][0][0].encode() == expected_packet.encode() ) def test_transport(self): c = client.Client() - c.eio.transport = mock.MagicMock(return_value='foo') - assert c.transport() == 'foo' + c.eio.transport = mock.MagicMock(return_value="foo") + assert c.transport() == "foo" c.eio.transport.assert_called_once_with() def test_start_background_task(self): c = client.Client() - c.eio.start_background_task = mock.MagicMock(return_value='foo') - assert c.start_background_task('foo', 'bar', baz='baz') == 'foo' - c.eio.start_background_task.assert_called_once_with( - 'foo', 'bar', baz='baz' - ) + c.eio.start_background_task = mock.MagicMock(return_value="foo") + assert c.start_background_task("foo", "bar", baz="baz") == "foo" + c.eio.start_background_task.assert_called_once_with("foo", "bar", baz="baz") def test_sleep(self): c = client.Client() @@ -680,270 +672,254 @@ class TestClient(unittest.TestCase): def test_send_packet(self): c = client.Client() c.eio.send = mock.MagicMock() - c._send_packet(packet.Packet(packet.EVENT, 'foo')) + c._send_packet(packet.Packet(packet.EVENT, "foo")) c.eio.send.assert_called_once_with('2"foo"') def test_send_packet_binary(self): c = client.Client() c.eio.send = mock.MagicMock() - c._send_packet(packet.Packet(packet.EVENT, b'foo')) + c._send_packet(packet.Packet(packet.EVENT, b"foo")) assert c.eio.send.call_args_list == [ mock.call('51-{"_placeholder":true,"num":0}'), - mock.call(b'foo'), + mock.call(b"foo"), ] or c.eio.send.call_args_list == [ mock.call('51-{"num":0,"_placeholder":true}'), - mock.call(b'foo'), + mock.call(b"foo"), ] def test_send_packet_default_binary(self): c = client.Client() c.eio.send = mock.MagicMock() - c._send_packet(packet.Packet(packet.EVENT, 'foo')) + c._send_packet(packet.Packet(packet.EVENT, "foo")) c.eio.send.assert_called_once_with('2"foo"') def test_generate_ack_id(self): c = client.Client() - assert c._generate_ack_id('/', 'cb') == 1 - assert c._generate_ack_id('/', 'cb') == 2 - assert c._generate_ack_id('/', 'cb') == 3 - assert c._generate_ack_id('/foo', 'cb') == 1 - assert c._generate_ack_id('/bar', 'cb') == 1 - assert c._generate_ack_id('/', 'cb') == 4 - assert c._generate_ack_id('/bar', 'cb') == 2 + assert c._generate_ack_id("/", "cb") == 1 + assert c._generate_ack_id("/", "cb") == 2 + assert c._generate_ack_id("/", "cb") == 3 + assert c._generate_ack_id("/foo", "cb") == 1 + assert c._generate_ack_id("/bar", "cb") == 1 + assert c._generate_ack_id("/", "cb") == 4 + assert c._generate_ack_id("/bar", "cb") == 2 def test_handle_connect(self): c = client.Client() c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() - c._handle_connect('/', {'sid': '123'}) - assert c.namespaces == {'/': '123'} + c._handle_connect("/", {"sid": "123"}) + assert c.namespaces == {"/": "123"} c._connect_event.set.assert_called_once_with() - c._trigger_event.assert_called_once_with('connect', namespace='/') + c._trigger_event.assert_called_once_with("connect", namespace="/") c._send_packet.assert_not_called() def test_handle_connect_with_namespaces(self): c = client.Client() - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() - c._handle_connect('/', {'sid': '3'}) + c._handle_connect("/", {"sid": "3"}) c._connect_event.set.assert_called_once_with() - c._trigger_event.assert_called_once_with('connect', namespace='/') - assert c.namespaces == {'/': '3', '/foo': '1', '/bar': '2'} + c._trigger_event.assert_called_once_with("connect", namespace="/") + assert c.namespaces == {"/": "3", "/foo": "1", "/bar": "2"} def test_handle_connect_namespace(self): c = client.Client() - c.namespaces = {'/foo': '1'} + c.namespaces = {"/foo": "1"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() c._send_packet = mock.MagicMock() - c._handle_connect('/foo', {'sid': '123'}) - c._handle_connect('/bar', {'sid': '2'}) + c._handle_connect("/foo", {"sid": "123"}) + c._handle_connect("/bar", {"sid": "2"}) assert c._trigger_event.call_count == 1 c._connect_event.set.assert_called_once_with() - c._trigger_event.assert_called_once_with('connect', namespace='/bar') - assert c.namespaces == {'/foo': '1', '/bar': '2'} + c._trigger_event.assert_called_once_with("connect", namespace="/bar") + assert c.namespaces == {"/foo": "1", "/bar": "2"} def test_handle_disconnect(self): c = client.Client() - c.namespace = {'/': '1'} + c.namespace = {"/": "1"} c.connected = True c._trigger_event = mock.MagicMock() - c._handle_disconnect('/') - c._trigger_event.assert_any_call('disconnect', namespace='/') - c._trigger_event.assert_any_call('__disconnect_final', namespace='/') + c._handle_disconnect("/") + c._trigger_event.assert_any_call("disconnect", namespace="/") + c._trigger_event.assert_any_call("__disconnect_final", namespace="/") assert not c.connected - c._handle_disconnect('/') + c._handle_disconnect("/") assert c._trigger_event.call_count == 2 def test_handle_disconnect_namespace(self): c = client.Client() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() - c._handle_disconnect('/foo') - c._trigger_event.assert_any_call( - 'disconnect', namespace='/foo' - ) - c._trigger_event.assert_any_call( - '__disconnect_final', namespace='/foo' - ) - assert c.namespaces == {'/bar': '2'} + c._handle_disconnect("/foo") + c._trigger_event.assert_any_call("disconnect", namespace="/foo") + c._trigger_event.assert_any_call("__disconnect_final", namespace="/foo") + assert c.namespaces == {"/bar": "2"} assert c.connected - c._handle_disconnect('/bar') - c._trigger_event.assert_any_call( - 'disconnect', namespace='/bar' - ) - c._trigger_event.assert_any_call( - '__disconnect_final', namespace='/bar' - ) + c._handle_disconnect("/bar") + c._trigger_event.assert_any_call("disconnect", namespace="/bar") + c._trigger_event.assert_any_call("__disconnect_final", namespace="/bar") assert c.namespaces == {} assert not c.connected def test_handle_disconnect_unknown_namespace(self): c = client.Client() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() - c._handle_disconnect('/baz') - c._trigger_event.assert_any_call( - 'disconnect', namespace='/baz' - ) - c._trigger_event.assert_any_call( - '__disconnect_final', namespace='/baz' - ) - assert c.namespaces == {'/foo': '1', '/bar': '2'} + c._handle_disconnect("/baz") + c._trigger_event.assert_any_call("disconnect", namespace="/baz") + c._trigger_event.assert_any_call("__disconnect_final", namespace="/baz") + assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected def test_handle_disconnect_default_namespace(self): c = client.Client() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._trigger_event = mock.MagicMock() - c._handle_disconnect('/') + c._handle_disconnect("/") print(c._trigger_event.call_args_list) - c._trigger_event.assert_any_call('disconnect', namespace='/') - c._trigger_event.assert_any_call('__disconnect_final', namespace='/') - assert c.namespaces == {'/foo': '1', '/bar': '2'} + c._trigger_event.assert_any_call("disconnect", namespace="/") + c._trigger_event.assert_any_call("__disconnect_final", namespace="/") + assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected def test_handle_event(self): c = client.Client() c._trigger_event = mock.MagicMock() - c._handle_event('/', None, ['foo', ('bar', 'baz')]) - c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz')) + c._handle_event("/", None, ["foo", ("bar", "baz")]) + c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) def test_handle_event_with_id_no_arguments(self): c = client.Client() c._trigger_event = mock.MagicMock(return_value=None) c._send_packet = mock.MagicMock() - c._handle_event('/', 123, ['foo', ('bar', 'baz')]) - c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz')) + c._handle_event("/", 123, ["foo", ("bar", "baz")]) + c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.call_count == 1 - expected_packet = packet.Packet( - packet.ACK, namespace='/', id=123, data=[]) + expected_packet = packet.Packet(packet.ACK, namespace="/", id=123, data=[]) assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_handle_event_with_id_one_argument(self): c = client.Client() - c._trigger_event = mock.MagicMock(return_value='ret') + c._trigger_event = mock.MagicMock(return_value="ret") c._send_packet = mock.MagicMock() - c._handle_event('/', 123, ['foo', ('bar', 'baz')]) - c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz')) + c._handle_event("/", 123, ["foo", ("bar", "baz")]) + c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.call_count == 1 - expected_packet = packet.Packet( - packet.ACK, namespace='/', id=123, data=['ret']) + expected_packet = packet.Packet(packet.ACK, namespace="/", id=123, data=["ret"]) assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_handle_event_with_id_one_list_argument(self): c = client.Client() - c._trigger_event = mock.MagicMock(return_value=['a', 'b']) + c._trigger_event = mock.MagicMock(return_value=["a", "b"]) c._send_packet = mock.MagicMock() - c._handle_event('/', 123, ['foo', ('bar', 'baz')]) - c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz')) + c._handle_event("/", 123, ["foo", ("bar", "baz")]) + c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.call_count == 1 expected_packet = packet.Packet( - packet.ACK, namespace='/', id=123, data=[['a', 'b']]) + packet.ACK, namespace="/", id=123, data=[["a", "b"]] + ) assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_handle_event_with_id_two_arguments(self): c = client.Client() - c._trigger_event = mock.MagicMock(return_value=('a', 'b')) + c._trigger_event = mock.MagicMock(return_value=("a", "b")) c._send_packet = mock.MagicMock() - c._handle_event('/', 123, ['foo', ('bar', 'baz')]) - c._trigger_event.assert_called_once_with('foo', '/', ('bar', 'baz')) + c._handle_event("/", 123, ["foo", ("bar", "baz")]) + c._trigger_event.assert_called_once_with("foo", "/", ("bar", "baz")) assert c._send_packet.call_count == 1 expected_packet = packet.Packet( - packet.ACK, namespace='/', id=123, data=['a', 'b']) + packet.ACK, namespace="/", id=123, data=["a", "b"] + ) assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) def test_handle_ack(self): c = client.Client() mock_cb = mock.MagicMock() - c.callbacks['/foo'] = {123: mock_cb} - c._handle_ack('/foo', 123, ['bar', 'baz']) - mock_cb.assert_called_once_with('bar', 'baz') - assert 123 not in c.callbacks['/foo'] + c.callbacks["/foo"] = {123: mock_cb} + c._handle_ack("/foo", 123, ["bar", "baz"]) + mock_cb.assert_called_once_with("bar", "baz") + assert 123 not in c.callbacks["/foo"] def test_handle_ack_not_found(self): c = client.Client() mock_cb = mock.MagicMock() - c.callbacks['/foo'] = {123: mock_cb} - c._handle_ack('/foo', 124, ['bar', 'baz']) + c.callbacks["/foo"] = {123: mock_cb} + c._handle_ack("/foo", 124, ["bar", "baz"]) mock_cb.assert_not_called() - assert 123 in c.callbacks['/foo'] + assert 123 in c.callbacks["/foo"] def test_handle_error(self): c = client.Client() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() - c._handle_error('/', 'error') + c._handle_error("/", "error") assert c.namespaces == {} assert not c.connected c._connect_event.set.assert_called_once_with() - c._trigger_event.assert_called_once_with('connect_error', '/', 'error') + c._trigger_event.assert_called_once_with("connect_error", "/", "error") def test_handle_error_with_no_arguments(self): c = client.Client() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() - c._handle_error('/', None) + c._handle_error("/", None) assert c.namespaces == {} assert not c.connected c._connect_event.set.assert_called_once_with() - c._trigger_event.assert_called_once_with('connect_error', '/') + c._trigger_event.assert_called_once_with("connect_error", "/") def test_handle_error_namespace(self): c = client.Client() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() - c._handle_error('/bar', ['error', 'message']) - assert c.namespaces == {'/foo': '1'} + c._handle_error("/bar", ["error", "message"]) + assert c.namespaces == {"/foo": "1"} assert c.connected c._connect_event.set.assert_called_once_with() c._trigger_event.assert_called_once_with( - 'connect_error', '/bar', 'error', 'message' + "connect_error", "/bar", "error", "message" ) def test_handle_error_namespace_with_no_arguments(self): c = client.Client() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() c._trigger_event = mock.MagicMock() - c._handle_error('/bar', None) - assert c.namespaces == {'/foo': '1'} + c._handle_error("/bar", None) + assert c.namespaces == {"/foo": "1"} assert c.connected c._connect_event.set.assert_called_once_with() - c._trigger_event.assert_called_once_with('connect_error', '/bar') + c._trigger_event.assert_called_once_with("connect_error", "/bar") def test_handle_error_unknown_namespace(self): c = client.Client() c.connected = True - c.namespaces = {'/foo': '1', '/bar': '2'} + c.namespaces = {"/foo": "1", "/bar": "2"} c._connect_event = mock.MagicMock() - c._handle_error('/baz', 'error') - assert c.namespaces == {'/foo': '1', '/bar': '2'} + c._handle_error("/baz", "error") + assert c.namespaces == {"/foo": "1", "/bar": "2"} assert c.connected c._connect_event.set.assert_called_once_with() @@ -951,24 +927,24 @@ class TestClient(unittest.TestCase): c = client.Client() handler = mock.MagicMock() catchall_handler = mock.MagicMock() - c.on('foo', handler) - 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) + c.on("foo", handler) + 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) def test_trigger_event_namespace(self): c = client.Client() handler = mock.MagicMock() catchall_handler = mock.MagicMock() - c.on('foo', handler, namespace='/bar') - c.on('*', catchall_handler, namespace='/bar') - c._trigger_event('foo', '/bar', 1, '2') - c._trigger_event('bar', '/bar', 1, '2', 3) - handler.assert_called_once_with(1, '2') - catchall_handler.assert_called_once_with('bar', 1, '2', 3) + c.on("foo", handler, namespace="/bar") + c.on("*", catchall_handler, namespace="/bar") + c._trigger_event("foo", "/bar", 1, "2") + c._trigger_event("bar", "/bar", 1, "2", 3) + handler.assert_called_once_with(1, "2") + catchall_handler.assert_called_once_with("bar", 1, "2", 3) def test_trigger_event_class_namespace(self): c = client.Client() @@ -979,9 +955,9 @@ class TestClient(unittest.TestCase): result.append(a) result.append(b) - c.register_namespace(MyNamespace('/')) - c._trigger_event('foo', '/', 1, '2') - assert result == [1, '2'] + c.register_namespace(MyNamespace("/")) + c._trigger_event("foo", "/", 1, "2") + assert result == [1, "2"] def test_trigger_event_unknown_namespace(self): c = client.Client() @@ -992,14 +968,14 @@ class TestClient(unittest.TestCase): result.append(a) result.append(b) - c.register_namespace(MyNamespace('/')) - c._trigger_event('foo', '/bar', 1, '2') + c.register_namespace(MyNamespace("/")) + c._trigger_event("foo", "/bar", 1, "2") assert result == [] - @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) + @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect(self, random): c = client.Client() - c._reconnect_task = 'foo' + c._reconnect_task = "foo" c._reconnect_abort = c.eio.create_event() c._reconnect_abort.wait = mock.MagicMock(return_value=False) c.connect = mock.MagicMock( @@ -1014,10 +990,10 @@ class TestClient(unittest.TestCase): ] assert c._reconnect_task is None - @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) + @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_max_delay(self, random): c = client.Client(reconnection_delay_max=3) - c._reconnect_task = 'foo' + c._reconnect_task = "foo" c._reconnect_abort = c.eio.create_event() c._reconnect_abort.wait = mock.MagicMock(return_value=False) c.connect = mock.MagicMock( @@ -1032,11 +1008,11 @@ class TestClient(unittest.TestCase): ] assert c._reconnect_task is None - @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) + @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_max_attempts(self, random): c = client.Client(reconnection_attempts=2) - c.connection_namespaces = ['/'] - c._reconnect_task = 'foo' + c.connection_namespaces = ["/"] + c._reconnect_task = "foo" c._reconnect_abort = c.eio.create_event() c._reconnect_abort.wait = mock.MagicMock(return_value=False) c._trigger_event = mock.MagicMock() @@ -1049,15 +1025,14 @@ class TestClient(unittest.TestCase): mock.call(1.5), mock.call(1.5), ] - assert c._reconnect_task == 'foo' - c._trigger_event.assert_called_once_with('__disconnect_final', - namespace='/') + assert c._reconnect_task == "foo" + c._trigger_event.assert_called_once_with("__disconnect_final", namespace="/") - @mock.patch('socketio.client.random.random', side_effect=[1, 0, 0.5]) + @mock.patch("socketio.client.random.random", side_effect=[1, 0, 0.5]) def test_handle_reconnect_aborted(self, random): c = client.Client() - c.connection_namespaces = ['/'] - c._reconnect_task = 'foo' + c.connection_namespaces = ["/"] + c._reconnect_task = "foo" c._reconnect_abort = c.eio.create_event() c._reconnect_abort.wait = mock.MagicMock(side_effect=[False, True]) c._trigger_event = mock.MagicMock() @@ -1068,54 +1043,45 @@ class TestClient(unittest.TestCase): mock.call(1.5), mock.call(1.5), ] - assert c._reconnect_task == 'foo' - c._trigger_event.assert_called_once_with('__disconnect_final', - namespace='/') + assert c._reconnect_task == "foo" + c._trigger_event.assert_called_once_with("__disconnect_final", namespace="/") def test_handle_eio_connect(self): c = client.Client() - c.connection_namespaces = ['/', '/foo'] - c.connection_auth = 'auth' + c.connection_namespaces = ["/", "/foo"] + c.connection_auth = "auth" c._send_packet = mock.MagicMock() - c.eio.sid = 'foo' + c.eio.sid = "foo" assert c.sid is None c._handle_eio_connect() - assert c.sid == 'foo' + assert c.sid == "foo" assert c._send_packet.call_count == 2 - expected_packet = packet.Packet( - packet.CONNECT, data='auth', namespace='/') + expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/") assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) - expected_packet = packet.Packet( - packet.CONNECT, data='auth', namespace='/foo') + expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/foo") assert ( - c._send_packet.call_args_list[1][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[1][0][0].encode() == expected_packet.encode() ) def test_handle_eio_connect_function(self): c = client.Client() - c.connection_namespaces = ['/', '/foo'] - c.connection_auth = lambda: 'auth' + c.connection_namespaces = ["/", "/foo"] + c.connection_auth = lambda: "auth" c._send_packet = mock.MagicMock() - c.eio.sid = 'foo' + c.eio.sid = "foo" assert c.sid is None c._handle_eio_connect() - assert c.sid == 'foo' + assert c.sid == "foo" assert c._send_packet.call_count == 2 - expected_packet = packet.Packet( - packet.CONNECT, data='auth', namespace='/') + expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/") assert ( - c._send_packet.call_args_list[0][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[0][0][0].encode() == expected_packet.encode() ) - expected_packet = packet.Packet( - packet.CONNECT, data='auth', namespace='/foo') + expected_packet = packet.Packet(packet.CONNECT, data="auth", namespace="/foo") assert ( - c._send_packet.call_args_list[1][0][0].encode() - == expected_packet.encode() + c._send_packet.call_args_list[1][0][0].encode() == expected_packet.encode() ) def test_handle_eio_message(self): @@ -1127,97 +1093,95 @@ class TestClient(unittest.TestCase): c._handle_error = mock.MagicMock() c._handle_eio_message('0{"sid":"123"}') - c._handle_connect.assert_called_with(None, {'sid': '123'}) + c._handle_connect.assert_called_with(None, {"sid": "123"}) c._handle_eio_message('0/foo,{"sid":"123"}') - c._handle_connect.assert_called_with('/foo', {'sid': '123'}) - c._handle_eio_message('1') + c._handle_connect.assert_called_with("/foo", {"sid": "123"}) + c._handle_eio_message("1") c._handle_disconnect.assert_called_with(None) - c._handle_eio_message('1/foo') - c._handle_disconnect.assert_called_with('/foo') + c._handle_eio_message("1/foo") + c._handle_disconnect.assert_called_with("/foo") c._handle_eio_message('2["foo"]') - c._handle_event.assert_called_with(None, None, ['foo']) + c._handle_event.assert_called_with(None, None, ["foo"]) c._handle_eio_message('3/foo,["bar"]') - c._handle_ack.assert_called_with('/foo', None, ['bar']) - c._handle_eio_message('4') + c._handle_ack.assert_called_with("/foo", None, ["bar"]) + c._handle_eio_message("4") c._handle_error.assert_called_with(None, None) c._handle_eio_message('4"foo"') - c._handle_error.assert_called_with(None, 'foo') + c._handle_error.assert_called_with(None, "foo") c._handle_eio_message('4["foo"]') - c._handle_error.assert_called_with(None, ['foo']) - c._handle_eio_message('4/foo') - c._handle_error.assert_called_with('/foo', None) + c._handle_error.assert_called_with(None, ["foo"]) + c._handle_eio_message("4/foo") + c._handle_error.assert_called_with("/foo", None) c._handle_eio_message('4/foo,["foo","bar"]') - c._handle_error.assert_called_with('/foo', ['foo', 'bar']) + c._handle_error.assert_called_with("/foo", ["foo", "bar"]) c._handle_eio_message('51-{"_placeholder":true,"num":0}') assert c._binary_packet.packet_type == packet.BINARY_EVENT - c._handle_eio_message(b'foo') - c._handle_event.assert_called_with(None, None, b'foo') + c._handle_eio_message(b"foo") + c._handle_event.assert_called_with(None, None, b"foo") c._handle_eio_message( '62-/foo,{"1":{"_placeholder":true,"num":1},' '"2":{"_placeholder":true,"num":0}}' ) assert c._binary_packet.packet_type == packet.BINARY_ACK - c._handle_eio_message(b'bar') - c._handle_eio_message(b'foo') - c._handle_ack.assert_called_with( - '/foo', None, {'1': b'foo', '2': b'bar'} - ) + c._handle_eio_message(b"bar") + c._handle_eio_message(b"foo") + c._handle_ack.assert_called_with("/foo", None, {"1": b"foo", "2": b"bar"}) with pytest.raises(ValueError): - c._handle_eio_message('9') + c._handle_eio_message("9") def test_eio_disconnect(self): c = client.Client() - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c.connected = True c._trigger_event = mock.MagicMock() c.start_background_task = mock.MagicMock() - c.sid = 'foo' - c.eio.state = 'connected' + c.sid = "foo" + c.eio.state = "connected" c._handle_eio_disconnect() - c._trigger_event.assert_called_once_with('disconnect', namespace='/') + c._trigger_event.assert_called_once_with("disconnect", namespace="/") assert c.sid is None assert not c.connected def test_eio_disconnect_namespaces(self): c = client.Client() c.connected = True - c.namespaces = {'/': '1', '/foo': '2', '/bar': '3'} + c.namespaces = {"/": "1", "/foo": "2", "/bar": "3"} c._trigger_event = mock.MagicMock() c.start_background_task = mock.MagicMock() - c.sid = 'foo' - c.eio.state = 'connected' + c.sid = "foo" + c.eio.state = "connected" c._handle_eio_disconnect() - c._trigger_event.assert_any_call('disconnect', namespace='/foo') - c._trigger_event.assert_any_call('disconnect', namespace='/bar') - c._trigger_event.assert_any_call('disconnect', namespace='/') + c._trigger_event.assert_any_call("disconnect", namespace="/foo") + c._trigger_event.assert_any_call("disconnect", namespace="/bar") + c._trigger_event.assert_any_call("disconnect", namespace="/") assert c.sid is None assert not c.connected def test_eio_disconnect_reconnect(self): c = client.Client(reconnection=True) c.start_background_task = mock.MagicMock() - c.eio.state = 'connected' + c.eio.state = "connected" c._handle_eio_disconnect() c.start_background_task.assert_called_once_with(c._handle_reconnect) def test_eio_disconnect_self_disconnect(self): c = client.Client(reconnection=True) c.start_background_task = mock.MagicMock() - c.eio.state = 'disconnected' + c.eio.state = "disconnected" c._handle_eio_disconnect() c.start_background_task.assert_not_called() def test_eio_disconnect_no_reconnect(self): c = client.Client(reconnection=False) - c.namespaces = {'/': '1'} + c.namespaces = {"/": "1"} c.connected = True c._trigger_event = mock.MagicMock() c.start_background_task = mock.MagicMock() - c.sid = 'foo' - c.eio.state = 'connected' + c.sid = "foo" + c.eio.state = "connected" c._handle_eio_disconnect() - c._trigger_event.assert_any_call('disconnect', namespace='/') - c._trigger_event.assert_any_call('__disconnect_final', namespace='/') + c._trigger_event.assert_any_call("disconnect", namespace="/") + c._trigger_event.assert_any_call("__disconnect_final", namespace="/") assert c.sid is None assert not c.connected c.start_background_task.assert_not_called() diff --git a/tests/common/test_manager.py b/tests/common/test_manager.py index 8bb826a..9da4c94 100644 --- a/tests/common/test_manager.py +++ b/tests/common/test_manager.py @@ -24,329 +24,324 @@ class TestBaseManager(unittest.TestCase): self.bm.initialize() def test_connect(self): - sid = self.bm.connect('123', '/foo') - assert None in self.bm.rooms['/foo'] - assert sid in self.bm.rooms['/foo'] - assert sid in self.bm.rooms['/foo'][None] - assert sid in self.bm.rooms['/foo'][sid] - assert dict(self.bm.rooms['/foo'][None]) == {sid: '123'} - assert dict(self.bm.rooms['/foo'][sid]) == {sid: '123'} - assert self.bm.sid_from_eio_sid('123', '/foo') == sid - assert self.bm.sid_from_eio_sid('1234', '/foo') is None - assert self.bm.sid_from_eio_sid('123', '/bar') is None - assert self.bm.eio_sid_from_sid(sid, '/foo') == '123' - assert self.bm.eio_sid_from_sid('x', '/foo') is None - assert self.bm.eio_sid_from_sid(sid, '/bar') is None + sid = self.bm.connect("123", "/foo") + assert None in self.bm.rooms["/foo"] + assert sid in self.bm.rooms["/foo"] + assert sid in self.bm.rooms["/foo"][None] + assert sid in self.bm.rooms["/foo"][sid] + assert dict(self.bm.rooms["/foo"][None]) == {sid: "123"} + assert dict(self.bm.rooms["/foo"][sid]) == {sid: "123"} + assert self.bm.sid_from_eio_sid("123", "/foo") == sid + assert self.bm.sid_from_eio_sid("1234", "/foo") is None + assert self.bm.sid_from_eio_sid("123", "/bar") is None + assert self.bm.eio_sid_from_sid(sid, "/foo") == "123" + assert self.bm.eio_sid_from_sid("x", "/foo") is None + assert self.bm.eio_sid_from_sid(sid, "/bar") is None def test_pre_disconnect(self): - sid1 = self.bm.connect('123', '/foo') - sid2 = self.bm.connect('456', '/foo') - assert self.bm.is_connected(sid1, '/foo') - assert self.bm.pre_disconnect(sid1, '/foo') == '123' - assert self.bm.pending_disconnect == {'/foo': [sid1]} - assert not self.bm.is_connected(sid1, '/foo') - assert self.bm.pre_disconnect(sid2, '/foo') == '456' - assert self.bm.pending_disconnect == {'/foo': [sid1, sid2]} - assert not self.bm.is_connected(sid2, '/foo') - self.bm.disconnect(sid1, '/foo') - assert self.bm.pending_disconnect == {'/foo': [sid2]} - self.bm.disconnect(sid2, '/foo') + sid1 = self.bm.connect("123", "/foo") + sid2 = self.bm.connect("456", "/foo") + assert self.bm.is_connected(sid1, "/foo") + assert self.bm.pre_disconnect(sid1, "/foo") == "123" + assert self.bm.pending_disconnect == {"/foo": [sid1]} + assert not self.bm.is_connected(sid1, "/foo") + assert self.bm.pre_disconnect(sid2, "/foo") == "456" + assert self.bm.pending_disconnect == {"/foo": [sid1, sid2]} + assert not self.bm.is_connected(sid2, "/foo") + self.bm.disconnect(sid1, "/foo") + assert self.bm.pending_disconnect == {"/foo": [sid2]} + self.bm.disconnect(sid2, "/foo") assert self.bm.pending_disconnect == {} def test_disconnect(self): - sid1 = self.bm.connect('123', '/foo') - sid2 = self.bm.connect('456', '/foo') - self.bm.enter_room(sid1, '/foo', 'bar') - self.bm.enter_room(sid2, '/foo', 'baz') - self.bm.disconnect(sid1, '/foo') - assert dict(self.bm.rooms['/foo'][None]) == {sid2: '456'} - assert dict(self.bm.rooms['/foo'][sid2]) == {sid2: '456'} - assert dict(self.bm.rooms['/foo']['baz']) == {sid2: '456'} + sid1 = self.bm.connect("123", "/foo") + sid2 = self.bm.connect("456", "/foo") + self.bm.enter_room(sid1, "/foo", "bar") + self.bm.enter_room(sid2, "/foo", "baz") + self.bm.disconnect(sid1, "/foo") + assert dict(self.bm.rooms["/foo"][None]) == {sid2: "456"} + assert dict(self.bm.rooms["/foo"][sid2]) == {sid2: "456"} + assert dict(self.bm.rooms["/foo"]["baz"]) == {sid2: "456"} def test_disconnect_default_namespace(self): - sid1 = self.bm.connect('123', '/') - sid2 = self.bm.connect('123', '/foo') - sid3 = self.bm.connect('456', '/') - sid4 = self.bm.connect('456', '/foo') - assert self.bm.is_connected(sid1, '/') - assert self.bm.is_connected(sid2, '/foo') - assert not self.bm.is_connected(sid2, '/') - assert not self.bm.is_connected(sid1, '/foo') - self.bm.disconnect(sid1, '/') - assert not self.bm.is_connected(sid1, '/') - assert self.bm.is_connected(sid2, '/foo') - self.bm.disconnect(sid2, '/foo') - assert not self.bm.is_connected(sid2, '/foo') - assert dict(self.bm.rooms['/'][None]) == {sid3: '456'} - assert dict(self.bm.rooms['/'][sid3]) == {sid3: '456'} - assert dict(self.bm.rooms['/foo'][None]) == {sid4: '456'} - assert dict(self.bm.rooms['/foo'][sid4]) == {sid4: '456'} + sid1 = self.bm.connect("123", "/") + sid2 = self.bm.connect("123", "/foo") + sid3 = self.bm.connect("456", "/") + sid4 = self.bm.connect("456", "/foo") + assert self.bm.is_connected(sid1, "/") + assert self.bm.is_connected(sid2, "/foo") + assert not self.bm.is_connected(sid2, "/") + assert not self.bm.is_connected(sid1, "/foo") + self.bm.disconnect(sid1, "/") + assert not self.bm.is_connected(sid1, "/") + assert self.bm.is_connected(sid2, "/foo") + self.bm.disconnect(sid2, "/foo") + assert not self.bm.is_connected(sid2, "/foo") + assert dict(self.bm.rooms["/"][None]) == {sid3: "456"} + assert dict(self.bm.rooms["/"][sid3]) == {sid3: "456"} + assert dict(self.bm.rooms["/foo"][None]) == {sid4: "456"} + assert dict(self.bm.rooms["/foo"][sid4]) == {sid4: "456"} def test_disconnect_twice(self): - sid1 = self.bm.connect('123', '/') - sid2 = self.bm.connect('123', '/foo') - sid3 = self.bm.connect('456', '/') - sid4 = self.bm.connect('456', '/foo') - self.bm.disconnect(sid1, '/') - self.bm.disconnect(sid2, '/foo') - self.bm.disconnect(sid1, '/') - self.bm.disconnect(sid2, '/foo') - assert dict(self.bm.rooms['/'][None]) == {sid3: '456'} - assert dict(self.bm.rooms['/'][sid3]) == {sid3: '456'} - assert dict(self.bm.rooms['/foo'][None]) == {sid4: '456'} - assert dict(self.bm.rooms['/foo'][sid4]) == {sid4: '456'} + sid1 = self.bm.connect("123", "/") + sid2 = self.bm.connect("123", "/foo") + sid3 = self.bm.connect("456", "/") + sid4 = self.bm.connect("456", "/foo") + self.bm.disconnect(sid1, "/") + self.bm.disconnect(sid2, "/foo") + self.bm.disconnect(sid1, "/") + self.bm.disconnect(sid2, "/foo") + assert dict(self.bm.rooms["/"][None]) == {sid3: "456"} + assert dict(self.bm.rooms["/"][sid3]) == {sid3: "456"} + assert dict(self.bm.rooms["/foo"][None]) == {sid4: "456"} + assert dict(self.bm.rooms["/foo"][sid4]) == {sid4: "456"} def test_disconnect_all(self): - sid1 = self.bm.connect('123', '/foo') - sid2 = self.bm.connect('456', '/foo') - self.bm.enter_room(sid1, '/foo', 'bar') - self.bm.enter_room(sid2, '/foo', 'baz') - self.bm.disconnect(sid1, '/foo') - self.bm.disconnect(sid2, '/foo') + sid1 = self.bm.connect("123", "/foo") + sid2 = self.bm.connect("456", "/foo") + self.bm.enter_room(sid1, "/foo", "bar") + self.bm.enter_room(sid2, "/foo", "baz") + self.bm.disconnect(sid1, "/foo") + self.bm.disconnect(sid2, "/foo") assert self.bm.rooms == {} def test_disconnect_with_callbacks(self): - sid1 = self.bm.connect('123', '/') - sid2 = self.bm.connect('123', '/foo') - sid3 = self.bm.connect('456', '/foo') - self.bm._generate_ack_id(sid1, 'f') - self.bm._generate_ack_id(sid2, 'g') - self.bm._generate_ack_id(sid3, 'h') - self.bm.disconnect(sid2, '/foo') + sid1 = self.bm.connect("123", "/") + sid2 = self.bm.connect("123", "/foo") + sid3 = self.bm.connect("456", "/foo") + self.bm._generate_ack_id(sid1, "f") + self.bm._generate_ack_id(sid2, "g") + self.bm._generate_ack_id(sid3, "h") + self.bm.disconnect(sid2, "/foo") assert sid2 not in self.bm.callbacks - self.bm.disconnect(sid1, '/') + self.bm.disconnect(sid1, "/") assert sid1 not in self.bm.callbacks assert sid3 in self.bm.callbacks def test_disconnect_bad_namespace(self): - self.bm.connect('123', '/') - self.bm.connect('123', '/foo') - self.bm.disconnect('123', '/bar') # should not assert + self.bm.connect("123", "/") + self.bm.connect("123", "/foo") + self.bm.disconnect("123", "/bar") # should not assert def test_enter_room_bad_namespace(self): - sid = self.bm.connect('123', '/') + sid = self.bm.connect("123", "/") with pytest.raises(ValueError): - self.bm.enter_room(sid, '/foo', 'bar') + self.bm.enter_room(sid, "/foo", "bar") def test_trigger_callback(self): - sid1 = self.bm.connect('123', '/') - sid2 = self.bm.connect('123', '/foo') + sid1 = self.bm.connect("123", "/") + sid2 = self.bm.connect("123", "/foo") cb = mock.MagicMock() id1 = self.bm._generate_ack_id(sid1, cb) id2 = self.bm._generate_ack_id(sid2, cb) id3 = self.bm._generate_ack_id(sid1, cb) - self.bm.trigger_callback(sid1, id1, ['foo']) - self.bm.trigger_callback(sid1, id3, ['bar']) - self.bm.trigger_callback(sid2, id2, ['bar', 'baz']) + self.bm.trigger_callback(sid1, id1, ["foo"]) + self.bm.trigger_callback(sid1, id3, ["bar"]) + self.bm.trigger_callback(sid2, id2, ["bar", "baz"]) assert cb.call_count == 3 - cb.assert_any_call('foo') - cb.assert_any_call('bar') - cb.assert_any_call('bar', 'baz') + cb.assert_any_call("foo") + cb.assert_any_call("bar") + cb.assert_any_call("bar", "baz") def test_invalid_callback(self): - sid = self.bm.connect('123', '/') + sid = self.bm.connect("123", "/") cb = mock.MagicMock() id = self.bm._generate_ack_id(sid, cb) # these should not raise an exception - self.bm.trigger_callback('xxx', id, ['foo']) - self.bm.trigger_callback(sid, id + 1, ['foo']) + self.bm.trigger_callback("xxx", id, ["foo"]) + self.bm.trigger_callback(sid, id + 1, ["foo"]) assert cb.call_count == 0 def test_get_namespaces(self): assert list(self.bm.get_namespaces()) == [] - self.bm.connect('123', '/') - self.bm.connect('123', '/foo') + self.bm.connect("123", "/") + self.bm.connect("123", "/foo") namespaces = list(self.bm.get_namespaces()) assert len(namespaces) == 2 - assert '/' in namespaces - assert '/foo' in namespaces + assert "/" in namespaces + assert "/foo" in namespaces def test_get_participants(self): - sid1 = self.bm.connect('123', '/') - sid2 = self.bm.connect('456', '/') - sid3 = self.bm.connect('789', '/') - self.bm.disconnect(sid3, '/') - assert sid3 not in self.bm.rooms['/'][None] - participants = list(self.bm.get_participants('/', None)) + sid1 = self.bm.connect("123", "/") + sid2 = self.bm.connect("456", "/") + sid3 = self.bm.connect("789", "/") + self.bm.disconnect(sid3, "/") + assert sid3 not in self.bm.rooms["/"][None] + participants = list(self.bm.get_participants("/", None)) assert len(participants) == 2 - assert (sid1, '123') in participants - assert (sid2, '456') in participants - assert (sid3, '789') not in participants + assert (sid1, "123") in participants + assert (sid2, "456") in participants + assert (sid3, "789") not in participants def test_leave_invalid_room(self): - sid = self.bm.connect('123', '/foo') - self.bm.leave_room(sid, '/foo', 'baz') - self.bm.leave_room(sid, '/bar', 'baz') + sid = self.bm.connect("123", "/foo") + self.bm.leave_room(sid, "/foo", "baz") + self.bm.leave_room(sid, "/bar", "baz") def test_no_room(self): - rooms = self.bm.get_rooms('123', '/foo') + rooms = self.bm.get_rooms("123", "/foo") assert [] == rooms def test_close_room(self): - sid1 = self.bm.connect('123', '/foo') - self.bm.connect('456', '/foo') - self.bm.connect('789', '/foo') - self.bm.enter_room(sid1, '/foo', 'bar') - self.bm.enter_room(sid1, '/foo', 'bar') - self.bm.close_room('bar', '/foo') - assert 'bar' not in self.bm.rooms['/foo'] + sid1 = self.bm.connect("123", "/foo") + self.bm.connect("456", "/foo") + self.bm.connect("789", "/foo") + self.bm.enter_room(sid1, "/foo", "bar") + self.bm.enter_room(sid1, "/foo", "bar") + self.bm.close_room("bar", "/foo") + assert "bar" not in self.bm.rooms["/foo"] def test_close_invalid_room(self): - self.bm.close_room('bar', '/foo') + self.bm.close_room("bar", "/foo") def test_rooms(self): - sid = self.bm.connect('123', '/foo') - self.bm.enter_room(sid, '/foo', 'bar') - r = self.bm.get_rooms(sid, '/foo') + sid = self.bm.connect("123", "/foo") + self.bm.enter_room(sid, "/foo", "bar") + r = self.bm.get_rooms(sid, "/foo") assert len(r) == 2 assert sid in r - assert 'bar' in r + assert "bar" in r def test_emit_to_sid(self): - sid = self.bm.connect('123', '/foo') - self.bm.connect('456', '/foo') - self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo', room=sid) + sid = self.bm.connect("123", "/foo") + self.bm.connect("456", "/foo") + self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", room=sid) assert self.bm.server._send_eio_packet.call_count == 1 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_room(self): - sid1 = self.bm.connect('123', '/foo') - self.bm.enter_room(sid1, '/foo', 'bar') - sid2 = self.bm.connect('456', '/foo') - self.bm.enter_room(sid2, '/foo', 'bar') - self.bm.connect('789', '/foo') - self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo', room='bar') + sid1 = self.bm.connect("123", "/foo") + self.bm.enter_room(sid1, "/foo", "bar") + sid2 = self.bm.connect("456", "/foo") + self.bm.enter_room(sid2, "/foo", "bar") + self.bm.connect("789", "/foo") + self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", room="bar") assert self.bm.server._send_eio_packet.call_count == 2 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' - assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == '456' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" + assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == "456" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt == self.bm.server._send_eio_packet.call_args_list[1][0][1] assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_rooms(self): - sid1 = self.bm.connect('123', '/foo') - self.bm.enter_room(sid1, '/foo', 'bar') - sid2 = self.bm.connect('456', '/foo') - self.bm.enter_room(sid2, '/foo', 'bar') - self.bm.enter_room(sid2, '/foo', 'baz') - sid3 = self.bm.connect('789', '/foo') - self.bm.enter_room(sid3, '/foo', 'baz') - self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo', - room=['bar', 'baz']) + sid1 = self.bm.connect("123", "/foo") + self.bm.enter_room(sid1, "/foo", "bar") + sid2 = self.bm.connect("456", "/foo") + self.bm.enter_room(sid2, "/foo", "bar") + self.bm.enter_room(sid2, "/foo", "baz") + sid3 = self.bm.connect("789", "/foo") + self.bm.enter_room(sid3, "/foo", "baz") + self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", room=["bar", "baz"]) assert self.bm.server._send_eio_packet.call_count == 3 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' - assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == '456' - assert self.bm.server._send_eio_packet.call_args_list[2][0][0] == '789' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" + assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == "456" + assert self.bm.server._send_eio_packet.call_args_list[2][0][0] == "789" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt == self.bm.server._send_eio_packet.call_args_list[1][0][1] assert pkt == self.bm.server._send_eio_packet.call_args_list[2][0][1] assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_all(self): - sid1 = self.bm.connect('123', '/foo') - self.bm.enter_room(sid1, '/foo', 'bar') - sid2 = self.bm.connect('456', '/foo') - self.bm.enter_room(sid2, '/foo', 'bar') - self.bm.connect('789', '/foo') - self.bm.connect('abc', '/bar') - self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo') + sid1 = self.bm.connect("123", "/foo") + self.bm.enter_room(sid1, "/foo", "bar") + sid2 = self.bm.connect("456", "/foo") + self.bm.enter_room(sid2, "/foo", "bar") + self.bm.connect("789", "/foo") + self.bm.connect("abc", "/bar") + self.bm.emit("my event", {"foo": "bar"}, namespace="/foo") assert self.bm.server._send_eio_packet.call_count == 3 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' - assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == '456' - assert self.bm.server._send_eio_packet.call_args_list[2][0][0] == '789' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" + assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == "456" + assert self.bm.server._send_eio_packet.call_args_list[2][0][0] == "789" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt == self.bm.server._send_eio_packet.call_args_list[1][0][1] assert pkt == self.bm.server._send_eio_packet.call_args_list[2][0][1] assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_all_skip_one(self): - sid1 = self.bm.connect('123', '/foo') - self.bm.enter_room(sid1, '/foo', 'bar') - sid2 = self.bm.connect('456', '/foo') - self.bm.enter_room(sid2, '/foo', 'bar') - self.bm.connect('789', '/foo') - self.bm.connect('abc', '/bar') - self.bm.emit( - 'my event', {'foo': 'bar'}, namespace='/foo', skip_sid=sid2 - ) + sid1 = self.bm.connect("123", "/foo") + self.bm.enter_room(sid1, "/foo", "bar") + sid2 = self.bm.connect("456", "/foo") + self.bm.enter_room(sid2, "/foo", "bar") + self.bm.connect("789", "/foo") + self.bm.connect("abc", "/bar") + self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", skip_sid=sid2) assert self.bm.server._send_eio_packet.call_count == 2 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' - assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == '789' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" + assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == "789" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt == self.bm.server._send_eio_packet.call_args_list[1][0][1] assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_to_all_skip_two(self): - sid1 = self.bm.connect('123', '/foo') - self.bm.enter_room(sid1, '/foo', 'bar') - sid2 = self.bm.connect('456', '/foo') - self.bm.enter_room(sid2, '/foo', 'bar') - sid3 = self.bm.connect('789', '/foo') - self.bm.connect('abc', '/bar') + sid1 = self.bm.connect("123", "/foo") + self.bm.enter_room(sid1, "/foo", "bar") + sid2 = self.bm.connect("456", "/foo") + self.bm.enter_room(sid2, "/foo", "bar") + sid3 = self.bm.connect("789", "/foo") + self.bm.connect("abc", "/bar") self.bm.emit( - 'my event', - {'foo': 'bar'}, - namespace='/foo', + "my event", + {"foo": "bar"}, + namespace="/foo", skip_sid=[sid1, sid3], ) assert self.bm.server._send_eio_packet.call_count == 1 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '456' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "456" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event",{"foo":"bar"}]' def test_emit_with_callback(self): - sid = self.bm.connect('123', '/foo') + sid = self.bm.connect("123", "/foo") self.bm._generate_ack_id = mock.MagicMock() self.bm._generate_ack_id.return_value = 11 - self.bm.emit( - 'my event', {'foo': 'bar'}, namespace='/foo', callback='cb' - ) - self.bm._generate_ack_id.assert_called_once_with(sid, 'cb') + self.bm.emit("my event", {"foo": "bar"}, namespace="/foo", callback="cb") + self.bm._generate_ack_id.assert_called_once_with(sid, "cb") assert self.bm.server._send_packet.call_count == 1 - assert self.bm.server._send_packet.call_args_list[0][0][0] == '123' + assert self.bm.server._send_packet.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_packet.call_args_list[0][0][1] assert pkt.encode() == '2/foo,11["my event",{"foo":"bar"}]' def test_emit_to_invalid_room(self): - self.bm.emit('my event', {'foo': 'bar'}, namespace='/', room='123') + self.bm.emit("my event", {"foo": "bar"}, namespace="/", room="123") def test_emit_to_invalid_namespace(self): - self.bm.emit('my event', {'foo': 'bar'}, namespace='/foo') + self.bm.emit("my event", {"foo": "bar"}, namespace="/foo") def test_emit_with_tuple(self): - sid = self.bm.connect('123', '/foo') - self.bm.emit('my event', ('foo', 'bar'), namespace='/foo', room=sid) + sid = self.bm.connect("123", "/foo") + self.bm.emit("my event", ("foo", "bar"), namespace="/foo", room=sid) assert self.bm.server._send_eio_packet.call_count == 1 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event","foo","bar"]' def test_emit_with_list(self): - sid = self.bm.connect('123', '/foo') - self.bm.emit('my event', ['foo', 'bar'], namespace='/foo', room=sid) + sid = self.bm.connect("123", "/foo") + self.bm.emit("my event", ["foo", "bar"], namespace="/foo", room=sid) assert self.bm.server._send_eio_packet.call_count == 1 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event",["foo","bar"]]' def test_emit_with_none(self): - sid = self.bm.connect('123', '/foo') - self.bm.emit('my event', None, namespace='/foo', room=sid) + sid = self.bm.connect("123", "/foo") + self.bm.emit("my event", None, namespace="/foo", room=sid) assert self.bm.server._send_eio_packet.call_count == 1 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt.encode() == '42/foo,["my event"]' def test_emit_binary(self): - sid = self.bm.connect('123', '/') - self.bm.emit(u'my event', b'my binary data', namespace='/', room=sid) + sid = self.bm.connect("123", "/") + self.bm.emit("my event", b"my binary data", namespace="/", room=sid) assert self.bm.server._send_eio_packet.call_count == 2 - assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == '123' + assert self.bm.server._send_eio_packet.call_args_list[0][0][0] == "123" pkt = self.bm.server._send_eio_packet.call_args_list[0][0][1] assert pkt.encode() == '451-["my event",{"_placeholder":true,"num":0}]' - assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == '123' + assert self.bm.server._send_eio_packet.call_args_list[1][0][0] == "123" pkt = self.bm.server._send_eio_packet.call_args_list[1][0][1] - assert pkt.encode() == b'my binary data' + assert pkt.encode() == b"my binary data" diff --git a/tests/common/test_middleware.py b/tests/common/test_middleware.py index 8611a04..60ec0e8 100644 --- a/tests/common/test_middleware.py +++ b/tests/common/test_middleware.py @@ -7,33 +7,31 @@ from socketio import middleware class TestMiddleware(unittest.TestCase): def test_wsgi_routing(self): mock_wsgi_app = mock.MagicMock() - mock_sio_app = 'foo' + mock_sio_app = "foo" m = middleware.Middleware(mock_sio_app, mock_wsgi_app) - environ = {'PATH_INFO': '/foo'} + environ = {"PATH_INFO": "/foo"} start_response = "foo" m(environ, start_response) mock_wsgi_app.assert_called_once_with(environ, start_response) def test_sio_routing(self): - mock_wsgi_app = 'foo' + mock_wsgi_app = "foo" mock_sio_app = mock.Mock() mock_sio_app.handle_request = mock.MagicMock() m = middleware.Middleware(mock_sio_app, mock_wsgi_app) - environ = {'PATH_INFO': '/socket.io/'} + environ = {"PATH_INFO": "/socket.io/"} start_response = "foo" m(environ, start_response) - mock_sio_app.handle_request.assert_called_once_with( - environ, start_response - ) + mock_sio_app.handle_request.assert_called_once_with(environ, start_response) def test_404(self): mock_wsgi_app = None mock_sio_app = mock.Mock() m = middleware.Middleware(mock_sio_app, mock_wsgi_app) - environ = {'PATH_INFO': '/foo/bar'} + environ = {"PATH_INFO": "/foo/bar"} start_response = mock.MagicMock() r = m(environ, start_response) - assert r == [b'Not Found'] + assert r == [b"Not Found"] start_response.assert_called_once_with( - "404 Not Found", [('Content-Type', 'text/plain')] + "404 Not Found", [("Content-Type", "text/plain")] ) diff --git a/tests/common/test_msgpack_packet.py b/tests/common/test_msgpack_packet.py index 4930cff..930cc7c 100644 --- a/tests/common/test_msgpack_packet.py +++ b/tests/common/test_msgpack_packet.py @@ -7,7 +7,8 @@ from socketio import packet class TestMsgPackPacket(unittest.TestCase): def test_encode_decode(self): p = msgpack_packet.MsgPackPacket( - packet.CONNECT, data={'auth': {'token': '123'}}, namespace='/foo') + packet.CONNECT, data={"auth": {"token": "123"}}, namespace="/foo" + ) p2 = msgpack_packet.MsgPackPacket(encoded_packet=p.encode()) assert p.packet_type == p2.packet_type assert p.data == p2.data @@ -16,7 +17,8 @@ class TestMsgPackPacket(unittest.TestCase): def test_encode_decode_with_id(self): p = msgpack_packet.MsgPackPacket( - packet.EVENT, data=['ev', 42], id=123, namespace='/foo') + packet.EVENT, data=["ev", 42], id=123, namespace="/foo" + ) p2 = msgpack_packet.MsgPackPacket(encoded_packet=p.encode()) assert p.packet_type == p2.packet_type assert p.data == p2.data @@ -24,13 +26,13 @@ class TestMsgPackPacket(unittest.TestCase): assert p.namespace == p2.namespace def test_encode_binary_event_packet(self): - p = msgpack_packet.MsgPackPacket(packet.EVENT, data={'foo': b'bar'}) + 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'} + assert p2.data == {"foo": b"bar"} def test_encode_binary_ack_packet(self): - p = msgpack_packet.MsgPackPacket(packet.ACK, data={'foo': b'bar'}) + 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'} + assert p2.data == {"foo": b"bar"} diff --git a/tests/common/test_namespace.py b/tests/common/test_namespace.py index 7967cec..e42d20c 100644 --- a/tests/common/test_namespace.py +++ b/tests/common/test_namespace.py @@ -10,262 +10,247 @@ class TestNamespace(unittest.TestCase): class MyNamespace(namespace.Namespace): def on_connect(self, sid, environ): - result['result'] = (sid, environ) + result["result"] = (sid, environ) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - ns.trigger_event('connect', 'sid', {'foo': 'bar'}) - assert result['result'] == ('sid', {'foo': 'bar'}) + ns.trigger_event("connect", "sid", {"foo": "bar"}) + assert result["result"] == ("sid", {"foo": "bar"}) def test_disconnect_event(self): result = {} class MyNamespace(namespace.Namespace): def on_disconnect(self, sid): - result['result'] = sid + result["result"] = sid - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - ns.trigger_event('disconnect', 'sid') - assert result['result'] == 'sid' + ns.trigger_event("disconnect", "sid") + assert result["result"] == "sid" def test_event(self): result = {} class MyNamespace(namespace.Namespace): def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - ns.trigger_event('custom_message', 'sid', {'data': 'data'}) - assert result['result'] == ('sid', {'data': 'data'}) + ns.trigger_event("custom_message", "sid", {"data": "data"}) + assert result["result"] == ("sid", {"data": "data"}) def test_event_not_found(self): result = {} class MyNamespace(namespace.Namespace): def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_server(mock.MagicMock()) - ns.trigger_event('another_custom_message', 'sid', {'data': 'data'}) + ns.trigger_event("another_custom_message", "sid", {"data": "data"}) assert result == {} def test_emit(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.emit('ev', data='data', to='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', - to='room', + "ev", + data="data", + to="room", room=None, - skip_sid='skip', - namespace='/foo', - callback='cb', + skip_sid="skip", + namespace="/foo", + callback="cb", ignore_queue=False, ) ns.emit( - 'ev', - data='data', - room='room', - skip_sid='skip', - namespace='/bar', - callback='cb', + "ev", + data="data", + room="room", + skip_sid="skip", + namespace="/bar", + callback="cb", ignore_queue=True, ) ns.server.emit.assert_called_with( - 'ev', - data='data', + "ev", + data="data", to=None, - room='room', - skip_sid='skip', - namespace='/bar', - callback='cb', + room="room", + skip_sid="skip", + namespace="/bar", + callback="cb", ignore_queue=True, ) def test_send(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.send(data='data', to='room', skip_sid='skip', callback='cb') + ns.send(data="data", to="room", skip_sid="skip", callback="cb") ns.server.send.assert_called_with( - 'data', - to='room', + "data", + to="room", room=None, - skip_sid='skip', - namespace='/foo', - callback='cb', + skip_sid="skip", + namespace="/foo", + callback="cb", ignore_queue=False, ) ns.send( - data='data', - room='room', - skip_sid='skip', - namespace='/bar', - callback='cb', + data="data", + room="room", + skip_sid="skip", + namespace="/bar", + callback="cb", ignore_queue=True, ) ns.server.send.assert_called_with( - 'data', + "data", to=None, - room='room', - skip_sid='skip', - namespace='/bar', - callback='cb', + room="room", + skip_sid="skip", + namespace="/bar", + callback="cb", ignore_queue=True, ) def test_call(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.call('ev', data='data', to='sid') + ns.call("ev", data="data", to="sid") ns.server.call.assert_called_with( - 'ev', - data='data', - to='sid', + "ev", + data="data", + to="sid", sid=None, - namespace='/foo', + namespace="/foo", timeout=None, ignore_queue=False, ) ns.call( - 'ev', - data='data', - sid='sid', - namespace='/bar', + "ev", + data="data", + sid="sid", + namespace="/bar", timeout=45, ignore_queue=True, ) ns.server.call.assert_called_with( - 'ev', - data='data', + "ev", + data="data", to=None, - sid='sid', - namespace='/bar', + sid="sid", + namespace="/bar", timeout=45, ignore_queue=True, ) def test_enter_room(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.enter_room('sid', 'room') - ns.server.enter_room.assert_called_with( - 'sid', 'room', namespace='/foo' - ) - ns.enter_room('sid', 'room', namespace='/bar') - ns.server.enter_room.assert_called_with( - 'sid', 'room', namespace='/bar' - ) + ns.enter_room("sid", "room") + ns.server.enter_room.assert_called_with("sid", "room", namespace="/foo") + ns.enter_room("sid", "room", namespace="/bar") + ns.server.enter_room.assert_called_with("sid", "room", namespace="/bar") def test_leave_room(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.leave_room('sid', 'room') - ns.server.leave_room.assert_called_with( - 'sid', 'room', namespace='/foo' - ) - ns.leave_room('sid', 'room', namespace='/bar') - ns.server.leave_room.assert_called_with( - 'sid', 'room', namespace='/bar' - ) + ns.leave_room("sid", "room") + ns.server.leave_room.assert_called_with("sid", "room", namespace="/foo") + ns.leave_room("sid", "room", namespace="/bar") + ns.server.leave_room.assert_called_with("sid", "room", namespace="/bar") def test_close_room(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.close_room('room') - ns.server.close_room.assert_called_with('room', namespace='/foo') - ns.close_room('room', namespace='/bar') - ns.server.close_room.assert_called_with('room', namespace='/bar') + ns.close_room("room") + ns.server.close_room.assert_called_with("room", namespace="/foo") + ns.close_room("room", namespace="/bar") + ns.server.close_room.assert_called_with("room", namespace="/bar") def test_rooms(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.rooms('sid') - ns.server.rooms.assert_called_with('sid', namespace='/foo') - ns.rooms('sid', namespace='/bar') - ns.server.rooms.assert_called_with('sid', namespace='/bar') + ns.rooms("sid") + ns.server.rooms.assert_called_with("sid", namespace="/foo") + ns.rooms("sid", namespace="/bar") + ns.server.rooms.assert_called_with("sid", namespace="/bar") def test_session(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.get_session('sid') - ns.server.get_session.assert_called_with('sid', namespace='/foo') - ns.get_session('sid', namespace='/bar') - ns.server.get_session.assert_called_with('sid', namespace='/bar') - ns.save_session('sid', {'a': 'b'}) - ns.server.save_session.assert_called_with( - 'sid', {'a': 'b'}, namespace='/foo' - ) - ns.save_session('sid', {'a': 'b'}, namespace='/bar') - ns.server.save_session.assert_called_with( - 'sid', {'a': 'b'}, namespace='/bar' - ) - ns.session('sid') - ns.server.session.assert_called_with('sid', namespace='/foo') - ns.session('sid', namespace='/bar') - ns.server.session.assert_called_with('sid', namespace='/bar') + ns.get_session("sid") + ns.server.get_session.assert_called_with("sid", namespace="/foo") + ns.get_session("sid", namespace="/bar") + ns.server.get_session.assert_called_with("sid", namespace="/bar") + ns.save_session("sid", {"a": "b"}) + ns.server.save_session.assert_called_with("sid", {"a": "b"}, namespace="/foo") + ns.save_session("sid", {"a": "b"}, namespace="/bar") + ns.server.save_session.assert_called_with("sid", {"a": "b"}, namespace="/bar") + ns.session("sid") + ns.server.session.assert_called_with("sid", namespace="/foo") + ns.session("sid", namespace="/bar") + ns.server.session.assert_called_with("sid", namespace="/bar") def test_disconnect(self): - ns = namespace.Namespace('/foo') + ns = namespace.Namespace("/foo") ns._set_server(mock.MagicMock()) - ns.disconnect('sid') - ns.server.disconnect.assert_called_with('sid', namespace='/foo') - ns.disconnect('sid', namespace='/bar') - ns.server.disconnect.assert_called_with('sid', namespace='/bar') + ns.disconnect("sid") + ns.server.disconnect.assert_called_with("sid", namespace="/foo") + ns.disconnect("sid", namespace="/bar") + ns.server.disconnect.assert_called_with("sid", namespace="/bar") def test_event_not_found_client(self): result = {} class MyNamespace(namespace.ClientNamespace): def on_custom_message(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) - ns = MyNamespace('/foo') + ns = MyNamespace("/foo") ns._set_client(mock.MagicMock()) - ns.trigger_event('another_custom_message', 'sid', {'data': 'data'}) + ns.trigger_event("another_custom_message", "sid", {"data": "data"}) assert result == {} def test_emit_client(self): - ns = namespace.ClientNamespace('/foo') + ns = namespace.ClientNamespace("/foo") ns._set_client(mock.MagicMock()) - ns.emit('ev', data='data', callback='cb') + ns.emit("ev", data="data", callback="cb") ns.client.emit.assert_called_with( - 'ev', data='data', namespace='/foo', callback='cb' + "ev", data="data", namespace="/foo", callback="cb" ) - ns.emit('ev', data='data', namespace='/bar', callback='cb') + ns.emit("ev", data="data", namespace="/bar", callback="cb") ns.client.emit.assert_called_with( - 'ev', data='data', namespace='/bar', callback='cb' + "ev", data="data", namespace="/bar", callback="cb" ) def test_send_client(self): - ns = namespace.ClientNamespace('/foo') + ns = namespace.ClientNamespace("/foo") ns._set_client(mock.MagicMock()) - ns.send(data='data', callback='cb') - ns.client.send.assert_called_with( - 'data', namespace='/foo', callback='cb' - ) - ns.send(data='data', namespace='/bar', callback='cb') - ns.client.send.assert_called_with( - 'data', namespace='/bar', callback='cb' - ) + ns.send(data="data", callback="cb") + ns.client.send.assert_called_with("data", namespace="/foo", callback="cb") + ns.send(data="data", namespace="/bar", callback="cb") + ns.client.send.assert_called_with("data", namespace="/bar", callback="cb") def test_call_client(self): - ns = namespace.ClientNamespace('/foo') + ns = namespace.ClientNamespace("/foo") ns._set_client(mock.MagicMock()) - ns.call('ev', data='data') + 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) + "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 + "ev", data="data", namespace="/bar", timeout=45 ) def test_disconnect_client(self): - ns = namespace.ClientNamespace('/foo') + ns = namespace.ClientNamespace("/foo") ns._set_client(mock.MagicMock()) ns.disconnect() ns.client.disconnect.assert_called_with() diff --git a/tests/common/test_packet.py b/tests/common/test_packet.py index 1dcc8f0..4e08feb 100644 --- a/tests/common/test_packet.py +++ b/tests/common/test_packet.py @@ -13,130 +13,124 @@ class TestPacket(unittest.TestCase): assert pkt.namespace is None assert pkt.id is None assert pkt.attachment_count == 0 - assert pkt.encode() == '2' + assert pkt.encode() == "2" def test_decode_default_packet(self): - pkt = packet.Packet(encoded_packet='2') - assert pkt.encode(), '2' + pkt = packet.Packet(encoded_packet="2") + assert pkt.encode(), "2" def test_encode_text_event_packet(self): - pkt = packet.Packet( - packet_type=packet.EVENT, data=['foo'] - ) + pkt = packet.Packet(packet_type=packet.EVENT, data=["foo"]) assert pkt.packet_type == packet.EVENT - assert pkt.data == ['foo'] + assert pkt.data == ["foo"] assert pkt.encode() == '2["foo"]' def test_decode_text_event_packet(self): pkt = packet.Packet(encoded_packet='2["foo"]') assert pkt.packet_type == packet.EVENT - assert pkt.data == ['foo'] + assert pkt.data == ["foo"] assert pkt.encode() == '2["foo"]' def test_decode_empty_event_packet(self): - pkt = packet.Packet(encoded_packet='1') + pkt = packet.Packet(encoded_packet="1") assert pkt.packet_type == packet.DISCONNECT # same thing, but with a numeric payload pkt = packet.Packet(encoded_packet=1) assert pkt.packet_type == packet.DISCONNECT def test_encode_binary_event_packet(self): - pkt = packet.Packet(packet_type=packet.EVENT, data=b'1234') + pkt = packet.Packet(packet_type=packet.EVENT, data=b"1234") assert pkt.packet_type == packet.BINARY_EVENT - assert pkt.data == b'1234' - a = ['51-{"_placeholder":true,"num":0}', b'1234'] - b = ['51-{"num":0,"_placeholder":true}', b'1234'] + assert pkt.data == b"1234" + a = ['51-{"_placeholder":true,"num":0}', b"1234"] + b = ['51-{"num":0,"_placeholder":true}', b"1234"] encoded_packet = pkt.encode() assert encoded_packet == a or encoded_packet == b def test_decode_binary_event_packet(self): pkt = packet.Packet(encoded_packet='51-{"_placeholder":true,"num":0}') - assert pkt.add_attachment(b'1234') + assert pkt.add_attachment(b"1234") assert pkt.packet_type == packet.BINARY_EVENT - assert pkt.data == b'1234' + assert pkt.data == b"1234" def test_encode_text_ack_packet(self): - pkt = packet.Packet( - packet_type=packet.ACK, data=['foo'] - ) + pkt = packet.Packet(packet_type=packet.ACK, data=["foo"]) assert pkt.packet_type == packet.ACK - assert pkt.data == ['foo'] + assert pkt.data == ["foo"] assert pkt.encode() == '3["foo"]' def test_decode_text_ack_packet(self): pkt = packet.Packet(encoded_packet='3["foo"]') assert pkt.packet_type == packet.ACK - assert pkt.data == ['foo'] + assert pkt.data == ["foo"] assert pkt.encode() == '3["foo"]' def test_encode_binary_ack_packet(self): - pkt = packet.Packet(packet_type=packet.ACK, data=b'1234') + pkt = packet.Packet(packet_type=packet.ACK, data=b"1234") assert pkt.packet_type == packet.BINARY_ACK - assert pkt.data == b'1234' - a = ['61-{"_placeholder":true,"num":0}', b'1234'] - b = ['61-{"num":0,"_placeholder":true}', b'1234'] + assert pkt.data == b"1234" + a = ['61-{"_placeholder":true,"num":0}', b"1234"] + b = ['61-{"num":0,"_placeholder":true}', b"1234"] encoded_packet = pkt.encode() assert encoded_packet == a or encoded_packet == b def test_decode_binary_ack_packet(self): pkt = packet.Packet(encoded_packet='61-{"_placeholder":true,"num":0}') - assert pkt.add_attachment(b'1234') + assert pkt.add_attachment(b"1234") assert pkt.packet_type == packet.BINARY_ACK - assert pkt.data == b'1234' + assert pkt.data == b"1234" def test_invalid_binary_packet(self): with pytest.raises(ValueError): - packet.Packet(packet_type=packet.CONNECT_ERROR, data=b'123') + packet.Packet(packet_type=packet.CONNECT_ERROR, data=b"123") def test_encode_namespace(self): pkt = packet.Packet( packet_type=packet.EVENT, - data=['foo'], - namespace='/bar', + data=["foo"], + namespace="/bar", ) - assert pkt.namespace == '/bar' + assert pkt.namespace == "/bar" assert pkt.encode() == '2/bar,["foo"]' def test_decode_namespace(self): pkt = packet.Packet(encoded_packet='2/bar,["foo"]') - assert pkt.namespace == '/bar' + assert pkt.namespace == "/bar" assert pkt.encode() == '2/bar,["foo"]' def test_decode_namespace_with_query_string(self): # some Socket.IO clients mistakenly attach the query string to the # namespace pkt = packet.Packet(encoded_packet='2/bar?a=b,["foo"]') - assert pkt.namespace == '/bar' + assert pkt.namespace == "/bar" assert pkt.encode() == '2/bar,["foo"]' def test_encode_namespace_no_data(self): - pkt = packet.Packet(packet_type=packet.EVENT, namespace='/bar') - assert pkt.encode() == '2/bar,' + pkt = packet.Packet(packet_type=packet.EVENT, namespace="/bar") + assert pkt.encode() == "2/bar," def test_decode_namespace_no_data(self): - pkt = packet.Packet(encoded_packet='2/bar,') - assert pkt.namespace == '/bar' + pkt = packet.Packet(encoded_packet="2/bar,") + assert pkt.namespace == "/bar" assert pkt.data is None - assert pkt.encode() == '2/bar,' + assert pkt.encode() == "2/bar," def test_encode_namespace_with_hyphens(self): pkt = packet.Packet( packet_type=packet.EVENT, - data=['foo'], - namespace='/b-a-r', + data=["foo"], + namespace="/b-a-r", ) - assert pkt.namespace == '/b-a-r' + assert pkt.namespace == "/b-a-r" assert pkt.encode() == '2/b-a-r,["foo"]' def test_decode_namespace_with_hyphens(self): pkt = packet.Packet(encoded_packet='2/b-a-r,["foo"]') - assert pkt.namespace == '/b-a-r' + assert pkt.namespace == "/b-a-r" assert pkt.encode() == '2/b-a-r,["foo"]' def test_encode_event_with_hyphens(self): - pkt = packet.Packet( - packet_type=packet.EVENT, data=['f-o-o'] - ) + pkt = packet.Packet(packet_type=packet.EVENT, data=["f-o-o"]) assert pkt.namespace is None assert pkt.encode() == '2["f-o-o"]' @@ -146,9 +140,7 @@ class TestPacket(unittest.TestCase): assert pkt.encode() == '2["f-o-o"]' def test_encode_id(self): - pkt = packet.Packet( - packet_type=packet.EVENT, data=['foo'], id=123 - ) + pkt = packet.Packet(packet_type=packet.EVENT, data=["foo"], id=123) assert pkt.id == 123 assert pkt.encode() == '2123["foo"]' @@ -158,66 +150,66 @@ class TestPacket(unittest.TestCase): assert pkt.encode() == '2123["foo"]' def test_decode_id_long(self): - pkt = packet.Packet(encoded_packet='2' + '1' * 100 + '["foo"]') - assert pkt.id == int('1' * 100) - assert pkt.data == ['foo'] + pkt = packet.Packet(encoded_packet="2" + "1" * 100 + '["foo"]') + assert pkt.id == int("1" * 100) + assert pkt.data == ["foo"] def test_decode_id_too_long(self): with pytest.raises(ValueError): - packet.Packet(encoded_packet='2' + '1' * 101) + packet.Packet(encoded_packet="2" + "1" * 101) with pytest.raises(ValueError): - packet.Packet(encoded_packet='2' + '1' * 101 + '["foo"]') + packet.Packet(encoded_packet="2" + "1" * 101 + '["foo"]') def test_encode_id_no_data(self): pkt = packet.Packet(packet_type=packet.EVENT, id=123) assert pkt.id == 123 assert pkt.data is None - assert pkt.encode() == '2123' + assert pkt.encode() == "2123" def test_decode_id_no_data(self): - pkt = packet.Packet(encoded_packet='2123') + pkt = packet.Packet(encoded_packet="2123") assert pkt.id == 123 assert pkt.data is None - assert pkt.encode() == '2123' + assert pkt.encode() == "2123" def test_encode_namespace_and_id(self): pkt = packet.Packet( packet_type=packet.EVENT, - data=['foo'], - namespace='/bar', + data=["foo"], + namespace="/bar", id=123, ) - assert pkt.namespace == '/bar' + assert pkt.namespace == "/bar" assert pkt.id == 123 assert pkt.encode() == '2/bar,123["foo"]' def test_decode_namespace_and_id(self): pkt = packet.Packet(encoded_packet='2/bar,123["foo"]') - assert pkt.namespace == '/bar' + assert pkt.namespace == "/bar" assert pkt.id == 123 assert pkt.encode() == '2/bar,123["foo"]' def test_encode_many_binary(self): pkt = packet.Packet( packet_type=packet.EVENT, - data={'a': '123', 'b': b'456', 'c': [b'789', 123]}, + data={"a": "123", "b": b"456", "c": [b"789", 123]}, ) assert pkt.packet_type == packet.BINARY_EVENT ep = pkt.encode() assert len(ep) == 3 - assert b'456' in ep - assert b'789' in ep + assert b"456" in ep + assert b"789" in ep def test_encode_many_binary_ack(self): pkt = packet.Packet( packet_type=packet.ACK, - data={'a': '123', 'b': b'456', 'c': [b'789', 123]}, + data={"a": "123", "b": b"456", "c": [b"789", 123]}, ) assert pkt.packet_type == packet.BINARY_ACK ep = pkt.encode() assert len(ep) == 3 - assert b'456' in ep - assert b'789' in ep + assert b"456" in ep + assert b"789" in ep def test_decode_many_binary(self): pkt = packet.Packet( @@ -226,12 +218,12 @@ class TestPacket(unittest.TestCase): '"c":[{"_placeholder":true,"num":1},123]}' ) ) - assert not pkt.add_attachment(b'456') - assert pkt.add_attachment(b'789') + assert not pkt.add_attachment(b"456") + assert pkt.add_attachment(b"789") assert pkt.packet_type == packet.BINARY_EVENT - assert pkt.data['a'] == '123' - assert pkt.data['b'] == b'456' - assert pkt.data['c'] == [b'789', 123] + assert pkt.data["a"] == "123" + assert pkt.data["b"] == b"456" + assert pkt.data["c"] == [b"789", 123] def test_decode_many_binary_ack(self): pkt = packet.Packet( @@ -240,12 +232,12 @@ class TestPacket(unittest.TestCase): '"c":[{"_placeholder":true,"num":1},123]}' ) ) - assert not pkt.add_attachment(b'456') - assert pkt.add_attachment(b'789') + assert not pkt.add_attachment(b"456") + assert pkt.add_attachment(b"789") assert pkt.packet_type == packet.BINARY_ACK - assert pkt.data['a'] == '123' - assert pkt.data['b'] == b'456' - assert pkt.data['c'] == [b'789', 123] + assert pkt.data["a"] == "123" + assert pkt.data["b"] == b"456" + assert pkt.data["c"] == [b"789", 123] def test_decode_too_many_binary_packets(self): pkt = packet.Packet( @@ -254,14 +246,14 @@ class TestPacket(unittest.TestCase): '"c":[{"_placeholder":true,"num":1},123]}' ) ) - assert not pkt.add_attachment(b'456') - assert pkt.add_attachment(b'789') + assert not pkt.add_attachment(b"456") + assert pkt.add_attachment(b"789") with pytest.raises(ValueError): - pkt.add_attachment(b'123') + pkt.add_attachment(b"123") def test_decode_attachment_count_too_long(self): with pytest.raises(ValueError): - packet.Packet(encoded_packet='6' + ('1' * 11) + '-{"a":"123"}') + packet.Packet(encoded_packet="6" + ("1" * 11) + '-{"a":"123"}') def test_decode_dash_in_payload(self): pkt = packet.Packet(encoded_packet='6{"a":"0123456789-"}') @@ -270,14 +262,14 @@ class TestPacket(unittest.TestCase): def test_data_is_binary_list(self): pkt = packet.Packet() - assert not pkt._data_is_binary(['foo']) + 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 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({"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 pkt._data_is_binary({"a": b"foo"}) + assert pkt._data_is_binary({"a": "foo", "b": b"bar"}) diff --git a/tests/common/test_pubsub_manager.py b/tests/common/test_pubsub_manager.py index 4e97214..25e7b0e 100644 --- a/tests/common/test_pubsub_manager.py +++ b/tests/common/test_pubsub_manager.py @@ -25,18 +25,16 @@ class TestPubSubManager(unittest.TestCase): self.pm = pubsub_manager.PubSubManager() self.pm._publish = mock.MagicMock() self.pm.set_server(mock_server) - self.pm.host_id = '123456' + self.pm.host_id = "123456" self.pm.initialize() def test_default_init(self): - assert self.pm.channel == 'socketio' - self.pm.server.start_background_task.assert_called_once_with( - self.pm._thread - ) + assert self.pm.channel == "socketio" + self.pm.server.start_background_task.assert_called_once_with(self.pm._thread) def test_custom_init(self): - pubsub = pubsub_manager.PubSubManager(channel='foo') - assert pubsub.channel == 'foo' + pubsub = pubsub_manager.PubSubManager(channel="foo") + assert pubsub.channel == "foo" assert len(pubsub.host_id) == 32 def test_write_only_init(self): @@ -44,190 +42,210 @@ class TestPubSubManager(unittest.TestCase): pm = pubsub_manager.PubSubManager(write_only=True) pm.set_server(mock_server) pm.initialize() - assert pm.channel == 'socketio' + assert pm.channel == "socketio" assert len(pm.host_id) == 32 assert pm.server.start_background_task.call_count == 0 def test_write_only_default_logger(self): pm = pubsub_manager.PubSubManager(write_only=True) pm.initialize() - assert pm.channel == 'socketio' + assert pm.channel == "socketio" assert len(pm.host_id) == 32 - assert pm._get_logger() == logging.getLogger('socketio') + assert pm._get_logger() == logging.getLogger("socketio") def test_write_only_with_provided_logger(self): - test_logger = logging.getLogger('new_logger') + test_logger = logging.getLogger("new_logger") pm = pubsub_manager.PubSubManager(write_only=True, logger=test_logger) pm.initialize() - assert pm.channel == 'socketio' + assert pm.channel == "socketio" assert len(pm.host_id) == 32 assert pm._get_logger() == test_logger def test_emit(self): - self.pm.emit('foo', 'bar') + self.pm.emit("foo", "bar") self.pm._publish.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/', - 'room': None, - 'skip_sid': None, - 'callback': None, - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/", + "room": None, + "skip_sid": None, + "callback": None, + "host_id": "123456", } ) def test_emit_with_namespace(self): - self.pm.emit('foo', 'bar', namespace='/baz') + self.pm.emit("foo", "bar", namespace="/baz") self.pm._publish.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/baz', - 'room': None, - 'skip_sid': None, - 'callback': None, - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/baz", + "room": None, + "skip_sid": None, + "callback": None, + "host_id": "123456", } ) def test_emit_with_room(self): - self.pm.emit('foo', 'bar', room='baz') + self.pm.emit("foo", "bar", room="baz") self.pm._publish.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/', - 'room': 'baz', - 'skip_sid': None, - 'callback': None, - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/", + "room": "baz", + "skip_sid": None, + "callback": None, + "host_id": "123456", } ) def test_emit_with_skip_sid(self): - self.pm.emit('foo', 'bar', skip_sid='baz') + self.pm.emit("foo", "bar", skip_sid="baz") self.pm._publish.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/', - 'room': None, - 'skip_sid': 'baz', - 'callback': None, - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/", + "room": None, + "skip_sid": "baz", + "callback": None, + "host_id": "123456", } ) def test_emit_with_callback(self): - with mock.patch.object( - self.pm, '_generate_ack_id', return_value='123' - ): - self.pm.emit('foo', 'bar', room='baz', callback='cb') + with mock.patch.object(self.pm, "_generate_ack_id", return_value="123"): + self.pm.emit("foo", "bar", room="baz", callback="cb") self.pm._publish.assert_called_once_with( { - 'method': 'emit', - 'event': 'foo', - 'data': 'bar', - 'namespace': '/', - 'room': 'baz', - 'skip_sid': None, - 'callback': ('baz', '/', '123'), - 'host_id': '123456', + "method": "emit", + "event": "foo", + "data": "bar", + "namespace": "/", + "room": "baz", + "skip_sid": None, + "callback": ("baz", "/", "123"), + "host_id": "123456", } ) def test_emit_with_callback_without_server(self): standalone_pm = pubsub_manager.PubSubManager() with pytest.raises(RuntimeError): - standalone_pm.emit('foo', 'bar', callback='cb') + standalone_pm.emit("foo", "bar", callback="cb") def test_emit_with_callback_missing_room(self): - with mock.patch.object( - self.pm, '_generate_ack_id', return_value='123' - ): + with mock.patch.object(self.pm, "_generate_ack_id", return_value="123"): with pytest.raises(ValueError): - self.pm.emit('foo', 'bar', callback='cb') + self.pm.emit("foo", "bar", callback="cb") def test_emit_with_ignore_queue(self): - sid = self.pm.connect('123', '/') - self.pm.emit( - 'foo', 'bar', room=sid, namespace='/', ignore_queue=True - ) + sid = self.pm.connect("123", "/") + self.pm.emit("foo", "bar", room=sid, namespace="/", ignore_queue=True) self.pm._publish.assert_not_called() assert self.pm.server._send_eio_packet.call_count == 1 - assert self.pm.server._send_eio_packet.call_args_list[0][0][0] == '123' + assert self.pm.server._send_eio_packet.call_args_list[0][0][0] == "123" pkt = self.pm.server._send_eio_packet.call_args_list[0][0][1] assert pkt.encode() == '42["foo","bar"]' def test_can_disconnect(self): - sid = self.pm.connect('123', '/') - assert self.pm.can_disconnect(sid, '/') - self.pm.can_disconnect(sid, '/foo') + sid = self.pm.connect("123", "/") + assert self.pm.can_disconnect(sid, "/") + self.pm.can_disconnect(sid, "/foo") self.pm._publish.assert_called_once_with( - {'method': 'disconnect', 'sid': sid, 'namespace': '/foo', - 'host_id': '123456'} + { + "method": "disconnect", + "sid": sid, + "namespace": "/foo", + "host_id": "123456", + } ) def test_disconnect(self): - self.pm.disconnect('foo') + self.pm.disconnect("foo") self.pm._publish.assert_called_once_with( - {'method': 'disconnect', 'sid': 'foo', 'namespace': '/', - 'host_id': '123456'} + { + "method": "disconnect", + "sid": "foo", + "namespace": "/", + "host_id": "123456", + } ) def test_disconnect_ignore_queue(self): - sid = self.pm.connect('123', '/') - self.pm.pre_disconnect(sid, '/') + sid = self.pm.connect("123", "/") + self.pm.pre_disconnect(sid, "/") self.pm.disconnect(sid, ignore_queue=True) self.pm._publish.assert_not_called() - assert not self.pm.is_connected(sid, '/') + assert not self.pm.is_connected(sid, "/") def test_enter_room(self): - sid = self.pm.connect('123', '/') - self.pm.enter_room(sid, '/', 'foo') - self.pm.enter_room('456', '/', 'foo') - assert sid in self.pm.rooms['/']['foo'] - assert self.pm.rooms['/']['foo'][sid] == '123' + sid = self.pm.connect("123", "/") + self.pm.enter_room(sid, "/", "foo") + self.pm.enter_room("456", "/", "foo") + assert sid in self.pm.rooms["/"]["foo"] + assert self.pm.rooms["/"]["foo"][sid] == "123" self.pm._publish.assert_called_once_with( - {'method': 'enter_room', 'sid': '456', 'room': 'foo', - 'namespace': '/', 'host_id': '123456'} + { + "method": "enter_room", + "sid": "456", + "room": "foo", + "namespace": "/", + "host_id": "123456", + } ) def test_leave_room(self): - sid = self.pm.connect('123', '/') - self.pm.leave_room(sid, '/', 'foo') - self.pm.leave_room('456', '/', 'foo') - assert 'foo' not in self.pm.rooms['/'] + sid = self.pm.connect("123", "/") + self.pm.leave_room(sid, "/", "foo") + self.pm.leave_room("456", "/", "foo") + assert "foo" not in self.pm.rooms["/"] self.pm._publish.assert_called_once_with( - {'method': 'leave_room', 'sid': '456', 'room': 'foo', - 'namespace': '/', 'host_id': '123456'} + { + "method": "leave_room", + "sid": "456", + "room": "foo", + "namespace": "/", + "host_id": "123456", + } ) def test_close_room(self): - self.pm.close_room('foo') + self.pm.close_room("foo") self.pm._publish.assert_called_once_with( - {'method': 'close_room', 'room': 'foo', 'namespace': '/', - 'host_id': '123456'} + { + "method": "close_room", + "room": "foo", + "namespace": "/", + "host_id": "123456", + } ) def test_close_room_with_namespace(self): - self.pm.close_room('foo', '/bar') + self.pm.close_room("foo", "/bar") self.pm._publish.assert_called_once_with( - {'method': 'close_room', 'room': 'foo', 'namespace': '/bar', - 'host_id': '123456'} + { + "method": "close_room", + "room": "foo", + "namespace": "/bar", + "host_id": "123456", + } ) def test_handle_emit(self): - with mock.patch.object(manager.Manager, 'emit') as super_emit: - self.pm._handle_emit({'event': 'foo', 'data': 'bar'}) + with mock.patch.object(manager.Manager, "emit") as super_emit: + self.pm._handle_emit({"event": "foo", "data": "bar"}) super_emit.assert_called_once_with( - 'foo', - 'bar', + "foo", + "bar", namespace=None, room=None, skip_sid=None, @@ -235,210 +253,186 @@ class TestPubSubManager(unittest.TestCase): ) def test_handle_emit_with_namespace(self): - with mock.patch.object(manager.Manager, 'emit') as super_emit: - self.pm._handle_emit( - {'event': 'foo', 'data': 'bar', 'namespace': '/baz'} - ) + with mock.patch.object(manager.Manager, "emit") as super_emit: + self.pm._handle_emit({"event": "foo", "data": "bar", "namespace": "/baz"}) super_emit.assert_called_once_with( - 'foo', - 'bar', - namespace='/baz', + "foo", + "bar", + namespace="/baz", room=None, skip_sid=None, callback=None, ) def test_handle_emit_with_room(self): - with mock.patch.object(manager.Manager, 'emit') as super_emit: - self.pm._handle_emit( - {'event': 'foo', 'data': 'bar', 'room': 'baz'} - ) + with mock.patch.object(manager.Manager, "emit") as super_emit: + self.pm._handle_emit({"event": "foo", "data": "bar", "room": "baz"}) super_emit.assert_called_once_with( - 'foo', - 'bar', + "foo", + "bar", namespace=None, - room='baz', + room="baz", skip_sid=None, callback=None, ) def test_handle_emit_with_skip_sid(self): - with mock.patch.object(manager.Manager, 'emit') as super_emit: - self.pm._handle_emit( - {'event': 'foo', 'data': 'bar', 'skip_sid': '123'} - ) + with mock.patch.object(manager.Manager, "emit") as super_emit: + self.pm._handle_emit({"event": "foo", "data": "bar", "skip_sid": "123"}) super_emit.assert_called_once_with( - 'foo', - 'bar', + "foo", + "bar", namespace=None, room=None, - skip_sid='123', + skip_sid="123", callback=None, ) def test_handle_emit_with_remote_callback(self): - with mock.patch.object(manager.Manager, 'emit') as super_emit: + with mock.patch.object(manager.Manager, "emit") as super_emit: self.pm._handle_emit( { - 'event': 'foo', - 'data': 'bar', - 'namespace': '/baz', - 'callback': ('sid', '/baz', 123), - 'host_id': 'x', + "event": "foo", + "data": "bar", + "namespace": "/baz", + "callback": ("sid", "/baz", 123), + "host_id": "x", } ) assert super_emit.call_count == 1 - assert super_emit.call_args[0] == ('foo', 'bar') - assert super_emit.call_args[1]['namespace'] == '/baz' - assert super_emit.call_args[1]['room'] is None - assert super_emit.call_args[1]['skip_sid'] is None - assert isinstance( - super_emit.call_args[1]['callback'], functools.partial - ) - super_emit.call_args[1]['callback']('one', 2, 'three') + assert super_emit.call_args[0] == ("foo", "bar") + assert super_emit.call_args[1]["namespace"] == "/baz" + assert super_emit.call_args[1]["room"] is None + assert super_emit.call_args[1]["skip_sid"] is None + assert isinstance(super_emit.call_args[1]["callback"], functools.partial) + super_emit.call_args[1]["callback"]("one", 2, "three") self.pm._publish.assert_called_once_with( { - 'method': 'callback', - 'host_id': 'x', - 'sid': 'sid', - 'namespace': '/baz', - 'id': 123, - 'args': ('one', 2, 'three'), + "method": "callback", + "host_id": "x", + "sid": "sid", + "namespace": "/baz", + "id": 123, + "args": ("one", 2, "three"), } ) def test_handle_emit_with_local_callback(self): - with mock.patch.object(manager.Manager, 'emit') as super_emit: + with mock.patch.object(manager.Manager, "emit") as super_emit: self.pm._handle_emit( { - 'event': 'foo', - 'data': 'bar', - 'namespace': '/baz', - 'callback': ('sid', '/baz', 123), - 'host_id': self.pm.host_id, + "event": "foo", + "data": "bar", + "namespace": "/baz", + "callback": ("sid", "/baz", 123), + "host_id": self.pm.host_id, } ) assert super_emit.call_count == 1 - assert super_emit.call_args[0] == ('foo', 'bar') - assert super_emit.call_args[1]['namespace'] == '/baz' - assert super_emit.call_args[1]['room'] is None - assert super_emit.call_args[1]['skip_sid'] is None - assert isinstance( - super_emit.call_args[1]['callback'], functools.partial - ) - super_emit.call_args[1]['callback']('one', 2, 'three') + assert super_emit.call_args[0] == ("foo", "bar") + assert super_emit.call_args[1]["namespace"] == "/baz" + assert super_emit.call_args[1]["room"] is None + assert super_emit.call_args[1]["skip_sid"] is None + assert isinstance(super_emit.call_args[1]["callback"], functools.partial) + super_emit.call_args[1]["callback"]("one", 2, "three") self.pm._publish.assert_not_called() def test_handle_callback(self): host_id = self.pm.host_id - with mock.patch.object(self.pm, 'trigger_callback') as trigger: + with mock.patch.object(self.pm, "trigger_callback") as trigger: self.pm._handle_callback( { - 'method': 'callback', - 'host_id': host_id, - 'sid': 'sid', - 'namespace': '/', - 'id': 123, - 'args': ('one', 2), + "method": "callback", + "host_id": host_id, + "sid": "sid", + "namespace": "/", + "id": 123, + "args": ("one", 2), } ) - trigger.assert_called_once_with('sid', 123, ('one', 2)) + trigger.assert_called_once_with("sid", 123, ("one", 2)) def test_handle_callback_bad_host_id(self): - with mock.patch.object(self.pm, 'trigger_callback') as trigger: + with mock.patch.object(self.pm, "trigger_callback") as trigger: self.pm._handle_callback( { - 'method': 'callback', - 'host_id': 'bad', - 'sid': 'sid', - 'namespace': '/', - 'id': 123, - 'args': ('one', 2), + "method": "callback", + "host_id": "bad", + "sid": "sid", + "namespace": "/", + "id": 123, + "args": ("one", 2), } ) assert trigger.call_count == 0 def test_handle_callback_missing_args(self): host_id = self.pm.host_id - with mock.patch.object(self.pm, 'trigger_callback') as trigger: + with mock.patch.object(self.pm, "trigger_callback") as trigger: self.pm._handle_callback( { - 'method': 'callback', - 'host_id': host_id, - 'sid': 'sid', - 'namespace': '/', - 'id': 123, + "method": "callback", + "host_id": host_id, + "sid": "sid", + "namespace": "/", + "id": 123, } ) self.pm._handle_callback( { - 'method': 'callback', - 'host_id': host_id, - 'sid': 'sid', - 'namespace': '/', + "method": "callback", + "host_id": host_id, + "sid": "sid", + "namespace": "/", } ) self.pm._handle_callback( - {'method': 'callback', 'host_id': host_id, 'sid': 'sid'} - ) - self.pm._handle_callback( - {'method': 'callback', 'host_id': host_id} + {"method": "callback", "host_id": host_id, "sid": "sid"} ) + self.pm._handle_callback({"method": "callback", "host_id": host_id}) assert trigger.call_count == 0 def test_handle_disconnect(self): self.pm._handle_disconnect( - {'method': 'disconnect', 'sid': '123', 'namespace': '/foo'} + {"method": "disconnect", "sid": "123", "namespace": "/foo"} ) self.pm.server.disconnect.assert_called_once_with( - sid='123', namespace='/foo', ignore_queue=True + sid="123", namespace="/foo", ignore_queue=True ) def test_handle_enter_room(self): - sid = self.pm.connect('123', '/') - with mock.patch.object( - manager.Manager, 'enter_room' - ) as super_enter_room: - self.pm._handle_enter_room({ - 'method': 'enter_room', 'sid': sid, 'namespace': '/', - 'room': 'foo'}) - self.pm._handle_enter_room({ - 'method': 'enter_room', 'sid': '456', 'namespace': '/', - 'room': 'foo'}) - super_enter_room.assert_called_once_with(sid, '/', 'foo') + sid = self.pm.connect("123", "/") + with mock.patch.object(manager.Manager, "enter_room") as super_enter_room: + self.pm._handle_enter_room( + {"method": "enter_room", "sid": sid, "namespace": "/", "room": "foo"} + ) + self.pm._handle_enter_room( + {"method": "enter_room", "sid": "456", "namespace": "/", "room": "foo"} + ) + super_enter_room.assert_called_once_with(sid, "/", "foo") def test_handle_leave_room(self): - sid = self.pm.connect('123', '/') - with mock.patch.object( - manager.Manager, 'leave_room' - ) as super_leave_room: - self.pm._handle_leave_room({ - 'method': 'leave_room', 'sid': sid, 'namespace': '/', - 'room': 'foo'}) - self.pm._handle_leave_room({ - 'method': 'leave_room', 'sid': '456', 'namespace': '/', - 'room': 'foo'}) - super_leave_room.assert_called_once_with(sid, '/', 'foo') + sid = self.pm.connect("123", "/") + with mock.patch.object(manager.Manager, "leave_room") as super_leave_room: + self.pm._handle_leave_room( + {"method": "leave_room", "sid": sid, "namespace": "/", "room": "foo"} + ) + self.pm._handle_leave_room( + {"method": "leave_room", "sid": "456", "namespace": "/", "room": "foo"} + ) + super_leave_room.assert_called_once_with(sid, "/", "foo") def test_handle_close_room(self): - with mock.patch.object( - manager.Manager, 'close_room' - ) as super_close_room: - self.pm._handle_close_room({'method': 'close_room', 'room': 'foo'}) - super_close_room.assert_called_once_with( - room='foo', namespace=None - ) + with mock.patch.object(manager.Manager, "close_room") as super_close_room: + self.pm._handle_close_room({"method": "close_room", "room": "foo"}) + super_close_room.assert_called_once_with(room="foo", namespace=None) def test_handle_close_room_with_namespace(self): - with mock.patch.object( - manager.Manager, 'close_room' - ) as super_close_room: + with mock.patch.object(manager.Manager, "close_room") as super_close_room: self.pm._handle_close_room( - {'method': 'close_room', 'room': 'foo', 'namespace': '/bar'} - ) - super_close_room.assert_called_once_with( - room='foo', namespace='/bar' + {"method": "close_room", "room": "foo", "namespace": "/bar"} ) + super_close_room.assert_called_once_with(room="foo", namespace="/bar") def test_background_thread(self): self.pm._handle_emit = mock.MagicMock() @@ -452,29 +446,47 @@ class TestPubSubManager(unittest.TestCase): def messages(): import pickle - yield {'method': 'emit', 'value': 'foo', 'host_id': 'x'} - yield {'missing': 'method', 'host_id': 'x'} + yield {"method": "emit", "value": "foo", "host_id": "x"} + yield {"missing": "method", "host_id": "x"} yield '{"method": "callback", "value": "bar", "host_id": "x"}' - yield {'method': 'disconnect', 'sid': '123', 'namespace': '/foo', - 'host_id': 'x'} - yield {'method': 'bogus', 'host_id': 'x'} - yield pickle.dumps({'method': 'close_room', 'value': 'baz', - 'host_id': 'x'}) - yield {'method': 'enter_room', 'sid': '123', 'namespace': '/foo', - 'room': 'room', 'host_id': 'x'} - yield {'method': 'leave_room', 'sid': '123', 'namespace': '/foo', - 'room': 'room', 'host_id': 'x'} - yield 'bad json' - yield b'bad pickled' + yield { + "method": "disconnect", + "sid": "123", + "namespace": "/foo", + "host_id": "x", + } + yield {"method": "bogus", "host_id": "x"} + yield pickle.dumps({"method": "close_room", "value": "baz", "host_id": "x"}) + yield { + "method": "enter_room", + "sid": "123", + "namespace": "/foo", + "room": "room", + "host_id": "x", + } + yield { + "method": "leave_room", + "sid": "123", + "namespace": "/foo", + "room": "room", + "host_id": "x", + } + yield "bad json" + yield b"bad pickled" # these should not publish anything on the queue, as they come from # the same host - yield {'method': 'emit', 'value': 'foo', 'host_id': host_id} - yield {'method': 'callback', 'value': 'bar', 'host_id': host_id} - yield {'method': 'disconnect', 'sid': '123', 'namespace': '/foo', - 'host_id': host_id} - yield pickle.dumps({'method': 'close_room', 'value': 'baz', - 'host_id': host_id}) + yield {"method": "emit", "value": "foo", "host_id": host_id} + yield {"method": "callback", "value": "bar", "host_id": host_id} + yield { + "method": "disconnect", + "sid": "123", + "namespace": "/foo", + "host_id": host_id, + } + yield pickle.dumps( + {"method": "close_room", "value": "baz", "host_id": host_id} + ) self.pm._listen = mock.MagicMock(side_effect=messages) try: @@ -483,36 +495,45 @@ class TestPubSubManager(unittest.TestCase): pass self.pm._handle_emit.assert_called_once_with( - {'method': 'emit', 'value': 'foo', 'host_id': 'x'} + {"method": "emit", "value": "foo", "host_id": "x"} ) self.pm._handle_callback.assert_any_call( - {'method': 'callback', 'value': 'bar', 'host_id': 'x'} + {"method": "callback", "value": "bar", "host_id": "x"} ) self.pm._handle_callback.assert_any_call( - {'method': 'callback', 'value': 'bar', 'host_id': host_id} + {"method": "callback", "value": "bar", "host_id": host_id} ) self.pm._handle_disconnect.assert_called_once_with( - {'method': 'disconnect', 'sid': '123', 'namespace': '/foo', - 'host_id': 'x'} + {"method": "disconnect", "sid": "123", "namespace": "/foo", "host_id": "x"} ) self.pm._handle_enter_room.assert_called_once_with( - {'method': 'enter_room', 'sid': '123', 'namespace': '/foo', - 'room': 'room', 'host_id': 'x'} + { + "method": "enter_room", + "sid": "123", + "namespace": "/foo", + "room": "room", + "host_id": "x", + } ) self.pm._handle_leave_room.assert_called_once_with( - {'method': 'leave_room', 'sid': '123', 'namespace': '/foo', - 'room': 'room', 'host_id': 'x'} + { + "method": "leave_room", + "sid": "123", + "namespace": "/foo", + "room": "room", + "host_id": "x", + } ) self.pm._handle_close_room.assert_called_once_with( - {'method': 'close_room', 'value': 'baz', 'host_id': 'x'} + {"method": "close_room", "value": "baz", "host_id": "x"} ) def test_background_thread_exception(self): self.pm._handle_emit = mock.MagicMock(side_effect=[ValueError(), None]) def messages(): - yield {'method': 'emit', 'value': 'foo', 'host_id': 'x'} - yield {'method': 'emit', 'value': 'bar', 'host_id': 'x'} + yield {"method": "emit", "value": "foo", "host_id": "x"} + yield {"method": "emit", "value": "bar", "host_id": "x"} self.pm._listen = mock.MagicMock(side_effect=messages) try: @@ -521,8 +542,8 @@ class TestPubSubManager(unittest.TestCase): pass self.pm._handle_emit.assert_any_call( - {'method': 'emit', 'value': 'foo', 'host_id': 'x'} + {"method": "emit", "value": "foo", "host_id": "x"} ) self.pm._handle_emit.assert_called_with( - {'method': 'emit', 'value': 'bar', 'host_id': 'x'} + {"method": "emit", "value": "bar", "host_id": "x"} ) diff --git a/tests/common/test_server.py b/tests/common/test_server.py index 08c59ac..d7d6cf3 100644 --- a/tests/common/test_server.py +++ b/tests/common/test_server.py @@ -13,8 +13,10 @@ from socketio import packet from socketio import server -@mock.patch('socketio.server.engineio.Server', **{ - 'return_value.generate_id.side_effect': [str(i) for i in range(1, 10)]}) +@mock.patch( + "socketio.server.engineio.Server", + **{"return_value.generate_id.side_effect": [str(i) for i in range(1, 10)]}, +) class TestServer(unittest.TestCase): def tearDown(self): # restore JSON encoder, in case a test changed it @@ -22,12 +24,10 @@ class TestServer(unittest.TestCase): def test_create(self, eio): mgr = mock.MagicMock() - s = server.Server( - client_manager=mgr, async_handlers=True, foo='bar' - ) + s = server.Server(client_manager=mgr, async_handlers=True, foo="bar") s.handle_request({}, None) s.handle_request({}, None) - eio.assert_called_once_with(**{'foo': 'bar', 'async_handlers': False}) + eio.assert_called_once_with(**{"foo": "bar", "async_handlers": False}) assert s.manager == mgr assert s.eio.on.call_count == 3 assert s.async_handlers @@ -36,19 +36,19 @@ class TestServer(unittest.TestCase): def test_on_event(self, eio): s = server.Server() - @s.on('connect') + @s.on("connect") def foo(): pass def bar(): pass - s.on('disconnect', bar) - s.on('disconnect', bar, namespace='/foo') + s.on("disconnect", bar) + s.on("disconnect", bar, namespace="/foo") - assert s.handlers['/']['connect'] == foo - assert s.handlers['/']['disconnect'] == bar - assert s.handlers['/foo']['disconnect'] == bar + assert s.handlers["/"]["connect"] == foo + assert s.handlers["/"]["disconnect"] == bar + assert s.handlers["/foo"]["disconnect"] == bar def test_event(self, eio): s = server.Server() @@ -65,51 +65,51 @@ class TestServer(unittest.TestCase): def bar(): pass - @s.event(namespace='/foo') + @s.event(namespace="/foo") def disconnect(): pass - assert s.handlers['/']['connect'] == connect - assert s.handlers['/']['foo'] == foo - assert s.handlers['/']['bar'] == bar - assert s.handlers['/foo']['disconnect'] == disconnect + assert s.handlers["/"]["connect"] == connect + assert s.handlers["/"]["foo"] == foo + assert s.handlers["/"]["bar"] == bar + assert s.handlers["/foo"]["disconnect"] == disconnect def test_emit(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) s.emit( - 'my event', - {'foo': 'bar'}, - to='room', - skip_sid='123', - namespace='/foo', - callback='cb', + "my event", + {"foo": "bar"}, + to="room", + skip_sid="123", + namespace="/foo", + callback="cb", ) s.manager.emit.assert_called_once_with( - 'my event', - {'foo': 'bar'}, - '/foo', - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + "/foo", + room="room", + skip_sid="123", + callback="cb", ignore_queue=False, ) s.emit( - 'my event', - {'foo': 'bar'}, - room='room', - skip_sid='123', - namespace='/foo', - callback='cb', + "my event", + {"foo": "bar"}, + room="room", + skip_sid="123", + namespace="/foo", + callback="cb", ignore_queue=True, ) s.manager.emit.assert_called_with( - 'my event', - {'foo': 'bar'}, - '/foo', - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + "/foo", + room="room", + skip_sid="123", + callback="cb", ignore_queue=True, ) @@ -117,68 +117,67 @@ class TestServer(unittest.TestCase): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) s.emit( - 'my event', - {'foo': 'bar'}, - to='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + to="room", + skip_sid="123", + callback="cb", ) s.manager.emit.assert_called_once_with( - 'my event', - {'foo': 'bar'}, - '/', - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + "/", + room="room", + skip_sid="123", + callback="cb", ignore_queue=False, ) s.emit( - 'my event', - {'foo': 'bar'}, - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + room="room", + skip_sid="123", + callback="cb", ignore_queue=True, ) s.manager.emit.assert_called_with( - 'my event', - {'foo': 'bar'}, - '/', - room='room', - skip_sid='123', - callback='cb', + "my event", + {"foo": "bar"}, + "/", + room="room", + skip_sid="123", + callback="cb", ignore_queue=True, ) def test_send(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.send( - 'foo', to='room', skip_sid='123', namespace='/foo', callback='cb' - ) + s.send("foo", to="room", skip_sid="123", namespace="/foo", callback="cb") s.manager.emit.assert_called_once_with( - 'message', - 'foo', - '/foo', - room='room', - skip_sid='123', - callback='cb', + "message", + "foo", + "/foo", + room="room", + skip_sid="123", + callback="cb", ignore_queue=False, ) s.send( - 'foo', room='room', - skip_sid='123', - namespace='/foo', - callback='cb', + "foo", + room="room", + skip_sid="123", + namespace="/foo", + callback="cb", ignore_queue=True, ) s.manager.emit.assert_called_with( - 'message', - 'foo', - '/foo', - room='room', - skip_sid='123', - callback='cb', + "message", + "foo", + "/foo", + room="room", + skip_sid="123", + callback="cb", ignore_queue=True, ) @@ -188,11 +187,11 @@ class TestServer(unittest.TestCase): def fake_event_wait(timeout=None): assert timeout == 60 - s.manager.emit.call_args_list[0][1]['callback']('foo', 321) + s.manager.emit.call_args_list[0][1]["callback"]("foo", 321) return True s.eio.create_event.return_value.wait = fake_event_wait - assert s.call('foo', sid='123') == ('foo', 321) + assert s.call("foo", sid="123") == ("foo", 321) def test_call_with_timeout(self, eio): mgr = mock.MagicMock() @@ -204,582 +203,574 @@ class TestServer(unittest.TestCase): s.eio.create_event.return_value.wait = fake_event_wait with pytest.raises(exceptions.TimeoutError): - s.call('foo', sid='123', timeout=12) + s.call("foo", sid="123", timeout=12) def test_call_with_broadcast(self, eio): s = server.Server() with pytest.raises(ValueError): - s.call('foo') + s.call("foo") def test_call_without_async_handlers(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr, async_handlers=False) with pytest.raises(RuntimeError): - s.call('foo', sid='123', timeout=12) + s.call("foo", sid="123", timeout=12) def test_enter_room(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.enter_room('123', 'room', namespace='/foo') - s.manager.enter_room.assert_called_once_with('123', '/foo', 'room') + s.enter_room("123", "room", namespace="/foo") + s.manager.enter_room.assert_called_once_with("123", "/foo", "room") def test_enter_room_default_namespace(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.enter_room('123', 'room') - s.manager.enter_room.assert_called_once_with('123', '/', 'room') + s.enter_room("123", "room") + s.manager.enter_room.assert_called_once_with("123", "/", "room") def test_leave_room(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.leave_room('123', 'room', namespace='/foo') - s.manager.leave_room.assert_called_once_with('123', '/foo', 'room') + s.leave_room("123", "room", namespace="/foo") + s.manager.leave_room.assert_called_once_with("123", "/foo", "room") def test_leave_room_default_namespace(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.leave_room('123', 'room') - s.manager.leave_room.assert_called_once_with('123', '/', 'room') + s.leave_room("123", "room") + s.manager.leave_room.assert_called_once_with("123", "/", "room") def test_close_room(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.close_room('room', namespace='/foo') - s.manager.close_room.assert_called_once_with('room', '/foo') + s.close_room("room", namespace="/foo") + s.manager.close_room.assert_called_once_with("room", "/foo") def test_close_room_default_namespace(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.close_room('room') - s.manager.close_room.assert_called_once_with('room', '/') + s.close_room("room") + s.manager.close_room.assert_called_once_with("room", "/") def test_rooms(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.rooms('123', namespace='/foo') - s.manager.get_rooms.assert_called_once_with('123', '/foo') + s.rooms("123", namespace="/foo") + s.manager.get_rooms.assert_called_once_with("123", "/foo") def test_rooms_default_namespace(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s.rooms('123') - s.manager.get_rooms.assert_called_once_with('123', '/') + s.rooms("123") + s.manager.get_rooms.assert_called_once_with("123", "/") def test_handle_request(self, eio): s = server.Server() - s.handle_request('environ', 'start_response') - s.eio.handle_request.assert_called_once_with( - 'environ', 'start_response' - ) + s.handle_request("environ", "start_response") + s.eio.handle_request.assert_called_once_with("environ", "start_response") def test_send_packet(self, eio): s = server.Server() - s._send_packet('123', packet.Packet( - packet.EVENT, ['my event', 'my data'], namespace='/foo')) - s.eio.send.assert_called_once_with( - '123', '2/foo,["my event","my data"]' + s._send_packet( + "123", + packet.Packet(packet.EVENT, ["my event", "my data"], namespace="/foo"), ) + s.eio.send.assert_called_once_with("123", '2/foo,["my event","my data"]') def test_send_eio_packet(self, eio): s = server.Server() - s._send_eio_packet('123', eio_packet.Packet( - eio_packet.MESSAGE, 'hello')) + s._send_eio_packet("123", eio_packet.Packet(eio_packet.MESSAGE, "hello")) assert s.eio.send_packet.call_count == 1 - assert s.eio.send_packet.call_args_list[0][0][0] == '123' + assert s.eio.send_packet.call_args_list[0][0][0] == "123" pkt = s.eio.send_packet.call_args_list[0][0][1] - assert pkt.encode() == '4hello' + assert pkt.encode() == "4hello" def test_transport(self, eio): s = server.Server() - s.eio.transport = mock.MagicMock(return_value='polling') - s._handle_eio_connect('foo', 'environ') - assert s.transport('foo') == 'polling' - s.eio.transport.assert_called_once_with('foo') + s.eio.transport = mock.MagicMock(return_value="polling") + s._handle_eio_connect("foo", "environ") + assert s.transport("foo") == "polling" + s.eio.transport.assert_called_once_with("foo") def test_handle_connect(self, eio): s = server.Server() s.manager.initialize = mock.MagicMock() handler = mock.MagicMock() - s.on('connect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - assert s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - s.eio.send.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + assert s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + s.eio.send.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - s._handle_eio_connect('456', 'environ') + s._handle_eio_connect("456", "environ") assert s.manager.initialize.call_count == 1 def test_handle_connect_with_auth(self, eio): s = server.Server() s.manager.initialize = mock.MagicMock() handler = mock.MagicMock() - s.on('connect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0{"token":"abc"}') - assert s.manager.is_connected('1', '/') - handler.assert_called_with('1', 'environ', {'token': 'abc'}) - s.eio.send.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", '0{"token":"abc"}') + assert s.manager.is_connected("1", "/") + handler.assert_called_with("1", "environ", {"token": "abc"}) + s.eio.send.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - s._handle_eio_connect('456', 'environ') + s._handle_eio_connect("456", "environ") assert s.manager.initialize.call_count == 1 def test_handle_connect_with_auth_none(self, eio): s = server.Server() s.manager.initialize = mock.MagicMock() handler = mock.MagicMock(side_effect=[TypeError, None]) - s.on('connect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - assert s.manager.is_connected('1', '/') - handler.assert_called_with('1', 'environ', None) - s.eio.send.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + assert s.manager.is_connected("1", "/") + handler.assert_called_with("1", "environ", None) + s.eio.send.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - s._handle_eio_connect('456', 'environ') + s._handle_eio_connect("456", "environ") assert s.manager.initialize.call_count == 1 def test_handle_connect_with_default_implied_namespaces(self, eio): s = server.Server() - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - s._handle_eio_message('123', '0/foo,') - assert s.manager.is_connected('1', '/') - assert not s.manager.is_connected('2', '/foo') + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + s._handle_eio_message("123", "0/foo,") + assert s.manager.is_connected("1", "/") + assert not s.manager.is_connected("2", "/foo") def test_handle_connect_with_implied_namespaces(self, eio): - s = server.Server(namespaces=['/foo']) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - s._handle_eio_message('123', '0/foo,') - assert not s.manager.is_connected('1', '/') - assert s.manager.is_connected('1', '/foo') + s = server.Server(namespaces=["/foo"]) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + s._handle_eio_message("123", "0/foo,") + assert not s.manager.is_connected("1", "/") + assert s.manager.is_connected("1", "/foo") def test_handle_connect_with_all_implied_namespaces(self, eio): - s = server.Server(namespaces='*') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - s._handle_eio_message('123', '0/foo,') - assert s.manager.is_connected('1', '/') - assert s.manager.is_connected('2', '/foo') + s = server.Server(namespaces="*") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + s._handle_eio_message("123", "0/foo,") + assert s.manager.is_connected("1", "/") + assert s.manager.is_connected("2", "/foo") def test_handle_connect_namespace(self, eio): s = server.Server() handler = mock.MagicMock() - s.on('connect', handler, namespace='/foo') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - assert s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') - s.eio.send.assert_called_once_with('123', '0/foo,{"sid":"1"}') + s.on("connect", handler, namespace="/foo") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + assert s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") + s.eio.send.assert_called_once_with("123", '0/foo,{"sid":"1"}') def test_handle_connect_namespace_twice(self, eio): s = server.Server() handler = mock.MagicMock() - s.on('connect', handler, namespace='/foo') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - s._handle_eio_message('123', '0/foo,') - assert s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') - s.eio.send.assert_any_call('123', '0/foo,{"sid":"1"}') - s.eio.send.assert_any_call('123', '4/foo,"Unable to connect"') + s.on("connect", handler, namespace="/foo") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + s._handle_eio_message("123", "0/foo,") + assert s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") + s.eio.send.assert_any_call("123", '0/foo,{"sid":"1"}') + s.eio.send.assert_any_call("123", '4/foo,"Unable to connect"') def test_handle_connect_always_connect(self, eio): s = server.Server(always_connect=True) s.manager.initialize = mock.MagicMock() handler = mock.MagicMock() - s.on('connect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - assert s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - s.eio.send.assert_called_once_with('123', '0{"sid":"1"}') + s.on("connect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + assert s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + s.eio.send.assert_called_once_with("123", '0{"sid":"1"}') assert s.manager.initialize.call_count == 1 - s._handle_eio_connect('456', 'environ') + s._handle_eio_connect("456", "environ") assert s.manager.initialize.call_count == 1 def test_handle_connect_rejected(self, eio): s = server.Server() handler = mock.MagicMock(return_value=False) - s.on('connect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - assert not s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - assert not s.manager.is_connected('1', '/') + s.on("connect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + assert not s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + assert not s.manager.is_connected("1", "/") s.eio.send.assert_called_once_with( - '123', '4{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '4{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_namespace_rejected(self, eio): s = server.Server() handler = mock.MagicMock(return_value=False) - s.on('connect', handler, namespace='/foo') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - assert not s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') - assert not s.manager.is_connected('1', '/foo') + s.on("connect", handler, namespace="/foo") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + assert not s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") + assert not s.manager.is_connected("1", "/foo") s.eio.send.assert_called_once_with( - '123', '4/foo,{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '4/foo,{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_rejected_always_connect(self, eio): s = server.Server(always_connect=True) handler = mock.MagicMock(return_value=False) - s.on('connect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - assert not s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - s.eio.send.assert_any_call('123', '0{"sid":"1"}') + s.on("connect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + assert not s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + s.eio.send.assert_any_call("123", '0{"sid":"1"}') s.eio.send.assert_any_call( - '123', '1{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '1{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_namespace_rejected_always_connect(self, eio): s = server.Server(always_connect=True) handler = mock.MagicMock(return_value=False) - s.on('connect', handler, namespace='/foo') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - assert not s.manager.is_connected('1', '/foo') - handler.assert_called_once_with('1', 'environ') - s.eio.send.assert_any_call('123', '0/foo,{"sid":"1"}') + s.on("connect", handler, namespace="/foo") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + assert not s.manager.is_connected("1", "/foo") + handler.assert_called_once_with("1", "environ") + s.eio.send.assert_any_call("123", '0/foo,{"sid":"1"}') s.eio.send.assert_any_call( - '123', '1/foo,{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '1/foo,{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_rejected_with_exception(self, eio): s = server.Server() handler = mock.MagicMock( - side_effect=exceptions.ConnectionRefusedError('fail_reason') + side_effect=exceptions.ConnectionRefusedError("fail_reason") ) - s.on('connect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - assert not s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') - s.eio.send.assert_called_once_with('123', '4{"message":"fail_reason"}') - assert s.environ == {'123': 'environ'} + s.on("connect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + assert not s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") + s.eio.send.assert_called_once_with("123", '4{"message":"fail_reason"}') + assert s.environ == {"123": "environ"} def test_handle_connect_rejected_with_empty_exception(self, eio): s = server.Server() - handler = mock.MagicMock( - side_effect=exceptions.ConnectionRefusedError() - ) - s.on('connect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - assert not s.manager.is_connected('1', '/') - handler.assert_called_once_with('1', 'environ') + handler = mock.MagicMock(side_effect=exceptions.ConnectionRefusedError()) + s.on("connect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + assert not s.manager.is_connected("1", "/") + handler.assert_called_once_with("1", "environ") s.eio.send.assert_called_once_with( - '123', '4{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '4{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_connect_namespace_rejected_with_exception(self, eio): s = server.Server() handler = mock.MagicMock( - side_effect=exceptions.ConnectionRefusedError('fail_reason', 1) + side_effect=exceptions.ConnectionRefusedError("fail_reason", 1) ) - s.on('connect', handler, namespace='/foo') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - assert not s.manager.is_connected('1', '/foo') + s.on("connect", handler, namespace="/foo") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + assert not s.manager.is_connected("1", "/foo") s.eio.send.assert_called_once_with( - '123', '4/foo,{"message":"fail_reason","data":1}' + "123", '4/foo,{"message":"fail_reason","data":1}' ) - assert s.environ == {'123': 'environ'} + assert s.environ == {"123": "environ"} def test_handle_connect_namespace_rejected_with_empty_exception(self, eio): s = server.Server() - handler = mock.MagicMock( - side_effect=exceptions.ConnectionRefusedError() - ) - s.on('connect', handler, namespace='/foo') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - assert not s.manager.is_connected('1', '/foo') + handler = mock.MagicMock(side_effect=exceptions.ConnectionRefusedError()) + s.on("connect", handler, namespace="/foo") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + assert not s.manager.is_connected("1", "/foo") s.eio.send.assert_called_once_with( - '123', '4/foo,{"message":"Connection rejected by server"}') - assert s.environ == {'123': 'environ'} + "123", '4/foo,{"message":"Connection rejected by server"}' + ) + assert s.environ == {"123": "environ"} def test_handle_disconnect(self, eio): s = server.Server() s.manager.disconnect = mock.MagicMock() handler = mock.MagicMock() - s.on('disconnect', handler) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - s._handle_eio_disconnect('123') - handler.assert_called_once_with('1') - s.manager.disconnect.assert_called_once_with('1', '/', - ignore_queue=True) + s.on("disconnect", handler) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + s._handle_eio_disconnect("123") + handler.assert_called_once_with("1") + s.manager.disconnect.assert_called_once_with("1", "/", ignore_queue=True) assert s.environ == {} def test_handle_disconnect_namespace(self, eio): s = server.Server() handler = mock.MagicMock() - s.on('disconnect', handler) + s.on("disconnect", handler) handler_namespace = mock.MagicMock() - s.on('disconnect', handler_namespace, namespace='/foo') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - s._handle_eio_disconnect('123') + s.on("disconnect", handler_namespace, namespace="/foo") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + s._handle_eio_disconnect("123") handler.assert_not_called() - handler_namespace.assert_called_once_with('1') + handler_namespace.assert_called_once_with("1") assert s.environ == {} def test_handle_disconnect_only_namespace(self, eio): s = server.Server() handler = mock.MagicMock() - s.on('disconnect', handler) + s.on("disconnect", handler) handler_namespace = mock.MagicMock() - s.on('disconnect', handler_namespace, namespace='/foo') - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - s._handle_eio_message('123', '1/foo,') + s.on("disconnect", handler_namespace, namespace="/foo") + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + s._handle_eio_message("123", "1/foo,") assert handler.call_count == 0 - handler_namespace.assert_called_once_with('1') - assert s.environ == {'123': 'environ'} + handler_namespace.assert_called_once_with("1") + assert s.environ == {"123": "environ"} def test_handle_disconnect_unknown_client(self, eio): mgr = mock.MagicMock() s = server.Server(client_manager=mgr) - s._handle_eio_disconnect('123') + s._handle_eio_disconnect("123") def test_handle_event(self, eio): s = server.Server(async_handlers=False) - s.manager.connect('123', '/') + s.manager.connect("123", "/") handler = mock.MagicMock() catchall_handler = mock.MagicMock() - s.on('msg', handler) - s.on('*', catchall_handler) - s._handle_eio_message('123', '2["msg","a","b"]') - s._handle_eio_message('123', '2["my message","a","b","c"]') - handler.assert_called_once_with('1', 'a', 'b') - catchall_handler.assert_called_once_with( - 'my message', '1', 'a', 'b', 'c') + s.on("msg", handler) + s.on("*", catchall_handler) + s._handle_eio_message("123", '2["msg","a","b"]') + s._handle_eio_message("123", '2["my message","a","b","c"]') + handler.assert_called_once_with("1", "a", "b") + catchall_handler.assert_called_once_with("my message", "1", "a", "b", "c") def test_handle_event_with_namespace(self, eio): s = server.Server(async_handlers=False) - s.manager.connect('123', '/foo') + s.manager.connect("123", "/foo") handler = mock.MagicMock() catchall_handler = mock.MagicMock() - s.on('msg', handler, namespace='/foo') - s.on('*', catchall_handler, namespace='/foo') - s._handle_eio_message('123', '2/foo,["msg","a","b"]') - s._handle_eio_message('123', '2/foo,["my message","a","b","c"]') - handler.assert_called_once_with('1', 'a', 'b') - catchall_handler.assert_called_once_with( - 'my message', '1', 'a', 'b', 'c') + s.on("msg", handler, namespace="/foo") + s.on("*", catchall_handler, namespace="/foo") + s._handle_eio_message("123", '2/foo,["msg","a","b"]') + s._handle_eio_message("123", '2/foo,["my message","a","b","c"]') + handler.assert_called_once_with("1", "a", "b") + catchall_handler.assert_called_once_with("my message", "1", "a", "b", "c") def test_handle_event_with_disconnected_namespace(self, eio): s = server.Server(async_handlers=False) - s.manager.connect('123', '/foo') + s.manager.connect("123", "/foo") handler = mock.MagicMock() - s.on('my message', handler, namespace='/bar') - s._handle_eio_message('123', '2/bar,["my message","a","b","c"]') + s.on("my message", handler, namespace="/bar") + s._handle_eio_message("123", '2/bar,["my message","a","b","c"]') handler.assert_not_called() def test_handle_event_binary(self, eio): s = server.Server(async_handlers=False) - s.manager.connect('123', '/') + s.manager.connect("123", "/") handler = mock.MagicMock() - s.on('my message', handler) + s.on("my message", handler) s._handle_eio_message( - '123', + "123", '52-["my message","a",' '{"_placeholder":true,"num":1},' '{"_placeholder":true,"num":0}]', ) - s._handle_eio_message('123', b'foo') - s._handle_eio_message('123', b'bar') - handler.assert_called_once_with('1', 'a', b'bar', b'foo') + s._handle_eio_message("123", b"foo") + s._handle_eio_message("123", b"bar") + handler.assert_called_once_with("1", "a", b"bar", b"foo") def test_handle_event_binary_ack(self, eio): s = server.Server() s.manager.trigger_callback = mock.MagicMock() - sid = s.manager.connect('123', '/') + sid = s.manager.connect("123", "/") s._handle_eio_message( - '123', '61-321["my message","a",' '{"_placeholder":true,"num":0}]' + "123", '61-321["my message","a",' '{"_placeholder":true,"num":0}]' ) - s._handle_eio_message('123', b'foo') + s._handle_eio_message("123", b"foo") s.manager.trigger_callback.assert_called_once_with( - sid, 321, ['my message', 'a', b'foo'] + sid, 321, ["my message", "a", b"foo"] ) def test_handle_event_with_ack(self, eio): s = server.Server(async_handlers=False) - sid = s.manager.connect('123', '/') - handler = mock.MagicMock(return_value='foo') - s.on('my message', handler) - s._handle_eio_message('123', '21000["my message","foo"]') - handler.assert_called_once_with(sid, 'foo') - s.eio.send.assert_called_once_with('123', '31000["foo"]') + sid = s.manager.connect("123", "/") + handler = mock.MagicMock(return_value="foo") + s.on("my message", handler) + s._handle_eio_message("123", '21000["my message","foo"]') + handler.assert_called_once_with(sid, "foo") + s.eio.send.assert_called_once_with("123", '31000["foo"]') def test_handle_unknown_event_with_ack(self, eio): s = server.Server(async_handlers=False) - s.manager.connect('123', '/') - handler = mock.MagicMock(return_value='foo') - s.on('my message', handler) - s._handle_eio_message('123', '21000["another message","foo"]') + s.manager.connect("123", "/") + handler = mock.MagicMock(return_value="foo") + s.on("my message", handler) + s._handle_eio_message("123", '21000["another message","foo"]') s.eio.send.assert_not_called() def test_handle_event_with_ack_none(self, eio): s = server.Server(async_handlers=False) - sid = s.manager.connect('123', '/') + sid = s.manager.connect("123", "/") handler = mock.MagicMock(return_value=None) - s.on('my message', handler) - s._handle_eio_message('123', '21000["my message","foo"]') - handler.assert_called_once_with(sid, 'foo') - s.eio.send.assert_called_once_with('123', '31000[]') + s.on("my message", handler) + s._handle_eio_message("123", '21000["my message","foo"]') + handler.assert_called_once_with(sid, "foo") + s.eio.send.assert_called_once_with("123", "31000[]") def test_handle_event_with_ack_tuple(self, eio): s = server.Server(async_handlers=False) - handler = mock.MagicMock(return_value=(1, '2', True)) - s.on('my message', handler) - sid = s.manager.connect('123', '/') - s._handle_eio_message('123', '21000["my message","a","b","c"]') - handler.assert_called_once_with(sid, 'a', 'b', 'c') - s.eio.send.assert_called_with( - '123', '31000[1,"2",true]' - ) + handler = mock.MagicMock(return_value=(1, "2", True)) + s.on("my message", handler) + sid = s.manager.connect("123", "/") + s._handle_eio_message("123", '21000["my message","a","b","c"]') + handler.assert_called_once_with(sid, "a", "b", "c") + s.eio.send.assert_called_with("123", '31000[1,"2",true]') def test_handle_event_with_ack_list(self, eio): s = server.Server(async_handlers=False) - handler = mock.MagicMock(return_value=[1, '2', True]) - s.on('my message', handler) - sid = s.manager.connect('123', '/') - s._handle_eio_message('123', '21000["my message","a","b","c"]') - handler.assert_called_once_with(sid, 'a', 'b', 'c') - s.eio.send.assert_called_with( - '123', '31000[[1,"2",true]]' - ) + handler = mock.MagicMock(return_value=[1, "2", True]) + s.on("my message", handler) + sid = s.manager.connect("123", "/") + s._handle_eio_message("123", '21000["my message","a","b","c"]') + handler.assert_called_once_with(sid, "a", "b", "c") + s.eio.send.assert_called_with("123", '31000[[1,"2",true]]') def test_handle_event_with_ack_binary(self, eio): s = server.Server(async_handlers=False) - handler = mock.MagicMock(return_value=b'foo') - s.on('my message', handler) - sid = s.manager.connect('123', '/') - s._handle_eio_message('123', '21000["my message","foo"]') - handler.assert_any_call(sid, 'foo') + handler = mock.MagicMock(return_value=b"foo") + s.on("my message", handler) + sid = s.manager.connect("123", "/") + s._handle_eio_message("123", '21000["my message","foo"]') + handler.assert_any_call(sid, "foo") def test_handle_error_packet(self, eio): s = server.Server() with pytest.raises(ValueError): - s._handle_eio_message('123', '4') + s._handle_eio_message("123", "4") def test_handle_invalid_packet(self, eio): s = server.Server() with pytest.raises(ValueError): - s._handle_eio_message('123', '9') + s._handle_eio_message("123", "9") def test_send_with_ack(self, eio): s = server.Server() - s.handlers['/'] = {} - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') + s.handlers["/"] = {} + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") cb = mock.MagicMock() - id1 = s.manager._generate_ack_id('1', cb) - id2 = s.manager._generate_ack_id('1', cb) - s._send_packet('123', packet.Packet( - packet.EVENT, ['my event', 'foo'], id=id1)) - s._send_packet('123', packet.Packet( - packet.EVENT, ['my event', 'bar'], id=id2)) - s._handle_eio_message('123', '31["foo",2]') - cb.assert_called_once_with('foo', 2) + id1 = s.manager._generate_ack_id("1", cb) + id2 = s.manager._generate_ack_id("1", cb) + s._send_packet("123", packet.Packet(packet.EVENT, ["my event", "foo"], id=id1)) + s._send_packet("123", packet.Packet(packet.EVENT, ["my event", "bar"], id=id2)) + s._handle_eio_message("123", '31["foo",2]') + cb.assert_called_once_with("foo", 2) def test_send_with_ack_namespace(self, eio): s = server.Server() - s.handlers['/foo'] = {} - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') + s.handlers["/foo"] = {} + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") cb = mock.MagicMock() - id = s.manager._generate_ack_id('1', cb) - s._send_packet('123', packet.Packet( - packet.EVENT, ['my event', 'foo'], namespace='/foo', id=id)) - s._handle_eio_message('123', '3/foo,1["foo",2]') - cb.assert_called_once_with('foo', 2) + id = s.manager._generate_ack_id("1", cb) + s._send_packet( + "123", + packet.Packet(packet.EVENT, ["my event", "foo"], namespace="/foo", id=id), + ) + s._handle_eio_message("123", '3/foo,1["foo",2]') + cb.assert_called_once_with("foo", 2) def test_session(self, eio): fake_session = {} def fake_get_session(eio_sid): - assert eio_sid == '123' + assert eio_sid == "123" return fake_session def fake_save_session(eio_sid, session): global fake_session - assert eio_sid == '123' + assert eio_sid == "123" fake_session = session s = server.Server() - s.handlers['/'] = {} - s.handlers['/ns'] = {} + s.handlers["/"] = {} + s.handlers["/ns"] = {} s.eio.get_session = fake_get_session s.eio.save_session = fake_save_session - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - s._handle_eio_message('123', '0/ns') - sid = s.manager.sid_from_eio_sid('123', '/') - sid2 = s.manager.sid_from_eio_sid('123', '/ns') - s.save_session(sid, {'foo': 'bar'}) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + s._handle_eio_message("123", "0/ns") + sid = s.manager.sid_from_eio_sid("123", "/") + sid2 = s.manager.sid_from_eio_sid("123", "/ns") + s.save_session(sid, {"foo": "bar"}) with s.session(sid) as session: - assert session == {'foo': 'bar'} - session['foo'] = 'baz' - session['bar'] = 'foo' - assert s.get_session(sid) == {'foo': 'baz', 'bar': 'foo'} - assert fake_session == {'/': {'foo': 'baz', 'bar': 'foo'}} - with s.session(sid2, namespace='/ns') as session: + assert session == {"foo": "bar"} + session["foo"] = "baz" + session["bar"] = "foo" + assert s.get_session(sid) == {"foo": "baz", "bar": "foo"} + assert fake_session == {"/": {"foo": "baz", "bar": "foo"}} + with s.session(sid2, namespace="/ns") as session: assert session == {} - session['a'] = 'b' - assert s.get_session(sid2, namespace='/ns') == {'a': 'b'} + session["a"] = "b" + assert s.get_session(sid2, namespace="/ns") == {"a": "b"} assert fake_session == { - '/': {'foo': 'baz', 'bar': 'foo'}, - '/ns': {'a': 'b'}, + "/": {"foo": "baz", "bar": "foo"}, + "/ns": {"a": "b"}, } def test_disconnect(self, eio): s = server.Server() - s.handlers['/'] = {} - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - s.disconnect('1') - s.eio.send.assert_any_call('123', '1') + s.handlers["/"] = {} + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + s.disconnect("1") + s.eio.send.assert_any_call("123", "1") def test_disconnect_ignore_queue(self, eio): s = server.Server() - s.handlers['/'] = {} - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - s.disconnect('1', ignore_queue=True) - s.eio.send.assert_any_call('123', '1') + s.handlers["/"] = {} + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + s.disconnect("1", ignore_queue=True) + s.eio.send.assert_any_call("123", "1") def test_disconnect_namespace(self, eio): s = server.Server() - s.handlers['/foo'] = {} - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - s.disconnect('1', namespace='/foo') - s.eio.send.assert_any_call('123', '1/foo,') + s.handlers["/foo"] = {} + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + s.disconnect("1", namespace="/foo") + s.eio.send.assert_any_call("123", "1/foo,") def test_disconnect_twice(self, eio): s = server.Server() - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - s.disconnect('1') + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + s.disconnect("1") calls = s.eio.send.call_count - s.disconnect('1') + s.disconnect("1") assert calls == s.eio.send.call_count def test_disconnect_twice_namespace(self, eio): s = server.Server() - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - s.disconnect('123', namespace='/foo') + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + s.disconnect("123", namespace="/foo") calls = s.eio.send.call_count - s.disconnect('123', namespace='/foo') + s.disconnect("123", namespace="/foo") assert calls == s.eio.send.call_count def test_namespace_handler(self, eio): @@ -787,33 +778,33 @@ class TestServer(unittest.TestCase): class MyNamespace(namespace.Namespace): def on_connect(self, sid, environ): - result['result'] = (sid, environ) + result["result"] = (sid, environ) def on_disconnect(self, sid): - result['result'] = ('disconnect', sid) + result["result"] = ("disconnect", sid) def on_foo(self, sid, data): - result['result'] = (sid, data) + result["result"] = (sid, data) def on_bar(self, sid): - result['result'] = 'bar' + result["result"] = "bar" def on_baz(self, sid, data1, data2): - result['result'] = (data1, data2) + result["result"] = (data1, data2) s = server.Server(async_handlers=False) - s.register_namespace(MyNamespace('/foo')) - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0/foo,') - assert result['result'] == ('1', 'environ') - s._handle_eio_message('123', '2/foo,["foo","a"]') - assert result['result'] == ('1', 'a') - s._handle_eio_message('123', '2/foo,["bar"]') - assert result['result'] == 'bar' - s._handle_eio_message('123', '2/foo,["baz","a","b"]') - assert result['result'] == ('a', 'b') - s.disconnect('1', '/foo') - assert result['result'] == ('disconnect', '1') + s.register_namespace(MyNamespace("/foo")) + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0/foo,") + assert result["result"] == ("1", "environ") + s._handle_eio_message("123", '2/foo,["foo","a"]') + assert result["result"] == ("1", "a") + s._handle_eio_message("123", '2/foo,["bar"]') + assert result["result"] == "bar" + s._handle_eio_message("123", '2/foo,["baz","a","b"]') + assert result["result"] == ("a", "b") + s.disconnect("1", "/foo") + assert result["result"] == ("disconnect", "1") def test_bad_namespace_handler(self, eio): class Dummy(object): @@ -837,12 +828,12 @@ class TestServer(unittest.TestCase): def test_get_environ(self, eio): s = server.Server() - s.handlers['/'] = {} - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') - sid = s.manager.sid_from_eio_sid('123', '/') - assert s.get_environ(sid) == 'environ' - assert s.get_environ('foo') is None + s.handlers["/"] = {} + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") + sid = s.manager.sid_from_eio_sid("123", "/") + assert s.get_environ(sid) == "environ" + assert s.get_environ("foo") is None def test_logger(self, eio): s = server.Server(logger=False) @@ -854,17 +845,15 @@ class TestServer(unittest.TestCase): s = server.Server(logger=True) assert s.logger.getEffectiveLevel() == logging.WARNING s.logger.setLevel(logging.NOTSET) - s = server.Server(logger='foo') - assert s.logger == 'foo' + s = server.Server(logger="foo") + assert s.logger == "foo" def test_engineio_logger(self, eio): - server.Server(engineio_logger='foo') - eio.assert_called_once_with( - **{'logger': 'foo', 'async_handlers': False} - ) + server.Server(engineio_logger="foo") + eio.assert_called_once_with(**{"logger": "foo", "async_handlers": False}) def test_msgpack(self, eio): - s = server.Server(serializer='msgpack') + s = server.Server(serializer="msgpack") assert s.packet_class == msgpack_packet.MsgPackPacket def test_custom_serializer(self, eio): @@ -881,39 +870,37 @@ class TestServer(unittest.TestCase): class CustomJSON(object): @staticmethod def dumps(*args, **kwargs): - return '*** encoded ***' + return "*** encoded ***" @staticmethod def loads(*args, **kwargs): - return '+++ decoded +++' + return "+++ decoded +++" server.Server(json=CustomJSON) - eio.assert_called_once_with( - **{'json': CustomJSON, 'async_handlers': False} - ) + eio.assert_called_once_with(**{"json": CustomJSON, "async_handlers": False}) pkt = packet.Packet( packet_type=packet.EVENT, - data={'foo': 'bar'}, + data={"foo": "bar"}, ) - assert pkt.encode() == '2*** encoded ***' + assert pkt.encode() == "2*** encoded ***" pkt2 = packet.Packet(encoded_packet=pkt.encode()) - assert pkt2.data == '+++ decoded +++' + assert pkt2.data == "+++ decoded +++" # restore the default JSON module packet.Packet.json = json def test_async_handlers(self, eio): s = server.Server(async_handlers=True) - sid = s.manager.connect('123', '/') - s._handle_eio_message('123', '2["my message","a","b","c"]') + sid = s.manager.connect("123", "/") + s._handle_eio_message("123", '2["my message","a","b","c"]') s.eio.start_background_task.assert_called_once_with( s._handle_event_internal, s, sid, - '123', - ['my message', 'a', 'b', 'c'], - '/', + "123", + ["my message", "a", "b", "c"], + "/", None, ) @@ -924,10 +911,8 @@ class TestServer(unittest.TestCase): def test_start_background_task(self, eio): s = server.Server() - s.start_background_task('foo', 'bar', baz='baz') - s.eio.start_background_task.assert_called_once_with( - 'foo', 'bar', baz='baz' - ) + s.start_background_task("foo", "bar", baz="baz") + s.eio.start_background_task.assert_called_once_with("foo", "bar", baz="baz") def test_sleep(self, eio): s = server.Server() diff --git a/tests/common/test_simple_client.py b/tests/common/test_simple_client.py index 3b9f983..8e80a49 100644 --- a/tests/common/test_simple_client.py +++ b/tests/common/test_simple_client.py @@ -7,79 +7,103 @@ from socketio.exceptions import SocketIOError, TimeoutError, DisconnectedError class TestSimpleClient(unittest.TestCase): def test_constructor(self): - client = SimpleClient(1, '2', a='3', b=4) - assert client.client_args == (1, '2') - assert client.client_kwargs == {'a': '3', 'b': 4} + client = SimpleClient(1, "2", a="3", b=4) + assert client.client_args == (1, "2") + assert client.client_kwargs == {"a": "3", "b": 4} assert client.client is None assert client.input_buffer == [] assert not client.connected def test_connect(self): - client = SimpleClient(123, a='b') - with mock.patch('socketio.simple_client.Client') as mock_client: - client.connect('url', headers='h', auth='a', transports='t', - namespace='n', socketio_path='s', wait_timeout='w') - mock_client.assert_called_once_with(123, a='b') + client = SimpleClient(123, a="b") + with mock.patch("socketio.simple_client.Client") as mock_client: + client.connect( + "url", + headers="h", + auth="a", + transports="t", + namespace="n", + socketio_path="s", + wait_timeout="w", + ) + mock_client.assert_called_once_with(123, a="b") assert client.client == mock_client() mock_client().connect.assert_called_once_with( - 'url', headers='h', auth='a', transports='t', - namespaces=['n'], socketio_path='s', wait_timeout='w') + "url", + headers="h", + auth="a", + transports="t", + namespaces=["n"], + socketio_path="s", + wait_timeout="w", + ) mock_client().event.call_count == 3 - mock_client().on.assert_called_once_with('*', namespace='n') - assert client.namespace == 'n' + mock_client().on.assert_called_once_with("*", namespace="n") + assert client.namespace == "n" assert not client.input_event.is_set() def test_connect_context_manager(self): - with SimpleClient(123, a='b') as client: - with mock.patch('socketio.simple_client.Client') as mock_client: - client.connect('url', headers='h', auth='a', transports='t', - namespace='n', socketio_path='s', - wait_timeout='w') - mock_client.assert_called_once_with(123, a='b') + with SimpleClient(123, a="b") as client: + with mock.patch("socketio.simple_client.Client") as mock_client: + client.connect( + "url", + headers="h", + auth="a", + transports="t", + namespace="n", + socketio_path="s", + wait_timeout="w", + ) + mock_client.assert_called_once_with(123, a="b") assert client.client == mock_client() mock_client().connect.assert_called_once_with( - 'url', headers='h', auth='a', transports='t', - namespaces=['n'], socketio_path='s', wait_timeout='w') + "url", + headers="h", + auth="a", + transports="t", + namespaces=["n"], + socketio_path="s", + wait_timeout="w", + ) mock_client().event.call_count == 3 - mock_client().on.assert_called_once_with('*', namespace='n') - assert client.namespace == 'n' + mock_client().on.assert_called_once_with("*", namespace="n") + assert client.namespace == "n" assert not client.input_event.is_set() def test_connect_twice(self): - client = SimpleClient(123, a='b') + client = SimpleClient(123, a="b") client.client = mock.MagicMock() client.connected = True with pytest.raises(RuntimeError): - client.connect('url') + client.connect("url") def test_properties(self): client = SimpleClient() - client.client = mock.MagicMock(transport='websocket') - client.client.get_sid.return_value = 'sid' + client.client = mock.MagicMock(transport="websocket") + client.client.get_sid.return_value = "sid" client.connected_event.set() client.connected = True - assert client.sid == 'sid' - assert client.transport == 'websocket' + assert client.sid == "sid" + assert client.transport == "websocket" def test_emit(self): client = SimpleClient() client.client = mock.MagicMock() - client.namespace = '/ns' + client.namespace = "/ns" client.connected_event.set() client.connected = True - client.emit('foo', 'bar') - client.client.emit.assert_called_once_with('foo', 'bar', - namespace='/ns') + client.emit("foo", "bar") + client.client.emit.assert_called_once_with("foo", "bar", namespace="/ns") def test_emit_disconnected(self): client = SimpleClient() client.connected_event.set() client.connected = False with pytest.raises(DisconnectedError): - client.emit('foo', 'bar') + client.emit("foo", "bar") def test_emit_retries(self): client = SimpleClient() @@ -88,44 +112,44 @@ class TestSimpleClient(unittest.TestCase): client.client = mock.MagicMock() client.client.emit.side_effect = [SocketIOError(), None] - client.emit('foo', 'bar') - client.client.emit.assert_called_with('foo', 'bar', namespace='/') + client.emit("foo", "bar") + client.client.emit.assert_called_with("foo", "bar", namespace="/") def test_call(self): client = SimpleClient() client.client = mock.MagicMock() - client.client.call.return_value = 'result' - client.namespace = '/ns' + client.client.call.return_value = "result" + client.namespace = "/ns" client.connected_event.set() client.connected = True - assert client.call('foo', 'bar') == 'result' - client.client.call.assert_called_once_with('foo', 'bar', - namespace='/ns', timeout=60) + assert client.call("foo", "bar") == "result" + client.client.call.assert_called_once_with( + "foo", "bar", namespace="/ns", timeout=60 + ) def test_call_disconnected(self): client = SimpleClient() client.connected_event.set() client.connected = False with pytest.raises(DisconnectedError): - client.call('foo', 'bar') + client.call("foo", "bar") def test_call_retries(self): client = SimpleClient() client.connected_event.set() client.connected = True client.client = mock.MagicMock() - client.client.call.side_effect = [SocketIOError(), 'result'] + client.client.call.side_effect = [SocketIOError(), "result"] - assert client.call('foo', 'bar') == 'result' - client.client.call.assert_called_with('foo', 'bar', namespace='/', - timeout=60) + assert client.call("foo", "bar") == "result" + client.client.call.assert_called_with("foo", "bar", namespace="/", timeout=60) def test_receive_with_input_buffer(self): client = SimpleClient() - client.input_buffer = ['foo', 'bar'] - assert client.receive() == 'foo' - assert client.receive() == 'bar' + client.input_buffer = ["foo", "bar"] + assert client.receive() == "foo" + assert client.receive() == "bar" def test_receive_without_input_buffer(self): client = SimpleClient() @@ -134,11 +158,11 @@ class TestSimpleClient(unittest.TestCase): client.input_event = mock.MagicMock() def fake_wait(timeout=None): - client.input_buffer = ['foo'] + client.input_buffer = ["foo"] return True client.input_event.wait = fake_wait - assert client.receive() == 'foo' + assert client.receive() == "foo" def test_receive_with_timeout(self): client = SimpleClient() diff --git a/tests/performance/binary_packet.py b/tests/performance/binary_packet.py index b9084ee..07432d9 100644 --- a/tests/performance/binary_packet.py +++ b/tests/performance/binary_packet.py @@ -3,7 +3,7 @@ from socketio import packet def test(): - p = packet.Packet(packet.EVENT, {'foo': b'bar'}) + p = packet.Packet(packet.EVENT, {"foo": b"bar"}) start = time.time() count = 0 while True: @@ -17,6 +17,6 @@ def test(): return count -if __name__ == '__main__': +if __name__ == "__main__": count = test() - print('binary_packet:', count, 'packets processed.') + print("binary_packet:", count, "packets processed.") diff --git a/tests/performance/json_packet.py b/tests/performance/json_packet.py index 6861a5c..3437687 100644 --- a/tests/performance/json_packet.py +++ b/tests/performance/json_packet.py @@ -3,7 +3,7 @@ from socketio import packet def test(): - p = packet.Packet(packet.EVENT, {'foo': 'bar'}) + p = packet.Packet(packet.EVENT, {"foo": "bar"}) start = time.time() count = 0 while True: @@ -14,6 +14,6 @@ def test(): return count -if __name__ == '__main__': +if __name__ == "__main__": count = test() - print('json_packet:', count, 'packets processed.') + print("json_packet:", count, "packets processed.") diff --git a/tests/performance/namespace_packet.py b/tests/performance/namespace_packet.py index 4d560a7..2013325 100644 --- a/tests/performance/namespace_packet.py +++ b/tests/performance/namespace_packet.py @@ -3,7 +3,7 @@ from socketio import packet def test(): - p = packet.Packet(packet.EVENT, 'hello', namespace='/foo') + p = packet.Packet(packet.EVENT, "hello", namespace="/foo") start = time.time() count = 0 while True: @@ -14,6 +14,6 @@ def test(): return count -if __name__ == '__main__': +if __name__ == "__main__": count = test() - print('namespace_packet:', count, 'packets processed.') + print("namespace_packet:", count, "packets processed.") diff --git a/tests/performance/server_receive.py b/tests/performance/server_receive.py index 77f6161..a52d32b 100644 --- a/tests/performance/server_receive.py +++ b/tests/performance/server_receive.py @@ -6,16 +6,16 @@ def test(): s = socketio.Server(async_handlers=False) start = time.time() count = 0 - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") while True: - s._handle_eio_message('123', '2["test","hello"]') + s._handle_eio_message("123", '2["test","hello"]') count += 1 if time.time() - start >= 5: break return count -if __name__ == '__main__': +if __name__ == "__main__": count = test() - print('server_receive:', count, 'packets received.') + print("server_receive:", count, "packets received.") diff --git a/tests/performance/server_send.py b/tests/performance/server_send.py index b6b2d70..4b01c48 100644 --- a/tests/performance/server_send.py +++ b/tests/performance/server_send.py @@ -14,16 +14,16 @@ def test(): s = Server() start = time.time() count = 0 - s._handle_eio_connect('123', 'environ') - s._handle_eio_message('123', '0') + s._handle_eio_connect("123", "environ") + s._handle_eio_message("123", "0") while True: - s.emit('test', 'hello') + s.emit("test", "hello") count += 1 if time.time() - start >= 5: break return count -if __name__ == '__main__': +if __name__ == "__main__": count = test() - print('server_send:', count, 'packets received.') + print("server_send:", count, "packets received.") diff --git a/tests/performance/server_send_broadcast.py b/tests/performance/server_send_broadcast.py index ce99d0a..b9f4e44 100644 --- a/tests/performance/server_send_broadcast.py +++ b/tests/performance/server_send_broadcast.py @@ -15,16 +15,16 @@ def test(): start = time.time() count = 0 for i in range(100): - s._handle_eio_connect(str(i), 'environ') - s._handle_eio_message(str(i), '0') + s._handle_eio_connect(str(i), "environ") + s._handle_eio_message(str(i), "0") while True: - s.emit('test', 'hello') + s.emit("test", "hello") count += 1 if time.time() - start >= 5: break return count -if __name__ == '__main__': +if __name__ == "__main__": count = test() - print('server_send:', count, 'packets received.') + print("server_send:", count, "packets received.") diff --git a/tests/performance/text_packet.py b/tests/performance/text_packet.py index a28dfd1..051b245 100644 --- a/tests/performance/text_packet.py +++ b/tests/performance/text_packet.py @@ -3,7 +3,7 @@ from socketio import packet def test(): - p = packet.Packet(packet.EVENT, 'hello') + p = packet.Packet(packet.EVENT, "hello") start = time.time() count = 0 while True: @@ -14,6 +14,6 @@ def test(): return count -if __name__ == '__main__': +if __name__ == "__main__": count = test() - print('text_packet:', count, 'packets processed.') + print("text_packet:", count, "packets processed.") diff --git a/tests/web_server.py b/tests/web_server.py index cb24668..cae7b8b 100644 --- a/tests/web_server.py +++ b/tests/web_server.py @@ -15,13 +15,14 @@ class SocketIOWebServer: Note 2: This class only supports the "threading" async_mode, with WebSocket support provided by the simple-websocket package. """ + def __init__(self, sio): - if sio.async_mode != 'threading': + if sio.async_mode != "threading": raise ValueError('The async_mode must be "threading"') def http_app(environ, start_response): - start_response('200 OK', [('Content-Type', 'text/plain')]) - return [b'OK'] + start_response("200 OK", [("Content-Type", "text/plain")]) + return [b"OK"] self.sio = sio self.app = socketio.WSGIApp(sio, http_app) @@ -35,6 +36,7 @@ class SocketIOWebServer: The server is started in a background thread. """ + class ThreadingWSGIServer(ThreadingMixIn, WSGIServer): pass @@ -44,20 +46,21 @@ class SocketIOWebServer: # pass the raw socket to the WSGI app so that it can be used # by WebSocket connections (hack copied from gunicorn) - env['gunicorn.socket'] = self.connection + env["gunicorn.socket"] = self.connection return env - self.httpd = make_server('', port, self._app_wrapper, - ThreadingWSGIServer, WebSocketRequestHandler) + self.httpd = make_server( + "", port, self._app_wrapper, ThreadingWSGIServer, WebSocketRequestHandler + ) self.thread = threading.Thread(target=self.httpd.serve_forever) self.thread.start() # wait for the server to start while True: try: - r = requests.get(f'http://localhost:{port}/') + r = requests.get(f"http://localhost:{port}/") r.raise_for_status() - if r.text == 'OK': + if r.text == "OK": break except: time.sleep(0.1) @@ -77,5 +80,5 @@ class SocketIOWebServer: except StopIteration: # end the WebSocket request without sending a response # (this is a hack that was copied from gunicorn's threaded worker) - start_response('200 OK', []) + start_response("200 OK", []) return []