diff --git a/src/spikeinterface/core/base.py b/src/spikeinterface/core/base.py index 9dd5d4d5b5..ae563c17ae 100644 --- a/src/spikeinterface/core/base.py +++ b/src/spikeinterface/core/base.py @@ -81,6 +81,10 @@ def __init__(self, main_ids: Sequence) -> None: # "main_ids" will either be channel_ids or units_ids # They are used for properties self._main_ids = np.array(main_ids) + if self._main_ids.dtype.kind == "T": + # numpy's variable-width StringDType, which is what a zarr v3 store hands back for a + # string column. Store it as fixed-width unicode like every other source. + self._main_ids = np.array(self._main_ids.tolist()) if len(self._main_ids) > 0: assert ( self._main_ids.dtype.kind in "uiSU" diff --git a/src/spikeinterface/core/zarrextractors.py b/src/spikeinterface/core/zarrextractors.py index 02ae5e9ecd..6cdc1c9fde 100644 --- a/src/spikeinterface/core/zarrextractors.py +++ b/src/spikeinterface/core/zarrextractors.py @@ -37,7 +37,7 @@ def super_zarr_open(folder_path: str | Path, mode: str = "r", storage_options: d Returns ------- - root: zarr.hierarchy.Group + root: zarr.Group The zarr root group object Raises @@ -313,7 +313,7 @@ def __init__(self, spikes_group, segment_slices: np.ndarray): self._sample_index = spikes_group["sample_index"] self._unit_index = spikes_group["unit_index"] self._segment_slices = np.asarray(segment_slices, dtype="int64") - self._n = len(self._sample_index) + self._n = self._sample_index.shape[0] self.dtype = np.dtype(minimum_spike_dtype) @property @@ -436,7 +436,7 @@ def __init__( spikes = ZarrSpikeVector(spikes_group, segment_slices_list) else: # Materialize the spike vector in memory and sort it by (segment_index, sample_index, unit_index) - spikes = np.zeros(len(spikes_group["sample_index"]), dtype=minimum_spike_dtype) + spikes = np.zeros(spikes_group["sample_index"].shape[0], dtype=minimum_spike_dtype) spikes["sample_index"] = spikes_group["sample_index"][:] spikes["unit_index"] = spikes_group["unit_index"][:] for i, (start, end) in enumerate(segment_slices_list): @@ -610,7 +610,7 @@ def get_default_zarr_compressor(clevel: int = 5): return Blosc(cname="zstd", clevel=clevel, shuffle=Blosc.BITSHUFFLE) -def add_properties_and_annotations(zarr_group: zarr.hierarchy.Group, recording_or_sorting: BaseRecording | BaseSorting): +def add_properties_and_annotations(zarr_group: zarr.Group, recording_or_sorting: BaseRecording | BaseSorting): # save properties prop_group = zarr_group.create_group("properties") for key in recording_or_sorting.get_property_keys(): @@ -624,7 +624,7 @@ def add_properties_and_annotations(zarr_group: zarr.hierarchy.Group, recording_o zarr_group.attrs["annotations"] = check_json(recording_or_sorting._annotations) -def add_sorting_to_zarr_group(sorting: BaseSorting, zarr_group: zarr.hierarchy.Group, **kwargs): +def add_sorting_to_zarr_group(sorting: BaseSorting, zarr_group: zarr.Group, **kwargs): """ Add a sorting extractor to a zarr group. @@ -632,7 +632,7 @@ def add_sorting_to_zarr_group(sorting: BaseSorting, zarr_group: zarr.hierarchy.G ---------- sorting : BaseSorting The sorting extractor object to be added to the zarr group - zarr_group : zarr.hierarchy.Group + zarr_group : zarr.Group The zarr group kwargs : dict Other arguments passed to the zarr compressor @@ -668,9 +668,7 @@ def add_sorting_to_zarr_group(sorting: BaseSorting, zarr_group: zarr.hierarchy.G # Recording -def add_recording_to_zarr_group( - recording: BaseRecording, zarr_group: zarr.hierarchy.Group, verbose=False, dtype=None, **kwargs -): +def add_recording_to_zarr_group(recording: BaseRecording, zarr_group: zarr.Group, verbose=False, dtype=None, **kwargs): zarr_kwargs, job_kwargs = split_job_kwargs(kwargs) if recording.check_serializability("json"): diff --git a/src/spikeinterface/extractors/nwbextractors.py b/src/spikeinterface/extractors/nwbextractors.py index fd45aa07c2..e6a30e9fb0 100644 --- a/src/spikeinterface/extractors/nwbextractors.py +++ b/src/spikeinterface/extractors/nwbextractors.py @@ -305,8 +305,9 @@ def _get_backend_from_local_file(file_path: str | Path) -> str: try: import zarr - with zarr.open(file_path, "r") as f: - backend = "zarr" + # `mode` is keyword-only in zarr v3, and its groups are not context managers + zarr.open(file_path, mode="r") + backend = "zarr" except: raise RuntimeError(f"{file_path} is not a valid Zarr folder!") else: