Repository: mne-tools/mne-python

Issue:
Test failure for 1.5.0 on Fedora: 
### Description of the problem

A test fails when building mne-python from source on Fedora rawhide (python 3.12)

### Steps to reproduce


The complete spec file is here:

https://src.fedoraproject.org/fork/ankursinha/rpms/python-mne/blob/b5469bbe631fb57fc09fbb4a453615e1b7ba9c1c/f/python-mne.spec#_140

We're just running the tests during the build like this:

```
export SETUPTOOLS_SCM_PRETEND_VERSION='%{version}'
export MNE_SKIP_TESTING_DATASET_TESTS=true
export MNE_SKIP_NETWORK_TESTS=1
export MNE_DONTWRITE_HOME=true
export MNE_FORCE_SERIAL=true
 
# Deselected tests require additional data or don't work in mock
# Two deselected for sklearn warnings
# Tools directory ignored as it contains tests for upstream release process
 
# required for some tests
mkdir subjects
 
# https://github.com/mne-tools/mne-python/blob/v1.0.3/tools/github_actions_test.sh#L7
# skip tests that require network
pytest -v -m "not (slowtest or pgtest)" \
    --deselect mne/datasets/tests/test_datasets.py \
    --deselect mne/utils/tests/test_numerics.py
```


### Link to data

_No response_

### Expected results

All tests pass.

### Actual results

```
=================================== FAILURES ===================================
________________ test_cluster_permutation_with_adjacency[NumPy] ________________
mne/stats/tests/test_cluster_level.py:472: in test_cluster_permutation_with_adjacency
    assert len(w) == 1
E   assert 2 == 1
E    +  where 2 = len([<warnings.WarningMessage object at 0x7f2d3ee7c110>, <warnings.WarningMessage object at 0x7f2d3ee7cd10>])
```

### Additional information

The complete build log is attached:

[build.log.txt](https://github.com/mne-tools/mne-python/files/12466211/build.log.txt)



Discussion:
thanks for the report, we'll look into it.

Resolving patch:
diff --git a/mne/chpi.py b/mne/chpi.py
--- a/mne/chpi.py
+++ b/mne/chpi.py
@@ -18,6 +18,7 @@
 #
 # License: BSD-3-Clause
 
+import copy
 from functools import partial
 import itertools
 
@@ -416,16 +417,21 @@ def _get_hpi_initial_fit(info, adjust=False, verbose=None):
         key=lambda x: x["ident"],
     )  # ascending (dig) order
     if len(hpi_dig) == 0:  # CTF data, probably
+        msg = "HPIFIT: No HPI dig points, using hpifit result"
         hpi_dig = sorted(hpi_result["dig_points"], key=lambda x: x["ident"])
         if all(
             d["coord_frame"] in (FIFF.FIFFV_COORD_DEVICE, FIFF.FIFFV_COORD_UNKNOWN)
             for d in hpi_dig
         ):
+            # Do not modify in place!
+            hpi_dig = copy.deepcopy(hpi_dig)
+            msg += " transformed to head coords"
             for dig in hpi_dig:
                 dig.update(
                     r=apply_trans(info["dev_head_t"], dig["r"]),
                     coord_frame=FIFF.FIFFV_COORD_HEAD,
                 )
+        logger.debug(msg)
 
     # zero-based indexing, dig->info
     # CTF does not populate some entries so we use .get here


Test patch:
diff --git a/mne/stats/tests/test_cluster_level.py b/mne/stats/tests/test_cluster_level.py
--- a/mne/stats/tests/test_cluster_level.py
+++ b/mne/stats/tests/test_cluster_level.py
@@ -469,7 +469,8 @@ def test_cluster_permutation_with_adjacency(numba_conditional, monkeypatch):
                 X1d_3, adjacency=adjacency, threshold=dict(start=10, step=1)
             )
         if not did_warn:
-            assert len(w) == 1
+            messages = [str(ww.message) for ww in w]
+            assert any("is more extreme" in message for message in messages), messages
             did_warn = True
 
         with pytest.raises(ValueError, match="threshold.*<= 0 for tail == -1"):
diff --git a/mne/tests/test_chpi.py b/mne/tests/test_chpi.py
--- a/mne/tests/test_chpi.py
+++ b/mne/tests/test_chpi.py
@@ -752,7 +752,7 @@ def test_chpi_subtraction_filter_chpi():
 
 
 @testing.requires_testing_data
-def test_calculate_head_pos_ctf():
+def test_calculate_head_pos_ctf(tmp_path):
     """Test extracting of cHPI positions from CTF data."""
     raw = read_raw_ctf(ctf_chpi_fname)
     chpi_locs = extract_chpi_locs_ctf(raw)
@@ -764,9 +764,28 @@ def test_calculate_head_pos_ctf():
     )  # 7 mm/s
     plot_head_positions(quats, info=raw.info)
 
-    raw = read_raw_fif(ctf_fname)
     with pytest.raises(RuntimeError, match="Could not find"):
-        extract_chpi_locs_ctf(raw)
+        extract_chpi_locs_ctf(read_raw_fif(ctf_fname))
+
+    # save-load should not affect result
+    fname_temp = tmp_path / "test_ctf_raw.fif"
+    raw.save(fname_temp)
+    raw_read = read_raw_fif(fname_temp)
+    # the two attributes used by compute_head_pos
+    assert_allclose(
+        raw.info["dev_head_t"]["trans"], raw_read.info["dev_head_t"]["trans"]
+    )
+    with pytest.warns(RuntimeWarning, match="is poor"):
+        head_rrs = _get_hpi_initial_fit(raw.info, verbose="debug")
+    with pytest.warns(RuntimeWarning, match="is poor"):
+        head_rrs_2 = _get_hpi_initial_fit(raw_read.info, verbose="debug")
+    assert_allclose(head_rrs, head_rrs_2, atol=1e-5)
+    quats_2 = compute_head_pos(raw_read.info, chpi_locs)
+    _assert_quats(quats, quats_2, dist_tol=1e-5, angle_tol=0.1)
+    chpi_locs_2 = extract_chpi_locs_ctf(raw_read)
+    assert_allclose(chpi_locs["rrs"], chpi_locs_2["rrs"], atol=1e-5)
+    quats_3 = compute_head_pos(raw_read.info, chpi_locs_2)
+    _assert_quats(quats, quats_3, dist_tol=1e-5, angle_tol=0.1)
 
 
 @testing.requires_testing_data