summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--README.rst35
-rwxr-xr-xbin/wsdump.py8
-rw-r--r--examples/echoapp_client.py4
-rw-r--r--setup.py4
-rw-r--r--test_websocket.py233
-rw-r--r--websocket.py95
7 files changed, 208 insertions, 172 deletions
diff --git a/.gitignore b/.gitignore
index c7d73ad..4bcc1f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
build
dist
websocket_client.egg-info
+websocket_client_py3.egg-info
diff --git a/README.rst b/README.rst
index 320342b..7df261b 100644
--- a/README.rst
+++ b/README.rst
@@ -6,6 +6,13 @@ websocket-client module is WebSocket client for python. This provide the low le
websocket-client supports only hybi-13.
+How about Python 2
+===========================
+
+py2( https://github.com/liris/websocket-client ) branch is for python 2. Every test case is passed.
+If you are using python2, please check it.
+
+
License
============
@@ -14,18 +21,12 @@ License
Installation
=============
-This module is tested on only Python 2.7.
+This module is tested on Python 3.3.
-Type "python setup.py install" or "pip install websocket-client" to install.
+Check out git repository of py3 branch, and type "python3 setup.py install".
This module does not depend on any other module.
-How about Python 3
-===========================
-
-py3( https://github.com/liris/websocket-client/tree/py3 ) branch is for python 3.3. Every test case is passed.
-If you are using python3, please check it.
-
Example
============
@@ -33,12 +34,12 @@ Low Level API example::
from websocket import create_connection
ws = create_connection("ws://echo.websocket.org/")
- print "Sending 'Hello, World'..."
+ print("Sending 'Hello, World'...")
ws.send("Hello, World")
- print "Sent"
- print "Reeiving..."
+ print("Sent")
+ print("Reeiving...")
result = ws.recv()
- print "Received '%s'" % result
+ print("Received '%s'" % result)
ws.close()
If you want to customize socket options, set sockopt.
@@ -53,17 +54,17 @@ sockopt example:
JavaScript websocket-like API example::
import websocket
- import thread
+ import threading
import time
def on_message(ws, message):
print message
def on_error(ws, error):
- print error
+ print(error)
def on_close(ws):
- print "### closed ###"
+ print("### closed ###")
def on_open(ws):
def run(*args):
@@ -72,8 +73,8 @@ JavaScript websocket-like API example::
ws.send("Hello %d" % i)
time.sleep(1)
ws.close()
- print "thread terminating..."
- thread.start_new_thread(run, ())
+ print("thread terminating...")
+ threading.Thread(target=run, args=()).start()
if __name__ == "__main__":
diff --git a/bin/wsdump.py b/bin/wsdump.py
index 9cc5f03..f9708f9 100755
--- a/bin/wsdump.py
+++ b/bin/wsdump.py
@@ -45,11 +45,11 @@ class InteractiveConsole(code.InteractiveConsole):
sys.stdout.flush()
def raw_input(self, prompt):
- line = raw_input(prompt)
- if ENCODING and ENCODING != "utf-8" and not isinstance(line, unicode):
+ line = input(prompt)
+ if ENCODING and ENCODING != "utf-8" and not isinstance(line, str):
line = line.decode(ENCODING).encode("utf-8")
- elif isinstance(line, unicode):
- line = encode("utf-8")
+ elif isinstance(line, str):
+ line = line.encode("utf-8")
return line
diff --git a/examples/echoapp_client.py b/examples/echoapp_client.py
index e5232f7..76a55c7 100644
--- a/examples/echoapp_client.py
+++ b/examples/echoapp_client.py
@@ -1,5 +1,5 @@
import websocket
-import thread
+import _thread
import time
import sys
@@ -29,7 +29,7 @@ def on_open(ws):
ws.close()
print("Thread terminating...")
- thread.start_new_thread(run, ())
+ _thread.start_new_thread(run, ())
if __name__ == "__main__":
websocket.enableTrace(True)
diff --git a/setup.py b/setup.py
index d9a3192..4d098da 100644
--- a/setup.py
+++ b/setup.py
@@ -4,9 +4,9 @@ VERSION = "0.12.0"
setup(
- name="websocket-client",
+ name="websocket-client-py3",
version=VERSION,
- description="WebSocket client for python. hybi13 is supported.",
+ description="WebSocket client for python3. hybi13 is supported.",
long_description=open("README.rst").read(),
author="liris",
author_email="liris.pp@gmail.com",
diff --git a/test_websocket.py b/test_websocket.py
index 0800a3c..30fdd50 100644
--- a/test_websocket.py
+++ b/test_websocket.py
@@ -29,7 +29,7 @@ TRACABLE = False
def create_mask_key(n):
- return "abcd"
+ return b"abcd"
class SockMock(object):
@@ -38,6 +38,8 @@ class SockMock(object):
self.sent = []
def add_packet(self, data):
+ if isinstance(data, str):
+ data = bytes(data, "utf-8")
self.data.append(data)
def recv(self, bufsize):
@@ -53,12 +55,16 @@ class SockMock(object):
self.sent.append(data)
return len(data)
+ def close(self):
+ pass
+
class HeaderSockMock(SockMock):
def __init__(self, fname):
SockMock.__init__(self)
- self.add_packet(open(fname).read())
+ with open(fname, "rb") as f:
+ self.add_packet(f.read())
class WebSocketTest(unittest.TestCase):
@@ -69,72 +75,72 @@ class WebSocketTest(unittest.TestCase):
pass
def testDefaultTimeout(self):
- self.assertEquals(ws.getdefaulttimeout(), None)
+ self.assertEqual(ws.getdefaulttimeout(), None)
ws.setdefaulttimeout(10)
- self.assertEquals(ws.getdefaulttimeout(), 10)
+ self.assertEqual(ws.getdefaulttimeout(), 10)
ws.setdefaulttimeout(None)
def testParseUrl(self):
p = ws._parse_url("ws://www.example.com/r")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 80)
- self.assertEquals(p[2], "/r")
- self.assertEquals(p[3], False)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 80)
+ self.assertEqual(p[2], "/r")
+ self.assertEqual(p[3], False)
p = ws._parse_url("ws://www.example.com/r/")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 80)
- self.assertEquals(p[2], "/r/")
- self.assertEquals(p[3], False)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 80)
+ self.assertEqual(p[2], "/r/")
+ self.assertEqual(p[3], False)
p = ws._parse_url("ws://www.example.com/")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 80)
- self.assertEquals(p[2], "/")
- self.assertEquals(p[3], False)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 80)
+ self.assertEqual(p[2], "/")
+ self.assertEqual(p[3], False)
p = ws._parse_url("ws://www.example.com")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 80)
- self.assertEquals(p[2], "/")
- self.assertEquals(p[3], False)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 80)
+ self.assertEqual(p[2], "/")
+ self.assertEqual(p[3], False)
p = ws._parse_url("ws://www.example.com:8080/r")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 8080)
- self.assertEquals(p[2], "/r")
- self.assertEquals(p[3], False)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 8080)
+ self.assertEqual(p[2], "/r")
+ self.assertEqual(p[3], False)
p = ws._parse_url("ws://www.example.com:8080/")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 8080)
- self.assertEquals(p[2], "/")
- self.assertEquals(p[3], False)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 8080)
+ self.assertEqual(p[2], "/")
+ self.assertEqual(p[3], False)
p = ws._parse_url("ws://www.example.com:8080")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 8080)
- self.assertEquals(p[2], "/")
- self.assertEquals(p[3], False)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 8080)
+ self.assertEqual(p[2], "/")
+ self.assertEqual(p[3], False)
p = ws._parse_url("wss://www.example.com:8080/r")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 8080)
- self.assertEquals(p[2], "/r")
- self.assertEquals(p[3], True)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 8080)
+ self.assertEqual(p[2], "/r")
+ self.assertEqual(p[3], True)
p = ws._parse_url("wss://www.example.com:8080/r?key=value")
- self.assertEquals(p[0], "www.example.com")
- self.assertEquals(p[1], 8080)
- self.assertEquals(p[2], "/r?key=value")
- self.assertEquals(p[3], True)
+ self.assertEqual(p[0], "www.example.com")
+ self.assertEqual(p[1], 8080)
+ self.assertEqual(p[2], "/r?key=value")
+ self.assertEqual(p[3], True)
self.assertRaises(ValueError, ws._parse_url, "http://www.example.com/r")
def testWSKey(self):
key = ws._create_sec_websocket_key()
- self.assert_(key != 24)
- self.assert_("¥n" not in key)
+ self.assertTrue(key != 24)
+ self.assertTrue("¥n" not in key)
def testWsUtils(self):
sock = ws.WebSocket()
@@ -145,32 +151,34 @@ class WebSocketTest(unittest.TestCase):
"connection": "upgrade",
"sec-websocket-accept": "Kxep+hNu9n51529fGidYu7a3wO0=",
}
- self.assertEquals(sock._validate_header(required_header, key), True)
+ self.assertEqual(sock._validate_header(required_header, key), True)
header = required_header.copy()
header["upgrade"] = "http"
- self.assertEquals(sock._validate_header(header, key), False)
+ self.assertEqual(sock._validate_header(header, key), False)
del header["upgrade"]
- self.assertEquals(sock._validate_header(header, key), False)
+ self.assertEqual(sock._validate_header(header, key), False)
header = required_header.copy()
header["connection"] = "something"
- self.assertEquals(sock._validate_header(header, key), False)
+ self.assertEqual(sock._validate_header(header, key), False)
del header["connection"]
- self.assertEquals(sock._validate_header(header, key), False)
+ self.assertEqual(sock._validate_header(header, key), False)
header = required_header.copy()
header["sec-websocket-accept"] = "something"
- self.assertEquals(sock._validate_header(header, key), False)
+ self.assertEqual(sock._validate_header(header, key), False)
del header["sec-websocket-accept"]
- self.assertEquals(sock._validate_header(header, key), False)
+ self.assertEqual(sock._validate_header(header, key), False)
+ sock.close()
def testReadHeader(self):
sock = ws.WebSocket()
+ sock.sock.close()
sock.sock = HeaderSockMock("data/header01.txt")
status, header = sock._read_headers()
- self.assertEquals(status, 101)
- self.assertEquals(header["connection"], "upgrade")
+ self.assertEqual(status, 101)
+ self.assertEqual(header["connection"], "upgrade")
sock.sock = HeaderSockMock("data/header02.txt")
self.assertRaises(ws.WebSocketException, sock._read_headers)
@@ -179,70 +187,75 @@ class WebSocketTest(unittest.TestCase):
# TODO: add longer frame data
sock = ws.WebSocket()
sock.set_mask_key(create_mask_key)
+ sock.sock.close()
s = sock.sock = HeaderSockMock("data/header01.txt")
sock.send("Hello")
- self.assertEquals(s.sent[0], "\x81\x85abcd)\x07\x0f\x08\x0e")
+ self.assertEqual(s.sent[0], b"\x81\x85abcd)\x07\x0f\x08\x0e")
sock.send("こんにちは")
- self.assertEquals(s.sent[1], "\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
+ self.assertEqual(s.sent[1], b"\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
sock.send(u"こんにちは")
- self.assertEquals(s.sent[1], "\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
+ self.assertEqual(s.sent[1], b"\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
def testRecv(self):
# TODO: add longer frame data
sock = ws.WebSocket()
+ sock.sock.close()
s = sock.sock = SockMock()
- s.add_packet("\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
+ s.add_packet(b"\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
data = sock.recv()
- self.assertEquals(data, "こんにちは")
+ self.assertEqual(data, "こんにちは")
- s.add_packet("\x81\x85abcd)\x07\x0f\x08\x0e")
+ s.add_packet(b"\x81\x85abcd)\x07\x0f\x08\x0e")
data = sock.recv()
- self.assertEquals(data, "Hello")
+ self.assertEqual(data, "Hello")
def testInternalRecvStrict(self):
sock = ws.WebSocket()
+ sock.sock.close()
s = sock.sock = SockMock()
- s.add_packet("foo")
+ s.add_packet(b"foo")
s.add_packet(socket.timeout())
- s.add_packet("bar")
+ s.add_packet(b"bar")
s.add_packet(SSLError("The read operation timed out"))
- s.add_packet("baz")
+ s.add_packet(b"baz")
with self.assertRaises(ws.WebSocketTimeoutException):
data = sock._recv_strict(9)
with self.assertRaises(ws.WebSocketTimeoutException):
data = sock._recv_strict(9)
data = sock._recv_strict(9)
- self.assertEquals(data, "foobarbaz")
+ self.assertEqual(data, b"foobarbaz")
with self.assertRaises(ws.WebSocketConnectionClosedException):
data = sock._recv_strict(1)
def testRecvTimeout(self):
sock = ws.WebSocket()
+ sock.sock.close()
s = sock.sock = SockMock()
- s.add_packet("\x81")
+ s.add_packet(b"\x81")
s.add_packet(socket.timeout())
- s.add_packet("\x8dabcd\x29\x07\x0f\x08\x0e")
+ s.add_packet(b"\x8dabcd\x29\x07\x0f\x08\x0e")
s.add_packet(socket.timeout())
- s.add_packet("\x4e\x43\x33\x0e\x10\x0f\x00\x40")
+ s.add_packet(b"\x4e\x43\x33\x0e\x10\x0f\x00\x40")
with self.assertRaises(ws.WebSocketTimeoutException):
data = sock.recv()
with self.assertRaises(ws.WebSocketTimeoutException):
data = sock.recv()
data = sock.recv()
- self.assertEquals(data, "Hello, World!")
+ self.assertEqual(data, "Hello, World!")
with self.assertRaises(ws.WebSocketConnectionClosedException):
data = sock.recv()
@unittest.skipUnless(TEST_FRAGMENTATION, "fragmentation not implemented")
def testRecvWithSimpleFragmentation(self):
sock = ws.WebSocket()
+ sock.sock.close()
s = sock.sock = SockMock()
# OPCODE=TEXT, FIN=0, MSG="Brevity is "
- s.add_packet("\x01\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C")
+ s.add_packet(b"\x01\x8babcd#\x10\x06\x12\x08\x16\x1aD\x08\x11C")
# OPCODE=CONT, FIN=1, MSG="the soul of wit"
- s.add_packet("\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17")
+ s.add_packet(b"\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17")
data = sock.recv()
self.assertEqual(data, "Brevity is the soul of wit")
with self.assertRaises(ws.WebSocketConnectionClosedException):
@@ -251,23 +264,25 @@ class WebSocketTest(unittest.TestCase):
@unittest.skipUnless(TEST_FRAGMENTATION, "fragmentation not implemented")
def testRecvContFragmentation(self):
sock = ws.WebSocket()
+ sock.sock.close()
s = sock.sock = SockMock()
# OPCODE=CONT, FIN=1, MSG="the soul of wit"
- s.add_packet("\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17")
+ s.add_packet(b"\x80\x8fabcd\x15\n\x06D\x12\r\x16\x08A\r\x05D\x16\x0b\x17")
self.assertRaises(ws.WebSocketException, sock.recv)
@unittest.skipUnless(TEST_FRAGMENTATION, "fragmentation not implemented")
def testRecvWithProlongedFragmentation(self):
sock = ws.WebSocket()
+ sock.sock.close()
s = sock.sock = SockMock()
# OPCODE=TEXT, FIN=0, MSG="Once more unto the breach, "
- s.add_packet("\x01\x9babcd.\x0c\x00\x01A\x0f\x0c\x16\x04B\x16\n\x15" \
- "\rC\x10\t\x07C\x06\x13\x07\x02\x07\tNC")
+ s.add_packet(b"\x01\x9babcd.\x0c\x00\x01A\x0f\x0c\x16\x04B\x16\n\x15" \
+ b"\rC\x10\t\x07C\x06\x13\x07\x02\x07\tNC")
# OPCODE=CONT, FIN=0, MSG="dear friends, "
- s.add_packet("\x00\x8eabcd\x05\x07\x02\x16A\x04\x11\r\x04\x0c\x07" \
- "\x17MB")
+ s.add_packet(b"\x00\x8eabcd\x05\x07\x02\x16A\x04\x11\r\x04\x0c\x07" \
+ b"\x17MB")
# OPCODE=CONT, FIN=1, MSG="once more"
- s.add_packet("\x80\x89abcd\x0e\x0c\x00\x01A\x0f\x0c\x16\x04")
+ s.add_packet(b"\x80\x89abcd\x0e\x0c\x00\x01A\x0f\x0c\x16\x04")
data = sock.recv()
self.assertEqual(data, "Once more unto the breach, dear friends, " \
"once more")
@@ -278,36 +293,37 @@ class WebSocketTest(unittest.TestCase):
def testRecvWithFragmentationAndControlFrame(self):
sock = ws.WebSocket()
sock.set_mask_key(create_mask_key)
+ sock.sock.close()
s = sock.sock = SockMock()
# OPCODE=TEXT, FIN=0, MSG="Too much "
- s.add_packet("\x01\x89abcd5\r\x0cD\x0c\x17\x00\x0cA")
+ s.add_packet(b"\x01\x89abcd5\r\x0cD\x0c\x17\x00\x0cA")
# OPCODE=PING, FIN=1, MSG="Please PONG this"
- s.add_packet("\x89\x90abcd1\x0e\x06\x05\x12\x07C4.,$D\x15\n\n\x17")
+ s.add_packet(b"\x89\x90abcd1\x0e\x06\x05\x12\x07C4.,$D\x15\n\n\x17")
# OPCODE=CONT, FIN=1, MSG="of a good thing"
- s.add_packet("\x80\x8fabcd\x0e\x04C\x05A\x05\x0c\x0b\x05B\x17\x0c" \
- "\x08\x0c\x04")
+ s.add_packet(b"\x80\x8fabcd\x0e\x04C\x05A\x05\x0c\x0b\x05B\x17\x0c" \
+ b"\x08\x0c\x04")
data = sock.recv()
self.assertEqual(data, "Too much of a good thing")
with self.assertRaises(ws.WebSocketConnectionClosedException):
sock.recv()
- self.assertEqual(s.sent[0], "\x8a\x90abcd1\x0e\x06\x05\x12\x07C4.,$D" \
- "\x15\n\n\x17")
+ self.assertEqual(s.sent[0], b"\x8a\x90abcd1\x0e\x06\x05\x12\x07C4.,$D" \
+ b"\x15\n\n\x17")
def testWebSocket(self):
s = ws.create_connection("ws://echo.websocket.org/")
- self.assertNotEquals(s, None)
+ self.assertNotEqual(s, None)
s.send("Hello, World")
result = s.recv()
- self.assertEquals(result, "Hello, World")
+ self.assertEqual(result, "Hello, World")
s.send("こにゃにゃちは、世界")
result = s.recv()
- self.assertEquals(result, "こにゃにゃちは、世界")
+ self.assertEqual(result, "こにゃにゃちは、世界")
s.close()
def testPingPong(self):
s = ws.create_connection("ws://echo.websocket.org/")
- self.assertNotEquals(s, None)
+ self.assertNotEqual(s, None)
s.ping("Hello")
s.pong("Hi")
s.close()
@@ -316,41 +332,56 @@ class WebSocketTest(unittest.TestCase):
try:
import ssl
s = ws.create_connection("wss://echo.websocket.org/")
- self.assertNotEquals(s, None)
- self.assert_(isinstance(s.sock, ssl.SSLSock))
+ self.assertNotEqual(s, None)
+ self.assertTrue(isinstance(s.sock, ssl.SSLSock))
s.send("Hello, World")
result = s.recv()
- self.assertEquals(result, "Hello, World")
+ self.assertEqual(result, "Hello, World")
s.send("こにゃにゃちは、世界")
result = s.recv()
- self.assertEquals(result, "こにゃにゃちは、世界")
+ self.assertEqual(result, "こにゃにゃちは、世界")
s.close()
except:
pass
def testWebSocketWihtCustomHeader(self):
s = ws.create_connection("ws://echo.websocket.org/",
+ headers={"User-Agent": "PythonWebsocketClient"})
+ self.assertNotEqual(s, None)
+
+ def testWebSocketWihtCustomHeader(self):
+ s = ws.create_connection("ws://echo.websocket.org/",
headers={"User-Agent": "PythonWebsocketClient"})
- self.assertNotEquals(s, None)
+ self.assertNotEqual(s, None)
s.send("Hello, World")
result = s.recv()
- self.assertEquals(result, "Hello, World")
+ self.assertEqual(result, "Hello, World")
s.close()
def testAfterClose(self):
- from socket import error
s = ws.create_connection("ws://echo.websocket.org/")
- self.assertNotEquals(s, None)
+ self.assertNotEqual(s, None)
s.close()
- self.assertRaises(error, s.send, "Hello")
- self.assertRaises(error, s.recv)
+ try:
+ s.send("Hello")
+ #never reach here
+ self.assertEqual(1, 0)
+ except OSError:
+ pass
+
+ try:
+ s.recv()
+ #never reach here
+ self.assertEqual(1, 0)
+ except OSError:
+ pass
def testUUID4(self):
""" WebSocket key should be a UUID4.
"""
key = ws._create_sec_websocket_key()
u = uuid.UUID(bytes=base64.b64decode(key))
- self.assertEquals(4, u.version)
+ self.assertEqual(4, u.version)
class WebSocketAppTest(unittest.TestCase):
@@ -397,8 +428,8 @@ class WebSocketAppTest(unittest.TestCase):
self.assertFalse(isinstance(WebSocketAppTest.keep_running_close,
WebSocketAppTest.NotSetYet))
- self.assertEquals(True, WebSocketAppTest.keep_running_open)
- self.assertEquals(False, WebSocketAppTest.keep_running_close)
+ self.assertEqual(True, WebSocketAppTest.keep_running_open)
+ self.assertEqual(False, WebSocketAppTest.keep_running_close)
def testSockMaskKey(self):
""" A WebSocketApp should forward the received mask_key function down
@@ -419,16 +450,18 @@ class WebSocketAppTest(unittest.TestCase):
app.run_forever()
# Note: We can't use 'is' for comparing the functions directly, need to use 'id'.
- self.assertEquals(WebSocketAppTest.get_mask_key_id, id(my_mask_key_func))
+ self.assertEqual(WebSocketAppTest.get_mask_key_id, id(my_mask_key_func))
class SockOptTest(unittest.TestCase):
def testSockOpt(self):
sockopt = ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),)
s = ws.WebSocket(sockopt=sockopt)
- self.assertNotEquals(s.sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY), 0)
+ self.assertNotEqual(s.sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY), 0)
+ s.close()
s = ws.create_connection("ws://echo.websocket.org", sockopt=sockopt)
- self.assertNotEquals(s.sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY), 0)
+ self.assertNotEqual(s.sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY), 0)
+ s.close()
if __name__ == "__main__":
diff --git a/websocket.py b/websocket.py
index bdd6b45..aadc08f 100644
--- a/websocket.py
+++ b/websocket.py
@@ -21,19 +21,18 @@ Copyright (C) 2010 Hiroki Ohtani(liris)
import socket
-
try:
import ssl
from ssl import SSLError
HAVE_SSL = True
except ImportError:
- # dummy class of SSLError for ssl none-support environment.
+ HAVE_SSL = False
+
+ # dummy class for SSLError
class SSLError(Exception):
pass
- HAVE_SSL = False
-
-from urlparse import urlparse
+from urllib.parse import urlparse
import os
import array
import struct
@@ -202,7 +201,7 @@ def create_connection(url, timeout=None, **options):
return websock
_MAX_INTEGER = (1 << 32) -1
-_AVAILABLE_KEY_CHARS = range(0x21, 0x2f + 1) + range(0x3a, 0x7e + 1)
+_AVAILABLE_KEY_CHARS = list(range(0x21, 0x2f + 1)) + list(range(0x3a, 0x7e + 1))
_MAX_CHAR_BYTE = (1<<8) -1
# ref. Websocket gets an update, and it breaks stuff.
@@ -211,7 +210,7 @@ _MAX_CHAR_BYTE = (1<<8) -1
def _create_sec_websocket_key():
uid = uuid.uuid4()
- return base64.encodestring(uid.bytes).strip()
+ return base64.encodebytes(uid.bytes).strip().decode("utf-8")
_HEADERS_TO_CHECK = {
@@ -285,7 +284,7 @@ class ABNF(object):
opcode: operation code. please see OPCODE_XXX.
"""
- if opcode == ABNF.OPCODE_TEXT and isinstance(data, unicode):
+ if opcode == ABNF.OPCODE_TEXT and isinstance(data, str):
data = data.encode("utf-8")
# mask must be set if send data from client
return ABNF(1, 0, 0, 0, opcode, 1, data)
@@ -302,16 +301,17 @@ class ABNF(object):
if length >= ABNF.LENGTH_63:
raise ValueError("data is too long")
- frame_header = chr(self.fin << 7
+ frame_header = []
+ frame_header = bytes((self.fin << 7
| self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4
- | self.opcode)
+ | self.opcode,))
if length < ABNF.LENGTH_7:
- frame_header += chr(self.mask << 7 | length)
+ frame_header += bytes((self.mask << 7 | length,))
elif length < ABNF.LENGTH_16:
- frame_header += chr(self.mask << 7 | 0x7e)
+ frame_header += bytes((self.mask << 7 | 0x7e,))
frame_header += struct.pack("!H", length)
else:
- frame_header += chr(self.mask << 7 | 0x7f)
+ frame_header += bytes((self.mask << 7 | 0x7f,))
frame_header += struct.pack("!Q", length)
if not self.mask:
@@ -322,7 +322,7 @@ class ABNF(object):
def _get_masked(self, mask_key):
s = ABNF.mask(mask_key, self.data)
- return mask_key + "".join(s)
+ return mask_key + s
@staticmethod
def mask(mask_key, data):
@@ -335,9 +335,10 @@ class ABNF(object):
"""
_m = array.array("B", mask_key)
_d = array.array("B", data)
- for i in xrange(len(_d)):
+ for i in range(len(_d)):
_d[i] ^= _m[i % 4]
- return _d.tostring()
+
+ return _d.tobytes()
class WebSocket(object):
@@ -455,7 +456,6 @@ class WebSocket(object):
self._handshake(hostname, port, resource, **options)
def _handshake(self, host, port, resource, **options):
- sock = self.sock
headers = []
headers.append("GET %s HTTP/1.1" % resource)
headers.append("Upgrade: websocket")
@@ -481,7 +481,7 @@ class WebSocket(object):
headers.append("")
header_str = "\r\n".join(headers)
- self._send(header_str)
+ self._send(bytes(header_str, "utf-8"))
if traceEnabled:
logger.debug("--- request header ---")
logger.debug(header_str)
@@ -500,7 +500,7 @@ class WebSocket(object):
self.connected = True
def _validate_header(self, headers, key):
- for k, v in _HEADERS_TO_CHECK.iteritems():
+ for k, v in _HEADERS_TO_CHECK.items():
r = headers.get(k, None)
if not r:
return False
@@ -514,7 +514,8 @@ class WebSocket(object):
result = result.lower()
value = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
- hashed = base64.encodestring(hashlib.sha1(value).digest()).strip().lower()
+ digest = hashlib.sha1(bytes(value, "utf-8")).digest()
+ hashed = base64.encodebytes(digest).strip().decode("utf-8").lower()
return hashed == result
def _read_headers(self):
@@ -522,7 +523,6 @@ class WebSocket(object):
headers = {}
if traceEnabled:
logger.debug("--- response header ---")
-
while True:
line = self._recv_line()
if line == "\r\n":
@@ -550,12 +550,14 @@ class WebSocket(object):
"""
Send the data as string.
- payload: Payload must be utf-8 string or unicoce,
+ payload: Payload must be utf-8 bytes or str,
if the opcode is OPCODE_TEXT.
- Otherwise, it must be string(byte array)
+ Otherwise, it must be byte array
opcode: operation code to send. Please see OPCODE_XXX.
"""
+ if isinstance(payload, str):
+ payload = bytes(payload, "utf-8")
frame = ABNF.create_frame(payload, opcode)
if self.get_mask_key:
frame.get_mask_key = self.get_mask_key
@@ -594,6 +596,8 @@ class WebSocket(object):
return value: string(byte array) value.
"""
opcode, data = self.recv_data()
+ if opcode == ABNF.OPCODE_TEXT:
+ return data.decode("utf-8")
return data
def recv_data(self):
@@ -635,14 +639,16 @@ class WebSocket(object):
# Header
if self._frame_header is None:
self._frame_header = self._recv_strict(2)
- b1 = ord(self._frame_header[0])
+ b1 = self._frame_header[0]
fin = b1 >> 7 & 1
rsv1 = b1 >> 6 & 1
rsv2 = b1 >> 5 & 1
rsv3 = b1 >> 4 & 1
opcode = b1 & 0xf
- b2 = ord(self._frame_header[1])
+
+ b2 = self._frame_header[1]
has_mask = b2 >> 7 & 1
+
# Frame length
if self._frame_length is None:
length_bits = b2 & 0x7f
@@ -654,30 +660,35 @@ class WebSocket(object):
self._frame_length = struct.unpack("!Q", length_data)[0]
else:
self._frame_length = length_bits
+
# Mask
if self._frame_mask is None:
self._frame_mask = self._recv_strict(4) if has_mask else ""
+
# Payload
payload = self._recv_strict(self._frame_length)
if has_mask:
payload = ABNF.mask(self._frame_mask, payload)
+
# Reset for next frame
self._frame_header = None
self._frame_length = None
self._frame_mask = None
- return ABNF(fin, rsv1, rsv2, rsv3, opcode, has_mask, payload)
+ return ABNF(fin, rsv1, rsv2, rsv3, opcode, has_mask, payload)
- def send_close(self, status=STATUS_NORMAL, reason=""):
+ def send_close(self, status=STATUS_NORMAL, reason=b""):
"""
send close data to the server.
status: status code to send. see STATUS_XXX.
- reason: the reason to close. This must be string.
+ reason: the reason to close. This must be string or bytes
"""
if status < 0 or status >= ABNF.LENGTH_16:
raise ValueError("code is invalid range")
+ if isinstance(reason, str):
+ reason = bytes(reason, "utf-8")
self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE)
def close(self, status=STATUS_NORMAL, reason=""):
@@ -718,35 +729,26 @@ class WebSocket(object):
try:
return self.sock.send(data)
except socket.timeout as e:
- raise WebSocketTimeoutException(e.message)
- except Exception as e:
- if "timed out" in e.message:
- raise WebSocketTimeoutException(e.message)
- else:
- raise e
+ raise WebSocketTimeoutException(*e.args)
def _recv(self, bufsize):
try:
bytes = self.sock.recv(bufsize)
except socket.timeout as e:
- raise WebSocketTimeoutException(e.message)
- except SSLError as e:
- if e.message == "The read operation timed out":
- raise WebSocketTimeoutException(e.message)
- else:
- raise
+ raise WebSocketTimeoutException(*e.args)
+
if not bytes:
raise WebSocketConnectionClosedException()
return bytes
-
def _recv_strict(self, bufsize):
shortage = bufsize - sum(len(x) for x in self._recv_buffer)
while shortage > 0:
bytes = self._recv(shortage)
self._recv_buffer.append(bytes)
shortage -= len(bytes)
- unified = "".join(self._recv_buffer)
+
+ unified = b"".join(self._recv_buffer)
if shortage == 0:
self._recv_buffer = []
return unified
@@ -754,15 +756,14 @@ class WebSocket(object):
self._recv_buffer = [unified[bufsize:]]
return unified[:bufsize]
-
def _recv_line(self):
line = []
while True:
c = self._recv(1)
line.append(c)
- if c == "\n":
+ if c == b"\n":
break
- return "".join(line)
+ return b"".join(line).decode("utf-8")
class WebSocketApp(object):
@@ -857,7 +858,7 @@ class WebSocketApp(object):
if data is None:
break
self._callback(self.on_message, data)
- except Exception, e:
+ except Exception as e:
self._callback(self.on_error, e)
finally:
if thread:
@@ -870,7 +871,7 @@ class WebSocketApp(object):
if callback:
try:
callback(self, *args)
- except Exception, e:
+ except Exception as e:
logger.error(e)
if logger.isEnabledFor(logging.DEBUG):
_, _, tb = sys.exc_info()