Skip to content

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

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).

Activity

  1. xitij2000 commented on Apr 27, 2026

    @xitij2000

    @feanil Sorry if this was already discussed and I'm jumping in too late, but I'd like to recommend hatch instead of uv as the build backend. It supports build environments which will allow replacing tox as well. It's a pypa project so it follows PEP standards closely and can still use uv for installing packages.
    Sorry if this has already been discussed and eliminated.

  2. feanil commented on Apr 29, 2026

    @feanil
    ContributorAuthor

    @xitij2000 My understanding is that the build backend is still setuptools and we're just using uv for dependency management. Hatch seems promising as a setuptools replacement but I haven't evaluated it too deeply yet because I didn't want to add complexity to the switch from setup.py to pyproject.toml by also changing the build backend at the same time. Let me know if I misunderstood something about the ecosystem here.

  3. added
    epicLarge unit of work, consisting of multiple tasks
    on Apr 29, 2026
  4. farhan commented on Apr 29, 2026

    @farhan
  5. moved this from 🆕 New to 📋 Backlog in Aximprovements Teamon Apr 29, 2026
  6. bradenmacdonald commented on Apr 30, 2026

    @bradenmacdonald

    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.

    I just want to point out that sample-plugin/backend is not using a src/ directory layout, and I would highly recommend that we try to adopt that where feasible, for these reasons and this reason (editable installs of repos like opaque-keys will not be usable by important tools like mypy because they're not using a src/ directory, but repos like openedx-core that do use a src directory work fine).

  7. feanil commented on Apr 30, 2026

    @feanil
    ContributorAuthor

    @bradenmacdonald thanks, that seems like another general improvement we should make across all of our libraries as we modernize.

  8. feanil commented on May 1, 2026

    @feanil
    ContributorAuthor

    PR for that refactor in the sample-plugin repo: openedx/sample-plugin#32 if anyone has a sec to review.

  9. salman2013 commented on May 6, 2026

    @salman2013

    Uses setup.py/setup.cfg — pip-compile / requirements/*.txt — PUBLISHED on PyPI

    Uses setup.py/setup.cfg + requirements/*.txt — NOT on PyPI

    Uses setup.py/setup.cfg — NO requirements/*.txt — NOT on PyPI

  10. moved this from 📋 Backlog to 🏗 In progress in Aximprovements Teamon May 13, 2026
  11. 133 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

epicLarge unit of work, consisting of multiple tasks

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions