All notable changes to hackrfpy are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Work on the current development branch. Entries move to a versioned section on release.
- Type annotations across the entire shipped package, and
mypypromoted to a blocking CI gate (disallow_untyped_defs). The package has always shipped apy.typedmarker, which tells downstream type-checkers the inline annotations are real; previously only 1 of ~114 definitions was annotated, so that marker was a false promise. It is now enforced. HostOpsprotocol (_host.py) making the contract betweenHackRFand the command mixins explicit and type-checkable. The mixins call ~27 methods onselfthat live on the host class; that dependency was previously implicit in a comment. Runtime composition and MRO are unchanged.- Continuous integration: GitHub Actions workflow running the test suite across Windows, Linux, and macOS on Python 3.11-3.13, plus a ruff + mypy lint job.
- CLI test suite covering argument parsing, the mode state file, preset
resolution,
info/detect/doctor,rx/tx/sweepdispatch, and the module-level exit-code mapping. Overall coverage raised from 73% to 86% (cli.pyfrom 12% to ~98%). - Community health files:
CONTRIBUTING.md,CODE_OF_CONDUCT.md,SECURITY.md, issue templates, and a pull request template.
- Library diagnostics now go through the standard
loggingmodule instead ofprint(). Records are emitted on thehackrfpylogger: warnings atWARNING, verbose progress messages atINFO. A consumer can now route, reformat, or silence hackrfpy's output like any other library.- Diagnostics no longer touch stdout.
print_messagepreviously wrote to stdout, sohrf sweep -v > out.csvprepended[*] mode: rxinto the CSV. stdout is now reserved for data (sweep CSV, IQ on-r -) and explicitly requested output (--print-cmd). Diagnostics go to stderr. - Console behavior is unchanged for scripts and the CLI: warnings still appear
with no setup at all, and
verbose=True/-vstill prints progress. If the host application has configured logging, hackrfpy stays out of the way and simply propagates records to it.
- Diagnostics no longer touch stdout.
- Packaging classifiers: removed the contradictory
Operating System :: OS Independent(the library shells out to the Windowshackrf-toolsbinaries and Linux/macOS operation is unverified), leavingOperating System :: Microsoft :: Windows. Development status raised from3 - Alphato5 - Production/Stableto match the 1.0.0 release. - Ruff configuration added (
line-length = 100,select = ["E", "F", "W"]), and the codebase made lint-clean so the CI lint job is meaningful.
- The
atexitbackstop never reaped an orphanedPersistentReceiver.PersistentReceiverregisters itself in the live-handle registry, whose shutdown hook callsif h.is_alive(): h.stop()-- butis_alive()did not exist on the class, so the resultingAttributeErrorwas swallowed by the hook's bareexcept Exceptionand the receiver was silently left running. Found by the typing pass;is_alive()added and pinned with a regression test. - Reading from a closed
PersistentReceiverraised a bareTypeError: 'NoneType' object is not iterableinstead of a typed error; it now raisesHackRFDeviceErrorwith an actionable message. sweep_stream(..., print_cmd=True)would handStreamCtxaNoneand crash; it now raisesHackRFValueErrorpointing atsweep(..., print_cmd=True).- Unbounded memory growth on long-lived RX/TX handles:
_Processdrained child stdout/stderr into lists that were never trimmed, so an open-ended capture or repeat transmit retained every per-second stats line for the life of the process. Both drain paths now share a 64 KB cap (_DRAIN_CAP). transmit()now verifies the source file exists before arming TX and spawninghackrf_transfer, raisingHackRFEnvironmentErrorinstead of failing with a generic non-zero exit from the tool. The TX-mode gate is still checked first, andprint_cmddry runs skip the check.- SigMF sidecars now declare the
hackrfnamespace incore:extensions. Previously thehackrf:*gain keys were written without declaring the extension, which strict SigMF validators reject. - Removed unreachable dead code in
core.py(an orphanedreturn load_iq(...)after areturn, referencing three undefined names). - The test suite no longer writes a stray
capture.sigmf-metainto the working directory on every run. CITATION.cffversion and release date corrected to1.0.0/2026-06-16, aligning the citation metadata withpyproject.tomland the tagged release.
1.0.0 - 2026-06-16
Initial public release.
- Python wrapper and non-GUI command-line tool (
hrf) for the HackRF One, driving thehackrf-toolsbinaries directly (no libhackrf bindings). - Receive: bounded and streaming capture, with decode to
complex64and self-describing SigMF (.sigmf-meta) sidecars. - Spectrum sweep with streaming CSV parsing.
- Transmit: file playback and constant-wave source, guarded by an explicit operating-mode gate (transmit refuses unless the instance is switched to TX mode, which emits a one-time safety banner) and a TX gain ceiling.
- Device management passthroughs (clock, Opera Cake, SPI flash, debug) and
preflight
info/detect/doctorhelpers. - Cross-platform process lifecycle handling with best-effort clean interrupt (SIGINT on POSIX, CTRL_BREAK on Windows) and an atexit backstop for live RX/TX handles.
- Validation layer with hard-range checks, gain snapping to real device steps,
and a parameter readback (
last_params) reflecting the values actually used.