Skip to content

fix: intra-family version floors — autolens[optional] import fails #687

Description

@Jammy2211

Overview

pyauto-heart verify_install Check D (pip install "autolens[optional]") is FAILING, and is one of the two legs holding release readiness RED (sidecar 2026-08-03T06:01:09Z, PyAutoHeart run 30788224561, job 91606144514). The install succeeds but import autolens raises AttributeError: module 'autofit' has no attribute 'Latent' — pip resolved autofit 2026.4.30.582, an April release, alongside a 2026.8.2.1 autoarray/autogalaxy/autonerves.

The cause is that every intra-family dependency across the five libraries is a bare package name with no version floor. When pip backtracks through the [optional] -> [jax] -> autofit[jax] -> autonerves[jax] extras chain it may walk the release history back to 2022, and it treats "version X does not provide the extra 'jax'" as a warning rather than an error — so an ancient autofit with no jax extra is a legal solution, and pip settles there. This is a real user-facing defect, not a CI artefact.

Plan

  • Add >=2026.7.29.2 floors to the cross-package intra-family dependencies in PyAutoArray, PyAutoFit, PyAutoGalaxy, PyAutoLens and PyAutoCTI — in both the base dependencies and the [jax] extras.
  • Leave self-referential extras (autolens[jax] inside autolens[optional], and siblings) unfloored: a self-reference is already version-locked, and a floor there would make a local 1.0.dev0 wheel build unsatisfiable.
  • Make verify_install Check D name the interpreter it used in its sidecar detail, so a CI-vs-local Python divergence can never hide a resolution bug again.
  • Verify on both python3.12 and python3.13 before shipping — the bug is invisible on 3.12.
Detailed implementation plan

Affected Repositories

  • PyAutoLens (primary)
  • PyAutoArray
  • PyAutoFit
  • PyAutoGalaxy
  • PyAutoCTI
  • PyAutoHeart (Check D evidence detail)
  • PyAutoNerves — inspected, no change needed (only self-references)

Branch Survey

Repository Current Branch Dirty?
./PyAutoNerves main clean
./PyAutoArray main clean
./PyAutoFit main clean
./PyAutoGalaxy main clean
./PyAutoLens main clean
./PyAutoCTI main clean
./PyAutoHeart main clean

worktree_check_conflict reports formal claims on PyAutoFit (point-source-defaults-campaign, nautilus-1core-serial-pool, simulator-util-to-af-ex), PyAutoLens (point-source-defaults-campaign) and PyAutoHeart (interferometer-start-here-integrate-oom). Each claiming branch was diffed against origin/main: none touches pyproject.toml, and the PyAutoHeart branch has an empty diff (already merged). No genuine file-level overlap; proceeding rather than parking, since this is a release-RED leg.

Suggested branch: feature/intra-family-dep-floors

Implementation Steps

  1. PyAutoArray/pyproject.tomldependencies: "autonerves" -> "autonerves>=2026.7.29.2"; [project.optional-dependencies] jax: "autonerves[jax]" -> "autonerves[jax]>=2026.7.29.2". Leave the autoarray[jax] self-reference in optional unchanged.
  2. PyAutoFit/pyproject.toml — same two edits (autonerves, autonerves[jax]). Leave the autofit[jax] self-reference unchanged.
  3. PyAutoGalaxy/pyproject.tomldependencies: "autofit", "autoarray" -> >=2026.7.29.2; jax extra: "autofit[jax]" -> "autofit[jax]>=2026.7.29.2". Leave the autogalaxy[jax] self-reference unchanged.
  4. PyAutoLens/pyproject.tomldependencies: "autogalaxy" -> "autogalaxy>=2026.7.29.2"; jax extra: "autogalaxy[jax]" -> "autogalaxy[jax]>=2026.7.29.2". Leave the autolens[jax] self-reference unchanged.
  5. PyAutoCTI/pyproject.tomldependencies: "autofit", "autoarray" -> >=2026.7.29.2.
  6. PyAutoHeart/heart/checks/verify_install.sh — in check_d, capture the venv interpreter version and include it in both the PASS and FAIL RESULTS+=(...) detail strings, matching how Check B names its interpreter.

Why 2026.7.29.2 is the right floor

