Skip to content

Replace black, isort, flake8, autoflake and pyupgrade with ruff - #761

Draft
zigpy-review-bot wants to merge 4 commits into
devfrom
zigpy-bot/migrate-to-ruff
Draft

zigpy-review-bot wants to merge 4 commits into
devfrom
zigpy-bot/migrate-to-ruff

Conversation

@zigpy-review-bot

@zigpy-review-bot zigpy-review-bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Why

#759 bumped only the two hooks that crashed on Python 3.14. The rest of the stack is old (black 23.3.0, isort 5.12.0, autoflake v2.0.2, ruff v0.0.261), and flake8 cannot move at all: pyproject-flake8==7.0.0 pins flake8==7.0.0 exactly, and there is no newer release of it. This replaces the stack with ruff, as zigpy, zha, zha-device-handlers and zigpy-znp already do.

Changes

  • Hooks: ruff-check + ruff-format (ruff-pre-commit v0.16.9, now under astral-sh/) replace black, isort, flake8, autoflake, pyupgrade and the old ruff hook. codespell goes from v2.2.4 to v2.4.3, and mirrors-mypy stays at v2.3.1.
  • ruff.toml moves into [tool.ruff] in pyproject.toml, replacing [tool.isort] and [tool.flake8]. The existing rule selection and ignores are kept, with the full B and SIM families replacing the individual B0xx / SIM1xx codes and I replacing isort. tests/ was excluded from ruff and only checked by flake8. It is now checked by ruff, with the same F811, F401, F403 per-file ignores flake8 had. flake8's E266 exemption for bellows/types/named.py is not carried over because ruff only has E266 as a preview rule, which is not enabled.
  • requirements_test.txt: drop isort, black, flake8 and Flake8-pyproject, and bump ruff==0.0.261 to ruff==0.16.9 to match the hook.
  • Remove the unused flake8 problem matcher. The shared CI workflow only loads python.json.

Second commit, the resulting fixes. Mostly autofixes: import sorting, pyupgrade rewrites, ruff format output (lowercase hex escapes, joined implicit string concatenations) and unused loop variables. By hand:

  • Every EZSP version module docstring opened with four quotes (""""EZSP ...), leaving a stray " in the text.
  • EZSP.leaveNetwork created a dead asyncio.Future() that the with statement immediately rebinds (F811).
  • _cancel_pending_data_frames defaulted to a single RuntimeError instance created at import time and reused on every call (B008). It is now created per call.
  • Exception chaining for re-raised errors, explicit zip(strict=...), %-formatting → f-strings in the CLI (with !s where the value is a zigpy enum, whose format() returns the repr), # flake8: noqa → # ruff: noqa, and a test that did not keep a reference to its background tasks (RUF006).

Third commit: the new rules showed that four tests in tests/test_ezsp.py could not fail.

  • test_write_custom_eui64 and test_write_custom_eui64_rcp compared setTokenData.mock_calls against the expected calls without assert (B015). With the assert added, both failed. The expectations used positional arguments while the code passes keywords. The RCP test's getTokenData mock also reported success for every key, so the code picked the NCP key, not the RCP one the test is about. The mock now only knows the RCP key, and both tests check the real calls.
  • test_list_command_initial_failure and test_form_network_fail used t.EmberStatus.FAILURE, which no longer exists. They passed on the resulting AttributeError, raised before the code under test ran (pytest.raises(Exception), B017). They now use ERR_FATAL and check for the specific error.

Fourth commit: remove tox.ini. Nothing references it (CI runs the shared zigpy/workflows pipeline, not tox), it was last changed in 2020, and its py37 / py38 environments cannot run against requires-python = ">=3.11".

Verification

  • pre-commit run --all-files passes on Python 3.14.
  • Tests: 705 passed, the same as on dev. Coverage stays at 99%, the CI minimum.

Context

This is one of a set of draft PRs that align the pre-commit setup of the zigpy libraries on ruff (ruff check + ruff format), which zigpy, zha, zha-device-handlers, zigpy-znp, zigpy-ota and zigpy-ziggurat already use. The same change is proposed for bellows, zigpy-deconz, zigpy-xbee, zigpy-zigate and zigpy-cli, plus small ruff config fixes in zigpy and zigpy-ziggurat.

The commits are kept separate so parts can be dropped or moved into their own PR. Maintainers can ask the bot for that, or for any other change, by commenting @zigpy-review-bot <request> on this PR.

Mostly autofixes: import sorting, pyupgrade rewrites, ruff format output (lowercase hex escapes, joined implicit string concatenations) and unused loop variables. By hand:
- Remove the stray fourth quote that opened every EZSP version module docstring (`""""EZSP ...`).
- Drop a dead `stack_status = asyncio.Future()` in `EZSP.leaveNetwork`, immediately rebound by the `with` statement (F811).
- Create the default `RuntimeError` in `_cancel_pending_data_frames` per call instead of sharing one instance created at import time (B008).
- Exception chaining for re-raised errors, explicit zip(strict=...), %-formatting -> f-strings in the CLI, and keep a reference to background tasks in a test (RUF006).
Surfaced by the new ruff rules:
- test_write_custom_eui64 and test_write_custom_eui64_rcp compared setTokenData.mock_calls without asserting (B015). Asserting them showed the expected calls used positional arguments while the code passes keywords, and the RCP test's getTokenData mock reported success for every key, so the NCP key was picked. The mock now only knows the RCP key.
- test_list_command_initial_failure and test_form_network_fail used t.EmberStatus.FAILURE, which no longer exists, so they passed on an AttributeError raised before the code under test ran (B017). They now use ERR_FATAL and check for the specific error.
@codecov

codecov Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.15385% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 99.60%. Comparing base (9c4b89a) to head (a07bc69).
⚠️ Report is 1 commits behind head on dev.

Files with missing lines Patch % Lines
bellows/zigbee/application.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #761      +/-   ##
==========================================
+ Coverage   99.58%   99.60%   +0.02%     
==========================================
  Files          64       64              
  Lines        4330     4327       -3     
==========================================
- Hits         4312     4310       -2     
+ Misses         18       17       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Nothing references it (CI runs the shared zigpy/workflows pipeline, not tox), it was last changed in 2020, and its py37/py38 environments cannot run against requires-python >= 3.11.
@zigpy-review-bot zigpy-review-bot added the code quality Improvement to code quality label Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code quality Improvement to code quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant