From 2d4818139f7c85e3f795d60f46443a5dd2c04e3c Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Mon, 16 Jan 2023 14:22:09 +0530 Subject: [PATCH 01/17] Add websocket typings --- typings/websocket/__init__.pyi | 30 ++ typings/websocket/_abnf.pyi | 155 ++++++++++ typings/websocket/_app.pyi | 210 ++++++++++++++ typings/websocket/_cookiejar.pyi | 19 ++ typings/websocket/_core.pyi | 416 +++++++++++++++++++++++++++ typings/websocket/_exceptions.pyi | 81 ++++++ typings/websocket/_handshake.pyi | 42 +++ typings/websocket/_http.pyi | 41 +++ typings/websocket/_logging.pyi | 45 +++ typings/websocket/_socket.pyi | 57 ++++ typings/websocket/_ssl_compat.pyi | 23 ++ typings/websocket/_url.pyi | 47 +++ typings/websocket/_utils.pyi | 46 +++ typings/websocket/_wsdump.pyi | 68 +++++ typings/websocket/tests/__init__.pyi | 4 + 15 files changed, 1284 insertions(+) create mode 100644 typings/websocket/__init__.pyi create mode 100644 typings/websocket/_abnf.pyi create mode 100644 typings/websocket/_app.pyi create mode 100644 typings/websocket/_cookiejar.pyi create mode 100644 typings/websocket/_core.pyi create mode 100644 typings/websocket/_exceptions.pyi create mode 100644 typings/websocket/_handshake.pyi create mode 100644 typings/websocket/_http.pyi create mode 100644 typings/websocket/_logging.pyi create mode 100644 typings/websocket/_socket.pyi create mode 100644 typings/websocket/_ssl_compat.pyi create mode 100644 typings/websocket/_url.pyi create mode 100644 typings/websocket/_utils.pyi create mode 100644 typings/websocket/_wsdump.pyi create mode 100644 typings/websocket/tests/__init__.pyi diff --git a/typings/websocket/__init__.pyi b/typings/websocket/__init__.pyi new file mode 100644 index 000000000..6e67b80b3 --- /dev/null +++ b/typings/websocket/__init__.pyi @@ -0,0 +1,30 @@ +""" +This type stub file was generated by pyright. +""" + +from ._abnf import * +from ._app import WebSocketApp, setReconnect +from ._core import * +from ._exceptions import * +from ._logging import * +from ._socket import * + +""" +__init__.py +websocket - WebSocket client library for Python + +Copyright 2022 engn33r + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +__version__ = ... diff --git a/typings/websocket/_abnf.pyi b/typings/websocket/_abnf.pyi new file mode 100644 index 000000000..139330620 --- /dev/null +++ b/typings/websocket/_abnf.pyi @@ -0,0 +1,155 @@ +""" +This type stub file was generated by pyright. +""" + +from ._exceptions import * + +__all__ = ['ABNF', 'continuous_frame', 'frame_buffer', 'STATUS_NORMAL', 'STATUS_GOING_AWAY', 'STATUS_PROTOCOL_ERROR', 'STATUS_UNSUPPORTED_DATA_TYPE', 'STATUS_STATUS_NOT_AVAILABLE', 'STATUS_ABNORMAL_CLOSED', 'STATUS_INVALID_PAYLOAD', 'STATUS_POLICY_VIOLATION', 'STATUS_MESSAGE_TOO_BIG', 'STATUS_INVALID_EXTENSION', 'STATUS_UNEXPECTED_CONDITION', 'STATUS_BAD_GATEWAY', 'STATUS_TLS_HANDSHAKE_ERROR'] +STATUS_NORMAL = ... +STATUS_GOING_AWAY = ... +STATUS_PROTOCOL_ERROR = ... +STATUS_UNSUPPORTED_DATA_TYPE = ... +STATUS_STATUS_NOT_AVAILABLE = ... +STATUS_ABNORMAL_CLOSED = ... +STATUS_INVALID_PAYLOAD = ... +STATUS_POLICY_VIOLATION = ... +STATUS_MESSAGE_TOO_BIG = ... +STATUS_INVALID_EXTENSION = ... +STATUS_UNEXPECTED_CONDITION = ... +STATUS_SERVICE_RESTART = ... +STATUS_TRY_AGAIN_LATER = ... +STATUS_BAD_GATEWAY = ... +STATUS_TLS_HANDSHAKE_ERROR = ... +VALID_CLOSE_STATUS = ... +class ABNF: + """ + ABNF frame class. + See http://tools.ietf.org/html/rfc5234 + and http://tools.ietf.org/html/rfc6455#section-5.2 + """ + OPCODE_CONT = ... + OPCODE_TEXT = ... + OPCODE_BINARY = ... + OPCODE_CLOSE = ... + OPCODE_PING = ... + OPCODE_PONG = ... + OPCODES = ... + OPCODE_MAP = ... + LENGTH_7 = ... + LENGTH_16 = ... + LENGTH_63 = ... + def __init__(self, fin=..., rsv1=..., rsv2=..., rsv3=..., opcode=..., mask=..., data=...) -> None: + """ + Constructor for ABNF. Please check RFC for arguments. + """ + ... + + def validate(self, skip_utf8_validation=...) -> None: + """ + Validate the ABNF frame. + + Parameters + ---------- + skip_utf8_validation: skip utf8 validation. + """ + ... + + def __str__(self) -> str: + ... + + @staticmethod + def create_frame(data, opcode, fin=...): # -> ABNF: + """ + Create frame to send text, binary and other data. + + Parameters + ---------- + data: + data to send. This is string value(byte array). + If opcode is OPCODE_TEXT and this value is unicode, + data value is converted into unicode string, automatically. + opcode: + operation code. please see OPCODE_XXX. + fin: + fin flag. if set to 0, create continue fragmentation. + """ + ... + + def format(self) -> bytes: + """ + Format this object to string(byte array) to send data to server. + """ + ... + + @staticmethod + def mask(mask_key, data): # -> bytes: + """ + Mask or unmask data. Just do xor for each byte + + Parameters + ---------- + mask_key: bytes or str + 4 byte mask. + data: bytes or str + data to mask/unmask. + """ + ... + + + +class frame_buffer: + _HEADER_MASK_INDEX = ... + _HEADER_LENGTH_INDEX = ... + def __init__(self, recv_fn, skip_utf8_validation) -> None: + ... + + def clear(self): # -> None: + ... + + def has_received_header(self) -> bool: + ... + + def recv_header(self): # -> None: + ... + + def has_mask(self): # -> int | Literal[False]: + ... + + def has_received_length(self) -> bool: + ... + + def recv_length(self): # -> None: + ... + + def has_received_mask(self) -> bool: + ... + + def recv_mask(self): # -> None: + ... + + def recv_frame(self): # -> ABNF: + ... + + def recv_strict(self, bufsize: int) -> bytes: + ... + + + +class continuous_frame: + def __init__(self, fire_cont_frame, skip_utf8_validation) -> None: + ... + + def validate(self, frame): # -> None: + ... + + def add(self, frame): # -> None: + ... + + def is_fire(self, frame): # -> Unknown: + ... + + def extract(self, frame): # -> list[Unknown]: + ... + + + diff --git a/typings/websocket/_app.pyi b/typings/websocket/_app.pyi new file mode 100644 index 000000000..e19ce6d57 --- /dev/null +++ b/typings/websocket/_app.pyi @@ -0,0 +1,210 @@ +""" +This type stub file was generated by pyright. +""" + +from ._exceptions import * + +__all__ = ["WebSocketApp"] +RECONNECT = ... +def setReconnect(reconnectInterval): # -> None: + ... + +class DispatcherBase: + """ + DispatcherBase + """ + def __init__(self, app, ping_timeout) -> None: + ... + + def timeout(self, seconds, callback): # -> None: + ... + + def reconnect(self, seconds, reconnector): # -> None: + ... + + + +class Dispatcher(DispatcherBase): + """ + Dispatcher + """ + def read(self, sock, read_callback, check_callback): # -> None: + ... + + + +class SSLDispatcher(DispatcherBase): + """ + SSLDispatcher + """ + def read(self, sock, read_callback, check_callback): # -> None: + ... + + def select(self): # -> list[Unknown] | SelectorKey | None: + ... + + + +class WrappedDispatcher: + """ + WrappedDispatcher + """ + def __init__(self, app, ping_timeout, dispatcher) -> None: + ... + + def read(self, sock, read_callback, check_callback): # -> None: + ... + + def timeout(self, seconds, callback): # -> None: + ... + + def reconnect(self, seconds, reconnector): # -> None: + ... + + + +class WebSocketApp: + """ + Higher level of APIs are provided. The interface is like JavaScript WebSocket object. + """ + def __init__(self, url, header=..., on_open=..., on_message=..., on_error=..., on_close=..., on_ping=..., on_pong=..., on_cont_message=..., keep_running=..., get_mask_key=..., cookie=..., subprotocols=..., on_data=..., socket=...) -> None: + """ + WebSocketApp initialization + + Parameters + ---------- + url: str + Websocket url. + header: list or dict + Custom header for websocket handshake. + on_open: function + Callback object which is called at opening websocket. + on_open has one argument. + The 1st argument is this class object. + on_message: function + Callback object which is called when received data. + on_message has 2 arguments. + The 1st argument is this class object. + The 2nd argument is utf-8 data received from the server. + on_error: function + Callback object which is called when we get error. + on_error has 2 arguments. + The 1st argument is this class object. + The 2nd argument is exception object. + on_close: function + Callback object which is called when connection is closed. + on_close has 3 arguments. + The 1st argument is this class object. + The 2nd argument is close_status_code. + The 3rd argument is close_msg. + on_cont_message: function + Callback object which is called when a continuation + frame is received. + on_cont_message has 3 arguments. + The 1st argument is this class object. + The 2nd argument is utf-8 string which we get from the server. + The 3rd argument is continue flag. if 0, the data continue + to next frame data + on_data: function + Callback object which is called when a message received. + This is called before on_message or on_cont_message, + and then on_message or on_cont_message is called. + on_data has 4 argument. + The 1st argument is this class object. + The 2nd argument is utf-8 string which we get from the server. + The 3rd argument is data type. ABNF.OPCODE_TEXT or ABNF.OPCODE_BINARY will be came. + The 4th argument is continue flag. If 0, the data continue + keep_running: bool + This parameter is obsolete and ignored. + get_mask_key: function + A callable function to get new mask keys, see the + WebSocket.set_mask_key's docstring for more information. + cookie: str + Cookie value. + subprotocols: list + List of available sub protocols. Default is None. + socket: socket + Pre-initialized stream socket. + """ + ... + + def send(self, data, opcode=...): # -> None: + """ + send message + + Parameters + ---------- + data: str + Message to send. If you set opcode to OPCODE_TEXT, + data must be utf-8 string or unicode. + opcode: int + Operation code of data. Default is OPCODE_TEXT. + """ + ... + + def close(self, **kwargs): # -> None: + """ + Close websocket connection. + """ + ... + + def run_forever(self, sockopt=..., sslopt=..., ping_interval=..., ping_timeout=..., ping_payload=..., http_proxy_host=..., http_proxy_port=..., http_no_proxy=..., http_proxy_auth=..., http_proxy_timeout=..., skip_utf8_validation=..., host=..., origin=..., dispatcher=..., suppress_origin=..., proxy_type=..., reconnect=...): + """ + Run event loop for WebSocket framework. + + This loop is an infinite loop and is alive while websocket is available. + + Parameters + ---------- + sockopt: tuple + Values for socket.setsockopt. + sockopt must be tuple + and each element is argument of sock.setsockopt. + sslopt: dict + Optional dict object for ssl socket option. + ping_interval: int or float + Automatically send "ping" command + every specified period (in seconds). + If set to 0, no ping is sent periodically. + ping_timeout: int or float + Timeout (in seconds) if the pong message is not received. + ping_payload: str + Payload message to send with each ping. + http_proxy_host: str + HTTP proxy host name. + http_proxy_port: int or str + HTTP proxy port. If not set, set to 80. + http_no_proxy: list + Whitelisted host names that don't use the proxy. + 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. + skip_utf8_validation: bool + skip utf8 validation. + host: str + update host header. + origin: str + update origin header. + dispatcher: Dispatcher object + customize reading data from socket. + suppress_origin: bool + suppress outputting origin header. + proxy_type: str + type of proxy from: http, socks4, socks4a, socks5, socks5h + reconnect: int + delay interval when reconnecting + + Returns + ------- + teardown: bool + False if the `WebSocketApp` is closed or caught KeyboardInterrupt, + True if any other exception was raised during a loop. + """ + ... + + def create_dispatcher(self, ping_timeout, dispatcher=..., is_ssl=...): # -> WrappedDispatcher | SSLDispatcher | Dispatcher: + ... + + + diff --git a/typings/websocket/_cookiejar.pyi b/typings/websocket/_cookiejar.pyi new file mode 100644 index 000000000..3cb82afd8 --- /dev/null +++ b/typings/websocket/_cookiejar.pyi @@ -0,0 +1,19 @@ +""" +This type stub file was generated by pyright. +""" + +class SimpleCookieJar: + def __init__(self) -> None: + ... + + def add(self, set_cookie): # -> None: + ... + + def set(self, set_cookie): # -> None: + ... + + def get(self, host): # -> str: + ... + + + diff --git a/typings/websocket/_core.pyi b/typings/websocket/_core.pyi new file mode 100644 index 000000000..07868e9d2 --- /dev/null +++ b/typings/websocket/_core.pyi @@ -0,0 +1,416 @@ +""" +This type stub file was generated by pyright. +""" + +from ._abnf import * +from ._exceptions import * +from ._handshake import * +from ._http import * +from ._logging import * +from ._socket import * +from ._ssl_compat import * +from ._utils import * + +__all__ = ['WebSocket', 'create_connection'] +class WebSocket: + """ + Low level WebSocket interface. + + This class is based on the WebSocket protocol `draft-hixie-thewebsocketprotocol-76 `_ + + We can connect to the websocket server and send/receive data. + The following example is an echo client. + + >>> import websocket + >>> ws = websocket.WebSocket() + >>> ws.connect("ws://echo.websocket.events") + >>> ws.recv() + 'echo.websocket.events sponsored by Lob.com' + >>> ws.send("Hello, Server") + 19 + >>> ws.recv() + 'Hello, Server' + >>> ws.close() + + Parameters + ---------- + get_mask_key: func + A callable function to get new mask keys, see the + WebSocket.set_mask_key's docstring for more information. + sockopt: tuple + Values for socket.setsockopt. + sockopt must be tuple and each element is argument of sock.setsockopt. + sslopt: dict + Optional dict object for ssl socket options. See FAQ for details. + fire_cont_frame: bool + Fire recv event for each cont frame. Default is False. + enable_multithread: bool + If set to True, lock send method. + skip_utf8_validation: bool + Skip utf8 validation. + """ + def __init__(self, get_mask_key=..., sockopt=..., sslopt=..., fire_cont_frame=..., enable_multithread=..., skip_utf8_validation=..., **_) -> None: + """ + Initialize WebSocket object. + + Parameters + ---------- + sslopt: dict + Optional dict object for ssl socket options. See FAQ for details. + """ + ... + + def __iter__(self): # -> Generator[Unknown | Literal[''], None, None]: + """ + Allow iteration over websocket, implying sequential `recv` executions. + """ + ... + + def __next__(self): # -> Literal['']: + ... + + def next(self): # -> Literal['']: + ... + + def fileno(self): + ... + + def set_mask_key(self, func): # -> None: + """ + Set function to create mask key. You can customize mask key generator. + Mainly, this is for testing purpose. + + Parameters + ---------- + func: func + callable object. the func takes 1 argument as integer. + The argument means length of mask key. + This func must return string(byte array), + which length is argument specified. + """ + ... + + def gettimeout(self): # -> None: + """ + Get the websocket timeout (in seconds) as an int or float + + Returns + ---------- + timeout: int or float + returns timeout value (in seconds). This value could be either float/integer. + """ + ... + + def settimeout(self, timeout): # -> None: + """ + Set the timeout to the websocket. + + Parameters + ---------- + timeout: int or float + timeout time (in seconds). This value could be either float/integer. + """ + ... + + timeout = ... + def getsubprotocol(self): # -> None: + """ + Get subprotocol + """ + ... + + subprotocol = ... + def getstatus(self): # -> int | None: + """ + Get handshake status + """ + ... + + status = ... + def getheaders(self): # -> dict[Unknown, Unknown] | None: + """ + Get handshake response header + """ + ... + + def is_ssl(self): # -> bool: + ... + + headers = ... + def connect(self, url, **options): + """ + Connect to url. url is websocket url scheme. + ie. ws://host:port/resource + You can customize using 'options'. + If you set "header" list object, you can set your own custom header. + + >>> ws = WebSocket() + >>> ws.connect("ws://echo.websocket.events", + ... header=["User-Agent: MyProgram", + ... "x-custom: header"]) + + Parameters + ---------- + header: list or dict + Custom http header list or dict. + cookie: str + Cookie value. + origin: str + Custom origin url. + connection: str + Custom connection header value. + Default value "Upgrade" set in _handshake.py + suppress_origin: bool + Suppress outputting origin header. + host: str + Custom host header string. + timeout: int or float + Socket timeout time. This value is an integer or float. + If you set None for this value, it means "use default_timeout value" + http_proxy_host: str + HTTP proxy host name. + http_proxy_port: str or int + HTTP proxy port. Default is 80. + http_no_proxy: list + 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 + List of available subprotocols. Default is None. + socket: socket + Pre-initialized stream socket. + """ + ... + + def send(self, payload, opcode=...): # -> int: + """ + Send the data as string. + + Parameters + ---------- + payload: str + Payload must be utf-8 string or unicode, + If the opcode is OPCODE_TEXT. + Otherwise, it must be string(byte array). + opcode: int + Operation code (opcode) to send. + """ + ... + + def send_frame(self, frame): # -> int: + """ + Send the data frame. + + >>> ws = create_connection("ws://echo.websocket.events") + >>> frame = ABNF.create_frame("Hello", ABNF.OPCODE_TEXT) + >>> ws.send_frame(frame) + >>> cont_frame = ABNF.create_frame("My name is ", ABNF.OPCODE_CONT, 0) + >>> ws.send_frame(frame) + >>> cont_frame = ABNF.create_frame("Foo Bar", ABNF.OPCODE_CONT, 1) + >>> ws.send_frame(frame) + + Parameters + ---------- + frame: ABNF frame + frame data created by ABNF.create_frame + """ + ... + + def send_binary(self, payload): # -> int: + """ + Send a binary message (OPCODE_BINARY). + + Parameters + ---------- + payload: bytes + payload of message to send. + """ + ... + + def ping(self, payload=...): # -> None: + """ + Send ping data. + + Parameters + ---------- + payload: str + data payload to send server. + """ + ... + + def pong(self, payload=...): # -> None: + """ + Send pong data. + + Parameters + ---------- + payload: str + data payload to send server. + """ + ... + + def recv(self): # -> Literal['']: + """ + Receive string data(byte array) from the server. + + Returns + ---------- + data: string (byte array) value. + """ + ... + + def recv_data(self, control_frame=...): # -> tuple[Unknown, Unknown]: + """ + Receive data with operation code. + + Parameters + ---------- + control_frame: bool + a boolean flag indicating whether to return control frame + data, defaults to False + + Returns + ------- + opcode, frame.data: tuple + tuple of operation code and string(byte array) value. + """ + ... + + def recv_data_frame(self, control_frame=...): + """ + Receive data with operation code. + + If a valid ping message is received, a pong response is sent. + + Parameters + ---------- + control_frame: bool + a boolean flag indicating whether to return control frame + data, defaults to False + + Returns + ------- + frame.opcode, frame: tuple + tuple of operation code and string(byte array) value. + """ + ... + + def recv_frame(self): # -> ABNF: + """ + Receive data as frame from server. + + Returns + ------- + self.frame_buffer.recv_frame(): ABNF frame object + """ + ... + + def send_close(self, status=..., reason=...): # -> None: + """ + Send close data to the server. + + Parameters + ---------- + status: int + Status code to send. See STATUS_XXX. + reason: str or bytes + The reason to close. This must be string or UTF-8 bytes. + """ + ... + + def close(self, status=..., reason=..., timeout=...): + """ + Close Websocket object + + Parameters + ---------- + status: int + Status code to send. See STATUS_XXX. + reason: bytes + The reason to close in UTF-8. + timeout: int or float + Timeout until receive a close frame. + If None, it will wait forever until receive a close frame. + """ + ... + + def abort(self): # -> None: + """ + Low-level asynchronous abort, wakes up other threads that are waiting in recv_* + """ + ... + + def shutdown(self): # -> None: + """ + close socket, immediately. + """ + ... + + + +def create_connection(url, timeout=..., class_=..., **options): # -> WebSocket: + """ + Connect to url and return websocket object. + + Connect to url and return the WebSocket object. + Passing optional timeout parameter will set the timeout on the socket. + If no timeout is supplied, + the global default timeout setting returned by getdefaulttimeout() is used. + You can customize using 'options'. + If you set "header" list object, you can set your own custom header. + + >>> conn = create_connection("ws://echo.websocket.events", + ... header=["User-Agent: MyProgram", + ... "x-custom: header"]) + + Parameters + ---------- + class_: class + class to instantiate when creating the connection. It has to implement + settimeout and connect. It's __init__ should be compatible with + WebSocket.__init__, i.e. accept all of it's kwargs. + header: list or dict + custom http header list or dict. + cookie: str + Cookie value. + origin: str + custom origin url. + suppress_origin: bool + suppress outputting origin header. + host: str + custom host header string. + timeout: int or float + socket timeout time. This value could be either float/integer. + If set to None, it uses the default_timeout value. + http_proxy_host: str + HTTP proxy host name. + http_proxy_port: str or int + HTTP proxy port. If not set, set to 80. + http_no_proxy: list + 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 + Number of redirects to follow. + sockopt: tuple + Values for socket.setsockopt. + sockopt must be a tuple and each element is an argument of sock.setsockopt. + sslopt: dict + Optional dict object for ssl socket options. See FAQ for details. + subprotocols: list + List of available subprotocols. Default is None. + skip_utf8_validation: bool + Skip utf8 validation. + socket: socket + Pre-initialized stream socket. + """ + ... + diff --git a/typings/websocket/_exceptions.pyi b/typings/websocket/_exceptions.pyi new file mode 100644 index 000000000..20116dfc2 --- /dev/null +++ b/typings/websocket/_exceptions.pyi @@ -0,0 +1,81 @@ +""" +This type stub file was generated by pyright. +""" + +""" +_exceptions.py +websocket - WebSocket client library for Python + +Copyright 2022 engn33r + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +class WebSocketException(Exception): + """ + WebSocket exception class. + """ + ... + + +class WebSocketProtocolException(WebSocketException): + """ + If the WebSocket protocol is invalid, this exception will be raised. + """ + ... + + +class WebSocketPayloadException(WebSocketException): + """ + If the WebSocket payload is invalid, this exception will be raised. + """ + ... + + +class WebSocketConnectionClosedException(WebSocketException): + """ + If remote host closed the connection or some network error happened, + this exception will be raised. + """ + ... + + +class WebSocketTimeoutException(WebSocketException): + """ + WebSocketTimeoutException will be raised at socket timeout during read/write data. + """ + ... + + +class WebSocketProxyException(WebSocketException): + """ + WebSocketProxyException will be raised when proxy error occurred. + """ + ... + + +class WebSocketBadStatusException(WebSocketException): + """ + WebSocketBadStatusException will be raised when we get bad handshake status code. + """ + def __init__(self, message, status_code, status_message=..., resp_headers=...) -> None: + ... + + + +class WebSocketAddressException(WebSocketException): + """ + If the websocket address info cannot be found, this exception will be raised. + """ + ... + + diff --git a/typings/websocket/_handshake.pyi b/typings/websocket/_handshake.pyi new file mode 100644 index 000000000..f7489bea4 --- /dev/null +++ b/typings/websocket/_handshake.pyi @@ -0,0 +1,42 @@ +""" +This type stub file was generated by pyright. +""" + +from ._exceptions import * +from ._http import * +from ._logging import * +from ._socket import * + +""" +_handshake.py +websocket - WebSocket client library for Python + +Copyright 2022 engn33r + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +__all__ = ["handshake_response", "handshake", "SUPPORTED_REDIRECT_STATUSES"] +VERSION = ... +SUPPORTED_REDIRECT_STATUSES = ... +SUCCESS_STATUSES = ... +CookieJar = ... +class handshake_response: + def __init__(self, status, headers, subprotocol) -> None: + ... + + + +def handshake(sock, url, hostname, port, resource, **options): # -> handshake_response: + ... + +_HEADERS_TO_CHECK = ... diff --git a/typings/websocket/_http.pyi b/typings/websocket/_http.pyi new file mode 100644 index 000000000..9ced66fab --- /dev/null +++ b/typings/websocket/_http.pyi @@ -0,0 +1,41 @@ +""" +This type stub file was generated by pyright. +""" + +from ._exceptions import * +from ._logging import * +from ._socket import * +from ._ssl_compat import * +from ._url import * + +""" +_http.py +websocket - WebSocket client library for Python + +Copyright 2022 engn33r + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +__all__ = ["proxy_info", "connect", "read_headers"] +class proxy_info: + def __init__(self, **options) -> None: + ... + + + +def connect(url, options, proxy, socket): + ... + +def read_headers(sock): # -> tuple[int | None, dict[Unknown, Unknown], str | None]: + ... + diff --git a/typings/websocket/_logging.pyi b/typings/websocket/_logging.pyi new file mode 100644 index 000000000..bcf18dc7a --- /dev/null +++ b/typings/websocket/_logging.pyi @@ -0,0 +1,45 @@ +""" +This type stub file was generated by pyright. +""" + +_logger = ... +_traceEnabled = ... +__all__ = ["enableTrace", "dump", "error", "warning", "debug", "trace", "isEnabledForError", "isEnabledForDebug", "isEnabledForTrace"] +def enableTrace(traceable, handler=..., level=...): # -> None: + """ + Turn on/off the traceability. + + Parameters + ---------- + traceable: bool + If set to True, traceability is enabled. + """ + ... + +def dump(title, message): # -> None: + ... + +def error(msg): # -> None: + ... + +def warning(msg): # -> None: + ... + +def debug(msg): # -> None: + ... + +def info(msg): # -> None: + ... + +def trace(msg): # -> None: + ... + +def isEnabledForError(): # -> bool: + ... + +def isEnabledForDebug(): # -> bool: + ... + +def isEnabledForTrace(): # -> Literal[False]: + ... + diff --git a/typings/websocket/_socket.pyi b/typings/websocket/_socket.pyi new file mode 100644 index 000000000..e45acdc98 --- /dev/null +++ b/typings/websocket/_socket.pyi @@ -0,0 +1,57 @@ +""" +This type stub file was generated by pyright. +""" + +import socket +from ._exceptions import * +from ._ssl_compat import * +from ._utils import * + +DEFAULT_SOCKET_OPTION = ... +if hasattr(socket, "SO_KEEPALIVE"): + ... +if hasattr(socket, "TCP_KEEPIDLE"): + ... +if hasattr(socket, "TCP_KEEPINTVL"): + ... +if hasattr(socket, "TCP_KEEPCNT"): + ... +_default_timeout = ... +__all__ = ["DEFAULT_SOCKET_OPTION", "sock_opt", "setdefaulttimeout", "getdefaulttimeout", "recv", "recv_line", "send"] +class sock_opt: + def __init__(self, sockopt, sslopt) -> None: + ... + + + +def setdefaulttimeout(timeout): # -> None: + """ + Set the global timeout setting to connect. + + Parameters + ---------- + timeout: int or float + default socket timeout time (in seconds) + """ + ... + +def getdefaulttimeout(): # -> None: + """ + Get default timeout + + Returns + ---------- + _default_timeout: int or float + Return the global timeout setting (in seconds) to connect. + """ + ... + +def recv(sock, bufsize): + ... + +def recv_line(sock): # -> bytes: + ... + +def send(sock, data): + ... + diff --git a/typings/websocket/_ssl_compat.pyi b/typings/websocket/_ssl_compat.pyi new file mode 100644 index 000000000..cba150293 --- /dev/null +++ b/typings/websocket/_ssl_compat.pyi @@ -0,0 +1,23 @@ +""" +This type stub file was generated by pyright. +""" + +""" +_ssl_compat.py +websocket - WebSocket client library for Python + +Copyright 2022 engn33r + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +__all__ = ["HAVE_SSL", "ssl", "SSLError", "SSLWantReadError", "SSLWantWriteError"] diff --git a/typings/websocket/_url.pyi b/typings/websocket/_url.pyi new file mode 100644 index 000000000..0d1bc01e9 --- /dev/null +++ b/typings/websocket/_url.pyi @@ -0,0 +1,47 @@ +""" +This type stub file was generated by pyright. +""" + +__all__ = ["parse_url", "get_proxy_info"] +def parse_url(url): # -> tuple[str, int, str, bool]: + """ + parse url and the result is tuple of + (hostname, port, resource path and the flag of secure mode) + + Parameters + ---------- + url: str + url string. + """ + ... + +DEFAULT_NO_PROXY_HOST = ... +def get_proxy_info(hostname, is_secure, proxy_host=..., proxy_port=..., proxy_auth=..., no_proxy=..., proxy_type=...): # -> tuple[None, Literal[0], None] | tuple[Unknown, int, Unknown | None] | tuple[str | None, int | None, tuple[str, str] | None]: + """ + Try to retrieve proxy host and port from environment + if not provided in options. + Result is (proxy_host, proxy_port, proxy_auth). + proxy_auth is tuple of username and password + of proxy authentication information. + + Parameters + ---------- + hostname: str + Websocket server name. + is_secure: bool + Is the connection secure? (wss) looks for "https_proxy" in env + before falling back to "http_proxy" + proxy_host: str + http proxy host name. + http_proxy_port: str or int + http proxy port. + http_no_proxy: list + 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. + proxy_type: str + Specify the proxy protocol (http, socks4, socks4a, socks5, socks5h). Default is "http". + Use socks4a or socks5h if you want to send DNS requests through the proxy. + """ + ... + diff --git a/typings/websocket/_utils.pyi b/typings/websocket/_utils.pyi new file mode 100644 index 000000000..619d80a64 --- /dev/null +++ b/typings/websocket/_utils.pyi @@ -0,0 +1,46 @@ +""" +This type stub file was generated by pyright. +""" + +""" +_url.py +websocket - WebSocket client library for Python + +Copyright 2022 engn33r + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +__all__ = ["NoLock", "validate_utf8", "extract_err_message", "extract_error_code"] +class NoLock: + def __enter__(self): # -> None: + ... + + def __exit__(self, exc_type, exc_value, traceback): # -> None: + ... + + + +def validate_utf8(utfbytes): # -> bool: + """ + validate utf8 byte string. + utfbytes: utf byte string to check. + return value: if valid utf8 string, return true. Otherwise, return false. + """ + ... + +def extract_err_message(exception): # -> None: + ... + +def extract_error_code(exception): # -> None: + ... + diff --git a/typings/websocket/_wsdump.pyi b/typings/websocket/_wsdump.pyi new file mode 100644 index 000000000..a64c1a827 --- /dev/null +++ b/typings/websocket/_wsdump.pyi @@ -0,0 +1,68 @@ +""" +This type stub file was generated by pyright. +""" + +import argparse +import code + +""" +wsdump.py +websocket - WebSocket client library for Python + +Copyright 2022 engn33r + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" +def get_encoding(): # -> Any | str: + ... + +OPCODE_DATA = ... +ENCODING = ... +class VAction(argparse.Action): + def __call__(self, parser, args, values, option_string=...): # -> None: + ... + + + +def parse_args(): # -> Namespace: + ... + +class RawInput: + def raw_input(self, prompt): # -> bytes: + ... + + + +class InteractiveConsole(RawInput, code.InteractiveConsole): + def write(self, data): # -> None: + ... + + def read(self): # -> bytes: + ... + + + +class NonInteractive(RawInput): + def write(self, data): # -> None: + ... + + def read(self): # -> bytes: + ... + + + +def main(): # -> None: + ... + +if __name__ == "__main__": + ... diff --git a/typings/websocket/tests/__init__.pyi b/typings/websocket/tests/__init__.pyi new file mode 100644 index 000000000..006bc2749 --- /dev/null +++ b/typings/websocket/tests/__init__.pyi @@ -0,0 +1,4 @@ +""" +This type stub file was generated by pyright. +""" + From 2386cf2ff7dfc0141e63343865f49c65a1efa116 Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Mon, 16 Jan 2023 15:11:40 +0530 Subject: [PATCH 02/17] Ignore partially undefined warnings for websocket methods --- ops/pebble.py | 6 +++--- typings/websocket/_core.pyi | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ops/pebble.py b/ops/pebble.py index d0352ddfd..ae0203bd5 100644 --- a/ops/pebble.py +++ b/ops/pebble.py @@ -1197,10 +1197,10 @@ def _wait(self) -> int: os.close(self._cancel_reader) # Close websockets (shutdown doesn't send CLOSE message or wait for response). - self._control_ws.shutdown() - self._stdio_ws.shutdown() + self._control_ws.shutdown() # type: ignore + self._stdio_ws.shutdown() # type: ignore if self._stderr_ws is not None: - self._stderr_ws.shutdown() + self._stderr_ws.shutdown() # type: ignore if change.err: raise ChangeError(change.err, change) diff --git a/typings/websocket/_core.pyi b/typings/websocket/_core.pyi index 07868e9d2..84caae3c8 100644 --- a/typings/websocket/_core.pyi +++ b/typings/websocket/_core.pyi @@ -253,7 +253,7 @@ class WebSocket: """ ... - def recv(self): # -> Literal['']: + def recv(self): # -> str | bytes: """ Receive string data(byte array) from the server. From b807eba21821d98be3cfc3c046ee7d365172180b Mon Sep 17 00:00:00 2001 From: Ben Hoyt Date: Tue, 17 Jan 2023 16:57:14 +1300 Subject: [PATCH 03/17] Use local _WebSocket type stub of just methods we're using --- ops/pebble.py | 6 +- typings/websocket/__init__.pyi | 30 -- typings/websocket/_abnf.pyi | 155 ---------- typings/websocket/_app.pyi | 210 -------------- typings/websocket/_cookiejar.pyi | 19 -- typings/websocket/_core.pyi | 416 --------------------------- typings/websocket/_exceptions.pyi | 81 ------ typings/websocket/_handshake.pyi | 42 --- typings/websocket/_http.pyi | 41 --- typings/websocket/_logging.pyi | 45 --- typings/websocket/_socket.pyi | 57 ---- typings/websocket/_ssl_compat.pyi | 23 -- typings/websocket/_url.pyi | 47 --- typings/websocket/_utils.pyi | 46 --- typings/websocket/_wsdump.pyi | 68 ----- typings/websocket/tests/__init__.pyi | 4 - 16 files changed, 3 insertions(+), 1287 deletions(-) delete mode 100644 typings/websocket/__init__.pyi delete mode 100644 typings/websocket/_abnf.pyi delete mode 100644 typings/websocket/_app.pyi delete mode 100644 typings/websocket/_cookiejar.pyi delete mode 100644 typings/websocket/_core.pyi delete mode 100644 typings/websocket/_exceptions.pyi delete mode 100644 typings/websocket/_handshake.pyi delete mode 100644 typings/websocket/_http.pyi delete mode 100644 typings/websocket/_logging.pyi delete mode 100644 typings/websocket/_socket.pyi delete mode 100644 typings/websocket/_ssl_compat.pyi delete mode 100644 typings/websocket/_url.pyi delete mode 100644 typings/websocket/_utils.pyi delete mode 100644 typings/websocket/_wsdump.pyi delete mode 100644 typings/websocket/tests/__init__.pyi diff --git a/ops/pebble.py b/ops/pebble.py index ae0203bd5..d0352ddfd 100644 --- a/ops/pebble.py +++ b/ops/pebble.py @@ -1197,10 +1197,10 @@ def _wait(self) -> int: os.close(self._cancel_reader) # Close websockets (shutdown doesn't send CLOSE message or wait for response). - self._control_ws.shutdown() # type: ignore - self._stdio_ws.shutdown() # type: ignore + self._control_ws.shutdown() + self._stdio_ws.shutdown() if self._stderr_ws is not None: - self._stderr_ws.shutdown() # type: ignore + self._stderr_ws.shutdown() if change.err: raise ChangeError(change.err, change) diff --git a/typings/websocket/__init__.pyi b/typings/websocket/__init__.pyi deleted file mode 100644 index 6e67b80b3..000000000 --- a/typings/websocket/__init__.pyi +++ /dev/null @@ -1,30 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -from ._abnf import * -from ._app import WebSocketApp, setReconnect -from ._core import * -from ._exceptions import * -from ._logging import * -from ._socket import * - -""" -__init__.py -websocket - WebSocket client library for Python - -Copyright 2022 engn33r - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" -__version__ = ... diff --git a/typings/websocket/_abnf.pyi b/typings/websocket/_abnf.pyi deleted file mode 100644 index 139330620..000000000 --- a/typings/websocket/_abnf.pyi +++ /dev/null @@ -1,155 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -from ._exceptions import * - -__all__ = ['ABNF', 'continuous_frame', 'frame_buffer', 'STATUS_NORMAL', 'STATUS_GOING_AWAY', 'STATUS_PROTOCOL_ERROR', 'STATUS_UNSUPPORTED_DATA_TYPE', 'STATUS_STATUS_NOT_AVAILABLE', 'STATUS_ABNORMAL_CLOSED', 'STATUS_INVALID_PAYLOAD', 'STATUS_POLICY_VIOLATION', 'STATUS_MESSAGE_TOO_BIG', 'STATUS_INVALID_EXTENSION', 'STATUS_UNEXPECTED_CONDITION', 'STATUS_BAD_GATEWAY', 'STATUS_TLS_HANDSHAKE_ERROR'] -STATUS_NORMAL = ... -STATUS_GOING_AWAY = ... -STATUS_PROTOCOL_ERROR = ... -STATUS_UNSUPPORTED_DATA_TYPE = ... -STATUS_STATUS_NOT_AVAILABLE = ... -STATUS_ABNORMAL_CLOSED = ... -STATUS_INVALID_PAYLOAD = ... -STATUS_POLICY_VIOLATION = ... -STATUS_MESSAGE_TOO_BIG = ... -STATUS_INVALID_EXTENSION = ... -STATUS_UNEXPECTED_CONDITION = ... -STATUS_SERVICE_RESTART = ... -STATUS_TRY_AGAIN_LATER = ... -STATUS_BAD_GATEWAY = ... -STATUS_TLS_HANDSHAKE_ERROR = ... -VALID_CLOSE_STATUS = ... -class ABNF: - """ - ABNF frame class. - See http://tools.ietf.org/html/rfc5234 - and http://tools.ietf.org/html/rfc6455#section-5.2 - """ - OPCODE_CONT = ... - OPCODE_TEXT = ... - OPCODE_BINARY = ... - OPCODE_CLOSE = ... - OPCODE_PING = ... - OPCODE_PONG = ... - OPCODES = ... - OPCODE_MAP = ... - LENGTH_7 = ... - LENGTH_16 = ... - LENGTH_63 = ... - def __init__(self, fin=..., rsv1=..., rsv2=..., rsv3=..., opcode=..., mask=..., data=...) -> None: - """ - Constructor for ABNF. Please check RFC for arguments. - """ - ... - - def validate(self, skip_utf8_validation=...) -> None: - """ - Validate the ABNF frame. - - Parameters - ---------- - skip_utf8_validation: skip utf8 validation. - """ - ... - - def __str__(self) -> str: - ... - - @staticmethod - def create_frame(data, opcode, fin=...): # -> ABNF: - """ - Create frame to send text, binary and other data. - - Parameters - ---------- - data: - data to send. This is string value(byte array). - If opcode is OPCODE_TEXT and this value is unicode, - data value is converted into unicode string, automatically. - opcode: - operation code. please see OPCODE_XXX. - fin: - fin flag. if set to 0, create continue fragmentation. - """ - ... - - def format(self) -> bytes: - """ - Format this object to string(byte array) to send data to server. - """ - ... - - @staticmethod - def mask(mask_key, data): # -> bytes: - """ - Mask or unmask data. Just do xor for each byte - - Parameters - ---------- - mask_key: bytes or str - 4 byte mask. - data: bytes or str - data to mask/unmask. - """ - ... - - - -class frame_buffer: - _HEADER_MASK_INDEX = ... - _HEADER_LENGTH_INDEX = ... - def __init__(self, recv_fn, skip_utf8_validation) -> None: - ... - - def clear(self): # -> None: - ... - - def has_received_header(self) -> bool: - ... - - def recv_header(self): # -> None: - ... - - def has_mask(self): # -> int | Literal[False]: - ... - - def has_received_length(self) -> bool: - ... - - def recv_length(self): # -> None: - ... - - def has_received_mask(self) -> bool: - ... - - def recv_mask(self): # -> None: - ... - - def recv_frame(self): # -> ABNF: - ... - - def recv_strict(self, bufsize: int) -> bytes: - ... - - - -class continuous_frame: - def __init__(self, fire_cont_frame, skip_utf8_validation) -> None: - ... - - def validate(self, frame): # -> None: - ... - - def add(self, frame): # -> None: - ... - - def is_fire(self, frame): # -> Unknown: - ... - - def extract(self, frame): # -> list[Unknown]: - ... - - - diff --git a/typings/websocket/_app.pyi b/typings/websocket/_app.pyi deleted file mode 100644 index e19ce6d57..000000000 --- a/typings/websocket/_app.pyi +++ /dev/null @@ -1,210 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -from ._exceptions import * - -__all__ = ["WebSocketApp"] -RECONNECT = ... -def setReconnect(reconnectInterval): # -> None: - ... - -class DispatcherBase: - """ - DispatcherBase - """ - def __init__(self, app, ping_timeout) -> None: - ... - - def timeout(self, seconds, callback): # -> None: - ... - - def reconnect(self, seconds, reconnector): # -> None: - ... - - - -class Dispatcher(DispatcherBase): - """ - Dispatcher - """ - def read(self, sock, read_callback, check_callback): # -> None: - ... - - - -class SSLDispatcher(DispatcherBase): - """ - SSLDispatcher - """ - def read(self, sock, read_callback, check_callback): # -> None: - ... - - def select(self): # -> list[Unknown] | SelectorKey | None: - ... - - - -class WrappedDispatcher: - """ - WrappedDispatcher - """ - def __init__(self, app, ping_timeout, dispatcher) -> None: - ... - - def read(self, sock, read_callback, check_callback): # -> None: - ... - - def timeout(self, seconds, callback): # -> None: - ... - - def reconnect(self, seconds, reconnector): # -> None: - ... - - - -class WebSocketApp: - """ - Higher level of APIs are provided. The interface is like JavaScript WebSocket object. - """ - def __init__(self, url, header=..., on_open=..., on_message=..., on_error=..., on_close=..., on_ping=..., on_pong=..., on_cont_message=..., keep_running=..., get_mask_key=..., cookie=..., subprotocols=..., on_data=..., socket=...) -> None: - """ - WebSocketApp initialization - - Parameters - ---------- - url: str - Websocket url. - header: list or dict - Custom header for websocket handshake. - on_open: function - Callback object which is called at opening websocket. - on_open has one argument. - The 1st argument is this class object. - on_message: function - Callback object which is called when received data. - on_message has 2 arguments. - The 1st argument is this class object. - The 2nd argument is utf-8 data received from the server. - on_error: function - Callback object which is called when we get error. - on_error has 2 arguments. - The 1st argument is this class object. - The 2nd argument is exception object. - on_close: function - Callback object which is called when connection is closed. - on_close has 3 arguments. - The 1st argument is this class object. - The 2nd argument is close_status_code. - The 3rd argument is close_msg. - on_cont_message: function - Callback object which is called when a continuation - frame is received. - on_cont_message has 3 arguments. - The 1st argument is this class object. - The 2nd argument is utf-8 string which we get from the server. - The 3rd argument is continue flag. if 0, the data continue - to next frame data - on_data: function - Callback object which is called when a message received. - This is called before on_message or on_cont_message, - and then on_message or on_cont_message is called. - on_data has 4 argument. - The 1st argument is this class object. - The 2nd argument is utf-8 string which we get from the server. - The 3rd argument is data type. ABNF.OPCODE_TEXT or ABNF.OPCODE_BINARY will be came. - The 4th argument is continue flag. If 0, the data continue - keep_running: bool - This parameter is obsolete and ignored. - get_mask_key: function - A callable function to get new mask keys, see the - WebSocket.set_mask_key's docstring for more information. - cookie: str - Cookie value. - subprotocols: list - List of available sub protocols. Default is None. - socket: socket - Pre-initialized stream socket. - """ - ... - - def send(self, data, opcode=...): # -> None: - """ - send message - - Parameters - ---------- - data: str - Message to send. If you set opcode to OPCODE_TEXT, - data must be utf-8 string or unicode. - opcode: int - Operation code of data. Default is OPCODE_TEXT. - """ - ... - - def close(self, **kwargs): # -> None: - """ - Close websocket connection. - """ - ... - - def run_forever(self, sockopt=..., sslopt=..., ping_interval=..., ping_timeout=..., ping_payload=..., http_proxy_host=..., http_proxy_port=..., http_no_proxy=..., http_proxy_auth=..., http_proxy_timeout=..., skip_utf8_validation=..., host=..., origin=..., dispatcher=..., suppress_origin=..., proxy_type=..., reconnect=...): - """ - Run event loop for WebSocket framework. - - This loop is an infinite loop and is alive while websocket is available. - - Parameters - ---------- - sockopt: tuple - Values for socket.setsockopt. - sockopt must be tuple - and each element is argument of sock.setsockopt. - sslopt: dict - Optional dict object for ssl socket option. - ping_interval: int or float - Automatically send "ping" command - every specified period (in seconds). - If set to 0, no ping is sent periodically. - ping_timeout: int or float - Timeout (in seconds) if the pong message is not received. - ping_payload: str - Payload message to send with each ping. - http_proxy_host: str - HTTP proxy host name. - http_proxy_port: int or str - HTTP proxy port. If not set, set to 80. - http_no_proxy: list - Whitelisted host names that don't use the proxy. - 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. - skip_utf8_validation: bool - skip utf8 validation. - host: str - update host header. - origin: str - update origin header. - dispatcher: Dispatcher object - customize reading data from socket. - suppress_origin: bool - suppress outputting origin header. - proxy_type: str - type of proxy from: http, socks4, socks4a, socks5, socks5h - reconnect: int - delay interval when reconnecting - - Returns - ------- - teardown: bool - False if the `WebSocketApp` is closed or caught KeyboardInterrupt, - True if any other exception was raised during a loop. - """ - ... - - def create_dispatcher(self, ping_timeout, dispatcher=..., is_ssl=...): # -> WrappedDispatcher | SSLDispatcher | Dispatcher: - ... - - - diff --git a/typings/websocket/_cookiejar.pyi b/typings/websocket/_cookiejar.pyi deleted file mode 100644 index 3cb82afd8..000000000 --- a/typings/websocket/_cookiejar.pyi +++ /dev/null @@ -1,19 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -class SimpleCookieJar: - def __init__(self) -> None: - ... - - def add(self, set_cookie): # -> None: - ... - - def set(self, set_cookie): # -> None: - ... - - def get(self, host): # -> str: - ... - - - diff --git a/typings/websocket/_core.pyi b/typings/websocket/_core.pyi deleted file mode 100644 index 84caae3c8..000000000 --- a/typings/websocket/_core.pyi +++ /dev/null @@ -1,416 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -from ._abnf import * -from ._exceptions import * -from ._handshake import * -from ._http import * -from ._logging import * -from ._socket import * -from ._ssl_compat import * -from ._utils import * - -__all__ = ['WebSocket', 'create_connection'] -class WebSocket: - """ - Low level WebSocket interface. - - This class is based on the WebSocket protocol `draft-hixie-thewebsocketprotocol-76 `_ - - We can connect to the websocket server and send/receive data. - The following example is an echo client. - - >>> import websocket - >>> ws = websocket.WebSocket() - >>> ws.connect("ws://echo.websocket.events") - >>> ws.recv() - 'echo.websocket.events sponsored by Lob.com' - >>> ws.send("Hello, Server") - 19 - >>> ws.recv() - 'Hello, Server' - >>> ws.close() - - Parameters - ---------- - get_mask_key: func - A callable function to get new mask keys, see the - WebSocket.set_mask_key's docstring for more information. - sockopt: tuple - Values for socket.setsockopt. - sockopt must be tuple and each element is argument of sock.setsockopt. - sslopt: dict - Optional dict object for ssl socket options. See FAQ for details. - fire_cont_frame: bool - Fire recv event for each cont frame. Default is False. - enable_multithread: bool - If set to True, lock send method. - skip_utf8_validation: bool - Skip utf8 validation. - """ - def __init__(self, get_mask_key=..., sockopt=..., sslopt=..., fire_cont_frame=..., enable_multithread=..., skip_utf8_validation=..., **_) -> None: - """ - Initialize WebSocket object. - - Parameters - ---------- - sslopt: dict - Optional dict object for ssl socket options. See FAQ for details. - """ - ... - - def __iter__(self): # -> Generator[Unknown | Literal[''], None, None]: - """ - Allow iteration over websocket, implying sequential `recv` executions. - """ - ... - - def __next__(self): # -> Literal['']: - ... - - def next(self): # -> Literal['']: - ... - - def fileno(self): - ... - - def set_mask_key(self, func): # -> None: - """ - Set function to create mask key. You can customize mask key generator. - Mainly, this is for testing purpose. - - Parameters - ---------- - func: func - callable object. the func takes 1 argument as integer. - The argument means length of mask key. - This func must return string(byte array), - which length is argument specified. - """ - ... - - def gettimeout(self): # -> None: - """ - Get the websocket timeout (in seconds) as an int or float - - Returns - ---------- - timeout: int or float - returns timeout value (in seconds). This value could be either float/integer. - """ - ... - - def settimeout(self, timeout): # -> None: - """ - Set the timeout to the websocket. - - Parameters - ---------- - timeout: int or float - timeout time (in seconds). This value could be either float/integer. - """ - ... - - timeout = ... - def getsubprotocol(self): # -> None: - """ - Get subprotocol - """ - ... - - subprotocol = ... - def getstatus(self): # -> int | None: - """ - Get handshake status - """ - ... - - status = ... - def getheaders(self): # -> dict[Unknown, Unknown] | None: - """ - Get handshake response header - """ - ... - - def is_ssl(self): # -> bool: - ... - - headers = ... - def connect(self, url, **options): - """ - Connect to url. url is websocket url scheme. - ie. ws://host:port/resource - You can customize using 'options'. - If you set "header" list object, you can set your own custom header. - - >>> ws = WebSocket() - >>> ws.connect("ws://echo.websocket.events", - ... header=["User-Agent: MyProgram", - ... "x-custom: header"]) - - Parameters - ---------- - header: list or dict - Custom http header list or dict. - cookie: str - Cookie value. - origin: str - Custom origin url. - connection: str - Custom connection header value. - Default value "Upgrade" set in _handshake.py - suppress_origin: bool - Suppress outputting origin header. - host: str - Custom host header string. - timeout: int or float - Socket timeout time. This value is an integer or float. - If you set None for this value, it means "use default_timeout value" - http_proxy_host: str - HTTP proxy host name. - http_proxy_port: str or int - HTTP proxy port. Default is 80. - http_no_proxy: list - 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 - List of available subprotocols. Default is None. - socket: socket - Pre-initialized stream socket. - """ - ... - - def send(self, payload, opcode=...): # -> int: - """ - Send the data as string. - - Parameters - ---------- - payload: str - Payload must be utf-8 string or unicode, - If the opcode is OPCODE_TEXT. - Otherwise, it must be string(byte array). - opcode: int - Operation code (opcode) to send. - """ - ... - - def send_frame(self, frame): # -> int: - """ - Send the data frame. - - >>> ws = create_connection("ws://echo.websocket.events") - >>> frame = ABNF.create_frame("Hello", ABNF.OPCODE_TEXT) - >>> ws.send_frame(frame) - >>> cont_frame = ABNF.create_frame("My name is ", ABNF.OPCODE_CONT, 0) - >>> ws.send_frame(frame) - >>> cont_frame = ABNF.create_frame("Foo Bar", ABNF.OPCODE_CONT, 1) - >>> ws.send_frame(frame) - - Parameters - ---------- - frame: ABNF frame - frame data created by ABNF.create_frame - """ - ... - - def send_binary(self, payload): # -> int: - """ - Send a binary message (OPCODE_BINARY). - - Parameters - ---------- - payload: bytes - payload of message to send. - """ - ... - - def ping(self, payload=...): # -> None: - """ - Send ping data. - - Parameters - ---------- - payload: str - data payload to send server. - """ - ... - - def pong(self, payload=...): # -> None: - """ - Send pong data. - - Parameters - ---------- - payload: str - data payload to send server. - """ - ... - - def recv(self): # -> str | bytes: - """ - Receive string data(byte array) from the server. - - Returns - ---------- - data: string (byte array) value. - """ - ... - - def recv_data(self, control_frame=...): # -> tuple[Unknown, Unknown]: - """ - Receive data with operation code. - - Parameters - ---------- - control_frame: bool - a boolean flag indicating whether to return control frame - data, defaults to False - - Returns - ------- - opcode, frame.data: tuple - tuple of operation code and string(byte array) value. - """ - ... - - def recv_data_frame(self, control_frame=...): - """ - Receive data with operation code. - - If a valid ping message is received, a pong response is sent. - - Parameters - ---------- - control_frame: bool - a boolean flag indicating whether to return control frame - data, defaults to False - - Returns - ------- - frame.opcode, frame: tuple - tuple of operation code and string(byte array) value. - """ - ... - - def recv_frame(self): # -> ABNF: - """ - Receive data as frame from server. - - Returns - ------- - self.frame_buffer.recv_frame(): ABNF frame object - """ - ... - - def send_close(self, status=..., reason=...): # -> None: - """ - Send close data to the server. - - Parameters - ---------- - status: int - Status code to send. See STATUS_XXX. - reason: str or bytes - The reason to close. This must be string or UTF-8 bytes. - """ - ... - - def close(self, status=..., reason=..., timeout=...): - """ - Close Websocket object - - Parameters - ---------- - status: int - Status code to send. See STATUS_XXX. - reason: bytes - The reason to close in UTF-8. - timeout: int or float - Timeout until receive a close frame. - If None, it will wait forever until receive a close frame. - """ - ... - - def abort(self): # -> None: - """ - Low-level asynchronous abort, wakes up other threads that are waiting in recv_* - """ - ... - - def shutdown(self): # -> None: - """ - close socket, immediately. - """ - ... - - - -def create_connection(url, timeout=..., class_=..., **options): # -> WebSocket: - """ - Connect to url and return websocket object. - - Connect to url and return the WebSocket object. - Passing optional timeout parameter will set the timeout on the socket. - If no timeout is supplied, - the global default timeout setting returned by getdefaulttimeout() is used. - You can customize using 'options'. - If you set "header" list object, you can set your own custom header. - - >>> conn = create_connection("ws://echo.websocket.events", - ... header=["User-Agent: MyProgram", - ... "x-custom: header"]) - - Parameters - ---------- - class_: class - class to instantiate when creating the connection. It has to implement - settimeout and connect. It's __init__ should be compatible with - WebSocket.__init__, i.e. accept all of it's kwargs. - header: list or dict - custom http header list or dict. - cookie: str - Cookie value. - origin: str - custom origin url. - suppress_origin: bool - suppress outputting origin header. - host: str - custom host header string. - timeout: int or float - socket timeout time. This value could be either float/integer. - If set to None, it uses the default_timeout value. - http_proxy_host: str - HTTP proxy host name. - http_proxy_port: str or int - HTTP proxy port. If not set, set to 80. - http_no_proxy: list - 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 - Number of redirects to follow. - sockopt: tuple - Values for socket.setsockopt. - sockopt must be a tuple and each element is an argument of sock.setsockopt. - sslopt: dict - Optional dict object for ssl socket options. See FAQ for details. - subprotocols: list - List of available subprotocols. Default is None. - skip_utf8_validation: bool - Skip utf8 validation. - socket: socket - Pre-initialized stream socket. - """ - ... - diff --git a/typings/websocket/_exceptions.pyi b/typings/websocket/_exceptions.pyi deleted file mode 100644 index 20116dfc2..000000000 --- a/typings/websocket/_exceptions.pyi +++ /dev/null @@ -1,81 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -""" -_exceptions.py -websocket - WebSocket client library for Python - -Copyright 2022 engn33r - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" -class WebSocketException(Exception): - """ - WebSocket exception class. - """ - ... - - -class WebSocketProtocolException(WebSocketException): - """ - If the WebSocket protocol is invalid, this exception will be raised. - """ - ... - - -class WebSocketPayloadException(WebSocketException): - """ - If the WebSocket payload is invalid, this exception will be raised. - """ - ... - - -class WebSocketConnectionClosedException(WebSocketException): - """ - If remote host closed the connection or some network error happened, - this exception will be raised. - """ - ... - - -class WebSocketTimeoutException(WebSocketException): - """ - WebSocketTimeoutException will be raised at socket timeout during read/write data. - """ - ... - - -class WebSocketProxyException(WebSocketException): - """ - WebSocketProxyException will be raised when proxy error occurred. - """ - ... - - -class WebSocketBadStatusException(WebSocketException): - """ - WebSocketBadStatusException will be raised when we get bad handshake status code. - """ - def __init__(self, message, status_code, status_message=..., resp_headers=...) -> None: - ... - - - -class WebSocketAddressException(WebSocketException): - """ - If the websocket address info cannot be found, this exception will be raised. - """ - ... - - diff --git a/typings/websocket/_handshake.pyi b/typings/websocket/_handshake.pyi deleted file mode 100644 index f7489bea4..000000000 --- a/typings/websocket/_handshake.pyi +++ /dev/null @@ -1,42 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -from ._exceptions import * -from ._http import * -from ._logging import * -from ._socket import * - -""" -_handshake.py -websocket - WebSocket client library for Python - -Copyright 2022 engn33r - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" -__all__ = ["handshake_response", "handshake", "SUPPORTED_REDIRECT_STATUSES"] -VERSION = ... -SUPPORTED_REDIRECT_STATUSES = ... -SUCCESS_STATUSES = ... -CookieJar = ... -class handshake_response: - def __init__(self, status, headers, subprotocol) -> None: - ... - - - -def handshake(sock, url, hostname, port, resource, **options): # -> handshake_response: - ... - -_HEADERS_TO_CHECK = ... diff --git a/typings/websocket/_http.pyi b/typings/websocket/_http.pyi deleted file mode 100644 index 9ced66fab..000000000 --- a/typings/websocket/_http.pyi +++ /dev/null @@ -1,41 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -from ._exceptions import * -from ._logging import * -from ._socket import * -from ._ssl_compat import * -from ._url import * - -""" -_http.py -websocket - WebSocket client library for Python - -Copyright 2022 engn33r - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" -__all__ = ["proxy_info", "connect", "read_headers"] -class proxy_info: - def __init__(self, **options) -> None: - ... - - - -def connect(url, options, proxy, socket): - ... - -def read_headers(sock): # -> tuple[int | None, dict[Unknown, Unknown], str | None]: - ... - diff --git a/typings/websocket/_logging.pyi b/typings/websocket/_logging.pyi deleted file mode 100644 index bcf18dc7a..000000000 --- a/typings/websocket/_logging.pyi +++ /dev/null @@ -1,45 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -_logger = ... -_traceEnabled = ... -__all__ = ["enableTrace", "dump", "error", "warning", "debug", "trace", "isEnabledForError", "isEnabledForDebug", "isEnabledForTrace"] -def enableTrace(traceable, handler=..., level=...): # -> None: - """ - Turn on/off the traceability. - - Parameters - ---------- - traceable: bool - If set to True, traceability is enabled. - """ - ... - -def dump(title, message): # -> None: - ... - -def error(msg): # -> None: - ... - -def warning(msg): # -> None: - ... - -def debug(msg): # -> None: - ... - -def info(msg): # -> None: - ... - -def trace(msg): # -> None: - ... - -def isEnabledForError(): # -> bool: - ... - -def isEnabledForDebug(): # -> bool: - ... - -def isEnabledForTrace(): # -> Literal[False]: - ... - diff --git a/typings/websocket/_socket.pyi b/typings/websocket/_socket.pyi deleted file mode 100644 index e45acdc98..000000000 --- a/typings/websocket/_socket.pyi +++ /dev/null @@ -1,57 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -import socket -from ._exceptions import * -from ._ssl_compat import * -from ._utils import * - -DEFAULT_SOCKET_OPTION = ... -if hasattr(socket, "SO_KEEPALIVE"): - ... -if hasattr(socket, "TCP_KEEPIDLE"): - ... -if hasattr(socket, "TCP_KEEPINTVL"): - ... -if hasattr(socket, "TCP_KEEPCNT"): - ... -_default_timeout = ... -__all__ = ["DEFAULT_SOCKET_OPTION", "sock_opt", "setdefaulttimeout", "getdefaulttimeout", "recv", "recv_line", "send"] -class sock_opt: - def __init__(self, sockopt, sslopt) -> None: - ... - - - -def setdefaulttimeout(timeout): # -> None: - """ - Set the global timeout setting to connect. - - Parameters - ---------- - timeout: int or float - default socket timeout time (in seconds) - """ - ... - -def getdefaulttimeout(): # -> None: - """ - Get default timeout - - Returns - ---------- - _default_timeout: int or float - Return the global timeout setting (in seconds) to connect. - """ - ... - -def recv(sock, bufsize): - ... - -def recv_line(sock): # -> bytes: - ... - -def send(sock, data): - ... - diff --git a/typings/websocket/_ssl_compat.pyi b/typings/websocket/_ssl_compat.pyi deleted file mode 100644 index cba150293..000000000 --- a/typings/websocket/_ssl_compat.pyi +++ /dev/null @@ -1,23 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -""" -_ssl_compat.py -websocket - WebSocket client library for Python - -Copyright 2022 engn33r - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" -__all__ = ["HAVE_SSL", "ssl", "SSLError", "SSLWantReadError", "SSLWantWriteError"] diff --git a/typings/websocket/_url.pyi b/typings/websocket/_url.pyi deleted file mode 100644 index 0d1bc01e9..000000000 --- a/typings/websocket/_url.pyi +++ /dev/null @@ -1,47 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -__all__ = ["parse_url", "get_proxy_info"] -def parse_url(url): # -> tuple[str, int, str, bool]: - """ - parse url and the result is tuple of - (hostname, port, resource path and the flag of secure mode) - - Parameters - ---------- - url: str - url string. - """ - ... - -DEFAULT_NO_PROXY_HOST = ... -def get_proxy_info(hostname, is_secure, proxy_host=..., proxy_port=..., proxy_auth=..., no_proxy=..., proxy_type=...): # -> tuple[None, Literal[0], None] | tuple[Unknown, int, Unknown | None] | tuple[str | None, int | None, tuple[str, str] | None]: - """ - Try to retrieve proxy host and port from environment - if not provided in options. - Result is (proxy_host, proxy_port, proxy_auth). - proxy_auth is tuple of username and password - of proxy authentication information. - - Parameters - ---------- - hostname: str - Websocket server name. - is_secure: bool - Is the connection secure? (wss) looks for "https_proxy" in env - before falling back to "http_proxy" - proxy_host: str - http proxy host name. - http_proxy_port: str or int - http proxy port. - http_no_proxy: list - 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. - proxy_type: str - Specify the proxy protocol (http, socks4, socks4a, socks5, socks5h). Default is "http". - Use socks4a or socks5h if you want to send DNS requests through the proxy. - """ - ... - diff --git a/typings/websocket/_utils.pyi b/typings/websocket/_utils.pyi deleted file mode 100644 index 619d80a64..000000000 --- a/typings/websocket/_utils.pyi +++ /dev/null @@ -1,46 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -""" -_url.py -websocket - WebSocket client library for Python - -Copyright 2022 engn33r - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" -__all__ = ["NoLock", "validate_utf8", "extract_err_message", "extract_error_code"] -class NoLock: - def __enter__(self): # -> None: - ... - - def __exit__(self, exc_type, exc_value, traceback): # -> None: - ... - - - -def validate_utf8(utfbytes): # -> bool: - """ - validate utf8 byte string. - utfbytes: utf byte string to check. - return value: if valid utf8 string, return true. Otherwise, return false. - """ - ... - -def extract_err_message(exception): # -> None: - ... - -def extract_error_code(exception): # -> None: - ... - diff --git a/typings/websocket/_wsdump.pyi b/typings/websocket/_wsdump.pyi deleted file mode 100644 index a64c1a827..000000000 --- a/typings/websocket/_wsdump.pyi +++ /dev/null @@ -1,68 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - -import argparse -import code - -""" -wsdump.py -websocket - WebSocket client library for Python - -Copyright 2022 engn33r - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -""" -def get_encoding(): # -> Any | str: - ... - -OPCODE_DATA = ... -ENCODING = ... -class VAction(argparse.Action): - def __call__(self, parser, args, values, option_string=...): # -> None: - ... - - - -def parse_args(): # -> Namespace: - ... - -class RawInput: - def raw_input(self, prompt): # -> bytes: - ... - - - -class InteractiveConsole(RawInput, code.InteractiveConsole): - def write(self, data): # -> None: - ... - - def read(self): # -> bytes: - ... - - - -class NonInteractive(RawInput): - def write(self, data): # -> None: - ... - - def read(self): # -> bytes: - ... - - - -def main(): # -> None: - ... - -if __name__ == "__main__": - ... diff --git a/typings/websocket/tests/__init__.pyi b/typings/websocket/tests/__init__.pyi deleted file mode 100644 index 006bc2749..000000000 --- a/typings/websocket/tests/__init__.pyi +++ /dev/null @@ -1,4 +0,0 @@ -""" -This type stub file was generated by pyright. -""" - From 8d6559434763b57a574c252902f681b1668aa7d3 Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Mon, 16 Jan 2023 15:22:45 +0530 Subject: [PATCH 04/17] Pin versions in requirements --- requirements-dev.txt | 4 ++-- requirements.txt | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index a95f1b075..10889327c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,3 +1,3 @@ -PyYAML -pyright==1.1.257 +PyYAML==6.0 +pyright==v1.1.289 typing_extensions==4.2.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 359c38a89..e49490067 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ -PyYAML -websocket-client \ No newline at end of file +PyYAML==6.0 +websockets==10.4 +websocket-client==1.4.2 \ No newline at end of file From f9d907e53a0b28b0730c81292ce67ba63b6d183c Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Mon, 16 Jan 2023 18:07:45 +0530 Subject: [PATCH 05/17] Bump up pyright version --- ops/model.py | 2 +- ops/pebble.py | 4 ++-- ops/storage.py | 12 +++++++----- tox.ini | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ops/model.py b/ops/model.py index 77347ba6a..558b278ec 100644 --- a/ops/model.py +++ b/ops/model.py @@ -2555,7 +2555,7 @@ def _run(self, *args: str, return_output: bool = False, # pyright infers the first match when argument overloading/unpacking is used, # so this needs to be coerced into the right type - result = typing.cast('CompletedProcess[bytes]', result) + result = typing.cast('CompletedProcess[bytes]', result) # type: ignore except CalledProcessError as e: raise ModelError(e.stderr) if return_output: diff --git a/ops/pebble.py b/ops/pebble.py index d0352ddfd..4e497e697 100644 --- a/ops/pebble.py +++ b/ops/pebble.py @@ -2483,8 +2483,8 @@ def __init__( self._max_lookahead = max_lookahead self._max_boundary_length = max_boundary_length - self._buf = bytearray() - self._pos = 0 # current position in buf + self._buf: bytearray = bytearray() + self._pos: int = 0 # current position in buf self._done = False # whether we have found the terminal boundary and are done parsing self._header_terminator = b'\r\n\r\n' diff --git a/ops/storage.py b/ops/storage.py index 50381da4a..fbd99ec3c 100755 --- a/ops/storage.py +++ b/ops/storage.py @@ -299,11 +299,13 @@ def _save_notice_list(self, notices: '_Notices') -> None: # we load yaml.CSafeX if available, falling back to slower yaml.SafeX. -_BaseDumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) # type: Type[yaml.SafeDumper] -_BaseLoader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) # type: Type[yaml.SafeLoader] +_dtype = Union[Type[yaml.SafeDumper], Type[yaml.cyaml.CSafeDumper]] +_ltype = Union[Type[yaml.SafeLoader], Type[yaml.cyaml.CSafeLoader]] +_BaseDumper: _dtype = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) +_BaseLoader: _ltype = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) -class _SimpleLoader(_BaseLoader): +class _SimpleLoader(_BaseLoader): # type: ignore """Handle a couple basic python types. yaml.SafeLoader can handle all the basic int/float/dict/set/etc that we want. The only one @@ -321,7 +323,7 @@ class _SimpleLoader(_BaseLoader): _SimpleLoader.construct_python_tuple) # type: ignore -class _SimpleDumper(_BaseDumper): +class _SimpleDumper(_BaseDumper): # type: ignore """Add types supported by 'marshal'. YAML can support arbitrary types, but that is generally considered unsafe (like pickle). So @@ -330,7 +332,7 @@ class _SimpleDumper(_BaseDumper): represent_tuple = yaml.Dumper.represent_tuple # type: _TupleRepresenterType -_SimpleDumper.add_representer(tuple, _SimpleDumper.represent_tuple) +_SimpleDumper.add_representer(tuple, _SimpleDumper.represent_tuple) # type: ignore def juju_backend_available() -> bool: diff --git a/tox.ini b/tox.ini index 542a24ad7..54d51d4b1 100644 --- a/tox.ini +++ b/tox.ini @@ -57,7 +57,7 @@ commands = [testenv:static] description = Run static type checker deps = - pyright==1.1.264 + pyright==1.1.289 -r{toxinidir}/requirements.txt commands = pyright {posargs} From 0f31a6b0c95fdfc21f3802266e9fb23e81bdd03d Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Tue, 17 Jan 2023 10:41:26 +0530 Subject: [PATCH 06/17] Drop unnecessary casts --- ops/model.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ops/model.py b/ops/model.py index 558b278ec..54fca6667 100644 --- a/ops/model.py +++ b/ops/model.py @@ -56,8 +56,6 @@ from ops.jujuversion import JujuVersion if typing.TYPE_CHECKING: - from subprocess import CompletedProcess # noqa - from pebble import ( # pyright: reportMissingTypeStubs=false CheckInfo, CheckLevel, @@ -2552,17 +2550,13 @@ def _run(self, *args: str, return_output: bool = False, args += ('--format=json',) try: result = run(args, **kwargs) - - # pyright infers the first match when argument overloading/unpacking is used, - # so this needs to be coerced into the right type - result = typing.cast('CompletedProcess[bytes]', result) # type: ignore except CalledProcessError as e: raise ModelError(e.stderr) if return_output: if result.stdout is None: return '' else: - text = typing.cast(str, result.stdout) + text = result.stdout if use_json: return json.loads(text) else: From c01bbce81c7901c0b53648af631eb542b108bf76 Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Tue, 17 Jan 2023 13:17:00 +0530 Subject: [PATCH 07/17] Do away inline requirements Requirements are defined at one place('requirements*.txt' files) and are read or linked from there. --- requirements-dev.txt | 11 ++++++++--- requirements.txt | 1 - setup.py | 17 +++++++++++------ tox.ini | 16 ++++------------ 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 10889327c..65e5a1ad1 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,3 +1,8 @@ -PyYAML==6.0 -pyright==v1.1.289 -typing_extensions==4.2.0 \ No newline at end of file +ipdb==0.13.11 +logassert==7 +pyright==1.1.289 +pytest==7.2.1 +pytest-operator==0.23.0 +typing_extensions==4.2.0 + +-r requirements.txt \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e49490067..5f38c74e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,2 @@ PyYAML==6.0 -websockets==10.4 websocket-client==1.4.2 \ No newline at end of file diff --git a/setup.py b/setup.py index d0e75dc66..00f910de5 100644 --- a/setup.py +++ b/setup.py @@ -14,9 +14,11 @@ """Setup script for the Operator Framework.""" -from importlib.util import spec_from_file_location, module_from_spec +from importlib.util import module_from_spec, spec_from_file_location from pathlib import Path -from setuptools import setup, find_packages +from typing import List + +from setuptools import find_packages, setup def _read_me() -> str: @@ -26,6 +28,12 @@ def _read_me() -> str: return readme +def _requirements() -> List[str]: + file = Path((__file__)).parent.joinpath('requirements.txt') + with open(file, 'r') as fh: + return fh.readlines() + + def _get_version() -> str: """Get the version via ops/version.py, without loading ops/__init__.py.""" spec = spec_from_file_location('ops.version', 'ops/version.py') @@ -72,10 +80,7 @@ def _get_version() -> str: "Operating System :: POSIX :: Linux", ], python_requires='>=3.8', - install_requires=[ - 'PyYAML', - 'websocket-client', - ], + install_requires=_requirements(), package_data={'ops': ['py.typed']}, ) diff --git a/tox.ini b/tox.ini index 54d51d4b1..118b6b6fc 100644 --- a/tox.ini +++ b/tox.ini @@ -57,8 +57,7 @@ commands = [testenv:static] description = Run static type checker deps = - pyright==1.1.289 - -r{toxinidir}/requirements.txt + -r{toxinidir}/requirements-dev.txt commands = pyright {posargs} @@ -68,12 +67,9 @@ passenv = RUN_REAL_PEBBLE_TESTS PEBBLE deps = - pytest - ipdb ipython!=8.1.0 # this version is broken and was causing failures - logassert coverage[toml] - -r{toxinidir}/requirements.txt + -r{toxinidir}/requirements-dev.txt commands = coverage run --source={[vars]src_path} \ -m pytest --ignore={[vars]tst_path}smoke -v --tb native {posargs} @@ -88,10 +84,7 @@ setenv = PEBBLE=/tmp/pebble RUN_REAL_PEBBLE_TESTS=1 deps = - pytest - pytest-operator - logassert - -r{toxinidir}/requirements.txt + -r{toxinidir}/requirements-dev.txt commands = bash -c "umask 0; (pebble run --http=':4000' --create-dirs &>/dev/null & ) ; sleep 1; pytest -v --tb native -k RealPebble {posargs} ; killall -y 3m pebble" @@ -101,8 +94,7 @@ whitelist_externals = juju charmcraft bash deps = - pytest - pytest-operator + -r{toxinidir}/requirements-dev.txt commands = # Build a source tarball for ops, and drop it into the root directory of the smoke test charm. bash -c 'rm -vf ./test/charms/test_smoke/*.tar.gz # Cleanup old builds' From 93d9e091bc96755c2f8191efc3a787991eecc67b Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Tue, 17 Jan 2023 13:22:19 +0530 Subject: [PATCH 08/17] Fix static checks --- ops/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ops/model.py b/ops/model.py index 54fca6667..cc756543a 100644 --- a/ops/model.py +++ b/ops/model.py @@ -2556,7 +2556,7 @@ def _run(self, *args: str, return_output: bool = False, if result.stdout is None: return '' else: - text = result.stdout + text = typing.cast(str, result.stdout) # type: ignore if use_json: return json.loads(text) else: From 3026fcb4d7f4feb0318490c43d5ac6385538d9f3 Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Tue, 17 Jan 2023 14:17:07 +0530 Subject: [PATCH 09/17] Remove redundant type vars --- ops/storage.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ops/storage.py b/ops/storage.py index fbd99ec3c..18c3fd406 100755 --- a/ops/storage.py +++ b/ops/storage.py @@ -22,7 +22,7 @@ import typing from datetime import timedelta from pathlib import Path -from typing import Any, Callable, Generator, List, Optional, Tuple, Type, Union +from typing import Any, Callable, Generator, List, Optional, Tuple, Union import yaml # pyright: reportMissingModuleSource=false @@ -299,10 +299,8 @@ def _save_notice_list(self, notices: '_Notices') -> None: # we load yaml.CSafeX if available, falling back to slower yaml.SafeX. -_dtype = Union[Type[yaml.SafeDumper], Type[yaml.cyaml.CSafeDumper]] -_ltype = Union[Type[yaml.SafeLoader], Type[yaml.cyaml.CSafeLoader]] -_BaseDumper: _dtype = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) -_BaseLoader: _ltype = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) +_BaseDumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper) +_BaseLoader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader) class _SimpleLoader(_BaseLoader): # type: ignore From 486837606ff4d2f37d8b50d4006a9aaeded836f5 Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Wed, 18 Jan 2023 09:16:47 +0530 Subject: [PATCH 10/17] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f71fef701..7228533ac 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ is to feel natural for somebody used to coding in Python, and reasonably easy to who is not a pythonista. The dependencies of the operator framework are kept as minimal as possible; currently that's Python -3.8 or greater, and `PyYAML` (both are included by default in Ubuntu's cloud images from 20.04 on). +3.8 or greater, and a couple of python libraries outlined in [requirements.txt](requirements.txt). For a brief intro on how to get started, check out the [Hello, World!](https://juju.is/docs/sdk/hello-world) section of the documentation! From 89f53d4a30dce97205008297b5ec35ee26a5ed1d Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Wed, 18 Jan 2023 18:47:22 +0530 Subject: [PATCH 11/17] README nitpick --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7228533ac..21d81bff5 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ is to feel natural for somebody used to coding in Python, and reasonably easy to who is not a pythonista. The dependencies of the operator framework are kept as minimal as possible; currently that's Python -3.8 or greater, and a couple of python libraries outlined in [requirements.txt](requirements.txt). +3.8 or greater, and the small of Python libraries referenced in [requirements.txt](requirements.txt). For a brief intro on how to get started, check out the [Hello, World!](https://juju.is/docs/sdk/hello-world) section of the documentation! From ce94d7e91567fa15d42460231a92e78c9eddab39 Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Wed, 18 Jan 2023 18:48:14 +0530 Subject: [PATCH 12/17] Pin requirements to major only versions Also removes all hardcoded requirements from the tox script. --- requirements-dev.txt | 13 ++++++++++--- requirements.txt | 4 ++-- tox.ini | 13 ++----------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 65e5a1ad1..ee1623e66 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,8 +1,15 @@ -ipdb==0.13.11 +isort==5.11.4 logassert==7 -pyright==1.1.289 +autopep8==1.6.0 +flake8==4.0.1 +flake8-docstrings==1.6.0 +flake8-builtins==2.1.0 +pyproject-flake8==4.0.1 +pep8-naming==0.13.2 pytest==7.2.1 +pyright==1.1.289 pytest-operator==0.23.0 +coverage[toml]==7.0.5 typing_extensions==4.2.0 --r requirements.txt \ No newline at end of file +-r requirements.txt diff --git a/requirements.txt b/requirements.txt index 5f38c74e5..afd5bc095 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -PyYAML==6.0 -websocket-client==1.4.2 \ No newline at end of file +PyYAML==6.* +websocket-client==1.* \ No newline at end of file diff --git a/tox.ini b/tox.ini index 118b6b6fc..ac03e1784 100644 --- a/tox.ini +++ b/tox.ini @@ -32,8 +32,7 @@ commands = [testenv:fmt] description = Apply coding style standards to code deps = - isort - autopep8 + -r{toxinidir}/requirements-dev.txt commands = isort {[vars]all_path} autopep8 --in-place {[vars]all_path} @@ -41,13 +40,7 @@ commands = [testenv:lint] description = Check code against coding style standards deps = - autopep8 - isort - flake8==4.0.1 - flake8-docstrings - flake8-builtins - pyproject-flake8 - pep8-naming + -r{toxinidir}/requirements-dev.txt commands = # pflake8 wrapper suppports config from pyproject.toml pflake8 {[vars]all_path} @@ -67,8 +60,6 @@ passenv = RUN_REAL_PEBBLE_TESTS PEBBLE deps = - ipython!=8.1.0 # this version is broken and was causing failures - coverage[toml] -r{toxinidir}/requirements-dev.txt commands = coverage run --source={[vars]src_path} \ From 404281b3a3b8531c589f7faae42b9d40f92cfd29 Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Thu, 19 Jan 2023 01:52:15 +0530 Subject: [PATCH 13/17] Follow up reviews --- README.md | 2 +- setup.py | 16 +++++++++++++--- tox.ini | 1 - 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 21d81bff5..4ac030e47 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ is to feel natural for somebody used to coding in Python, and reasonably easy to who is not a pythonista. The dependencies of the operator framework are kept as minimal as possible; currently that's Python -3.8 or greater, and the small of Python libraries referenced in [requirements.txt](requirements.txt). +3.8 or greater, and the small number of Python libraries referenced in [requirements.txt](requirements.txt). For a brief intro on how to get started, check out the [Hello, World!](https://juju.is/docs/sdk/hello-world) section of the documentation! diff --git a/setup.py b/setup.py index 00f910de5..2637c8b41 100644 --- a/setup.py +++ b/setup.py @@ -29,9 +29,19 @@ def _read_me() -> str: def _requirements() -> List[str]: - file = Path((__file__)).parent.joinpath('requirements.txt') - with open(file, 'r') as fh: - return fh.readlines() + """Return the required packages to run the project.""" + reqs = [] + with open(Path(__file__).parent / 'requirements.txt', encoding='utf-8') as fh: + for line in fh.readlines(): + # Handle blank lines and comments in requirements.txt files + # TODO(tinvaan): DRY, consider setuptools offering for requirements parsing + # https://setuptools.pypa.io/en/latest/pkg_resources.html#requirements-parsing + line = line.strip() + if line and not line.startswith("#"): + req = [val for val in line.split(' ') if '==' in val] + if len(req) > 0: + reqs.append(req[0]) + return reqs def _get_version() -> str: diff --git a/tox.ini b/tox.ini index ac03e1784..e552dd630 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,6 @@ all_path = {[vars]src_path} {[vars]tst_path} basepython = python3 setenv = PYTHONPATH = {toxinidir}:{toxinidir}/lib:{[vars]src_path} - PYTHONBREAKPOINT=ipdb.set_trace PY_COLORS=1 passenv = PYTHONPATH From 6627ce7065a207a531b4d6a20b5590e0fe625589 Mon Sep 17 00:00:00 2001 From: Harish Navnit Date: Thu, 19 Jan 2023 08:37:26 +0530 Subject: [PATCH 14/17] Simplify requirements parsing for now --- setup.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 2637c8b41..7efdfc54c 100644 --- a/setup.py +++ b/setup.py @@ -33,14 +33,11 @@ def _requirements() -> List[str]: reqs = [] with open(Path(__file__).parent / 'requirements.txt', encoding='utf-8') as fh: for line in fh.readlines(): - # Handle blank lines and comments in requirements.txt files # TODO(tinvaan): DRY, consider setuptools offering for requirements parsing # https://setuptools.pypa.io/en/latest/pkg_resources.html#requirements-parsing line = line.strip() if line and not line.startswith("#"): - req = [val for val in line.split(' ') if '==' in val] - if len(req) > 0: - reqs.append(req[0]) + reqs.append(line) return reqs From db814ba020ee5e7a091fdeee93547460dff55ffa Mon Sep 17 00:00:00 2001 From: Ben Hoyt Date: Tue, 24 Jan 2023 15:41:30 +1300 Subject: [PATCH 15/17] Remove a couple of unnecessary typing.cast() and "type: ignore"s --- ops/model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ops/model.py b/ops/model.py index cc756543a..2622cf610 100644 --- a/ops/model.py +++ b/ops/model.py @@ -2160,7 +2160,7 @@ def _build_fileinfo(path: StrOrPath) -> 'FileInfo': name=path.name, type=ftype, size=info.st_size, - permissions=typing.cast(int, stat.S_IMODE(info.st_mode)), # type: ignore + permissions=stat.S_IMODE(info.st_mode), last_modified=datetime.datetime.fromtimestamp(info.st_mtime), user_id=info.st_uid, user=pwd.getpwuid(info.st_uid).pw_name, @@ -2556,7 +2556,7 @@ def _run(self, *args: str, return_output: bool = False, if result.stdout is None: return '' else: - text = typing.cast(str, result.stdout) # type: ignore + text = typing.cast(str, result.stdout) if use_json: return json.loads(text) else: From c81768f58556128667298dca9f379460a962250b Mon Sep 17 00:00:00 2001 From: Ben Hoyt Date: Wed, 25 Jan 2023 14:12:03 +1300 Subject: [PATCH 16/17] Simplify private yaml.safe_dump type annotations and fix Pyright errors --- ops/_private/yaml.py | 18 ++++-------------- test/test_private.py | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/ops/_private/yaml.py b/ops/_private/yaml.py index 94c1fd7b4..78b28533f 100644 --- a/ops/_private/yaml.py +++ b/ops/_private/yaml.py @@ -14,7 +14,7 @@ """Internal YAML helpers.""" -from typing import Any, Optional, TextIO, Union, overload +from typing import Any, Optional, TextIO, Union import yaml @@ -28,16 +28,6 @@ def safe_load(stream: Union[str, TextIO]) -> Any: return yaml.load(stream, Loader=_safe_loader) # type: ignore -@overload -def safe_dump(data: Any, *args: Any, encoding: None = None, **kwargs: Any) -> str: ... # noqa -@overload -def safe_dump(data: Any, *args: Any, encoding: str = "", **kwargs: Any) -> bytes: ... # noqa - - -def safe_dump(data: Any, stream: Optional[Union[str, TextIO]] = None, **kwargs: Any # noqa - ) -> Union[str, bytes]: - """Same as yaml.safe_dump, but use fast C dumper if available. - - If `encoding:str` is provided, return bytes. Else, return str. - """ - return yaml.dump(data, stream=stream, Dumper=_safe_dumper, **kwargs) # type: ignore +def safe_dump(data: Any, stream: Optional[TextIO] = None) -> str: + """Same as yaml.safe_dump, but use fast C dumper if available.""" + return yaml.dump(data, stream=stream, Dumper=_safe_dumper) # type: ignore diff --git a/test/test_private.py b/test/test_private.py index 8346be158..e74507800 100644 --- a/test/test_private.py +++ b/test/test_private.py @@ -41,7 +41,7 @@ def test_safe_dump(self): self.assertEqual(s, 'baz: 123\nfoo: bar\n') f = io.StringIO() - s = yaml.safe_dump({'foo': 'bar', 'baz': 123}, stream=f) + yaml.safe_dump({'foo': 'bar', 'baz': 123}, stream=f) self.assertEqual(f.getvalue(), 'baz: 123\nfoo: bar\n') # Should error -- it's not safe to dump an instance of a user-defined class From b5a274da4432f0a8f6b26409126ed2c31e3bd7d9 Mon Sep 17 00:00:00 2001 From: Ben Hoyt Date: Thu, 26 Jan 2023 11:44:59 +1300 Subject: [PATCH 17/17] Upgrade to latest Pyright (1.1.291) to fix bytearray/Unknown issue I guess this shows why we pin dev dependencies! This was seemingly fixed in 1.1.290, likely this fix to do with caching of Unknown types: https://github.com/microsoft/pyright/commit/bd010d11926856025835c3bf75d0351094417e9f Prior to this Pyright fix, the following cut-down snippet showed the buf: ----- import typing class Foo: def __init__(self): self._buf = bytearray() self._done = False def bar(self, data: bytes): self._buf.extend(data) while True: i, self._done = thing() if i == -1 or self._done: return self._buf = self._buf[1:] def thing() -> typing.Tuple[int, bool]: return 0, False ----- --- ops/pebble.py | 4 ++-- requirements-dev.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ops/pebble.py b/ops/pebble.py index a0d23b355..c129f8b0c 100644 --- a/ops/pebble.py +++ b/ops/pebble.py @@ -2483,8 +2483,8 @@ def __init__( self._max_lookahead = max_lookahead self._max_boundary_length = max_boundary_length - self._buf: bytearray = bytearray() - self._pos: int = 0 # current position in buf + self._buf = bytearray() + self._pos = 0 # current position in buf self._done = False # whether we have found the terminal boundary and are done parsing self._header_terminator = b'\r\n\r\n' diff --git a/requirements-dev.txt b/requirements-dev.txt index ee1623e66..18abf8073 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ flake8-builtins==2.1.0 pyproject-flake8==4.0.1 pep8-naming==0.13.2 pytest==7.2.1 -pyright==1.1.289 +pyright==1.1.291 pytest-operator==0.23.0 coverage[toml]==7.0.5 typing_extensions==4.2.0