Skip to content

Support zigpy 2.0.0#179

Draft
TheJulianJES wants to merge 5 commits into
zigpy:devfrom
TheJulianJES:tjj/zigpy-2.0-compat
Draft

Support zigpy 2.0.0#179
TheJulianJES wants to merge 5 commits into
zigpy:devfrom
TheJulianJES:tjj/zigpy-2.0-compat

Conversation

@TheJulianJES

@TheJulianJES TheJulianJES commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

This PR updates zigpy-xbee to be more compatible with zigpy 2.0.0, without relying on the presence of zha-quirks.

As zha-quirks now depends on ZHA, which pulls in zigpy-xbee, I noticed some test failures of the deprecated CustomCluster usage in all quirks tests. These are addressed by this.

Do note this PR was not tested.

AI summary

Why

  • zigpy 2.0.0 moved the quirks API out of zigpy (into zha-device-handlers). zigpy.quirks is now only a deprecation shim that lazily re-imports CustomDevice/CustomCluster from zhaquirks.legacy. This gives zigpy-xbee an implicit, undeclared dependency on zhaquirks: under Home Assistant it kept working (ZHA installs zha-quirks, so the shim resolves — only DeprecationWarnings were emitted), but a standalone install fails at import with ModuleNotFoundError: No module named 'zhaquirks'. zigpy-xbee should not depend on zha-device-handlers at all.
  • zigpy recently switched its serial layer from pyserial-asyncio-fast to serialx, whose Serial class has no BAUDRATES attribute. This breaks the baudrate setter on the path that switches baud to auto-enter API mode (init_api_mode); a coordinator already in API mode does not hit it.

Changes

  • Reimplement XBeeGroup/XBeeGroupResponse as plain Groups subclasses kept out of the global cluster registry (_skip_registry), and XBeeCoordinator as a zigpy.device.Device that builds its endpoint and clusters directly instead of via a quirks CustomDevice. add_endpoint registers endpoints directly rather than mutating a quirks replacement dict.
  • Replace the deprecated Device.update_last_seen() call.
  • Define the standard baudrate list on Gateway so validation no longer depends on the serial backend.
  • Bump minimums: zigpy>=2.0.0 (was 0.70.0), requires-python>=3.11 (was 3.8); bump the pyupgrade target to --py311-plus; drop the unused, unmaintained asynctest test dependency.
  • Remove tox.ini, which is no longer used (CI runs via the shared zigpy/workflows workflow).
  • Apply the resulting Python 3.11+ modernizations: rewrite the deprecated asyncio.TimeoutError alias to the builtin TimeoutError, and replace typing.Dict/Optional with builtin generics and PEP 604 unions (unused imports dropped).

Testing

  • pytest: 105 passed, 100% coverage, with DeprecationWarning treated as errors.
  • CI green on Python 3.11, 3.12, 3.13, and 3.14; pre-commit (black, flake8, isort, ruff, mypy, pyupgrade, autoflake, codespell) all pass.
  • Verified against both zigpy 2.0.0 and 1.5.1.

zigpy 2.0.0 moved the quirks API out of zigpy into zha-device-handlers,
so importing CustomDevice/CustomCluster from zigpy.quirks now fails with
ModuleNotFoundError (zhaquirks is not, and must not be, a dependency).

- Reimplement XBeeGroup/XBeeGroupResponse as plain Groups subclasses kept
  out of the global cluster registry via _skip_registry.
- Reimplement XBeeCoordinator as a zigpy.device.Device that builds its
  coordinator endpoint and clusters directly instead of via a quirks
  CustomDevice 'replacement' dict.
- Rewrite ControllerApplication.add_endpoint to register endpoints and
  clusters directly rather than mutating the quirks replacement dict.
- Replace the deprecated Device.update_last_seen() call with a direct
  last_seen assignment.
zigpy 2.0.0 switched its serial layer from pyserial-asyncio-fast to
serialx, whose Serial class does not expose a BAUDRATES attribute. The
baudrate setter (used when entering AT command mode) relied on
self._transport.serial.BAUDRATES and would raise AttributeError.

- Define the standard baudrate list on Gateway and validate against it.
- Drop the stale 'import serial_asyncio_fast' from the uart tests and
  patch zigpy.serial.create_serial_connection (what uart.connect actually
  calls) instead.
- Require zigpy>=2.0.0 (where the quirks API was moved out) instead of the
  long-outdated 0.70.0 floor.
- Require Python >=3.11 to match zigpy 2.0.0, and update the tox env list
  (py311-py313) and pyupgrade target (--py311-plus) accordingly.
- Drop the unused, unmaintained asynctest test dependency; the tests use
  unittest.mock.
The --py311-plus pyupgrade target rewrites the deprecated asyncio.TimeoutError
alias to the builtin TimeoutError and replaces typing.Dict/Optional with
builtin generics and PEP 604 unions; autoflake drops the now-unused imports.
CI runs via the shared zigpy/workflows workflow, not tox; the file is no
longer referenced.
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (f5f9d6f) to head (1a14981).

Additional details and impacted files
@@            Coverage Diff            @@
##               dev      #179   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            7         7           
  Lines          718       736   +18     
=========================================
+ Hits           718       736   +18     

☔ 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.

{"status": foundation.Status},
direction=foundation.Direction.Client_to_Server,
),
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This construct looks really odd but it apparently is the correct way 😓

Image

The ZCL header does not flip the manufacturer specific bit either.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not actually seeing where this is used. #46 introduced the change.

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