Skip to content

Commit bd8a1e1

Browse files
committed
[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
1 parent 1b30e49 commit bd8a1e1

File tree

1 file changed

+43
-27
lines changed

1 file changed

+43
-27
lines changed

lldb/packages/Python/lldbsuite/test/gdbclientutils.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
from abc import ABC, abstractmethod
12
import ctypes
23
import errno
34
import io
45
import threading
56
import socket
67
import traceback
78
from lldbsuite.support import seven
9+
from typing import Optional
810

911

1012
def checksum(message):
@@ -86,8 +88,8 @@ class MockGDBServerResponder:
8688
handles any packet not recognized in the common packet handling code.
8789
"""
8890

89-
registerCount = 40
90-
packetLog = None
91+
registerCount: int = 40
92+
packetLog: Optional[list[str]] = None
9193

9294
class RESPONSE_DISCONNECT:
9395
pass
@@ -103,6 +105,7 @@ def respond(self, packet):
103105
Return the unframed packet data that the server should issue in response
104106
to the given packet received from the client.
105107
"""
108+
assert self.packetLog is not None
106109
self.packetLog.append(packet)
107110
if packet is MockGDBServer.PACKET_INTERRUPT:
108111
return self.interrupt()
@@ -242,7 +245,7 @@ def qProcessInfo(self):
242245
def qHostInfo(self):
243246
return "ptrsize:8;endian:little;"
244247

245-
def qEcho(self):
248+
def qEcho(self, _: int):
246249
return "E04"
247250

248251
def qQueryGDBServer(self):
@@ -263,10 +266,10 @@ def A(self, packet):
263266
def D(self, packet):
264267
return "OK"
265268

266-
def readRegisters(self):
269+
def readRegisters(self) -> str:
267270
return "00000000" * self.registerCount
268271

269-
def readRegister(self, register):
272+
def readRegister(self, register: int) -> str:
270273
return "00000000"
271274

272275
def writeRegisters(self, registers_hex):
@@ -306,7 +309,8 @@ def haltReason(self):
306309
# SIGINT is 2, return type is 2 digit hex string
307310
return "S02"
308311

309-
def qXferRead(self, obj, annex, offset, length):
312+
def qXferRead(self, obj: str, annex: str, offset: int,
313+
length: int) -> tuple[str | None, bool]:
310314
return None, False
311315

312316
def _qXferResponse(self, data, has_more):
@@ -374,15 +378,17 @@ class UnexpectedPacketException(Exception):
374378
pass
375379

376380

377-
class ServerChannel:
381+
class ServerChannel(ABC):
378382
"""
379383
A wrapper class for TCP or pty-based server.
380384
"""
381385

382-
def get_connect_address(self):
386+
@abstractmethod
387+
def get_connect_address(self) -> str:
383388
"""Get address for the client to connect to."""
384389

385-
def get_connect_url(self):
390+
@abstractmethod
391+
def get_connect_url(self) -> str:
386392
"""Get URL suitable for process connect command."""
387393

388394
def close_server(self):
@@ -394,10 +400,12 @@ def accept(self):
394400
def close_connection(self):
395401
"""Close all resources used by the accepted connection."""
396402

397-
def recv(self):
403+
@abstractmethod
404+
def recv(self) -> bytes:
398405
"""Receive a data packet from the connected client."""
399406

400-
def sendall(self, data):
407+
@abstractmethod
408+
def sendall(self, data: bytes) -> None:
401409
"""Send the data to the connected client."""
402410

403411

@@ -428,11 +436,11 @@ def close_connection(self):
428436
self._connection.close()
429437
self._connection = None
430438

431-
def recv(self):
439+
def recv(self) -> bytes:
432440
assert self._connection is not None
433441
return self._connection.recv(4096)
434442

435-
def sendall(self, data):
443+
def sendall(self, data: bytes) -> None:
436444
assert self._connection is not None
437445
return self._connection.sendall(data)
438446

@@ -444,21 +452,21 @@ def __init__(self):
444452
)[0]
445453
super().__init__(family, type, proto, addr)
446454

