Skip to content

CALUNGA-283 - Add combined venv fallback for cross-package import testing#294

Open
smatula wants to merge 1 commit into
calungaproject:mainfrom
smatula:combined-venv-fallback
Open

CALUNGA-283 - Add combined venv fallback for cross-package import testing#294
smatula wants to merge 1 commit into
calungaproject:mainfrom
smatula:combined-venv-fallback

Conversation

@smatula
Copy link
Copy Markdown

@smatula smatula commented May 29, 2026

Some wheels fail to import individually because they depend on sibling packages at import time (e.g. sphinxcontrib needs sphinx/docutils). This adds a combined venv fallback that re-tests all importable wheels in a single shared environment when individual testing has failures.

The fallback uses tiered installs to handle multiple versions of the same package, with post-install version verification to prevent false positives when pip resolves a different version via dependency resolution.

Summary by Sourcery

Add a combined virtualenv fallback path to re-run wheel import tests when individual per-wheel venv testing reports failures.

Enhancements:

  • Introduce tiered combined-venv installation of wheels to support testing cross-package import dependencies while handling multiple versions of the same package safely.
  • Add version verification logic to ensure the wheel version being import-tested matches the installed version in the combined virtualenv and fall back to the individual phase result otherwise.
  • Adjust final result reporting to distinguish passes that occur via the combined-venv fallback from those that pass in the initial per-wheel phase.

Tests:

  • Extend the wheel install-and-import testing task to track importable wheels, rerun failed imports in a shared venv, and produce a separate combined-venv summary report.

Some wheels fail to import individually because they depend on sibling
packages at import time (e.g. sphinxcontrib needs sphinx/docutils).
This adds a combined venv fallback that re-tests all importable wheels
in a single shared environment when individual testing has failures.

The fallback uses tiered installs to handle multiple versions of the
same package, with post-install version verification to prevent false
positives when pip resolves a different version via dependency resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 29, 2026

Reviewer's Guide

Adds a two-phase wheel import test: phase 1 runs existing per-wheel venv tests while tracking importable wheels and failures; phase 2 introduces a combined-venv fallback that re-tests importable wheels together using tiered installs to handle multiple versions and verifies installed versions, with separate combined-venv reporting and updated final result messaging.

File-Level Changes

Change Details Files
Track importable wheels and whether any individual per-wheel venv test failed to decide if a combined-venv fallback phase is needed.
  • Initialize IMPORTABLE_WHEELS array and INDIVIDUAL_FAILED flag before the per-wheel loop.
  • Append each non-empty, importable wheel to IMPORTABLE_WHEELS during phase 1.
  • Mark INDIVIDUAL_FAILED=true on pip install failure, verify_import script errors, and non-SKIP test failures in phase 1.
  • Short-circuit with RESULT: PASSED and exit 0 when INDIVIDUAL_FAILED is false after phase 1 summary.
tasks/install-and-import-wheels.yaml
Introduce a combined-venv fallback phase that installs and tests all importable wheels together to cover cross-package import dependencies.
  • Create a new /tmp/test-venv-combined virtualenv used only for the fallback phase.
  • Compute install tiers in Python to group wheels by package name and sort versions so each tier can be installed sequentially without version conflicts.
  • Persist tier structure to /tmp/install-tiers.json and stream tiers into a shell loop that installs each tier with pip and runs imports immediately after installation.
  • Set up a separate COMBINED_RESULTS_DIR, copy over SKIP results from phase 1, and write combined-phase results there.
tasks/install-and-import-wheels.yaml
Verify that each wheel in the combined venv is tested against the intended version and fall back to individual results when the installed version does not match.
  • Derive EXPECTED_VER and normalized PKG_NAME from the wheel filename for each wheel in a tier.
  • Query the installed version via importlib.metadata.version() inside the combined venv and compare it to EXPECTED_VER.
  • When the installed version is NOT_INSTALLED or mismatched, skip running verify_import and instead copy the individual phase result JSON into the combined results directory for that wheel.
  • Only run verify_import.py in the combined venv when the expected version matches the installed version, reusing the same PASS/FAIL/SKIP handling and error-detail printing as phase 1.
