[Lldb-commits] [lldb] [llvm] [lldb] Add type hints to gdbclientutils.py and use abstract base class (PR #162172)
Daniel Sanders via lldb-commits
lldb-commits at lists.llvm.org
Thu Oct 9 14:33:19 PDT 2025
https://github.com/dsandersllvm updated https://github.com/llvm/llvm-project/pull/162172
>From bd8a1e123b468c5e9f2251d2a7f55d9c22069396 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Fri, 3 Oct 2025 20:05:11 -0700
Subject: [PATCH 1/4] [lldb] Add type hints to gdbclientutils.py and fix issues
Everything in this should be python 3.9. The docs say the minimum is 3.8
but there's existing code in this suite that needs 3.9 so I think 3.9 is
ok.
Issues:
qEcho() is passed an argument by the callers that the function didn't have
Several functions in the base class would silently do nothing if not
overriden. These now use @abstractmethod to require overrides
sendall() had inconsistent return types between overrides
---
.../Python/lldbsuite/test/gdbclientutils.py | 70 ++++++++++++-------
1 file changed, 43 insertions(+), 27 deletions(-)
diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index b603c35c8df09..5fe1bc3155386 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -1,3 +1,4 @@
+from abc import ABC, abstractmethod
import ctypes
import errno
import io
@@ -5,6 +6,7 @@
import socket
import traceback
from lldbsuite.support import seven
+from typing import Optional
def checksum(message):
@@ -86,8 +88,8 @@ class MockGDBServerResponder:
handles any packet not recognized in the common packet handling code.
"""
- registerCount = 40
- packetLog = None
+ registerCount: int = 40
+ packetLog: Optional[list[str]] = None
class RESPONSE_DISCONNECT:
pass
@@ -103,6 +105,7 @@ def respond(self, packet):
Return the unframed packet data that the server should issue in response
to the given packet received from the client.
"""
+ assert self.packetLog is not None
self.packetLog.append(packet)
if packet is MockGDBServer.PACKET_INTERRUPT:
return self.interrupt()
@@ -242,7 +245,7 @@ def qProcessInfo(self):
def qHostInfo(self):
return "ptrsize:8;endian:little;"
- def qEcho(self):
+ def qEcho(self, _: int):
return "E04"
def qQueryGDBServer(self):
@@ -263,10 +266,10 @@ def A(self, packet):
def D(self, packet):
return "OK"
- def readRegisters(self):
+ def readRegisters(self) -> str:
return "00000000" * self.registerCount
- def readRegister(self, register):
+ def readRegister(self, register: int) -> str:
return "00000000"
def writeRegisters(self, registers_hex):
@@ -306,7 +309,8 @@ def haltReason(self):
# SIGINT is 2, return type is 2 digit hex string
return "S02"
- def qXferRead(self, obj, annex, offset, length):
+ def qXferRead(self, obj: str, annex: str, offset: int,
+ length: int) -> tuple[str | None, bool]:
return None, False
def _qXferResponse(self, data, has_more):
@@ -374,15 +378,17 @@ class UnexpectedPacketException(Exception):
pass
-class ServerChannel:
+class ServerChannel(ABC):
"""
A wrapper class for TCP or pty-based server.
"""
- def get_connect_address(self):
+ @abstractmethod
+ def get_connect_address(self) -> str:
"""Get address for the client to connect to."""
- def get_connect_url(self):
+ @abstractmethod
+ def get_connect_url(self) -> str:
"""Get URL suitable for process connect command."""
def close_server(self):
@@ -394,10 +400,12 @@ def accept(self):
def close_connection(self):
"""Close all resources used by the accepted connection."""
- def recv(self):
+ @abstractmethod
+ def recv(self) -> bytes:
"""Receive a data packet from the connected client."""
- def sendall(self, data):
+ @abstractmethod
+ def sendall(self, data: bytes) -> None:
"""Send the data to the connected client."""
@@ -428,11 +436,11 @@ def close_connection(self):
self._connection.close()
self._connection = None
- def recv(self):
+ def recv(self) -> bytes:
assert self._connection is not None
return self._connection.recv(4096)
- def sendall(self, data):
+ def sendall(self, data: bytes) -> None:
assert self._connection is not None
return self._connection.sendall(data)
@@ -444,10 +452,10 @@ def __init__(self):
)[0]
super().__init__(family, type, proto, addr)
- def get_connect_address(self):
+ def get_connect_address(self) -> str:
return "[{}]:{}".format(*self._server_socket.getsockname())
- def get_connect_url(self):
+ def get_connect_url(self) -> str:
return "connect://" + self.get_connect_address()
@@ -455,10 +463,10 @@ class UnixServerSocket(ServerSocket):
def __init__(self, addr):
super().__init__(socket.AF_UNIX, socket.SOCK_STREAM, 0, addr)
- def get_connect_address(self):
+ def get_connect_address(self) -> str:
return self._server_socket.getsockname()
- def get_connect_url(self):
+ def get_connect_url(self) -> str:
return "unix-connect://" + self.get_connect_address()
@@ -472,7 +480,7 @@ def __init__(self):
self._primary = io.FileIO(primary, "r+b")
self._secondary = io.FileIO(secondary, "r+b")
- def get_connect_address(self):
+ def get_connect_address(self) -> str:
libc = ctypes.CDLL(None)
libc.ptsname.argtypes = (ctypes.c_int,)
libc.ptsname.restype = ctypes.c_char_p
@@ -485,7 +493,7 @@ def close_server(self):
self._secondary.close()
self._primary.close()
- def recv(self):
+ def recv(self) -> bytes:
try:
return self._primary.read(4096)
except OSError as e:
@@ -494,8 +502,8 @@ def recv(self):
return b""
raise
- def sendall(self, data):
- return self._primary.write(data)
+ def sendall(self, data: bytes) -> None:
+ self._primary.write(data)
class MockGDBServer:
@@ -528,18 +536,21 @@ def stop(self):
self._thread.join()
self._thread = None
- def get_connect_address(self):
+ def get_connect_address(self) -> str:
+ assert self._socket is not None
return self._socket.get_connect_address()
- def get_connect_url(self):
+ def get_connect_url(self) -> str:
+ assert self._socket is not None
return self._socket.get_connect_url()
def run(self):
+ assert self._socket is not None
# For testing purposes, we only need to worry about one client
# connecting just one time.
try:
self._socket.accept()
- except:
+ except Exception:
traceback.print_exc()
return
self._shouldSendAck = True
@@ -554,7 +565,7 @@ def run(self):
self._receive(data)
except self.TerminateConnectionException:
pass
- except Exception as e:
+ except Exception:
print(
"An exception happened when receiving the response from the gdb server. Closing the client..."
)
@@ -587,7 +598,9 @@ def _parsePacket(self):
Once a complete packet is found at the front of self._receivedData,
its data is removed form self._receivedData.
"""
+ assert self._receivedData is not None
data = self._receivedData
+ assert self._receivedDataOffset is not None
i = self._receivedDataOffset
data_len = len(data)
if data_len == 0:
@@ -640,10 +653,13 @@ def _parsePacket(self):
self._receivedDataOffset = 0
return packet
- def _sendPacket(self, packet):
- self._socket.sendall(seven.bitcast_to_bytes(frame_packet(packet)))
+ def _sendPacket(self, packet: str):
+ assert self._socket is not None
+ framed_packet = seven.bitcast_to_bytes(frame_packet(packet))
+ self._socket.sendall(framed_packet)
def _handlePacket(self, packet):
+ assert self._socket is not None
if packet is self.PACKET_ACK:
# Ignore ACKs from the client. For the future, we can consider
# adding validation code to make sure the client only sends ACKs
>From 89c90a87126cb4b88d5356bca6f0e3073712597c Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Tue, 7 Oct 2025 16:01:24 -0700
Subject: [PATCH 2/4] fixup: formatting using darker
---
lldb/packages/Python/lldbsuite/test/gdbclientutils.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index 5fe1bc3155386..8797acba5bd24 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -309,8 +309,9 @@ def haltReason(self):
# SIGINT is 2, return type is 2 digit hex string
return "S02"
- def qXferRead(self, obj: str, annex: str, offset: int,
- length: int) -> tuple[str | None, bool]:
+ def qXferRead(
+ self, obj: str, annex: str, offset: int, length: int
+ ) -> tuple[str | None, bool]:
return None, False
def _qXferResponse(self, data, has_more):
>From 3ee4b0964937dcbc6c80a33104b003583bdb695f Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Thu, 9 Oct 2025 14:31:08 -0700
Subject: [PATCH 3/4] fixup: Change python 3.9 and 3.10 usage to be 3.8
---
lldb/packages/Python/lldbsuite/test/gdbclientutils.py | 6 +++---
pyproject.toml | 3 +++
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index 8797acba5bd24..ae660382abde3 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -6,7 +6,7 @@
import socket
import traceback
from lldbsuite.support import seven
-from typing import Optional
+from typing import Optional, List, Tuple
def checksum(message):
@@ -89,7 +89,7 @@ class MockGDBServerResponder:
"""
registerCount: int = 40
- packetLog: Optional[list[str]] = None
+ packetLog: Optional[List[str]] = None
class RESPONSE_DISCONNECT:
pass
@@ -311,7 +311,7 @@ def haltReason(self):
def qXferRead(
self, obj: str, annex: str, offset: int, length: int
- ) -> tuple[str | None, bool]:
+ ) -> Tuple[Optional[str], bool]:
return None, False
def _qXferResponse(self, data, has_more):
diff --git a/pyproject.toml b/pyproject.toml
index b8313eb9fca45..cc5c446b80d8d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,3 +4,6 @@ extend-exclude = '''
third-party/
)
'''
+
+[tool.pyright]
+pythonVersion = "3.8"
>From 3e3bda5be922c2ccb036ad8db16add27a7676253 Mon Sep 17 00:00:00 2001
From: Daniel Sanders <daniel_l_sanders at apple.com>
Date: Thu, 9 Oct 2025 14:32:09 -0700
Subject: [PATCH 4/4] fixup: Name qEcho's unused parameter
This does cause pyright to report the unused parameter though
---
lldb/packages/Python/lldbsuite/test/gdbclientutils.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index ae660382abde3..5d3fcad49f7b9 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -245,7 +245,7 @@ def qProcessInfo(self):
def qHostInfo(self):
return "ptrsize:8;endian:little;"
- def qEcho(self, _: int):
+ def qEcho(self, num: int):
return "E04"
def qQueryGDBServer(self):
More information about the lldb-commits
mailing list