Skip to content

feat: teach find_python_dependencies to scan uv.lock - #735

Merged
feanil merged 3 commits into
openedx:masterfrom
irfanuddinahmad:irfanuddinahmad/find-python-dependencies-pyproject-uv
Aug 10, 2026
Merged

feat: teach find_python_dependencies to scan uv.lock#735
feanil merged 3 commits into
openedx:masterfrom
irfanuddinahmad:irfanuddinahmad/find-python-dependencies-pyproject-uv

Conversation

@irfanuddinahmad

@irfanuddinahmad irfanuddinahmad commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What

find_python_dependencies previously only knew how to scan pip-compile style requirements.txt files (via requirements-parser) for dependencies whose PyPI-registered homepage belongs to a "second party" org (edx-unsupported, mitodl, overhangio, open-craft, eduNEXT, raccoongang) rather than openedx itself, so they can be flagged for review/migration.

Repos migrating from pip-compile to pyproject.toml + uv per the org-wide Python packaging modernization (openedx/public-engineering#506) have no flat requirements file left for it to scan. This forced openedx-platform to disable its Check Python Dependencies workflow entirely as part of its own migration (openedx/openedx-platform#38915), rather than have it silently no-op after requirements/edx/{base,testing}.txt were removed.

This closes #725.

How

iter_requirement_names() now branches on the input file name:

  • uv.lock: reads the fully-resolved [[package]] list — this matches the same direct+transitive dependency closure a pip-compile'd requirements.txt used to represent, so it's the most faithful drop-in replacement for the old --req-file requirements/edx/base.txt usage.
  • anything else: falls back to the existing requirements.txt parsing, unchanged.

pyproject.toml scanning was deliberately left out (see review discussion below): its [project.dependencies]/[dependency-groups] only list direct dependencies, not the resolved transitive closure, so scanning it directly would be misleading about what this tool actually checks.

main() also now dedupes names-per-file before hitting the PyPI API.

Bumped __version__ 4.0.0 → 4.1.0 for this new capability.

Side effect worth calling out: scanning uv.lock broadens what gets checked

uv.lock is a single unified lockfile covering every dependency-group at once (base, testing, doc, quality, assets, coverage, semgrep, etc.) — there's no way to scan "just base+testing" from it the way the old per-file .txt layout allowed. _names_from_uv_lock yields every package in the lock with no group filtering.

Concretely, for openedx-platform: the pre-migration check only ever scanned requirements/edx/base.txt + requirements/edx/testing.txt (confirmed by reading that repo's own check_python_dependencies.yml, both before and after its migration commit). Once it re-enables by pointing --req-file at uv.lock, the check will also start flagging second-party-org packages living in the previously-invisible doc/quality/assets/coverage/semgrep/development groups.

This is arguably a net positive for supply-chain coverage — a compromised or unvetted dev-tooling package still executes code on CI runners and dev machines, with access to secrets/tokens, so that's a real risk surface too, not just production code. But it is a real behavior change, not a like-for-like swap: if any of those dev-only groups currently has an unvetted second-party dependency, the check will start failing on first re-enable where it never would have before.

Verification

  • tests/test_find_python_dependencies.py covers both input formats (requirements.txt, uv.lock) plus two main()-level tests (one that should flag a second-party dependency, one that should respect --ignore).
  • Ran the new tests and the full existing suite: 107 passed (confirmed via the actual CI run log, not just locally).
  • Sanity-checked iter_requirement_names() directly against openedx-platform's real uv.lock (445 names) to confirm it doesn't choke on a real-world file.

Follow-up

Once this is released, openedx-platform's check_python_dependencies.yml can point --req-file at uv.lock and be re-enabled (currently workflow_dispatch-only + if: false, per the comment there referencing this issue) — see the scope-broadening note above before doing so.

@openedx-webhooks openedx-webhooks added open-source-contribution PR author is not from Axim or 2U core contributor PR author is a Core Contributor (who may or may not have write access to this repo). labels Jul 21, 2026
@openedx-webhooks

Copy link
Copy Markdown

Thanks for the pull request, @irfanuddinahmad!

This repository is currently maintained by @openedx/axim-engineering.

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 approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To 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:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

Details
Where 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:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@github-project-automation github-project-automation Bot moved this to Needs Triage in Contributions Jul 21, 2026
irfanuddinahmad pushed a commit to openedx/openedx-platform that referenced this pull request Jul 21, 2026
openedx/repo-tools#725 (find_python_dependencies needs to scan
pyproject.toml/uv.lock) now has a proposed fix at
openedx/repo-tools#735 -- linking it from the disabled-check comment
so re-enabling this workflow is easy to track once it merges/releases.
irfanuddinahmad pushed a commit to irfanuddinahmad/edx-platform that referenced this pull request Jul 27, 2026
openedx/repo-tools#725 (find_python_dependencies needs to scan
pyproject.toml/uv.lock) now has a proposed fix at
openedx/repo-tools#735 -- linking it from the disabled-check comment
so re-enabling this workflow is easy to track once it merges/releases.
@mphilbrick211 mphilbrick211 moved this from Needs Triage to Ready for Review in Contributions Jul 27, 2026
@mphilbrick211

