Repository navigation
Modernize Python repos: pyproject.toml + uv + semantic-release #506
Description
Activity
@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.@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.
- addedepicLarge unit of work, consisting of multiple tasksLarge unit of work, consisting of multiple tasks
on Apr 29, 2026 - added a sub-issue
on Apr 29, 2026 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/backendis not using asrc/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 likeopaque-keyswill not be usable by important tools like mypy because they're not using asrc/directory, but repos likeopenedx-corethat do use a src directory work fine).@bradenmacdonald thanks, that seems like another general improvement we should make across all of our libraries as we modernize.
Reacted by Braden MacDonaldPR for that refactor in the sample-plugin repo: openedx/sample-plugin#32 if anyone has a sec to review.
Uses setup.py/setup.cfg — pip-compile / requirements/*.txt — PUBLISHED on PyPI
- django-wiki - https://github.com/openedx/django-wiki
- XBlock - https://github.com/openedx/XBlock
- event-tracking - https://github.com/openedx/event-tracking
- edx-ora2 - https://github.com/openedx/edx-ora2
- acid-block - https://github.com/openedx/acid-block
- xblock-sdk - https://github.com/openedx/xblock-sdk
- xblock-image-explorer - https://github.com/openedx/xblock-image-explorer
- opaque-keys - https://github.com/openedx/opaque-keys
- i18n-tools - https://github.com/openedx/i18n-tools
- edx-submissions - https://github.com/openedx/edx-submissions
- xblock-drag-and-drop-v2 - https://github.com/openedx/xblock-drag-and-drop-v2
- edx-val - https://github.com/openedx/edx-val
- openedx-webhooks - https://github.com/openedx/openedx-webhooks
- xblock-google-drive - https://github.com/openedx/xblock-google-drive
- edx-milestones - https://github.com/openedx/edx-milestones
- edx-search - https://github.com/openedx/edx-search
- edx-lint - https://github.com/openedx/edx-lint
- auth-backends - https://github.com/openedx/auth-backends
- edx-rest-api-client - https://github.com/openedx/edx-rest-api-client
- edx-proctoring - https://github.com/openedx/edx-proctoring
- edx-organizations - https://github.com/openedx/edx-organizations
- ccx-keys - https://github.com/openedx/ccx-keys
- django-pyfs - https://github.com/openedx/django-pyfs
- xblock-lti-consumer - https://github.com/openedx/xblock-lti-consumer
- edx-drf-extensions - https://github.com/openedx/edx-drf-extensions
- edx-django-sites-extensions - https://github.com/openedx/edx-django-sites-extensions
- django-user-tasks - https://github.com/openedx/django-user-tasks
- django-config-models - https://github.com/openedx/django-config-models
- edx-enterprise - https://github.com/openedx/edx-enterprise
- web-fragments - https://github.com/openedx/web-fragments
- edx-celeryutils - https://github.com/openedx/edx-celeryutils
- help-tokens - https://github.com/openedx/help-tokens
- RecommenderXBlock - https://github.com/openedx/RecommenderXBlock
- DoneXBlock - https://github.com/openedx/DoneXBlock
- edx-ace - https://github.com/openedx/edx-ace
- edx-enterprise-data - https://github.com/openedx/edx-enterprise-data
- completion - https://github.com/openedx/completion
- edx-toggles - https://github.com/openedx/edx-toggles
- edx-django-utils - https://github.com/openedx/edx-django-utils
- xss-utils - https://github.com/openedx/xss-utils
- code-annotations - https://github.com/openedx/code-annotations
- edx-rbac - https://github.com/openedx/edx-rbac
- edx-when - https://github.com/openedx/edx-when
- openedx-calc - https://github.com/openedx/openedx-calc
- openedx-chem - https://github.com/openedx/openedx-chem
- staff-graded-xblock - https://github.com/openedx/staff-graded-xblock
- super-csv - https://github.com/openedx/super-csv
- edx-bulk-grades - https://github.com/openedx/edx-bulk-grades
- api-doc-tools - https://github.com/openedx/api-doc-tools
- xblock-free-text-response - https://github.com/openedx/xblock-free-text-response
- xblock-in-video-quiz - https://github.com/openedx/xblock-in-video-quiz
- enmerkar-underscore - https://github.com/openedx/enmerkar-underscore
- pytest-repo-health - https://github.com/openedx/pytest-repo-health
- license-manager - https://github.com/openedx/license-manager
- taxonomy-connector - https://github.com/openedx/taxonomy-connector
- event-routing-backends - https://github.com/openedx/event-routing-backends
- olxcleaner - https://github.com/openedx/olxcleaner
- openedx-events - https://github.com/openedx/openedx-events
- openedx-filters - https://github.com/openedx/openedx-filters
- openedx-core - https://github.com/openedx/openedx-core
- codejail-includes - https://github.com/openedx/codejail-includes
- event-bus-kafka - https://github.com/openedx/event-bus-kafka
- django-require - https://github.com/openedx/django-require
- openedx-atlas - https://github.com/openedx/openedx-atlas
- FeedbackXBlock - https://github.com/openedx/FeedbackXBlock
- xblock-skill-tagging - https://github.com/openedx/xblock-skill-tagging
- openedx-ledger - https://github.com/openedx/openedx-ledger
- edx-enterprise-subsidy-client - https://github.com/openedx/edx-enterprise-subsidy-client
- tutor-contrib-aspects - https://github.com/openedx/tutor-contrib-aspects
- event-bus-redis - https://github.com/openedx/event-bus-redis
- platform-plugin-aspects - https://github.com/openedx/platform-plugin-aspects
- xblocks-contrib - https://github.com/openedx/xblocks-contrib
- forum - https://github.com/openedx/forum
- enterprise-integrated-channels - https://github.com/openedx/enterprise-integrated-channels
- crowdsourcehinter - https://github.com/openedx/crowdsourcehinter
- codejail - https://github.com/openedx/codejail
- openedx-authz - https://github.com/openedx/openedx-authz
Uses setup.py/setup.cfg + requirements/*.txt — NOT on PyPI
- credentials-themes - https://github.com/openedx/credentials-themes
- mockprock - https://github.com/openedx/mockprock
- edx-repo-health - https://github.com/openedx/edx-repo-health
- openedx-webhooks-data-schema - https://github.com/openedx/openedx-webhooks-data-schema
- enterprise-catalog - https://github.com/openedx/enterprise-catalog
- enterprise-access - https://github.com/openedx/enterprise-access
- enterprise-subsidy - https://github.com/openedx/enterprise-subsidy
- xapi-db-load - https://github.com/openedx/xapi-db-load
- codejail-service - https://github.com/openedx/codejail-service
- openedx-user-groups - https://github.com/openedx/openedx-user-groups
- cc2olx - https://github.com/openedx/cc2olx
Uses setup.py/setup.cfg — NO requirements/*.txt — NOT on PyPI
- pr_watcher_notifier - https://github.com/openedx/pr_watcher_notifier
Reacted by Muhammad Farhan Khan- added a sub-issue
on May 19, 2026 133 remaining items
- added 7 commits that reference this issue
on Sep 29, 2026 - added a commit that references this issue
on Oct 1, 2026 - added 4 commits that reference this issue
on Oct 1, 2026
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fields🔖 Ready
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:
uv, which is faster and produces a singlereproducible
uv.locklockfile (no more per-environment.txtfiles)pyproject.toml(PEP 621/735) consolidates package metadata and dependencydeclarations in one file, eliminating
setup.py,setup.cfg, andrequirements/*.txtpython-semantic-releaseautomates version bumps and PyPI publishing from conventionalcommit 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:
edx_lint write_uv_constraints(feat: add write_uv_constraints command to manage uv constraint-dependencies edx-lint#537) — syncs global versionconstraints from edx-lint into each repo's
[tool.uv].constraint-dependenciesWhich repos qualify?
A repo should be modernized if it meets all of the following:
pip-compile/requirements/*.txtfor dependency managementsetup.pyorsetup.cfgfor package metadata (or apyproject.tomlthatstill uses
dynamic = [..., "dependencies"]pointing to a requirements file)Work per repo
1. Consolidate package metadata into
pyproject.tomlMove all package metadata into a single
pyproject.tomlusing PEP 621. This meansreplacing
setup.py/setup.cfg, declaring a staticdependencieslist under[project], and usingsetuptools-scmfor version management from git tags.Reference: backend/pyproject.toml (
[project],[build-system], and[tool.setuptools_scm]sections)setup.cfg/setup.pyinto[project]dependenciesas a static list (not dynamic from a requirements file)setuptools-scmfor version discoverysetup.pyandsetup.cfgNote: The sample-plugin houses the python library in a subdirectory and so has
to set the
rootsetting intool.setuptools_scmto... This should not benecessary for any other repo and should be omitted.
2. Switch dependency management from pip-compile to uv
Replace all
requirements/*.in+requirements/*.txtfiles with PEP 735[dependency-groups]inpyproject.tomland a singleuv.locklockfile. Thestandard groups are
test-base,test,quality,doc,ci, anddev— withadditional version-matrix groups as needed. Update
tox.inito usetox-uv'suv-venv-lock-runner, update theMakefileto useuv lock/uv sync, and updateCI 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[dependency-groups]topyproject.tomlcovering test, quality, doc, ci, and dev[tool.edx_lint].uv_constraintsfor any repo-specific version overrides,then run
edx_lint write_uv_constraintsto populate[tool.uv].constraint-dependenciesuv.lockand commit itrequirements/directorytox.inito usetox-uv>=1anduv-venv-lock-runnerwithdependency_groupsMakefiletargets (upgrade,compile-requirements,requirements)astral-sh/setup-uv, install deps viauv sync --group ci,and run tests via
uv run tox3. Add semantic-release
Configure
python-semantic-releaseso that pushing a conventional commit tomainautomatically 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.ymlNote: The sample plugin overrides
minor_tagsbecause it wants to publish newminor 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.
[tool.semantic_release]config topyproject.tomlwith abuild_commandthat sets
SETUPTOOLS_SCM_PRETEND_VERSIONat build timerelease.ymlworkflow that runs CI then publishes to PyPI via OIDCcommitlint.ymlworkflow to enforce conventional commits on PRsNotes
[tool.uv].constraint-dependenciesis machine-managed. Never edit it directly.Repo-specific version overrides belong in
[tool.edx_lint].uv_constraints.uv syncdoes not put tools on PATH. Useuv run toxin CI, not baretox.requires-python. If the new versiondrops an older Python, bump accordingly and remove that Python from the tox envlist.