Skip to content

Commit 0b9e148

Browse files
test: Close file handles in contrib tests for Python 3.14
Fix tests/contrib/ failures on Python 3.14 caused by unclosed file handles: * tests/contrib/test_viz.py opened JSON files via json.load(path.open(...)) and tests/contrib/test_contrib_utils.py read archives via path.open("rb").read(), never closing the file objects. When garbage collection finalized them, CPython emitted 'ResourceWarning: unclosed file'. * pyproject.toml sets filterwarnings = ["error"], so the ResourceWarning raised during finalization became an unraisable exception that pytest re-raised as PytestUnraisableExceptionWarning, failing the test. * On Python <=3.13 these warnings were silently matched by the existing 'ignore: Exception ignored in:' filter, as the unraisable err_msg was None. Python 3.14's _io module now supplies an explicit message, 'Exception ignored while finalizing file <...>', through PyErr_FormatUnraisable (python/cpython#108082), so the filter no longer matched and the warnings escalated to failures. Replace the leaking calls with json.loads(path.read_text(...)) and path.read_bytes(), matching the existing conventions in tests/test_scripts.py. Assisted-by: ClaudeCode:claude-fable-5
1 parent 93b2a55 commit 0b9e148

2 files changed

Lines changed: 29 additions & 21 deletions

File tree