Copy link
Copy Markdown

@openedx/axim-engineering hi there! Would someone be able to take a look at this?

@feanil
feanil self-requested a review July 29, 2026 12:38

@feanil feanil left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@irfanuddinahmad this looks good, I don't think it's valuable to parse the pyproject dependencies and also I think it may be a bit misleading. Let's drop that and bump the version and then I think this is good to merge and release.

yield from _dependency_group_names(all_groups.get(included, []), all_groups, seen)


def _names_from_pyproject_toml(data):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how valuable this is to have. These aren't the resolved full dependencies and so if someone ran the tool against this, they might be mislead into thinking that this tool resolves all the sub-dependencies if we pass the pyproject file instead of a lock file of some sort.

At the very least, we should document that we don't resolve dependencies via the find_python_dependencies tool. But I think it might be better to only support compiled file types like the uv.lock and *.txt files. That way the intent is clear and since we're moving everything to uv.lock, we don't need this at the moment anyway so let's not add more code than we need.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — dropped _names_from_pyproject_toml/_dependency_group_names and the pyproject.toml branch in iter_requirement_names() entirely, along with the now-unused packaging dependency (its only import was in the removed code) and the two pyproject.toml-specific tests. uv.lock/requirements.txt support is unchanged. Bumped __version__ to 4.1.0. Full suite still passes (95 tests).

