Skip to content

refactoring_branch: tooling, CI, documentation, and structural refactoring#3

Closed
Copilot wants to merge 3 commits into
mainfrom
copilot/review-openlifu-sdk-structure
Closed

refactoring_branch: tooling, CI, documentation, and structural refactoring#3
Copilot wants to merge 3 commits into
mainfrom
copilot/review-openlifu-sdk-structure

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 2, 2026

Summary

Implements all recommendations from the architectural review. Changes are organized into 5 phases.


Phase 1 – Bug Fixes

Logging library contract violations

  • LIFUUart.py and LIFUTXDevice.py: Removed propagate = False, hardcoded setLevel(ERROR), and manual StreamHandler setup. Libraries must never configure the root logging hierarchy. Logger names changed from hardcoded strings to __name__.

Shared mutable state bug

  • LIFUInterface: signal_connect, signal_disconnect, signal_data_received, hvcontroller, and txdevice were declared as class-level attributes — all instances shared the same signal objects. Moved to __init__ as properly typed instance attributes.

F-string logging (lazy evaluation)

  • Replaced all logger.error(f"msg {x}") with logger.error("msg %s", x) across LIFUTXDevice.py, LIFUHVController.py, LIFUUart.py, LIFUInterface.py, and LIFUUserConfig.py.

Other code quality fixes

  • Fixed a bare logging.warn useless expression in calc_pulse_patternlogger.warning(...)
  • Fixed raise ValueError(...) inside except to chain with from e (PEP 3134 / ruff B904)
  • Fixed unused expression n_detected_tx / TRANSMITTERS_PER_MODULE — now assigned to n_modules with a debug log
  • Fixed two unused dict comprehensions in set_solution — now assigned to named variables with an explanatory comment
  • Fixed mid-file LIFUConfig import (E402) — moved to top of file alongside all other imports

pyproject.toml

  • Deduplicated identical [test] and [dev] optional-dependency groups; [dev] now adds pre-commit, ruff, and mypy

Phase 2 – Tooling

pyproject.toml additions

  • ruff (linting + formatting): selects E, W, F, I, UP, B, G (logging f-strings), LOG, C4, PIE, RUF; line length 120
  • mypy: non-strict baseline with ignore_missing_imports = true
  • pytest: testpaths = ["unit-test"], -v addopts
  • coverage: source = src/, excludes firmware/libusb binaries

New files

  • .pre-commit-config.yaml: ruff (lint + format), pre-commit-hooks (trailing whitespace, YAML/TOML check, large-file guard, no-commit-to-main)
  • .editorconfig: UTF-8, LF, 4-space indent, 120 max line for Python

Phase 3 – CI

.github/workflows/test.yml — runs on every push and pull request:

  • lint job: ruff check src/ + ruff format src/ --check
  • test job (depends on lint): pytest unit-test/ -v --cov=src --cov-report=xml across ubuntu-latest, windows-latest, macos-latest; uploads coverage.xml artifact from Ubuntu run
  • Both jobs have explicit permissions: contents: read (CodeQL clean)

Phase 4 – Documentation

  • README.md: Added CI/PyPI/Python/License badges; Features section; architecture tree; examples section; test & build instructions; links to CONTRIBUTING and CHANGELOG
  • CONTRIBUTING.md: Full contributor guide — virtual env setup, project structure, coding conventions (logging rules, type annotations, docstrings, exception chaining), test/lint/pre-commit instructions, PR and release process
  • CHANGELOG.md: Keep-a-Changelog format documenting all Phase 1–5 changes; links to GitHub compare URLs

Phase 5 – Structural Refactoring

Beamforming extraction

LIFUTXDevice.py was 2 623 lines mixing UART command wrappers with register-map math. The TX7332 register-map domain is now isolated in a new package:

src/openlifu_sdk/beamforming/
├── __init__.py          ← public API with __all__
└── tx7332.py            ← constants + helpers + dataclasses (Tx7332Registers, TxDeviceRegisters, ...)

LIFUTXDevice.py is now ~1 735 lines and re-exports all extracted names for full backward compatibility — existing imports (from openlifu_sdk.io.LIFUTXDevice import Tx7332DelayProfile) continue to work unchanged.

Transport Protocol

src/openlifu_sdk/transport.py: A @runtime_checkable Protocol class (Transport) that formally defines the interface expected by TxDevice and HVController. Any class with demo_mode, asyncMode, is_connected(), check_usb_status(), send_packet(), clear_buffer(), and disconnect() satisfies the protocol — enabling test doubles without inheritance.

SDK Exception Hierarchy

src/openlifu_sdk/exceptions.py:

OpenLIFUError
├── DeviceNotConnectedError
├── CommunicationError
├── SolutionValidationError (also ValueError)
├── FirmwareUpdateError
└── ConfigurationError

Updated public API

src/openlifu_sdk/__init__.py now exports LIFUInterface, LIFUInterfaceStatus, all exceptions, and Transport.


Verification

  • ✅ All 60 existing unit tests pass
  • ruff check src/ && ruff format src/ --check — fully clean (0 errors)
  • ✅ CodeQL: 0 alerts (Python + Actions)
  • ✅ Full backward compatibility maintained for all imports

Copilot AI and others added 3 commits April 2, 2026 03:05
…IBUTING, CHANGELOG)

Agent-Logs-Url: https://github.com/OpenwaterHealth/openlifu-sdk/sessions/0b696c10-0b7e-433c-a117-0c21c5b80e26

Co-authored-by: georgevigelette <114104081+georgevigelette@users.noreply.github.com>
…tions, review fixes

Agent-Logs-Url: https://github.com/OpenwaterHealth/openlifu-sdk/sessions/0b696c10-0b7e-433c-a117-0c21c5b80e26

Co-authored-by: georgevigelette <114104081+georgevigelette@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants