Repository navigation
Description
Overview
Import time is now the single largest cost in smoke tests — 2.6s (49%) of a 5.3s modeling script. matplotlib and scipy are the main culprits, loaded eagerly via plot submodules and utility modules across the stack. Deferring these to first-use could cut import time by 40-60%, bringing modeling scripts under 4s and simulator scripts under 2.5s.
Plan
- Defer matplotlib imports by lazy-loading
plotsubmodules in autoarray, autogalaxy, autolens, and autofit - Defer scipy imports in autoarray's convolver, delaunay interpolator, and utility modules
- Defer scipy imports in autofit's interpolator and BFGS search modules
- Profile before/after to validate improvement
Detailed implementation plan
Affected Repositories
- PyAutoLens (primary — issue tracker)
- PyAutoArray
- PyAutoGalaxy
- PyAutoFit
Work Classification
Library
Branch Survey
| Repository | Current Branch | Dirty? |
|---|---|---|
| PyAutoFit | main_build | clean |
| PyAutoArray | main | 4 untracked |
| PyAutoGalaxy | main | 2 untracked |
| PyAutoLens | main | clean |
Suggested branch: feature/lazy-imports
Implementation Steps
-
PyAutoArray — Defer plot submodule
- In
autoarray/__init__.py, convertfrom . import plotto a lazy import pattern - Move matplotlib backend setup in
autoarray/plot/__init__.pyfrom module-level to first-use
- In
-
PyAutoArray — Defer scipy imports
autoarray/operators/convolver.py: Moveimport scipyto inside methods that use itautoarray/inversion/mesh/interpolator/delaunay.py: Movescipy.spatialimports to inside class methodsautoarray/mask/mask_2d_util.py: Movescipy.ndimageimport to inside functionsautoarray/util/cholesky_funcs.py: Movescipy.linalgto inside functionsautoarray/util/fnnls.py: Movescipy.linalgto inside functions
-
PyAutoFit — Defer scipy and matplotlib
- Lazy-load the
interpolatorsubmodule (uses scipy) - Defer scipy.optimize in BFGS/LBFGS search modules
- Lazy-load
non_linear.plotsubmodule
- Lazy-load the
-
PyAutoGalaxy — Defer plot submodule
- In
autogalaxy/__init__.py, convertfrom . import plotto lazy import
- In
-
PyAutoLens — Defer plot submodule
- In
autolens/__init__.py, convertfrom . import plotto lazy import
- In
-
Validation
- Profile
python -X importtime -c "import autolens"before and after - Run existing test suites to confirm no regressions
- Run smoke tests to measure end-to-end improvement
- Profile
Key Files
autoarray/__init__.py— remove eager plot importautoarray/plot/__init__.py— defer backend setupautoarray/operators/convolver.py— defer scipyautoarray/inversion/mesh/interpolator/delaunay.py— defer scipy.spatialautofit/__init__.py— remove eager plot/interpolator importsautogalaxy/__init__.py— remove eager plot importautolens/__init__.py— remove eager plot import
Original Prompt
Click to expand starting prompt
Optimize Python Import Times
Motivation
Smoke test profiling (issue PyAutoLabs/PyAutoFit#1183) has reduced per-script runtime from ~100s to 3.6-5.3s. The remaining breakdown for imaging/modeling.py (5.3s total):
| Component | Time | % |
|---|---|---|
| Python imports | 2.6s | 49% |
| Simple model composition | 0.6s | 11% |
| search.fit (1 likelihood) | 0.6s | 11% |
| Subplot rendering (matplotlib) | 1.0s | 19% |
| Everything else | 0.5s | 10% |
Import time is now the single largest cost — nearly half the total. For imaging/simulator.py (3.6s total), imports are 2.3s (64%).
The import breakdown (from earlier profiling):
| Package | Time |
|---|---|
| autofit | 0.8s |
| autoarray | 0.3s |
| autogalaxy | 1.0s |
| autolens | 0.02s |
| autoconf.jax_wrapper | 0.08s |
autogalaxy (1.0s) and autofit (0.8s) dominate. These likely pull in heavy dependencies at module level (scipy, numba, astropy, matplotlib).
Approach
Investigate lazy imports for heavy dependencies that aren't needed at module load time. Candidates:
scipy— only needed for specific operations (convolution, interpolation)numba— only needed when JIT functions are first calledastropy— only needed for FITS I/O and cosmologymatplotlib— only needed when plotting functions are called
The goal is to defer these imports until first use, reducing the ~2.6s import floor. Even a 50% reduction would bring modeling scripts under 4s and simulator scripts under 2.5s.
Context
All other smoke test optimizations have been implemented:
PYAUTO_WORKSPACE_SMALL_DATASETS=1— 15x15 grids, over_sample_size=2, 2 MGE gaussiansPYAUTO_FAST_PLOTS=1— skip tight_layout + savefigPYAUTO_DISABLE_CRITICAL_CAUSTICS=1— skip curve overlaysPYAUTO_DISABLE_JAX=1— skip JAX JIT compilationPYAUTOFIT_TEST_MODE=2— skip VRAM, model.info, result.info, pre/post-fit I/O- Cosmology distance caching, FitImaging cached_property
Import optimization is the last remaining lever for further speedup.
Activity
Jammy2211 commentedon Apr 7, 2026
Smoke Test Results — 2026-04-07
All 9 failures are pre-existing
apply_maskshape mismatches (stale full-size datasets vsPYAUTO_WORKSPACE_SMALL_DATASETS=115x15 masks). Not related to the lazy import changes.PRs
Unit Tests
Jammy2211 commentedon Apr 7, 2026
Smoke Test Results — 2026-04-07
All 9 failures are pre-existing
apply_maskshape mismatches (stale full-size datasets vsPYAUTO_WORKSPACE_SMALL_DATASETS=115x15 masks). Identical to previous run — no new failures from lazy imports.PRs
Import Time
matplotlib.pyplotfully deferred — not loaded until first plot accessscipy.statsfully deferred — not loaded until first useUnit Tests
Jammy2211 commentedon Apr 7, 2026
Shipped — 2026-04-07
PRs
Summary
Deferred scipy and matplotlib imports across the PyAuto stack to reduce
import autolenstime from ~2.7s to ~1.9s (30% reduction). scipy is deferred via local imports in convolver, delaunay, mask utilities, cholesky, fnnls, and PriorVectorized. matplotlib is deferred by replacing all module-levelimport matplotlib.pyplot as pltwithsubplots()/get_cmap()wrappers inautoarray.plot.utils, movingplot_utils.pytoautogalaxy.utilto break circular imports, and lazy-loading the plot submodule in autogalaxy/autolens__init__.Session Notes
autogalaxy.plot.__init__and several plot submodules that imported fromautogalaxy.plot.plot_utils. Fixed by movingplot_utils.pytoautogalaxy/util/plot_utils.py.import matplotlib.pyplot as pltin plotter files were replaced with thesubplots()wrapper.gui/scribbler.pyandgui/clicker.pykeep matplotlib imports but moved them inside methods since these are interactive GUI tools never loaded during normal import.