‎tests/contrib/test_contrib_utils.py‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ def test_download_archive_type(
7373
archive_url = "https://www.hepdata.net/record/resource/1408476?view=true"
7474
output_directory = tmp_path.joinpath("likelihoods")
7575
# Give BytesIO a tarfile
76-
requests_mock.get(archive_url, content=tarfile_path.open("rb").read())
76+
requests_mock.get(archive_url, content=tarfile_path.read_bytes())
7777
download(archive_url, output_directory)
7878

7979
# Give BytesIO an uncompressed tarfile
80-
requests_mock.get(archive_url, content=tarfile_uncompressed_path.open("rb").read())
80+
requests_mock.get(archive_url, content=tarfile_uncompressed_path.read_bytes())
8181
download(archive_url, output_directory)
8282

8383
# Give BytesIO a zipfile
84-
requests_mock.get(archive_url, content=zipfile_path.open("rb").read())
84+
requests_mock.get(archive_url, content=zipfile_path.read_bytes())
8585
# Run without and with existing output_directory to cover both
8686
# cases of the shutil.rmtree logic
8787
rmtree(output_directory)
@@ -97,9 +97,7 @@ def test_download_archive_type(
9797

9898
def test_download_archive_force(tmp_path, requests_mock, tarfile_path):
9999
archive_url = "https://www.cern.ch/record/resource/123456789"
100-
requests_mock.get(
101-
archive_url, content=tarfile_path.open("rb").read(), status_code=200
102-
)
100+
requests_mock.get(archive_url, content=tarfile_path.read_bytes(), status_code=200)
103101

104102
with pytest.raises(InvalidArchiveHost):
105103
download(archive_url, tmp_path.joinpath("likelihoods"), force=False)

‎tests/contrib/test_viz.py‎

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414

1515
def test_brazil_band_collection(datadir):
16-
data = json.load(datadir.joinpath("hypotest_results.json").open(encoding="utf-8"))
16+
data = json.loads(
17+
datadir.joinpath("hypotest_results.json").read_text(encoding="utf-8")
18+
)
1719

1820
fig = Figure()
1921
ax = fig.subplots()
@@ -31,8 +33,8 @@ def test_brazil_band_collection(datadir):
3133
assert brazil_band_collection.clb is None
3234
assert brazil_band_collection.axes == ax
3335

34-
data = json.load(
35-
datadir.joinpath("tail_probs_hypotest_results.json").open(encoding="utf-8")
36+
data = json.loads(
37+
datadir.joinpath("tail_probs_hypotest_results.json").read_text(encoding="utf-8")
3638
)
3739

3840
fig = Figure()
@@ -54,7 +56,9 @@ def test_brazil_band_collection(datadir):
5456

5557
@pytest.mark.mpl_image_compare(tolerance=25)
5658
def test_plot_results(datadir):
57-
data = json.load(datadir.joinpath("hypotest_results.json").open(encoding="utf-8"))
59+
data = json.loads(
60+
datadir.joinpath("hypotest_results.json").read_text(encoding="utf-8")
61+
)
5862

5963
fig = Figure()
6064
ax = fig.subplots()
@@ -68,7 +72,9 @@ def test_plot_results(datadir):
6872

6973
@pytest.mark.mpl_image_compare(tolerance=25)
7074
def test_plot_results_no_axis(datadir):
71-
data = json.load(datadir.joinpath("hypotest_results.json").open(encoding="utf-8"))
75+
data = json.loads(
76+
datadir.joinpath("hypotest_results.json").read_text(encoding="utf-8")
77+
)
7278

7379
mpl.use("agg") # Use non-gui backend
7480
fig, ax = plt.subplots()
@@ -80,8 +86,8 @@ def test_plot_results_no_axis(datadir):
8086

8187
@pytest.mark.mpl_image_compare(tolerance=25)
8288
def test_plot_results_components(datadir):
83-
data = json.load(
84-
datadir.joinpath("tail_probs_hypotest_results.json").open(encoding="utf-8")
89+
data = json.loads(
90+
datadir.joinpath("tail_probs_hypotest_results.json").read_text(encoding="utf-8")
8591
)
8692

8793
fig = Figure()
@@ -94,8 +100,8 @@ def test_plot_results_components(datadir):
94100

95101
@pytest.mark.mpl_image_compare(tolerance=25)
96102
def test_plot_results_components_no_clb(datadir):
97-
data = json.load(
98-
datadir.joinpath("tail_probs_hypotest_results.json").open(encoding="utf-8")
103+
data = json.loads(
104+
datadir.joinpath("tail_probs_hypotest_results.json").read_text(encoding="utf-8")
99105
)
100106

101107
fig = Figure()
@@ -116,8 +122,8 @@ def test_plot_results_components_no_clb(datadir):
116122

117123
@pytest.mark.mpl_image_compare(tolerance=25)
118124
def test_plot_results_components_no_clsb(datadir):
119-
data = json.load(
120-
datadir.joinpath("tail_probs_hypotest_results.json").open(encoding="utf-8")
125+
data = json.loads(
126+
datadir.joinpath("tail_probs_hypotest_results.json").read_text(encoding="utf-8")
121127
)
122128

123129
fig = Figure()
@@ -138,8 +144,8 @@ def test_plot_results_components_no_clsb(datadir):
138144

139145
@pytest.mark.mpl_image_compare(tolerance=25)
140146
def test_plot_results_components_no_cls(datadir):
141-
data = json.load(
142-
datadir.joinpath("tail_probs_hypotest_results.json").open(encoding="utf-8")
147+
data = json.loads(
148+
datadir.joinpath("tail_probs_hypotest_results.json").read_text(encoding="utf-8")
143149
)
144150

145151
fig = Figure()
@@ -168,7 +174,9 @@ def test_plot_results_components_data_structure(datadir):
168174
"""
169175
test results should have format of: [CLs_obs, [CLsb, CLb], [CLs_exp band]]
170176
"""
171-
data = json.load(datadir.joinpath("hypotest_results.json").open(encoding="utf-8"))
177+
data = json.loads(
178+
datadir.joinpath("hypotest_results.json").read_text(encoding="utf-8")
179+
)
172180

173181
fig = Figure()
174182
ax = fig.subplots()
@@ -184,7 +192,9 @@ def test_plot_results_wrong_axis_labels(datadir, mocker):
184192
values in label_part will be wrong, causing `next` to fail on the iterator
185193
for label_idx.
186194
"""
187-
data = json.load(datadir.joinpath("hypotest_results.json").open(encoding="utf-8"))
195+
data = json.loads(
196+
datadir.joinpath("hypotest_results.json").read_text(encoding="utf-8")
197+
)
188198

189199
fig = Figure()
190200
ax = fig.subplots()

0 commit comments

Comments
 (0)