tasks/install-and-import-wheels.yaml
Add a combined-venv summary report and adjust final task result messaging to distinguish fallback-based passes.
  • Aggregate PASS, FAIL, and SKIP counts from JSON results in COMBINED_RESULTS_DIR, printing a tabular combined summary and per-wheel failure details similar to the phase 1 report.
  • Reuse the NO TESTS RUN and FAILED summary logic based on TOTAL, PASS_COUNT, FAIL_COUNT, and SKIP_COUNT, but now using combined results.
  • Change the final success message to 'RESULT: PASSED (via combined venv fallback)' when the overall result is determined after running the combined venv phase.
tasks/install-and-import-wheels.yaml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@smatula smatula marked this pull request as ready for review June 2, 2026 11:03
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The wheel filename parsing for package name and version (splitting on - and doing custom sort_key) is fairly ad‑hoc and may mis-handle PEP 440 edge cases (e.g. local versions, pre/post releases); consider using packaging.version.Version and packaging.utils.canonicalize_name (or a small helper) to make tier grouping and version comparison more robust.
  • The logic that derives PKG_NAME from the wheel filename (name.split('-')[0].lower().replace('_','-')) assumes the distribution name has no dashes in it; if this runs against wheels with multiple - segments in the name, the combined venv verification could target the wrong package, so it might be safer to reuse the same name parsing helper you use for tiering or a PEP 427/440-aware parser.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The wheel filename parsing for package name and version (splitting on `-` and doing custom `sort_key`) is fairly ad‑hoc and may mis-handle PEP 440 edge cases (e.g. local versions, pre/post releases); consider using `packaging.version.Version` and `packaging.utils.canonicalize_name` (or a small helper) to make tier grouping and version comparison more robust.
- The logic that derives `PKG_NAME` from the wheel filename (`name.split('-')[0].lower().replace('_','-')`) assumes the distribution name has no dashes in it; if this runs against wheels with multiple `-` segments in the name, the combined venv verification could target the wrong package, so it might be safer to reuse the same name parsing helper you use for tiering or a PEP 427/440-aware parser.

## Individual Comments

### Comment 1
<location path="tasks/install-and-import-wheels.yaml" line_range="581-583" />
<code_context>
+                # actually installed. If pip resolved a different version
+                # (e.g. via dependency resolution), carry over the individual
+                # phase result instead of testing the wrong version.
+                EXPECTED_VER=$(python3.12 -c "from pathlib import PurePosixPath; print(PurePosixPath('${WHEEL}').name.split('-')[1])")
+                PKG_NAME=$(python3.12 -c "from pathlib import PurePosixPath; print(PurePosixPath('${WHEEL}').name.split('-')[0].lower().replace('_', '-'))")
+                INSTALLED_VER=$(/tmp/test-venv-combined/bin/python -c "
+        from importlib.metadata import version
+        try:
</code_context>
<issue_to_address>
**issue (bug_risk):** Expected vs installed version comparison inherits the same split('-')[1] fragility and may mis-detect mismatches.

`EXPECTED_VER` is derived with `PurePosixPath(...).name.split('-')[1]`, which assumes a `name-version-...` pattern with no dashes in `name`. For projects whose names contain dashes, this will compute the wrong expected version and incorrectly report a mismatch, triggering unnecessary fallbacks.

Consider introducing a small helper that parses wheel filenames according to the wheel spec (extracting normalized project name and version), and reuse it both here and in the tier-building logic to avoid this class of bugs.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +581 to +583
EXPECTED_VER=$(python3.12 -c "from pathlib import PurePosixPath; print(PurePosixPath('${WHEEL}').name.split('-')[1])")
PKG_NAME=$(python3.12 -c "from pathlib import PurePosixPath; print(PurePosixPath('${WHEEL}').name.split('-')[0].lower().replace('_', '-'))")
INSTALLED_VER=$(/tmp/test-venv-combined/bin/python -c "
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Expected vs installed version comparison inherits the same split('-')[1] fragility and may mis-detect mismatches.

EXPECTED_VER is derived with PurePosixPath(...).name.split('-')[1], which assumes a name-version-... pattern with no dashes in name. For projects whose names contain dashes, this will compute the wrong expected version and incorrectly report a mismatch, triggering unnecessary fallbacks.

Consider introducing a small helper that parses wheel filenames according to the wheel spec (extracting normalized project name and version), and reuse it both here and in the tier-building logic to avoid this class of bugs.

@jvulgan
Copy link
Copy Markdown
Contributor

jvulgan commented Jun 2, 2026

/lgtm

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants