From c56b3bb5aad6af035467abccea4214a75c345342 Mon Sep 17 00:00:00 2001 From: Erick Cobos Date: Fri, 10 Jul 2026 15:34:00 +0100 Subject: [PATCH 1/4] drop support for analyzers with no settings.json --- src/spikeinterface/core/sortinganalyzer.py | 23 +++++----------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/spikeinterface/core/sortinganalyzer.py b/src/spikeinterface/core/sortinganalyzer.py index a7af4d9630..7cb1aa3afe 100644 --- a/src/spikeinterface/core/sortinganalyzer.py +++ b/src/spikeinterface/core/sortinganalyzer.py @@ -905,28 +905,15 @@ def load_from_binary_folder( raise ValueError("This folder is not a SortingAnalyzer with format='binary_folder'") # Load settings file - analyzer_has_settings_file = settings_file.exists() - if analyzer_has_settings_file: + if settings_file.exists(): with open(settings_file, "r") as f: settings = json.load(f) else: - # TODO: Remove support for analyzers that have no settings.json (throw an error instead) - settings = dict() - settings = cls._handle_backward_compatibility_settings_pre_init(settings) - - # Create settings file (if not originally in the analyzer) - if not analyzer_has_settings_file: - # PATCH: Because SortingAnalyzer added settings.json during the development of 0.101.0 we need to save - # this as a bridge for early adopters. The else branch can be removed in version 0.102.0/0.103.0 - # so that this can be simplified in the future - # See https://github.com/SpikeInterface/spikeinterface/issues/2788 - warnings.warn( - "settings.json not found in this analyzer folder. Creating one with default settings.", - category=FutureWarning, - stacklevel=2, + raise ValueError( + "This folder is not a valid SortingAnalyzer folder. The settings.json file is missing. " + "Please ensure that you are loading a valid SortingAnalyzer folder." ) - with open(settings_file, "w") as f: - json.dump(check_json(settings), f, indent=4) + settings = cls._handle_backward_compatibility_settings_pre_init(settings) # Load sorting (in memory) sorting = NumpySorting.from_sorting( From 60aac0d486d72a3ef107cf6789e949fa21d2c3fb Mon Sep 17 00:00:00 2001 From: Erick Cobos Date: Fri, 10 Jul 2026 16:16:11 +0100 Subject: [PATCH 2/4] check for required input before loading --- src/spikeinterface/core/sortinganalyzer.py | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/spikeinterface/core/sortinganalyzer.py b/src/spikeinterface/core/sortinganalyzer.py index 7cb1aa3afe..4eead6928a 100644 --- a/src/spikeinterface/core/sortinganalyzer.py +++ b/src/spikeinterface/core/sortinganalyzer.py @@ -900,19 +900,15 @@ def load_from_binary_folder( rec_attributes_file = folder / "recording_info" / "recording_attributes.json" probegroup_file = folder / "recording_info" / "probegroup.json" - # Check that rec_attributes_file exists, otherwise this is not a valid SortingAnalyzer folder - if not rec_attributes_file.is_file(): - raise ValueError("This folder is not a SortingAnalyzer with format='binary_folder'") + # Check all required files are present + if not (settings_file.is_file() and sorting_folder.is_dir() and + rec_attributes_file.is_file()): + raise ValueError(f"Folder {folder} is not a valid SortingAnalyzer binary folder." + " Please ensure that you are loading a valid SortingAnalyzer folder.") # Load settings file - if settings_file.exists(): - with open(settings_file, "r") as f: - settings = json.load(f) - else: - raise ValueError( - "This folder is not a valid SortingAnalyzer folder. The settings.json file is missing. " - "Please ensure that you are loading a valid SortingAnalyzer folder." - ) + with open(settings_file, "r") as f: + settings = json.load(f) settings = cls._handle_backward_compatibility_settings_pre_init(settings) # Load sorting (in memory) @@ -1099,6 +1095,14 @@ def load_from_zarr( "This may lead to unexpected behavior in loading extensions. " "Consider re-generating the SortingAnalyzer object." ) + + # Check all required inputs exist + if (zarr_root.attrs.get("settings") is None or zarr_root.get("sorting") is None + or zarr_root.get("recording_info") is None + or zarr_root["recording_info"].attrs.get("recording_attributes") is None + ): + raise ValueError(f"Folder {folder} is not a valid SortingAnalyzer Zarr folder." + " Please ensure that you are loading a valid SortingAnalyzer folder.") # Load settings settings = zarr_root.attrs["settings"] From 01dd054692bdf61c7c5ac56049ef303357f465a0 Mon Sep 17 00:00:00 2001 From: Erick Cobos Date: Fri, 10 Jul 2026 19:38:46 +0100 Subject: [PATCH 3/4] Create SortingAnalyzer directly in create_* --- src/spikeinterface/core/sortinganalyzer.py | 40 ++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/spikeinterface/core/sortinganalyzer.py b/src/spikeinterface/core/sortinganalyzer.py index 4eead6928a..382bc585b0 100644 --- a/src/spikeinterface/core/sortinganalyzer.py +++ b/src/spikeinterface/core/sortinganalyzer.py @@ -414,8 +414,8 @@ def __init__( self, sorting: BaseSorting, recording: BaseRecording | None = None, + format: Literal["memory", "binary_folder", "zarr"] = "memory", rec_attributes: dict | None = None, - format: str | None = None, sparsity: ChannelSparsity | None = None, return_in_uV: bool = True, peak_sign: PeakSignType = "both", @@ -697,7 +697,7 @@ def create_binary_folder( json.dump(check_json(settings), f, indent=4) # Save the sorting output - sorting.save(folder=sorting_folder) + sorting = sorting.save(folder=sorting_folder) # Dump sorting provenance if sorting.check_serializability("json"): @@ -740,7 +740,21 @@ def create_binary_folder( if probegroup is not None: probeinterface.write_probeinterface(probegroup_file, probegroup) - return cls.load_from_binary_folder(folder, recording=recording, backend_options=backend_options) + # Create SortingAnalyzer + sorting_analyzer = SortingAnalyzer( + sorting=sorting, + recording=recording, + rec_attributes={**rec_attributes_to_save, 'probegroup': probegroup}, + format="binary_folder", + sparsity=sparsity, + return_in_uV=return_in_uV, + peak_sign=peak_sign, + peak_mode=peak_mode, + backend_options=backend_options, + ) + sorting_analyzer.folder = folder + + return sorting_analyzer @classmethod def _handle_backward_compatibility_settings_pre_init(cls, settings: dict[str, Any]): @@ -1063,7 +1077,21 @@ def create_zarr( # Consolidate metadata (for faster reads) zarr.consolidate_metadata(zarr_root.store) - return cls.load_from_zarr(folder, recording=recording, backend_options=backend_options) + # Create SortingAnalyzer + sorting_analyzer = SortingAnalyzer( + sorting=NumpySorting.from_sorting(sorting, with_metadata=True, copy_spike_vector=True), + recording=recording, + rec_attributes={**rec_attributes_to_save, 'probegroup': probegroup}, + format="zarr", + sparsity=sparsity, + return_in_uV=return_in_uV, + peak_sign=peak_sign, + peak_mode=peak_mode, + backend_options=backend_options, + ) + sorting_analyzer.folder = folder + + return sorting_analyzer @classmethod def load_from_zarr( @@ -1095,9 +1123,9 @@ def load_from_zarr( "This may lead to unexpected behavior in loading extensions. " "Consider re-generating the SortingAnalyzer object." ) - + # Check all required inputs exist - if (zarr_root.attrs.get("settings") is None or zarr_root.get("sorting") is None + if (zarr_root.attrs.get("settings") is None or zarr_root.get("sorting") is None or zarr_root.get("recording_info") is None or zarr_root["recording_info"].attrs.get("recording_attributes") is None ): From f4dc4a32c34ece0bdbed0f4bb31bb854e54c15aa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jul 2026 03:45:39 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/spikeinterface/core/sortinganalyzer.py | 23 +++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/spikeinterface/core/sortinganalyzer.py b/src/spikeinterface/core/sortinganalyzer.py index 382bc585b0..7c67021afa 100644 --- a/src/spikeinterface/core/sortinganalyzer.py +++ b/src/spikeinterface/core/sortinganalyzer.py @@ -744,7 +744,7 @@ def create_binary_folder( sorting_analyzer = SortingAnalyzer( sorting=sorting, recording=recording, - rec_attributes={**rec_attributes_to_save, 'probegroup': probegroup}, + rec_attributes={**rec_attributes_to_save, "probegroup": probegroup}, format="binary_folder", sparsity=sparsity, return_in_uV=return_in_uV, @@ -915,10 +915,11 @@ def load_from_binary_folder( probegroup_file = folder / "recording_info" / "probegroup.json" # Check all required files are present - if not (settings_file.is_file() and sorting_folder.is_dir() and - rec_attributes_file.is_file()): - raise ValueError(f"Folder {folder} is not a valid SortingAnalyzer binary folder." - " Please ensure that you are loading a valid SortingAnalyzer folder.") + if not (settings_file.is_file() and sorting_folder.is_dir() and rec_attributes_file.is_file()): + raise ValueError( + f"Folder {folder} is not a valid SortingAnalyzer binary folder." + " Please ensure that you are loading a valid SortingAnalyzer folder." + ) # Load settings file with open(settings_file, "r") as f: @@ -1081,7 +1082,7 @@ def create_zarr( sorting_analyzer = SortingAnalyzer( sorting=NumpySorting.from_sorting(sorting, with_metadata=True, copy_spike_vector=True), recording=recording, - rec_attributes={**rec_attributes_to_save, 'probegroup': probegroup}, + rec_attributes={**rec_attributes_to_save, "probegroup": probegroup}, format="zarr", sparsity=sparsity, return_in_uV=return_in_uV, @@ -1125,12 +1126,16 @@ def load_from_zarr( ) # Check all required inputs exist - if (zarr_root.attrs.get("settings") is None or zarr_root.get("sorting") is None + if ( + zarr_root.attrs.get("settings") is None + or zarr_root.get("sorting") is None or zarr_root.get("recording_info") is None or zarr_root["recording_info"].attrs.get("recording_attributes") is None ): - raise ValueError(f"Folder {folder} is not a valid SortingAnalyzer Zarr folder." - " Please ensure that you are loading a valid SortingAnalyzer folder.") + raise ValueError( + f"Folder {folder} is not a valid SortingAnalyzer Zarr folder." + " Please ensure that you are loading a valid SortingAnalyzer folder." + ) # Load settings settings = zarr_root.attrs["settings"]