Skip to content

Commit b9d11a7

Browse files
Jammy2211claude
authored andcommitted
fix: skip _compute_latent_samples in PYAUTO_TEST_MODE
Short-circuit SearchUpdater._compute_latent_samples to return None when autoconf.test_mode.skip_latents() is True. Test-mode runs already bypass the sampler but the post-fit latent pass still draws 100 PDF samples and dispatches analysis.compute_latent_samples per sample — under PyAutoGalaxy's AnalysisDataset.LATENT_BATCH_MODE = "jit" override that is a Python loop of 100 JIT dispatches per stage, ~750s per SLaM fit on CPU. End-to-end SLaM smoke now completes in 29.6s instead of timing out at 5min. PYAUTO_SKIP_LATENTS=1 also bypasses the path in real-mode fits where the user explicitly wants to skip latent post-processing. Real-mode behaviour with no env vars set is unchanged. Requires rhayes777/PyAutoConf PR (skip_latents helper) merged first. Fixes #1294. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 55f5e30 commit b9d11a7

2 files changed

Lines changed: 85 additions & 0 deletions

File tree

autofit/non_linear/search/updater.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import psutil
99

1010
from autoconf import conf
11+
from autoconf.test_mode import skip_latents
1112

1213
from autofit import exc
1314
from autofit.non_linear.paths.database import DatabasePaths
@@ -232,6 +233,8 @@ def _compute_latent_samples(
232233
during_analysis: bool,
233234
) -> Optional[Samples]:
234235
"""Compute and persist latent variable samples if configured."""
236+
if skip_latents():
237+
return None
235238
if not (
236239
(during_analysis and conf.instance["output"]["latent_during_fit"])
237240
or (not during_analysis and conf.instance["output"]["latent_after_fit"])
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import logging
2+
from unittest.mock import MagicMock
3+
4+
from autoconf import conf
5+
6+
from autofit.non_linear.search.updater import SearchUpdater
7+
8+
9+
def _make_updater() -> SearchUpdater:
10+
return SearchUpdater(
11+
paths=MagicMock(),
12+
timer=MagicMock(),
13+
search_logger=logging.getLogger("test_updater"),
14+
plot_results_func=MagicMock(),
15+
samples_from_func=MagicMock(),
16+
disable_output=False,
17+
iterations_per_full_update=1.0,
18+
)
19+
20+
21+
def test__compute_latent_samples__skipped_in_test_mode(monkeypatch):
22+
monkeypatch.setenv("PYAUTO_TEST_MODE", "1")
23+
monkeypatch.delenv("PYAUTO_SKIP_LATENTS", raising=False)
24+
25+
analysis = MagicMock()
26+
result = _make_updater()._compute_latent_samples(
27+
samples=MagicMock(),
28+
samples_save=MagicMock(),
29+
analysis=analysis,
30+
fitness=MagicMock(),
31+
during_analysis=False,
32+
)
33+
34+
assert result is None
35+
analysis.compute_latent_samples.assert_not_called()
36+
37+
38+
def test__compute_latent_samples__skipped_by_explicit_env_var(monkeypatch):
39+
monkeypatch.delenv("PYAUTO_TEST_MODE", raising=False)
40+
monkeypatch.setenv("PYAUTO_SKIP_LATENTS", "1")
41+
42+
analysis = MagicMock()
43+
result = _make_updater()._compute_latent_samples(
44+
samples=MagicMock(),
45+
samples_save=MagicMock(),
46+
analysis=analysis,
47+
fitness=MagicMock(),
48+
during_analysis=False,
49+
)
50+
51+
assert result is None
52+
analysis.compute_latent_samples.assert_not_called()
53+
54+
55+
def test__compute_latent_samples__config_gate_still_works(monkeypatch):
56+
"""
57+
With neither env var set, the existing ``latent_after_fit`` /
58+
``latent_during_fit`` config gate must still short-circuit
59+
when both are disabled. Regression for the new skip_latents()
60+
check not bypassing the original logic.
61+
"""
62+
monkeypatch.delenv("PYAUTO_TEST_MODE", raising=False)
63+
monkeypatch.delenv("PYAUTO_SKIP_LATENTS", raising=False)
64+
65+
original_after = conf.instance["output"]["latent_after_fit"]
66+
original_during = conf.instance["output"]["latent_during_fit"]
67+
conf.instance["output"]["latent_after_fit"] = False
68+
conf.instance["output"]["latent_during_fit"] = False
69+
try:
70+
analysis = MagicMock()
71+
result = _make_updater()._compute_latent_samples(
72+
samples=MagicMock(),
73+
samples_save=MagicMock(),
74+
analysis=analysis,
75+
fitness=MagicMock(),
76+
during_analysis=False,
77+
)
78+
assert result is None
79+
analysis.compute_latent_samples.assert_not_called()
80+
finally:
81+
conf.instance["output"]["latent_after_fit"] = original_after
82+
conf.instance["output"]["latent_during_fit"] = original_during

0 commit comments

Comments
 (0)