Skip to content

Commit 457fe23

Browse files
committed
Silence the three autonerves-rooted CLI-noise sources
Fixes the three root causes identified by the 2026-08-06 /cli_noise_clean audit (PyAutoMind draft/maintenance/pyautonerves/cli_noise_autonerves_batch.md): 1. fits leak — fitsable.ndarray_via_fits_from and header_obj_from called fits.open without closing, emitting 'ResourceWarning: unclosed file' in every downstream repo that loads FITS. Both now use 'with fits.open(...)'. 2. pytest collection — test_test_mode.py imported the real API functions test_mode_level/test_mode_samples by bare name, so pytest collected them as tests (PytestReturnNotNoneWarning, an ERROR in future pytest). The unused test_mode_level import is dropped and test_mode_samples is aliased to _test_mode_samples. 3. check_version false positive — with workspace_root defaulting to cwd, every library import from inside a library's own source repo warned 'Cannot verify the workspace ... is compatible'. check_version now skips silently when the root is a package source checkout (setup.py or pyproject.toml at its top level) and no version floor is recorded; a recorded floor is still enforced, and a genuine workspace missing its version keys still warns. Regression tests added for all three. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015NrwGppUCg8r4Foed6bgSf
1 parent e9f7c11 commit 457fe23

5 files changed

Lines changed: 72 additions & 10 deletions

File tree

autonerves/fitsable.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,10 @@ def ndarray_via_fits_from(
207207
--------
208208
array_2d = ndarray_via_fits_from(file_path='/path/to/file/filename.fits', hdu=0)
209209
"""
210-
hdu_list = fits.open(file_path, do_not_scale_image_data=do_not_scale_image_data)
211-
return ndarray_via_hdu_from(hdu_list[hdu])
210+
with fits.open(
211+
file_path, do_not_scale_image_data=do_not_scale_image_data
212+
) as hdu_list:
213+
return ndarray_via_hdu_from(hdu_list[hdu])
212214

213215

214216
def header_obj_from(file_path: Union[Path, str], hdu: int) -> Dict:
@@ -233,8 +235,8 @@ def header_obj_from(file_path: Union[Path, str], hdu: int) -> Dict:
233235
--------
234236
array_2d = ndarray_via_fits_from(file_path='/path/to/file/filename.fits', hdu=0)
235237
"""
236-
hdu_list = fits.open(file_path)
237-
return hdu_list[hdu].header
238+
with fits.open(file_path) as hdu_list:
239+
return hdu_list[hdu].header
238240

239241

240242

autonerves/workspace.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ def _version_date(parsed_version):
8282
return None
8383

8484

85+
def _is_source_checkout(root):
86+
"""
87+
True when ``root`` is a Python package source checkout (a ``setup.py`` or
88+
``pyproject.toml`` at its top level) rather than a workspace clone.
89+
90+
``check_version`` is called unconditionally on library import with
91+
``workspace_root`` defaulting to the current working directory, so any
92+
pytest run or script executed from inside a library's own repo would
93+
otherwise warn "Cannot verify the workspace ..." on every import — a
94+
false positive, since a source checkout is not a workspace and records
95+
no version floor to verify. Workspace clones ship neither file, so a
96+
genuine workspace missing its version keys still warns.
97+
"""
98+
return (root / "setup.py").exists() or (root / "pyproject.toml").exists()
99+
100+
85101
def _library_name_from_workspace(workspace_root):
86102
name = workspace_root.name
87103
suffix = "_workspace"
@@ -168,7 +184,10 @@ def check_version(library_version, workspace_root=None):
168184
installs) warn on inequality rather than raising.
169185
170186
If no floor source is found, a warning is emitted and the check is
171-
skipped.
187+
skipped — unless ``workspace_root`` is a package source checkout
188+
(``setup.py``/``pyproject.toml`` at its top level), in which case the
189+
check is skipped silently: running from inside a library's own repo is
190+
not a workspace-compatibility question at all.
172191
173192
The check can be disabled in two ways:
174193
@@ -203,6 +222,8 @@ def check_version(library_version, workspace_root=None):
203222
floor_version = version_file.read_text().strip()
204223

