Easy USB access for Python with backend-neutral, cross-platform support
—
Pluggable backend architecture supporting multiple USB libraries with automatic backend detection and configuration. PyUSB's backend system provides abstraction over different USB implementations while maintaining consistent API behavior.
Abstract base class defining the backend interface that all USB backends must implement.
class IBackend:
"""
Abstract backend interface for USB operations.
All USB backends must implement this interface to provide
USB device access through different underlying libraries.
"""
def enumerate_devices(self):
"""Enumerate available USB devices."""
def open_device(self, device):
"""Open device for communication."""
def close_device(self, device_handle):
"""Close device handle."""
def set_configuration(self, device_handle, config_value):
"""Set device configuration."""
def claim_interface(self, device_handle, interface_number):
"""Claim interface for exclusive access."""
def release_interface(self, device_handle, interface_number):
"""Release interface."""Modern libusb 1.x backend providing comprehensive USB support with advanced features.
def get_backend():
"""
Get libusb 1.x backend instance.
Returns:
Backend object for libusb 1.x operations
Raises:
- NoBackendError: libusb 1.x not available
"""
# libusb 1.x error codes
LIBUSB_SUCCESS = 0
LIBUSB_ERROR_IO = -1
LIBUSB_ERROR_INVALID_PARAM = -2
LIBUSB_ERROR_ACCESS = -3
LIBUSB_ERROR_NO_DEVICE = -4
LIBUSB_ERROR_NOT_FOUND = -5
LIBUSB_ERROR_BUSY = -6
LIBUSB_ERROR_TIMEOUT = -7
LIBUSB_ERROR_OVERFLOW = -8
LIBUSB_ERROR_PIPE = -9
LIBUSB_ERROR_INTERRUPTED = -10
LIBUSB_ERROR_NO_MEM = -11
LIBUSB_ERROR_NOT_SUPPORTED = -12
LIBUSB_ERROR_OTHER = -99Legacy libusb 0.1 backend for compatibility with older systems.
def get_backend():
"""
Get libusb 0.1 backend instance.
Returns:
Backend object for libusb 0.1 operations
Raises:
- NoBackendError: libusb 0.1 not available
"""OpenUSB backend providing alternative USB library support.
def get_backend():
"""
Get OpenUSB backend instance.
Returns:
Backend object for OpenUSB operations
Raises:
- NoBackendError: OpenUSB not available
"""
# OpenUSB result codes
OPENUSB_SUCCESS = 0
OPENUSB_PLATFORM_FAILURE = -1
OPENUSB_NO_RESOURCES = -2
OPENUSB_NO_BANDWIDTH = -3
OPENUSB_NOT_SUPPORTED = -4
OPENUSB_HC_HARDWARE_ERROR = -5
OPENUSB_INVALID_PERM = -6
OPENUSB_BUSY = -7
OPENUSB_BADARG = -8
OPENUSB_NOACCESS = -9
OPENUSB_PARSE_ERROR = -10
OPENUSB_UNKNOWN_DEVICE = -11
OPENUSB_INVALID_HANDLE = -12
OPENUSB_IO_TIMEOUT = -13
OPENUSB_IO_CANCELLED = -14
OPENUSB_IO_OVERFLOW = -15
OPENUSB_CB_CONTINUE = -16Automatic backend selection and access to specific backend modules.
def get_backend():
"""
Get best available backend automatically.
Attempts to load backends in order of preference:
1. libusb 1.x (most modern and capable)
2. libusb 0.1 (legacy compatibility)
3. OpenUSB (alternative implementation)
Returns:
Backend object for the first available backend
Raises:
- NoBackendError: No USB backend available
"""
import usb.backend.libusb1 # Modern libusb 1.x backend
import usb.backend.libusb0 # Legacy libusb 0.1 backend
import usb.backend.openusb # OpenUSB backendHelper functions for loading USB backend libraries with error handling and library location.
def locate_library(candidates, find_library=None):
"""
Locate library from candidate list.
Parameters:
- candidates: list, candidate library names
- find_library: callable, library finder function
Returns:
str: path to library or None if not found
"""
def load_library(lib, name=None, lib_cls=None):
"""
Load library from path.
Parameters:
- lib: str, library path
- name: str, library name for error messages
- lib_cls: class, library wrapper class
Returns:
Library object
Raises:
- LibraryException: Library loading failed
"""
class LibraryException(Exception):
"""Base exception for library loading errors."""
class LibraryNotFoundException(LibraryException):
"""Library not found exception."""
class NoLibraryCandidatesException(LibraryException):
"""No library candidates available exception."""import usb.core
# PyUSB automatically selects the best available backend
device = usb.core.find(idVendor=0x1234, idProduct=0x5678)
if device:
print(f"Device found using automatic backend selection")
print(f"Backend: {device._ctx.backend.__class__.__module__}")
else:
print("No device found or no backend available")import usb.core
import usb.backend.libusb1
# Use specific backend
try:
backend = usb.backend.libusb1.get_backend()
device = usb.core.find(idVendor=0x1234, idProduct=0x5678, backend=backend)
if device:
print("Device found using libusb1 backend")
else:
print("Device not found")
except usb.core.NoBackendError:
print("libusb1 backend not available")import usb.backend.libusb1
import usb.backend.libusb0
import usb.backend.openusb
import usb.core
def check_backends():
"""Check which backends are available."""
backends = {
'libusb1': usb.backend.libusb1,
'libusb0': usb.backend.libusb0,
'openusb': usb.backend.openusb
}
available = []
for name, backend_module in backends.items():
try:
backend = backend_module.get_backend()
if backend:
available.append(name)
print(f"{name}: Available")
except usb.core.NoBackendError:
print(f"{name}: Not available")
return available
print("Backend availability:")
available_backends = check_backends()
print(f"Available backends: {available_backends}")import usb.core
import usb.backend.libusb1
try:
backend = usb.backend.libusb1.get_backend()
device = usb.core.find(idVendor=0x1234, idProduct=0x5678, backend=backend)
if device:
# Perform operations that might fail
try:
device.set_configuration()
data = device.read(0x81, 64, timeout=1000)
except usb.core.USBError as e:
# Check for libusb1-specific error codes
if hasattr(e, 'backend_error_code'):
error_code = e.backend_error_code
if error_code == usb.backend.libusb1.LIBUSB_ERROR_TIMEOUT:
print("Operation timed out")
elif error_code == usb.backend.libusb1.LIBUSB_ERROR_NO_DEVICE:
print("Device disconnected")
elif error_code == usb.backend.libusb1.LIBUSB_ERROR_ACCESS:
print("Access denied - check permissions")
else:
print(f"USB error with backend code: {error_code}")
else:
print(f"USB error: {e}")
except usb.core.NoBackendError:
print("libusb1 backend not available")import usb.core
import usb.backend.libusb1
import usb.backend.libusb0
def find_device_any_backend(vendor_id, product_id):
"""Try to find device using any available backend."""
backends_to_try = [
('libusb1', usb.backend.libusb1),
('libusb0', usb.backend.libusb0),
]
for backend_name, backend_module in backends_to_try:
try:
backend = backend_module.get_backend()
device = usb.core.find(
idVendor=vendor_id,
idProduct=product_id,
backend=backend
)
if device:
print(f"Device found using {backend_name} backend")
return device, backend_name
except usb.core.NoBackendError:
print(f"{backend_name} backend not available")
continue
return None, None
# Search for device
device, backend_used = find_device_any_backend(0x1234, 0x5678)
if device:
print(f"Successfully found device using {backend_used}")
else:
print("Device not found with any backend")import usb.core
import usb.backend.libusb1
import os
# Some backends may support configuration through environment variables
# For example, libusb debug output:
os.environ['LIBUSB_DEBUG'] = '3' # Enable verbose libusb debugging
try:
backend = usb.backend.libusb1.get_backend()
print("libusb1 backend initialized with debug output")
# Find device with debugging enabled
device = usb.core.find(idVendor=0x1234, idProduct=0x5678, backend=backend)
except usb.core.NoBackendError:
print("libusb1 backend not available")import usb.core
import usb.backend.libusb1
import usb.backend.libusb0
import time
def benchmark_backend(backend_module, backend_name):
"""Benchmark device enumeration with specific backend."""
try:
backend = backend_module.get_backend()
start_time = time.time()
devices = usb.core.find(find_all=True, backend=backend)
end_time = time.time()
device_count = len(devices) if devices else 0
elapsed = end_time - start_time
print(f"{backend_name}: Found {device_count} devices in {elapsed:.3f}s")
return elapsed
except usb.core.NoBackendError:
print(f"{backend_name}: Not available")
return None
print("Backend performance comparison:")
libusb1_time = benchmark_backend(usb.backend.libusb1, "libusb1")
libusb0_time = benchmark_backend(usb.backend.libusb0, "libusb0")
if libusb1_time and libusb0_time:
if libusb1_time < libusb0_time:
print("libusb1 is faster for device enumeration")
else:
print("libusb0 is faster for device enumeration")import usb.core
from usb.backend import IBackend
class CustomBackend(IBackend):
"""Example custom backend implementation."""
def enumerate_devices(self):
"""Custom device enumeration logic."""
# Implement custom device discovery
pass
def open_device(self, device):
"""Custom device opening logic."""
# Implement custom device access
pass
# Implement other required methods...
# Use custom backend
custom_backend = CustomBackend()
try:
device = usb.core.find(
idVendor=0x1234,
idProduct=0x5678,
backend=custom_backend
)
if device:
print("Device found using custom backend")
except Exception as e:
print(f"Custom backend error: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-pyusb