Skip to content

build: Migrate from Poetry to uv - #143

Merged
akalex merged 8 commits into
masterfrom
chore/migrate-poetry-to-uv
Aug 7, 2026
Merged

akalex merged 8 commits into
masterfrom
chore/migrate-poetry-to-uv

Conversation

@akalex

@akalex akalex commented Aug 7, 2026

Copy link
Copy Markdown
Member

Summary

Replaces Poetry with uv as this project's dependency manager, lock-file generator, task runner, and release tool.

This is a tooling-only change. pyproject.toml was already PEP 621 with hatchling as the build backend, so no package metadata was rewritten. The published package, its runtime dependencies (google-auth, httpx, h11), and the build backend are all unchanged. Not one line under async_firebase/ or tests/ was touched.

What changed

Area Before After
Lock file poetry.lock uv.lock
Dev deps [project.optional-dependencies] dev PEP 735 [dependency-groups] dev
Makefile poetry run … uv run …
CI snok/install-poetry + actions/setup-python + actions/cache astral-sh/setup-uv@v9
CD poetry build / poetry publish + PYPI_TOKEN uv build / uv publish via OIDC
Dependabot package-ecosystem: pip package-ecosystem: uv

Dependency versions are untouched

Every runtime and dev dependency constraint moved across character-for-character. The only pyproject.toml change is the table header: [project.optional-dependencies][dependency-groups].

CI got simpler

The create-virtualenv job is gone. It ran a five-version matrix purely to warm a venv cache that each downstream job rebuilt anyway; setup-uv's built-in caching replaces it. The four remaining jobs keep their exact names (linters-ruff, linters-mypy, test, integration-test), so required-status-checks are unaffected. Triggers, the 3.10–3.14 matrix, needs: edges, the fork guard, and the Codacy step are all unchanged.

CI now syncs with uv sync --locked, which fails the build if uv.lock drifts from pyproject.toml.

Dependabot had to change ecosystems

The pip ecosystem does not understand uv.lock — left as-is, Dependabot would have silently stopped updating dependencies once poetry.lock was deleted. The dev-dependencies group also moved from a dependency-type: "development" filter to an explicit patterns list, because dependency-type is documented for pip but not for uv. Runtime deps are deliberately excluded from the group so they keep arriving as individually reviewable PRs.

⚠️ Breaking change (contributors only)

The dev extra has been removed. pip install async-firebase[dev] no longer installs anything.

Library consumers are unaffected — this only ever contained CI tooling. Worth knowing: uv/pip resolve the missing extra with a warning, not an error, so the command still exits 0 while installing only the runtime packages.

Contributors with an existing environment should run:

rm -rf .venv && make setup_dev

make install behaviour change

The old target ran poetry config virtualenvs.create false and installed globally. uv sync --no-dev now creates and populates .venv instead. If anything downstream depended on the global install, uv sync --no-dev --active is the equivalent.

🔴 Required before the next release

A trusted publisher must be configured on PyPI, or the next tagged release will fail to publish.

PyPI → async-firebase → Manage → Publishing → Add a new GitHub publisher:

  • Owner: healthjoy
  • Repository: async-firebase
  • Workflow: cd.yml
  • Environment: (leave blank)

Keep the PYPI_TOKEN secret in place until one release has published successfully via OIDC, then delete it.

Testing

Verified locally on a clean rm -rf .venv && uv sync --locked rebuild:

  • 138 passed, 8 skipped, 98% coverage — identical to the pre-migration baseline
  • ruff check and ruff format --check clean
  • mypy clean
  • uv build produces both sdist and wheel; the built wheel installs into a throwaway env and imports
  • twine check passes on both artifacts
  • make install, make setup_dev, make test, make mypy all work
  • ✅ No poetry references remain outside the CHANGES.md entry

Not verifiable locally:

  • The 3.10–3.12 matrix legs (local runs use a single interpreter) — these run for the first time on this PR.
  • CD/OIDC publishing, which only proves out on a real tagged release.

Note for reviewers

A whole-branch review caught one genuine bug worth calling out, fixed in 10d30ac: the CD job originally specified permissions: id-token: write alone. GitHub replaces rather than merges permissions, so every unlisted scope drops to noneactions/checkout would have failed with a 403 at the release job's first step, before uv publish ever ran. Adding contents: read fixes it, matching the pattern already used in codeql-analysis.yml.

The uv.lock diff is large but entirely generated — review pyproject.toml instead to confirm no constraint drifted.

akalex added 7 commits August 7, 2026 09:54
Replaces poetry.lock with uv.lock. Dev dependencies move from
[project.optional-dependencies] to [dependency-groups], which uv
installs by default on sync.

BREAKING: the 'dev' extra is no longer published, so
'pip install async-firebase[dev]' no longer works. Dev dependencies
are CI tooling and were never intended for library consumers.
Drops the create-virtualenv cache-warming job, now redundant with
setup-uv's built-in caching. Uses uv sync --locked so CI fails if
uv.lock drifts from pyproject.toml.
Replaces poetry build/publish with uv build/publish using OIDC,
removing the need for a PYPI_TOKEN secret.

Requires a trusted publisher configured on PyPI for this repo and
cd.yml before the next tagged release.
The pip ecosystem does not update uv.lock. Also replaces the
dependency-type group filter, which is undocumented for uv, with an
explicit pattern list covering every dev-group member.
Also gitignores docs/superpowers/, which holds agent tooling scratch
output that should not be committed.
Specifying any permissions block drops every unlisted scope to none, so
the OIDC-only block left actions/checkout without contents: read and
would have failed the release job at checkout on the first tagged push.
@akalex akalex self-assigned this Aug 7, 2026
astral-sh/setup-uv does not publish floating major tags — neither v9 nor
v8 resolve, only exact versions. The v9 reference failed every job with
"Unable to resolve action astral-sh/setup-uv@v9".
@akalex
akalex merged commit ca83847 into master Aug 7, 2026
10 checks passed
@akalex
akalex deleted the chore/migrate-poetry-to-uv branch August 7, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant