From 8985f7074efc9b9786e77b8ff055c6bb45e84f53 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Fri, 23 May 2025 11:33:31 +0100 Subject: [PATCH 01/24] user access to proj_id and proj_name --- mne/_fiff/meas_info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 4833474a412..7724418f840 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -1634,8 +1634,8 @@ class Info(ValidatedDict, SetChannelsMixin, MontageMixin, ContainsMixin): "Please use methods inst.add_channels(), " "inst.drop_channels(), and inst.pick() instead.", "proc_history": "proc_history cannot be set directly.", - "proj_id": "proj_id cannot be set directly.", - "proj_name": "proj_name cannot be set directly.", + "proj_id": partial(_check_types, name="proj_id", types=(int, None)), + "proj_name": partial(_check_types, name="proj_name", types=(str, None)), "projs": "projs cannot be set directly. " "Please use methods inst.add_proj() and inst.del_proj() " "instead.", From ec964f53c46f987ecfa4a2dff8fa394f18d9b6a2 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Fri, 23 May 2025 12:06:47 +0100 Subject: [PATCH 02/24] updated class documentation --- mne/_fiff/meas_info.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 7724418f840..b9bb055e7fa 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -1173,10 +1173,10 @@ class Info(ValidatedDict, SetChannelsMixin, MontageMixin, ContainsMixin): .. warning:: The only entries that should be manually changed by the user are: - ``info['bads']``, ``info['description']``, ``info['device_info']`` - ``info['dev_head_t']``, ``info['experimenter']``, - ``info['helium_info']``, ``info['line_freq']``, ``info['temp']``, - and ``info['subject_info']``. + ``info['bads']``, ``info['description']``, ``info['device_info']``, + ``info['proj_id']``, ``info['proj_name']``, ``info['dev_head_t']``, + ``info['experimenter']``, ``info['helium_info']``, + ``info['line_freq']``, ``info['temp']``, and ``info['subject_info']``. All other entries should be considered read-only, though they can be modified by various MNE-Python functions or methods (which have From 71b1ecd4b87d49fb38f6e8db9ae6defbb26fc848 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 11:14:40 +0000 Subject: [PATCH 03/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/_fiff/meas_info.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index b9bb055e7fa..4f4bbfdf917 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -1173,9 +1173,9 @@ class Info(ValidatedDict, SetChannelsMixin, MontageMixin, ContainsMixin): .. warning:: The only entries that should be manually changed by the user are: - ``info['bads']``, ``info['description']``, ``info['device_info']``, - ``info['proj_id']``, ``info['proj_name']``, ``info['dev_head_t']``, - ``info['experimenter']``, ``info['helium_info']``, + ``info['bads']``, ``info['description']``, ``info['device_info']``, + ``info['proj_id']``, ``info['proj_name']``, ``info['dev_head_t']``, + ``info['experimenter']``, ``info['helium_info']``, ``info['line_freq']``, ``info['temp']``, and ``info['subject_info']``. All other entries should be considered read-only, though they can be @@ -1634,7 +1634,7 @@ class Info(ValidatedDict, SetChannelsMixin, MontageMixin, ContainsMixin): "Please use methods inst.add_channels(), " "inst.drop_channels(), and inst.pick() instead.", "proc_history": "proc_history cannot be set directly.", - "proj_id": partial(_check_types, name="proj_id", types=(int, None)), + "proj_id": partial(_check_types, name="proj_id", types=(int, None)), "proj_name": partial(_check_types, name="proj_name", types=(str, None)), "projs": "projs cannot be set directly. " "Please use methods inst.add_proj() and inst.del_proj() " From e40061bd586c294bc8829558408a27d876c05434 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Sun, 25 May 2025 12:04:57 +0100 Subject: [PATCH 04/24] Added tests and contrib info --- doc/changes/devel/13261.newfeature.rst | 2 ++ doc/changes/names.inc | 1 + mne/_fiff/meas_info.py | 2 +- mne/_fiff/tests/test_meas_info.py | 13 +++++++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 doc/changes/devel/13261.newfeature.rst diff --git a/doc/changes/devel/13261.newfeature.rst b/doc/changes/devel/13261.newfeature.rst new file mode 100644 index 00000000000..2306781b881 --- /dev/null +++ b/doc/changes/devel/13261.newfeature.rst @@ -0,0 +1,2 @@ +User can set values for fields ``proj_id`` and ``proj_name`` in :class:`Info` dict, by :newcontrib:`Laurent Le Mentec`_. + diff --git a/doc/changes/names.inc b/doc/changes/names.inc index d20931b7a51..c4c8501e3ca 100644 --- a/doc/changes/names.inc +++ b/doc/changes/names.inc @@ -166,6 +166,7 @@ .. _Larry Eisenman: https://github.com/lneisenman .. _Lau Møller Andersen: https://github.com/ualsbombe .. _Laura Gwilliams: https://lauragwilliams.github.io +.. _Laurent Le Mentec: https://github.com/LaurentLM .. _Leonardo Barbosa: https://github.com/noreun .. _Leonardo Rochael Almeida: https://github.com/leorochael .. _Liberty Hamilton: https://github.com/libertyh diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index b9bb055e7fa..30fa847f227 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -2537,7 +2537,7 @@ def read_meas_info(fid, tree, clean_bads=False, verbose=None): info["meas_id"] = meas_info["parent_id"] info["experimenter"] = experimenter info["description"] = description - info["proj_id"] = proj_id + info["proj_id"] = proj_id.item() info["proj_name"] = proj_name if meas_date is None: meas_date = (info["meas_id"]["secs"], info["meas_id"]["usecs"]) diff --git a/mne/_fiff/tests/test_meas_info.py b/mne/_fiff/tests/test_meas_info.py index 9ca83697df0..2b6cf6202c4 100644 --- a/mne/_fiff/tests/test_meas_info.py +++ b/mne/_fiff/tests/test_meas_info.py @@ -1217,6 +1217,7 @@ def test_info_bad(): info["line_freq"] = 50.0 info["bads"] = info["ch_names"][:1] info["temp"] = ("whatever", 1.0) + with pytest.raises(RuntimeError, match=r"info\['temp'\]"): info["bad_key"] = 1.0 for key, match in [("sfreq", r"inst\.resample"), ("chs", r"inst\.add_channels")]: @@ -1277,3 +1278,15 @@ def test_tag_consistency(): assert call_set == call_names, "Mismatch between _call_dict and _call_dict_names" # TODO: This was inspired by FIFF_DIG_STRING gh-13083, we should ideally add a test # that those dig points can actually be read in correctly at some point. + + +def test_proj_id_entries(): + """Test that proj_id entries are the right type.""" + info = create_info(5, 1000.0, "eeg") + info['proj_id'] = 123 + with pytest.raises(TypeError, match="must be an instance"): + info["proj_id"] = "bad" + with pytest.raises(TypeError, match="must be an instance"): + info["proj_id"] = np.array([123]) + with pytest.raises(TypeError, match="must be an instance"): + info["proj_id"] = True \ No newline at end of file From 6ac6dc71935e2c964862b97c52a12d513858e913 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 25 May 2025 11:05:30 +0000 Subject: [PATCH 05/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/_fiff/tests/test_meas_info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mne/_fiff/tests/test_meas_info.py b/mne/_fiff/tests/test_meas_info.py index 2b6cf6202c4..f85563eadd2 100644 --- a/mne/_fiff/tests/test_meas_info.py +++ b/mne/_fiff/tests/test_meas_info.py @@ -1283,10 +1283,10 @@ def test_tag_consistency(): def test_proj_id_entries(): """Test that proj_id entries are the right type.""" info = create_info(5, 1000.0, "eeg") - info['proj_id'] = 123 + info["proj_id"] = 123 with pytest.raises(TypeError, match="must be an instance"): info["proj_id"] = "bad" with pytest.raises(TypeError, match="must be an instance"): info["proj_id"] = np.array([123]) with pytest.raises(TypeError, match="must be an instance"): - info["proj_id"] = True \ No newline at end of file + info["proj_id"] = True From 079d7a24b21f644fd0e03d174c93fb18c4df0c69 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Sun, 25 May 2025 12:28:11 +0100 Subject: [PATCH 06/24] Attempt to fix ndarray error --- mne/_fiff/meas_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index dbbcd2c4924..55164aa43ba 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -1634,7 +1634,7 @@ class Info(ValidatedDict, SetChannelsMixin, MontageMixin, ContainsMixin): "Please use methods inst.add_channels(), " "inst.drop_channels(), and inst.pick() instead.", "proc_history": "proc_history cannot be set directly.", - "proj_id": partial(_check_types, name="proj_id", types=(int, None)), + "proj_id": partial(_check_types, name="proj_id", types=(int, np.ndarray, None), cast=int), "proj_name": partial(_check_types, name="proj_name", types=(str, None)), "projs": "projs cannot be set directly. " "Please use methods inst.add_proj() and inst.del_proj() " From 0e6778a6a7f9d38206460f990e9355eb3c684e25 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 25 May 2025 11:28:33 +0000 Subject: [PATCH 07/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/_fiff/meas_info.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 55164aa43ba..966af8dbb95 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -1634,7 +1634,9 @@ class Info(ValidatedDict, SetChannelsMixin, MontageMixin, ContainsMixin): "Please use methods inst.add_channels(), " "inst.drop_channels(), and inst.pick() instead.", "proc_history": "proc_history cannot be set directly.", - "proj_id": partial(_check_types, name="proj_id", types=(int, np.ndarray, None), cast=int), + "proj_id": partial( + _check_types, name="proj_id", types=(int, np.ndarray, None), cast=int + ), "proj_name": partial(_check_types, name="proj_name", types=(str, None)), "projs": "projs cannot be set directly. " "Please use methods inst.add_proj() and inst.del_proj() " From 9eeb532e3cd8c880b9111e43f41322452b9db01e Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Sun, 25 May 2025 13:44:08 +0100 Subject: [PATCH 08/24] fix for ndarrays --- doc/changes/devel/13261.newfeature.rst | 3 +-- mne/_fiff/meas_info.py | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/changes/devel/13261.newfeature.rst b/doc/changes/devel/13261.newfeature.rst index 2306781b881..5e7ce4dc85e 100644 --- a/doc/changes/devel/13261.newfeature.rst +++ b/doc/changes/devel/13261.newfeature.rst @@ -1,2 +1 @@ -User can set values for fields ``proj_id`` and ``proj_name`` in :class:`Info` dict, by :newcontrib:`Laurent Le Mentec`_. - +User can set values for fields ``proj_id`` and ``proj_name`` in :class:`Info` dict, by :newcontrib:`Laurent Le Mentec`_. \ No newline at end of file diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 966af8dbb95..cff33e81567 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -1635,7 +1635,7 @@ class Info(ValidatedDict, SetChannelsMixin, MontageMixin, ContainsMixin): "inst.drop_channels(), and inst.pick() instead.", "proc_history": "proc_history cannot be set directly.", "proj_id": partial( - _check_types, name="proj_id", types=(int, np.ndarray, None), cast=int + _check_types, name="proj_id", types=(int, None), cast=int ), "proj_name": partial(_check_types, name="proj_name", types=(str, None)), "projs": "projs cannot be set directly. " @@ -2539,7 +2539,9 @@ def read_meas_info(fid, tree, clean_bads=False, verbose=None): info["meas_id"] = meas_info["parent_id"] info["experimenter"] = experimenter info["description"] = description - info["proj_id"] = proj_id.item() + if type(proj_id) == np.ndarray: + proj_id = proj_id.item() + info["proj_id"] = proj_id info["proj_name"] = proj_name if meas_date is None: meas_date = (info["meas_id"]["secs"], info["meas_id"]["usecs"]) From 5212596a122e001d19437546e22b3e271b2db90b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 25 May 2025 12:44:30 +0000 Subject: [PATCH 09/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/_fiff/meas_info.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index cff33e81567..a612f23bca1 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -1634,9 +1634,7 @@ class Info(ValidatedDict, SetChannelsMixin, MontageMixin, ContainsMixin): "Please use methods inst.add_channels(), " "inst.drop_channels(), and inst.pick() instead.", "proc_history": "proc_history cannot be set directly.", - "proj_id": partial( - _check_types, name="proj_id", types=(int, None), cast=int - ), + "proj_id": partial(_check_types, name="proj_id", types=(int, None), cast=int), "proj_name": partial(_check_types, name="proj_name", types=(str, None)), "projs": "projs cannot be set directly. " "Please use methods inst.add_proj() and inst.del_proj() " From 25e0a0fb70403532192e5ba6687b3bb7318519c5 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Sun, 25 May 2025 14:10:44 +0100 Subject: [PATCH 10/24] fix formatting --- doc/changes/devel/13261.newfeature.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/devel/13261.newfeature.rst b/doc/changes/devel/13261.newfeature.rst index 5e7ce4dc85e..1c6c736bb45 100644 --- a/doc/changes/devel/13261.newfeature.rst +++ b/doc/changes/devel/13261.newfeature.rst @@ -1 +1 @@ -User can set values for fields ``proj_id`` and ``proj_name`` in :class:`Info` dict, by :newcontrib:`Laurent Le Mentec`_. \ No newline at end of file +User can set values for fields ``proj_id`` and ``proj_name`` in ``Info`` dict, by :newcontrib:`Laurent Le Mentec`. \ No newline at end of file From e43df5229b8071c73d99a0938417df411c8c474a Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Sun, 25 May 2025 19:26:19 +0100 Subject: [PATCH 11/24] using isinstance to check proj_id type --- mne/_fiff/meas_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index a612f23bca1..0617675e467 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -2537,7 +2537,7 @@ def read_meas_info(fid, tree, clean_bads=False, verbose=None): info["meas_id"] = meas_info["parent_id"] info["experimenter"] = experimenter info["description"] = description - if type(proj_id) == np.ndarray: + if isinstance(proj_id, np.ndarray): proj_id = proj_id.item() info["proj_id"] = proj_id info["proj_name"] = proj_name From c576799a5bad87153f29aad44101c575c16d7fc3 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Tue, 3 Jun 2025 20:46:32 +0100 Subject: [PATCH 12/24] initialise infor['prij_id'] as int instead of nd array. Conversion to int when coming from FIFF. --- mne/_fiff/meas_info.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 0617675e467..3129a82d3fe 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -2206,7 +2206,10 @@ def read_meas_info(fid, tree, clean_bads=False, verbose=None): description = tag.data elif kind == FIFF.FIFF_PROJ_ID: tag = read_tag(fid, pos) - proj_id = tag.data + if isinstance(tag.data, np.ndarray): + proj_id = int(proj_id.item()) + else: + proj_id = int(tag.data.item()) elif kind == FIFF.FIFF_PROJ_NAME: tag = read_tag(fid, pos) proj_name = tag.data @@ -2537,8 +2540,6 @@ def read_meas_info(fid, tree, clean_bads=False, verbose=None): info["meas_id"] = meas_info["parent_id"] info["experimenter"] = experimenter info["description"] = description - if isinstance(proj_id, np.ndarray): - proj_id = proj_id.item() info["proj_id"] = proj_id info["proj_name"] = proj_name if meas_date is None: @@ -3500,7 +3501,7 @@ def anonymize_info(info, daysback=None, keep_his=False, verbose=None): info["description"] = default_desc with info._unlock(): if info["proj_id"] is not None: - info["proj_id"] = np.zeros_like(info["proj_id"]) + info["proj_id"] = 0 if info["proj_name"] is not None: info["proj_name"] = default_str if info["utc_offset"] is not None: From a5f20fb47e5f33b3fa4415affdc5bbde8c78aaf3 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Tue, 3 Jun 2025 20:48:55 +0100 Subject: [PATCH 13/24] updated type conversion --- mne/_fiff/meas_info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 3129a82d3fe..a65eb4061e5 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -2207,9 +2207,9 @@ def read_meas_info(fid, tree, clean_bads=False, verbose=None): elif kind == FIFF.FIFF_PROJ_ID: tag = read_tag(fid, pos) if isinstance(tag.data, np.ndarray): - proj_id = int(proj_id.item()) - else: proj_id = int(tag.data.item()) + else: + proj_id = int(tag.data) elif kind == FIFF.FIFF_PROJ_NAME: tag = read_tag(fid, pos) proj_name = tag.data From b0e1a72b8745a64c3ad09dd07827d4a9ae4f0616 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Tue, 3 Jun 2025 23:09:02 +0100 Subject: [PATCH 14/24] changed ndarray to int as per allowed types for info['proj_id'] --- mne/_fiff/tests/test_meas_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/_fiff/tests/test_meas_info.py b/mne/_fiff/tests/test_meas_info.py index f85563eadd2..178d4a7c8fe 100644 --- a/mne/_fiff/tests/test_meas_info.py +++ b/mne/_fiff/tests/test_meas_info.py @@ -798,7 +798,7 @@ def _complete_info(info): info["experimenter"] = "f" info["description"] = "g" with info._unlock(): - info["proj_id"] = np.ones(1, int) + info["proj_id"] = 1 info["proj_name"] = "h" info["utc_offset"] = "i" d = (1717707794, 2) From 883534e6702f1de7e9b216469b2bd99d33f9dc5d Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Wed, 4 Jun 2025 22:15:47 +0100 Subject: [PATCH 15/24] fixed tests and merge --- mne/_fiff/meas_info.py | 9 +++++++++ mne/_fiff/tests/test_meas_info.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index a65eb4061e5..c4890f094ea 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -3012,6 +3012,15 @@ def _where_isinstance(values, kind): return values[int(idx)] elif len(idx) > 1: raise RuntimeError(msg) + #proj_id + elif _check_isinstance(values, (int, None), all): + if key == "proj_id": + unique_values = set(values) + if len(unique_values) == 1: + return list(unique_values)[0] + else: + # We are merging a known proj_id with an unknown one + return None # other else: unique_values = set(values) diff --git a/mne/_fiff/tests/test_meas_info.py b/mne/_fiff/tests/test_meas_info.py index 178d4a7c8fe..f7003848da4 100644 --- a/mne/_fiff/tests/test_meas_info.py +++ b/mne/_fiff/tests/test_meas_info.py @@ -637,7 +637,7 @@ def _test_anonymize_info(base_info, tmp_path): for lev in tp[:-1]: this = this[lev] this[tp[-1]] = default_str - exp_info["proj_id"] = np.array([0]) + exp_info["proj_id"] = 0 for key in ("sex", "id", "height", "weight"): exp_info["subject_info"][key] = 0 exp_info["subject_info"]["his_id"] = str(default_subject_id) From 6c6bd85130ce8c0189c4838befdc191f14effcf1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 21:16:07 +0000 Subject: [PATCH 16/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/_fiff/meas_info.py | 2 +- mne/_fiff/tests/test_meas_info.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index c4890f094ea..f17a1bbc27f 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -3012,7 +3012,7 @@ def _where_isinstance(values, kind): return values[int(idx)] elif len(idx) > 1: raise RuntimeError(msg) - #proj_id + # proj_id elif _check_isinstance(values, (int, None), all): if key == "proj_id": unique_values = set(values) diff --git a/mne/_fiff/tests/test_meas_info.py b/mne/_fiff/tests/test_meas_info.py index f7003848da4..89a3e4358ef 100644 --- a/mne/_fiff/tests/test_meas_info.py +++ b/mne/_fiff/tests/test_meas_info.py @@ -637,7 +637,7 @@ def _test_anonymize_info(base_info, tmp_path): for lev in tp[:-1]: this = this[lev] this[tp[-1]] = default_str - exp_info["proj_id"] = 0 + exp_info["proj_id"] = 0 for key in ("sex", "id", "height", "weight"): exp_info["subject_info"][key] = 0 exp_info["subject_info"]["his_id"] = str(default_subject_id) From 7d94a82995b0b0206c70c91f68415df72be02a90 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Thu, 5 Jun 2025 00:09:02 +0100 Subject: [PATCH 17/24] update in tests and _merge_info_values --- mne/_fiff/meas_info.py | 2 +- mne/_fiff/tests/test_meas_info.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index f17a1bbc27f..e636fc36e83 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -3013,7 +3013,7 @@ def _where_isinstance(values, kind): elif len(idx) > 1: raise RuntimeError(msg) # proj_id - elif _check_isinstance(values, (int, None), all): + elif _check_isinstance(values, (int, type(None)), all): if key == "proj_id": unique_values = set(values) if len(unique_values) == 1: diff --git a/mne/_fiff/tests/test_meas_info.py b/mne/_fiff/tests/test_meas_info.py index 89a3e4358ef..b43229ff882 100644 --- a/mne/_fiff/tests/test_meas_info.py +++ b/mne/_fiff/tests/test_meas_info.py @@ -1284,9 +1284,9 @@ def test_proj_id_entries(): """Test that proj_id entries are the right type.""" info = create_info(5, 1000.0, "eeg") info["proj_id"] = 123 + # Boolean should be cast into an int + info["proj_id"] = True with pytest.raises(TypeError, match="must be an instance"): info["proj_id"] = "bad" with pytest.raises(TypeError, match="must be an instance"): - info["proj_id"] = np.array([123]) - with pytest.raises(TypeError, match="must be an instance"): - info["proj_id"] = True + info["proj_id"] = np.array([123]) \ No newline at end of file From 7b148c0b1b4a54fa096ff1d445cc15122bc8ec0c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 23:09:35 +0000 Subject: [PATCH 18/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/_fiff/tests/test_meas_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne/_fiff/tests/test_meas_info.py b/mne/_fiff/tests/test_meas_info.py index b43229ff882..2a4cd60cb0a 100644 --- a/mne/_fiff/tests/test_meas_info.py +++ b/mne/_fiff/tests/test_meas_info.py @@ -1289,4 +1289,4 @@ def test_proj_id_entries(): with pytest.raises(TypeError, match="must be an instance"): info["proj_id"] = "bad" with pytest.raises(TypeError, match="must be an instance"): - info["proj_id"] = np.array([123]) \ No newline at end of file + info["proj_id"] = np.array([123]) From 78a3b5dffc5136ca0f6475b8b210086900a0aa60 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Thu, 5 Jun 2025 19:21:24 +0100 Subject: [PATCH 19/24] changed merging behaviour for project_id --- mne/_fiff/meas_info.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index f17a1bbc27f..5a0f5f9033e 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -3013,14 +3013,9 @@ def _where_isinstance(values, kind): elif len(idx) > 1: raise RuntimeError(msg) # proj_id - elif _check_isinstance(values, (int, None), all): - if key == "proj_id": - unique_values = set(values) - if len(unique_values) == 1: - return list(unique_values)[0] - else: - # We are merging a known proj_id with an unknown one - return None + elif _check_isinstance(values, (int, None), all) and key == "proj_id": + unique_values = set(values) + return list(unique_values)[0] # other else: unique_values = set(values) From a8609c8966cfe68488fe9f8eae913e44cb7d542a Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Thu, 5 Jun 2025 19:25:27 +0100 Subject: [PATCH 20/24] updated merging of proj_id --- mne/_fiff/meas_info.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index e636fc36e83..e5a6d710afa 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -3013,14 +3013,9 @@ def _where_isinstance(values, kind): elif len(idx) > 1: raise RuntimeError(msg) # proj_id - elif _check_isinstance(values, (int, type(None)), all): - if key == "proj_id": - unique_values = set(values) - if len(unique_values) == 1: - return list(unique_values)[0] - else: - # We are merging a known proj_id with an unknown one - return None + elif _check_isinstance(values, (int, type(None)), all) and key == "proj_id": + unique_values = set(values) + return list(unique_values)[0] # other else: unique_values = set(values) From 9a4527f8801ada7c53e17d5865cb3ec5e7dea889 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Thu, 5 Jun 2025 19:46:03 +0100 Subject: [PATCH 21/24] Update mne/_fiff/meas_info.py Co-authored-by: Eric Larson --- mne/_fiff/meas_info.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index e5a6d710afa..941c7831a08 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -2206,10 +2206,7 @@ def read_meas_info(fid, tree, clean_bads=False, verbose=None): description = tag.data elif kind == FIFF.FIFF_PROJ_ID: tag = read_tag(fid, pos) - if isinstance(tag.data, np.ndarray): - proj_id = int(tag.data.item()) - else: - proj_id = int(tag.data) + proj_id = int(tag.data.item()) elif kind == FIFF.FIFF_PROJ_NAME: tag = read_tag(fid, pos) proj_name = tag.data From 6f7673db46f429185c78a5f30f06dd3a8af4f89f Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Thu, 5 Jun 2025 19:52:20 +0100 Subject: [PATCH 22/24] Added info message as ped Eric's suggestion --- mne/_fiff/meas_info.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 941c7831a08..498af52d4d8 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -3012,6 +3012,8 @@ def _where_isinstance(values, kind): # proj_id elif _check_isinstance(values, (int, type(None)), all) and key == "proj_id": unique_values = set(values) + if len(unique_values) != 1: + logger.info("Found multiple proj_ids, using the first one.") return list(unique_values)[0] # other else: From 8c3eb38d0a488c9ecdfa3d047bc9a96d5fbb3398 Mon Sep 17 00:00:00 2001 From: LaurentLM Date: Fri, 6 Jun 2025 15:06:51 +0100 Subject: [PATCH 23/24] improved merging messages. Fix bug when merging experimenters. --- mne/_fiff/meas_info.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 498af52d4d8..4fc03499850 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -3015,6 +3015,15 @@ def _where_isinstance(values, kind): if len(unique_values) != 1: logger.info("Found multiple proj_ids, using the first one.") return list(unique_values)[0] + + elif key == "experimenter" or key =="proj_name": + if _check_isinstance(values, (str, type(None)), all) : + unique_values = set(values) + unique_values.discard(None) + if len(unique_values) == 1: + return list(unique_values)[0] + else: + return None # other else: unique_values = set(values) @@ -3024,7 +3033,7 @@ def _where_isinstance(values, kind): logger.info("Found multiple StringIO instances. Setting value to `None`") return None elif isinstance(list(unique_values)[0], str): - logger.info("Found multiple filenames. Setting value to `None`") + logger.info(f"Found multiple {key}. Setting value to `None`") return None else: raise RuntimeError(msg) @@ -3765,4 +3774,4 @@ def _get_fnirs_ch_pos(info): def _camel_to_snake(s): - return re.sub(r"(? Date: Fri, 6 Jun 2025 14:07:16 +0000 Subject: [PATCH 24/24] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mne/_fiff/meas_info.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mne/_fiff/meas_info.py b/mne/_fiff/meas_info.py index 4fc03499850..8692682056b 100644 --- a/mne/_fiff/meas_info.py +++ b/mne/_fiff/meas_info.py @@ -3015,9 +3015,9 @@ def _where_isinstance(values, kind): if len(unique_values) != 1: logger.info("Found multiple proj_ids, using the first one.") return list(unique_values)[0] - - elif key == "experimenter" or key =="proj_name": - if _check_isinstance(values, (str, type(None)), all) : + + elif key == "experimenter" or key == "proj_name": + if _check_isinstance(values, (str, type(None)), all): unique_values = set(values) unique_values.discard(None) if len(unique_values) == 1: @@ -3774,4 +3774,4 @@ def _get_fnirs_ch_pos(info): def _camel_to_snake(s): - return re.sub(r"(?