Modernize python tooling - #519
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for the pull request, @salman2013! 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. |
Populates [tool.uv].constraint-dependencies with setuptools<82.0 and common constraints so uv.lock pins setuptools to <82 (required by openedx-django-pyfs which uses pkg_resources). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@openedx/axim-engineering this is ready for review. Thanks! |
|
👋 Reviewed this against the same checklist we've been applying across the modernization effort (openedx/public-engineering#506/#511/#513/#514). A couple of things worth fixing before merge: 1. Old 2. Minor/non-blocking: |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
24e1715 to
6bad88d
Compare
There was a problem hiding this comment.
Improvements:
-
CHANGELOG.rstnot deleted — for PyPI repos (release gate passed),CHANGELOG.rstshould be deleted becausepython-semantic-releasetakes over release notes. The file is also still listed inMANIFEST.in. — this is an absent deletion. -
.github/workflows/pypi-publish.ymlnot deleted — this workflow fires on every tag push and will conflict withrelease.yml, causing duplicate publish attempts.
| @@ -0,0 +1,161 @@ | |||
| [build-system] | |||
| requires = ["setuptools>=64", "setuptools-scm>=8.0"] | |||
There was a problem hiding this comment.
We had a discussion on it.
It's not a blocker though.
| "workbench" = ["static/**/*", "templates/**/*", "test/**/*"] | ||
|
|
||
| [tool.setuptools.exclude-package-data] | ||
| "*" = ["tests*", "*.tests*", "spec*", "*.spec*"] |
There was a problem hiding this comment.
The pattern "tests*" does not match directories named test/ (singular). The test dirs in this repo (workbench/test/, sample_xblocks/basic/test/) use the singular form, so they appear in the built wheel. Add "test*" and "*.test*":
"*" = ["test*", "tests*", "*.test*", "*.tests*", "spec*", "*.spec*"]There was a problem hiding this comment.
Confirmed still outstanding at the current head (6bad88d) -- line is now unchanged: "*" = ["tests*", "*.tests*", "spec*", "*.spec*"], which still won't match the singular test/ dirs (workbench/test/, sample_xblocks/basic/test/). Minimal fix that matches the actual dir names without over-broadening to any file merely starting with "test":
| "*" = ["tests*", "*.tests*", "spec*", "*.spec*"] | |
| "*" = ["tests*", "*.tests*", "spec*", "*.spec*", "test/*", "*/test/*"] |
|
|
||
| [tool.coverage.run] | ||
| branch = true | ||
| source = ["."] |
There was a problem hiding this comment.
After the src/ move, source = ["."] measures coverage from the repo root rather than the installed packages. Use source_pkgs instead:
source_pkgs = ["workbench", "sample_xblocks"]This ensures pytest-cov targets the installed package under src/ rather than unrelated root-level files.
There was a problem hiding this comment.
Confirmed still source = ["."] at the current head. Suggested fix:
| source = ["."] | |
| source_pkgs = ["workbench", "sample_xblocks"] |
| branch = true | ||
| source = ["."] | ||
| omit = [ | ||
| "workbench/test/*", |
There was a problem hiding this comment.
The omit paths here (and on the next line) use the pre-src/ layout. After the move, test files live at src/workbench/test/* and src/sample_xblocks/*/test/*, so these patterns will not match and test-helper code will be included in coverage:
omit = [
"src/workbench/test/*",
"src/sample_xblocks/*/test/*",
"*/migrations/*",
"*/__pycache__/*",
"*/settings.py",
]There was a problem hiding this comment.
Confirmed still unfixed -- both omit lines are unchanged (workbench/test/*, sample_xblocks/*/test/*), pre-src/ layout. Since this comment spans two lines I'm not using a suggestion block here (a single-line suggestion on a two-line comment risks a partial apply that duplicates the other line) -- but the fix is:
omit = [
"*/workbench/test/*",
"*/sample_xblocks/*/test/*",
"*/migrations/*",
"*/__pycache__/*",
"*/settings.py",
]
Using a */ prefix rather than hardcoding src/ so it still matches regardless of whether coverage sees the editable-install path or a site-packages path.
| __version__ = '0.14.0' | ||
| from importlib.metadata import version | ||
|
|
||
| __version__ = version("xblock-sdk") |
There was a problem hiding this comment.
importlib.metadata.version() raises PackageNotFoundError on any checkout that hasn't been pip install -e .'d. Wrap with a fallback:
from importlib.metadata import version, PackageNotFoundError
try:
__version__ = version("xblock-sdk")
except PackageNotFoundError:
__version__ = "0.0.0"There was a problem hiding this comment.
Confirmed still unwrapped at the current head:
from importlib.metadata import version
__version__ = version("xblock-sdk")Same real risk as the sibling repos in this effort -- any environment where xblock-sdk's dist-info isn't discoverable at import time raises unhandled and takes down the whole package on import.
This comment is anchored on the __version__ = ... line only, and the fix also touches the import line above it, so a single-line suggestion here would leave a duplicate import if applied as-is. Full fix:
from importlib.metadata import PackageNotFoundError, version
try:
__version__ = version("xblock-sdk")
except PackageNotFoundError:
__version__ = "unknown"|
|
||
| - name: Upload dist artifacts | ||
| if: steps.release.outputs.released == 'true' | ||
| uses: actions/upload-artifact@v4 |
There was a problem hiding this comment.
actions/upload-artifact@v4 is a floating tag. Pin to a SHA with a version comment for supply-chain security, consistent with actions/checkout and setup-uv elsewhere in this PR.
There was a problem hiding this comment.
Confirmed still @v4 (floating) at the current head. Verified real SHA via the tags API (git/refs/tags/v4 on actions/upload-artifact resolves to this commit):
| uses: actions/upload-artifact@v4 | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 |
|
|
||
| steps: | ||
| - name: Download dist artifacts | ||
| uses: actions/download-artifact@v4 |
There was a problem hiding this comment.
actions/download-artifact@v4 is a floating tag. Pin to a SHA with a version comment, same as the upload step above.
There was a problem hiding this comment.
Confirmed still @v4 (floating) at the current head. Verified real SHA the same way (git/refs/tags/v4 on actions/download-artifact):
| uses: actions/download-artifact@v4 | |
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 |
| @@ -1,33 +1,33 @@ | |||
| name: Python CI | |||
| on: | |||
| push: | |||
There was a problem hiding this comment.
The push: branches: [master] trigger was removed.
Is this intentional?
There was a problem hiding this comment.
Checked -- this is fine, not a regression. ci.yml dropped its standalone push: branches: [master] trigger, but release.yml (which itself triggers on: push: branches: [master]) calls ci.yml via workflow_call as its run_tests job and gates release on needs: run_tests. So the full test suite still runs on every push to master -- it's just invoked through release.yml now instead of ci.yml triggering itself redundantly. Net behavior is unchanged; this matches the pattern used elsewhere in this migration (tests-gate-release via workflow_call).
| install: requirements | ||
|
|
||
| test: clean ## run tests in the current virtualenv | ||
| pip install -qr requirements/local.txt --exists-action w ## Install sample xblocks |
There was a problem hiding this comment.
local dependency group is missing in the pyproject.toml
its also missing here while testing.
Is this intentional?
There was a problem hiding this comment.
Confirmed intentional on the dependency-group side: the old requirements/local.txt only did -e . (installing the package itself), and [tool.uv] package = true in pyproject.toml means every uv sync already installs this package in editable mode -- so there's no need for a separate "local" group.
But the Makefile line itself (now at line 47, shifted since your comment) is a live bug, not just a stale reference: requirements/local.txt no longer exists in this PR at all (confirmed -- the whole requirements/ dir is deleted), so make coverage fails outright today.
| pip install -qr requirements/local.txt --exists-action w ## Install sample xblocks |
(deletes just that one pip install line -- pytest --cov-report html right below already runs against whatever's installed via uv sync, no separate install step needed.)
There was a problem hiding this comment.
The local group is intentionally absent. The old requirements/local.txt only contained -e . (install the package in editable mode), which is now
handled automatically by package = true in [tool.uv] — every uv sync call installs the package in editable mode without a separate group.
irfanuddinahmad
left a comment
There was a problem hiding this comment.
Second pass -- replied to farhan's 9 outstanding threads above with current-code confirmation (all still unfixed as of this head) plus SHA-pins/suggestions. A few new things beyond those threads:
gh pr viewcurrently showsmergeable: CONFLICTINGagainst master. CI is green but predates that conflict, so it hasn't actually validated this code against current master.- Two now-dead workflow files are still present and weren't in farhan's earlier pass:
.github/workflows/pypi-publish.ymlreferencesrequirements/pip.txtand callspython setup.py sdist bdist_wheel-- both deleted by this PR, so this workflow would fail outright if it ever ran (a tag push), and it's fully superseded byrelease.yml'spublish_to_pypijob anyway. Worth deleting rather than leaving a broken duplicate publish path around. .github/workflows/upgrade-python-requirements.ymlcalls the org's pip-tools-oriented reusable workflow (openedx/.github/.github/workflows/upgrade-python-requirements.yml@master), which doesn't have anything to do now that there's norequirements/*.inleft to compile -- is this staying around intentionally (e.g. pending an org-wide uv equivalent) or should it go too?changelog: "false"inrelease.ymldisables changelog generation same as flagged on sibling PRs in this effort. Unlike some of those, this repo already has realCHANGELOG.rsthistory and no insertion marker, so nothing's at risk of being deleted -- but it does mean no changelog entries get generated going forward with no stated reason.- Unlike the #511 XBlocks track's adoption of ruff elsewhere (e.g.
xblocks-core), this repo has no ruff config at all -- just noting the inconsistency, not asking for it here.
| ] | ||
|
|
||
| [tool.uv] | ||
| package = true |
There was a problem hiding this comment.
A dev-named dependency-group exists (line 129), and every uv sync call actually used in this repo already names an explicit group (--group dev, --group ci) -- exactly the condition where default-groups = [] is needed. Without it, uv sync --group ci in ci.yml also implicitly syncs the full dev superset (which includes quality+doc+ci) alongside it, installing sphinx/pycodestyle/pydocstyle/edx-lint/isort into what's meant to be a minimal CI job.
| package = true | |
| package = true | |
| default-groups = [] |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Keep setup-uv over setup-python (our modernization) - Keep pypi-publish.yml deleted (replaced by release.yml) - Keep requirements/ deleted (replaced by uv dependency groups) - Take actions/checkout v7.0.1 bump from upstream Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feanil
left a comment
There was a problem hiding this comment.
Looks good, seems like it will be good to merge once the merge conlficts are resolved.
Modernizes the Python tooling for this repo in three phases, aligning with the Open edX org standard established in openedx/sample-plugin.
Ticket: openedx/public-engineering#511
Parent ticket: openedx/public-engineering#506
Changes generated by Claude Sonnet 4.6 using the modernize-python-tooling skill, reviewed by a human.