irfanuddinahmad pushed a commit to irfanuddinahmad/repo-tools that referenced this pull request Aug 6, 2026
Per review (feanil, PR openedx#735): scanning pyproject.toml's
[project.dependencies]/[dependency-groups] only surfaces direct
dependencies, not the resolved transitive closure -- unlike uv.lock or
a pip-compile'd requirements.txt, both of which represent a fully
resolved dependency graph. Supporting pyproject.toml directly would be
misleading (callers could assume this tool resolves dependencies when
it doesn't) and isn't needed anyway, since repos migrating off
pip-compile land on uv.lock as their fully-resolved file.

Removed _names_from_pyproject_toml/_dependency_group_names and the
pyproject.toml branch in iter_requirement_names(), the now-unused
`packaging` dependency (only import was in the removed code) and its
two uv.lock entries, and the two tests exercising pyproject.toml
support. uv.lock and requirements.txt support is unchanged.

Bumped __version__ to 4.1.0 (new capability: uv.lock support) per
review request, ready to merge and release.
@irfanuddinahmad

Copy link
Copy Markdown
Contributor Author

Pushed — dropped pyproject.toml scanning entirely (kept uv.lock + the existing requirements.txt fallback), removed the now-unused packaging dep and its two pyproject.toml-only tests, and bumped __version__ to 4.1.0. PR description updated to match. Ready for another look.

Irfan Ahmad added 2 commits August 6, 2026 15:30
find_python_dependencies previously only understood pip-compile style
requirements.txt files (via requirements-parser). Repos migrating from
pip-compile to pyproject.toml + uv (openedx/public-engineering#506)
have no flat requirements file left for it to scan, which forced
openedx-platform to disable its Check Python Dependencies workflow
entirely (openedx/openedx-platform#38915, tracked in
openedx#725).

iter_requirement_names() now detects the input file by name:
- uv.lock: reads the fully-resolved [[package]] list, matching the
  same direct+transitive closure a pip-compile'd requirements.txt used
  to represent.
- pyproject.toml: reads [project.dependencies],
  [project.optional-dependencies], and [dependency-groups], resolving
  {include-group = "..."} references.
- anything else: falls back to the existing requirements.txt parsing,
  unchanged.

Verified against openedx-platform's actual pyproject.toml (202 names)
and uv.lock (445 names).

Closes openedx#725
Per review (feanil, PR openedx#735): scanning pyproject.toml's
[project.dependencies]/[dependency-groups] only surfaces direct
dependencies, not the resolved transitive closure -- unlike uv.lock or
a pip-compile'd requirements.txt, both of which represent a fully
resolved dependency graph. Supporting pyproject.toml directly would be
misleading (callers could assume this tool resolves dependencies when
it doesn't) and isn't needed anyway, since repos migrating off
pip-compile land on uv.lock as their fully-resolved file.

Removed _names_from_pyproject_toml/_dependency_group_names and the
pyproject.toml branch in iter_requirement_names(), the now-unused
`packaging` dependency (only import was in the removed code) and its
two uv.lock entries, and the two tests exercising pyproject.toml
support. uv.lock and requirements.txt support is unchanged.

Bumped __version__ to 4.1.0 (new capability: uv.lock support) per
review request, ready to merge and release.
@irfanuddinahmad
irfanuddinahmad force-pushed the irfanuddinahmad/find-python-dependencies-pyproject-uv branch from b93e6b3 to 2609cb9 Compare August 6, 2026 10:31
@irfanuddinahmad
irfanuddinahmad requested a review from feanil August 10, 2026 06:21
@farhan

farhan commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Two small docs fixes before merge:

PR title still says "scan pyproject.toml and uv.lock" — pyproject.toml was dropped in the second commit. Suggest updating to feat: teach find_python_dependencies to scan uv.lock.

PR description claims two main()-level tests including one for --ignore, but the test file only has one (test_main_flags_second_party_dependency_from_uv_lock). Worth updating the description to match, and optionally restoring the --ignore test for uv.lock (the ignore logic is correct — just a coverage gap).


Before this merges, it would be good to see a quick smoke test across both supported formats to confirm nothing regresses on real-world repos.

Install from this branch:

pip install "git+https://github.com/irfanuddinahmad/repo-tools.git@irfanuddinahmad/find-python-dependencies-pyproject-uv#egg=edx-repo-tools[find_dependencies]"

Test against a uv.lock repo (e.g. openedx-platform — already partially verified per the PR description):

find_python_dependencies --req-file path/to/openedx-platform/uv.lock

Test against a pip-compile requirements.txt repo (e.g. course-discovery or credentials) to confirm the existing fallback is intact:

find_python_dependencies \
  --req-file path/to/repo/requirements/production.txt \
  --req-file path/to/repo/requirements/testing.txt

Could you share the terminal output for both? Specifically: how many packages were scanned and whether any second-party packages were flagged.


I have merging rights — happy to merge this once the above points are addressed.

🤖 Generated with Claude Code

PR description claimed this test already existed; farhan caught the gap.
@irfanuddinahmad irfanuddinahmad changed the title feat: teach find_python_dependencies to scan pyproject.toml and uv.lock feat: teach find_python_dependencies to scan uv.lock Aug 10, 2026
@irfanuddinahmad

Copy link
Copy Markdown
Contributor Author

Addressed both items and ran the requested smoke tests, installing from this branch (pip install "git+https://github.com/irfanuddinahmad/repo-tools.git@irfanuddinahmad/find-python-dependencies-pyproject-uv#egg=edx-repo-tools[find_dependencies]"):

  • PR title updated to feat: teach find_python_dependencies to scan uv.lock.
  • PR description: added the missing test_main_respects_ignore_for_uv_lock test (the --ignore coverage the description already claimed) in e7770b3, so the description's test count is now accurate. Also bumped the cited suite total to 107 passed.

Smoke test 1 — uv.lock (openedx-platform, real repo):

$ find_python_dependencies --req-file openedx-platform/uv.lock
The following packages are from 2nd party orgs and should not be added as a core dependency, they can be added as an optional dependency operationally or they can be transferred to the openedx org before they are included:
https://github.com/open-craft/xblock-poll
https://github.com/mitodl/edx-sga

445 packages scanned (matches the count already in the PR description), 2 second-party packages flagged, exit code 1.

Smoke test 2 — pip-compile requirements.txt fallback (edx-platform, real repo):

$ find_python_dependencies --req-file edx-platform/requirements/edx/base.txt --req-file edx-platform/requirements/edx/testing.txt
The following packages are from 2nd party orgs and should not be added as a core dependency, they can be added as an optional dependency operationally or they can be transferred to the openedx org before they are included:
https://github.com/mitodl/edx-sga
https://github.com/open-craft/xblock-poll

355 unique packages scanned across both files, same 2 packages flagged, exit code 1. Confirms the pre-existing requirements.txt path is unaffected by this change.

Both formats behave as expected on real-world repos — ready for another look.

@feanil
feanil merged commit f737aed into openedx:master Aug 10, 2026
3 checks passed
@github-project-automation github-project-automation Bot moved this from Ready for Review to Done in Contributions Aug 10, 2026
irfanuddinahmad pushed a commit to openedx/openedx-platform that referenced this pull request Aug 10, 2026
….lock

openedx/repo-tools#735 (merged today, 13:53, 43 minutes before feanil's
review) taught find_python_dependencies to scan uv.lock directly. Revert
the workaround this workflow was disabled with: restore the pull_request/
merge_group triggers, drop if: false, and run it via `uvx --from
edx-repo-tools[find_dependencies]` against uv.lock instead of pip-installing
the tool and pointing it at the now-deleted requirements/edx/*.txt files.

Verified locally against this repo's real uv.lock: scans all packages,
correctly identifies the two pre-approved second-party dependencies
(edx-sga, xblock-poll), and exits 0 once they're passed via --ignore.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core contributor PR author is a Core Contributor (who may or may not have write access to this repo). open-source-contribution PR author is not from Axim or 2U

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

find_python_dependencies: support pyproject.toml / uv.lock, not just requirements/*.txt

5 participants