fix: move 1D simulator helpers into af.ex.util (#1444) - #1445
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1444.
The bug
Four workspace-smoke notebooks failed with
ModuleNotFoundError: No module named 'util'(PyAutoHeart workspace-smoke run 30790463134) —simulators.ipynbandsimulators_sample.ipynbundernotebooks/simulators/in bothautofit_workspaceandHowToFit.This is not a cwd bug and not a regression of the notebook kernel-cwd fix.
import utilfails 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.pyputsscripts/simulators/onsys.path[0], which resolvesscripts/simulators/util.py— this is why the.pysiblings pass.sys.path[0]is the cwd, andutil.pyexists only underscripts/, so no cwd in the tree resolves it.notebooks/simulators/util.pyused to exist as a hand-maintained duplicate (git show 73aab12:notebooks/simulators/util.py) but cannot survive:PyAutoHands/autohands/generate.py:131rmtree'snotebooks/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 hostsplot_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_workspaceandHowToFitdiffered 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:
requirements.txt, and the existingplot_profile_1dalready defers it. The workspace copies imported it at module scope; hoisting that would make matplotlib a hard import ofautofit.to_dictcomes fromautonerves.dictable, notautofit.autofit/__init__.py:125doesfrom . import example as ex, butto_dictis not bound until line 172 — a module-scopefrom autofit import to_dictwould hit a partially initialised module.af.util.numpy_array_to_jsonis fine viaimport autofit as af, since attribute lookup happens at call time (theexample/analysis.pyprecedent).The shared output/figure/model-json code is factored into small private helpers. The model filename (
model.jsonvsmodel_{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
util.pyand from the newaf.ex.utilunder an identical numpy seed — identical file sets and byte-identical json content in every case.test_autofit/tools/test_example_util.pyadded (5 tests) —example/util.pypreviously had zero coverage..pysiblings 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— deletesscripts/simulators/util.py, callsaf.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