Repository: SpikeInterface/spikeinterface

Issue:
`select_units` fails in `SortingAnalyzer` after using `load_sorting_analyzer`
## Problem

After saving a sorter (to binary_folder) and then reloading, you can no longer use the `select_units` function.

## MRE

```python
rec, sorting = si.generate_ground_truth_recording()
analyzer = si.create_sorting_analyzer(sorting, rec, format = 'binary_folder', folder='./test')
analyzer.compute(['random_spikes', 'waveforms', 'templates'])
new_analyzer= si.load_sorting_analyzer(folder='./test')
new_analyzer.select_units(unit_ids=[1])
```
Stack trace
```
Cell In[16], line 1
    new_analyzer.select_units(unit_ids=[1])
  File ~\Documents\GitHub\spikeinterface\src\spikeinterface\core\sortinganalyzer.py:714 in select_units
    return self._save_or_select(format=format, folder=folder, unit_ids=unit_ids)
  File ~\Documents\GitHub\spikeinterface\src\spikeinterface\core\sortinganalyzer.py:669 in _save_or_select
    new_ext = new_sorting_analyzer.extensions[extension_name] = extension.copy(
  File ~\Documents\GitHub\spikeinterface\src\spikeinterface\core\sortinganalyzer.py:1630 in copy
    new_extension.data = self._select_extension_data(unit_ids)
  File ~\Documents\GitHub\spikeinterface\src\spikeinterface\core\analyzer_extension_core.py:426 in _select_extension_data
    new_data[key] = arr[keep_unit_indices, :, :]
TypeError: unhashable type: 'numpy.ndarray'
```

The issue is that upon reload we load the `info.json` from the extension which means that our `self.data` has a key of `info` and a value of `dict`. Then when we try to use the `keep_unit_indices` it leads to the error trying to index on the dict with an array.

## Solution

We just don't load the `info.json` into the data. I'm just not sure where we need to move it to? @alejoe91 @samuelgarcia. 

cc @HerrietHsieh


Discussion:

Patch:
diff --git a/src/spikeinterface/core/sortinganalyzer.py b/src/spikeinterface/core/sortinganalyzer.py
index 46d02099d..009401201 100644
--- a/src/spikeinterface/core/sortinganalyzer.py
+++ b/src/spikeinterface/core/sortinganalyzer.py
@@ -1608,7 +1608,9 @@ class AnalyzerExtension:
         if self.format == "binary_folder":
             extension_folder = self._get_binary_extension_folder()
             for ext_data_file in extension_folder.iterdir():
-                if ext_data_file.name == "params.json":
+                # patch for https://github.com/SpikeInterface/spikeinterface/issues/3041
+                # maybe add a check for version number from the info.json during loading only
+                if ext_data_file.name == "params.json" or ext_data_file.name == "info.json":
                     continue
                 ext_data_name = ext_data_file.stem
                 if ext_data_file.suffix == ".json":


Test patch:
diff --git a/src/spikeinterface/core/tests/test_sortinganalyzer.py b/src/spikeinterface/core/tests/test_sortinganalyzer.py
index d78093214..7456680b2 100644
--- a/src/spikeinterface/core/tests/test_sortinganalyzer.py
+++ b/src/spikeinterface/core/tests/test_sortinganalyzer.py
@@ -67,9 +67,16 @@ def test_SortingAnalyzer_binary_folder(tmp_path, dataset):
     sorting_analyzer = create_sorting_analyzer(
         sorting, recording, format="binary_folder", folder=folder, sparse=False, sparsity=None
     )
+
+    sorting_analyzer.compute(["random_spikes", "templates"])
     sorting_analyzer = load_sorting_analyzer(folder, format="auto")
     _check_sorting_analyzers(sorting_analyzer, sorting, cache_folder=tmp_path)
 
+    # test select_units see https://github.com/SpikeInterface/spikeinterface/issues/3041
+    # this bug requires that we have an info.json file so we calculate templates above
+    select_units_sorting_analyer = sorting_analyzer.select_units(unit_ids=[1])
+    assert len(select_units_sorting_analyer.unit_ids) == 1
+
     folder = tmp_path / "test_SortingAnalyzer_binary_folder"
     if folder.exists():
         shutil.rmtree(folder)
@@ -97,9 +104,15 @@ def test_SortingAnalyzer_zarr(tmp_path, dataset):
     sorting_analyzer = create_sorting_analyzer(
         sorting, recording, format="zarr", folder=folder, sparse=False, sparsity=None
     )
+    sorting_analyzer.compute(["random_spikes", "templates"])
     sorting_analyzer = load_sorting_analyzer(folder, format="auto")
     _check_sorting_analyzers(sorting_analyzer, sorting, cache_folder=tmp_path)
 
+    # test select_units see https://github.com/SpikeInterface/spikeinterface/issues/3041
+    # this bug requires that we have an info.json file so we calculate templates above
+    select_units_sorting_analyer = sorting_analyzer.select_units(unit_ids=[1])
+    assert len(select_units_sorting_analyer.unit_ids) == 1
+
     folder = tmp_path / "test_SortingAnalyzer_zarr.zarr"
     if folder.exists():
         shutil.rmtree(folder)
@@ -312,7 +325,7 @@ def test_extensions_sorting():
 
 if __name__ == "__main__":
     tmp_path = Path("test_SortingAnalyzer")
-    dataset = _get_dataset()
+    dataset = get_dataset()
     test_SortingAnalyzer_memory(tmp_path, dataset)
     test_SortingAnalyzer_binary_folder(tmp_path, dataset)
     test_SortingAnalyzer_zarr(tmp_path, dataset)