From a08297efb960dad9a70a95396202ded7f40ecb23 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Thu, 27 Aug 2026 19:02:58 -0400 Subject: [PATCH] fix: save_results survives SamplesException/FitException from the max-likelihood tracer (PyAutoFit#1535) --- autolens/analysis/analysis/dataset.py | 11 +++++- .../analysis/test_analysis_dataset.py | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/autolens/analysis/analysis/dataset.py b/autolens/analysis/analysis/dataset.py index 097e67d64..1b9be1ceb 100644 --- a/autolens/analysis/analysis/dataset.py +++ b/autolens/analysis/analysis/dataset.py @@ -189,5 +189,12 @@ def save_results(self, paths: af.DirectoryPaths, result: ResultDataset): obj=result.max_log_likelihood_tracer, file_path=paths._files_path / "tracer.json", ) - except AttributeError: - pass + except (AttributeError, af.exc.SamplesException, af.exc.FitException) as e: + # Building the tracer requires materializing the maximum log likelihood sample as a model + # instance, which the model may reject (e.g. `ell_comps` outside the unit disk). Writing an + # extra output file must never kill a completed fit before `paths.completed()` is called + # (PyAutoFit #1535), so the failure is logged and the fit finishes without `tracer.json`. + logger.warning( + f"The maximum log likelihood tracer could not be written to tracer.json, " + f"the model-fit is otherwise unaffected:\n{e}" + ) diff --git a/test_autolens/analysis/analysis/test_analysis_dataset.py b/test_autolens/analysis/analysis/test_analysis_dataset.py index b38cc1e80..3c0fb59e1 100644 --- a/test_autolens/analysis/analysis/test_analysis_dataset.py +++ b/test_autolens/analysis/analysis/test_analysis_dataset.py @@ -118,3 +118,41 @@ def test__save_attributes__dataset_fits_output_for_aggregator(analysis_imaging_7 assert ext_names[:4] == ["MASK", "DATA", "NOISE_MAP", "PSF"] os.remove(dataset_fits_path) + + +class _RaisingTracerResult: + """ + Result double whose tracer cannot be built, because materializing the maximum log + likelihood sample as a model instance fails. + """ + + def __init__(self, error): + self._error = error + + @property + def max_log_likelihood_tracer(self): + raise self._error + + +@pytest.mark.parametrize( + "error", + [ + AttributeError("no tracer on this result"), + af.exc.SamplesException("stored parameters cannot be reconstructed"), + af.exc.FitException("ell_comps must satisfy e0**2+e1**2 < 1"), + ], +) +def test__save_results__tracer_failure_never_kills_the_fit(analysis_imaging_7x7, error): + """ + `save_results` runs after the search has finished but before `paths.completed()`, so a + failure writing the (optional) `tracer.json` must be logged and swallowed rather than + losing the run its `.completed` marker (PyAutoFit #1535). + """ + paths = af.DirectoryPaths() + + analysis_imaging_7x7.save_results( + paths=paths, + result=_RaisingTracerResult(error), + ) + + assert not (paths._files_path / "tracer.json").exists()