diff --git a/pyproject.toml b/pyproject.toml index e3fc83b..772b788 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,6 +45,9 @@ dependencies = [ "caterpillar-py", # binary protocols "bitarray", # asn1c-python extensions "typing-extensions", # compatibility with 3.10 + # --- protocol family integrations (see TOOLS.md) + "pymodbus>=3.8.6", # Modbus (TCP/RTU) client support (device_id= API) + "asyncua>=1.1", # OPC-UA client support # --- dependencies for examples "rich", # colored terminal output and logging "cmd2", # advanced command shells (cmd 2.0) @@ -70,6 +73,11 @@ sdist.include = ["src/icspacket/_version.py"] [tool.setuptools_scm] write_to = "src/icspacket/_version.py" +[dependency-groups] +dev = [ + "pytest>=9.1.1", +] + # --- example scripts [project.scripts] "mms_utility.py" = "icspacket.examples.mms_utility:cli_main" @@ -79,4 +87,7 @@ write_to = "src/icspacket/_version.py" "dnp3dump.py" = "icspacket.examples.dnp3dump:cli_main" "dnp3read.py" = "icspacket.examples.dnp3read:cli_main" "dnp3linkaddr.py" = "icspacket.examples.dnp3linkaddr:cli_main" -"gooseobserv.py" = "icspacket.examples.gooseobserv:cli_main" \ No newline at end of file +"gooseobserv.py" = "icspacket.examples.gooseobserv:cli_main" +"modbusclient.py" = "icspacket.examples.modbusclient:cli_main" +"cipclient.py" = "icspacket.examples.cipclient:cli_main" +"opcuaclient.py" = "icspacket.examples.opcuaclient:cli_main" diff --git a/src/icspacket/proto/cotp/connection.py b/src/icspacket/proto/cotp/connection.py index ea7c3fd..6db11dc 100644 --- a/src/icspacket/proto/cotp/connection.py +++ b/src/icspacket/proto/cotp/connection.py @@ -39,12 +39,55 @@ ) from icspacket.proto.tpkt import tpktsock -COTP_DEFAULT_SRC_REF = 0 +COTP_DEFAULT_SRC_REF = 1 """Default source reference identifier for COTP connections.""" logger = logging.getLogger(__name__) +_CLASS0_MAX_TPDU_SIZE = 2048 +_CLASS0_ALLOWED_CR_CC_PARAMS = { + Parameter_Code.CALLING_T_SELECTOR, + Parameter_Code.CALLED_T_SELECTOR, + Parameter_Code.TPDU_SIZE, + Parameter_Code.MAX_TPDU_SIZE, +} + + +def _tpdu_size_to_octets(size: TPDU_Size) -> int: + return 1 << size.value + + +def _parameter_values(parameters: Iterable[Parameter]) -> dict[Parameter_Code, object]: + values: dict[Parameter_Code, object] = {} + for parameter in parameters: + values[parameter.type_id] = parameter.value + return values + + +def _decode_tpdu_size(value: object) -> int: + if isinstance(value, TPDU_Size): + return 1 << value.value + + try: + return 1 << TPDU_Size(value).value + except ValueError as e: + raise ConnectionError(f"Invalid TPDU size parameter: {value!r}") from e + + +def _decode_preferred_tpdu_size(value: object) -> int: + if isinstance(value, int): + multiplier = value + elif isinstance(value, bytes): + multiplier = int.from_bytes(value, "big") + else: + raise ConnectionError(f"Invalid preferred TPDU size parameter: {value!r}") + + if multiplier < 1: + raise ConnectionError("Preferred TPDU size parameter must be >= 1") + return multiplier * 128 + + class COTP_Connection(connection): """ Manages a COTP (Connection-Oriented Transport Protocol) connection over a TCP/IP socket. @@ -93,23 +136,28 @@ def __init__( timeout: float | None = None, ) -> None: super().__init__() - self.sock = sock - if self.sock is None: + selected_src_ref = src_ref if src_ref is not None else COTP_DEFAULT_SRC_REF + if selected_src_ref <= 0 or selected_src_ref > 0xFFFF: + raise ValueError("COTP source reference must be in range 1..65535") + + if sock is None: if sock_cls is None: raise ValueError("Must specify either sock or sock_cls!") - self.sock = sock_cls(socket.AF_INET, socket.SOCK_STREAM) + sock = sock_cls(socket.AF_INET, socket.SOCK_STREAM) + self.sock: socket.socket = sock # private members - self.__src_ref = src_ref if src_ref is not None else COTP_DEFAULT_SRC_REF + self.__src_ref = selected_src_ref self.__dst_ref = 0 self.__class = protocol_class - self.__tpdu_size = max_tpdu_size + self.__requested_tpdu_size = max_tpdu_size + self.__tpdu_size = _tpdu_size_to_octets(max_tpdu_size) # public (modifiable) members - self.src_tsap = bytes.fromhex(src_tsap) - self.dst_tsap = bytes.fromhex(dst_tsap) - self.conn_params = list(parameters or []) + self.src_tsap: bytes = bytes.fromhex(src_tsap) + self.dst_tsap: bytes = bytes.fromhex(dst_tsap) + self.conn_params: list[Parameter] = list(parameters or []) if timeout: self.sock.settimeout(timeout) @@ -133,9 +181,9 @@ def connect(self, address: tuple[str, int]) -> None: cr_tpdu.dst_ref = 0 cr_tpdu.parameters.extend(list(self.conn_params)) cr_tpdu.parameters += [ - Parameter(Parameter_Code.TPDU_SIZE, self.__tpdu_size), - Parameter(Parameter_Code.CALLING_T_SELECTOR, self.dst_tsap), - Parameter(Parameter_Code.CALLED_T_SELECTOR, self.src_tsap), + Parameter(Parameter_Code.TPDU_SIZE, self.__requested_tpdu_size), + Parameter(Parameter_Code.CALLING_T_SELECTOR, self.src_tsap), + Parameter(Parameter_Code.CALLED_T_SELECTOR, self.dst_tsap), ] self.connect_raw(address, cr_tpdu) @@ -165,26 +213,22 @@ def connect_raw( self.send_tpdu(tpdu_cr) tpdu = self.receive_tpdu() - self._propagate_errors(tpdu) if isinstance(tpdu, TPDU_DisconnectRequest): reason = tpdu.reason info = tpdu.user_data if tpdu.user_data else "" + self._close_transport() raise ConnectionRefusedError( f"Remote refused connection with reason {reason!r}: {info}" ) + self._propagate_errors(tpdu) if not isinstance(tpdu, TPDU_ConnectionConfirm): + self._close_transport() raise ConnectionError( f"Expected COTP Connection Response, got TPDU with code={tpdu.tpdu_code}" ) - if self.protocol_class == TPDU_Class.CLASS4: - if not tpdu.is_valid(): - raise ConnectionError( - f"Received invalid COTP Connection Response (invalid checksum): {tpdu}" - ) - - self.__dst_ref = tpdu.src_ref + self._apply_connection_confirm(tpdu, tpdu_cr) self._valid = True @override @@ -192,6 +236,10 @@ def close(self) -> None: """ Close the connection gracefully with a normal disconnect reason. """ + if self.protocol_class == TPDU_Class.CLASS0: + self._close_transport() + return + self.close_with_reason() def close_with_reason( @@ -204,6 +252,13 @@ def close_with_reason( :param reason: Disconnect reason code (default: NORMAL). :type reason: TPDU_DisconnectReason """ + if ( + self.protocol_class == TPDU_Class.CLASS0 + and reason == TPDU_DisconnectReason.NORMAL + ): + self._close_transport() + return + dr_tdpu = TPDU_DisconnectRequest() dr_tdpu.src_ref = self.__src_ref dr_tdpu.dst_ref = self.__dst_ref @@ -221,13 +276,73 @@ def close_raw(self, dr_tdpu: TPDU_DisconnectRequest) -> None: return self.send_tpdu(dr_tdpu) + self._close_transport() + + def _close_transport(self) -> None: + """Close the underlying network connection and clear COTP state.""" try: self.sock.close() - except BrokenPipeError: + except (BrokenPipeError, OSError): pass self._connected = False self._valid = False + def _apply_connection_confirm( + self, + tpdu_cc: TPDU_ConnectionConfirm, + tpdu_cr: TPDU_ConnectionRequest, + ) -> None: + if tpdu_cc.dst_ref != self.__src_ref: + self._close_transport() + raise ConnectionError( + "Received invalid CC TPDU destination reference: " + + f"{tpdu_cc.dst_ref}, expected {self.__src_ref}" + ) + + cc_parameters = _parameter_values(tpdu_cc.parameters) + cr_parameters = _parameter_values(tpdu_cr.parameters) + self.__tpdu_size = self._negotiate_tpdu_size(cc_parameters, cr_parameters) + self.__dst_ref = tpdu_cc.src_ref + self.__class = TPDU_Class.CLASS0 + + def _negotiate_tpdu_size( + self, + cc_parameters: dict[Parameter_Code, object], + cr_parameters: dict[Parameter_Code, object], + ) -> int: + if Parameter_Code.MAX_TPDU_SIZE in cc_parameters: + selected_size = _decode_preferred_tpdu_size( + cc_parameters[Parameter_Code.MAX_TPDU_SIZE] + ) + requested_size = _decode_preferred_tpdu_size( + cr_parameters[Parameter_Code.MAX_TPDU_SIZE] + ) + elif Parameter_Code.TPDU_SIZE in cc_parameters: + selected_size = _decode_tpdu_size(cc_parameters[Parameter_Code.TPDU_SIZE]) + requested_size = ( + _decode_tpdu_size(cr_parameters[Parameter_Code.TPDU_SIZE]) + if Parameter_Code.TPDU_SIZE in cr_parameters + else 128 + ) + else: + selected_size = 128 + requested_size = ( + _decode_tpdu_size(cr_parameters[Parameter_Code.TPDU_SIZE]) + if Parameter_Code.TPDU_SIZE in cr_parameters + else 128 + ) + + if selected_size > requested_size: + self._close_transport() + raise ConnectionError( + f"CC TPDU selected TPDU size {selected_size} above requested " + + f"{requested_size}" + ) + if selected_size > _CLASS0_MAX_TPDU_SIZE: + self._close_transport() + raise ConnectionError("Class 0 selected TPDU size cannot exceed 2048 octets") + return selected_size + def _propagate_errors(self, tpdu: TPDU) -> None: """ Raise exceptions if a TPDU error message is received. @@ -238,6 +353,7 @@ def _propagate_errors(self, tpdu: TPDU) -> None: :raises ConnectionError: If the TPDU is an Error TPDU. """ if isinstance(tpdu, TPDU_Error): + self._close_transport() raise ConnectionError(f"Received COTP error: {tpdu.reject_cause}") def send_tpdu(self, tpdu: _TPDULike) -> None: @@ -276,15 +392,21 @@ def receive_tpdu(self): raise ConnectionError("Connection not established") # add size of TPKT header here - size = 2**self.__tpdu_size.value + size = self.__tpdu_size if isinstance(self.sock, tpktsock): size += 4 data = self.sock.recv(size) if not data: + self._connected = False + self._valid = False raise ConnectionClosedError("Connection closed") - tpdu = parse_tpdu(data) + try: + tpdu = parse_tpdu(data) + except ValueError as e: + self._close_transport() + raise ConnectionError("Received invalid COTP TPDU") from e logger.log( TRACE, "Received (%s) TPDU with %d bytes", @@ -309,14 +431,16 @@ def send_data(self, data: bytes) -> None: tpdu_nr = 0 data_len = len(data) # We have to subtract the fixed TPDU size here - max_tpdu_size = 2**self.__tpdu_size.value - 3 + max_tpdu_size = self.__tpdu_size - 3 while offset < data_len: chunk = data[offset : min(data_len, offset + max_tpdu_size)] offset += len(chunk) dt_tpdu = TPDU_Data() dt_tpdu.nr.eot = offset >= data_len - dt_tpdu.nr.value = tpdu_nr + dt_tpdu.nr.value = ( + 0 if self.protocol_class == TPDU_Class.CLASS0 else tpdu_nr + ) dt_tpdu.user_data = chunk self.send_tpdu(dt_tpdu) tpdu_nr = (tpdu_nr + 1) % 0x7F @@ -334,14 +458,24 @@ def recv_data(self) -> bytes: if not self._valid: raise ConnectionError("Connection not established") - parts = [] + parts: list[bytes] = [] while True: tpdu = self.receive_tpdu() self._propagate_errors(tpdu) + if isinstance(tpdu, TPDU_DisconnectRequest): + reason = tpdu.reason + self._close_transport() + raise ConnectionClosedError( + f"Remote disconnected COTP connection: {reason!r}" + ) if not isinstance(tpdu, TPDU_Data): raise ConnectionError( f"Expected DT TPDU, got TPDU with code={tpdu.tpdu_code}" ) + if self.protocol_class == TPDU_Class.CLASS0: + if tpdu.code_arg != 0 or tpdu.tpdu_nr != 0: + self._close_transport() + raise ConnectionError("Received invalid class 0 DT TPDU") parts.append(tpdu.user_data) if tpdu.is_last: diff --git a/src/icspacket/proto/cotp/structs.py b/src/icspacket/proto/cotp/structs.py index 5300457..5a3f55f 100644 --- a/src/icspacket/proto/cotp/structs.py +++ b/src/icspacket/proto/cotp/structs.py @@ -13,20 +13,24 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# pyright: reportInvalidTypeForm=false, reportGeneralTypeIssues=false, reportAssignmentType=false +# 1pyright: reportInvalidTypeForm=false, reportGeneralTypeIssues=false, reportAssignmentType=false # [ITU X.224] - Open Systems Interconnection – Connection-mode protocol # specifications -from collections.abc import Iterable +from typing_extensions import overload import enum +from typing import Any +from collections.abc import Iterable + from caterpillar.context import CTX_OBJECT -from caterpillar.model import bitfield, EnumFactory, struct +from caterpillar.model import Invisible, bitfield, EnumFactory, struct from caterpillar.options import S_ADD_BYTES +from caterpillar.py import StructDefMixin from caterpillar.shared import Action -from caterpillar.shortcuts import F, BigEndian, opt, pack, this, unpack +from caterpillar.shortcuts import F, BigEndian, opt, pack, this, unpack, f from caterpillar.fields import ( DEFAULT_OPTION, Bytes, @@ -37,6 +41,8 @@ uint16, ENUM_STRICT, ) +from caterpillar.types import int1_t, uint8_t, uint16_t, uint32_t +from caterpillar.abc import _ContextLike def checksum(tpdu_data: Iterable[int], checksum_off: int): @@ -110,7 +116,7 @@ class TPDU_Code(enum.IntEnum): ED = 0x01 # Expected Data EA = 0x02 # Expedited data acknowledgement - RJ = 0x03 # Reject + RJ = 0x05 # Reject AK = 0x06 # Data acknowledgement ER = 0x07 # Error DR = 0x08 # Disconnect request @@ -250,29 +256,29 @@ class TPDU_AdditionalOptions: class)""" # fmt: off - unused : 1 = False - non_blocking : 1 = False + unused : f[bool, 1] = False + non_blocking : f[bool, 1] = False """Use of non-blocking expedited data in class 4""" - use_request_ack : 1 = False + use_request_ack : f[bool, 1] = False """Use of request acknowledgement in class 1, 3, 4""" - use_selective_ack : 1 = False + use_selective_ack : f[bool, 1] = False """Use of selective acknowledgement in class 4""" - speed_up : 1 = False + speed_up : f[bool, 1] = False """Use of network expedited in class 1""" - use_receipt_info : 1 = False + use_receipt_info : f[bool, 1] = False """ - True: Use of receipt confirmation in class 1 - False: Use of explicit AK variant in class 1 """ - use_checksum_16bit : 1 = False + use_checksum_16bit : f[bool, 1] = False """16-bit checksum defined in 6.17 shall be used in class 4""" - use_transport_speed_up : 1 = True + use_transport_speed_up : f[bool, 1] = True """Use of transport expedited data transfer service""" # fmt: on @@ -282,16 +288,16 @@ class TPDU_TransitDelay: """Transit delay (not used if class 0 is the preferred class)""" # fmt: off - calling_target_value : uint16 = 0 + calling_target_value : uint16_t = 0 """target value, calling-called user direction;""" - calling_maximum_acceptable : uint16 = 0 + calling_maximum_acceptable : uint16_t = 0 """maximum acceptable, calling-called user direction;""" - called_target_value : uint16 = 0 + called_target_value : uint16_t = 0 """target value, called-calling user direction;""" - called_maximum_acceptable : uint16 = 0 + called_maximum_acceptable : uint16_t = 0 """maximum acceptable, called-calling user direction;""" # fmt: on @@ -301,13 +307,13 @@ class TPDU_ResidualErrorRate: """Residual error rate (not used if class 0 is the preferred class)""" # fmt: off - target_value : uint8 = 0 + target_value : uint8_t = 0 """target value, power of 10;""" - minimum_acceptable : uint8 = 0 + minimum_acceptable : uint8_t = 0 """minimum acceptable, power of 10;""" - tsdu_size_of_interest : uint8 = 0 + tsdu_size_of_interest : uint8_t = 0 """TSDU size of interest, expressed as a power of 2.""" # fmt: on @@ -321,8 +327,8 @@ class Parameter_Code(enum.IntEnum): __struct__ = uint8 # fmt: off - CALLED_T_SELECTOR = 0b11000001 # Transport-Selector (T-selector) called or Invalid TPDU - CALLING_T_SELECTOR = 0b11000010 # Transport-Selector (T-selector) calling + CALLING_T_SELECTOR = 0b11000001 # Transport-Selector (T-selector) calling + CALLED_T_SELECTOR = 0b11000010 # Transport-Selector (T-selector) called/responding or Invalid TPDU TPDU_SIZE = 0b11000000 # TPDU size MAX_TPDU_SIZE = 0b11110000 # Preferred maximum TPDU size VERSION = 0b11000100 # Version number @@ -369,7 +375,7 @@ class Parameter_Code(enum.IntEnum): @struct(options=[S_ADD_BYTES]) -class Parameter: +class Parameter(StructDefMixin): """13.2.3 Variable part The variable part is used to define less frequently used parameters. If the @@ -377,11 +383,11 @@ class Parameter: """ # fmt: off - type_id : Enum(Parameter_Code, uint8) | ENUM_STRICT = 0 + type_id : f[Parameter_Code, Enum(Parameter_Code, uint8) | ENUM_STRICT] = 0 """The parameter code""" # Simple TLV structure with dynamic parsing behabior - value : Prefixed(uint8, F(this.type_id) >> TPDU_PARAM_TYPES) = b"" + value : f[Any, Prefixed(uint8, F(this.type_id) >> TPDU_PARAM_TYPES)] = b"" """ The parameter length indication indicates the length, in octets, of the parameter value field. @@ -392,7 +398,7 @@ class Parameter: # --- Verification @staticmethod - def _verify_parameter(context) -> None: + def _verify_parameter(context: _ContextLike) -> None: # Since we're using a greedy length by default on the value, we can't be # sure if the parameter is valid or not. This action resolbes that # issue. @@ -400,7 +406,7 @@ def _verify_parameter(context) -> None: if parameter.type_id == 0 and not parameter.value: raise ValueError("Invalid parameter") - _verify: Action(unpack=_verify_parameter) + _verify: f[None, Action(unpack=_verify_parameter)] = Invisible() # fmt: on @@ -410,7 +416,7 @@ class TPDU: # fmt: off - li : uint8 = 0 + li : uint8_t = 0 """13.2.1 Length indicator field The length indicated shall be the header length in octets including @@ -418,7 +424,7 @@ class TPDU: The value 255 (1111 1111) is reserved for possible extensions. """ - code : uint8 = 0 + code : uint8_t = 0 """13.2.2.2 TPDU code This field contains the TPDU code. It is used to define the structure of the @@ -572,7 +578,7 @@ def build(self, add_checksum: bool = False) -> bytes: >>> pdu.build(add_checksum=True) b'\\n\\xe0\\x00\\x00\\x00\\x00\\x00\\xc3\\x02|\\xd5' >>> parsed = TPDU_ConnectionRequest.from_octets(_) - TPDU_ConnectionRequest(li=10, code=224,...parameters=[Parameter(type_id=, value=b'|\\xd5')]) + TPDU_ConnectionRequest(li=10, code=224,...parameters=[Parameter(type_id=, value=b'|\\xd5')]) :param add_checksum: Whether to generate and insert a checksum parameter during the build process. @@ -619,10 +625,10 @@ class TPDU_ClassOption: """ # fmt: off - class_id : (4, EnumFactory(TPDU_Class)) = TPDU_Class.CLASS0 - reserved : 2 = 0 - extended_formats : 1 = False - explicit_flow_control : 1 = False + class_id : f[TPDU_Class | int, (4, EnumFactory(TPDU_Class))] = TPDU_Class.CLASS0 + reserved : f[int, 2] = 0 + extended_formats : f[bool, 1] = False + explicit_flow_control : f[bool, 1] = False # fmt: on @@ -647,10 +653,10 @@ class TPDU_ConnectionRequest(TPDU): TPDU_FIXED_SIZE = 6 # fmt: off - dst_ref: uint16 = 0 + dst_ref: uint16_t = 0 """c) DST-REF - Set to zero.""" - src_ref: uint16 = 0 + src_ref: uint16_t = 0 """d) SRC-REF Reference selected by the transport entity initiating the CR-TPDU to @@ -666,7 +672,7 @@ class TPDU_ConnectionRequest(TPDU): listed in the variable part if required. """ - parameters: Bytes(this.li - 6) & TPDU_VariablePart = None + parameters: f[list[Parameter], Bytes(this.li - 6) & TPDU_VariablePart] = None """13.3.4 Variable part The following parameters are permitted in the variable part: @@ -690,14 +696,14 @@ class 4 is preferred and class 3 is an alternate, it may be used) class) """ - user_data: TPDU_UserData = None + user_data: f[bytes, TPDU_UserData] = None """ No user data are permitted in class 0, and are optional in other classes. """ # fmt: on def __post_init__(self) -> None: - self.tpdu_code = TPDU_Code.CR + self.tpdu_code: TPDU_Code = TPDU_Code.CR self.class_opt = self.class_opt or TPDU_ClassOption() self.parameters = self.parameters or [] self.user_data = self.user_data or b"" @@ -710,14 +716,14 @@ class TPDU_ConnectionConfirm(TPDU): TPDU_FIXED_SIZE = 6 # fmt: off - dst_ref : uint16 = 0 + dst_ref : uint16_t = 0 """c) DST-REF Reference identifying the requested transport connection at the remote transport entity. """ - src_ref : uint16 = 0 + src_ref : uint16_t = 0 """d) SRC-REF Reference selected by the transport entity initiating the CC-TPDU to @@ -731,10 +737,10 @@ class TPDU_ConnectionConfirm(TPDU): the accepted transport connection. """ - parameters : Bytes(this.li - 6) & TPDU_VariablePart = None + parameters : f[list[Parameter], Bytes(this.li - 6) & TPDU_VariablePart] = None """Same as in :class:`TPDU_ConnectionRequest`""" - user_data : TPDU_UserData = b"" + user_data : f[bytes, TPDU_UserData] = b"" """13.4.5 User Data No user data are permitted in class 0, and are optional in the other classes. @@ -742,7 +748,7 @@ class TPDU_ConnectionConfirm(TPDU): # fmt: on def __post_init__(self): - self.tpdu_code = TPDU_Code.CC + self.tpdu_code: TPDU_Code = TPDU_Code.CC self.class_opt = self.class_opt or TPDU_ClassOption() self.parameters = self.parameters or [] self.user_data = self.user_data or b"" @@ -759,18 +765,18 @@ class TPDU_DisconnectRequest(TPDU): TPDU_FIXED_SIZE = 6 # fmt: off - dst_ref: uint16 = 0 - """Destination reference — identifies the transport connection to be + dst_ref: uint16_t = 0 + """Destination reference - identifies the transport connection to be released.""" - src_ref: uint16 = 0 - """Source reference — identifies the transport connection from the sender's + src_ref: uint16_t = 0 + """Source reference - identifies the transport connection from the sender's perspective.""" - reason: TPDU_DisconnectReason = 0 + reason: f[TPDU_DisconnectReason | int, Enum(TPDU_DisconnectReason, uint8)] = 0 """Reason code for disconnection (X.224 §13.5.4).""" - parameters: Bytes(this.li - 6) & TPDU_VariablePart = None + parameters: f[list[Parameter], Bytes(this.li - 6) & TPDU_VariablePart] = None """Optional parameters (variable part) Allowed parameters: @@ -779,14 +785,14 @@ class TPDU_DisconnectRequest(TPDU): - b) Checksum """ - user_data: TPDU_UserData = None - """Optional user data — must not exceed 64 octets.""" + user_data: f[bytes, TPDU_UserData] = None + """Optional user data - must not exceed 64 octets.""" # fmt: on def __post_init__(self): self.parameters = self.parameters or [] self.user_data = self.user_data or b"" - self.tpdu_code = TPDU_Code.DR + self.tpdu_code: TPDU_Code = TPDU_Code.DR @struct(order=BigEndian) @@ -800,33 +806,33 @@ class TPDU_DisconnectConfirm(TPDU): TPDU_FIXED_SIZE = 5 # fmt: off - dst_ref: uint16 = 0 - """Destination reference — identifies the transport connection being + dst_ref: uint16_t = 0 + """Destination reference - identifies the transport connection being confirmed as disconnected.""" - src_ref: uint16 = 0 - """Source reference — identifies the transport connection from the sender's + src_ref: uint16_t = 0 + """Source reference - identifies the transport connection from the sender's perspective.""" - parameters: Bytes(this.li - 5) & TPDU_VariablePart = None + parameters: f[list[Parameter], Bytes(this.li - 5) & TPDU_VariablePart] = None """Only checksum is allowed as a parameter""" # fmt: on def __post_init__(self): self.parameters = self.parameters or [] - self.tpdu_code = TPDU_Code.DC + self.tpdu_code: TPDU_Code = TPDU_Code.DC @bitfield class TPDU_Number: - eot: 1 = False + eot: f[bool, 1] = False """d) EOT When set to ONE, it indicates that the current DT-TPDU is the last data unit of a complete DT-TPDU sequence (end of TSDU). """ - value: 7 = 0 + value: f[int, 7] = 0 """e) TPDU-NR TPDU send sequence number (zero in class 0). May take any value in class 2 @@ -849,7 +855,7 @@ class TPDU_Data(TPDU): nr: TPDU_Number = None """e) TPDU-NR""" - user_data: TPDU_UserData = b"" + user_data: f[bytes, TPDU_UserData] = b"" """This field contains data of the TSDU being transmitted.""" # fmt: on @@ -857,7 +863,7 @@ def __post_init__(self): if not isinstance(self.nr, TPDU_Number): self.nr = TPDU_Number() self.user_data = self.user_data or b"" - self.tpdu_code = TPDU_Code.DT + self.tpdu_code: TPDU_Code = TPDU_Code.DT @property def tpdu_nr(self) -> int: @@ -878,18 +884,18 @@ class TPDU_ExpeditedData(TPDU): TPDU_FIXED_SIZE = 4 - dst_ref: uint16 = 0 - """Destination reference — identifies the transport connection to which the + dst_ref: uint16_t = 0 + """Destination reference - identifies the transport connection to which the expedited data belongs.""" ed_nr: TPDU_Number = None """Sequence number for expedited data (X.224 §13.8.4).""" - parameters: Bytes(this.li - 4) & TPDU_VariablePart = None + parameters: f[list[Parameter], Bytes(this.li - 4) & TPDU_VariablePart] = None """Only checksum is allowed as a parameter""" - user_data: TPDU_UserData = None - """The expedited data payload — must not exceed the maximum allowed for + user_data: f[bytes, TPDU_UserData] = None + """The expedited data payload - must not exceed the maximum allowed for expedited service.""" def __post_init__(self): @@ -897,7 +903,7 @@ def __post_init__(self): if not isinstance(self.ed_nr, TPDU_Number): self.ed_nr = TPDU_Number() self.parameters = self.parameters or [] - self.tpdu_code = TPDU_Code.ED + self.tpdu_code: TPDU_Code = TPDU_Code.ED @struct(order=BigEndian) @@ -910,16 +916,16 @@ class TPDU_DataAcknowledgement(TPDU): TPDU_FIXED_SIZE = 6 - dst_ref: uint16 = 0 - """Destination reference — identifies the transport connection.""" + dst_ref: uint16_t = 0 + """Destination reference - identifies the transport connection.""" next_nr: TPDU_Number = None """Next expected TPDU sequence number.""" - credit: uint16 = 0 - """Flow control credit — number of TPDUs the sender is prepared to receive.""" + credit: uint16_t = 0 + """Flow control credit - number of TPDUs the sender is prepared to receive.""" - parameters: Bytes(this.li - 6) & TPDU_VariablePart = None + parameters: f[list[Parameter], Bytes(this.li - 6) & TPDU_VariablePart] = None """Optional parameters allowed in AK-TPDU: - a) Checksum @@ -934,7 +940,7 @@ class 4. def __post_init__(self): self.parameters = self.parameters or [] - self.tpdu_code = TPDU_Code.AK + self.tpdu_code: TPDU_Code = TPDU_Code.AK if not isinstance(self.next_nr, TPDU_Number): self.next_nr = TPDU_Number() @@ -949,18 +955,18 @@ class TPDU_ExpeditedDataAcknowledgement(TPDU): TPDU_FIXED_SIZE = 4 # fmt: off - dst_ref: uint16 = 0 - """Destination reference — identifies the transport connection.""" + dst_ref: uint16_t = 0 + """Destination reference - identifies the transport connection.""" ed_nr: TPDU_Number = None """Expedited data sequence number being acknowledged.""" - parameters: Bytes(this.li - 4) & TPDU_VariablePart = None + parameters: f[list[Parameter], Bytes(this.li - 4) & TPDU_VariablePart] = None """Only checksum is allowed as a parameter""" # fmt: on def __post_init__(self): - self.tpdu_code = TPDU_Code.EA + self.tpdu_code: TPDU_Code = TPDU_Code.EA self.parameters = self.parameters or [] if not isinstance(self.ed_nr, TPDU_Number): self.ed_nr = TPDU_Number() @@ -975,14 +981,14 @@ class TPDU_Reject(TPDU): TPDU_FIXED_SIZE = 5 - dst_ref: uint16 = 0 - """Destination reference — identifies the transport connection.""" + dst_ref: uint16_t = 0 + """Destination reference - identifies the transport connection.""" - y_nr: uint16 = 0 + y_nr: uint16_t = 0 """Next expected TPDU sequence number (Y(R)).""" def __post_init__(self): - self.tpdu_code = TPDU_Code.RJ + self.tpdu_code: TPDU_Code = TPDU_Code.RJ # Reject cause codes for ER (X.224 §13.12.3) @@ -1004,13 +1010,13 @@ class TPDU_Error(TPDU): TPDU_FIXED_SIZE = 4 # fmt: off - dst_ref: uint16 = 0 + dst_ref: uint16_t = 0 """Destination reference (see §13.4.3).""" - reject_cause: ER_RejectCause = ER_RejectCause.REASON_NOT_SPECIFIED + reject_cause: f[ER_RejectCause | int, Enum(ER_RejectCause, uint8)] = ER_RejectCause.REASON_NOT_SPECIFIED """Reject cause (§13.12.3).""" - parameters: Bytes(this.li - 4) & TPDU_VariablePart = None + parameters: f[list[Parameter], Bytes(this.li - 4) & TPDU_VariablePart] = None """Optional parameters: - a) Invalid TPDU @@ -1019,7 +1025,7 @@ class TPDU_Error(TPDU): # fmt: on def __post_init__(self): - self.tpdu_code = TPDU_Code.ER + self.tpdu_code: TPDU_Code = TPDU_Code.ER self.parameters = self.parameters or [] @@ -1077,6 +1083,18 @@ def parse_tpdu(octets: bytes) -> _TPDULike: if len(octets) < 2: raise ValueError("TPDU must have at least 2 octets") + li = octets[0] + if li == 0xFF: + raise ValueError("Reserved TPDU length indicator") + if li >= len(octets): + raise ValueError(f"Invalid TPDU length indicator: li={li}, total={len(octets)}") + tpdu_base = TPDU.from_octets(octets) tpdu_type = TPDU_TYPES.get(tpdu_base.tpdu_code, TPDU) + fixed_size = getattr(tpdu_type, "TPDU_FIXED_SIZE", 1) + if li < fixed_size: + raise ValueError( + "TPDU fixed part cannot be contained within header: " + + f"li={li}, fixed_size={fixed_size}" + ) return tpdu_type.from_octets(octets) diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..9bae01b --- /dev/null +++ b/uv.lock @@ -0,0 +1,748 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.11'", + "python_full_version < '3.11'", +] + +[[package]] +name = "aiosqlite" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/8a/64761f4005f17809769d23e518d915db74e6310474e733e3593cfc854ef1/aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650", size = 14821, upload-time = "2025-12-23T19:25:43.997Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload-time = "2025-12-23T19:25:42.139Z" }, +] + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] + +[[package]] +name = "asyncua" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiosqlite" }, + { name = "anyio" }, + { name = "cryptography" }, + { name = "pyopenssl" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "sortedcontainers" }, + { name = "typing-extensions" }, + { name = "wait-for2", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/7d/14830444700e18631853c417b05472c7036cd266e90866e8d0ae4bcd7c72/asyncua-2.0.1.tar.gz", hash = "sha256:f9f73804b4d56a12aaad7a2f062b15f08c856718d93a10c647d82a9f38f787df", size = 1213396, upload-time = "2026-06-29T07:14:43.388Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/8e/37545889e8fa056accb03fe3f546fcf0f3e49192682f1dfa913a18fc5937/asyncua-2.0.1-py3-none-any.whl", hash = "sha256:f21d58c78f6fa9b592c7c29890527e530a35cbb4ac9f96002b6bddce7425a404", size = 1314333, upload-time = "2026-06-29T07:14:45.395Z" }, +] + +[[package]] +name = "backports-strenum" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/c7/2ed54c32fed313591ffb21edbd48db71e68827d43a61938e5a0bc2b6ec91/backports_strenum-1.3.1.tar.gz", hash = "sha256:77c52407342898497714f0596e86188bb7084f89063226f4ba66863482f42414", size = 7257, upload-time = "2023-12-09T14:36:40.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/50/56cf20e2ee5127b603b81d5a69580a1a325083e2b921aa8f067da83927c0/backports_strenum-1.3.1-py3-none-any.whl", hash = "sha256:cdcfe36dc897e2615dc793b7d3097f54d359918fc448754a517e6f23044ccf83", size = 8304, upload-time = "2023-12-09T14:36:39.905Z" }, +] + +[[package]] +name = "bitarray" +version = "3.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/01/59a0fbb89c2204ba07099a6e4b87768d25d6aa689df07547412218e03145/bitarray-3.9.1.tar.gz", hash = "sha256:796f2b4f0e4d84df50bd23ddfacb37d74eec2b2366813cb8f18bdae6b25e3d36", size = 159256, upload-time = "2026-07-19T07:35:45.203Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/d0/fc114f61e777e78f384b38e37d1f80195deac430b75d9612773b41083172/bitarray-3.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d2f9b165e3b6615b63a8e52318e3b7ff3d21613cd09771ab390c9195c90e8f58", size = 155424, upload-time = "2026-07-19T07:33:21.82Z" }, + { url = "https://files.pythonhosted.org/packages/eb/73/03bb480e05624ca953cacbfd775401f666a8daf6822927972d4a97afff39/bitarray-3.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:741a768c55370c78758199ae3ea0e892ab6c44715bbba2680238e92af1fb89f1", size = 152040, upload-time = "2026-07-19T07:33:23.034Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c5/b6e12dd9c6a8d37306a3f90026b34de001df00b38678f111e08ba9f6b172/bitarray-3.9.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9623497177e1d4b36b382043305dedc543421780b5657ac6393f2d164fbbda95", size = 342770, upload-time = "2026-07-19T07:33:24.305Z" }, + { url = "https://files.pythonhosted.org/packages/d7/d7/56020927c0f81c4fd13cb005e19be174c1790f12ab3d4c88b44c4e669173/bitarray-3.9.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:701b96896b77566cd9d6920a588210a7a48fe549ddab34ebcc348c07d6f96c89", size = 363399, upload-time = "2026-07-19T07:33:25.551Z" }, + { url = "https://files.pythonhosted.org/packages/67/61/b73a6c31dcbea241b122d07aab1c13e09267b7c9a2337b48d1ed9abf4632/bitarray-3.9.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e0016138e5e654617ccbd43afe87425a248016fd6877a823b980e22266480321", size = 374605, upload-time = "2026-07-19T07:33:26.746Z" }, + { url = "https://files.pythonhosted.org/packages/40/b5/b6ac1b6e54ab7f564e3b73b5fd3fa7fe6028d7bf14bdf2139b035b78198d/bitarray-3.9.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6010d8e75a78c803deea372cf43711849bc35fe64ec9867e772da53422eb9929", size = 344769, upload-time = "2026-07-19T07:33:27.903Z" }, + { url = "https://files.pythonhosted.org/packages/f3/6b/2490d85d3e3ada89e6036dc85dd16db1c69ba6e216a8513f376b514c4f7a/bitarray-3.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a9e4dc565bf50b18c80c977ce5eba7364eb18c6c3b4077e0a7ba04b2048d3b6d", size = 340815, upload-time = "2026-07-19T07:33:29.173Z" }, + { url = "https://files.pythonhosted.org/packages/86/0e/a0112e4aa1df66a48d7cbdd2ecf9f75d7c2f6448030383648d0539026249/bitarray-3.9.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc2b5f5e4871ad73d555b2938ef9f3cac08af633da463e9d5a1612353c9b4946", size = 360354, upload-time = "2026-07-19T07:33:30.45Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a8/eba74afabade6cf26814b1628b9fe177d2af13d5a115294511343c384111/bitarray-3.9.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8302cfc85358c3af8657c514bba297063fc98d264b15d5abc1e3e3ab774fd537", size = 356153, upload-time = "2026-07-19T07:33:31.719Z" }, + { url = "https://files.pythonhosted.org/packages/64/2c/e9f4b59bda1de5cdc39e35a47479e6def596cf9bf03a7b205e036e4e2de7/bitarray-3.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4d6b19ba11c54f3a07b7c4bd138d4df0d192f86e8ca9f407fb3e5a70970deadc", size = 341781, upload-time = "2026-07-19T07:33:32.8Z" }, + { url = "https://files.pythonhosted.org/packages/4b/5f/55f6ccfe0db310af4fd6487446e6ccf149d4aba073ddf80ea286e426b91d/bitarray-3.9.1-cp310-cp310-win32.whl", hash = "sha256:1a5c3cf52a850e5a15238e8416c7802795da2ea1110eeac921d20716cfb3fc51", size = 147117, upload-time = "2026-07-19T07:33:33.975Z" }, + { url = "https://files.pythonhosted.org/packages/4f/6b/d9ab717742b575e97c4420fe0202da215607f69b7a55aae509e1a86715d5/bitarray-3.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:3d9d589f259c8006dcf9929ba1a11dce7a37074505e5b72b350e2e23f7d68eb6", size = 154702, upload-time = "2026-07-19T07:33:35.109Z" }, + { url = "https://files.pythonhosted.org/packages/a2/d2/44160ad3901e1156f961c8f27e128b4c49eceee084d1324810276b4dc35c/bitarray-3.9.1-cp310-cp310-win_arm64.whl", hash = "sha256:8bdc0f7e919f84fd9e1ffeedc806c2064d9ad9809ecce131c63a2ccf3c076d37", size = 151642, upload-time = "2026-07-19T07:33:36.348Z" }, + { url = "https://files.pythonhosted.org/packages/67/0e/d0c4e4317b1ce2311b901876c283b3196f567e5a477063e070c35c4f8d94/bitarray-3.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:36137e762c68db66dc0fe16f06aedcf0a94e1765592f13feee8c53acde3f95d4", size = 155424, upload-time = "2026-07-19T07:33:37.469Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f9/5c4296d82ccdd6f872780c3250a502e1010f28284bbbc0a084b7b4ca3559/bitarray-3.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:138a960945fff0876d9cdb756a25d13f2aacee3849d8f642005fe7fb9b45a885", size = 152044, upload-time = "2026-07-19T07:33:38.641Z" }, + { url = "https://files.pythonhosted.org/packages/b6/68/0fc76f8893f5823fa9ebbd24100c4bac03c285c15b348369bd686d92eda7/bitarray-3.9.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e080707dd5fca338ae9665ee9b33260fbec71511abe3328860ab9181988c833", size = 351835, upload-time = "2026-07-19T07:33:39.971Z" }, + { url = "https://files.pythonhosted.org/packages/ef/c4/d376592c61146b91588cfaaafc0a6a5a7a5e4c76a90f8406b1a8783f6102/bitarray-3.9.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a15e9f50cf1dc8265613b0ebe7741f268de92d01e36772ada5352790e69396c5", size = 372083, upload-time = "2026-07-19T07:33:41.41Z" }, + { url = "https://files.pythonhosted.org/packages/8c/78/b501960cbc31c8e4e4572034f38e7adfedd657620407d8ae0ee924c7a670/bitarray-3.9.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:575cb4a0f212c3718a3830a5c46e8814eb8d16e3706f39afc0cd0ce352c771c7", size = 384183, upload-time = "2026-07-19T07:33:42.674Z" }, + { url = "https://files.pythonhosted.org/packages/ca/97/734f8ca722f2d94ac79da57c1ea0d17bf0985134d4aea2e307f6ce9ef92e/bitarray-3.9.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7f32b41d0bba064d1e0e381e0729b827e17b923e0247d40d36fdcafa7ee8f554", size = 353817, upload-time = "2026-07-19T07:33:43.949Z" }, + { url = "https://files.pythonhosted.org/packages/44/e4/f11e7d5920323562b04eea8845f9c884d95f3056f333af98854295feac25/bitarray-3.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aeb5c908f43b34d4cba564635f05eaa4db628c4a2dcd99e7eab672278b62b401", size = 349572, upload-time = "2026-07-19T07:33:45.323Z" }, + { url = "https://files.pythonhosted.org/packages/70/04/342f3d04f9a03fc7f8649fc97e48b8f0fcc6b58f31bca97a065309f7b015/bitarray-3.9.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:5e23e26018388057e4f35d84328b687ff6f8516cb86dbaa2f520d6cfac0047a6", size = 369321, upload-time = "2026-07-19T07:33:46.575Z" }, + { url = "https://files.pythonhosted.org/packages/f7/37/f8d565668f51e93dce9d2626f3428288703f1f61fbb2bf5cc0111f090114/bitarray-3.9.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bef7fab638f865512433ce8f21f29960fb16bcde7a02e4af08aef83fd97902c7", size = 365381, upload-time = "2026-07-19T07:33:48.167Z" }, + { url = "https://files.pythonhosted.org/packages/74/54/de1adb0b5539c11c1cc17638d13f3c6a2e9eb5daa45d356b3375fc9da8b7/bitarray-3.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:68c08f20951803fab7762894c012c001a130916c5e31a6898844aa2e59b9a53a", size = 350297, upload-time = "2026-07-19T07:33:49.559Z" }, + { url = "https://files.pythonhosted.org/packages/c9/13/c92d854092cfe607d6d18da803df81ddc72220b1177e3f32fc656537a32a/bitarray-3.9.1-cp311-cp311-win32.whl", hash = "sha256:8b6af8714dd95098daa72a6e8ee6834c3780a63a5528347b0faadb414fe76367", size = 147295, upload-time = "2026-07-19T07:33:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/80/24/6697d2395cde6ca2836eff63e57efe782fffecc5c212d1722659e34f3115/bitarray-3.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:811b5762db1ac1200a166bb9c932b387d1718359cbe3f03bd7478da8c8d95e6b", size = 154969, upload-time = "2026-07-19T07:33:52.054Z" }, + { url = "https://files.pythonhosted.org/packages/4b/df/133e08a7a0ee740668ba596b93d6a126e07e19cf382896b27916cac43d54/bitarray-3.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:bde6cb94f1196bbcf1a47e484d20d7d71c4bc5380433ab4f7ac506e1acc1378d", size = 151980, upload-time = "2026-07-19T07:33:53.221Z" }, + { url = "https://files.pythonhosted.org/packages/e8/0e/604bdbbeb3a08f159ed893e50a1b6499501e3635692b14d706ca0b237c61/bitarray-3.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ad48236a37a88f051ddd9f591adf0407df1a96b72bedffb56b44a1493f3ccfc5", size = 155172, upload-time = "2026-07-19T07:33:54.428Z" }, + { url = "https://files.pythonhosted.org/packages/57/5c/9ae2cfcca338d575b98f8d99b0742942b3e59fa8747991f0a8001a17f7f2/bitarray-3.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cfc01fff237333ae27120b704c152c7408305a2dbcf7cfdee02d9236588046b2", size = 151971, upload-time = "2026-07-19T07:33:55.638Z" }, + { url = "https://files.pythonhosted.org/packages/a4/f6/badc27464b96b458b3a271f4cc6ee0e56253a355ca901b30c730077b8672/bitarray-3.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:220af932e6732c8febf38b77cfbf248ac7d7f99b6d9595df2cc534f365ed7d5d", size = 355041, upload-time = "2026-07-19T07:33:56.858Z" }, + { url = "https://files.pythonhosted.org/packages/f1/9f/d05c68baf1b7733ccd4174e41ab7d7cdc74547f9538efe2a3d26e866fd29/bitarray-3.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dbe4f1f3c1c307aed80814ea0ad076ccb4125260ddac1dc2c304a80bef69aa56", size = 374533, upload-time = "2026-07-19T07:33:58.162Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4c/ed9114f60333647192cef4e051a7058a1b8803fc331ec17d7f692c1ecc08/bitarray-3.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f663f615633ef8258000b50e2ca4a6fb490caaede016f3a4ce65e451f85c8ec0", size = 388006, upload-time = "2026-07-19T07:33:59.556Z" }, + { url = "https://files.pythonhosted.org/packages/ca/9f/f1adeadf3ec4a3bd3d1d9c809bce8526ceb3b571e8dd8356c26de0dc699e/bitarray-3.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:528a0632d67d10f6089c5635079c2551b2538c8cbaaac64078b5bff70e74987e", size = 358625, upload-time = "2026-07-19T07:34:00.789Z" }, + { url = "https://files.pythonhosted.org/packages/f0/5d/f8fe99288abcd226e6ce4e1893f231b860673841a800f6a56b2555a21c68/bitarray-3.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8eae33580921506e3887a3d6bf6cb7f453881ce1734735316ccd5b118c9f1ded", size = 352386, upload-time = "2026-07-19T07:34:02.015Z" }, + { url = "https://files.pythonhosted.org/packages/59/56/570a28b769ea1ce9e92114eed1063a14abae0732b6060cc5d5ba9bbe8ac4/bitarray-3.9.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:80a94ec78c6f6938111c50ca159461574ccd41def36080a30fcef5051b5dc956", size = 371526, upload-time = "2026-07-19T07:34:03.815Z" }, + { url = "https://files.pythonhosted.org/packages/bf/c4/50fadb63031c1d390001bd5fbcff6e6d29961f832a4dc203e4a494f880be/bitarray-3.9.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9ac35d6e23fd22a329f847a772a2860f9306b6ac189de3d5e8ffa92f784432de", size = 369441, upload-time = "2026-07-19T07:34:05.471Z" }, + { url = "https://files.pythonhosted.org/packages/90/e7/1f9f65d56fb162a12b0d59c8624a7df2104574d6f531a248213c099bce91/bitarray-3.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:963ca4500acd6a46df827fc4cd383a8ed33283ecb4f377bb85d5fff7d860427c", size = 354422, upload-time = "2026-07-19T07:34:06.983Z" }, + { url = "https://files.pythonhosted.org/packages/d7/df/b3e671740b127eb9663079c67d2d2c6fa38565d9fcbf2f188f6bbad3702c/bitarray-3.9.1-cp312-cp312-win32.whl", hash = "sha256:5778c9403aee365f19a32432acf6a44cb888551cde607be2a3d269dab8db90ca", size = 147688, upload-time = "2026-07-19T07:34:08.58Z" }, + { url = "https://files.pythonhosted.org/packages/a3/42/067851c10750f3eb99a6f5c7b7f35abb464223e45572b68073a2232b13c3/bitarray-3.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:c10cb7fa227f40acccec58639eb46396e0e42d22fb3186a5b8eff879938263ba", size = 155256, upload-time = "2026-07-19T07:34:09.942Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5b/e14ebd38c27a09ede5f74568c64ee273216f52adef58ab0b2f549bbe6b0d/bitarray-3.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:9d238e7ad64edb83e3d65e42c52f3caec1079d0da021486c39ec62001e7ebddc", size = 152137, upload-time = "2026-07-19T07:34:11.206Z" }, + { url = "https://files.pythonhosted.org/packages/4a/2e/069abb71be80f951d966d8299d2a08ceb8b0637f3c364bf9d9441f0bda6a/bitarray-3.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fee327c587e9815be868e78c64d38209fb9fa01d261a65bd6d621f933703dfa9", size = 154963, upload-time = "2026-07-19T07:34:12.518Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ff/9215b47c42cbf9234ccb0ec50cbec6b5ac36960302d65508b6b8c5cbaf77/bitarray-3.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a29bf8475302eeb8d812f0a15a4f1465162270b432a3a746d4276ca215d411b8", size = 151718, upload-time = "2026-07-19T07:34:13.893Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a9/93beb27af2f265d982edd6dba2e12a7f50061b6e1ccfb2ef380509e1c9a4/bitarray-3.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:427ec45108c80d508af9414cbbf4f23a5b78cbd3bb70e8c608e2dc47f2d2f5eb", size = 352716, upload-time = "2026-07-19T07:34:15.107Z" }, + { url = "https://files.pythonhosted.org/packages/44/38/a8ff096ffd120a07b6fe7caa59930cfcb7adbcbcba96f0c9511f316457bd/bitarray-3.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:36b36409a33c82e48233a5bc8c911ffa292fe4f79ad6af215e98caa792fd230b", size = 372150, upload-time = "2026-07-19T07:34:16.561Z" }, + { url = "https://files.pythonhosted.org/packages/1c/40/ebf769e0b06997fa3c4925495c2616b0dc2292483e93e2d0802c3f8d1103/bitarray-3.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7aa578c55e221ade1ad295506a2f3f10ad6e6eb3fd990605fb31f57872d59cf7", size = 385609, upload-time = "2026-07-19T07:34:17.922Z" }, + { url = "https://files.pythonhosted.org/packages/4d/86/a95d1b7daf504a6af321656b2b3cedf602603ae77f0da1df2a253469e95e/bitarray-3.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c6a7881ea7e3be80dc4cc83e0fd6925e8a011749c21ae75894cd1279a55d7a", size = 356301, upload-time = "2026-07-19T07:34:19.226Z" }, + { url = "https://files.pythonhosted.org/packages/5e/db/875f6119728bf553350a76034e6489fded56ecc8f222572d1888d03f051c/bitarray-3.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e25af1aa4ded42b3f06a663a53040030f0a24432cfe08e731d57d5f44e2ca3a2", size = 350191, upload-time = "2026-07-19T07:34:20.48Z" }, + { url = "https://files.pythonhosted.org/packages/fe/2e/57b191a3c33056c09c8d1fd6f5751ba7856cf93d621a0ff235d0454f2c4e/bitarray-3.9.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:15a48736d4bd2a83cf674c32e8a9ad3eef2f521a43fa6b32548f334f59680802", size = 369232, upload-time = "2026-07-19T07:34:21.918Z" }, + { url = "https://files.pythonhosted.org/packages/80/75/a37fc8bea1779285962ad96231e555a0444ea71a2060be82abce458b81f7/bitarray-3.9.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e51d7460098537cbe3ffa6e4761b748871f29a3872dc335358dbeccdf193b71c", size = 367099, upload-time = "2026-07-19T07:34:23.189Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ba/ecdb0b0f9d688c5512fd1e4e630550b5f6746fc890e1eacd06a5b6552a34/bitarray-3.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9083051539ea9effcd5a339bdfa07adeec73e8749046ffe3193ccdf47222ff1", size = 352001, upload-time = "2026-07-19T07:34:24.651Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9b/a9b6596d1dc62954f2a200b4a07aff48d478e290934dbc7ca5daead104b9/bitarray-3.9.1-cp313-cp313-win32.whl", hash = "sha256:74d65ed78f5860aa4efcb6c6e8c33637e6b1d8cbef095758554026f80c72295f", size = 147519, upload-time = "2026-07-19T07:34:25.897Z" }, + { url = "https://files.pythonhosted.org/packages/d7/68/590ae7a95d8c7720c695bdebb6402977709f9845e8220a0e5e2f24645a4d/bitarray-3.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:83df6ddf60f19c64f3f43c394a48a3ff3ac3f4e571d34ebbf445ea44e72c3ce2", size = 155028, upload-time = "2026-07-19T07:34:27.132Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b7/eca262a563d3b6c02ae89fa14bdb7dfd81c6034becaae9996398f948b6b7/bitarray-3.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:516bd099adcfecc8b006122adb47703200dc57102e612c4d7da4a33c179e5390", size = 152025, upload-time = "2026-07-19T07:34:28.3Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b4/2e73911b3967c06808c65b3a9f348a64b750e5ed6ed99249fa7d2f89200f/bitarray-3.9.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:03446f91584ee7d1456970d7c9a4afb0dcc128fe90ca982d068b2c59f75ceb9a", size = 155012, upload-time = "2026-07-19T07:34:29.901Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/19d783951416c8dd08f833b5b625c586a56cb3e87bfeabca474763234ff2/bitarray-3.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fa471e730991c34ea0bbf183ea9b3232bf9bc86c84c30f7872a0dd366ea23972", size = 151826, upload-time = "2026-07-19T07:34:31.062Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/5fbe8ea99102397a93ba39d6c90896edfda1c628ccc244e96ce4627dffb4/bitarray-3.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ea4c8a3fd493f0bcd638037908aa321167290776fa4d324cdb0fe60ccc10577", size = 352666, upload-time = "2026-07-19T07:34:32.303Z" }, + { url = "https://files.pythonhosted.org/packages/3a/86/105cfa1e6accb69560449a2644e0ca05dce0e95a720d69d26eb8372a67dd/bitarray-3.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:76cf06c9d131a460a09168d42b2d41e0c915cebda2dbd386d69fb8d89c126948", size = 372439, upload-time = "2026-07-19T07:34:33.609Z" }, + { url = "https://files.pythonhosted.org/packages/2d/2a/17f4285423da2a7724c45f6b1367b42cb2fcb403f27f9b59b515ac2b0c95/bitarray-3.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e8d98d0f39d5e23a960f5cd6fad5e53a18119af559927644f288d1e3e6da9bd8", size = 384953, upload-time = "2026-07-19T07:34:35.03Z" }, + { url = "https://files.pythonhosted.org/packages/2c/61/92bea605a2d38a8674cd6d1a7ab4bce7867da68df972fad490488993f514/bitarray-3.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:068eb24bb3a11502837797d89e63a339199ce6e3e65ffe4c2d5854b3b2959084", size = 355778, upload-time = "2026-07-19T07:34:36.37Z" }, + { url = "https://files.pythonhosted.org/packages/6b/be/587678b392d3f82691849e0603de732cb0730fdb2609172176c77c9ab350/bitarray-3.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a0a32ff658f10bb9cda554346e429aa05eca9a22346abda100bb5b872d3806a1", size = 350318, upload-time = "2026-07-19T07:34:37.651Z" }, + { url = "https://files.pythonhosted.org/packages/57/14/6a032875b80626e7669fad8859530c940b306f0567af432098b4c8b05b61/bitarray-3.9.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:3a3c3fc85bd6af6bef7f85fe14b5dc2bfbdebd24b80cff297d79d222daaffc6d", size = 369365, upload-time = "2026-07-19T07:34:38.999Z" }, + { url = "https://files.pythonhosted.org/packages/cd/d4/b586892f0d861e01dc2d05a26be3c9f257bcc05325d16a89d5d73619d5f8/bitarray-3.9.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:a34246b68ebcf72b5f81c0a376f47aa558fa902025fcbff1970ca412735e735b", size = 366666, upload-time = "2026-07-19T07:34:40.295Z" }, + { url = "https://files.pythonhosted.org/packages/b2/5c/c456adf9271961094b7242b1e5fb0ef59b83b424f8f927306daa06c2ccb8/bitarray-3.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bd399698d0eac7e63c4c3824694a6a9f7f06caef09deaed2da209aed0c6cd2b0", size = 351675, upload-time = "2026-07-19T07:34:41.651Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ec/95289427b193cad46d6bda42471c30b10ea2c378f452281d89d0c35c737f/bitarray-3.9.1-cp314-cp314-win32.whl", hash = "sha256:a89aeb07984953b022a935f971bb37a237bef89359934883a7b3c4aaa73bc70a", size = 146572, upload-time = "2026-07-19T07:34:43.092Z" }, + { url = "https://files.pythonhosted.org/packages/c3/4e/d6015295aa58455adcd549d0da4d1497f8525d452641eae39d2d37078dce/bitarray-3.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:76fb57cb76529f6327edc9c31ec63f16e8569c791f96ec23c095debee1597659", size = 154037, upload-time = "2026-07-19T07:34:44.469Z" }, + { url = "https://files.pythonhosted.org/packages/9b/a7/ee5115e37b2a996901c192df7c8c7eb0d4fd09d42cd42cddae88b8da1029/bitarray-3.9.1-cp314-cp314-win_arm64.whl", hash = "sha256:86c50aad15a48e3b648cb2469ec7c6712a470ab8a24c72e4d4b1c92c50ee17b0", size = 151291, upload-time = "2026-07-19T07:34:45.737Z" }, + { url = "https://files.pythonhosted.org/packages/70/4a/c2cb4baabe47712611d680302c53e5f48caf32ff95b2217152cdabd4d355/bitarray-3.9.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:25c05a3a86eeaf630f48e48121a35afeb782441f5c6813592778ac57fcef70a3", size = 158254, upload-time = "2026-07-19T07:34:47.014Z" }, + { url = "https://files.pythonhosted.org/packages/a6/a3/411f8d2c8af6f17d30bd5fa8315d03496d4faac153bbe0d93cbf33406ab6/bitarray-3.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4e8d930f963e2206af8fc892c39b468485b332cad6e8b19736c8e2ad037a22a0", size = 154878, upload-time = "2026-07-19T07:34:48.411Z" }, + { url = "https://files.pythonhosted.org/packages/c1/cc/fd8008cf77f07630a2a6d88d9708e7f4b5aafb137fea2280804ac57eb3ad/bitarray-3.9.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3980a6f8e63a3c8d3c7696d04a9456915dbee738b4bd308cf00cfbb2c8a5fa6", size = 370542, upload-time = "2026-07-19T07:34:50.067Z" }, + { url = "https://files.pythonhosted.org/packages/24/8b/abda31324d9caac6ec9e37a0866ee96fdad075611b7a3bfd6541657a510e/bitarray-3.9.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:84424b867d8661f1df6fecd60f0de7a6b9a753b0f39d1382e922554cc0707984", size = 390878, upload-time = "2026-07-19T07:34:51.837Z" }, + { url = "https://files.pythonhosted.org/packages/52/a9/3f90af789b7b13cfa0517387cf60b50286c699fe37dfc1141bd4f2cba60d/bitarray-3.9.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7c4a02d031d054e9306fff4fc34c1872dbfaf798b8a7be05dd88aa8dfaab5a8b", size = 402064, upload-time = "2026-07-19T07:34:53.24Z" }, + { url = "https://files.pythonhosted.org/packages/c9/90/c9f94a92916fa6af76f34dd4b9620c7578bdecbcf0212752a383639114db/bitarray-3.9.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11702332975576f036f516931ef17f9638366a017006c561e3818146a62670f3", size = 371862, upload-time = "2026-07-19T07:34:54.722Z" }, + { url = "https://files.pythonhosted.org/packages/22/1e/33dd1db64b393f9472077f3aa1c36075273f645d0d1e8a4c1cbeaeecbad6/bitarray-3.9.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4c13a94bcffa317aacfbc4f5d380868b229070ab27b5af7a2f8dfaa0a2ce81b5", size = 367913, upload-time = "2026-07-19T07:34:56.201Z" }, + { url = "https://files.pythonhosted.org/packages/da/47/f443f480880adb8d7a730958840f3e0da6548763f770fad4a6aab289e8a2/bitarray-3.9.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:fac915bf0b356cbfac28788cb2d09b6f7d03f2a189fad3c5b1b9ec6b9f2c83c1", size = 387003, upload-time = "2026-07-19T07:34:57.757Z" }, + { url = "https://files.pythonhosted.org/packages/dd/cc/03798094542b054224d7d9f3e4bf3fdb3f86c1f994b445052b7f29507e22/bitarray-3.9.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:38db03a28fa1f59131bc38e49523cc2cb4b01f2b567c5179f4ae9338eb9780de", size = 383945, upload-time = "2026-07-19T07:34:59.167Z" }, + { url = "https://files.pythonhosted.org/packages/fa/9a/3ccb88303dd4f427d18667b81ac7def46169db1d608adb2f94655cf4495c/bitarray-3.9.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b6a642bca321f033d97a6bf55fe00a2b7c689dadff3ecbca761eaa601955eca1", size = 367502, upload-time = "2026-07-19T07:35:00.524Z" }, + { url = "https://files.pythonhosted.org/packages/f4/37/48315facb32194d34498cd940ffc12f797cb67a152bf478b3a5479b4ac93/bitarray-3.9.1-cp314-cp314t-win32.whl", hash = "sha256:2ad727d30a44ec0618ad7a17257d5de610230ed07e130ca1fb37d68080b3f5e4", size = 149270, upload-time = "2026-07-19T07:35:02.4Z" }, + { url = "https://files.pythonhosted.org/packages/54/49/635403b83b5e1c7f3d34dd7d93c99c874f1856494280e7ec4deccf262a21/bitarray-3.9.1-cp314-cp314t-win_amd64.whl", hash = "sha256:34df6adb30bd8d877ca46479f35bb01ac4c073813d4e258b5fc7f7dadebe1fd2", size = 157793, upload-time = "2026-07-19T07:35:03.984Z" }, + { url = "https://files.pythonhosted.org/packages/aa/35/a643004308bd7bfbf3916634f78b9624282eadbaba80c8ba240e2f800d5f/bitarray-3.9.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7237617573f967624e6f1db688c7c391de982253291f6deeac9038e70cea2d63", size = 154078, upload-time = "2026-07-19T07:35:05.382Z" }, +] + +[[package]] +name = "caterpillar-py" +version = "2.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/91/2ffcce444c7cf9e8f0e64ee83692ffc8a09de75339aa6801884905a6b546/caterpillar_py-2.9.0.tar.gz", hash = "sha256:c75605e4f93022fc41abfd81a96e84de13b095bb3a03d87392a38fb2699d1747", size = 128968, upload-time = "2026-07-04T20:44:47.602Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/91/0e0e8ada0892e35cc8ea75318daf1592e65b172801ea57d835c04f017bac/caterpillar_py-2.9.0-py3-none-any.whl", hash = "sha256:39c75b7fdf36d62c34e009f579f5ababaac4472b16344abb702a7c9ceaf36235", size = 162125, upload-time = "2026-07-04T20:44:45.894Z" }, +] + +[[package]] +name = "cffi" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/5f/ff100cae70ebe9d8df1c01a00e510e45d9adb5c1fdda84791b199141de97/cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9", size = 531036, upload-time = "2026-07-06T21:34:30.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/e9/6d7724983b3d5a0908dbf74f64038ade77c18646ff6636ec7894fd392ce1/cffi-2.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:b65f590ef2a44640f9a05dbb548a429b4ade77913ce683ac8b1480777658a6c0", size = 183837, upload-time = "2026-07-06T21:32:09.655Z" }, + { url = "https://files.pythonhosted.org/packages/69/aa/24580a278de21fd7322635556334d9b535f1cbc00b0a3919447cdf464c65/cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164bff1657b2a74f0b6d54e11c9b375bc97b931f2ca9c43fcf875838da1570dd", size = 184226, upload-time = "2026-07-06T21:32:11.196Z" }, + { url = "https://files.pythonhosted.org/packages/88/a9/02cae418ec4beb282ace11958d9d4737793439d561fadc7e6d56f2e2b354/cffi-2.1.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:c941bb58d5a6e1c3892d86e42927ed6c180302f07e6d395d08c416e594b98b46", size = 211107, upload-time = "2026-07-06T21:32:12.328Z" }, + { url = "https://files.pythonhosted.org/packages/3b/30/c806937ed5e4c2c7ac30d9d6b76b5dc57ff8b75d83800d9bb11a8253cf2a/cffi-2.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a016194dbe13d14ee9556e734b772d8d67b947092b268d757fd4290e3ba2dfc2", size = 218733, upload-time = "2026-07-06T21:32:13.67Z" }, + { url = "https://files.pythonhosted.org/packages/f9/cf/398272b8bbfd58aa314fda5a7f1cdbb26d1d78ae324a11211521315dd1f0/cffi-2.1.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:03e9810d18c646077e501f661b682fbf5dee4676048527ca3cffe66faa9960dd", size = 205543, upload-time = "2026-07-06T21:32:15.148Z" }, + { url = "https://files.pythonhosted.org/packages/45/ca/f91641185cdd90c36d317a9dc7f85e88ef8682d8b300977baff5e23c35d8/cffi-2.1.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:19c54ac121cad98450b4896fa9a43ee0180d57bc4bc911a33db6cab1efab6cd3", size = 205460, upload-time = "2026-07-06T21:32:16.479Z" }, + { url = "https://files.pythonhosted.org/packages/38/66/04781a77b411f0bb5b234d62c1814754ab75ebe455ccff1b08e8d7aae98f/cffi-2.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d433a51f1870e43a13b6732f92aaf540ff77c2015097c78556f75a2d6c030e0", size = 218760, upload-time = "2026-07-06T21:32:17.98Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9a/bb1d5ed9c3fcae158e9f6391bf309c95d98c2ac37ed56573228471d0af5e/cffi-2.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3d7f118b5adbfdfead90c25822690b02bc8074fba949bb7858bec4ebd55adb43", size = 221230, upload-time = "2026-07-06T21:32:19.407Z" }, + { url = "https://files.pythonhosted.org/packages/41/aa/3c1409cdd26094efacd1c36c66e0a6eb9d4296e4fd4f9901b8b2042f4323/cffi-2.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5f5df567f6eb216de69be06ce55c8b714090fae02b18a3b40da8163b8c5fa9c", size = 213524, upload-time = "2026-07-06T21:32:20.828Z" }, + { url = "https://files.pythonhosted.org/packages/fa/75/74dfb7c3fc6ebbd408038476bd4c1d7e925c62614e7b9c534ecc34218288/cffi-2.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:11b3fb55f4f8ad92274ed26705f65d8f91457de71f5380061eb6d125a768fecd", size = 220341, upload-time = "2026-07-06T21:32:21.9Z" }, + { url = "https://files.pythonhosted.org/packages/70/b6/9003c33a3e7d2c1306f5962e646457dcfe5a8cd8fce6bbe02d7af25db783/cffi-2.1.0-cp310-cp310-win32.whl", hash = "sha256:9d72af0cf10a76a600a9690078fe31c63b9588c8e86bf9fd353f713c84b5db0f", size = 174578, upload-time = "2026-07-06T21:32:23.073Z" }, + { url = "https://files.pythonhosted.org/packages/8a/26/710688310447531c7a22f857c7f79d9855ec18b03e04494ced723fb37e2f/cffi-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb62edb5bb52cca65fab91a63afa7561607120d26090a7e8fda6fb9f064726da", size = 185071, upload-time = "2026-07-06T21:32:24.671Z" }, + { url = "https://files.pythonhosted.org/packages/d3/67/85c89a59ba36a671e79638f44d466749f08179266a57e4f2ffdf92174072/cffi-2.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:02cb7ff33ded4f1532476731f89ede53e2e488a8e6205515a82144246ffa7dcc", size = 183845, upload-time = "2026-07-06T21:32:26.32Z" }, + { url = "https://files.pythonhosted.org/packages/ea/dd/e3b0baa2d3d6a857ac72b7efbf18e32e487c9cdafcc13049ad765495b15e/cffi-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f5bce581e6b8c235e566a14768a943b172ada3ed73537bb0c0be1edee312d4e7", size = 184186, upload-time = "2026-07-06T21:32:28.025Z" }, + { url = "https://files.pythonhosted.org/packages/65/68/9f3ef890cf3c6ab97bd531c5677f67613d302165d16f8142b2811782a614/cffi-2.1.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:30b65779d598c370374fefabf138d456fd6f3216bfa7bedfab1ba82025b0cd93", size = 211892, upload-time = "2026-07-06T21:32:29.565Z" }, + { url = "https://files.pythonhosted.org/packages/22/d7/1a74539db16d8bfd839ff1515948948efbb162e574650fd3d846896eea95/cffi-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88023dfe18799507b73f1dbb0d14326a17465de1bc9c9c7655c22845e9ddc3a2", size = 218793, upload-time = "2026-07-06T21:32:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ec/d1/9a5b7169499e8e8d8e636de70b97ac7c9447104d2ff1a2cd94790cea5162/cffi-2.1.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0a96b74cda968eebbad56d973efe5098974f0a9fb323865bf99ea1fd24e3e64c", size = 205737, upload-time = "2026-07-06T21:32:32.216Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b0/e131a9c41f10607926278453d9596163594fe1c4ebc46efe3b5e5b34eb84/cffi-2.1.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a5781494d4d400a3f47f8f1da94b324f6e6b440a53387774002890a2a2f4b50f", size = 204909, upload-time = "2026-07-06T21:32:33.655Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d2/4398416cd699b35167947c6e22aca52c47e69ad5695073c9f1f2c52e04aa/cffi-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aa7a1b53a2a4452ada2d1b5dade9960b2522f1e61293a811a077439e39029565", size = 217883, upload-time = "2026-07-06T21:32:35.173Z" }, + { url = "https://files.pythonhosted.org/packages/a2/a5/d4fe77b589e5e82d43ebc809bf2e6474afe8e48e32ea050b9357645b6471/cffi-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d8272c0e483b024e1b9ad029821470ed8ec65631dbd90217469da0e7cd89f1c", size = 221251, upload-time = "2026-07-06T21:32:36.527Z" }, + { url = "https://files.pythonhosted.org/packages/22/f0/a2fc43084c0433caf7f461bccc013e28f848d04ee1c5ed7fce71423cf4d9/cffi-2.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7762faa47e8ff7eb80bd261d9a7d8eea2d8baa69de5e95b70c1f338bbe712f02", size = 214250, upload-time = "2026-07-06T21:32:37.852Z" }, + { url = "https://files.pythonhosted.org/packages/04/8c/b925975448cf20634a9fbd5efceb807219db452653648d2897c0989cab2d/cffi-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89095c1968b4ba8285840e131bf2891b09ae137fe2146905acae0354fbce1b5e", size = 219441, upload-time = "2026-07-06T21:32:39.146Z" }, + { url = "https://files.pythonhosted.org/packages/eb/da/5c4918a2d61d86fa927d716cb3d8e4626ef8dc8f605a599d32f33897f59a/cffi-2.1.0-cp311-cp311-win32.whl", hash = "sha256:64c753a0f87a256020004f37a1c8c02c480e725f910f0b2a0f3f07debd1b2479", size = 174496, upload-time = "2026-07-06T21:32:40.467Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c8/6c2de1d55cf35ef8b92885d5ef280790f0fb9634d87ea1cc315176aecd61/cffi-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:4f26194e3d95e06501b942642855aed4f953d55e95d7d01b7c4483db3ecff458", size = 185113, upload-time = "2026-07-06T21:32:41.761Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4e/e8d7cb5783f1841a3c8fb3a7735838d7484d08ec08c9f984b14cac1ac0e9/cffi-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:35aaea0c7ee0e58a5cd8c2fd1a48fdf7ece0d2699b7ecdda08194e9ce5dd9b3d", size = 179927, upload-time = "2026-07-06T21:32:42.961Z" }, + { url = "https://files.pythonhosted.org/packages/1e/85/990925db5df586ec90beb97529c853497e7f85ba0234830447faf41c3057/cffi-2.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:df2b82571a1b30f58a87bf4e5a9e78d2b1eff6c6ce8fd3aa3757221f93f0863f", size = 184829, upload-time = "2026-07-06T21:32:44.324Z" }, + { url = "https://files.pythonhosted.org/packages/4b/92/e7bb136ad6b5352603732cf907ef862ca103f20f2031c1735a46300c20c9/cffi-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78474632761faa0fb96f30b1c928c84ebcf68713cbb80d15bab09dfe61640fde", size = 184728, upload-time = "2026-07-06T21:32:45.683Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c0/d1ec30ffb370f748f2fb54425972bfef9871e0132e82fb589c46b6676049/cffi-2.1.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5972433ad71a9e46516584ef60a0fda12d9dc459938d1539c3ddecf9bdc1368d", size = 214815, upload-time = "2026-07-06T21:32:48.557Z" }, + { url = "https://files.pythonhosted.org/packages/1b/dc/5620cf930688be01f2d673804291de757a934c90b946dbdc3d84130c2ea4/cffi-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b6422532152adf4e59b110cb2808cee7a033800952f5c036b4af047ee43199e7", size = 222429, upload-time = "2026-07-06T21:32:49.848Z" }, + { url = "https://files.pythonhosted.org/packages/4b/a4/77b53abbf7a1e0beb9637edbef2a94d15f9c822f591e85d439ffd91519a6/cffi-2.1.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:46b1c8db8f6122420f32d02fffb924c2fe9bc772d228c7c711748fff56aabb2b", size = 210315, upload-time = "2026-07-06T21:32:51.221Z" }, + { url = "https://files.pythonhosted.org/packages/58/0c/f528df19cc94b675087324d4760d9e6d5bfae97d6217aa4fac43de4f5fcc/cffi-2.1.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9fafc5aa2e2a39aaf7f8cc0c1f044a9b07fca12e558dca53a3cc5c654ad67a7", size = 208859, upload-time = "2026-07-06T21:32:52.512Z" }, + { url = "https://files.pythonhosted.org/packages/62/f2/c9522a81c32132799a1972c39f5c5f8b4c8b9f00488a23feaa6c06f07741/cffi-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1e9f50d192a3e525b15a75ab5114e442d83d657b7ec29182a991bc9a88fd3a66", size = 221844, upload-time = "2026-07-06T21:32:53.704Z" }, + { url = "https://files.pythonhosted.org/packages/6e/28/bd53988b9833e8f8ad539d26f4c07a6b3f6bcb1e9e02e7ca038250b3428d/cffi-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98fff996e983a36d3aa2eca83af40c5821202e7e6f32d13ae94e3d2286f10cfe", size = 225287, upload-time = "2026-07-06T21:32:54.907Z" }, + { url = "https://files.pythonhosted.org/packages/79/99/0d0fd37f055224085f42bbb2c022d002e17dde4a97972822327b07d84101/cffi-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:379de10ce1ba048b1448599d1b37b24caee16309d1ac98d3982fc997f768700b", size = 223681, upload-time = "2026-07-06T21:32:56.329Z" }, + { url = "https://files.pythonhosted.org/packages/b0/80/c138990aa2a70b1a269f6e06348729836d733d6f970867943f61d367f8cc/cffi-2.1.0-cp312-cp312-win32.whl", hash = "sha256:9b8f0f26ca4e7513c534d351eca551947d053fac438f2a04ac96d882909b0d3a", size = 175269, upload-time = "2026-07-06T21:32:57.777Z" }, + { url = "https://files.pythonhosted.org/packages/a8/eb/f636456ff21a83fc13c032b58cc5dde061691546ac79efa284b2989b7982/cffi-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:c97f080ea627e2863524c5af3836e2270b5f5dfff1f104392b959f8df0c5d384", size = 185881, upload-time = "2026-07-06T21:32:59.253Z" }, + { url = "https://files.pythonhosted.org/packages/dd/2c/400ea43e721727dca8a65c4521390e9196757caba4a45643acb2b63271b8/cffi-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:6d194185eabd279f1c05ebe3504265ddfc5ad2b58d0714f7db9f01da592e9eb6", size = 180088, upload-time = "2026-07-06T21:33:02.278Z" }, + { url = "https://files.pythonhosted.org/packages/96/88/a996879e2eeccb815f6e3a5967b12a308257412acec882039d386bd2aa7b/cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:10537b1df4967ca26d21e5072d7d54188354483b91dc75058968d3f0cf13fbda", size = 194331, upload-time = "2026-07-06T21:33:03.697Z" }, + { url = "https://files.pythonhosted.org/packages/58/85/7ae00d5c8dd6266f4e944c3db630f3c5c9a98b61d469c714d848b1d8138a/cffi-2.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a95b05f9baf29b91171b3a8bd2020b028835243e7b0ff6bb23e2a3c228518b1b", size = 196966, upload-time = "2026-07-06T21:33:05.353Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e9/45c3a76ad8d43ad9261f4c95436da61128d3ca545d72b9612c0ab5be0b1c/cffi-2.1.0-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:15faec4adfff450819f3aee0e2e02c812de6edb88203aa58807955db2003472a", size = 184795, upload-time = "2026-07-06T21:33:06.699Z" }, + { url = "https://files.pythonhosted.org/packages/84/4c/82f132cb4418ee6d953d982b19191e87e2a6372c8a4ce36e50b69d6ade4a/cffi-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:716ff8ec22f20b4d988b12884086bcef0fc99737043e503f7a3935a6be99b1ea", size = 184746, upload-time = "2026-07-06T21:33:08.071Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1c/4ed5a0e5bdca6cbc275556de3328dd1b76fd0c11cc13c88fe66d1d8715f2/cffi-2.1.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:63960549e4f8dc41e31accb97b975abaecfc44c03e396c093a6436763c2ea7db", size = 214747, upload-time = "2026-07-06T21:33:09.671Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a6/e879bb68cc23a2bc9ba8f4b7d8019f0c2694bad2ab6c4a3701d429439f58/cffi-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff067a8d8d880e7809e4ac88eb009bb848870115317b306666502ccad30b147f", size = 222392, upload-time = "2026-07-06T21:33:10.896Z" }, + { url = "https://files.pythonhosted.org/packages/88/f6/01890cfd63c08f8eb96a8319b0443690197d240a8bd6346048cf7bde9190/cffi-2.1.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:3b926723c13eba9f81d2ef3820d63aeceec3b2d4639906047bf675cb8a7a500d", size = 210285, upload-time = "2026-07-06T21:33:12.251Z" }, + { url = "https://files.pythonhosted.org/packages/a6/cf/2b684132056f438567b61e19d690dd31cd0921ace051e0a458be6074369e/cffi-2.1.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:47ff3a8bfd8cb9da1af7524b965127095055654c177fcfc7578debcb015eecd0", size = 208801, upload-time = "2026-07-06T21:33:13.617Z" }, + { url = "https://files.pythonhosted.org/packages/6f/08/f2e7d62c460faae0926f2d6e423694aa409ced3bc1fe2927a0a6e5f05416/cffi-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:799416bae98336e400981ff6e532d67d5c709cfb30afb79865a1315f94b0e224", size = 221808, upload-time = "2026-07-06T21:33:15.466Z" }, + { url = "https://files.pythonhosted.org/packages/38/37/04f54b8e63a02f3d908332c9effbf8c366167c6f733ed8a3d4f79b7e2a1e/cffi-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:961be50688f7fba2fa65f63712d3b9b341a22311f5253460ce933f52f0de1c8c", size = 225241, upload-time = "2026-07-06T21:33:16.869Z" }, + { url = "https://files.pythonhosted.org/packages/a9/d6/c72eecca433cd3e681c65ed313ab4835d9d4a379704d0f628a6a05f51c2e/cffi-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf5c6cf48238b0eb4c086978c492ad1cbc22373fc5b2d7353b3a598ce6db887a", size = 223588, upload-time = "2026-07-06T21:33:18.239Z" }, + { url = "https://files.pythonhosted.org/packages/c6/4b/e706f67279140f92939da3475ad610df18bfd52d50f14953a8e5fede71d5/cffi-2.1.0-cp313-cp313-win32.whl", hash = "sha256:db3eb7d46527159a878ec3460e9d40615bc25ba337d477db681aea6e4f05c5d2", size = 175248, upload-time = "2026-07-06T21:33:19.799Z" }, + { url = "https://files.pythonhosted.org/packages/5a/47/59eb7975cb0e4ef0afa764ea945b29a5bb4537a9f771cb7d6c8a5dd74c95/cffi-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:8e74a6135550c4748af665b1b1118b6aab33b1fc6a16f9aff630af107c3b4512", size = 185717, upload-time = "2026-07-06T21:33:21.47Z" }, + { url = "https://files.pythonhosted.org/packages/5a/af/34fee85c48f8d94efc8597bc09470c9dd274c145f1c12e0fbc6ab6d38d74/cffi-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:2282cd5e38aa8accd03e99d1256af8411c84cdbee6a89d841b563fdbd1f3e50f", size = 180114, upload-time = "2026-07-06T21:33:22.515Z" }, + { url = "https://files.pythonhosted.org/packages/d8/f0/81478e482afa03f6d18dc8f2afb5edc45b3080853b634b5ed91961be0998/cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d2117334c3af3bdcb9a88522b844a2bdb5efdc4f71c6c822df55486ae1c3347a", size = 194142, upload-time = "2026-07-06T21:33:23.657Z" }, + { url = "https://files.pythonhosted.org/packages/7d/95/8de304305cd9204974b0ca051b86d307cafca13aa575a0ef1b44d92c0d8c/cffi-2.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:702c436735fbe99d59ada02a1f65cfc0d31c0ee8b7290912f8fbc5cd1e4b16c3", size = 196819, upload-time = "2026-07-06T21:33:25.007Z" }, + { url = "https://files.pythonhosted.org/packages/20/71/7c8372d30e42415602ed9f268f7cfd66f1b855fed881ecd168bcb45dbc0b/cffi-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1ff3456eab0d889592d1936d6125bbfbc7ae4d3354a700f8bd80450a66445d4d", size = 184965, upload-time = "2026-07-06T21:33:26.605Z" }, + { url = "https://files.pythonhosted.org/packages/d6/5c/584e626835f0375c928176c04137c96927165cb8733cdb3150ec04e5ee5e/cffi-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c4165821e131d6d4ca444347c2b694e2311bcfa3fe5a861cc72968f28867beac", size = 184952, upload-time = "2026-07-06T21:33:27.823Z" }, + { url = "https://files.pythonhosted.org/packages/2e/d2/065fcae1c73979fac8e054462478d0ff8a29c40cdc2ed7ea5676a061df53/cffi-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:276f20fffd7b396e12516ba8edf9509210ac248cbbc5acbc39cd512f9f59ebe6", size = 222353, upload-time = "2026-07-06T21:33:29.178Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a5/e8bbb1ce5b3ac2f53ad6a10bde44318a5a8d99d4f4a000d44a6e39aeb3e4/cffi-2.1.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7d5980a3433d4b71a5e120f9dd551403d7824e31e2e67124fe2769c404c06913", size = 210051, upload-time = "2026-07-06T21:33:30.534Z" }, + { url = "https://files.pythonhosted.org/packages/28/ed/c127d3ac36e899c965e3361357c3befacd6578c03f40125183e41c3b219e/cffi-2.1.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6ca4919c6e4f89aa99c42510b42cf54596892c00b3f9077f6bdd1505e24b9c8d", size = 208630, upload-time = "2026-07-06T21:33:31.753Z" }, + { url = "https://files.pythonhosted.org/packages/cc/d7/97d3136f81db489ec8d1d67748c110d6c994268fd7528014aa9f2b085e4e/cffi-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d53d10f7da99ae46f7373b9150393e9c5eab9b224909982b43832668de4779f5", size = 221593, upload-time = "2026-07-06T21:33:33.044Z" }, + { url = "https://files.pythonhosted.org/packages/d3/27/93195977168ee63aed233a1a0993a2178798654d1f4bddcdd321d6fd3b21/cffi-2.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c351efb95e832a853a29361675f33a7ce53de1a109cd73fd47af0712213aa4ce", size = 225146, upload-time = "2026-07-06T21:33:34.224Z" }, + { url = "https://files.pythonhosted.org/packages/b3/c1/6dbd291ee2ae5a50a034aa057207081f545923bbf15dad4511e985aafff5/cffi-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7c7a88e2bac086f06d14577332760bdeecc42bdec8ac4077f6260557d9326", size = 223240, upload-time = "2026-07-06T21:33:35.57Z" }, + { url = "https://files.pythonhosted.org/packages/0f/6f/ade5ce9863a57992a6ea3d0d10d7e29b8749fc127204b3d493d667b2815f/cffi-2.1.0-cp314-cp314-win32.whl", hash = "sha256:1854b724d00f6654c742097d5387569021be12d3a0f770eae1df8f8acfcc6acd", size = 177723, upload-time = "2026-07-06T21:33:51.626Z" }, + { url = "https://files.pythonhosted.org/packages/41/de/92b9eeed4ae4a21d6fd9b2a2c8505cbed573299902ea73981cc13f7ff62c/cffi-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:1b96bfe2c4bd825681b7d311ad6d9b7280a091f43e8f63da5729638083cd3bfb", size = 187937, upload-time = "2026-07-06T21:33:53.403Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1a/cc6ae6c2913a03aab8898eee57963cf1035b8df5872ed8b9115fcc7e2be8/cffi-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:7d28dff1db6764108bc30788d85d61c876beff416d9a49cb9dd7c5a9f34f5804", size = 183001, upload-time = "2026-07-06T21:33:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/14/f0/134c00ce0779ec86dea2aa1aac69339c2741a8045072676763512363a2ea/cffi-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7ea6b3e2c4250ff1de21c630fe72d0f63eb95c2c32ffbf64a358cf4a8836d714", size = 188538, upload-time = "2026-07-06T21:33:36.792Z" }, + { url = "https://files.pythonhosted.org/packages/50/d8/3b86aba791cb610d24e8a3e1b2cd529e71fa15096b04e4d4e360049d4a4c/cffi-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6af371f3767faeffc6ac1ef57cdfd25844403e9d3f476c5537caee499de96376", size = 188230, upload-time = "2026-07-06T21:33:38.011Z" }, + { url = "https://files.pythonhosted.org/packages/14/d0/117dcd9209255ad8571fbc8c92ef32593a1d294dcec91ddc4e4db50606f2/cffi-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb4e8997a49aa2c08a3e43c9045d224448b8941d88e7ac163c7d383e560cbf98", size = 223899, upload-time = "2026-07-06T21:33:39.514Z" }, + { url = "https://files.pythonhosted.org/packages/b6/3d/f20f8b886b254e3ad10e15cd4186d3aed49f3e6a35ab37aab9f8f25f7c03/cffi-2.1.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf01d8c84cbea96b944c73b22182e6c7c432b3475632b8111dbfdc95ddad6e13", size = 211652, upload-time = "2026-07-06T21:33:40.851Z" }, + { url = "https://files.pythonhosted.org/packages/28/3b/fad54de07260b93ddeef4b96d0131d57ea900675df1d410ae1deee52d7a6/cffi-2.1.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:33eb1ad83ebe8f313e0df035c406227d55a79456704a863fad9842136af5ad7d", size = 210755, upload-time = "2026-07-06T21:33:42.183Z" }, + { url = "https://files.pythonhosted.org/packages/cc/82/3d5c705acb7abbba9bbd7d79b8e62e0f25b6120eb7ae6ac49f1b721722fe/cffi-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ac0f1a2d0cfa7eea3f2aaf006ab6e70e8feeb16b75d65b7e5939982ca2f11056", size = 223933, upload-time = "2026-07-06T21:33:43.603Z" }, + { url = "https://files.pythonhosted.org/packages/6c/d0/47e338384ab6b1004241002fa616301020cea4fc95f283506565d252f276/cffi-2.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c16914df9fb7f500e440e6875fa23ff5e0b31db01fa9c06af98d59a91f0dc2e4", size = 226749, upload-time = "2026-07-06T21:33:45.046Z" }, + { url = "https://files.pythonhosted.org/packages/70/25/65bd5b58ea4bfdfc15cde02cb5365f89ef8ab8b2adfb8fe5c4bd4233382f/cffi-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5ecbd0499275d57506d397eebe1981cee87b47fcd9ef5c22cab7ed7644a39a94", size = 225703, upload-time = "2026-07-06T21:33:46.374Z" }, + { url = "https://files.pythonhosted.org/packages/dc/78/aa01ac599a8a4322533d45a1f9bc93b338276d2d59dabbe7c6d92a775c81/cffi-2.1.0-cp314-cp314t-win32.whl", hash = "sha256:7d034dcffa09e9a46c93fa3a3be402096cb5354ac6e41ab8e5cc9cd8b642ad76", size = 182857, upload-time = "2026-07-06T21:33:47.696Z" }, + { url = "https://files.pythonhosted.org/packages/b9/26/d00496b22de4d4228f32dde94ad996f350c8aad676d63bcca0743c8dea4d/cffi-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0582a58f3051372229ca8e7f5f589f9e5632678208d8636fea3676711fdf7fe5", size = 194065, upload-time = "2026-07-06T21:33:48.953Z" }, + { url = "https://files.pythonhosted.org/packages/d5/dd/0c7dbf815a579ff005008a2d815a55d6bb047c349eef536d9dc53d3f0a8d/cffi-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:510aeeeac94811b138077451da1fb18b308a5feab47dd2b603af55804155e1c8", size = 186404, upload-time = "2026-07-06T21:33:50.309Z" }, + { url = "https://files.pythonhosted.org/packages/55/c7/8c8c50cb11c6750051daf12164098a9a6f027ac4356967fd4d800a07f242/cffi-2.1.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:2e9dabb9abcb7ad15938c7196ad5c1718a4e6d33cc79b4c0209bdb64c4a54a5c", size = 194121, upload-time = "2026-07-06T21:33:56.109Z" }, + { url = "https://files.pythonhosted.org/packages/99/e2/67680bf19a6b60d2bb7ff83baefa2a4c3d2d7dc0f3277034b802e1fc504c/cffi-2.1.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:37f525a7e7e50c017fdebe58b787be310ad59357ae43a053943a6e1a6c526001", size = 196820, upload-time = "2026-07-06T21:33:57.288Z" }, + { url = "https://files.pythonhosted.org/packages/ed/da/4bbe583a3b3a5c8c60892124fe17f3fa3656523faf0d3484eae90f091853/cffi-2.1.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:95f2954c2c9473d892eca6e0409f3568b37ab62a8eedb122461f73cc273476e3", size = 184936, upload-time = "2026-07-06T21:33:58.765Z" }, + { url = "https://files.pythonhosted.org/packages/e5/4b/1f4c36ab273980d7aa75bb126ea4f8971f24a96108acad3a0a084028c57b/cffi-2.1.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:cdf2448aab5f661c9315308ec8b93f4e8a1a67a3c733f8631067a2b67d5913dc", size = 185045, upload-time = "2026-07-06T21:34:00.085Z" }, + { url = "https://files.pythonhosted.org/packages/ef/c3/ad299dc38f3583f8d916b299f028af418a9ec98bc695fcbebeae7420691c/cffi-2.1.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90bec57cf82089383bd06a605b3eb8daebf7e5a668520beaf6e327a83a947699", size = 222342, upload-time = "2026-07-06T21:34:01.814Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d8/df4543cc087245044ed02ef3ad8e0a26619d0075ac7a77a12dc81177851b/cffi-2.1.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6274dcb2d15cef48daa73ed1be5a40d501d74dccd0cd6db364776d12cb6ba022", size = 210073, upload-time = "2026-07-06T21:34:03.255Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/fac738d73728c6cea2a88a2883dca54892496cbba88a1dc1f2909cb8a6f5/cffi-2.1.0-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b71d409cccee78310ab5dec549aed052aaea483346e282c7b02362596e01bb0", size = 208551, upload-time = "2026-07-06T21:34:04.433Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3f/0b04a700dd64f465c93020253a793a82c9b4dff9961f48facd0df945d9b8/cffi-2.1.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7d3538f9c0e50670f4deb93dbb696576e60590369cae2faf7de681e597a8a1f1", size = 221649, upload-time = "2026-07-06T21:34:06.157Z" }, + { url = "https://files.pythonhosted.org/packages/5d/7c/b7379a5704c79eda57ce075869ba70a0368d1c850f803b3c0d078d39dcaf/cffi-2.1.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:8f9ec95b8a043d3dfbc74d9abc6f7baf524dd27a8dc160b0a32ff9cdab650c28", size = 225203, upload-time = "2026-07-06T21:34:07.489Z" }, + { url = "https://files.pythonhosted.org/packages/5a/02/d5e6c43ea85c41bda2a184a3418f195fe7cf602967a8d2b94e085b83deef/cffi-2.1.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:af5e2915d41fe6c961694d7bfdc8562942638200f3ce2765dfb8b745cf997629", size = 223263, upload-time = "2026-07-06T21:34:08.712Z" }, + { url = "https://files.pythonhosted.org/packages/2c/d8/772b8259bf75749adffb1c546828978381fb516f60cf701f6c83daf60c85/cffi-2.1.0-cp315-cp315-win32.whl", hash = "sha256:0a42c688d19fca6e095a53c6a6e2295a5b050a8b289f109adab02a9e61a25de6", size = 177696, upload-time = "2026-07-06T21:34:26.355Z" }, + { url = "https://files.pythonhosted.org/packages/2f/dd/afa2191fc6d57fedd26e5844a2fe2fcc0bbfa00961bbaa5a41e4921e7cca/cffi-2.1.0-cp315-cp315-win_amd64.whl", hash = "sha256:bccbbb5ee76a61f9d99b5bf3846a51d7fca4b6a732fe46f89295610edaf41853", size = 187914, upload-time = "2026-07-06T21:34:27.58Z" }, + { url = "https://files.pythonhosted.org/packages/05/ef/6cd4f8c671517162379dc79cfae5aea9106bc38abb89628d5c16adf6a838/cffi-2.1.0-cp315-cp315-win_arm64.whl", hash = "sha256:8d35c139744adb3e727cd51b1a18324bbe44b8bd41bf8322bca4d41289f48eda", size = 183004, upload-time = "2026-07-06T21:34:28.905Z" }, + { url = "https://files.pythonhosted.org/packages/11/b6/12fc55092817a5faa26fb8c40c7f9d662e11a46ee248c137aafc42517d92/cffi-2.1.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:f9912624a0c0b834b7520d7769b3644453aabc0a7e1c839da7359f050750e9bc", size = 188378, upload-time = "2026-07-06T21:34:09.926Z" }, + { url = "https://files.pythonhosted.org/packages/8d/2e/cdac88979f295fde5daa69622c7d2111e56e7ceb94f211357fbe452339e4/cffi-2.1.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:df92f2aba50eb4d96718b68ef76f2e57a57b54f2fa62333496d16c6d585a85ca", size = 188319, upload-time = "2026-07-06T21:34:11.101Z" }, + { url = "https://files.pythonhosted.org/packages/e0/27/1d0b408497e41a74795af122d7b603c418c5fed0171450f899afd04e594f/cffi-2.1.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0520e1f4c35f44e209cbbb421b67eec42e6a157f59444dfb6058874ff3610e5d", size = 223904, upload-time = "2026-07-06T21:34:12.606Z" }, + { url = "https://files.pythonhosted.org/packages/8b/31/e115c985105dd7ffb32444505f18ceb874bb42d992af05d5dced7ecf1980/cffi-2.1.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:3681e031db29958a7502f5c0c9d6bbc4c36cb20f7b104086fa642d1799631ff8", size = 211554, upload-time = "2026-07-06T21:34:13.987Z" }, + { url = "https://files.pythonhosted.org/packages/5a/67/9e6e09409336d9e515c58367e7cfcf4f89df06ad25252675595a58eb59d5/cffi-2.1.0-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:762f99479dcb369f60ab9017ad4ab97a36a1dd7c1ee5a3b15db0f4b8659120cd", size = 210795, upload-time = "2026-07-06T21:34:15.972Z" }, + { url = "https://files.pythonhosted.org/packages/19/e5/d3cc82a4a0be7902af279c04181ad038449c096734464a5ae1de3e1401bd/cffi-2.1.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0611e7ebf90573a535ebdc33ae9da222d037853983e13359f580fab781ca017f", size = 223843, upload-time = "2026-07-06T21:34:17.509Z" }, + { url = "https://files.pythonhosted.org/packages/b9/65/b434abc97ce7cecc2c640fde160507c0ecc7e21544b483ba3325d2e2ea17/cffi-2.1.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:86cf8755a791f72c85dc287128cc62d4f24d392e3f1e15837245623f4a33cccc", size = 226773, upload-time = "2026-07-06T21:34:19.05Z" }, + { url = "https://files.pythonhosted.org/packages/b5/9f/d4dc66ca651eb1145a133314cda721abf13cfac3d28c4a0402263ae6ad75/cffi-2.1.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:ba00f661f8ba35d075c937174e27c2c421cec3942fd2e0ea3e66996757c0fdd9", size = 225719, upload-time = "2026-07-06T21:34:20.576Z" }, + { url = "https://files.pythonhosted.org/packages/68/5a/e536c528bc8057496c360c0978559a2dc45653f89dd6151078aa7d8fca1a/cffi-2.1.0-cp315-cp315t-win32.whl", hash = "sha256:cb96698e3c7413d906ce83f8ffd245ec1bd94707541f299d0ce4d6b0193e982b", size = 182760, upload-time = "2026-07-06T21:34:22.059Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0b/0ffe8b82d3875bced5fa1e7986a7a46b748262a40ab7f60b475eb9fb1bb3/cffi-2.1.0-cp315-cp315t-win_amd64.whl", hash = "sha256:f146d154428a2523f9cc7936c02353c2459b8f6cf07d3cd1ee1c0a611109c5d5", size = 193769, upload-time = "2026-07-06T21:34:23.589Z" }, + { url = "https://files.pythonhosted.org/packages/a0/17/1073b53b68c9b5ca6914adf5f8bf55aacc2d3be102418c90700160ea8605/cffi-2.1.0-cp315-cp315t-win_arm64.whl", hash = "sha256:cbb7640ce37159548d2147b5b8c241f962143d4c71231431820783f4dc78f210", size = 186405, upload-time = "2026-07-06T21:34:24.857Z" }, +] + +[[package]] +name = "cmd2" +version = "3.5.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "backports-strenum", marker = "python_full_version < '3.11'" }, + { name = "gnureadline", marker = "python_full_version < '3.11' and sys_platform == 'darwin'" }, + { name = "pyperclip", marker = "python_full_version < '3.11'" }, + { name = "pyreadline3", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, + { name = "rich", marker = "python_full_version < '3.11'" }, + { name = "rich-argparse", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/b0/a28751b91b81d4adf2cea305bd29a5465c3f7991b7e2ca1e96b4d9bfa40e/cmd2-3.5.1.tar.gz", hash = "sha256:1637f765e764b022dfa617f4711fb441599732082eb6310cf8739fbaec2335a0", size = 707325, upload-time = "2026-04-24T14:52:55.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/04/af57eb5fcb194c3cc476af904928e23ca51568232248b4932fb36c23b8a9/cmd2-3.5.1-py3-none-any.whl", hash = "sha256:321ebcfaea9dbbd8651c0bb10fdaf197f11b95f355d782d50eee9b5ef250f428", size = 147525, upload-time = "2026-04-24T14:52:53.426Z" }, +] + +[[package]] +name = "cmd2" +version = "4.1.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +dependencies = [ + { name = "prompt-toolkit", marker = "python_full_version >= '3.11'" }, + { name = "pyperclip", marker = "python_full_version >= '3.11'" }, + { name = "rich", marker = "python_full_version >= '3.11'" }, + { name = "rich-argparse", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/af/e9/74830fbad8a69aa0ada43c7fda61eaaed53e619b2ca4807a83366805c283/cmd2-4.1.2.tar.gz", hash = "sha256:07e62b40235ae4af1c5730fb6b3a4708456b57b9ff79acf02808ac584263290a", size = 848904, upload-time = "2026-07-16T15:50:59.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/6a/4306a3f65353890995991f53b37e1d997caf8f7a0a9cdc07a582be12b5fe/cmd2-4.1.2-py3-none-any.whl", hash = "sha256:ced3f57a018bec43aa32b6d9bf950d4bf7706183f995a641fbe11473360e0749", size = 194836, upload-time = "2026-07-16T15:50:57.993Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "crcmod" +version = "1.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c3bcd6c33d2473c1918e0b7f6826a043ca1245dd4e5b/crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e", size = 89670, upload-time = "2010-06-27T14:35:29.538Z" } + +[[package]] +name = "cryptography" +version = "49.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/99/d1c90d6041656cc6ee229dc99cd67fd0cd5aec3c5f7d72fffc27cc750054/cryptography-49.0.0.tar.gz", hash = "sha256:f89660a348f4f78a92366240a61404e337586ef7f5909a2fef59ca88ef505493", size = 854345, upload-time = "2026-06-12T20:02:30.512Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:966fe0e9c67490071f14c0d2b1cb2dfb3023c5ce39457343931415f08382f2db", size = 4032100, upload-time = "2026-06-12T20:02:32.143Z" }, + { url = "https://files.pythonhosted.org/packages/09/41/3797cfaf69cae04a13ee78ebd83f0678d9c02b4779d21ce24445326f1a69/cryptography-49.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:36d1709f992593689b45bda411498d62c6e365f2ca00b84657d4dadd24de16db", size = 4692978, upload-time = "2026-06-12T20:01:21.305Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8b/43011f7ebe515a8aa20d61f290a326cd890c2e738e16e59eaff8d9c3a412/cryptography-49.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0e959b578856a3924bc0cbb710fc12c387b9412a951389f3ca61704a9e25f325", size = 4716422, upload-time = "2026-06-12T20:01:48.566Z" }, + { url = "https://files.pythonhosted.org/packages/4a/91/01ce7303a4579e6d3a6abef01bd322848e9ea7a219adcabc5048b9033571/cryptography-49.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:53ecee2e23f7169b6117e99fc8a944e5e50f79e69758a83b52a00cb98ab2b2d2", size = 4700503, upload-time = "2026-06-12T20:02:47.091Z" }, + { url = "https://files.pythonhosted.org/packages/62/99/a2c95cf8293f07491e9e27c20cc4dcd18176d944e674679adeb1d0173fd6/cryptography-49.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:2eda353d8a27bcbcaa4cbed18994a74ab4d19a2ca897db188ea269ab9b71419b", size = 5309779, upload-time = "2026-06-12T20:02:08.987Z" }, + { url = "https://files.pythonhosted.org/packages/20/2c/0622f20ff02b2ef32558733443805dc82fd4c275be01b2d19d14676f3a1b/cryptography-49.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2afe9051da7ae7bd5905da5a949280c7d2bb75682e188f650a9d0f2756b834c6", size = 4749683, upload-time = "2026-06-12T20:02:03.335Z" }, + { url = "https://files.pythonhosted.org/packages/a3/5b/c5246635d5fd3b64e0d45ae10e99fd32fe9676a79915ccfe5a61ba9af1a5/cryptography-49.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:0b82e28ee398a386f0807bba7884d30f25218855690f45115831bcce5d90822c", size = 4337874, upload-time = "2026-06-12T20:02:54.323Z" }, + { url = "https://files.pythonhosted.org/packages/6d/88/05563c7fe2e914e87d1a536d06fe83e66b4e1d95cb593e05aea375531da8/cryptography-49.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ccac2bfebc306b862133e3bb71f3f6ee8bb525240089b2d952e4144b3a6d5da7", size = 4700283, upload-time = "2026-06-12T20:01:34.822Z" }, + { url = "https://files.pythonhosted.org/packages/c4/b6/d7696e4e890d6ae1469935164c9e5215c557671cb78d6e3f458ccceaa632/cryptography-49.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:d0527ce944105f257f605a827d6ebead966c752038b6e8656abb9c5edee6fc68", size = 5265844, upload-time = "2026-06-12T20:01:24.09Z" }, + { url = "https://files.pythonhosted.org/packages/a9/3c/f3ad17eecc1a57b0ba236dc01f90e783c51f4a2f35f64777cc4f47a184b2/cryptography-49.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:cbc77da8c523d5abd028635ba850a6966fcee2c82e2bf65a41d1d8afe0f98be9", size = 4749290, upload-time = "2026-06-12T20:01:30.848Z" }, + { url = "https://files.pythonhosted.org/packages/4f/01/339573cf1023163a400b0b5d16f6d507de413b9f60be6fd1b77feeaf6737/cryptography-49.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b87e65d263b3e5d3bb92a57e2a6638e2f31110fa7aa890c7b2dbba42248d0a3f", size = 4834612, upload-time = "2026-06-12T20:01:29.246Z" }, + { url = "https://files.pythonhosted.org/packages/71/fd/577302e213a1be9468f92d1afef66fcf1ef83d516819d9992ca547f592bd/cryptography-49.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:66ec79c3904820572d7e987abdf304281f141d37ad9a489b8e97066e7b9b6459", size = 4980804, upload-time = "2026-06-12T20:01:42.853Z" }, + { url = "https://files.pythonhosted.org/packages/1f/09/f42b1d190c5ba75f72062a387f8030d1d75f6ab035788f1d9c4b01de6525/cryptography-49.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:e5dfc1e64de5677cec922ffa8da89c546d0415bf6efdf081842e5d44c84e1f0e", size = 3810026, upload-time = "2026-06-12T20:02:39.262Z" }, + { url = "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:73a205dce83953d131a4aa1e0fd917a2fd1c5b1eef251e9d7152efefcbf5caf7", size = 4013892, upload-time = "2026-06-12T20:02:10.735Z" }, + { url = "https://files.pythonhosted.org/packages/86/12/c48a424f38db03027be9f7ed5c7dc5de9933dbee992865f98b13727a009d/cryptography-49.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:196ecd6a36e4e9aa10270393bb98d8df88fccee0bf1e5128b91ae4eb4375896d", size = 4678835, upload-time = "2026-06-12T20:02:48.743Z" }, + { url = "https://files.pythonhosted.org/packages/68/28/8a3ad4653662c93fc44dc4e5d8fd374c25c42e07b34bbfbadf49cf57a5a8/cryptography-49.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7abcee80084cda3f7691f3eb1ce480d8df49cec637b429aa35986c1de71738aa", size = 4697239, upload-time = "2026-06-12T20:02:56.03Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b2/2193fc74f81aee4f9b62733133b73b5176718932ed8f2e4b03fa040480a6/cryptography-49.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:4ae387c9cb68ea569ca17e490d66d8142b81c3cc814bf179974b7d146e490bbb", size = 4685593, upload-time = "2026-06-12T20:02:50.666Z" }, + { url = "https://files.pythonhosted.org/packages/47/f1/1d3eaa243bfc5de4a187b22aa8c048b3e4980bfbe830ac46e6bac2e66947/cryptography-49.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:f37d847238971164fdbc68ade6f6574aecc9c0af714190e2083429ff68f4ce9d", size = 5289961, upload-time = "2026-06-12T20:01:46.468Z" }, + { url = "https://files.pythonhosted.org/packages/58/39/2d51306721330c486495853eda1c567880ff036de15a14c4b74f399934af/cryptography-49.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:c2bc30226390d60ea19d9f82b19db005fe0452154a23c1c410c12ea801e43561", size = 4731145, upload-time = "2026-06-12T20:02:16.832Z" }, + { url = "https://files.pythonhosted.org/packages/17/50/983e838c7fd0d87fd8c969bcdd328edaf5f756e38df5281637424c155873/cryptography-49.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:07cab27cc7b7e0fd28e5e26bb9eeedde5c135c868b46de4a27845abe94af6122", size = 4321719, upload-time = "2026-06-12T20:02:52.611Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f5/8f571d7e27c55bce9f76f026143bcb1e040a4233149ecca0bea5fa5dd5f7/cryptography-49.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:b20133d204d2bb56ba047642199603876c872026ca53e79c35b83772ab2cc505", size = 4685209, upload-time = "2026-06-12T20:02:07.282Z" }, + { url = "https://files.pythonhosted.org/packages/e7/84/0e27016a6fc5a0886f797018b26aa42f40c09a82332bff77822a451deaaa/cryptography-49.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b970c6da94d5bb18629db453d14f2a1300f6bf59b61e9b82377931ef95504866", size = 5246285, upload-time = "2026-06-12T20:01:32.439Z" }, + { url = "https://files.pythonhosted.org/packages/11/2d/5e1fb307cb5931881516b464c98774b3f2c36b5d4bb9a2830253cf553cad/cryptography-49.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d8ecde755e2e91bf773fc94e8c9d730cd7f2007004cb492263a794ec3899a1c8", size = 4730441, upload-time = "2026-06-12T20:02:01.469Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c0/bff5a02ee731d207d6a1ed51732549d8c53d2bc8da1d10ec6f2844201d68/cryptography-49.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e3fb64c420688e5319ae25113a354015abbd8dffbfbc41781a1ea66fc7622ac3", size = 4815869, upload-time = "2026-06-12T20:01:36.574Z" }, + { url = "https://files.pythonhosted.org/packages/b9/26/814681d14248d95d73d5c3eea0c39a94eb8302df966f670a2c60de90974b/cryptography-49.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32703d93296f5c1f4b53349ad3a250c2cae0fdecd3a3dd5d47e616d8d616af27", size = 4960948, upload-time = "2026-06-12T20:02:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fe/93ecac273d3738939d023612ad12cca9a3740a5345d69fda04134c43fd96/cryptography-49.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:33cd0565932807baddb67b96dbee92f2c374b5c89dee09fd74079aeb8c8dba61", size = 3799153, upload-time = "2026-06-12T20:01:39.059Z" }, + { url = "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ec5e529fb80935c94fe7b729f9972b50e351a0e6b50aa294fd5cabb109fcc29a", size = 4025947, upload-time = "2026-06-12T20:01:25.745Z" }, + { url = "https://files.pythonhosted.org/packages/3d/df/40577043ca124e17012f408ddddaeb213b856336ac82ddb3bc915f39e29f/cryptography-49.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f78ff2c9ed8dc2d036b0f4d640e22522213d047c1b14e61205a7e55c80a494d4", size = 4692429, upload-time = "2026-06-12T20:01:53.628Z" }, + { url = "https://files.pythonhosted.org/packages/2c/99/2d13299eb3dd27b02dcfaafcc91d6b5cb3329f7cbd6d8f51921acd566c1a/cryptography-49.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:35b151772baff2c74cba7fa290ceaff4c3b11c0c881eb93eb5dbc05a7cfbba18", size = 4700968, upload-time = "2026-06-12T20:02:45.383Z" }, + { url = "https://files.pythonhosted.org/packages/a5/4d/9c0cd02f95e2602dd5e563da149ee0830abef3537be8b34dc56281ebe27a/cryptography-49.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0f21641cf4b30fca7aee061ced0ec7ad7b073518088b7c9969a297c0ae796c69", size = 4697758, upload-time = "2026-06-12T20:01:41.13Z" }, + { url = "https://files.pythonhosted.org/packages/24/01/186c825898477d77e2324d5360fefe622ff1d8d1963ec0554e2cada8ec77/cryptography-49.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9e82dcc8e56052715fb18b2429e3bca4823b1629136a2084fc45a9a5cecb9b64", size = 5298863, upload-time = "2026-06-12T20:02:24.579Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7b/62cbbab75d0659865bf0273790031544a0b16c8072d258f9428dcd8190dc/cryptography-49.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6f2debedf9ca60cf1d5bd466475638af5130f89965605cd818484d19987d3a21", size = 4735983, upload-time = "2026-06-12T20:01:50.14Z" }, + { url = "https://files.pythonhosted.org/packages/6c/72/3e798c064bc39e471008075d0f9bc9daf77a80879c092e4a8e170c585ed4/cryptography-49.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:8c25ceb16df5b9435f3f6a9829204985b0e0cbee3b48aacd432c7d2c850b44d9", size = 4334173, upload-time = "2026-06-12T20:01:44.743Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ee/6fca21d1ac73e06f8bef71940abfd4d2f6472b4bca284d770f32bd4086f6/cryptography-49.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:28d8b15e6275f12c8a207dc309dfa957903c927d08d0cc937ee3f63f200693cc", size = 4697298, upload-time = "2026-06-12T20:02:20.918Z" }, + { url = "https://files.pythonhosted.org/packages/67/d0/a5fcd3515f0bae49a7b6d0413cc1bdccdcc1fc0047037a0d480642cdc5d6/cryptography-49.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6fc361c34fb6aac015ce19435876635e5c6d21db31998b0920f675f131e043b8", size = 5254338, upload-time = "2026-06-12T20:02:22.737Z" }, + { url = "https://files.pythonhosted.org/packages/a0/84/84fe36f19caf857d61cb7fc9c63035a47ffabd84ea12d1d393148efa3615/cryptography-49.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2400ef9c9e2299a25614eb1dea3db54a69b1349efd043bfac9c67630d136df36", size = 4735650, upload-time = "2026-06-12T20:02:41.389Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a0/db537264e234f7273a73ec020873d6d6b39dfd8a53db78b550ca8320440e/cryptography-49.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:67e1d20ad9ef3a563c59ef22e7a8a0b8210bd26604369ea4a30a7c66aefe504e", size = 4834820, upload-time = "2026-06-12T20:01:51.847Z" }, + { url = "https://files.pythonhosted.org/packages/93/77/8df9eb486495979bccecd1062e2eaf435250e84437040295b57d09048b0b/cryptography-49.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:42b0684e0e40cf26122427802486f6d93aea593612603a94fbf260c7eb1e9c1b", size = 4967968, upload-time = "2026-06-12T20:02:12.524Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e6/f60198ea8d9dfa15fff9ed4ca02ce362f6eadd9ba757dcc50634c4257b63/cryptography-49.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:026ac7423e6fa66872d3bf889be5974507da3944f866f704fa200eadacd00001", size = 3785547, upload-time = "2026-06-12T20:02:26.847Z" }, + { url = "https://files.pythonhosted.org/packages/63/d3/4a83af35d65e3fad632c926fad684c193ea4398569ccb0bbbc7fe8f5dc9a/cryptography-49.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:fc1e275c2f1d97b1a6450b8b0ea3ebfa6e087a611c2b26cb2404d48588abab7b", size = 3993685, upload-time = "2026-06-12T20:02:14.883Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a7/f9dac0ab7f80368c56993a7bf638ef9935f825c91902798481fac0898138/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83782480a4a9da4d0feb51950131ba32e12e70813848b3343f6e18c28a66838", size = 4676239, upload-time = "2026-06-12T20:02:28.793Z" }, + { url = "https://files.pythonhosted.org/packages/d7/70/2ba3769dd0ae167e2f33dfa9592d45db6ff9a61d62ca1a5b3d1bdd09068f/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b39efa323140595abd3ecca8529d321ae50f55f3aa3ba9cc81ea56a6011953d5", size = 4715584, upload-time = "2026-06-12T20:01:27.495Z" }, + { url = "https://files.pythonhosted.org/packages/94/64/2923570ac1c0bd3a737aa366ac3abbbbde273042308b8cde95e2364a6e6a/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:b47db11c2c3525083296069b98ac5221907455e989ae0c2e3008bde851921615", size = 4675885, upload-time = "2026-06-12T20:01:55.49Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f8/614dc7e051418cfe53d55173c1e24c6b0085e89996fe90508c2fdf769aef/cryptography-49.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:084ef1af862eb07ec46d25f68689f2102a9fc0e05ce7b80f14f5fe51e4eef0f6", size = 4715449, upload-time = "2026-06-12T20:02:05.469Z" }, + { url = "https://files.pythonhosted.org/packages/aa/50/a9caea39ad19c431c1a3f8a31114df65b260cdfe67786b6c7e7c040c4c44/cryptography-49.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be9fcb48a55f023493482827d4f459bd263cc20efde64f204b97c123201850c6", size = 3783731, upload-time = "2026-06-12T20:02:43.319Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "gnureadline" +version = "8.3.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/33/d0a1a41e687f0d1956cc5a7b07735c6893f3fa061440fddb7a2c9d2bcd35/gnureadline-8.3.3.tar.gz", hash = "sha256:0972392bd2f31244e2d981178246fe8b729c8766454fdaeb275946ac47b7e9fd", size = 3595875, upload-time = "2026-01-06T15:03:17.802Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/f8/89e78ddcd8cc4589406d009184647c0bdcbfaf209f8a96005a7d0c1c272f/gnureadline-8.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a0427e9f75a0407391bdc2e0e76b06807b50a0e1fb73cf99b3d40a4dd1299c43", size = 166883, upload-time = "2026-01-06T15:03:54.181Z" }, + { url = "https://files.pythonhosted.org/packages/2e/42/1d5b155b980953cd27400f7107f6c38661f88482442ea27379614e6689d7/gnureadline-8.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:87a8d9ba3e87c495b9388ef5566a647d7ab1db345b841c745ae2c21033a37856", size = 166878, upload-time = "2026-01-06T15:03:55.497Z" }, + { url = "https://files.pythonhosted.org/packages/74/9a/1a9b7c9b7b03022d8dfa02e17f66e819ef377c7c48cf91173826422382e1/gnureadline-8.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fff8def8a9ec595e6dd9186bc4fc7061aaee34e4a0b762b120ef2398bbbbafc8", size = 166892, upload-time = "2026-01-06T15:04:00.751Z" }, + { url = "https://files.pythonhosted.org/packages/f6/a8/c5bb8a49dcea7819ce1a5816365f6aa15bc04efb91cc820dd985a55b9362/gnureadline-8.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa03cc35adeddb05412fda494b3d6851e810401341aa7abee7347f116dc74ad6", size = 166898, upload-time = "2026-01-06T15:04:02.192Z" }, + { url = "https://files.pythonhosted.org/packages/ce/29/cad97d1e8fc3102169a84f8fbf299b7306ebe27c2523dd0e441b40b29646/gnureadline-8.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:04ad9724dd1783d140146a1e83313918741975c1226a5dfa1b2e97560d8e36c7", size = 166926, upload-time = "2026-01-06T15:04:06.588Z" }, + { url = "https://files.pythonhosted.org/packages/76/80/fadacc11c6ebba0a49e66c1279c95dfc4caeb3bcf05da8965fc2efb5f163/gnureadline-8.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:831599cd9fea95eae2110646d274ed0fe0e0c20cf32e0eb01a5225d9dad4f1b4", size = 166744, upload-time = "2026-01-06T15:04:07.714Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a6/69fc7b54bbc74797c8ede68904b6b1f3fe9c891f1bb6be12a6b40d5aa76c/gnureadline-8.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14df36d06f8102caadff0df0a87ba33b381c2b22904f0ed2ad527784f5ec9f46", size = 167501, upload-time = "2026-01-06T15:04:11.297Z" }, + { url = "https://files.pythonhosted.org/packages/12/ae/1a20910eee2582eab73c4aea1ff6bd71ba78e0d12d58cddec32e7936fb42/gnureadline-8.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75519fea565510a868389cd841e45d64140a323d723dda30edf72009c2e3362f", size = 167327, upload-time = "2026-01-06T15:04:12.401Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ea/93d9bcccb3f0b02f9cf07c57c2492512f75b27d82fb722629698edf5356b/gnureadline-8.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8012e70db91f13409f36655a10f9752c43d9848de6d1ed379b526f3f8a449a44", size = 168490, upload-time = "2026-01-06T15:04:16.526Z" }, + { url = "https://files.pythonhosted.org/packages/6e/85/fd0f7fce581c56a45e2d53e34c29c9b82b6c3fd082533872e54d105a1bf5/gnureadline-8.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:da1335bdc70fc99f45578d7cdeb89bd5a16e0d26785bbe5bcc1dc1acdd7a7734", size = 168265, upload-time = "2026-01-06T15:04:18.262Z" }, + { url = "https://files.pythonhosted.org/packages/0c/b7/f8c9be26236c376c796a8b6ada0d4efe9bc604843d97c5bef0b86b4e865f/gnureadline-8.3.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:251495414ee34dd7f068e0c4f09ee46f068e0e08a75428a7fbdf41a8ffa8bb27", size = 167489, upload-time = "2026-01-06T15:04:22.465Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2b/ec2958df1bbb878d56c29b5ef7fbf1f1eb2c3b27bb3e9e1b4bff71a7dfad/gnureadline-8.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8513db40b4c5404ad3e883ad747e0cf113ec7b0b884dff1f6f873f9a1c1d2432", size = 167309, upload-time = "2026-01-06T15:04:23.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/bc/f32652ca2e685ad11862a3b9976d0ff7bccdf476cd60921fba144b65cd41/gnureadline-8.3.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:dfd893dac7b63f71dc41dce5d31c05388e55cb7bc6b58535e2a0eb29a5ad0352", size = 168590, upload-time = "2026-01-06T15:04:28.266Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8e/30a82d454640430a472660727f16c7804848a4f4af4f0bbfca410bc4250d/gnureadline-8.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1a954229ac14210f8efbbd724184f26a09a5b85ddb027a1f4ab64c22da59cf69", size = 168268, upload-time = "2026-01-06T15:04:29.467Z" }, +] + +[[package]] +name = "icspacket" +source = { editable = "." } +dependencies = [ + { name = "asyncua" }, + { name = "bitarray" }, + { name = "caterpillar-py" }, + { name = "cmd2", version = "3.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "cmd2", version = "4.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "crcmod" }, + { name = "pymodbus" }, + { name = "rich" }, + { name = "scapy" }, + { name = "typing-extensions" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "asyncua", specifier = ">=1.1" }, + { name = "bitarray" }, + { name = "caterpillar-py" }, + { name = "cmd2" }, + { name = "crcmod" }, + { name = "pymodbus", specifier = ">=3.8.6" }, + { name = "rich" }, + { name = "scapy" }, + { name = "typing-extensions" }, +] + +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=9.1.1" }] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pymodbus" +version = "3.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/55/ea2a6bb2e61926013df736cf7bba2405caafad36ab919bc6104c3cad1ea0/pymodbus-3.14.0.tar.gz", hash = "sha256:f1f486ec45b77b7565c5168c9609e244a4a6428d386f3cff56eb85a2297cd10c", size = 165886, upload-time = "2026-07-12T14:22:48.02Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/18/614c8e62787b5057317c1f59e632ee842717c169f4d27440b724ade19d9f/pymodbus-3.14.0-py3-none-any.whl", hash = "sha256:408f7a9594073a979e7749f0225508b8491ef74fa1979c81011dee96a7a7570c", size = 166539, upload-time = "2026-07-12T14:22:46.391Z" }, +] + +[[package]] +name = "pyopenssl" +version = "26.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/b7/da07bae88f5a9506b4def6f2f4903cf4c3b8831e560dba8fa18ca08f758f/pyopenssl-26.3.0.tar.gz", hash = "sha256:589de7fae1c9ea670d18422ed00fc04da787bbde8e1454aea872aa57b49ad341", size = 182024, upload-time = "2026-06-12T20:28:07.458Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl", hash = "sha256:46367f8f66b92271e6d218da9c87607e1ef5a0bc5c8dea5bb3db82f395c385a3", size = 56008, upload-time = "2026-06-12T20:28:05.999Z" }, +] + +[[package]] +name = "pyperclip" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/52/d87eba7cb129b81563019d1679026e7a112ef76855d6159d24754dbd2a51/pyperclip-1.11.0.tar.gz", hash = "sha256:244035963e4428530d9e3a6101a1ef97209c6825edab1567beac148ccc1db1b6", size = 12185, upload-time = "2025-09-26T14:40:37.245Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl", hash = "sha256:299403e9ff44581cb9ba2ffeed69c7aa96a008622ad0c46cb575ca75b5b84273", size = 11063, upload-time = "2025-09-26T14:40:36.069Z" }, +] + +[[package]] +name = "pyreadline3" +version = "3.5.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/6d/f94028646d7bbe6d9d873c47ee7c246f2d29129d253f0d96cb6fcab70733/pyreadline3-3.5.6.tar.gz", hash = "sha256:61e53218b99656091ddb077df9e71f25850e72e030b6183b39c9b7e6e4f4a9bf", size = 100368, upload-time = "2026-05-14T17:55:04.471Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/5e/35c856e186b74678c24927847ad9895a51f1bc02a0c6126477a6c6040064/pyreadline3-3.5.6-py3-none-any.whl", hash = "sha256:8449b734232e42a5dcd74048e39b60db2839a4c38cf3ae2bf7707d58b5389c0d", size = 85243, upload-time = "2026-05-14T17:55:03.262Z" }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pytz" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a", size = 320861, upload-time = "2026-05-04T01:35:29.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", size = 510141, upload-time = "2026-05-04T01:35:27.408Z" }, +] + +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + +[[package]] +name = "rich-argparse" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "rich" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/e5/1064c43203a357d668cd42435f7a15fe6af51512d85b2104fecb937aa861/rich_argparse-1.8.0.tar.gz", hash = "sha256:679df3d832fa94ad6e4bdb07ded088cd7ea2dddc58ae9b2b46346a40b06cbc0c", size = 38940, upload-time = "2026-05-01T15:18:43.604Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/35/1cceccc5fcb50fa2ed53e2aa278cd032f3902682a73e763fb1ac3be8e6fa/rich_argparse-1.8.0-py3-none-any.whl", hash = "sha256:d2a3ce7854654e2253c578763ab0a32f05016f23a55fadba7b9a91b6c0e92142", size = 25616, upload-time = "2026-05-01T15:18:42.395Z" }, +] + +[[package]] +name = "scapy" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/97/7caec64f05eae3d305d83e7cce1ef2f337710513b89efb334f7278202e79/scapy-2.7.0.tar.gz", hash = "sha256:bfc1ef1b93280aea1ddee53be7f74232aa28ac3d891244d41ee85200d24aa446", size = 2412897, upload-time = "2025-12-26T22:10:53.359Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/6f/bd32e5e8adc391063858da17271bb444e4b009842cffa593bca8b2b78af7/scapy-2.7.0-py3-none-any.whl", hash = "sha256:eb22786da92be6fd8e5c694ae5595e4f5b9ac1f4364c9c45986844f3e3063561", size = 2590982, upload-time = "2025-12-26T22:07:48.941Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sortedcontainers" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, + { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, + { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, + { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, + { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, + { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "wait-for2" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/7c/ea09d6a11990a8aa3ceac206fb7ea82366ea2c200caa87966611e0e18597/wait_for2-0.4.1.tar.gz", hash = "sha256:7f415415d21845c441391d6b4abe68f5959d2c0fbe927c2f61be28a297bc2acb", size = 17519, upload-time = "2025-06-13T19:45:00.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/56/0f88040567af7ff376ec9eaabe18fd980a4f5089d3bf8c7a32598ef06b8d/wait_for2-0.4.1-py3-none-any.whl", hash = "sha256:c694503e8c7420929e8a86bcffd9b00d55acaec2c14223a2b1e92bdc2ebf2154", size = 10985, upload-time = "2025-06-13T19:44:58.82Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/74/c6428f875774288bec1396f5bfcbc2d925700a4dad61727fd5f2b12f249d/wcwidth-0.8.2.tar.gz", hash = "sha256:91fbef97204b96a3d4d421609b80340b760cf33e26da123ff243d76b1fda8dda", size = 1466253, upload-time = "2026-06-29T18:11:11.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl", hash = "sha256:d63947694a0539a1d51e01eda7caf800c291020e6cdd7e28ad7b14dd33ad4f85", size = 323166, upload-time = "2026-06-29T18:11:09.888Z" }, +]