Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
3.9.4
3.8.9
3.7.10
3.6.13
2.7.18
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For use with pyenv to allow easy switching between Python versions

10 changes: 6 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ language: python

python:
- 2.7
- 3.3
- 3.5
- 3.6
- 3.7
- 3.8
- 3.9

before_install:
- sudo apt-get install python-dev libevent-dev
- pip install Cython

install:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install -r requirements/py2kreqs.txt; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install -r requirements/py2kreqs.txt; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip install -r requirements/py3kreqs.txt; fi
- python setup.py install

script:
script:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then py.test -v; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then py.test -v; fi
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
## Unreleased
[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.5.1...master)

**Changes:**

* Upgrade Python support to include 3.6, 3.7, 3.8 and 3.9
* Drop support for Python 3.* < 3.6 (Python 2.7 remains)

## [0.5.1](https://github.com/Lawouach/WebSocket-for-Python/tree/0.5.1) (2018-02-28)
[Full Changelog](https://github.com/Lawouach/WebSocket-for-Python/compare/0.5.0...0.5.1)
**Merged pull requests:**
Expand Down
7 changes: 4 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ def find_package_modules(self, package, package_dir):
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Communications',
Expand Down
10 changes: 5 additions & 5 deletions test/autobahn_test_servers.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def run_python3_asyncio(host="127.0.0.1", port=9009):
wsaccel.patch_ws4py()
from ws4py.async_websocket import EchoWebSocket
from ws4py.server.tulipserver import WebSocketProtocol

loop = asyncio.get_event_loop()

def start_server():
Expand Down Expand Up @@ -121,14 +121,14 @@ def run_autobahn_server(host="127.0.0.1", port=9003):
from twisted.internet import reactor
from autobahn.twisted.websocket import WebSocketServerProtocol, \
WebSocketServerFactory

class MyServerProtocol(WebSocketServerProtocol):
def onMessage(self, payload, isBinary):
self.sendMessage(payload, isBinary)

logger = logging.getLogger('autobahn_testsuite')
logger.warning("Serving Autobahn server on %s:%s" % (host, port))

factory = WebSocketServerFactory("ws://%s:%d" % (host, port))
factory.protocol = MyServerProtocol

Expand All @@ -142,7 +142,7 @@ def run_python_wsgi(host="127.0.0.1", port=9002):
"""
run_python_wsgi_async(host, port, False)

def run_python_wsgi_async(host="127.0.0.1", port=9010, async=True):
def run_python_wsgi_async(host="127.0.0.1", port=9010, async_=True):
"""
Runs wsgi server on python 2.x with async middleware"
"""
Expand All @@ -153,7 +153,7 @@ def run_python_wsgi_async(host="127.0.0.1", port=9010, async=True):
from ws4py.server.wsgiutils import WebSocketWSGIApplication

app = WebSocketWSGIApplication(handler_cls=EchoWebSocket)
if async:
if async_:
def middleware(app):
def later(environ, start_response):
for part in app(environ, start_response):
Expand Down
20 changes: 12 additions & 8 deletions test/test_logger.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
import logging
import logging
import logging.handlers as handlers
import os, os.path
import unittest
Expand All @@ -15,27 +15,31 @@ def clean_logger():
except KeyError:
pass
logger.removeHandler(handler)

class WSTestLogger(unittest.TestCase):
LOG_FILE = './my.log'

def tearDown(self):
clean_logger()

if os.path.exists(self.LOG_FILE):
os.remove(self.LOG_FILE)

def test_named_logger(self):
logger = configure_logger(stdout=False, filepath='./my.log')
logger = configure_logger(stdout=False, filepath=self.LOG_FILE)

logger = logging.getLogger('ws4py')
self.assertEqual(logger.getEffectiveLevel(), logging.INFO)

def test_level(self):
logger = configure_logger(stdout=True, filepath='./my.log',
logger = configure_logger(stdout=True, filepath=self.LOG_FILE,
level=logging.DEBUG)

self.assertEqual(logger.getEffectiveLevel(), logging.DEBUG)
for handler in logger.handlers:
self.assertEqual(handler.level, logging.DEBUG)

def test_file_logger(self):
filepath = os.path.abspath('./my.log')
filepath = os.path.abspath(self.LOG_FILE)
logger = configure_logger(stdout=False, filepath=filepath)
for handler in logger.handlers:
if isinstance(handler, handlers.RotatingFileHandler):
Expand Down
5 changes: 4 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
# and then run "tox" from this directory.

[tox]
envlist = py27
envlist = py27,py36,py37,py38,py39

[testenv]
commands = python setup.py test
deps =
py27: -r requirements/py2kreqs.txt
{py36,py37,py38,py39}: -r requirements/py3kreqs.txt
9 changes: 9 additions & 0 deletions ws4py/_asyncio_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Provide compatibility over different versions of asyncio."""

import asyncio

if hasattr(asyncio, "async"):
# Compatibility for Python 3.3 and older
ensure_future = getattr(asyncio, "async")
else:
ensure_future = asyncio.ensure_future
5 changes: 3 additions & 2 deletions ws4py/async_websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import types

from ws4py.websocket import WebSocket as _WebSocket
from ws4py import _asyncio_compat
from ws4py.messaging import Message

__all__ = ['WebSocket', 'EchoWebSocket']
Expand Down Expand Up @@ -84,7 +85,7 @@ def close_connection(self):
def closeit():
yield from self.proto.writer.drain()
self.proto.writer.close()
asyncio.async(closeit())
_asyncio_compat.ensure_future(closeit())

def _write(self, data):
"""
Expand All @@ -94,7 +95,7 @@ def _write(self, data):
def sendit(data):
self.proto.writer.write(data)
yield from self.proto.writer.drain()
asyncio.async(sendit(data))
_asyncio_compat.ensure_future(sendit(data))

@asyncio.coroutine
def run(self):
Expand Down
33 changes: 17 additions & 16 deletions ws4py/server/tulipserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ws4py import WS_KEY, WS_VERSION
from ws4py.exc import HandshakeError
from ws4py.websocket import WebSocket
from ws4py import _asyncio_compat

LF = b'\n'
CRLF = b'\r\n'
Expand All @@ -25,7 +26,7 @@ def __init__(self, handler_cls):

def _pseudo_connected(self, reader, writer):
pass

def connection_made(self, transport):
"""
A peer is now connected and we receive an instance
Expand All @@ -40,17 +41,17 @@ def connection_made(self, transport):
#self.stream.set_transport(transport)
asyncio.StreamReaderProtocol.connection_made(self, transport)
# Let make it concurrent for others to tag along
f = asyncio.async(self.handle_initial_handshake())
f = _asyncio_compat.ensure_future(self.handle_initial_handshake())
f.add_done_callback(self.terminated)

@property
def writer(self):
return self._stream_writer

@property
def reader(self):
return self._stream_reader

def terminated(self, f):
if f.done() and not f.cancelled():
ex = f.exception()
Expand All @@ -70,12 +71,12 @@ def close(self):
transport.
"""
self.ws.close()

def timeout(self):
self.ws.close_connection()
if self.ws.started:
self.ws.closed(1002, "Peer connection timed-out")

def connection_lost(self, exc):
"""
The peer connection is now, the closing
Expand All @@ -88,7 +89,7 @@ def connection_lost(self, exc):
self.ws.close_connection()
if self.ws.started:
self.ws.closed(1002, "Peer connection was lost")

@asyncio.coroutine
def handle_initial_handshake(self):
"""
Expand All @@ -100,15 +101,15 @@ def handle_initial_handshake(self):
"""
request_line = yield from self.next_line()
method, uri, req_protocol = request_line.strip().split(SPACE, 2)

# GET required
if method.upper() != b'GET':
raise HandshakeError('HTTP method must be a GET')

headers = yield from self.read_headers()
if req_protocol == b'HTTP/1.1' and 'Host' not in headers:
raise ValueError("Missing host header")

for key, expected_value in [('Upgrade', 'websocket'),
('Connection', 'upgrade')]:
actual_value = headers.get(key, '').lower()
Expand Down Expand Up @@ -160,7 +161,7 @@ def handle_initial_handshake(self):
self.ws.protocols = ws_protocols
self.ws.extensions = ws_extensions
self.ws.headers = headers

response = [req_protocol + b' 101 Switching Protocols']
response.append(b'Upgrade: websocket')
response.append(b'Content-Type: text/plain')
Expand All @@ -184,7 +185,7 @@ def handle_websocket(self):
exchange is completed and terminated.
"""
yield from self.ws.run()

@asyncio.coroutine
def read_headers(self):
"""
Expand All @@ -198,21 +199,21 @@ def read_headers(self):
if line == CRLF:
break
return BytesHeaderParser().parsebytes(headers)

@asyncio.coroutine
def next_line(self):
"""
Reads data until \r\n is met and then return all read
bytes.
bytes.
"""
line = yield from self.reader.readline()
if not line.endswith(CRLF):
raise ValueError("Missing mandatory trailing CRLF")
return line

if __name__ == '__main__':
from ws4py.async_websocket import EchoWebSocket

loop = asyncio.get_event_loop()

def start_server():
Expand Down