It is live on PyPI, is not yanked, and is the oldest release that still carries af.Latent. This is a floor, not an exact pin — consistent with the floors-not-pins release design (PyAutoBuild#118/#120). A floor must name an installable version.

Testing

  • Control test, already run on both interpreters before this issue was filed:
    • without floors, python3.13, TestPyPI+PyPI -> autofit 2026.4.30.582, import autolens raises
    • with floors, same command/interpreter -> autoarray/autofit/autogalaxy/autonerves 2026.8.2.1, import OK
  • After the edits: rebuild the five wheels, re-run pip install "autolens[optional]" on python3.12 and python3.13, confirm newest-family resolution and a clean import in both.
  • pyauto-heart verify_install D.

Known trade-off

The verify_install skill doc's B --version 1.0.dev0 --find-links dist/ example will no longer resolve intra-family wheels out of dist/, since 1.0.dev0 < 2026.7.29.2. Release CI is unaffected: it builds dated dev versions (e.g. 2026.8.3.1.dev69801) that clear the floor.

Timing note

The floors only take effect once new wheels are published. The RED verify_install leg does not clear until a release rehearsal republishes to TestPyPI and Check D re-runs against those wheels.

Key Files

  • PyAutoArray/pyproject.toml, PyAutoFit/pyproject.toml, PyAutoGalaxy/pyproject.toml, PyAutoLens/pyproject.toml, PyAutoCTI/pyproject.toml — intra-family dependency floors
  • PyAutoHeart/heart/checks/verify_install.shcheck_d interpreter in the evidence detail

Original Prompt

Click to expand starting prompt

autolens[optional] resolves an ancient autofit — intra-family deps have no version floors

Type: bug
Target: health_fixes
Repos:

  • @PyAutoNerves
  • @PyAutoArray
  • @PyAutoFit
  • @PyAutoGalaxy
  • @PyAutoLens
  • @PyAutoCTI
    Difficulty: low
    Autonomy: supervised
    Priority: high
    Status: draft

Finding (2026-08-03, PyAutoHeart readiness RED)

pyauto-heart verify_install Check D (pip install "autolens[optional]") FAILED
in the Release Integrate run (PyAutoHeart run 30788224561, job 91606144514),
sidecar ~/.pyauto-heart/verify_install.json 2026-08-03T06:01:09Z,
detail pip rc=0 import rc=1. It is one of the two legs holding the release RED.

The install succeeds; the import does not:

[05:58:53] -> import autolens
Traceback (most recent call last):
    import autolens; print(autolens.__version__)
AttributeError: module 'autofit' has no attribute 'Latent'

Check D resolved autofit 2026.4.30.582 (an April release, pulling
autoconf 2026.7.15.1 with it) while autoarray / autogalaxy / autonerves came
in at 2026.8.2.1.

Root cause

autolens[optional] expands to
autolens[jax] -> autogalaxy[jax] -> autofit[jax] -> autonerves[jax].

Every intra-family dependency in the five pyproject.toml files is a bare
package name with no version floor
("autofit", "autoarray",
"autogalaxy", "autonerves"). When pip backtracks anywhere in that extras
chain it may walk the entire release history back to 2022 — and pip treats
"version X does not provide the extra 'jax'" as a warning, not an error,
so an ancient autofit carrying no jax extra is a legal solution. pip settles
there after ~22,600 lines of backtracking.

The metadata itself did not regress: requires_dist for autonerves / autofit /
autogalaxy is identical between 2026.7.29.2 (PyPI) and 2026.8.2.1
(TestPyPI). The whole 2026.8.2.1 family is TestPyPI-only; PyPI's newest is
still 2026.7.29.2.

Why it passed locally and failed in CI

Check D builds its venv with the default python3. The verify_install_release
job calls setup-python for 3.11, then 3.12, then 3.13 — the last wins, so CI's
python3 is 3.13. Locally it is 3.12. Reproduced on both, same command,
same index args:

interpreter resolved autofit import autolens
3.12 2026.7.29.2 passes (still has Latent)
3.13 2026.4.30.582 AttributeError

Both are backtracked; 3.12 merely stops at a version that still has Latent.
This is a real user-facing defect, not a CI artefact — pip install autolens[optional] from live PyPI today also silently walks the family back.

Control test — floors fix it

Same command, same python3.13, floors added:

pip install "autolens[optional]==2026.8.3.1.dev69801" \
    autofit>=2026.7.29.2 autogalaxy>=2026.7.29.2 \
    autoarray>=2026.7.29.2 autonerves>=2026.7.29.2

-> autoarray 2026.8.2.1  autofit 2026.8.2.1
   autogalaxy 2026.8.2.1  autonerves 2026.8.2.1
-> import autolens: OK

Without the floors the identical command lands on autofit 2026.4.30.582 and
raises.

Task

  1. Add >=2026.7.29.2 floors to every intra-family dependency — base
    dependencies and the [jax] / [optional] extras — in
    PyAutoNerves, PyAutoArray, PyAutoFit, PyAutoGalaxy, PyAutoLens, and
    PyAutoCTI (autofit, autoarray are bare there too).
    This is a floor, not an exact pin — consistent with the floors-not-pins
    release design (PyAutoBuild#118/Feature/phase #120). A floor must name an installable
    version, so 2026.7.29.2 (live on PyPI, not yanked) is the right value.
  2. Make Check D state which interpreter it used in its sidecar detail
    (PyAutoHeart/heart/checks/verify_install.sh, check_d). "Default
    python3" silently differing between CI (3.13) and local (3.12) is what hid
    this; the evidence should name the interpreter the way Check B's details do.

Acceptance

  • pip install "autolens[optional]" on python3.12 and python3.13 resolves
    the whole PyAuto family at the newest available release, and import autolens
    succeeds.
  • Check D's sidecar detail names the interpreter version.
  • Note: the floors only take effect once new wheels are published. The RED
    verify_install leg does not clear until a release rehearsal republishes to
    TestPyPI and Check D re-runs against those wheels.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions