From 49d5a669f9939e7da5f30e5dc9a65983c1eb25f4 Mon Sep 17 00:00:00 2001 From: chrishalcrow Date: Mon, 4 May 2026 10:33:44 +0100 Subject: [PATCH 1/4] add install check for components sorters --- pyproject.toml | 21 +++++++++++++++++++ src/spikeinterface/sorters/internal/lupin.py | 14 +++++++++++++ .../sorters/internal/spyking_circus2.py | 14 +++++++++++++ .../sorters/internal/tridesclous2.py | 14 +++++++++++++ 4 files changed, 63 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d05daeec5d..e0fcc6c9e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -168,6 +168,26 @@ widgets = [ "distinctipy", ] +lupin = [ + "scipy", + "numba", + "scikit-learn", + "torch" +] + +spykingcircus2 = [ + "scipy", + "hdbscan", + "numba", +] + +tridesclous2= [ + "scipy", + "numba", + "scikit-learn", + "torch", +] + # `full` installs every module's optional feature deps. Defined as the union of # per-module extras so adding a dep to a module propagates here automatically. full = [ @@ -298,6 +318,7 @@ test-all = [ {include-group = "test-sortingcomponents"}, {include-group = "test-generation"}, ] +dev = [] [tool.pytest.ini_options] testpaths = ["src"] diff --git a/src/spikeinterface/sorters/internal/lupin.py b/src/spikeinterface/sorters/internal/lupin.py index 54c8ad5fcf..a2777151b3 100644 --- a/src/spikeinterface/sorters/internal/lupin.py +++ b/src/spikeinterface/sorters/internal/lupin.py @@ -102,8 +102,22 @@ class LupinSorter(ComponentsBasedSorter): "debug": "Save debug files", } + installation_mesg = "\tpip install 'spikeinterface[lupin]'\nOr, if you have cloned SpikeInterface locally, using:\n\tpip install '.[lupin]'" + handle_multi_segment = True + @classmethod + def is_installed(cls): + import importlib.util + + lupin_deps = ["scipy", "numba", "scikit-learn", "torch"] + + for package_name in lupin_deps: + if not importlib.util.find_spec(package_name): + return False + + return True + @classmethod def get_sorter_version(cls): return "2026.01" diff --git a/src/spikeinterface/sorters/internal/spyking_circus2.py b/src/spikeinterface/sorters/internal/spyking_circus2.py index b1cfcb0843..34eb29382b 100644 --- a/src/spikeinterface/sorters/internal/spyking_circus2.py +++ b/src/spikeinterface/sorters/internal/spyking_circus2.py @@ -86,6 +86,20 @@ class Spykingcircus2Sorter(ComponentsBasedSorter): In addition, it also uses a full Orthogonal Matching Pursuit engine to reconstruct the traces, leading to more spikes being discovered. The code is much faster and memory efficient, inheriting from all the preprocessing possibilities of spikeinterface""" + installation_mesg = "\tpip install 'spikeinterface[spykingcircus2]'\nOr, if you have cloned SpikeInterface locally, using:\n\tpip install '.[spykingcircus2]'" + + @classmethod + def is_installed(cls): + import importlib.util + + spykingcircus2_deps = ["scipy", "numba", "hbdscan"] + + for package_name in spykingcircus2_deps: + if not importlib.util.find_spec(package_name): + return False + + return True + @classmethod def get_sorter_version(cls): return "2025.12" diff --git a/src/spikeinterface/sorters/internal/tridesclous2.py b/src/spikeinterface/sorters/internal/tridesclous2.py index c042d8ee56..8dbf709e03 100644 --- a/src/spikeinterface/sorters/internal/tridesclous2.py +++ b/src/spikeinterface/sorters/internal/tridesclous2.py @@ -97,6 +97,20 @@ class Tridesclous2Sorter(ComponentsBasedSorter): handle_multi_segment = True + installation_mesg = "\tpip install 'spikeinterface[tridesclous2]'\nOr, if you have cloned SpikeInterface locally, using:\n\tpip install '.[tridesclous2]'" + + @classmethod + def is_installed(cls): + import importlib.util + + tridesclous2_deps = ["scipy", "numba", "hbdscan"] + + for package_name in tridesclous2_deps: + if not importlib.util.find_spec(package_name): + return False + + return True + @classmethod def get_sorter_version(cls): return "2026.01" From ab61abf135678f355211ca45f8be4aeb7615e5e8 Mon Sep 17 00:00:00 2001 From: chrishalcrow Date: Mon, 4 May 2026 11:05:52 +0100 Subject: [PATCH 2/4] include new packages for internal sorter tests --- pyproject.toml | 3 ++- src/spikeinterface/sorters/internal/spyking_circus2.py | 2 +- src/spikeinterface/sorters/internal/tridesclous2.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e0fcc6c9e3..54a6d525bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -281,6 +281,8 @@ test-sorters-internal = [ {include-group = "test-common"}, "torch", # spyking_circus2 template matching "hdbscan>=0.8.33", # simplesorter / tridesclous2 + "numba", # lupin / spykingcircus2 / tridesclous2 + "scikit-learn", # tridesclous2 ] test-sorters = [{include-group = "test-sorters-internal"}] test-curation = [{include-group = "test-common"}] @@ -318,7 +320,6 @@ test-all = [ {include-group = "test-sortingcomponents"}, {include-group = "test-generation"}, ] -dev = [] [tool.pytest.ini_options] testpaths = ["src"] diff --git a/src/spikeinterface/sorters/internal/spyking_circus2.py b/src/spikeinterface/sorters/internal/spyking_circus2.py index 34eb29382b..85e0da7220 100644 --- a/src/spikeinterface/sorters/internal/spyking_circus2.py +++ b/src/spikeinterface/sorters/internal/spyking_circus2.py @@ -92,7 +92,7 @@ class Spykingcircus2Sorter(ComponentsBasedSorter): def is_installed(cls): import importlib.util - spykingcircus2_deps = ["scipy", "numba", "hbdscan"] + spykingcircus2_deps = ["scipy", "numba", "hdbscan"] for package_name in spykingcircus2_deps: if not importlib.util.find_spec(package_name): diff --git a/src/spikeinterface/sorters/internal/tridesclous2.py b/src/spikeinterface/sorters/internal/tridesclous2.py index 8dbf709e03..23fa98b2cb 100644 --- a/src/spikeinterface/sorters/internal/tridesclous2.py +++ b/src/spikeinterface/sorters/internal/tridesclous2.py @@ -103,7 +103,7 @@ class Tridesclous2Sorter(ComponentsBasedSorter): def is_installed(cls): import importlib.util - tridesclous2_deps = ["scipy", "numba", "hbdscan"] + tridesclous2_deps = ["scipy", "numba", "hdbscan"] for package_name in tridesclous2_deps: if not importlib.util.find_spec(package_name): From 27df2312dc73560d440302f4521562b351973bf4 Mon Sep 17 00:00:00 2001 From: chrishalcrow Date: Mon, 4 May 2026 11:42:13 +0100 Subject: [PATCH 3/4] add scipy to internal sorters tests --- pyproject.toml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 878fb18d0d..912fba73e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -292,10 +292,11 @@ test-comparison = [ test-sorters-internal = [ {include-group = "test-common"}, - "torch", # spyking_circus2 template matching - "hdbscan>=0.8.33", # simplesorter / tridesclous2 - "numba", # lupin / spykingcircus2 / tridesclous2 - "scikit-learn", # tridesclous2 + "scipy", + "torch", + "hdbscan>=0.8.33", + "numba", + "scikit-learn", ] test-sorters = [{include-group = "test-sorters-internal"}] test-curation = [{include-group = "test-common"}] From 635c8eb2c2ccfa4f1296938f08c3517504ae5296 Mon Sep 17 00:00:00 2001 From: chrishalcrow Date: Mon, 4 May 2026 12:04:15 +0100 Subject: [PATCH 4/4] scikit-learn -> sklearn --- src/spikeinterface/sorters/internal/lupin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spikeinterface/sorters/internal/lupin.py b/src/spikeinterface/sorters/internal/lupin.py index a2777151b3..d21b4d3d50 100644 --- a/src/spikeinterface/sorters/internal/lupin.py +++ b/src/spikeinterface/sorters/internal/lupin.py @@ -110,7 +110,7 @@ class LupinSorter(ComponentsBasedSorter): def is_installed(cls): import importlib.util - lupin_deps = ["scipy", "numba", "scikit-learn", "torch"] + lupin_deps = ["scipy", "numba", "sklearn", "torch"] for package_name in lupin_deps: if not importlib.util.find_spec(package_name):