Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-websocket-client for openSUSE:Factory checked in at 2022-10-25 11:18:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-websocket-client (Old) and /work/SRC/openSUSE:Factory/.python-websocket-client.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python-websocket-client" Tue Oct 25 11:18:44 2022 rev:17 rq:1030886 version:1.4.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-websocket-client/python-websocket-client.changes 2022-04-16 00:13:39.593601885 +0200 +++ /work/SRC/openSUSE:Factory/.python-websocket-client.new.2275/python-websocket-client.changes 2022-10-25 11:18:55.205992049 +0200 @@ -1,0 +2,8 @@ +Tue Oct 11 17:11:02 UTC 2022 - Yogalakshmi Arunachalam <yarunachalam@suse.com> + +- Update to version 1.4.1 + - Fix stack growth bug when `run_forever` reconnects (#854) + - Add doctest CI for sphinx docs code examples (d150099) + - General docs improvements + +------------------------------------------------------------------- Old: ---- websocket-client-1.3.2.tar.gz New: ---- websocket-client-1.4.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-websocket-client.spec ++++++ --- /var/tmp/diff_new_pack.CrFK6U/_old 2022-10-25 11:18:55.677993096 +0200 +++ /var/tmp/diff_new_pack.CrFK6U/_new 2022-10-25 11:18:55.681993104 +0200 @@ -25,7 +25,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-websocket-client -Version: 1.3.2 +Version: 1.4.1 Release: 0 Summary: WebSocket client implementation License: LGPL-2.1-only ++++++ websocket-client-1.3.2.tar.gz -> websocket-client-1.4.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/ChangeLog new/websocket-client-1.4.1/ChangeLog --- old/websocket-client-1.3.2/ChangeLog 2022-03-29 12:20:48.000000000 +0200 +++ new/websocket-client-1.4.1/ChangeLog 2022-09-04 21:56:26.000000000 +0200 @@ -1,6 +1,20 @@ ChangeLog ============ +- 1.4.1 + - Fix stack growth bug when `run_forever` reconnects (#854) + - Add doctest CI for sphinx docs code examples (d150099) + - General docs improvements + +- 1.4.0 + - Fix automatic reconnect with `run_forever` (#838) + - Allow a timeout to be set when using a proxy (#842) + +- 1.3.3 + - Fix unclosed socket error (#826) + - Update header dict access (#818) + - Add utf8 workaround to docs (fc9ee9f) + - 1.3.2 - Add support for pre-initialized stream socket in new WebSocketApp (#804) - Remove rel.saferead() in examples (f0bf03d) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/PKG-INFO new/websocket-client-1.4.1/PKG-INFO --- old/websocket-client-1.3.2/PKG-INFO 2022-03-29 12:24:33.153716800 +0200 +++ new/websocket-client-1.4.1/PKG-INFO 2022-09-04 21:59:51.740593200 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: websocket-client -Version: 1.3.2 +Version: 1.4.1 Summary: WebSocket client for Python with low level API options Home-page: https://github.com/websocket-client/websocket-client.git Download-URL: https://github.com/websocket-client/websocket-client/releases @@ -10,7 +10,6 @@ Project-URL: Documentation, https://websocket-client.readthedocs.io/ Project-URL: Source, https://github.com/websocket-client/websocket-client/ Keywords: websockets client -Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved :: Apache Software License Classifier: Programming Language :: Python :: 3 @@ -69,6 +68,9 @@ - To install `Sphinx` and `sphinx_rtd_theme` to build project documentation, use: `pip3 install websocket-client[docs]` +While not a strict dependency, [rel](https://github.com/bubbleboy14/registeredeventlistener) +is useful when using `run_forever` with automatic reconnect. Install rel with `pip3 install rel`. + Footnote: Some shells, such as zsh, require you to escape the `[` and `]` characters with a `\`. ## Usage Tips @@ -101,9 +103,13 @@ ### Long-lived Connection Most real-world WebSockets situations involve longer-lived connections. -The WebSocketApp `run_forever` loop will automatically try to reconnect when a +The WebSocketApp `run_forever` loop will automatically try to reconnect +to an open WebSocket connection when a network connection is lost if it is provided with a dispatcher parameter, and provides a variety of event-based connection controls. +`run_forever` does not automatically reconnect if the server +closes the WebSocket. Customizing behavior when the server closes +the WebSocket should be handled in the `on_close` callback. This example uses [rel](https://github.com/bubbleboy14/registeredeventlistener) for the dispatcher to provide automatic reconnection. @@ -157,14 +163,3 @@ print("Received '%s'" % result) ws.close() ``` - -If you want to customize socket options, set sockopt, as seen below: - -```python -from websocket import create_connection - -ws = create_connection("ws://echo.websocket.events/", - sockopt=((socket.IPPROTO_TCP, socket.TCP_NODELAY),)) -``` - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/README.md new/websocket-client-1.4.1/README.md --- old/websocket-client-1.3.2/README.md 2022-03-11 18:25:16.000000000 +0100 +++ new/websocket-client-1.4.1/README.md 2022-08-26 14:51:50.000000000 +0200 @@ -36,6 +36,9 @@ - To install `Sphinx` and `sphinx_rtd_theme` to build project documentation, use: `pip3 install websocket-client[docs]` +While not a strict dependency, [rel](https://github.com/bubbleboy14/registeredeventlistener) +is useful when using `run_forever` with automatic reconnect. Install rel with `pip3 install rel`. + Footnote: Some shells, such as zsh, require you to escape the `[` and `]` characters with a `\`. ## Usage Tips @@ -68,9 +71,13 @@ ### Long-lived Connection Most real-world WebSockets situations involve longer-lived connections. -The WebSocketApp `run_forever` loop will automatically try to reconnect when a +The WebSocketApp `run_forever` loop will automatically try to reconnect +to an open WebSocket connection when a network connection is lost if it is provided with a dispatcher parameter, and provides a variety of event-based connection controls. +`run_forever` does not automatically reconnect if the server +closes the WebSocket. Customizing behavior when the server closes +the WebSocket should be handled in the `on_close` callback. This example uses [rel](https://github.com/bubbleboy14/registeredeventlistener) for the dispatcher to provide automatic reconnection. @@ -124,12 +131,3 @@ print("Received '%s'" % result) ws.close() ``` - -If you want to customize socket options, set sockopt, as seen below: - -```python -from websocket import create_connection - -ws = create_connection("ws://echo.websocket.events/", - sockopt=((socket.IPPROTO_TCP, socket.TCP_NODELAY),)) -``` Binary files old/websocket-client-1.3.2/examples/__pycache__/echo_client.cpython-310.pyc and new/websocket-client-1.4.1/examples/__pycache__/echo_client.cpython-310.pyc differ Binary files old/websocket-client-1.3.2/examples/__pycache__/echoapp_client.cpython-310.pyc and new/websocket-client-1.4.1/examples/__pycache__/echoapp_client.cpython-310.pyc differ Binary files old/websocket-client-1.3.2/examples/__pycache__/rel_client.cpython-310.pyc and new/websocket-client-1.4.1/examples/__pycache__/rel_client.cpython-310.pyc differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/setup.py new/websocket-client-1.4.1/setup.py --- old/websocket-client-1.3.2/setup.py 2022-03-29 12:18:04.000000000 +0200 +++ new/websocket-client-1.4.1/setup.py 2022-09-04 21:56:58.000000000 +0200 @@ -21,7 +21,7 @@ limitations under the License. """ -VERSION = "1.3.2" +VERSION = "1.4.1" install_requires = [] tests_require = [] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket/__init__.py new/websocket-client-1.4.1/websocket/__init__.py --- old/websocket-client-1.3.2/websocket/__init__.py 2022-03-29 12:18:18.000000000 +0200 +++ new/websocket-client-1.4.1/websocket/__init__.py 2022-09-04 21:57:07.000000000 +0200 @@ -17,10 +17,10 @@ limitations under the License. """ from ._abnf import * -from ._app import WebSocketApp +from ._app import WebSocketApp, setReconnect from ._core import * from ._exceptions import * from ._logging import * from ._socket import * -__version__ = "1.3.2" +__version__ = "1.4.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket/_app.py new/websocket-client-1.4.1/websocket/_app.py --- old/websocket-client-1.3.2/websocket/_app.py 2022-03-19 15:25:50.000000000 +0100 +++ new/websocket-client-1.4.1/websocket/_app.py 2022-09-04 21:52:06.000000000 +0200 @@ -1,3 +1,4 @@ +import inspect import selectors import sys import threading @@ -29,15 +30,40 @@ __all__ = ["WebSocketApp"] +RECONNECT = 0 -class Dispatcher: + +def setReconnect(reconnectInterval): + global RECONNECT + RECONNECT = reconnectInterval + + +class DispatcherBase: """ - Dispatcher + DispatcherBase """ def __init__(self, app, ping_timeout): self.app = app self.ping_timeout = ping_timeout + def timeout(self, seconds, callback): + time.sleep(seconds) + callback() + + def reconnect(self, seconds, reconnector): + try: + while True: + _logging.info("reconnect() - retrying in %s seconds [%s frames in stack]" % (seconds, len(inspect.stack()))) + time.sleep(seconds) + reconnector(reconnecting=True) + except KeyboardInterrupt as e: + _logging.info("User exited %s" % (e,)) + + +class Dispatcher(DispatcherBase): + """ + Dispatcher + """ def read(self, sock, read_callback, check_callback): while self.app.keep_running: sel = selectors.DefaultSelector() @@ -51,14 +77,10 @@ sel.close() -class SSLDispatcher: +class SSLDispatcher(DispatcherBase): """ SSLDispatcher """ - def __init__(self, app, ping_timeout): - self.app = app - self.ping_timeout = ping_timeout - def read(self, sock, read_callback, check_callback): while self.app.keep_running: r = self.select() @@ -90,10 +112,17 @@ self.app = app self.ping_timeout = ping_timeout self.dispatcher = dispatcher + dispatcher.signal(2, dispatcher.abort) # keyboard interrupt def read(self, sock, read_callback, check_callback): self.dispatcher.read(sock, read_callback) - self.ping_timeout and self.dispatcher.timeout(self.ping_timeout, check_callback) + self.ping_timeout and self.timeout(self.ping_timeout, check_callback) + + def timeout(self, seconds, callback): + self.dispatcher.timeout(seconds, callback) + + def reconnect(self, seconds, reconnector): + self.timeout(seconds, reconnector) class WebSocketApp: @@ -186,6 +215,7 @@ self.last_pong_tm = 0 self.subprotocols = subprotocols self.prepared_socket = socket + self.has_errored = False def send(self, data, opcode=ABNF.OPCODE_TEXT): """ @@ -228,9 +258,10 @@ ping_payload="", http_proxy_host=None, http_proxy_port=None, http_no_proxy=None, http_proxy_auth=None, + http_proxy_timeout=None, skip_utf8_validation=False, host=None, origin=None, dispatcher=None, - suppress_origin=False, proxy_type=None): + suppress_origin=False, proxy_type=None, reconnect=None): """ Run event loop for WebSocket framework. @@ -256,6 +287,10 @@ HTTP proxy host name. http_proxy_port: int or str HTTP proxy port. If not set, set to 80. + http_proxy_timeout: int or float + HTTP proxy timeout, default is 60 sec as per python-socks. + http_proxy_auth: tuple + HTTP proxy auth information. tuple of username and password. Default is None. http_no_proxy: list Whitelisted host names that don't use the proxy. skip_utf8_validation: bool @@ -276,6 +311,9 @@ True if any other exception was raised during a loop. """ + if reconnect is None: + reconnect = RECONNECT + if ping_timeout is not None and ping_timeout <= 0: raise WebSocketException("Ensure ping_timeout > 0") if ping_interval is not None and ping_interval < 0: @@ -317,84 +355,105 @@ # Finally call the callback AFTER all teardown is complete self._callback(self.on_close, close_status_code, close_reason) - try: + def setSock(reconnecting=False): self.sock = WebSocket( self.get_mask_key, sockopt=sockopt, sslopt=sslopt, fire_cont_frame=self.on_cont_message is not None, skip_utf8_validation=skip_utf8_validation, enable_multithread=True) self.sock.settimeout(getdefaulttimeout()) - self.sock.connect( - self.url, header=self.header, cookie=self.cookie, - http_proxy_host=http_proxy_host, - http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy, - http_proxy_auth=http_proxy_auth, subprotocols=self.subprotocols, - host=host, origin=origin, suppress_origin=suppress_origin, - proxy_type=proxy_type, socket=self.prepared_socket) - dispatcher = self.create_dispatcher(ping_timeout, dispatcher) - - self._callback(self.on_open) - - if ping_interval: - event = threading.Event() - thread = threading.Thread( - target=self._send_ping, args=(ping_interval, event, ping_payload)) - thread.daemon = True - thread.start() - - def read(): - if not self.keep_running: - return teardown() + try: + self.sock.connect( + self.url, header=self.header, cookie=self.cookie, + http_proxy_host=http_proxy_host, + http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy, + http_proxy_auth=http_proxy_auth, http_proxy_timeout=http_proxy_timeout, + subprotocols=self.subprotocols, + host=host, origin=origin, suppress_origin=suppress_origin, + proxy_type=proxy_type, socket=self.prepared_socket) + + self._callback(self.on_open) + + _logging.warning("websocket connected") + dispatcher.read(self.sock.sock, read, check) + except (WebSocketConnectionClosedException, ConnectionRefusedError, KeyboardInterrupt, SystemExit, Exception) as e: + _logging.error("%s - %s" % (e, reconnect and "reconnecting" or "goodbye")) + reconnecting or handleDisconnect(e) + + def read(): + if not self.keep_running: + return teardown() + try: op_code, frame = self.sock.recv_data_frame(True) - if op_code == ABNF.OPCODE_CLOSE: - return teardown(frame) - elif op_code == ABNF.OPCODE_PING: - self._callback(self.on_ping, frame.data) - elif op_code == ABNF.OPCODE_PONG: - self.last_pong_tm = time.time() - self._callback(self.on_pong, frame.data) - elif op_code == ABNF.OPCODE_CONT and self.on_cont_message: - self._callback(self.on_data, frame.data, - frame.opcode, frame.fin) - self._callback(self.on_cont_message, - frame.data, frame.fin) + except (WebSocketConnectionClosedException, KeyboardInterrupt) as e: + if custom_dispatcher: + return handleDisconnect(e) else: - data = frame.data - if op_code == ABNF.OPCODE_TEXT: - data = data.decode("utf-8") - self._callback(self.on_data, data, frame.opcode, True) - self._callback(self.on_message, data) - - return True - - def check(): - if (ping_timeout): - has_timeout_expired = time.time() - self.last_ping_tm > ping_timeout - has_pong_not_arrived_after_last_ping = self.last_pong_tm - self.last_ping_tm < 0 - has_pong_arrived_too_late = self.last_pong_tm - self.last_ping_tm > ping_timeout - - if (self.last_ping_tm and - has_timeout_expired and - (has_pong_not_arrived_after_last_ping or has_pong_arrived_too_late)): - raise WebSocketTimeoutException("ping/pong timed out") - return True - - dispatcher.read(self.sock.sock, read, check) - return False - except (Exception, KeyboardInterrupt, SystemExit) as e: + raise e + if op_code == ABNF.OPCODE_CLOSE: + return teardown(frame) + elif op_code == ABNF.OPCODE_PING: + self._callback(self.on_ping, frame.data) + elif op_code == ABNF.OPCODE_PONG: + self.last_pong_tm = time.time() + self._callback(self.on_pong, frame.data) + elif op_code == ABNF.OPCODE_CONT and self.on_cont_message: + self._callback(self.on_data, frame.data, + frame.opcode, frame.fin) + self._callback(self.on_cont_message, + frame.data, frame.fin) + else: + data = frame.data + if op_code == ABNF.OPCODE_TEXT: + data = data.decode("utf-8") + self._callback(self.on_data, data, frame.opcode, True) + self._callback(self.on_message, data) + + return True + + def check(): + if (ping_timeout): + has_timeout_expired = time.time() - self.last_ping_tm > ping_timeout + has_pong_not_arrived_after_last_ping = self.last_pong_tm - self.last_ping_tm < 0 + has_pong_arrived_too_late = self.last_pong_tm - self.last_ping_tm > ping_timeout + + if (self.last_ping_tm and + has_timeout_expired and + (has_pong_not_arrived_after_last_ping or has_pong_arrived_too_late)): + raise WebSocketTimeoutException("ping/pong timed out") + return True + + def handleDisconnect(e): + self.has_errored = True self._callback(self.on_error, e) if isinstance(e, SystemExit): # propagate SystemExit further raise - teardown() - return not isinstance(e, KeyboardInterrupt) + if reconnect and not isinstance(e, KeyboardInterrupt): + _logging.info("websocket disconnected (retrying in %s seconds) [%s frames in stack]" % (reconnect, len(inspect.stack()))) + dispatcher.reconnect(reconnect, setSock) + else: + teardown() + + custom_dispatcher = bool(dispatcher) + dispatcher = self.create_dispatcher(ping_timeout, dispatcher, not not sslopt) + + if ping_interval: + event = threading.Event() + thread = threading.Thread( + target=self._send_ping, args=(ping_interval, event, ping_payload)) + thread.daemon = True + thread.start() + + setSock() + return self.has_errored - def create_dispatcher(self, ping_timeout, dispatcher=None): + def create_dispatcher(self, ping_timeout, dispatcher=None, is_ssl=False): if dispatcher: # If custom dispatcher is set, use WrappedDispatcher return WrappedDispatcher(self, ping_timeout, dispatcher) timeout = ping_timeout or 10 - if self.sock.is_ssl(): + if is_ssl: return SSLDispatcher(self, timeout) return Dispatcher(self, timeout) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket/_core.py new/websocket-client-1.4.1/websocket/_core.py --- old/websocket-client-1.3.2/websocket/_core.py 2022-02-25 22:17:34.000000000 +0100 +++ new/websocket-client-1.4.1/websocket/_core.py 2022-08-24 20:36:28.000000000 +0200 @@ -233,6 +233,8 @@ Whitelisted host names that don't use the proxy. http_proxy_auth: tuple HTTP proxy auth information. Tuple of username and password. Default is None. + http_proxy_timeout: int or float + HTTP proxy timeout, default is 60 sec as per python-socks. redirect_limit: int Number of redirects to follow. subprotocols: list @@ -572,6 +574,8 @@ Whitelisted host names that don't use the proxy. http_proxy_auth: tuple HTTP proxy auth information. tuple of username and password. Default is None. + http_proxy_timeout: int or float + HTTP proxy timeout, default is 60 sec as per python-socks. enable_multithread: bool Enable lock for multithread. redirect_limit: int diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket/_handshake.py new/websocket-client-1.4.1/websocket/_handshake.py --- old/websocket-client-1.3.2/websocket/_handshake.py 2022-02-25 18:36:28.000000000 +0100 +++ new/websocket-client-1.4.1/websocket/_handshake.py 2022-05-08 21:58:55.000000000 +0200 @@ -81,7 +81,7 @@ hostport = _pack_hostname(host) else: hostport = "%s:%d" % (_pack_hostname(host), port) - if "host" in options and options["host"] is not None: + if options.get("host"): headers.append("Host: %s" % options["host"]) else: headers.append("Host: %s" % hostport) @@ -89,7 +89,7 @@ # scheme indicates whether http or https is used in Origin # The same approach is used in parse_url of _url.py to set default port scheme, url = url.split(":", 1) - if "suppress_origin" not in options or not options["suppress_origin"]: + if not options.get("suppress_origin"): if "origin" in options and options["origin"] is not None: headers.append("Origin: %s" % options["origin"]) elif scheme == "wss": @@ -100,16 +100,16 @@ key = _create_sec_websocket_key() # Append Sec-WebSocket-Key & Sec-WebSocket-Version if not manually specified - if 'header' not in options or 'Sec-WebSocket-Key' not in options['header']: + if not options.get('header') or 'Sec-WebSocket-Key' not in options['header']: key = _create_sec_websocket_key() headers.append("Sec-WebSocket-Key: %s" % key) else: key = options['header']['Sec-WebSocket-Key'] - if 'header' not in options or 'Sec-WebSocket-Version' not in options['header']: + if not options.get('header') or 'Sec-WebSocket-Version' not in options['header']: headers.append("Sec-WebSocket-Version: %s" % VERSION) - if 'connection' not in options or options['connection'] is None: + if not options.get('connection'): headers.append('Connection: Upgrade') else: headers.append(options['connection']) @@ -118,8 +118,8 @@ if subprotocols: headers.append("Sec-WebSocket-Protocol: %s" % ",".join(subprotocols)) - if "header" in options: - header = options["header"] + header = options.get("header") + if header: if isinstance(header, dict): header = [ ": ".join([k, v]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket/_http.py new/websocket-client-1.4.1/websocket/_http.py --- old/websocket-client-1.3.2/websocket/_http.py 2022-01-01 04:15:40.000000000 +0100 +++ new/websocket-client-1.4.1/websocket/_http.py 2022-08-25 15:14:44.000000000 +0200 @@ -23,7 +23,7 @@ from ._exceptions import * from ._logging import * -from ._socket import* +from ._socket import * from ._ssl_compat import * from ._url import * @@ -59,7 +59,7 @@ self.no_proxy = options.get("http_no_proxy", None) self.proxy_protocol = options.get("proxy_type", "http") # Note: If timeout not specified, default python-socks timeout is 60 seconds - self.proxy_timeout = options.get("timeout", None) + self.proxy_timeout = options.get("http_proxy_timeout", None) if self.proxy_protocol not in ['http', 'socks4', 'socks4a', 'socks5', 'socks5h']: raise ProxyError("Only http, socks4, socks5 proxy protocols are supported") else: @@ -114,22 +114,22 @@ if proxy.proxy_host and not socket and not (proxy.proxy_protocol == "http"): return _start_proxied_socket(url, options, proxy) - hostname, port, resource, is_secure = parse_url(url) + hostname, port_from_url, resource, is_secure = parse_url(url) if socket: - return socket, (hostname, port, resource) + return socket, (hostname, port_from_url, resource) addrinfo_list, need_tunnel, auth = _get_addrinfo_list( - hostname, port, is_secure, proxy) + hostname, port_from_url, is_secure, proxy) if not addrinfo_list: raise WebSocketException( - "Host not found.: " + hostname + ":" + str(port)) + "Host not found.: " + hostname + ":" + str(port_from_url)) sock = None try: sock = _open_socket(addrinfo_list, options.sockopt, options.timeout) if need_tunnel: - sock = _tunnel(sock, hostname, port, auth) + sock = _tunnel(sock, hostname, port_from_url, auth) if is_secure: if HAVE_SSL: @@ -137,7 +137,7 @@ else: raise WebSocketException("SSL not available.") - return sock, (hostname, port, resource) + return sock, (hostname, port_from_url, resource) except: if sock: sock.close() @@ -184,17 +184,16 @@ try: sock.connect(address) except socket.error as error: + sock.close() error.remote_ip = str(address[0]) try: eConnRefused = (errno.ECONNREFUSED, errno.WSAECONNREFUSED, errno.ENETUNREACH) - except: + except AttributeError: eConnRefused = (errno.ECONNREFUSED, errno.ENETUNREACH) if error.errno in eConnRefused: err = error continue else: - if sock: - sock.close() raise error else: break diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket/_logging.py new/websocket-client-1.4.1/websocket/_logging.py --- old/websocket-client-1.3.2/websocket/_logging.py 2022-02-25 22:19:33.000000000 +0100 +++ new/websocket-client-1.4.1/websocket/_logging.py 2022-08-24 20:16:25.000000000 +0200 @@ -35,7 +35,7 @@ "isEnabledForError", "isEnabledForDebug", "isEnabledForTrace"] -def enableTrace(traceable, handler=logging.StreamHandler()): +def enableTrace(traceable, handler=logging.StreamHandler(), level="DEBUG"): """ Turn on/off the traceability. @@ -48,7 +48,7 @@ _traceEnabled = traceable if traceable: _logger.addHandler(handler) - _logger.setLevel(logging.DEBUG) + _logger.setLevel(getattr(logging, level)) def dump(title, message): @@ -70,6 +70,10 @@ _logger.debug(msg) +def info(msg): + _logger.info(msg) + + def trace(msg): if _traceEnabled: _logger.debug(msg) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket/tests/test_app.py new/websocket-client-1.4.1/websocket/tests/test_app.py --- old/websocket-client-1.3.2/websocket/tests/test_app.py 2022-02-25 22:32:28.000000000 +0100 +++ new/websocket-client-1.4.1/websocket/tests/test_app.py 2022-09-04 21:52:06.000000000 +0200 @@ -80,7 +80,8 @@ app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_close=on_close, on_message=on_message) app.run_forever() - @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") +# @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") + @unittest.skipUnless(False, "Test disabled for now (requires rel)") def testRunForeverDispatcher(self): """ A WebSocketApp should keep running as long as its self.keep_running is not False (in the boolean context). @@ -98,7 +99,9 @@ self.close() app = ws.WebSocketApp('ws://127.0.0.1:' + LOCAL_WS_SERVER_PORT, on_open=on_open, on_message=on_message) - app.run_forever(dispatcher="Dispatcher") + app.run_forever(dispatcher="Dispatcher") # doesn't work +# app.run_forever(dispatcher=rel) # would work +# rel.dispatch() @unittest.skipUnless(TEST_WITH_LOCAL_SERVER, "Tests using local websocket server are disabled") def testRunForeverTeardownCleanExit(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket/tests/test_http.py new/websocket-client-1.4.1/websocket/tests/test_http.py --- old/websocket-client-1.3.2/websocket/tests/test_http.py 2022-02-25 22:32:17.000000000 +0100 +++ new/websocket-client-1.4.1/websocket/tests/test_http.py 2022-08-24 20:36:28.000000000 +0200 @@ -105,15 +105,15 @@ if ws._http.HAVE_PYTHON_SOCKS: # Need this check, otherwise case where python_socks is not installed triggers # websocket._exceptions.WebSocketException: Python Socks is needed for SOCKS proxying but is not available - self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4", timeout=1)) - self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4a", timeout=1)) - self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5", timeout=1)) - self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5h", timeout=1)) - self.assertRaises(ProxyConnectionError, connect, "wss://example.com", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=9999, proxy_type="socks4", timeout=1), None) + self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4", http_proxy_timeout=1)) + self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks4a", http_proxy_timeout=1)) + self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5", http_proxy_timeout=1)) + self.assertRaises((ProxyTimeoutError, OSError), _start_proxied_socket, "wss://example.com", OptsList(), proxy_info(http_proxy_host="example.com", http_proxy_port="8080", proxy_type="socks5h", http_proxy_timeout=1)) + self.assertRaises(ProxyConnectionError, connect, "wss://example.com", OptsList(), proxy_info(http_proxy_host="127.0.0.1", http_proxy_port=9999, proxy_type="socks4", http_proxy_timeout=1), None) self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http")) self.assertRaises(TypeError, _get_addrinfo_list, None, 80, True, proxy_info(http_proxy_host="127.0.0.1", http_proxy_port="9999", proxy_type="http")) - self.assertRaises(socket.timeout, connect, "wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=9999, proxy_type="http", timeout=1), None) + self.assertRaises(socket.timeout, connect, "wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=9999, proxy_type="http", http_proxy_timeout=1), None) self.assertEqual( connect("wss://google.com", OptsList(), proxy_info(http_proxy_host="8.8.8.8", http_proxy_port=8080, proxy_type="http"), True), (True, ("google.com", 443, "/"))) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket_client.egg-info/PKG-INFO new/websocket-client-1.4.1/websocket_client.egg-info/PKG-INFO --- old/websocket-client-1.3.2/websocket_client.egg-info/PKG-INFO 2022-03-29 12:24:32.000000000 +0200 +++ new/websocket-client-1.4.1/websocket_client.egg-info/PKG-INFO 2022-09-04 21:59:51.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: websocket-client -Version: 1.3.2 +Version: 1.4.1 Summary: WebSocket client for Python with low level API options Home-page: https://github.com/websocket-client/websocket-client.git Download-URL: https://github.com/websocket-client/websocket-client/releases @@ -10,7 +10,6 @@ Project-URL: Documentation, https://websocket-client.readthedocs.io/ Project-URL: Source, https://github.com/websocket-client/websocket-client/ Keywords: websockets client -Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved :: Apache Software License Classifier: Programming Language :: Python :: 3 @@ -69,6 +68,9 @@ - To install `Sphinx` and `sphinx_rtd_theme` to build project documentation, use: `pip3 install websocket-client[docs]` +While not a strict dependency, [rel](https://github.com/bubbleboy14/registeredeventlistener) +is useful when using `run_forever` with automatic reconnect. Install rel with `pip3 install rel`. + Footnote: Some shells, such as zsh, require you to escape the `[` and `]` characters with a `\`. ## Usage Tips @@ -101,9 +103,13 @@ ### Long-lived Connection Most real-world WebSockets situations involve longer-lived connections. -The WebSocketApp `run_forever` loop will automatically try to reconnect when a +The WebSocketApp `run_forever` loop will automatically try to reconnect +to an open WebSocket connection when a network connection is lost if it is provided with a dispatcher parameter, and provides a variety of event-based connection controls. +`run_forever` does not automatically reconnect if the server +closes the WebSocket. Customizing behavior when the server closes +the WebSocket should be handled in the `on_close` callback. This example uses [rel](https://github.com/bubbleboy14/registeredeventlistener) for the dispatcher to provide automatic reconnection. @@ -157,14 +163,3 @@ print("Received '%s'" % result) ws.close() ``` - -If you want to customize socket options, set sockopt, as seen below: - -```python -from websocket import create_connection - -ws = create_connection("ws://echo.websocket.events/", - sockopt=((socket.IPPROTO_TCP, socket.TCP_NODELAY),)) -``` - - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/websocket-client-1.3.2/websocket_client.egg-info/SOURCES.txt new/websocket-client-1.4.1/websocket_client.egg-info/SOURCES.txt --- old/websocket-client-1.3.2/websocket_client.egg-info/SOURCES.txt 2022-03-29 12:24:33.000000000 +0200 +++ new/websocket-client-1.4.1/websocket_client.egg-info/SOURCES.txt 2022-09-04 21:59:51.000000000 +0200 @@ -7,6 +7,9 @@ examples/echo_client.py examples/echoapp_client.py examples/rel_client.py +examples/__pycache__/echo_client.cpython-310.pyc +examples/__pycache__/echoapp_client.cpython-310.pyc +examples/__pycache__/rel_client.cpython-310.pyc websocket/__init__.py websocket/_abnf.py websocket/_app.py