diff -Nru python-socketio-client-0.6.5/.gitignore python-socketio-client-0.7.2/.gitignore --- python-socketio-client-0.6.5/.gitignore 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/.gitignore 2016-12-11 03:28:43.000000000 +0000 @@ -1,9 +1,14 @@ -*~ -*.sw[op] -*.py[cod] -*.egg -*.egg-info +# Python +*.egg* +*.py[co] +.cache +.coverage +__pycache__ build dist sdist -.coverage +# Transient +*.log +# Vim +*.sw[op] +*~ diff -Nru python-socketio-client-0.6.5/.travis.yml python-socketio-client-0.7.2/.travis.yml --- python-socketio-client-0.6.5/.travis.yml 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/.travis.yml 2016-12-11 03:28:43.000000000 +0000 @@ -3,17 +3,13 @@ - 2.6 - 2.7 - 3.4 + - 3.5 before_install: - - sudo apt-get update - - sudo apt-get install nodejs + - sudo apt-get install nodejs; node --version install: + - pip install -U coverage requests six websocket-client - npm install -G socket.io - - npm install -G yargs - - pip install -U requests - - pip install -U six - - pip install -U websocket-client - - pip install -U coverage before_script: - DEBUG=* node socketIO_client/tests/serve.js & - - sleep 3 + - sleep 1 script: nosetests diff -Nru python-socketio-client-0.6.5/CHANGES.rst python-socketio-client-0.7.2/CHANGES.rst --- python-socketio-client-0.6.5/CHANGES.rst 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/CHANGES.rst 2016-12-11 03:28:43.000000000 +0000 @@ -1,68 +1,36 @@ -0.6.5 ------ -- Updated wait loop to be more responsive under websocket transport - -0.6.4 ------ -- Fixed support for Python 3 +0.7 +--- - Fixed thread cleanup +- Fixed disconnect detection if defined directly thanks to Andreas Strikos +- Fixed support for unicode payloads -0.6.3 ------ -- Upgraded to socket.io protocol 1.x for websocket transport -- Added locks to fix concurrency issues with polling transport -- Fixed SSL support - -0.6.1 ------ +0.6 +--- - Upgraded to socket.io protocol 1.x thanks to Sean Arietta and Joe Palmer - -0.5.6 ------ -- Backported to support requests 0.8.2 - -0.5.5 ------ -- Fixed reconnection in the event of server restart -- Fixed calling on_reconnect() so that it is actually called -- Set default Namespace=None -- Added support for Python 3.4 - -0.5.3 ------ -- Updated wait loop to exit if the client wants to disconnect -- Fixed calling on_connect() so that it is called only once -- Set heartbeat_interval to be half of the heartbeat_timeout - -0.5.2 ------ -- Replaced secure=True with host='https://example.com' -- Fixed sending heartbeats thanks to Travis Odom - -0.5.1 ------ -- Added error handling in the event of websocket timeout -- Fixed sending acknowledgments in custom namespaces thanks to Travis Odom +- Fixed support for Python 3 +- Fixed SSL support +- Added locks to fix concurrency issues with polling transport +- Added SocketIO.off() and SocketIO.once() 0.5 --- -- Rewrote library to use coroutines instead of threads to save memory -- Improved connection resilience -- Added support for xhr-polling thanks to Francis Bull +- Added support for Python 3 - Added support for jsonp-polling thanks to Bernard Pratz +- Added support for xhr-polling thanks to Francis Bull - Added support for query params and cookies +- Fixed sending acknowledgments in custom namespaces thanks to Travis Odom +- Rewrote library to use coroutines instead of threads to save memory 0.4 --- - Added support for custom headers and proxies thanks to Rui and Sajal - Added support for server-side callbacks thanks to Zac Lee -- Added low-level _SocketIO to remove cyclic references - Merged Channel functionality into BaseNamespace thanks to Alexandre Bourget 0.3 --- - Added support for secure connections -- Added socketIO.wait() +- Added SocketIO.wait() - Improved exception handling in _RhythmicThread and _ListenerThread 0.2 diff -Nru python-socketio-client-0.6.5/LICENSE python-socketio-client-0.7.2/LICENSE --- python-socketio-client-0.6.5/LICENSE 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/LICENSE 2016-12-11 03:28:43.000000000 +0000 @@ -1,7 +1,19 @@ Copyright (c) 2013 Roy Hyunjin Han and contributors -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff -Nru python-socketio-client-0.6.5/MANIFEST.in python-socketio-client-0.7.2/MANIFEST.in --- python-socketio-client-0.6.5/MANIFEST.in 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/MANIFEST.in 2016-12-11 03:28:43.000000000 +0000 @@ -1,3 +1,3 @@ recursive-include socketIO_client * -include *.html *.js *.rst +include *.html *.js *.rst LICENSE global-exclude *.pyc diff -Nru python-socketio-client-0.6.5/README.rst python-socketio-client-0.7.2/README.rst --- python-socketio-client-0.6.5/README.rst 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/README.rst 2016-12-11 03:28:43.000000000 +0000 @@ -6,7 +6,7 @@ =============== Here is a `socket.io `_ client library for Python. You can use it to write test code for your socket.io server. -Please note that this version implements `socket.io protocol 1.x `_, which is not backwards compatible. If you want to communicate using `socket.io protocol 0.9 `_ (which is compatible with `gevent-socketio `_), please use `socketIO-client 0.5.6 `_. +Please note that this version implements `socket.io protocol 1.x `_, which is not backwards compatible. If you want to communicate using `socket.io protocol 0.9 `_ (which is compatible with `gevent-socketio `_), please use `socketIO-client 0.5.7.2 `_. Installation @@ -34,19 +34,18 @@ Launch your socket.io server. :: - # Get package folder - PACKAGE_FOLDER=`python -c "import os, socketIO_client;\ - print(os.path.dirname(socketIO_client.__file__))"` - # Start socket.io server - DEBUG=* node $PACKAGE_FOLDER/tests/serve.js - # Start proxy server in a separate terminal on the same machine - DEBUG=* node $PACKAGE_FOLDER/tests/proxy.js + cd $(python -c "import os, socketIO_client;\ + print(os.path.dirname(socketIO_client.__file__))") + + DEBUG=* node tests/serve.js # Start socket.io server in terminal one + DEBUG=* node tests/proxy.js # Start proxy server in terminal two + nosetests # Run tests in terminal three For debugging information, run these commands first. :: import logging - logging.getLogger('requests').setLevel(logging.WARNING) - logging.basicConfig(level=logging.DEBUG) + logging.getLogger('socketIO-client').setLevel(logging.DEBUG) + logging.basicConfig() Emit. :: @@ -71,12 +70,38 @@ from socketIO_client import SocketIO, LoggingNamespace + def on_connect(): + print('connect') + + def on_disconnect(): + print('disconnect') + + def on_reconnect(): + print('reconnect') + def on_aaa_response(*args): print('on_aaa_response', args) socketIO = SocketIO('localhost', 8000, LoggingNamespace) + socketIO.on('connect', on_connect) + socketIO.on('disconnect', on_disconnect) + socketIO.on('reconnect', on_reconnect) + + # Listen socketIO.on('aaa_response', on_aaa_response) socketIO.emit('aaa') + socketIO.emit('aaa') + socketIO.wait(seconds=1) + + # Stop listening + socketIO.off('aaa_response') + socketIO.emit('aaa') + socketIO.wait(seconds=1) + + # Listen only once + socketIO.once('aaa_response', on_aaa_response) + socketIO.emit('aaa') # Activate aaa_response + socketIO.emit('aaa') # Ignore socketIO.wait(seconds=1) Define events in a namespace. :: @@ -102,6 +127,12 @@ def on_connect(self): print('[Connected]') + def on_reconnect(self): + print('[Reconnected]') + + def on_disconnect(self): + print('[Disconnected]') + socketIO = SocketIO('localhost', 8000, Namespace) socketIO.wait(seconds=1) @@ -127,11 +158,17 @@ news_namespace.emit('aaa') socketIO.wait(seconds=1) -Connect via SSL. :: +Connect via SSL (https://github.com/invisibleroads/socketIO-client/issues/54). :: from socketIO_client import SocketIO + # Skip server certificate verification SocketIO('https://localhost', verify=False) + # Verify the server certificate + SocketIO('https://localhost', verify='server.crt') + # Verify the server certificate and encrypt using client certificate + socketIO = SocketIO('https://localhost', verify='server.crt', cert=( + 'client.crt', 'client.key')) Specify params, headers, cookies, proxies thanks to the `requests `_ library. :: @@ -164,7 +201,8 @@ - `Hiroki Ohtani `_ wrote `websocket-client `_. - `rod `_ wrote a `prototype for a Python client to a socket.io server `_. - `Alexandre Bourget `_ wrote `gevent-socketio `_, which is a socket.io server written in Python. -- `Paul Kienzle `_, `Zac Lee `_, `Josh VanderLinden `_, `Ian Fitzpatrick `_, `Lucas Klein `_, `Rui Chicoria `_, `Travis Odom `_, `Patrick Huber `_, `Brad Campbell `_, `Daniel `_, `Sean Arietta `_ submitted code to expand support of the socket.io protocol. +- `Paul Kienzle `_, `Zac Lee `_, `Josh VanderLinden `_, `Ian Fitzpatrick `_, `Lucas Klein `_, `Rui Chicoria `_, `Travis Odom `_, `Patrick Huber `_, `Brad Campbell `_, `Daniel `_, `Sean Arietta `_, `Sacha Stafyniak `_ submitted code to expand support of the socket.io protocol. - `Bernard Pratz `_, `Francis Bull `_ wrote prototypes to support xhr-polling and jsonp-polling. -- `Eric Chen `_, `Denis Zinevich `_, `Thiago Hersan `_, `Nayef Copty `_, `Jörgen Karlsson `_, `Branden Ghena `_, `Tim Landscheidt `_, `Matt Porritt `_ suggested ways to make the connection more robust. -- `Merlijn van Deen `_, `Frederic Sureau `_, `Marcus Cobden `_, `Drew Hutchison `_, `wuurrd `_, `Adam Kecer `_, `Alex Monk `_, `Vishal P R `_, `John Vandenberg `_, `Thomas Grainger `_ proposed changes that make the library more friendly and practical for you! +- `Joe Palmer `_ sponsored development. +- `Eric Chen `_, `Denis Zinevich `_, `Thiago Hersan `_, `Nayef Copty `_, `Jörgen Karlsson `_, `Branden Ghena `_, `Tim Landscheidt `_, `Matt Porritt `_, `Matt Dainty `_, `Thomaz de Oliveira dos Reis `_, `Felix König `_, `George Wilson `_, `Andreas Strikos `_, `Alessio Sergi `_ `Claudio Yacarini `_, `Khairi Hafsham `_, `Robbie Clarken `_ suggested ways to make the connection more robust. +- `Merlijn van Deen `_, `Frederic Sureau `_, `Marcus Cobden `_, `Drew Hutchison `_, `wuurrd `_, `Adam Kecer `_, `Alex Monk `_, `Vishal P R `_, `John Vandenberg `_, `Thomas Grainger `_, `Daniel Quinn `_, `Adric Worley `_, `Adam Roses Wight `_, `Jan Včelák `_ proposed changes that make the library more friendly and practical for you! diff -Nru python-socketio-client-0.6.5/TODO.goals python-socketio-client-0.7.2/TODO.goals --- python-socketio-client-0.6.5/TODO.goals 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/TODO.goals 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -Implement rooms #65 -Implement binary event -Implement binary ack diff -Nru python-socketio-client-0.6.5/debian/changelog python-socketio-client-0.7.2/debian/changelog --- python-socketio-client-0.6.5/debian/changelog 2022-11-14 13:01:33.000000000 +0000 +++ python-socketio-client-0.7.2/debian/changelog 2023-11-29 23:27:48.000000000 +0000 @@ -1,3 +1,20 @@ +python-socketio-client (0.7.2-1) unstable; urgency=low + + * New upstream version 0.7.2 + * adopt package + * set "R³: no" + * bump Standards-Version to 4.6.2, no further change needed. + + [ Jelmer Vernooij ] + * Migrate repository from Alioth to Salsa. + + [ Debian Janitor ] + Use secure copyright file specification URI. + Bump debhelper from deprecated 9 to 13. + Set debhelper-compat version in Build-Depends. + + -- Alexandre Detiste Thu, 30 Nov 2023 00:27:48 +0100 + python-socketio-client (0.6.5-1) unstable; urgency=medium * QA upload. diff -Nru python-socketio-client-0.6.5/debian/compat python-socketio-client-0.7.2/debian/compat --- python-socketio-client-0.6.5/debian/compat 2016-01-11 12:48:43.000000000 +0000 +++ python-socketio-client-0.7.2/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -9 diff -Nru python-socketio-client-0.6.5/debian/control python-socketio-client-0.7.2/debian/control --- python-socketio-client-0.6.5/debian/control 2022-11-14 13:01:33.000000000 +0000 +++ python-socketio-client-0.7.2/debian/control 2023-11-29 23:27:48.000000000 +0000 @@ -1,15 +1,16 @@ Source: python-socketio-client Section: python Priority: optional -Maintainer: Debian QA Group -Build-Depends: debhelper (>= 9) - , dh-python +Maintainer: Alexandre Detiste +Build-Depends: debhelper-compat (= 13) + , dh-sequence-python3 , python3-all , python3-setuptools -Standards-Version: 3.9.6 +Standards-Version: 4.6.2 Homepage: https://github.com/invisibleroads/socketIO-client -Vcs-Git: git://anonscm.debian.org/collab-maint/python-socketio-client.git -Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/python-socketio-client.git +Vcs-Git: https://salsa.debian.org/debian/python-socketio-client.git +Vcs-Browser: https://salsa.debian.org/debian/python-socketio-client +Rules-Requires-Root: no Package: python3-socketio-client Architecture: all diff -Nru python-socketio-client-0.6.5/debian/copyright python-socketio-client-0.7.2/debian/copyright --- python-socketio-client-0.6.5/debian/copyright 2016-01-11 12:48:43.000000000 +0000 +++ python-socketio-client-0.7.2/debian/copyright 2023-11-29 23:21:29.000000000 +0000 @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: socketIO-client Source: https://github.com/invisibleroads/socketIO-client @@ -8,6 +8,10 @@ Files: debian/* Copyright: 2014 Leo Iannacone + 2016 Apollon Oikonomopoulos + 2019 Ondřej Nový + 2022 Marcos Talau + 2023 Alexandre Detiste License: Expat License: Expat diff -Nru python-socketio-client-0.6.5/debian/python3-socketio-client.docs python-socketio-client-0.7.2/debian/python3-socketio-client.docs --- python-socketio-client-0.6.5/debian/python3-socketio-client.docs 2019-10-27 18:45:56.000000000 +0000 +++ python-socketio-client-0.7.2/debian/python3-socketio-client.docs 2023-11-29 23:06:29.000000000 +0000 @@ -1,2 +1 @@ README.rst -TODO.goals diff -Nru python-socketio-client-0.6.5/debian/rules python-socketio-client-0.7.2/debian/rules --- python-socketio-client-0.6.5/debian/rules 2019-10-27 18:47:31.000000000 +0000 +++ python-socketio-client-0.7.2/debian/rules 2023-11-29 23:26:47.000000000 +0000 @@ -8,10 +8,9 @@ export PYBUILD_DISABLE=test %: - dh $@ --with python3 --buildsystem=pybuild + dh $@ --buildsystem=pybuild -override_dh_auto_clean: - dh_auto_clean +execute_after_dh_auto_clean: rm -fr socketIO_client.egg-info override_dh_installchangelogs: diff -Nru python-socketio-client-0.6.5/debian/upstream/metadata python-socketio-client-0.7.2/debian/upstream/metadata --- python-socketio-client-0.6.5/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ python-socketio-client-0.7.2/debian/upstream/metadata 2023-11-29 23:16:15.000000000 +0000 @@ -0,0 +1,4 @@ +--- +Bug-Database: https://github.com/invisibleroads/socketIO-client/issues +Bug-Submit: https://github.com/invisibleroads/socketIO-client/issues/new +Repository-Browse: https://github.com/invisibleroads/socketIO-client diff -Nru python-socketio-client-0.6.5/debian/watch python-socketio-client-0.7.2/debian/watch --- python-socketio-client-0.6.5/debian/watch 2016-01-11 12:48:43.000000000 +0000 +++ python-socketio-client-0.7.2/debian/watch 2023-11-29 23:18:09.000000000 +0000 @@ -1,3 +1,3 @@ -version=3 +version=4 opts=filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/python-socketio-client-$1\.tar\.gz/ \ https://github.com/invisibleroads/socketIO-client/tags .*/v?(\d\S*)\.tar\.gz diff -Nru python-socketio-client-0.6.5/missions/Done/PullRequests-20160331.md python-socketio-client-0.7.2/missions/Done/PullRequests-20160331.md --- python-socketio-client-0.6.5/missions/Done/PullRequests-20160331.md 1970-01-01 00:00:00.000000000 +0000 +++ python-socketio-client-0.7.2/missions/Done/PullRequests-20160331.md 2016-12-11 03:28:43.000000000 +0000 @@ -0,0 +1,143 @@ +# Vision +Ensure that Python scripts can communicate with a Socket.IO server. + +# Mission +Address pull requests. + +# Owner +Roy Hyunjin Han + +# Context +It is important to demonstrate discipline in maintaining an open source project. + +# Timeframe +20160331-1245 - 20160417-1245: 17 days estimated + +20160331-1245 - 20160715-1700: 107 days actual + +# Objectives +1. + Make sure that the library works as promised. +2. + Address pull requests. + +# Log + +20160331-1300 - 20160331-1500 + +Make sure that the library works as promised. + +I think that if I allocate a few hours each day, then I should be able to get this done on schedule. + + + Clone repository + + Download socket.io + + Work through chat application example + + Start a new branch + +We'll just check whether all unit tests pass. We should also change our tests to use pytest. + + + Check that library works with both versions of socket.io + + + Test that socket.io-0.9.14 works with socketIO-client-0.5.6 + + cd ~/Projects/socketIO-client-0.5.6 + python setup.py develop + pip install -I -U nose + npm install socket.io@0.9.14 + node serve-tests + ~/.virtualenvs/crosscompute/bin/nosetests + + + Test that socket.io-1.4.5 works with socketIO-client-0.6.5 + + cd ~/Projects/socketIO-client-0.6.5 + python setup.py develop + pip install -I -U nose + npm install socket.io yargs + node socketIO_client/tests/serve.js + ~/.virtualenvs/crosscompute/bin/nosetests + +Well, I'm pleasantly surprised. Both tests still pass! + + _ Write an experiment to detect version of socket.io on server + + Option 1 is to try to connect with both and avoid the one that fails. But that is naive. + + Connect socketIO-client-0.5.6 to socket.io-1.4.5 and see what happens (it just hangs) + + Connect socketIO-client-0.6.5 to socket.io-0.9.14 and see what happens (warning: connection refused) + _ Option 2 is to have more precision by testing certain connection points. + +Let's try "Connect socketIO-client-0.6.5 to socket.io-0.9.14" again. + + WARNING:root:localhost:9000/socket.io [waiting for connection] HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /socket.io/?EIO=3&transport=polling&t=1459452848797-0 (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 111] Connection refused',)) + +After thinking about it some more, I think supporting both protocols in the same library will be needlessly complicated. We will keep the existing structure of having different versions for different protocols. + +20160331-2010 - 20160331-2030 + + + Add documentation for server SSL certification verification + + Add documentation for client SSL certification encryption + +20160331-2030 - 20160331-2130 + + + Work through one pull request + +20160403-1100 - 20160403-1200: 1 hour estimated + +20160403-1100 - 20160403-1400: 3 hours actual + + + Work through one pull request + +20160625-1815 - 20160625-1845: 30 minutes + +I am noticing some thread-related errors. + +For example, here is an error that appears + + Exception in thread Thread-1 (most likely raised during interpreter shutdown): + Traceback (most recent call last): + File "/usr/lib64/python2.7/threading.py", line 804, in __bootstrap_inner + File "/home/rhh/.virtualenvs/crosscompute/lib/python2.7/site-packages/socketIO_client/heartbeats.py", line 34, in run + File "/usr/lib64/python2.7/threading.py", line 617, in wait + File "/usr/lib64/python2.7/threading.py", line 367, in wait + : list.remove(x): x not in list + Unhandled exception in thread started by + sys.excepthook is missing + lost sys.stderr + +I am looking at line 367 of threading.py but it looks like the exception should have been ignored. + + try: + self.__waiters.remove(waiter) + except ValueError: + pass + +I think the ValueError is coming from somewhere else. + + - https://github.com/segmentio/analytics-python/issues/69 + - http://stackoverflow.com/questions/9532264/how-to-use-multiple-threads + +For now, let's just wait for the heartbeat thread to join. + + self._heartbeat_thread.join() + +If the exception appears again, then we'll use atexit.register(self._heartbeat_thread.join()). + +20160714-2053 + +The issue is that packet_text has utf-8 but we need a bytestring and six.b only encodes using latin-1. + + Option 1: Encode packet_text into a bytestring using utf-8, but then we won't be working with unicode. + Option 2: Leave packet_text alone and handle it differently based on whether it is unicode or a bytestring. + +20160715-1315 + +After thinking about it a bit, I think the second approach is more robust, because we'll just leave the packet data as it is mostly and just handle it verbatim. The first option can be vulnerable to cases where the packet type might be wrong? + +20160715-1700 + +If I ever do revisit binary support, I should try to generate a log of the binary protocol using Chrome Developer Tools. There were some notes about XHR2 vs base64. + + - https://github.com/socketio/engine.io-protocol + - https://github.com/socketio/socket.io-protocol + +The feus4177 repository has a working solution for binary support, but I didn't completely understand how it worked and I felt uncomfortable about merging something without full understanding. + +I also wanted to address unicode support and the decision was to keep everything as an encoded bytestring and only decode for non-binary events. I tried the approach of leaving the packet alone and just handling unicode or bytestring on a case by case basis, but it proved too messy. + +Perhaps when my life becomes less complex, I'll revisit both binary and unicode support. But for now, I have too many things in my head and my capacity for extra complexity is becoming rather limited. diff -Nru python-socketio-client-0.6.5/missions/PullRequests-20161209.md python-socketio-client-0.7.2/missions/PullRequests-20161209.md --- python-socketio-client-0.6.5/missions/PullRequests-20161209.md 1970-01-01 00:00:00.000000000 +0000 +++ python-socketio-client-0.7.2/missions/PullRequests-20161209.md 2016-12-11 03:28:43.000000000 +0000 @@ -0,0 +1,76 @@ +# Vision +Ensure that Python scripts can communicate with a Socket.IO server. + +# Mission +Address pull requests. + +# Owner +Roy Hyunjin Han + +# Context +Some of our systems now rely on this package. + +# Timeframe +20161209-2100 - 20161223-2100: 2 weeks estimated + +# Objectives +1. Review pull requests. +2. Review issues. +3. Release version. + +# Log + +20161209-2130 - 20161209-2230: 1 hour + + + Make decision on websocket-client issue for #139 + + Merge #139 into 0.7.2 + +20161209-2330 - 20161210-0000: 30 minutes + + + Merge #125 into 0.5.7.2 + +20161210-0045 - 20161210-0115: 30 minutes + + + Merge #136 into 0.7.2 + +20161210-1100 - 20161210-1200: 1 hour + + + Merge #135 into 0.7.2 + +20161210-2200 - 20161210-2230: 30 minutes + +I tried experimenting for a while with unicode events, where there are unicode characters in the event name, but it seems that Python 2 does not support unicode attributes. + +# Tasks + + + Release 0.5.7.2 + + Release 0.7.2 + Release 0.8.0 + + Add binary support + https://github.com/invisibleroads/socketIO-client/pull/85 + https://github.com/invisibleroads/socketIO-client/issues/70 + https://github.com/invisibleroads/socketIO-client/issues/71 + https://github.com/invisibleroads/socketIO-client/issues/91 + Replace *args with args + Investigate whether it is really true that callbacks can't take dictionaries + https://github.com/invisibleroads/socketIO-client/pull/112 + Check python3 support for socketIO-client 0.5.6 + https://github.com/invisibleroads/socketIO-client/issues/83 + Check why connected=True after termination + https://github.com/invisibleroads/socketIO-client/issues/80 + https://github.com/invisibleroads/socketIO-client/issues/98 + Consider catching heartbeat thread exception + https://github.com/invisibleroads/socketIO-client/issues/100 + Check disconnection issues + https://github.com/invisibleroads/socketIO-client/issues/107 + https://github.com/invisibleroads/socketIO-client/issues/111 + Check why transports are not being set + https://github.com/invisibleroads/socketIO-client/issues/102 + Look at 404 not found error + https://github.com/invisibleroads/socketIO-client/issues/101 + Check whether it works on Windows 8 + https://github.com/invisibleroads/socketIO-client/issues/97 + Consider allowing milliseconds + https://github.com/invisibleroads/socketIO-client/issues/106 + Consider using attrs instead of namedtuple diff -Nru python-socketio-client-0.6.5/missions/README.md python-socketio-client-0.7.2/missions/README.md --- python-socketio-client-0.6.5/missions/README.md 1970-01-01 00:00:00.000000000 +0000 +++ python-socketio-client-0.7.2/missions/README.md 2016-12-11 03:28:43.000000000 +0000 @@ -0,0 +1,23 @@ +# Vision +Describe your long-term goal for the project. + +# Mission +Describe a short-term goal that you can complete within two weeks. + +# Owner +State your name. + +# Context +Explain why the mission is important. + +# Timeframe +Give dates for when you will start and finish the mission. + +# Objectives +Specify at most three goals that must be achieved for the mission to be successful. + +# Log +Record progress toward objectives. + +# Tasks +List remaining tasks. diff -Nru python-socketio-client-0.6.5/setup.py python-socketio-client-0.7.2/setup.py --- python-socketio-client-0.6.5/setup.py 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/setup.py 2016-12-11 03:28:43.000000000 +0000 @@ -3,13 +3,6 @@ from setuptools import find_packages, setup -REQUIREMENTS = [ - 'requests', - 'six', - 'websocket-client', -] - - HERE = dirname(abspath(__file__)) LOAD_TEXT = lambda name: io.open(join(HERE, name), encoding='UTF-8').read() DESCRIPTION = '\n\n'.join(LOAD_TEXT(_) for _ in [ @@ -17,8 +10,8 @@ 'CHANGES.rst', ]) setup( - name='socketIO_client', - version='0.6.5', + name='socketIO-client', + version='0.7.2', description='A socket.io client library', long_description=DESCRIPTION, license='MIT', @@ -32,7 +25,11 @@ author='Roy Hyunjin Han', author_email='rhh@crosscompute.com', url='https://github.com/invisibleroads/socketIO-client', - install_requires=REQUIREMENTS, + install_requires=[ + 'requests>=2.7.0', + 'six', + 'websocket-client', + ], tests_require=[ 'nose', 'coverage', diff -Nru python-socketio-client-0.6.5/socketIO_client/__init__.py python-socketio-client-0.7.2/socketIO_client/__init__.py --- python-socketio-client-0.6.5/socketIO_client/__init__.py 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/socketIO_client/__init__.py 2016-12-11 03:28:43.000000000 +0000 @@ -1,9 +1,11 @@ +import atexit + from .exceptions import ConnectionError, TimeoutError, PacketError from .heartbeats import HeartbeatThread from .logs import LoggingMixin from .namespaces import ( - EngineIONamespace, SocketIONamespace, LoggingSocketIONamespace, - find_callback) + EngineIONamespace, SocketIONamespace, + LoggingSocketIONamespace, find_callback, make_logging_prefix) from .parsers import ( parse_host, parse_engineIO_session, format_socketIO_packet_data, parse_socketIO_packet_data, @@ -14,7 +16,7 @@ __all__ = 'SocketIO', 'SocketIONamespace' -__version__ = '0.6.3' +__version__ = '0.7.0' BaseNamespace = SocketIONamespace LoggingNamespace = LoggingSocketIONamespace @@ -43,8 +45,9 @@ self._http_session = prepare_http_session(kw) self._log_name = self._url - self._wants_to_close = False self._opened = False + self._wants_to_close = False + atexit.register(self._close) if Namespace: self.define(Namespace) @@ -75,7 +78,8 @@ except (TimeoutError, ConnectionError) as e: if not self._wait_for_connection: raise - warning = Exception('[waiting for connection] %s' % e) + warning = Exception( + '[engine.io waiting for connection] %s' % e) warning_screen.throw(warning) assert engineIO_packet_type == 0 # engineIO_packet_type == open return parse_engineIO_session(engineIO_packet_data) @@ -98,7 +102,7 @@ self._warn('unexpected engine.io packet') except Exception: pass - self._debug('[transport selected] %s', self.transport_name) + self._debug('[engine.io transport selected] %s', self.transport_name) def _reset_heartbeat(self): try: @@ -120,7 +124,7 @@ self._heartbeat_thread.start() if hurried: self._heartbeat_thread.hurry() - self._debug('[heartbeat reset]') + self._debug('[engine.io heartbeat reset]') def _connect_namespaces(self): pass @@ -156,6 +160,20 @@ namespace = self.define(EngineIONamespace) return namespace.on(event, callback) + def once(self, event, callback): + try: + namespace = self.get_namespace() + except PacketError: + namespace = self.define(EngineIONamespace) + return namespace.once(event, callback) + + def off(self, event): + try: + namespace = self.get_namespace() + except PacketError: + namespace = self.define(EngineIONamespace) + return namespace.off(event) + def get_namespace(self): try: return self._namespace @@ -175,9 +193,10 @@ self._wants_to_close = True try: self._heartbeat_thread.halt() + self._heartbeat_thread.join() except AttributeError: pass - if not self._opened: + if not hasattr(self, '_opened') or not self._opened: return engineIO_packet_type = 1 try: @@ -232,6 +251,9 @@ self._process_packets() except TimeoutError: pass + except KeyboardInterrupt: + self._close() + raise except ConnectionError as e: self._opened = False try: @@ -241,7 +263,7 @@ self._warn(warning) try: namespace = self.get_namespace() - namespace.on_disconnect() + namespace._find_packet_callback('disconnect')() except PacketError: pass self._heartbeat_thread.relax() @@ -275,7 +297,7 @@ raise PacketError( 'unexpected engine.io packet type (%s)' % engineIO_packet_type) delegate(engineIO_packet_data, namespace) - if engineIO_packet_type is 4: + if engineIO_packet_type == 4: return engineIO_packet_data def _on_open(self, data, namespace): @@ -356,7 +378,7 @@ self._namespace_by_path[path] = namespace = Namespace(self, path) if path: self.connect(path) - self.wait(for_connect=True) + self.wait(for_namespace=namespace) return namespace def on(self, event, callback, path=''): @@ -374,26 +396,30 @@ # Act - def connect(self, path, with_transport_instance=False): - socketIO_packet_type = 0 - socketIO_packet_data = format_socketIO_packet_data(path) - self._message( - str(socketIO_packet_type) + socketIO_packet_data, - with_transport_instance) + def connect(self, path='', with_transport_instance=False): + if path or not self.connected: + socketIO_packet_type = 0 + socketIO_packet_data = format_socketIO_packet_data(path) + self._message( + str(socketIO_packet_type) + socketIO_packet_data, + with_transport_instance) + self._wants_to_close = False def disconnect(self, path=''): - if not path or not self._opened: - self._close() - elif path: + if path and self._opened: socketIO_packet_type = 1 socketIO_packet_data = format_socketIO_packet_data(path) try: self._message(str(socketIO_packet_type) + socketIO_packet_data) except (TimeoutError, ConnectionError): pass + elif not path: + self._close() try: - namespace = self._namespace_by_path.pop(path) - namespace.on_disconnect() + namespace = self._namespace_by_path[path] + namespace._find_packet_callback('disconnect')() + if path: + del self._namespace_by_path[path] except KeyError: pass @@ -423,13 +449,17 @@ def wait_for_callbacks(self, seconds=None): self.wait(seconds, for_callbacks=True) - def _should_stop_waiting(self, for_connect=False, for_callbacks=False): - if for_connect: - for namespace in self._namespace_by_path.values(): - is_namespace_connected = getattr( - namespace, '_connected', False) - if not is_namespace_connected: - return False + def _should_stop_waiting(self, for_namespace=False, for_callbacks=False): + if for_namespace: + namespace = for_namespace + if getattr(namespace, '_invalid', False): + raise ConnectionError( + 'invalid socket.io namespace (%s)' % namespace.path) + if not getattr(namespace, '_connected', False): + self._debug( + '%s[socket.io waiting for connection]', + make_logging_prefix(namespace.path)) + return False return True if for_callbacks and not self._has_ack_callback: return True @@ -458,19 +488,20 @@ except KeyError: raise PacketError( 'unexpected socket.io packet type (%s)' % socketIO_packet_type) - delegate(socketIO_packet_data, namespace) + delegate(parse_socketIO_packet_data(socketIO_packet_data), namespace) return socketIO_packet_data - def _on_connect(self, data, namespace): + def _on_connect(self, data_parsed, namespace): namespace._connected = True namespace._find_packet_callback('connect')() + self._debug( + '%s[socket.io connected]', make_logging_prefix(namespace.path)) - def _on_disconnect(self, data, namespace): + def _on_disconnect(self, data_parsed, namespace): namespace._connected = False namespace._find_packet_callback('disconnect')() - def _on_event(self, data, namespace): - data_parsed = parse_socketIO_packet_data(data) + def _on_event(self, data_parsed, namespace): args = data_parsed.args try: event = args.pop(0) @@ -481,21 +512,20 @@ data_parsed.path, data_parsed.ack_id)) namespace._find_packet_callback(event)(*args) - def _on_ack(self, data, namespace): - data_parsed = parse_socketIO_packet_data(data) + def _on_ack(self, data_parsed, namespace): try: ack_callback = self._get_ack_callback(data_parsed.ack_id) except KeyError: return ack_callback(*data_parsed.args) - def _on_error(self, data, namespace): - namespace._find_packet_callback('error')(data) + def _on_error(self, data_parsed, namespace): + namespace._find_packet_callback('error')(*data_parsed.args) - def _on_binary_event(self, data, namespace): + def _on_binary_event(self, data_parsed, namespace): self._warn('[not implemented] binary event') - def _on_binary_ack(self, data, namespace): + def _on_binary_ack(self, data_parsed, namespace): self._warn('[not implemented] binary ack') def _prepare_to_send_ack(self, path, ack_id): diff -Nru python-socketio-client-0.6.5/socketIO_client/logs.py python-socketio-client-0.7.2/socketIO_client/logs.py --- python-socketio-client-0.6.5/socketIO_client/logs.py 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/socketIO_client/logs.py 2016-12-11 03:28:43.000000000 +0000 @@ -1,11 +1,17 @@ import logging import time +from .symmetries import NullHandler + + +LOG = logging.getLogger('socketIO-client') +LOG.addHandler(NullHandler()) + class LoggingMixin(object): def _log(self, level, msg, *attrs): - logging.log(level, '%s %s' % (self._log_name, msg), *attrs) + LOG.log(level, '%s %s' % (self._log_name, msg), *attrs) def _debug(self, msg, *attrs): self._log(logging.DEBUG, msg, *attrs) diff -Nru python-socketio-client-0.6.5/socketIO_client/namespaces.py python-socketio-client-0.7.2/socketIO_client/namespaces.py --- python-socketio-client-0.6.5/socketIO_client/namespaces.py 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/socketIO_client/namespaces.py 2016-12-11 03:28:43.000000000 +0000 @@ -7,6 +7,7 @@ def __init__(self, io): self._io = io self._callback_by_event = {} + self._once_events = set() self._log_name = io._url self.initialize() @@ -18,6 +19,19 @@ 'Define a callback to handle an event emitted by the server' self._callback_by_event[event] = callback + def once(self, event, callback): + 'Define a callback to handle the first event emitted by the server' + self._once_events.add(event) + self.on(event, callback) + + def off(self, event): + 'Remove an event handler' + try: + self._once_events.remove(event) + except KeyError: + pass + self._callback_by_event.pop(event, None) + def send(self, data): 'Send a message' self._io.send(data) @@ -53,9 +67,13 @@ def _find_packet_callback(self, event): # Check callbacks defined by on() try: - return self._callback_by_event[event] + callback = self._callback_by_event[event] except KeyError: pass + else: + if event in self._once_events: + self.off(event) + return callback # Check callbacks defined explicitly return getattr(self, 'on_' + event) @@ -119,6 +137,8 @@ def on_error(self, data): """Called after socket.io sends an error packet. You can override this method.""" + if data.lower() == 'invalid namespace': + self._invalid = True def _find_packet_callback(self, event): # Interpret events @@ -129,9 +149,13 @@ event = 'reconnect' # Check callbacks defined by on() try: - return self._callback_by_event[event] + callback = self._callback_by_event[event] except KeyError: pass + else: + if event in self._once_events: + self.off(event) + return callback # Check callbacks defined explicitly or use on_event() return getattr( self, 'on_' + event.replace(' ', '_'), @@ -181,17 +205,17 @@ def on_connect(self): self._debug( - '%s[socket.io connect]', _make_logging_header(self.path)) + '%s[socket.io connect]', make_logging_prefix(self.path)) super(LoggingSocketIONamespace, self).on_connect() def on_reconnect(self): self._debug( - '%s[socket.io reconnect]', _make_logging_header(self.path)) + '%s[socket.io reconnect]', make_logging_prefix(self.path)) super(LoggingSocketIONamespace, self).on_reconnect() def on_disconnect(self): self._debug( - '%s[socket.io disconnect]', _make_logging_header(self.path)) + '%s[socket.io disconnect]', make_logging_prefix(self.path)) super(LoggingSocketIONamespace, self).on_disconnect() def on_event(self, event, *args): @@ -200,14 +224,14 @@ if callback: arguments.append('callback(*args)') self._info( - '%s[socket.io event] %s(%s)', _make_logging_header(self.path), + '%s[socket.io event] %s(%s)', make_logging_prefix(self.path), event, ', '.join(arguments)) super(LoggingSocketIONamespace, self).on_event(event, *args) def on_error(self, data): - self._debug( - '%s[socket.io error] %s', _make_logging_header(self.path), data) - super(LoggingSocketIONamespace, self).on_error() + self._warn( + '%s[socket.io error] %s', make_logging_prefix(self.path), data) + super(LoggingSocketIONamespace, self).on_error(data) def find_callback(args, kw=None): @@ -220,5 +244,5 @@ return None, args -def _make_logging_header(path): +def make_logging_prefix(path): return path + ' ' if path else '' diff -Nru python-socketio-client-0.6.5/socketIO_client/parsers.py python-socketio-client-0.7.2/socketIO_client/parsers.py --- python-socketio-client-0.6.5/socketIO_client/parsers.py 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/socketIO_client/parsers.py 2016-12-11 03:28:43.000000000 +0000 @@ -1,8 +1,9 @@ import json +import six from collections import namedtuple +from six.moves.urllib.parse import urlparse as parse_url -from .symmetries import ( - decode_string, encode_string, get_byte, get_character, parse_url) +from .symmetries import decode_string, encode_string, get_byte, get_character EngineIOSession = namedtuple('EngineIOSession', [ @@ -16,7 +17,7 @@ url_pack = parse_url(host) is_secure = url_pack.scheme == 'https' port = port or url_pack.port or (443 if is_secure else 80) - url = '%s:%d%s/%s' % (url_pack.hostname, port, url_pack.path, resource) + url = '%s:%s%s/%s' % (url_pack.hostname, port, url_pack.path, resource) return is_secure, url @@ -82,6 +83,8 @@ args = json.loads(data) except ValueError: args = [] + if isinstance(args, six.string_types): + args = [args] return SocketIOData(path=path, ack_id=ack_id, args=args) diff -Nru python-socketio-client-0.6.5/socketIO_client/symmetries.py python-socketio-client-0.7.2/socketIO_client/symmetries.py --- python-socketio-client-0.6.5/socketIO_client/symmetries.py 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/socketIO_client/symmetries.py 2016-12-11 03:28:43.000000000 +0000 @@ -1,29 +1,41 @@ -import six try: - from urllib import urlencode as format_query -except ImportError: - from urllib.parse import urlencode as format_query + from logging import NullHandler +except ImportError: # Python 2.6 + from logging import Handler + + class NullHandler(Handler): + + def emit(self, record): + pass + + +from six import indexbytes + + try: - from urlparse import urlparse as parse_url + from ssl import SSLError except ImportError: - from urllib.parse import urlparse as parse_url + class SSLError(Exception): + pass + + try: memoryview = memoryview except NameError: memoryview = buffer +def get_byte(x, index): + return indexbytes(x, index) + + def get_character(x, index): return chr(get_byte(x, index)) -def get_byte(x, index): - return six.indexbytes(x, index) +def decode_string(x): + return x.decode('utf-8') def encode_string(x): return x.encode('utf-8') - - -def decode_string(x): - return x.decode('utf-8') diff -Nru python-socketio-client-0.6.5/socketIO_client/tests/__init__.py python-socketio-client-0.7.2/socketIO_client/tests/__init__.py --- python-socketio-client-0.6.5/socketIO_client/tests/__init__.py 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/socketIO_client/tests/__init__.py 2016-12-11 03:28:43.000000000 +0000 @@ -1,14 +1,22 @@ +# coding: utf-8 import logging import time from unittest import TestCase from .. import SocketIO, LoggingNamespace, find_callback +from ..exceptions import ConnectionError HOST = 'localhost' PORT = 9000 DATA = 'xxx' PAYLOAD = {'xxx': 'yyy'} +UNICODE_PAYLOAD = {u'인삼': u'뿌리'} +BINARY_DATA = bytearray(b'\xff\xff\xff') +BINARY_PAYLOAD = { + 'data': BINARY_DATA, + 'array': [bytearray(b'\xee'), bytearray(b'\xdd')] +} logging.basicConfig(level=logging.DEBUG) @@ -16,7 +24,7 @@ def setUp(self): super(BaseMixin, self).setUp() - self.called_on_response = False + self.response_count = 0 self.wait_time_in_seconds = 1 def tearDown(self): @@ -25,12 +33,43 @@ def test_disconnect(self): 'Disconnect' + self.socketIO.on('disconnect', self.on_event) + self.assertTrue(self.socketIO.connected) + self.assertEqual(self.response_count, 0) + self.socketIO.disconnect() + self.assertFalse(self.socketIO.connected) + self.assertEqual(self.response_count, 1) + + def test_disconnect_with_namespace(self): + 'Disconnect with namespace' namespace = self.socketIO.define(Namespace) self.assertTrue(self.socketIO.connected) - self.assertFalse(namespace.called_on_disconnect) + self.assertFalse('disconnect' in namespace.args_by_event) self.socketIO.disconnect() - self.assertTrue(namespace.called_on_disconnect) self.assertFalse(self.socketIO.connected) + self.assertTrue('disconnect' in namespace.args_by_event) + + def test_reconnect(self): + 'Reconnect' + self.socketIO.on('reconnect', self.on_event) + self.assertEqual(self.response_count, 0) + self.socketIO.connect() + self.assertEqual(self.response_count, 0) + self.socketIO.disconnect() + self.socketIO.connect() + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(self.response_count, 1) + + def test_reconnect_with_namespace(self): + 'Reconnect with namespace' + namespace = self.socketIO.define(Namespace) + self.assertFalse('reconnect' in namespace.args_by_event) + self.socketIO.connect() + self.assertFalse('reconnect' in namespace.args_by_event) + self.socketIO.disconnect() + self.socketIO.connect() + self.socketIO.wait(self.wait_time_in_seconds) + self.assertTrue('reconnect' in namespace.args_by_event) def test_emit(self): 'Emit' @@ -59,32 +98,81 @@ 'emit_with_multiple_payloads_response': (PAYLOAD, PAYLOAD), }) + def test_emit_with_unicode_payload(self): + 'Emit with unicode payload' + namespace = self.socketIO.define(Namespace) + self.socketIO.emit('emit_with_payload', UNICODE_PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(namespace.args_by_event, { + 'emit_with_payload_response': (UNICODE_PAYLOAD,), + }) + + """ + def test_emit_with_binary_payload(self): + 'Emit with binary payload' + namespace = self.socketIO.define(Namespace) + self.socketIO.emit('emit_with_payload', BINARY_PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(namespace.args_by_event, { + 'emit_with_payload_response': (BINARY_PAYLOAD,), + }) + """ + def test_emit_with_callback(self): 'Emit with callback' + self.assertEqual(self.response_count, 0) self.socketIO.emit('emit_with_callback', self.on_response) self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds) - self.assertTrue(self.called_on_response) + self.assertEqual(self.response_count, 1) def test_emit_with_callback_with_payload(self): 'Emit with callback with payload' + self.assertEqual(self.response_count, 0) self.socketIO.emit( 'emit_with_callback_with_payload', self.on_response) self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds) - self.assertTrue(self.called_on_response) + self.assertEqual(self.response_count, 1) def test_emit_with_callback_with_multiple_payloads(self): 'Emit with callback with multiple payloads' + self.assertEqual(self.response_count, 0) self.socketIO.emit( 'emit_with_callback_with_multiple_payloads', self.on_response) self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds) + self.assertEqual(self.response_count, 1) + + """ + def test_emit_with_callback_with_binary_payload(self): + 'Emit with callback with binary payload' + self.socketIO.emit( + 'emit_with_callback_with_binary_payload', self.on_binary_response) + self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds) self.assertTrue(self.called_on_response) + """ def test_emit_with_event(self): 'Emit to trigger an event' self.socketIO.on('emit_with_event_response', self.on_response) + self.assertEqual(self.response_count, 0) self.socketIO.emit('emit_with_event', PAYLOAD) self.socketIO.wait(self.wait_time_in_seconds) - self.assertTrue(self.called_on_response) + self.assertEqual(self.response_count, 1) + self.socketIO.emit('emit_with_event', PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(self.response_count, 2) + self.socketIO.off('emit_with_event_response') + self.socketIO.emit('emit_with_event', PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(self.response_count, 2) + + def test_once(self): + 'Listen for an event only once' + self.socketIO.once('emit_with_event_response', self.on_response) + self.assertEqual(self.response_count, 0) + self.socketIO.emit('emit_with_event', PAYLOAD) + self.socketIO.emit('emit_with_event', PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(self.response_count, 1) def test_send(self): 'Send' @@ -100,6 +188,15 @@ self.socketIO.wait(self.wait_time_in_seconds) self.assertEqual(namespace.response, DATA) + """ + def test_send_with_binary_data(self): + 'Send with binary data' + namespace = self.socketIO.define(Namespace) + self.socketIO.send(BINARY_DATA) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(namespace.response, BINARY_DATA) + """ + def test_ack(self): 'Respond to a server callback request' namespace = self.socketIO.define(Namespace) @@ -110,6 +207,19 @@ 'server_received_callback': (PAYLOAD,), }) + """ + def test_binary_ack(self): + 'Respond to a server callback request with binary data' + namespace = self.socketIO.define(Namespace) + self.socketIO.emit( + 'trigger_server_expects_callback', BINARY_PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(namespace.args_by_event, { + 'server_expects_callback': (BINARY_PAYLOAD,), + 'server_received_callback': (BINARY_PAYLOAD,), + }) + """ + def test_wait_with_disconnect(self): 'Exit loop when the client wants to disconnect' self.socketIO.define(Namespace) @@ -119,8 +229,13 @@ self.socketIO.wait(timeout_in_seconds) self.assertTrue(time.time() - start_time < timeout_in_seconds) + def test_namespace_invalid(self): + 'Connect to a namespace that is not defined on the server' + self.assertRaises( + ConnectionError, self.socketIO.define, Namespace, '/invalid') + def test_namespace_emit(self): - 'Behave differently in different namespaces' + 'Emit to namespaces' main_namespace = self.socketIO.define(Namespace) chat_namespace = self.socketIO.define(Namespace, '/chat') news_namespace = self.socketIO.define(Namespace, '/news') @@ -132,8 +247,23 @@ 'emit_with_payload_response': (PAYLOAD,), }) + """ + def test_namespace_emit_with_binary_payload(self): + 'Emit to namespaces with binary payload' + main_namespace = self.socketIO.define(Namespace) + chat_namespace = self.socketIO.define(Namespace, '/chat') + news_namespace = self.socketIO.define(Namespace, '/news') + news_namespace.emit('emit_with_payload', BINARY_PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(main_namespace.args_by_event, {}) + self.assertEqual(chat_namespace.args_by_event, {}) + self.assertEqual(news_namespace.args_by_event, { + 'emit_with_payload_response': (BINARY_PAYLOAD,), + }) + """ + def test_namespace_ack(self): - 'Respond to a server callback request within a namespace' + 'Respond to server callback request in namespace' chat_namespace = self.socketIO.define(Namespace, '/chat') chat_namespace.emit('trigger_server_expects_callback', PAYLOAD) self.socketIO.wait(self.wait_time_in_seconds) @@ -142,12 +272,36 @@ 'server_received_callback': (PAYLOAD,), }) + """ + def test_namespace_ack_with_binary_payload(self): + 'Respond to server callback request in namespace with binary payload' + chat_namespace = self.socketIO.define(Namespace, '/chat') + chat_namespace.emit( + 'trigger_server_expects_callback', BINARY_PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(chat_namespace.args_by_event, { + 'server_expects_callback': (BINARY_PAYLOAD,), + 'server_received_callback': (BINARY_PAYLOAD,), + }) + """ + + def on_event(self): + self.response_count += 1 + def on_response(self, *args): for arg in args: if isinstance(arg, dict): self.assertEqual(arg, PAYLOAD) else: self.assertEqual(arg, DATA) + self.response_count += 1 + + def on_binary_response(self, *args): + for arg in args: + if isinstance(arg, dict): + self.assertEqual(arg, BINARY_PAYLOAD) + else: + self.assertEqual(arg, BINARY_DATA) self.called_on_response = True @@ -172,12 +326,14 @@ class Namespace(LoggingNamespace): def initialize(self): - self.called_on_disconnect = False self.args_by_event = {} self.response = None def on_disconnect(self): - self.called_on_disconnect = True + self.args_by_event['disconnect'] = () + + def on_reconnect(self): + self.args_by_event['reconnect'] = () def on_wait_with_disconnect_response(self): self.disconnect() diff -Nru python-socketio-client-0.6.5/socketIO_client/tests/index.html python-socketio-client-0.7.2/socketIO_client/tests/index.html --- python-socketio-client-0.6.5/socketIO_client/tests/index.html 2015-06-01 20:16:32.000000000 +0000 +++ python-socketio-client-0.7.2/socketIO_client/tests/index.html 2016-12-11 03:28:43.000000000 +0000 @@ -1,6 +1,6 @@