docs/agents/python-standards.md
Use modern PEP 585 and PEP 604 type hints (Python 3.11+ native syntax):
list[T], dict[K, V], set[T] instead of List[T], Dict[K, V], Set[T]X | Y for unions instead of Union[X, Y]T | None instead of Optional[T]from __future__ import annotations (works natively in Python 3.11+)Prefer @dataclass over tuples and dicts for function return types:
@dataclass with named fields (e.g., CompileResult(success=True, error_output=""))tuple[bool, str] or dict[str, Any] -- unnamed fields are error-prone and hard to readdivmod) don't need a dataclassKeyboardInterrupt exceptionsException, ALWAYS explicitly re-raise KeyboardInterrupt first:
try:
operation()
except KeyboardInterrupt:
raise # MANDATORY: Always re-raise KeyboardInterrupt
except Exception as e:
logger.error(f"Operation failed: {e}")
from ci.util.global_interrupt_handler import notify_main_thread
try:
# Worker thread operation
operation()
except KeyboardInterrupt:
print("KeyboardInterrupt: Cancelling operation")
notify_main_thread() # Propagate interrupt to main thread
raise
notify_main_thread() calls _thread.interrupt_main() to ensure the main thread receives the interrupt signal--select BLE001 for automatic detectionsubprocess.run() or subprocess.Popen() directly — use RunningProcess.run() insteadRunningProcess (from the running_process package) wraps subprocess with proper timeout handling, streaming, and interrupt propagationsubprocess is problematic: missing real-time output streaming, inconsistent timeout behavior, and no integration with the project's interrupt handlingfrom running_process import RunningProcess
result = RunningProcess.run(["git", "status"], check=False, timeout=10, capture_output=True, text=True)
print(result.stdout)
import subprocess
result = subprocess.run(["git", "status"], capture_output=True, text=True)