from dataclasses import dataclass import pyudev @dataclass class USBDevice: vendor_id: str | None product_id: str | None vendor: str | None product: str | None serial: str | None @property def id(self) -> str | None: if self.vendor_id is None or self.product_id is None: return None return f"{self.vendor_id}:{self.product_id}" @property def name(self) -> str: return f"{self.vendor} {self.product}" class USBDevices: def __init__(self): self.context = pyudev.Context() def enumerate(self) -> list[USBDevice]: devices = [] for device in self.context.list_devices( subsystem="usb", DEVTYPE="usb_device" ): usb_device = USBDevice( vendor_id=device.get("ID_VENDOR_ID"), product_id=device.get("ID_MODEL_ID"), vendor=device.get("ID_VENDOR"), product=device.get("ID_MODEL"), serial=device.get("ID_SERIAL_SHORT"), ) if self._is_valid_device(usb_device): devices.append(usb_device) return devices @staticmethod def _is_valid_device(device: USBDevice) -> bool: # Exclude Linux USB root hubs if device.vendor_id == "1d6b": return False return True if __name__ == "__main__": devices = USBDevices() enumerated = devices.enumerate() #print(devices.enumerate()) for device in enumerated: print(device.id, device.name)