pyusb

Cross-platform Python library for direct USB device access via a backend-neutral libusb/OpenUSB API.

Library
PyPI
v1.3.1
2,309stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
53/100Fair
Development Activity4
Maintenance20
Community88
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
63/100Good
Architecture72
Code Quality58
Innovation45
Learning Curve75

PyUSB lets Python programs talk to USB devices directly, without shelling out to platform-specific drivers or writing C extensions. It exposes a frontend-backend architecture: the usb.core, usb.util, and usb.control modules provide a single Pythonic API (device enumeration, configuration/interface/endpoint descriptors, control/bulk/interrupt/isochronous transfers), while an IBackend interface routes calls into whichever native USB stack is installed on the host — libusb 1.0, libusb 0.1, or OpenUSB.

This makes it the de facto choice for hardware automation, custom device drivers, test rigs, and instrument control scripts written in Python: usb.core.find() locates a device by vendor/product ID or a custom matcher, and the rest of the API mirrors the USB specification closely enough that anyone with basic protocol knowledge can read and write descriptors, claim interfaces, and move data without fighting the library itself.

What You Get

  • usb.core.find() for locating devices by vendor/product ID or a custom predicate function, including find_all for enumerating every match
  • Full descriptor object model — Device, Configuration, Interface, and Endpoint classes that mirror the USB specification
  • Support for all four USB transfer types (control, bulk, interrupt, isochronous) through a uniform read/write API
  • Pluggable backend layer (usb.backend) with built-in support for libusb 1.0, libusb 0.1, and OpenUSB, selectable at runtime or overridable with a custom backend
  • A usb.legacy compatibility module for code still written against the pre-1.0 PyUSB API
  • String descriptor helpers (usb.util.get_string, get_langids) and request-type builders (usb.util.build_request_type) for constructing raw control transfers

Common Use Cases

  • Writing Python-based automation and test scripts that drive USB instruments, sensors, or manufacturing hardware
  • Building custom drivers for USB peripherals that have no vendor-supplied Python SDK
  • Reverse-engineering or debugging USB device protocols by inspecting raw descriptors and issuing manual control transfers
  • Prototyping firmware-adjacent tooling before committing to a compiled driver, using PyUSB’s fast Python iteration loop
  • Cross-platform device automation where the same script needs to run against libusb on Linux/macOS and Windows

Under The Hood

Architecture PyUSB splits cleanly into a frontend and a backend. The frontend (usb.core, usb.util, usb.control) exposes the public object model — Device, Configuration, Interface, and Endpoint — plus usb.core.find() for discovery, while every actual USB operation is delegated through the IBackend interface implemented separately for libusb 1.0, libusb 0.1, and OpenUSB in usb/backend/. Supporting modules keep the frontend thin: _objfinalizer.py handles deterministic resource cleanup for device handles, _lookup.py holds USB descriptor lookup tables, and usb.legacy re-exposes the pre-1.0 API on top of the same core so old scripts keep working. Because every backend implements the same small IBackend contract, swapping libusb1 for OpenUSB (or a custom backend) changes zero frontend code — the abstraction has stayed stable since the 1.0 rewrite.

Tech Stack Pure Python 3.9+ with no compiled extension modules — native USB access goes through ctypes bindings straight to the host’s libusb/OpenUSB shared library, so there’s nothing to build at install time, only a system library to have present. Packaging uses plain setuptools with setuptools_scm for git-tag-derived versioning, and the test matrix (Python 3.9 through 3.14) is driven by tox and run in GitHub Actions via a single run_tox.yml workflow.

Code Quality Tests live under tests/ as stdlib unittest suites (test_core.py-style coverage of backend, control, find, util, legacy, and interop behavior), run through tests/testall.py and exercised across all six supported Python versions by tox in CI — a real, if not exhaustive, safety net. There’s no type-checking or linter configuration in the repo (no mypy/ruff/flake8 config, no CONTRIBUTING.md), and naming intentionally breaks PEP8 in places (bLength, bDescriptorType) to mirror USB specification field names rather than Python convention, which is a deliberate readability trade-off for anyone cross-referencing the USB spec.

API Design The library’s strongest design choice is hiding three incompatible native USB stacks behind one small, stable interface — usb.core.find() plus a descriptor object model that mirrors the USB specification closely enough that protocol knowledge transfers directly into API knowledge, with minimal PyUSB-specific ceremony to learn on top.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search