Skip to content

Use UnitOfRatio.PARTS_PER_MILLION over deprecated CONCENTRATION_PARTS_PER_MILLION - #147

Open
jasonjhofmann wants to merge 2 commits into
dalinicus:mainfrom
jasonjhofmann:migrate-unitofratio
Open

Use UnitOfRatio.PARTS_PER_MILLION over deprecated CONCENTRATION_PARTS_PER_MILLION#147
jasonjhofmann wants to merge 2 commits into
dalinicus:mainfrom
jasonjhofmann:migrate-unitofratio

Conversation

@jasonjhofmann

Copy link
Copy Markdown

On Home Assistant 2026.8.x the integration logs this on every start:

[homeassistant.const] The deprecated constant CONCENTRATION_PARTS_PER_MILLION was used from ac_infinity. It will be removed in HA Core 2027.8. Use UnitOfRatio.PARTS_PER_MILLION instead, please report it to the author of the 'ac_infinity' custom integration

CONCENTRATION_PARTS_PER_MILLION was deprecated in core#175189 and is removed in HA Core 2027.8. This swaps the two uses (SensorType.CO2 and SensorType.HYDRO_TDS_PPM) to UnitOfRatio.PARTS_PER_MILLION.

The enum member's value is byte-identical ("ppm"), so no unit string, entity state, or recorded statistic changes — the deprecated constant is already just an alias for it.

Why this needs a version floor

UnitOfRatio first exists in HA 2026.7.0 (I checked homeassistant/const.py at the release tags — it is absent at 2026.6.0). HA 2026.7 in turn declares requires-python = ">=3.14.2". Two consequences, both handled here:

1. hacs.json gains "homeassistant": "2026.7.0". The repo currently declares no floor, so without this HACS would offer the update to users on older cores, where the import raises ImportError at setup.

2. quality.yaml moves Python 3.13 → 3.14. This one is not cosmetic. requirements.txt installs homeassistant unpinned, so on 3.13 pip resolves the newest core that still supports 3.13 — which predates UnitOfRatio:

$ python3.13 -m pip install homeassistant && python -c "from homeassistant.const import UnitOfRatio"
# resolves homeassistant 2026.2.3
ImportError: cannot import name 'UnitOfRatio' from 'homeassistant.const'

Without the bump, CI would go red on this PR for that reason alone.

The first commit is a prerequisite, and is independently useful

Moving CI to 3.14 pulls in a modern aiohttp, which surfaces 52 failures in tests/test_client.py that have nothing to do with this change:

TypeError: ClientResponse.__init__() missing 1 required keyword-only argument: 'stream_writer'

aiohttp 3.13 added a required keyword-only stream_writer to ClientResponse.__init__, and aioresponses (through 0.7.9, current) does not pass it. It is latent today only because the CI pin holds aiohttp back. The first commit adds a tests/conftest.py shim that defaults the kwarg, rather than capping the test-time aiohttp — pinning the tests would mean never exercising the aiohttp your users actually install. It is self-limiting in both directions: on aiohttp<3.13 the parameter does not exist and patching is skipped, and once aioresponses passes stream_writer itself the setdefault becomes a no-op.

It is a separate commit so you can take it on its own, or drop it if you would rather pin.

Verification

Measured on this branch, so the migration's effect is isolated:

Tree Python Result
main 3.13 (current CI) 252 passed
main 3.14 199 passed, 52 failed (stream_writer)
main + conftest shim 3.14 251 passed, 0 failed
this PR (shim + migration) 3.14 251 passed, 0 failed

The last two rows are identical, so the unit migration itself introduces no test change. The 252 → 251 difference between rows 1 and 3 is the HA version jump (2026.2.3 → 2026.8.1), not either commit here.

One note in fairness: there is a large, constant count of RuntimeError: There is no current event loop in thread 'MainThread' teardown errors in my local runs, present identically on unmodified main. They look environmental and I did not chase them, but I did not want to quietly omit them — they are unchanged by this PR.

Happy to drop the hacs.json floor or the CI bump into a separate PR, or adjust anything here, if you would prefer a different shape.

jasonjhofmann and others added 2 commits August 9, 2026 17:05
aiohttp 3.13 added a required keyword-only `stream_writer` argument to
`ClientResponse.__init__`. aioresponses (through 0.7.9, current) does not
pass it, so every mocked request in tests/test_client.py fails with:

    TypeError: ClientResponse.__init__() missing 1 required
    keyword-only argument: 'stream_writer'

This is latent on the current CI pin (Python 3.13 resolves an older aiohttp)
but surfaces as 52 failures the moment the runtime moves forward.

Defaults the kwarg in a new tests/conftest.py rather than capping the
test-time aiohttp, since requirements.txt is uncapped and pinning the tests
would mean never exercising the aiohttp users actually install. The shim is
self-limiting in both directions: on aiohttp<3.13 the parameter does not
exist and patching is skipped, and once aioresponses passes stream_writer
itself the setdefault becomes a no-op.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Home Assistant deprecated CONCENTRATION_PARTS_PER_MILLION in core#175189
(2026.8); it is removed in HA Core 2027.8. Running 2026.8.x, the integration
logs on every start:

    The deprecated constant CONCENTRATION_PARTS_PER_MILLION was used from
    ac_infinity. It will be removed in HA Core 2027.8. Use
    UnitOfRatio.PARTS_PER_MILLION instead, please report it to the author of
    the 'ac_infinity' custom integration

The replacement enum member has a byte-identical value ('ppm'), so no unit
string, entity state or stored statistic changes.

UnitOfRatio first exists in HA 2026.7.0 (absent in 2026.6.0), and HA 2026.7
requires Python >= 3.14.2. Two coupled changes follow:

- hacs.json gains "homeassistant": "2026.7.0". Without it HACS would offer
  this version to users on older cores, where the import raises ImportError
  at setup.
- quality.yaml moves 3.13 -> 3.14. requirements.txt installs homeassistant
  unpinned, so on 3.13 pip resolves the newest HA that still supports 3.13
  (2026.2.x), which predates UnitOfRatio and cannot exercise this code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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.

1 participant