diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2d69cfa..0045244 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,7 +23,7 @@ jobs: - name: Install dependencies run: | python3 -m pip install --upgrade pip - python3 -m pip install six yapf setuptools + python3 -m pip install yapf setuptools # Build and create dist - name: Build Package diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 31f6c2c..8fad7f1 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -13,10 +13,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.7", "3.10", "3.11"] - exclude: - - os: macos-latest - python-version: "3.7" + python-version: ["3.9", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -26,7 +23,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install six yapf + python -m pip install yapf - name: Run test run: | python test/run_all.py diff --git a/example/bench_wsh.py b/example/bench_wsh.py index 9ea2f93..c18069e 100644 --- a/example/bench_wsh.py +++ b/example/bench_wsh.py @@ -38,8 +38,6 @@ import time -from six.moves import range - def web_socket_do_extra_handshake(request): pass # Always accept. diff --git a/example/benchmark_helper_wsh.py b/example/benchmark_helper_wsh.py index 9ea9f56..805e6c3 100644 --- a/example/benchmark_helper_wsh.py +++ b/example/benchmark_helper_wsh.py @@ -30,8 +30,6 @@ from __future__ import absolute_import -import six - def web_socket_do_extra_handshake(request): # Turn off compression. @@ -46,7 +44,7 @@ def web_socket_transfer_data(request): if command is None: return - if not isinstance(command, six.text_type): + if not isinstance(command, str): raise ValueError('Invalid command data:' + command) commands = command.split(' ') if len(commands) == 0: diff --git a/example/cookie_wsh.py b/example/cookie_wsh.py index 1ca2c84..f25829b 100644 --- a/example/cookie_wsh.py +++ b/example/cookie_wsh.py @@ -27,8 +27,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from __future__ import absolute_import - -from six.moves import urllib +from urllib.parse import urlparse def _add_set_cookie(request, value): @@ -36,7 +35,7 @@ def _add_set_cookie(request, value): def web_socket_do_extra_handshake(request): - components = urllib.parse.urlparse(request.uri) + components = urlparse(request.uri) command = components[4] ONE_DAY_LIFE = 'Max-Age=86400' diff --git a/example/echo_client.py b/example/echo_client.py index 5063f00..be078d6 100755 --- a/example/echo_client.py +++ b/example/echo_client.py @@ -50,16 +50,13 @@ import argparse import base64 -import codecs import logging import os import re import socket import ssl -import sys from hashlib import sha1 -import six from pywebsocket3 import common, util from pywebsocket3.extensions import ( @@ -599,14 +596,6 @@ def _do_closing_handshake(self): def main(): - # Force Python 2 to use the locale encoding, even when the output is not a - # tty. This makes the behaviour the same as Python 3. The encoding won't - # necessarily support all unicode characters. This problem is particularly - # prevalent on Windows. - if six.PY2: - import locale - encoding = locale.getpreferredencoding() - sys.stdout = codecs.getwriter(encoding)(sys.stdout) parser = argparse.ArgumentParser() # We accept --command_line_flag style flags which is the same as Google @@ -615,7 +604,7 @@ def main(): '--server-host', '--server_host', dest='server_host', - type=six.text_type, + type=str, default='localhost', help='server host') parser.add_argument('-p', @@ -628,20 +617,20 @@ def main(): parser.add_argument('-o', '--origin', dest='origin', - type=six.text_type, + type=str, default=None, help='origin') parser.add_argument('-r', '--resource', dest='resource', - type=six.text_type, + type=str, default='/echo', help='resource path') parser.add_argument( '-m', '--message', dest='message', - type=six.text_type, + type=str, default=u'Hello,<>', help=('comma-separated messages to send. ' '%s will force close the connection from server.' % @@ -673,7 +662,7 @@ def main(): help='Use the permessage-deflate extension.') parser.add_argument('--log-level', '--log_level', - type=six.text_type, + type=str, dest='log_level', default='warn', choices=['debug', 'info', 'warn', 'error', 'critical'], diff --git a/example/echo_noext_wsh.py b/example/echo_noext_wsh.py index eba5032..dfb6b51 100644 --- a/example/echo_noext_wsh.py +++ b/example/echo_noext_wsh.py @@ -27,8 +27,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import six - _GOODBYE_MESSAGE = u'Goodbye' @@ -51,7 +49,7 @@ def web_socket_transfer_data(request): line = request.ws_stream.receive_message() if line is None: return - if isinstance(line, six.text_type): + if isinstance(line, str): request.ws_stream.send_message(line, binary=False) if line == _GOODBYE_MESSAGE: return diff --git a/example/echo_wsh.py b/example/echo_wsh.py index f7b3c6c..054228d 100644 --- a/example/echo_wsh.py +++ b/example/echo_wsh.py @@ -27,8 +27,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import six - _GOODBYE_MESSAGE = u'Goodbye' @@ -44,7 +42,7 @@ def web_socket_transfer_data(request): line = request.ws_stream.receive_message() if line is None: return - if isinstance(line, six.text_type): + if isinstance(line, str): request.ws_stream.send_message(line, binary=False) if line == _GOODBYE_MESSAGE: return diff --git a/pywebsocket3/handshake/base.py b/pywebsocket3/handshake/base.py index 561f7b6..72961f2 100644 --- a/pywebsocket3/handshake/base.py +++ b/pywebsocket3/handshake/base.py @@ -36,8 +36,6 @@ from pywebsocket3.extensions import get_extension_processor from pywebsocket3.stream import Stream, StreamOptions -from six.moves import map, range - # Defining aliases for values used frequently. _VERSION_LATEST = common.VERSION_HYBI_LATEST diff --git a/pywebsocket3/http_header_util.py b/pywebsocket3/http_header_util.py index 63e698b..6601baf 100644 --- a/pywebsocket3/http_header_util.py +++ b/pywebsocket3/http_header_util.py @@ -31,8 +31,7 @@ """ from __future__ import absolute_import - -import six.moves.urllib.parse +from urllib.parse import urlsplit _SEPARATORS = '()<>@,;:\\"/[]?={} \t' @@ -216,7 +215,7 @@ def quote_if_necessary(s): def parse_uri(uri): """Parse absolute URI then return host, port and resource.""" - parsed = six.moves.urllib.parse.urlsplit(uri) + parsed = urlsplit(uri) if parsed.scheme != 'wss' and parsed.scheme != 'ws': # |uri| must be a relative URI. # TODO(toyoshim): Should validate |uri|. diff --git a/pywebsocket3/msgutil.py b/pywebsocket3/msgutil.py index dd6a6fc..b9918ee 100644 --- a/pywebsocket3/msgutil.py +++ b/pywebsocket3/msgutil.py @@ -39,7 +39,7 @@ import threading -import six.moves.queue +import queue # Export Exception symbols from msgutil for backward compatibility from pywebsocket3._stream_exceptions import ( @@ -124,7 +124,7 @@ def __init__(self, request, onmessage=None): threading.Thread.__init__(self) self._request = request - self._queue = six.moves.queue.Queue() + self._queue = queue.Queue() self._onmessage = onmessage self._stop_requested = False self.setDaemon(True) @@ -157,7 +157,7 @@ def receive_nowait(self): """ try: message = self._queue.get_nowait() - except six.moves.queue.Empty: + except queue.Empty: message = None return message @@ -189,7 +189,7 @@ def __init__(self, request): """ threading.Thread.__init__(self) self._request = request - self._queue = six.moves.queue.Queue() + self._queue = queue.Queue() self.setDaemon(True) self.start() diff --git a/pywebsocket3/request_handler.py b/pywebsocket3/request_handler.py index 9d89b47..e1c4f53 100644 --- a/pywebsocket3/request_handler.py +++ b/pywebsocket3/request_handler.py @@ -29,10 +29,10 @@ """Request Handler and Request/Connection classes for standalone server. """ +import http import os -from six.moves import CGIHTTPServer -from six.moves import http_client +from http.server import CGIHTTPServer from pywebsocket3 import ( common, @@ -152,7 +152,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler): """CGIHTTPRequestHandler specialized for WebSocket.""" # Use httplib.HTTPMessage instead of mimetools.Message. - MessageClass = http_client.HTTPMessage + MessageClass = http.client.HTTPMessage def setup(self): """Override SocketServer.StreamRequestHandler.setup to wrap rfile diff --git a/pywebsocket3/standalone.py b/pywebsocket3/standalone.py index 0c324c4..e8f522d 100755 --- a/pywebsocket3/standalone.py +++ b/pywebsocket3/standalone.py @@ -162,8 +162,7 @@ import sys import traceback -import six -from six.moves import configparser +import configparser from pywebsocket3 import common, server_util, util from pywebsocket3.websocket_server import WebSocketServer @@ -181,7 +180,7 @@ def _build_option_parser(): parser.add_argument( '--config', dest='config_file', - type=six.text_type, + type=str, default=None, help=('Path to configuration file. See the file comment ' 'at the top of this file for the configuration ' @@ -318,7 +317,7 @@ def _build_option_parser(): # - FINE: Prints status of each frame processing step parser.add_argument('--log-level', '--log_level', - type=six.text_type, + type=str, dest='log_level', default='warn', choices=[ @@ -329,7 +328,7 @@ def _build_option_parser(): parser.add_argument( '--deflate-log-level', '--deflate_log_level', - type=six.text_type, + type=str, dest='deflate_log_level', default='warn', choices=['debug', 'info', 'warning', 'warn', 'error', 'critical'], @@ -366,7 +365,7 @@ def _build_option_parser(): '--handler-encoding', '--handler_encoding', dest='handler_encoding', - type=six.text_type, + type=str, default=None, help=('Text encoding used for loading handlers. ' 'By default, the encoding from the locale is used when ' diff --git a/pywebsocket3/stream.py b/pywebsocket3/stream.py index dd41850..3fbbc49 100644 --- a/pywebsocket3/stream.py +++ b/pywebsocket3/stream.py @@ -39,7 +39,6 @@ import time from collections import deque -import six from pywebsocket3 import common, util from pywebsocket3._stream_exceptions import ( @@ -564,7 +563,7 @@ def send_message(self, message, end=True, binary=False): raise BadOperationException( 'Requested send_message after sending out a closing handshake') - if binary and isinstance(message, six.text_type): + if binary and isinstance(message, str): raise BadOperationException( 'Message for binary frame must not be instance of Unicode') @@ -897,7 +896,7 @@ def close_connection(self, reason = '' else: if not isinstance(reason, bytes) and not isinstance( - reason, six.text_type): + reason, str): raise BadOperationException( 'close reason must be an instance of bytes or unicode') @@ -926,7 +925,7 @@ def close_connection(self, # note: mod_python Connection (mp_conn) doesn't have close method. def send_ping(self, body, binary=False): - if not binary and isinstance(body, six.text_type): + if not binary and isinstance(body, str): body = body.encode('UTF-8') frame = create_ping_frame(body, self._options.mask_send, self._options.outgoing_frame_filters) diff --git a/pywebsocket3/util.py b/pywebsocket3/util.py index 9c25ab8..c28217f 100644 --- a/pywebsocket3/util.py +++ b/pywebsocket3/util.py @@ -36,8 +36,6 @@ import struct import zlib -import six -from six.moves import map, range try: from pywebsocket3 import fast_masking @@ -96,7 +94,7 @@ def get_script_interp(script_path, cygwin_path=None): def hexify(s): - return ' '.join(['%02x' % x for x in six.iterbytes(s)]) + return ' '.join(['%02x' % x for x in iter(s)]) def get_class_logger(o): @@ -147,7 +145,7 @@ def _mask_using_swig(self, s): def _mask_using_array(self, s): """Perform the mask via python.""" - if isinstance(s, six.text_type): + if isinstance(s, str): raise Exception( 'Masking Operation should not process unicode strings') @@ -155,7 +153,7 @@ def _mask_using_array(self, s): # Use temporary local variables to eliminate the cost to access # attributes - masking_key = [c for c in six.iterbytes(self._masking_key)] + masking_key = [c for c in iter(self._masking_key)] masking_key_size = len(masking_key) masking_key_index = self._masking_key_index diff --git a/pywebsocket3/websocket_server.py b/pywebsocket3/websocket_server.py index e7485ec..2acd1dc 100644 --- a/pywebsocket3/websocket_server.py +++ b/pywebsocket3/websocket_server.py @@ -35,16 +35,16 @@ from __future__ import absolute_import +import http import logging import re import select import socket +import socketserver import ssl import threading import traceback -from six.moves import BaseHTTPServer, socketserver - from pywebsocket3 import dispatch, util from pywebsocket3.request_handler import WebSocketRequestHandler @@ -71,7 +71,7 @@ def _alias_handlers(dispatcher, websock_handlers_map_file): logging.error(str(e)) -class WebSocketServer(socketserver.ThreadingMixIn, BaseHTTPServer.HTTPServer): +class WebSocketServer(socketserver.ThreadingMixIn, http.server.HTTPServer): """HTTPServer specialized for WebSocket.""" # Overrides SocketServer.ThreadingMixIn.daemon_threads diff --git a/setup.py b/setup.py index ab9a24a..d5f2d80 100755 --- a/setup.py +++ b/setup.py @@ -45,7 +45,7 @@ # This is used since python_requires field is not recognized with # pip version 9.0.0 and earlier if sys.hexversion < 0x020700f0: - print('%s requires Python 2.7 or later.' % _PACKAGE_NAME, file=sys.stderr) + print('%s requires Python 3 or later.' % _PACKAGE_NAME, file=sys.stderr) sys.exit(1) if _USE_FAST_MASKING: @@ -65,8 +65,8 @@ license='See LICENSE', name=_PACKAGE_NAME, packages=[_PACKAGE_NAME, _PACKAGE_NAME + '.handshake'], - python_requires='>=2.7', - install_requires=['six'], + python_requires='>=3', + install_requires=[], url='https://github.com/GoogleChromeLabs/pywebsocket3', version='4.0.2', ) diff --git a/test/client_for_testing.py b/test/client_for_testing.py index 6275676..5d6cdd9 100644 --- a/test/client_for_testing.py +++ b/test/client_for_testing.py @@ -53,7 +53,6 @@ import time from hashlib import sha1 -from six import indexbytes, iterbytes from pywebsocket3 import common, util from pywebsocket3.handshake import HandshakeException @@ -451,8 +450,8 @@ def _mask_hybi(self, s): masking_nonce = os.urandom(4) result = [masking_nonce] count = 0 - for c in iterbytes(s): - result.append(util.pack_byte(c ^ indexbytes(masking_nonce, count))) + for c in iter(s): + result.append(util.pack_byte(c ^ masking_nonce[count])) count = (count + 1) % len(masking_nonce) return b''.join(result) diff --git a/test/mock.py b/test/mock.py index c460d9b..55045fa 100644 --- a/test/mock.py +++ b/test/mock.py @@ -30,12 +30,9 @@ """ from __future__ import absolute_import +import queue -import six -import six.moves.queue -from six.moves import range - -from pywebsocket3 import common, util +from pywebsocket3 import common from pywebsocket3.stream import Stream, StreamOptions @@ -113,7 +110,7 @@ class MockBlockingConn(_MockConnBase): """ def __init__(self): _MockConnBase.__init__(self) - self._queue = six.moves.queue.Queue() + self._queue = queue.Queue() def readline(self): """Override mod_python.apache.mp_conn.readline.""" @@ -140,7 +137,7 @@ def put_bytes(self, bytes): bytes: bytes to be read. """ - for byte in six.iterbytes(bytes): + for byte in iter(bytes): self._queue.put(byte) diff --git a/test/run_all.py b/test/run_all.py index 569bdb4..5ae7bf9 100755 --- a/test/run_all.py +++ b/test/run_all.py @@ -50,8 +50,6 @@ import sys import unittest -import six - _TEST_MODULE_PATTERN = re.compile(r'^(test_.+)\.py$') @@ -75,7 +73,7 @@ def _suite(): parser.add_argument( '--log-level', '--log_level', - type=six.text_type, + type=str, dest='log_level', default='warning', choices=['debug', 'info', 'warning', 'warn', 'error', 'critical']) diff --git a/test/test_dispatch.py b/test/test_dispatch.py index 18a39d1..c1f0b17 100755 --- a/test/test_dispatch.py +++ b/test/test_dispatch.py @@ -35,8 +35,6 @@ import os import unittest -from six.moves import zip - import set_sys_path # Update sys.path to locate pywebsocket3 module. from pywebsocket3 import dispatch, handshake from test import mock diff --git a/test/test_endtoend.py b/test/test_endtoend.py index 9718c6a..e0792f7 100755 --- a/test/test_endtoend.py +++ b/test/test_endtoend.py @@ -42,7 +42,7 @@ import time import unittest -from six.moves import urllib +import urllib import set_sys_path # Update sys.path to locate pywebsocket3 module. from test import client_for_testing diff --git a/test/test_memorizingfile.py b/test/test_memorizingfile.py index 4749085..0e8befc 100755 --- a/test/test_memorizingfile.py +++ b/test/test_memorizingfile.py @@ -32,10 +32,9 @@ from __future__ import absolute_import +from io import StringIO import unittest -import six - import set_sys_path # Update sys.path to locate pywebsocket3 module. from pywebsocket3 import memorizingfile @@ -75,22 +74,22 @@ def check_with_size(self, memorizing_file, read_size, expected_list): def test_get_memorized_lines(self): memorizing_file = memorizingfile.MemorizingFile( - six.StringIO('Hello\nWorld\nWelcome')) + StringIO('Hello\nWorld\nWelcome')) self.check(memorizing_file, 3, ['Hello\n', 'World\n', 'Welcome']) def test_get_memorized_lines_limit_memorized_lines(self): memorizing_file = memorizingfile.MemorizingFile( - six.StringIO('Hello\nWorld\nWelcome'), 2) + StringIO('Hello\nWorld\nWelcome'), 2) self.check(memorizing_file, 3, ['Hello\n', 'World\n']) def test_get_memorized_lines_empty_file(self): - memorizing_file = memorizingfile.MemorizingFile(six.StringIO('')) + memorizing_file = memorizingfile.MemorizingFile(StringIO('')) self.check(memorizing_file, 10, []) def test_get_memorized_lines_with_size(self): for size in range(1, 10): memorizing_file = memorizingfile.MemorizingFile( - six.StringIO('Hello\nWorld\nWelcome')) + StringIO('Hello\nWorld\nWelcome')) self.check_with_size(memorizing_file, size, ['Hello\n', 'World\n', 'Welcome']) diff --git a/test/test_mock.py b/test/test_mock.py index df5353b..8bb4a5e 100755 --- a/test/test_mock.py +++ b/test/test_mock.py @@ -35,7 +35,7 @@ import threading import unittest -import six.moves.queue +import queue import set_sys_path # Update sys.path to locate pywebsocket3 module. from test import mock @@ -95,7 +95,7 @@ def run(self): self._queue.put(data) conn = mock.MockBlockingConn() - queue = six.moves.queue.Queue() + queue = queue.Queue() reader = LineReader(conn, queue) self.assertTrue(queue.empty()) conn.put_bytes(b'Foo bar\r\n') diff --git a/test/test_msgutil.py b/test/test_msgutil.py index 99aa200..da6ef82 100755 --- a/test/test_msgutil.py +++ b/test/test_msgutil.py @@ -38,11 +38,7 @@ import struct import unittest import zlib - -from six import iterbytes -from six.moves import map -from six.moves import range -import six.moves.queue +import queue import set_sys_path # Update sys.path to locate pywebsocket3 module. from pywebsocket3 import common, msgutil, util @@ -59,10 +55,10 @@ def _mask_hybi(frame): - if isinstance(frame, six.text_type): + if isinstance(frame, str): Exception('masking does not accept Texts') - frame_key = list(iterbytes(_MASKING_NONCE)) + frame_key = list(iter(_MASKING_NONCE)) frame_key_len = len(frame_key) result = bytearray(frame) count = 0 @@ -865,7 +861,7 @@ def test_queue(self): self.assertEqual('Hello!', receiver.receive()) def test_onmessage(self): - onmessage_queue = six.moves.queue.Queue() + onmessage_queue = queue.Queue() def onmessage_handler(message): onmessage_queue.put(message) @@ -890,7 +886,7 @@ def test_send_nowait(self): # Use a queue to check the bytes written by MessageSender. # request.connection.written_data() cannot be used here because # MessageSender runs in a separate thread. - send_queue = six.moves.queue.Queue() + send_queue = queue.Queue() def write(bytes): send_queue.put(bytes) diff --git a/test/test_util.py b/test/test_util.py index 24c4b5b..b9692d0 100755 --- a/test/test_util.py +++ b/test/test_util.py @@ -37,9 +37,6 @@ import random import unittest -from six import int2byte, PY3 -from six.moves import range - import set_sys_path # Update sys.path to locate pywebsocket3 module. from pywebsocket3 import util @@ -162,7 +159,7 @@ def test_inflate_deflate_default(self): def test_random_section(self): random.seed(a=0) source = b''.join( - [int2byte(random.randint(0, 255)) for i in range(100 * 1024)]) + [bytes((random.randint(0, 255),)) for i in range(100 * 1024)]) chunked_input = get_random_section(source, 10)