Skip to content

Modernize Python repos: pyproject.toml + uv + semantic-release #506

@feanil

Description

@feanil

Context

The openedx org is standardizing on modern Python tooling across all maintained Python
packages. This issue tracks the work of applying that standard to repos that still use
legacy tooling.

Why:

  • pip-tools is being retired in favour of uv, which is faster and produces a single
    reproducible uv.lock lockfile (no more per-environment .txt files)
  • pyproject.toml (PEP 621/735) consolidates package metadata and dependency
    declarations in one file, eliminating setup.py, setup.cfg, and requirements/*.txt
  • python-semantic-release automates version bumps and PyPI publishing from conventional
    commit messages, removing manual release steps

Reference implementation: openedx/sample-plugin- The files to
model after are backend/pyproject.toml, backend/tox.ini, backend/Makefile, and
.github/workflows/backend-ci.yml.

Supporting infrastructure:


Which repos qualify?

A repo should be modernized if it meets all of the following:

  • Is a Python package published (or intended to be published) to PyPI
  • Uses pip-compile / requirements/*.txt for dependency management
  • Uses setup.py or setup.cfg for package metadata (or a pyproject.toml that
    still uses dynamic = [..., "dependencies"] pointing to a requirements file)

Work per repo


1. Consolidate package metadata into pyproject.toml

Move all package metadata into a single pyproject.toml using PEP 621. This means
replacing setup.py/setup.cfg, declaring a static dependencies list under
[project], and using setuptools-scm for version management from git tags.

Reference: backend/pyproject.toml ([project], [build-system], and [tool.setuptools_scm] sections)

  • Migrate metadata from setup.cfg/setup.py into [project]
  • Declare dependencies as a static list (not dynamic from a requirements file)
  • Configure setuptools-scm for version discovery
  • Delete setup.py and setup.cfg

Note: The sample-plugin houses the python library in a subdirectory and so has
to set the root setting in tool.setuptools_scm to ... This should not be
necessary for any other repo and should be omitted.


2. Switch dependency management from pip-compile to uv

Replace all requirements/*.in + requirements/*.txt files with PEP 735
[dependency-groups] in pyproject.toml and a single uv.lock lockfile. The
standard groups are test-base, test, quality, doc, ci, and dev — with
additional version-matrix groups as needed. Update tox.ini to use tox-uv's
uv-venv-lock-runner, update the Makefile to use uv lock/uv sync, and update
CI to install uv and run uv run tox.

Reference: backend/pyproject.toml ([dependency-groups] and [tool.uv] sections), backend/tox.ini, backend/Makefile, .github/workflows/backend-ci.yml

  • Add [dependency-groups] to pyproject.toml covering test, quality, doc, ci, and dev
  • Add [tool.edx_lint].uv_constraints for any repo-specific version overrides,
    then run edx_lint write_uv_constraints to populate [tool.uv].constraint-dependencies
  • Generate uv.lock and commit it
  • Delete the requirements/ directory
  • Update tox.ini to use tox-uv>=1 and uv-venv-lock-runner with dependency_groups
  • Update Makefile targets (upgrade, compile-requirements, requirements)
  • Update CI to install uv via astral-sh/setup-uv, install deps via uv sync --group ci,
    and run tests via uv run tox

3. Add semantic-release

Configure python-semantic-release so that pushing a conventional commit to main
automatically cuts a version, tags it, and publishes to PyPI. Add commitlint to enforce
conventional commit format on PRs.

Reference: backend/pyproject.toml ([tool.semantic_release] section), .github/workflows/release.yml

Note: The sample plugin overrides minor_tags because it wants to publish new
minor versions on docs changes. That is not needed in our other libraries. They
should use the default value unless you know for sure you need to use something
different.

  • Add [tool.semantic_release] config to pyproject.toml with a build_command
    that sets SETUPTOOLS_SCM_PRETEND_VERSION at build time
  • Add a release.yml workflow that runs CI then publishes to PyPI via OIDC
  • Add a commitlint.yml workflow to enforce conventional commits on PRs
  • Confirm PyPI trusted publisher (OIDC) is configured for the repo

Notes

  • [tool.uv].constraint-dependencies is machine-managed. Never edit it directly.
    Repo-specific version overrides belong in [tool.edx_lint].uv_constraints.
  • uv sync does not put tools on PATH. Use uv run tox in CI, not bare tox.
  • A new framework version may require bumping requires-python. If the new version
    drops an older Python, bump accordingly and remove that Python from the tox envlist.
  • OEP-67 ADR documenting this migration is in progress (link TBD once merged).

Metadata

Metadata

Assignees

Labels

epicLarge unit of work, consisting of multiple tasks

Type

No type

Projects

Status

📋 Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions