Skip to content

fix: move 1D simulator helpers into af.ex.util (#1444) - #1445

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/simulator-util-to-af-ex
Aug 3, 2026
Merged

fix: move 1D simulator helpers into af.ex.util (#1444)#1445
Jammy2211 merged 1 commit into
mainfrom
feature/simulator-util-to-af-ex

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Closes #1444.

The bug

Four workspace-smoke notebooks failed with ModuleNotFoundError: No module named 'util' (PyAutoHeart workspace-smoke run 30790463134) — simulators.ipynb and simulators_sample.ipynb under notebooks/simulators/ in both autofit_workspace and HowToFit.

This is not a cwd bug and not a regression of the notebook kernel-cwd fix. import util fails under both the old kernel cwd (notebooks/simulators/) and the new pinned one (workspace root); I reproduced it from each. The real asymmetry is script dir vs cwd:

  • python scripts/simulators/simulators.py puts scripts/simulators/ on sys.path[0], which resolves scripts/simulators/util.py — this is why the .py siblings pass.
  • A notebook kernel has no script directory. sys.path[0] is the cwd, and util.py exists only under scripts/, so no cwd in the tree resolves it.

notebooks/simulators/util.py used to exist as a hand-maintained duplicate (git show 73aab12:notebooks/simulators/util.py) but cannot survive: PyAutoHands/autohands/generate.py:131 rmtree's notebooks/ on every build and copies only .ipynb/.rst/.md. Restoring it would not help anyway with the kernel cwd pinned to the workspace root.

The fix

Move the four simulate helpers into the existing af.ex.util, which already hosts plot_profile_1d. That removes the local-module import entirely, so the same call works from a script, a notebook and Colab alike, and collapses two byte-identical 346-line copies (autofit_workspace and HowToFit differed only in four docstring path strings) into one.

Purely additive to the public API — nothing removed or renamed.

Two constraints a naive copy would get wrong, both verified:

  • matplotlib stays an in-function import. It is not in requirements.txt, and the existing plot_profile_1d already defers it. The workspace copies imported it at module scope; hoisting that would make matplotlib a hard import of autofit.
  • to_dict comes from autonerves.dictable, not autofit. autofit/__init__.py:125 does from . import example as ex, but to_dict is not bound until line 172 — a module-scope from autofit import to_dict would hit a partially initialised module. af.util.numpy_array_to_json is fine via import autofit as af, since attribute lookup happens at call time (the example/analysis.py precedent).

The shared output/figure/model-json code is factored into small private helpers. The model filename (model.json vs model_{i}.json) is passed explicitly by the caller rather than inferred from list length, so a one-profile list keeps the indexed filenames its dataset folder is read with — there is a regression test for exactly that.

Verification

  • Parity: ran all four helpers from the old workspace util.py and from the new af.ex.util under an identical numpy seed — identical file sets and byte-identical json content in every case.
  • test_autofit/tools/test_example_util.py added (5 tests) — example/util.py previously had zero coverage.
  • Full suite: 1647 passed, 2 skipped.
  • Downstream, on the matching workspace branches: all four notebooks execute clean, all four .py siblings pass, smoke 10/10 in both repos, navigator check OK.

Downstream

Workspace PRs are open and marked pending release — they need these helpers to ship first:

  • autofit_workspace — deletes scripts/simulators/util.py, calls af.ex.util.*
  • HowToFit — same, plus a second masked failure in the same notebook (a chain-run path derived from the script's own file path, which a notebook kernel does not define)

🤖 Generated with Claude Code

The four simulate_* helpers lived in scripts/simulators/util.py in both
autofit_workspace and HowToFit as byte-identical copies. Running
`python scripts/simulators/simulators.py` puts scripts/simulators/ on
sys.path[0] so `import util` resolves, but a notebook kernel has no script
directory - sys.path[0] is the cwd - so the generated simulators.ipynb and
simulators_sample.ipynb could never import it, and failed workspace smoke
with `ModuleNotFoundError: No module named 'util'`.

Homing them in the library removes the local-module import entirely, so the
same call works from a script, a notebook and Colab alike.

matplotlib stays an in-function import (it is not a PyAutoFit requirement,
matching the existing plot_profile_1d), and to_dict is imported from
autonerves.dictable rather than autofit - autofit/__init__.py imports
example at line 125 but only binds to_dict at line 172.

Verified byte-identical json output against the old workspace util.py under
a fixed seed for all four helpers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

fix: simulator notebooks cannot import util — move helpers into af.ex.util

1 participant