chore(deps): move to uv and bump every dependency in one pass - #110
Merged
Merged
Conversation
Replaces Poetry with uv, and folds the five open dependabot PRs into the single lock regeneration that migration requires. ## Why one commit and not two Bumping dependencies while still on Poetry was not possible here: the local Poetry install is broken (its venv points at a Homebrew python that has since been upgraded away), and uv cannot consume poetry.lock — so moving to uv is the prerequisite for the bump, and `uv lock` resolves to the newest allowed versions in the same step. Merging each dependabot PR separately would also have left the lock inconsistent with pyproject.toml between merges. ## Packaging: PEP 621 + uv `[tool.poetry]` becomes a standard `[project]` table, the dev dependencies become a PEP 735 `[dependency-groups].dev`, and the build backend is `uv_build` rather than poetry-core. `uv.lock` replaces `poetry.lock`. Release automation keeps working: release-please's Python strategy reads `parsedPyProject.project || parsedPyProject.tool.poetry`, so it bumps the version in a PEP 621 `[project]` table without a config change. ## Artefacts verified before touching the publish path #202 asked for this specifically, so the uv-built wheel and sdist were diffed against the poetry-built 0.13.1 downloaded from PyPI: * same module set, same `py.typed`, same `console_scripts` entry point, same bundled LICENSE, same sdist file list; * the only substantive differences are PEP 639 metadata — `License-Expression: MIT` replaces `License: MIT`, and the now-deprecated `Classifier: License :: OSI Approved :: MIT License` is gone (uv warns about it on every build); * dependency specifiers restate the same caret semantics in PEP 440 form (`>=3.14.3,<4` where `^3.14.3` was meant), so consumers see no surprise. ## Every open dependabot PR, resolved | Package | From | To | | --- | --- | --- | | aiohttp | 3.14.1 | 3.14.3 | | pydantic | 2.13.4 | 2.13.5 | | pytest | 8.4.2 | **9.1.1** (major) | | pytest-cov | 6.3.0 | **7.1.0** (major) | | pre-commit | 3.8.0 | **4.6.2** (major) | | twine | 6.2.0 | **7.0.0** (major) | | python-dotenv | 1.2.2 | 1.2.3 | | ruff | 0.15.21 | 0.16.7 | | mypy | 1.20.2 | **2.3.1** (major) | mypy was not among the five open PRs — it was queued behind `open-pull-requests-limit: 5`. It is included because "all the majors" should mean all of them, and strict mypy was already verified to pass on 2.3.1 as well as 1.20.2. ## ruff is now pinned in exactly one place The previous arrangement pinned ruff twice: ruff-pre-commit's `rev:` in .pre-commit-config.yaml, and the version in poetry.lock that CI installed. Those are two pins dependabot can only ever bump one of, which is precisely what made every ruff bump unmergeable in the integration repo until its second pin was removed (dimplex-controller-hass#201, #213). The hooks are now local and `language: system`, resolving ruff from the project environment, so uv.lock is the single source. That also required restricting `types_or` to `python, pyi`: ruff 0.16's ruff-format hook additionally claims `markdown`, and the Python blocks in README.md and docs/ are hand-aligned on purpose (see the temperature-constant table in docs/api-reference.md). `[tool.ruff] extend-exclude = ["*.md"]` keeps a bare `ruff format .` in step with the hooks. ## CI All three jobs use `astral-sh/setup-uv` and `uv sync --frozen`; the Poetry install steps, the hand-rolled venv cache and the two "read the version out of the lock file" greps are gone, because `uv run` resolves the tools from uv.lock directly. The test matrix gains 3.14, which the package's classifiers already claimed. `--frozen`, deliberately not `--locked`: uv records the project's own version inside uv.lock, so release-please bumping `version` in pyproject.toml makes the lock "stale" — `--locked` would fail on every release PR and leave main's lock stale until someone refreshed it. `--frozen` installs exactly what the lock pins without comparing it to pyproject.toml. A dependency added without re-locking still fails loudly, as a missing import. ## Dependabot `package-ecosystem: uv`, and the group no longer filters on `update-types`, so majors and minors arrive together as one PR instead of a queue of five. Re-adding `update-types: [minor, patch]` splits majors out again if that is ever preferred. ## Docs CONTRIBUTING, README and docs/ now describe `uv sync` / `uv run`. That also fixes instructions that were already broken: `pip install -e ".[dev]"` referred to an extra that never existed, since the dev dependencies were a Poetry group. Verified: 196 tests pass (Python 3.14.2), ruff check and format clean repo-wide, mypy strict clean, pre-commit passes with the new hooks, `uv build` produces both artefacts, and `uv lock --check` reports the lock consistent. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces Poetry with uv, and folds the five open dependabot PRs into the single lock regeneration that migration requires.
Why one PR and not two
Bumping dependencies while still on Poetry wasn't possible here: uv can't consume
poetry.lock, so moving to uv is the prerequisite for the bump, anduv lockresolves the newest allowed versions in the same step. Merging the five dependabot PRs separately would also have left the lock inconsistent withpyproject.tomlbetween merges.(For the record: your local
poetryis broken — its venv points at a Homebrew python that's since been upgraded away. That's incidental, but it's why I couldn't regeneratepoetry.lockeven if that were the goal.)Every open dependabot PR, resolved in one pass
mypy wasn't one of the five — it was queued behind
open-pull-requests-limit: 5. I included it because "all the majors" should mean all of them, and strict mypy already passed on 2.3.1 and 1.20.2, so it's not a gamble. Say the word if you'd rather I drop it.Once this merges, dependabot should close its five PRs on its next run, since the versions are satisfied.
Packaging: PEP 621 + uv
[tool.poetry]→ standard[project]; dev deps → PEP 735[dependency-groups].dev; build backend →uv_build;uv.lockreplacespoetry.lock.Release automation keeps working — I checked release-please's Python strategy before committing:
It reads
[project]first, so version bumps need no config change.Artefacts verified, as #202 asked
I downloaded the poetry-built 0.13.1 from PyPI and diffed it against
uv build:py.typed, sameconsole_scriptsentry point, same bundled LICENSE, same sdist file list (and no strayuv.lock/.venvin the sdist);License-Expression: MITreplacesLicense: MIT, and the deprecatedClassifier: License :: OSI Approved :: MIT Licenseis gone — uv warns about it on every build. If you'd rather keep byte-identical metadata I can put it back;>=3.14.3,<4for what^3.14.3meant), so consumers see no surprise.ruff is now pinned in exactly one place
This one matters. The previous arrangement pinned ruff twice — ruff-pre-commit's
rev:in.pre-commit-config.yaml, and the version inpoetry.lockthat CI installed. Dependabot can only bump one file per PR, so a ruff bump would have half-updated and CI would silently lint with a different version than contributors get. That is exactly the arrangement that made every ruff bump unmergeable in the integration repo until its second pin was removed (#201, #213). The hooks are now local withlanguage: systemand resolve ruff from the project environment, souv.lockis the only source.That required restricting
types_ortopython, pyi: ruff 0.16's ruff-format hook also claimsmarkdown, and your Python blocks in README/docs are hand-aligned on purpose — a naive rev bump would have reflowed the temperature-constant table indocs/api-reference.md.[tool.ruff] extend-exclude = ["*.md"]keeps a bareruff format .in step with the hooks.CI
All three jobs use
astral-sh/setup-uv(SHA-pinned) anduv sync --frozen. The Poetry install steps, the hand-rolled venv cache, and both "read the version out of the lock file" greps are gone —uv runresolves the tools fromuv.lockdirectly. The test matrix gains 3.14, which the classifiers already claimed.--frozen, deliberately not--locked— and this is worth knowing before someone "fixes" it:Dependabot
package-ecosystem: uv(confirmed valid —Dependabot::Uv::PackageManager::ECOSYSTEM = "uv"), and the group no longer filters onupdate-types, so majors and minors arrive as one PR instead of a queue of five. Re-addingupdate-types: [minor, patch]splits majors back out.Docs
CONTRIBUTING,READMEanddocs/now describeuv sync/uv run. This also fixes instructions that were already broken:pip install -e ".[dev]"referred to an extra that has never existed, since the dev dependencies were a Poetry group.Verification
uv lock --checkconsistent · 196 tests pass on Python 3.14.2 ·ruff check+format --checkclean repo-wide · mypy strict clean ·pre-commit run --all-filespasses with the new hooks ·uv buildproduces both artefacts.Two notes for you: your existing
.venvwas built by hand (ruff 0.14.14, mypy 2.3.1 — not from any lock), so runuv syncafter merging to reconcile it; and I validated in a throwaway environment rather than touching it.