205224
if floor_version is None or floor_version == "":
225+
if _is_source_checkout(root):
226+
return
206227
warnings.warn(_missing_version_warning(root, library_version))
207228
return
208229

test_autonerves/test_fitsable.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,22 @@ def test__output_to_fits__header_dict():
7070
assert header["A"] == 1
7171

7272

73+
def test__fits_readers_close_their_file_handles():
74+
"""Regression: `fits.open` without close leaked file handles, emitting
75+
`ResourceWarning: unclosed file` throughout every downstream repo that
76+
loads FITS via these helpers."""
77+
import gc
78+
import warnings
79+
80+
with warnings.catch_warnings():
81+
warnings.simplefilter("error", ResourceWarning)
82+
fitsable.ndarray_via_fits_from(
83+
file_path=test_data_path / "3x3_ones.fits", hdu=0
84+
)
85+
fitsable.header_obj_from(file_path=test_data_path / "3x3_ones.fits", hdu=0)
86+
gc.collect()
87+
88+
7389
def test__header_obj_from():
7490
header_obj = fitsable.header_obj_from(
7591
file_path=test_data_path / "3x3_ones.fits", hdu=0

test_autonerves/test_test_mode.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010

1111
from autonerves.test_mode import (
1212
is_test_mode,
13-
test_mode_level,
14-
test_mode_samples,
1513
with_test_mode_segment,
1614
)
1715

16+
# ``test_mode_samples`` is real API, but its ``test_`` prefix means a bare-name
17+
# import here would be collected by pytest as a test function
18+
# (PytestReturnNotNoneWarning, an ERROR in future pytest) — alias it instead.
19+
from autonerves.test_mode import test_mode_samples as _test_mode_samples
20+
1821

1922
@pytest.fixture(autouse=True)
2023
def _restore_test_mode_env():
@@ -69,13 +72,13 @@ def _restore_samples_env(self):
6972

7073
def test__env_unset_returns_historical_default_of_four(self):
7174
os.environ.pop("PYAUTO_TEST_MODE_SAMPLES", None)
72-
assert test_mode_samples() == 4
75+
assert _test_mode_samples() == 4
7376

7477
def test__env_set_returns_value(self):
7578
os.environ["PYAUTO_TEST_MODE_SAMPLES"] = "50000"
76-
assert test_mode_samples() == 50000
79+
assert _test_mode_samples() == 50000
7780

7881
def test__values_below_four_raise(self):
7982
os.environ["PYAUTO_TEST_MODE_SAMPLES"] = "3"
8083
with pytest.raises(ValueError):
81-
test_mode_samples()
84+
_test_mode_samples()

test_autonerves/test_workspace.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@ def test_missing_sources_warns(tmp_path):
3333
check_version("2026.7.22.1", workspace_root=tmp_path)
3434

3535

36+
@pytest.mark.parametrize("marker", ["setup.py", "pyproject.toml"])
37+
def test_missing_sources_in_source_checkout_skips_silently(tmp_path, marker):
38+
"""A package source checkout (setup.py/pyproject.toml at the root) is not
39+
a workspace — importing a library from inside its own repo must not warn
40+
that the "workspace" version cannot be verified."""
41+
(tmp_path / marker).write_text("")
42+
with warnings.catch_warnings():
43+
warnings.simplefilter("error")
44+
check_version("2026.7.22.1", workspace_root=tmp_path)
45+
46+
47+
def test_source_checkout_with_version_floor_still_checked(tmp_path):
48+
"""The source-checkout skip only covers the no-floor false positive — a
49+
recorded floor is still enforced even with a setup.py present."""
50+
(tmp_path / "setup.py").write_text("")
51+
(tmp_path / "version.txt").write_text("2026.7.22.1\n")
52+
with pytest.raises(WorkspaceVersionMismatchError):
53+
check_version("2025.1.1.1", workspace_root=tmp_path)
54+
55+
3656
def test_env_override_skips_mismatch(tmp_path, monkeypatch):
3757
monkeypatch.setenv("PYAUTO_SKIP_WORKSPACE_VERSION_CHECK", "1")
3858
(tmp_path / "version.txt").write_text("2025.1.1.1\n")

0 commit comments

Comments
 (0)