Skip to content

Drop Python 3.10, use Python 3.11 features, test on 3.15 - #2059

Open
dlech wants to merge 4 commits into
hbldh:developfrom
dlech:drop-python-3.10
Open

dlech wants to merge 4 commits into
hbldh:developfrom
dlech:drop-python-3.10

Conversation

@dlech

@dlech dlech commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Python 3.10 reached end-of-life in October 2026.

bleak: drop support for Python 3.10

  • requires-python = ">=3.11", isort/mypy targets bumped, 3.10 removed from the CI matrices and poe tasks.
  • Dropped the async-timeout dependency and the now-redundant python_version markers on the docs and Android test dependencies.
  • Dropped the pytest warning filter for the coverage C-tracer issue, which only affected 3.10.

bleak: use Python 3.11 features

  • Self, Never, Unpack, TypeVarTuple and assert_never now come straight from typing, and the async-timeout alias is replaced with asyncio.timeout(). Only override (3.12) is left in bleak._compat.
  • Catch the builtin TimeoutError instead of its alias asyncio.TimeoutError.
  • Use the PEP 646 *Ts syntax instead of Unpack[Ts].
  • BleakBackend is now an enum.StrEnum. This is the one user-visible change: str()/format() now return the value (e.g. "bluez_dbus") instead of "BleakBackend.BLUEZ_DBUS". The CHANGELOG notes it.
  • test_disconnect_timeout_tears_down now patches asyncio.timeout, scoped to the disconnect() call with monkeypatch.context(), instead of the module-level alias.

tests: drop the grpcio dependency

  • bumble pulls in grpcio, but on the host it was only needed because the Android emulator runner imported find_grpc_port() from bumble.transport.android_netsim, which imports grpc at the top. The runner now reads NetSim's .ini file itself.
  • The tests that use gRPC to talk to NetSim run inside the testbed app, which gets bumble and grpcio from briefcase, so the uv override now drops grpcio everywhere, not just on Windows. This fixes the BlueZ VM job on 3.15: grpcio 1.76.0 has no musl cp315 wheel and the VM has no C++ compiler.

CI: test on Python 3.15

  • Added 3.15 to the desktop, BlueZ integration and winvhci integration matrices, plus a test-py315 poe task.
  • Upgraded aiohttp (3.14.5), cffi (2.1.1), yarl and pyobjc (13.0) in the lock to versions with cp315 wheels. pyobjc 12.1 also fails to build from source with current Xcode.
  • The BlueZ VM now installs the latest uv from PyPI. The Alpine 3.24 uv package (0.11.19) only knows about Python 3.15.0b2, which segfaulted in pure-Python dbus-fast code during the tests.
  • winrt 3.2.1 still has no cp315 wheel, but it built from source fine on the Windows runner in the first CI run, so I left it at 3.2.1.

Tested locally on Linux: lint, mypy and pyright (desktop and Android), the docs build, and the test suite on 3.11, 3.14 and 3.15.2.

@codecov

codecov Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.12500% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.47%. Comparing base (a213f8c) to head (2016ec9).

Files with missing lines Patch % Lines
...k/backends/corebluetooth/CentralManagerDelegate.py 33.33% 2 Missing ⚠️
bleak/backends/p4android/scanner.py 0.00% 2 Missing ⚠️
bleak/__init__.py 66.66% 1 Missing ⚠️
bleak/backends/android/adapter.py 66.66% 1 Missing ⚠️
bleak/backends/corebluetooth/PeripheralDelegate.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2059      +/-   ##
===========================================
- Coverage    65.74%   65.47%   -0.28%     
===========================================
  Files           53       53              
  Lines         5047     5022      -25     
  Branches       611      610       -1     
