From 0c283e48e0d2b5f6e3a270ab267c4f86251cfc3d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 22 Aug 2026 20:35:21 +0000 Subject: [PATCH] fix: stop writing the literal comment ['] on every header_dict FITS card hdu_list_for_output_from passed a LIST, [""], as the FITS card comment. astropy does not reject it -- it str()s it -- so every card written from a header_dict landed on disk reading: PIXSCAY = 0.1 / [''] Every Imaging dataset the stack writes carries this on four cards (PIXSCAY, PIXSCAX, ORIGINY, ORIGINX), and it renders for anyone opening a PyAuto FITS in DS9, astropy or any external tool. Cosmetic, but it is output we hand to other people and it reads as a serialization bug. The intent was an empty comment; "" gives that, while the list gave the rendered repr of a list. Verified on disk: the card becomes a plain `PIXSCAY = 0.1` with no comment and no trailing slash, byte-size unchanged. Deliberately NOT adding real per-key comments, which the prompt raised as an option. autonerves receives an opaque header_dict and does not know the key vocabulary -- PIXSCAY/ORIGINY are autoarray's Mask2DKeys. Hardcoding their meanings here would couple the base serialization layer to a downstream key set, which is the wrong direction. If descriptive comments are wanted, the caller should be able to supply them, and that is a separate API change. Nothing reads FITS comments anywhere in the stack -- every header consumer indexes values by key name, verified during PyAutoNerves#153 -- so this changes no behaviour. Pinned by a test so the wart cannot return. The tracked fixture test_autonerves/files/array_out.fits is a test write target whose bytes change with the comment; refreshed. Verified the rewrite is byte-stable across repeated runs and identical with PYAUTO_SMALL_DATASETS exported and unset, which the autouse conftest fixture from #154 guarantees. --- autonerves/fitsable.py | 4 ++-- test_autonerves/files/array_out.fits | Bin 5760 -> 5760 bytes test_autonerves/test_fitsable.py | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/autonerves/fitsable.py b/autonerves/fitsable.py index a1ae1f8..505ecf6 100644 --- a/autonerves/fitsable.py +++ b/autonerves/fitsable.py @@ -135,9 +135,9 @@ def hdu_list_for_output_from( # Convert enum to its string value if needed key_str = key.value if isinstance(key, Enum) else key try: - header.append((key_str, value, [""])) + header.append((key_str, value, "")) except ValueError: - header.append((key_str, float(value), [""])) + header.append((key_str, float(value), "")) stamp_small_datasets_regime(header) diff --git a/test_autonerves/files/array_out.fits b/test_autonerves/files/array_out.fits index 85cddd500dfc4f577dcb3ba7422da00b1caf6067..cf7215509a6fffb285f7562fcb9b6661a77aacd6 100644 GIT binary patch delta 16 XcmZqBZP4AYo^i4hli}tEj0;2nG>`@h delta 23 ecmZqBZP4AYo{>#oAzEEMcCsL&_T~qS3q$}`od+%e diff --git a/test_autonerves/test_fitsable.py b/test_autonerves/test_fitsable.py index 27f78f7..58409ff 100644 --- a/test_autonerves/test_fitsable.py +++ b/test_autonerves/test_fitsable.py @@ -222,3 +222,27 @@ def test__stamp_key_stays_within_the_fits_standard_card_limit(): # would quietly un-fix the interferometer case. Pin the ceiling. assert len(KEY) <= 8 assert KEY == KEY.upper() + + +def test__header_dict_cards_carry_no_junk_comment(tmp_path): + # Regression: the comment was passed as the LIST [""], which astropy does not + # reject -- it str()s it -- so every header_dict card on disk read + # `PIXSCAY = 0.1 / ['']`. Cosmetic, but it shipped in every Imaging dataset + # the stack wrote and rendered for anyone opening a PyAuto FITS in DS9 or + # astropy. Pin the comment empty so the wart cannot come back. + fitsable.output_to_fits( + np.ones((4, 4)), + file_path=tmp_path / "h.fits", + header_dict={"PIXSCAY": 0.1, "ORIGINY": 0.0}, + ) + + header = fits.open(tmp_path / "h.fits")[0].header + + assert header["PIXSCAY"] == 0.1 + assert header.comments["PIXSCAY"] == "" + assert header.comments["ORIGINY"] == "" + assert "[" not in str(header.cards["PIXSCAY"]) + + # The regime stamp keeps its real comment -- this is about junk, not about + # removing every comment. + assert fitsable.SMALL_DATASETS_HEADER_COMMENT in str(header.cards[KEY])