feat: modernize openedx-authz to uv + pyproject.toml + semantic-release - #371
feat: modernize openedx-authz to uv + pyproject.toml + semantic-release#371irfanuddinahmad wants to merge 4 commits into
Conversation
Adopt the src/ layout for openedx_authz per the 2026-07-15 decision on openedx/public-engineering#506: move openedx_authz/ -> src/openedx_authz/ so editable installs resolve correctly for tools like mypy (flat-layout editable installs are not reliably resolvable). Update every hardcoded flat-path reference to the new location: MANIFEST.in, .coveragerc source, docs/conf.py (version-file path and the sphinx-apidoc source paths), tox.ini (pytest --cov/--ignore and the quality testenv's pylint/ruff/pydocstyle targets), and the Makefile's translation targets (extract/compile/detect/pull/dummy_translations, ruff format/check). pyproject.toml's [tool.setuptools.packages.find] where=["src"] wiring lands in the next commit alongside the rest of the metadata migration.
Replace setup.py/setup.cfg with PEP 621 static metadata in pyproject.toml. setuptools-scm now derives the version from git tags (fallback_version = "0.0.0"); the hardcoded __version__ in openedx_authz/__init__.py is removed since nothing else in the repo reads it beyond docs/conf.py, which now gets the version via importlib.metadata instead of regex-parsing __init__.py. Coverage configuration is consolidated from .coveragerc into [tool.coverage.*]. The dead [isort]/[wheel] settings from setup.cfg are ported into [tool.isort] verbatim (import sorting is actually enforced via ruff's "I" rule per the CHANGELOG's prior pycodestyle/isort -> ruff migration, but the old isort section is preserved rather than silently dropped). Also fixes a pre-existing MANIFEST.in/README.rst mismatch: the repo's license file is named `LICENSE` (no extension), but both referenced the nonexistent `LICENSE.txt`. Part of openedx/public-engineering#506, tracked in #516.
Replace requirements/*.in/*.txt with PEP 735 dependency groups in
pyproject.toml (test-base, test, quality, doc, ci, dev), resolved into
a committed uv.lock. Populate [tool.uv].constraint-dependencies via
`edx_lint write_uv_constraints` and add the (currently empty)
[tool.edx_lint].uv_constraints override point.
Update tox.ini to use tox-uv (uv-venv-lock-runner) and dependency_groups
instead of -r requirements/*.txt. Update the Makefile's upgrade/quality/
format/requirements/test/diff_cover/test-all targets to go through
`uv run`/`uv sync`/`uv lock` instead of pip-compile/pip-sync. Update
.readthedocs.yaml to install via `uv sync --group doc`. Drop the now-
stale requirements/ references from MANIFEST.in and .gitignore.
Update the CI workflow to install uv via astral-sh/setup-uv (SHA-pinned,
with caching), sync via `uv sync --group ci`, and run each tox env via
`uv run tox -e <env>`; add `fetch-depth: 0` so setuptools-scm can see
tags during test runs, and `permissions: contents: read`.
While verifying the full tox matrix locally post-migration, found and
fixed a real bug surfaced by the src/ layout move: three tests in
test_enforcer.py opened `openedx_authz/engine/config/{model.conf,
authz.policy}` as paths relative to the process cwd rather than via the
package's own ROOT_DIRECTORY (as settings/common.py and settings/test.py
already correctly do), so they broke once the package moved under src/.
Part of openedx/public-engineering#506, tracked in #516.
Add python-semantic-release configuration to pyproject.toml
(major_on_zero = false, allow_zero_version = true; build_command uses
python -m build since python-semantic-release's action environment
doesn't have uv available) and a release.yml workflow that runs the CI
suite, cuts a release with python-semantic-release on pushes to main,
and publishes to PyPI via OIDC trusted publishing (no stored API
token). ci.yml now triggers on workflow_call instead of push, since
release.yml owns that path (avoids running the suite twice on main).
Replace the old tag-triggered, token-based pypi-publish.yml (built
`python setup.py sdist bdist_wheel` and used an unpinned
`pypa/gh-action-pypi-publish@release/v1` ref with a stored
PYPI_UPLOAD_TOKEN) -- it would otherwise race release.yml's OIDC
publish on the first semantic-release tag. pypa/gh-action-pypi-publish
is pinned to a commit SHA (release/v1 is a floating branch, not a
version tag: confirmed root cause of a real production failure on a
sibling repo in this effort); the python-semantic-release and
actions/{upload,download}-artifact actions use plain version tags
matching openedx/XBlock's actual, currently-releasing release.yml,
per the org-wide lesson that hand-verified SHA pins for those four
actions were wrong in 3 of 5 audited sibling PRs.
Pre-flight check: latest git tag v1.21.1 (via --sort=-v:refname)
matches the version currently live on PyPI (1.21.1).
Part of openedx/public-engineering#506, tracked in #516.
|
Thanks for the pull request, @irfanuddinahmad! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
Summary
Modernize
openedx-authztosrc/layout + uv + pyproject.toml (PEP 621/735) + python-semantic-release.Part of openedx/public-engineering#506 (tracked in #516).
openedx_authz/tosrc/openedx_authz/(per the 2026-07-15 decision on #506)setup.py/setup.cfgwithpyproject.toml(PEP 621 static metadata);.coveragercfolded into[tool.coverage.*]uvwith PEP 735 dependency groups; commituv.locktox.inito usetox-uvwithuv-venv-lock-runnerastral-sh/setup-uv, SHA-pin the actions that need itpython-semantic-release+release.yml, replacing the old tag-triggeredpypi-publish.yml; publish to PyPI via OIDCRemoved
Deleted files:
setup.py,setup.cfg,.coveragerc,requirements/(all.in/.txtfiles),.github/workflows/pypi-publish.ymlNot included
No ruff/lint-tooling changes beyond what already existed — this migration is tooling-only.
Versioning
Dynamic —
setuptools-scmderives the package version from git tags. Confirmed the latest git tag matches the latest version actually published on PyPI (1.21.1), so the first automated release should compute a version strictly newer than that.Testing Notes
Verified locally:
uv lockresolves cleanly,uv sync --group devsucceeds,uv run toxpasses,python -m buildproduces a correctly-versioned wheel with tests excluded.Could not verify locally (needs CI / a maintainer):
openedx-authz— not a blocker to merging, but the first automated release will fail at thepublish_to_pypijob until it's set up.OPENEDX_SEMANTIC_RELEASE_GITHUB_TOKENorg secret is configured for this repo..github/workflows/upgrade-python-requirements.ymlcallsopenedx/.github's shared reusable workflow, which hardcodesadd-paths: requirementswith no override input — now thatrequirements/is deleted, that scheduled job will keep running but silently stop producing real dependency-upgrade PRs. Fix needs to land inopenedx/.github, not this repo.Code reviewer notes
release.yml's action pins intentionally matchopenedx/XBlock's actual, already-releasingrelease.yml: plain version tags forpython-semantic-release,publish-action,upload-artifact,download-artifact; onlypypa/gh-action-pypi-publishis SHA-pinned (documented@release/v1floating-branch bug), pinned to the verified commit SHA (not the tag object's SHA).This PR was created with Claude Code.