===========================================
- Hits          3318     3288      -30     
- Misses        1507     1509       +2     
- Partials       222      225       +3     
Flag Coverage Δ
android-integration-py3.13-api31 26.94% <28.12%> (-0.09%) ⬇️
android-integration-py3.13-api33 26.82% <28.12%> (-0.13%) ⬇️
bluez-integration-py310 ?
bluez-integration-py311 34.34% <31.25%> (-0.05%) ⬇️
bluez-integration-py312 34.34% <31.25%> (-0.05%) ⬇️
bluez-integration-py313 34.34% <31.25%> (-0.05%) ⬇️
bluez-integration-py314 33.02% <31.25%> (-0.06%) ⬇️
bluez-integration-py315 33.02% <31.25%> (?)
macos-latest-py310 ?
macos-latest-py311 16.24% <25.00%> (-0.20%) ⬇️
macos-latest-py312 16.24% <25.00%> (-0.20%) ⬇️
macos-latest-py313 16.24% <25.00%> (-0.20%) ⬇️
macos-latest-py314 16.01% <25.00%> (-0.21%) ⬇️
macos-latest-py315 16.01% <25.00%> (?)
ubuntu-latest-py310 ?
ubuntu-latest-py311 27.24% <28.12%> (-0.11%) ⬇️
ubuntu-latest-py312 27.24% <28.12%> (-0.09%) ⬇️
ubuntu-latest-py313 27.24% <28.12%> (-0.09%) ⬇️
ubuntu-latest-py314 25.77% <28.12%> (-0.10%) ⬇️
ubuntu-latest-py315 25.77% <28.12%> (?)
windows-latest-py310 ?
windows-latest-py311 15.77% <31.25%> (-0.14%) ⬇️
windows-latest-py312 15.77% <31.25%> (-0.14%) ⬇️
windows-latest-py313 15.77% <31.25%> (-0.14%) ⬇️
windows-latest-py314 15.48% <31.25%> (-0.15%) ⬇️
windows-latest-py315 15.48% <31.25%> (?)
winvhci-integration-py310 ?
winvhci-integration-py311 23.73% <37.50%> (-0.11%) ⬇️
winvhci-integration-py312 23.73% <37.50%> (-0.15%) ⬇️
winvhci-integration-py313 23.73% <37.50%> (-0.11%) ⬇️
winvhci-integration-py314 23.86% <37.50%> (-0.11%) ⬇️
winvhci-integration-py315 23.86% <37.50%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

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

Python 3.10 reached end-of-life in October 2026. Raise the minimum
supported version to 3.11 and stop testing on 3.10 in CI.

This also drops the async-timeout dependency, which was only needed on
Python 3.10, the Python version markers on the docs and Android test
dependencies, which no longer exclude any supported version, and the
pytest warning filter for the coverage C tracer issue that only affected
Python 3.10.
Now that the minimum supported Python version is 3.11:

* Import Self, Never, Unpack, TypeVarTuple and assert_never from typing
  instead of going through bleak._compat. Only override (Python 3.12) is
  left there.
* Use asyncio.timeout() directly instead of the async_timeout alias.
  test_disconnect_timeout_tears_down now patches asyncio.timeout for the
  duration of the disconnect() call instead of the alias in the BlueZ
  client module.
* Catch the builtin TimeoutError instead of asyncio.TimeoutError, which
  is just an alias for it since Python 3.11.
* Use the PEP 646 *Ts syntax instead of Unpack[Ts].
* Make BleakBackend an enum.StrEnum instead of mixing in str. This makes
  str() and format() return the plain value on all Python versions.
* Drop the Python version checks for tomllib in docs/conf.py and for
  Self in the type stubs.
bumble depends on grpcio for its Android emulator transports, but the
only host-side use was importing find_grpc_port() from
bumble.transport.android_netsim in the Android emulator test runner.
That module imports grpc at the top, even though find_grpc_port() just
reads the port from NetSim's .ini file. The tests that actually talk to
NetSim over gRPC run inside the Android testbed app, which gets its own
copy of bumble and grpcio from briefcase.

Do the .ini file lookup in the runner instead and drop grpcio from the
test dependencies everywhere, like it already was on Windows. grpcio
often has no wheels for new Python versions or for musl, which the BlueZ
integration test VM uses, and building it from source needs a C++
compiler.
Add Python 3.15 to the desktop, BlueZ integration and winvhci
integration test matrices and add a test-py315 poe task.

aiohttp 3.14.1, cffi 2.0.0 and pyobjc 12.1 have no wheels for Python
3.15 and pyobjc 12.1 fails to build from source with current Xcode, so
upgrade them (and yarl along with aiohttp) to versions that do.

The uv package in the Alpine VM for the BlueZ integration tests (0.11.19
in Alpine 3.24) only knows about Python 3.15.0b2, which segfaulted in
the tests. Install the latest uv from PyPI in the VM and use that
instead.
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.

1 participant