447-
def get_connect_address(self):
455+
def get_connect_address(self) -> str:
448456
return "[{}]:{}".format(*self._server_socket.getsockname())
449457

450-
def get_connect_url(self):
458+
def get_connect_url(self) -> str:
451459
return "connect://" + self.get_connect_address()
452460

453461

454462
class UnixServerSocket(ServerSocket):
455463
def __init__(self, addr):
456464
super().__init__(socket.AF_UNIX, socket.SOCK_STREAM, 0, addr)
457465

458-
def get_connect_address(self):
466+
def get_connect_address(self) -> str:
459467
return self._server_socket.getsockname()
460468

461-
def get_connect_url(self):
469+
def get_connect_url(self) -> str:
462470
return "unix-connect://" + self.get_connect_address()
463471

464472

@@ -472,7 +480,7 @@ def __init__(self):
472480
self._primary = io.FileIO(primary, "r+b")
473481
self._secondary = io.FileIO(secondary, "r+b")
474482

475-
def get_connect_address(self):
483+
def get_connect_address(self) -> str:
476484
libc = ctypes.CDLL(None)
477485
libc.ptsname.argtypes = (ctypes.c_int,)
478486
libc.ptsname.restype = ctypes.c_char_p
@@ -485,7 +493,7 @@ def close_server(self):
485493
self._secondary.close()
486494
self._primary.close()
487495

488-
def recv(self):
496+
def recv(self) -> bytes:
489497
try:
490498
return self._primary.read(4096)
491499
except OSError as e:
@@ -494,8 +502,8 @@ def recv(self):
494502
return b""
495503
raise
496504

497-
def sendall(self, data):
498-
return self._primary.write(data)
505+
def sendall(self, data: bytes) -> None:
506+
self._primary.write(data)
499507

500508

501509
class MockGDBServer:
@@ -528,18 +536,21 @@ def stop(self):
528536
self._thread.join()
529537
self._thread = None
530538

531-
def get_connect_address(self):
539+
def get_connect_address(self) -> str:
540+
assert self._socket is not None
532541
return self._socket.get_connect_address()
533542

534-
def get_connect_url(self):
543+
def get_connect_url(self) -> str:
544+
assert self._socket is not None
535545
return self._socket.get_connect_url()
536546

537547
def run(self):
548+
assert self._socket is not None
538549
# For testing purposes, we only need to worry about one client
539550
# connecting just one time.
540551
try:
541552
self._socket.accept()
542-
except:
553+
except Exception:
543554
traceback.print_exc()
544555
return
545556
self._shouldSendAck = True
@@ -554,7 +565,7 @@ def run(self):
554565
self._receive(data)
555566
except self.TerminateConnectionException:
556567
pass
557-
except Exception as e:
568+
except Exception:
558569
print(
559570
"An exception happened when receiving the response from the gdb server. Closing the client..."
560571
)
@@ -587,7 +598,9 @@ def _parsePacket(self):
587598
Once a complete packet is found at the front of self._receivedData,
588599
its data is removed form self._receivedData.
589600
"""
601+
assert self._receivedData is not None
590602
data = self._receivedData
603+
assert self._receivedDataOffset is not None
591604
i = self._receivedDataOffset
592605
data_len = len(data)
593606
if data_len == 0:
@@ -640,10 +653,13 @@ def _parsePacket(self):
640653
self._receivedDataOffset = 0
641654
return packet
642655

643-
def _sendPacket(self, packet):
644-
self._socket.sendall(seven.bitcast_to_bytes(frame_packet(packet)))
656+
def _sendPacket(self, packet: str):
657+
assert self._socket is not None
658+
framed_packet = seven.bitcast_to_bytes(frame_packet(packet))
659+
self._socket.sendall(framed_packet)
645660

646661
def _handlePacket(self, packet):
662+
assert self._socket is not None
647663
if packet is self.PACKET_ACK:
648664
# Ignore ACKs from the client. For the future, we can consider
649665
# adding validation code to make sure the client only sends ACKs

0 commit comments

Comments
 (0)