diff --git a/.github/scripts/serialization/objects.py b/.github/scripts/serialization/objects.py index f2f3469076..9544e4a8d9 100644 --- a/.github/scripts/serialization/objects.py +++ b/.github/scripts/serialization/objects.py @@ -140,7 +140,6 @@ def _check_recording_with_probe(rec, check_extra_data=None): def _build_recording_with_interleaved_probes(): - import numpy as np from probeinterface import ProbeGroup, generate_linear_probe from spikeinterface.core import generate_recording diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 0000000000..0860cd8fc9 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,23 @@ +name: Ruff Linting + +on: + pull_request: + types: [synchronize, opened, reopened] + branches: + - main + +concurrency: # Cancel previous workflows on the same pull request + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + run: + name: Ruff Linting + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/ruff-action@v3 + with: + args: check diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d35bc8cd3..157acbefda 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,8 +5,18 @@ repos: - id: check-yaml - id: end-of-file-fixer - id: trailing-whitespace -- repo: https://github.com/psf/black-pre-commit-mirror - rev: 26.10.1 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.15.0 hooks: - - id: black + - id: ruff-check + args: [--fix] + files: ^src/ + # occasional full lint including tests: pre-commit run ruff-check-tests --hook-stage manual --all-files + - id: ruff-check + alias: ruff-check-tests + name: ruff check (including tests) + args: [--fix, --config, "lint.exclude = []"] + files: ^src/ + stages: [manual] + - id: ruff-format files: ^src/ diff --git a/conftest.py b/conftest.py index 6c4bfbef3a..24a74fe1ec 100644 --- a/conftest.py +++ b/conftest.py @@ -56,7 +56,7 @@ def pytest_collection_modifyitems(config, items): try: rel_path = Path(item.fspath).relative_to(modules_location) - except: + except Exception: continue module = rel_path.parts[0] diff --git a/doc/development/development.rst b/doc/development/development.rst index 82b17e7a35..dba523b3c4 100644 --- a/doc/development/development.rst +++ b/doc/development/development.rst @@ -111,49 +111,65 @@ maintainability of the code, making it easier for contributors to collaborate. T for the developer we use the following tools and conventions: -Install Black and pre-commit -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Install ruff and pre-commit +^^^^^^^^^^^^^^^^^^^^^^^^^^^ -We use the Python formatter Black, with defaults set in the :code:`pyproject.toml`. This allows for -easy local formatting of code. +We use `ruff `_ both to format code and to lint it (catch errors such as +undefined names or unused variables). Its settings live in the :code:`[tool.ruff]` section of :code:`pyproject.toml`. +We use pre-commit to run ruff, and a few other checks, automatically before every commit. -To install Black, you can use pip, the Python package installer. Run the following command in your terminal: +You can install both with pip: .. code-block:: bash - pip install black + pip install ruff pre-commit -This will install Black into your current Python environment. +Then set up the pre-commit hooks for your local repository by running, from the repository root: -In addition to Black, we use pre-commit to manage a suite of code formatting. -Pre-commit helps to automate the process of running these tools (including Black) before every commit, -ensuring that all code is checked for style. +.. code-block:: bash + + pre-commit install -You can install pre-commit using pip as well: +Now, each time you make a commit, pre-commit will run :code:`ruff format` and :code:`ruff check --fix` on the changed files +under :code:`src/`. If the hooks make changes or find issues, the commit is stopped so you can review the changes, add them and commit again. + +You can also run ruff yourself at any time: .. code-block:: bash - pip install pre-commit + ruff format src # format the code + ruff check src # report lint errors + ruff check src --fix # report lint errors and apply the safe automatic fixes + +A few things to know about the lint configuration: +* Test files (:code:`tests/` folders, :code:`test_*.py` and :code:`conftest.py`) are excluded from linting. +* Unused imports (:code:`F401`) and unused variables (:code:`F841`) are reported but never removed automatically, + because they are sometimes needed: side-effect imports, re-exports, or function calls that read from a file. + Fix them by hand, or keep them and mark the line with :code:`# noqa: F401`. +* Pytest fixtures shared by several test modules belong in a :code:`conftest.py`, so pytest finds them without an import + (an import that ruff would see as unused). -Once pre-commit is installed, you can set up the pre-commit hooks for your local repository. -These hooks are scripts that pre-commit will run prior to each commit. To install the pre-commit hooks, -navigate to your local repository in your terminal and run the following command: +Since tests are not linted on every commit, it is worth checking them every now and then. A manual pre-commit hook lints +everything under :code:`src/`, tests included: .. code-block:: bash - pre-commit install + pre-commit run ruff-check-tests --hook-stage manual --all-files + +or, equivalently, with ruff directly: + +.. code-block:: bash -Now, each time you make a commit, pre-commit will automatically run Black and any other configured hooks. -If the hooks make changes or if there are any issues, the commit will be stopped, and you'll be able to review and add the changes. + ruff check src --config 'lint.exclude = []' -If you want Black to omit a line from formatting, you can add the following comment to the end of the line: +If you want ruff to leave a line unformatted, add the following comment to the end of the line: .. code-block:: python # fmt: skip -To ignore a block of code you must flank the code with two comments: +To leave a block of code unformatted, put these two comments around it: .. code-block:: python @@ -161,7 +177,7 @@ To ignore a block of code you must flank the code with two comments: code here # fmt: on -As described in the `black documentation `_. +To silence a single lint error on one line, add :code:`# noqa: ` (for example :code:`# noqa: F401`) to the end of that line. Docstring Conventions @@ -202,7 +218,7 @@ This allows users to quickly understand the type of data that should be input in There should be a space between each parameter and the colon following it. This is neccessary for using the `numpydoc validator `_. In the above example we demonstrate two other docstring conventions followed by SpikeInterface. First, that all string arguments should be presented -with double quotes. This is the same stylistic convention followed by Black and enforced by the pre-commit for the repo. Second, when a parameter is a +with double quotes. This is the same stylistic convention enforced by ruff format in the pre-commit for the repo. Second, when a parameter is a string with a limited number of values (e.g. :code:`mean` and :code:`median`), rather than give the type a value of :code:`str`, please list the possible strings so that the user knows what the options are. diff --git a/doc/images/make_comparison_figures.py b/doc/images/make_comparison_figures.py index cdf0c03f9f..be88e474b4 100644 --- a/doc/images/make_comparison_figures.py +++ b/doc/images/make_comparison_figures.py @@ -11,7 +11,6 @@ sys.path.append('../../examples/modules/comparison/') from generate_erroneous_sorting import generate_erroneous_sorting -import spikeinterface.extractors as se import spikeinterface.comparison as sc import spikeinterface.widgets as sw diff --git a/examples/forhowto/plot_extract_lfps.py b/examples/forhowto/plot_extract_lfps.py index 53c4c256c2..404af6edb6 100644 --- a/examples/forhowto/plot_extract_lfps.py +++ b/examples/forhowto/plot_extract_lfps.py @@ -44,12 +44,10 @@ import time import numpy as np import matplotlib.pyplot as plt -from pathlib import Path import pandas as pd import seaborn as sns import spikeinterface as si -import spikeinterface.extractors as se import spikeinterface.preprocessing as spre import spikeinterface.widgets as sw from spikeinterface.core import generate_ground_truth_recording diff --git a/examples/get_started/quickstart.py b/examples/get_started/quickstart.py index 75d5c8d63a..d53bb1d9ea 100644 --- a/examples/get_started/quickstart.py +++ b/examples/get_started/quickstart.py @@ -34,7 +34,6 @@ # The spikeinterface module by itself imports only the spikeinterface.core submodule # which is not useful for the end user -import spikeinterface # We need to import one by one different submodules separately (preferred). # There are several modules: @@ -50,9 +49,7 @@ import spikeinterface as si # import core only import spikeinterface.extractors as se -import spikeinterface.preprocessing as spre import spikeinterface.sorters as ss -import spikeinterface.postprocessing as spost import spikeinterface.metrics as sm import spikeinterface.comparison as sc import spikeinterface.exporters as sexp diff --git a/examples/how_to/auto_label_units.py b/examples/how_to/auto_label_units.py index b70d5e66b2..ac4fbf13dc 100644 --- a/examples/how_to/auto_label_units.py +++ b/examples/how_to/auto_label_units.py @@ -24,7 +24,6 @@ # 3. UnitRefine: pre-trained classifiers to label units as noise or SUA/MUA [Jain]_ # %% -import numpy as np import spikeinterface as si import spikeinterface.curation as sc diff --git a/examples/how_to/benchmark_with_hybrid_recordings.py b/examples/how_to/benchmark_with_hybrid_recordings.py index d983578797..ebac618421 100644 --- a/examples/how_to/benchmark_with_hybrid_recordings.py +++ b/examples/how_to/benchmark_with_hybrid_recordings.py @@ -32,7 +32,6 @@ import spikeinterface.generation as sgen import spikeinterface.widgets as sw -from spikeinterface.sortingcomponents.motion import estimate_motion import numpy as np import matplotlib.pyplot as plt diff --git a/examples/how_to/customize_a_plot.py b/examples/how_to/customize_a_plot.py index 5568534b52..23bff39d72 100644 --- a/examples/how_to/customize_a_plot.py +++ b/examples/how_to/customize_a_plot.py @@ -81,7 +81,6 @@ # Here's an example of making a unit summary plot. # + -import matplotlib.pyplot as plt fig, axs = plt.subplots(ncols=2, nrows=1) unit_id=8 diff --git a/examples/tutorials/comparison/plot_5_comparison_sorter_weaknesses.py b/examples/tutorials/comparison/plot_5_comparison_sorter_weaknesses.py index c588ee82cb..68480c6dc7 100644 --- a/examples/tutorials/comparison/plot_5_comparison_sorter_weaknesses.py +++ b/examples/tutorials/comparison/plot_5_comparison_sorter_weaknesses.py @@ -34,8 +34,6 @@ ############################################################################## # Import -import numpy as np -import pandas as pd import matplotlib.pyplot as plt from spikeinterface.comparison import compare_sorter_to_ground_truth diff --git a/examples/tutorials/core/plot_1_recording_extractor.py b/examples/tutorials/core/plot_1_recording_extractor.py index a3143161b2..a73ffa2716 100644 --- a/examples/tutorials/core/plot_1_recording_extractor.py +++ b/examples/tutorials/core/plot_1_recording_extractor.py @@ -14,7 +14,6 @@ """ -import matplotlib.pyplot as plt import numpy as np import spikeinterface.extractors as se diff --git a/examples/tutorials/core/plot_5_append_concatenate_segments.py b/examples/tutorials/core/plot_5_append_concatenate_segments.py index 5cb1cccb6f..29fb9147ca 100644 --- a/examples/tutorials/core/plot_5_append_concatenate_segments.py +++ b/examples/tutorials/core/plot_5_append_concatenate_segments.py @@ -22,11 +22,10 @@ Here is a short example. """ -import matplotlib.pyplot as plt import numpy as np -from spikeinterface import NumpyRecording, NumpySorting +from spikeinterface import NumpyRecording from spikeinterface import append_recordings, concatenate_recordings ############################################################################## diff --git a/examples/tutorials/curation/plot_1_automated_curation.py b/examples/tutorials/curation/plot_1_automated_curation.py index 97fc05bc6e..8826852cdc 100644 --- a/examples/tutorials/curation/plot_1_automated_curation.py +++ b/examples/tutorials/curation/plot_1_automated_curation.py @@ -193,7 +193,7 @@ def calculate_moving_avg(label_df, confidence_label, window_size): plt.figure(figsize=(6, 6)) plt.plot(p_agreement_sorted, p_agreement_moving_avg, label = 'Moving Average') plt.axhline(y=1/len(np.unique(predictions)), color='black', linestyle='--', label='Chance') -plt.xlabel('Confidence'); #plt.xlim(0.5, 1) +plt.xlabel('Confidence') #plt.xlim(0.5, 1) plt.ylabel('Proportion Agreement with Human Label'); plt.ylim(0, 1) plt.title('Agreement vs Confidence (Moving Average)') plt.legend(); plt.grid(True); plt.show() diff --git a/examples/tutorials/widgets/plot_3_waveforms_gallery.py b/examples/tutorials/widgets/plot_3_waveforms_gallery.py index 76041aab1a..94276a72e0 100644 --- a/examples/tutorials/widgets/plot_3_waveforms_gallery.py +++ b/examples/tutorials/widgets/plot_3_waveforms_gallery.py @@ -8,7 +8,6 @@ import matplotlib.pyplot as plt import spikeinterface as si -import spikeinterface.extractors as se import spikeinterface.widgets as sw ############################################################################## diff --git a/installation_tips/check_your_install.py b/installation_tips/check_your_install.py index caafe09e24..cf9ffe65fd 100644 --- a/installation_tips/check_your_install.py +++ b/installation_tips/check_your_install.py @@ -69,7 +69,7 @@ def open_sigui(): folder = f"./analyzer_with_{sorter_name}" analyzer = si.load_sorting_analyzer(folder) - win = run_mainwindow(analyzer, start_app=True) + _ = run_mainwindow(analyzer, start_app=True) def _clean(): diff --git a/pyproject.toml b/pyproject.toml index 4265be1622..e81fba5912 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,8 +51,20 @@ include = ["spikeinterface*"] namespaces = false exclude = ["spikeinterface.*.tests"] -[tool.black] +[tool.ruff] line-length = 120 +force-exclude = true +[tool.ruff.lint] +select = ['E4', 'E7', 'E9', 'F'] +exclude = ["**/tests/**", "**/test_*.py", "**/conftest.py", "examples/**", "doc/conf.py", "installation_tips/**"] +ignore = ['E741', 'E731', 'F821'] +# report but never auto-remove unused imports/variables: they may be side-effect imports, re-exports, or calls that advance state +unfixable = ['F401', 'F841'] +[tool.ruff.lint.per-file-ignores] +"**/__init__.py" = ['F401', 'F403'] +"src/spikeinterface/full.py" = ['F403'] +"src/spikeinterface/core/testing_tools.py" = ['E402', 'F403'] +"src/spikeinterface/extractors/extractor_classes.py" = ['F401', 'F403'] [project.urls] homepage = "https://github.com/SpikeInterface/spikeinterface" @@ -232,7 +244,7 @@ docs = [ dev = [ "spikeinterface[docs]", - "black", + "ruff", "pre-commit", ] @@ -342,7 +354,7 @@ test-all = [ # Tools for the pre-commit hooks. uv installs this group by default. dev = [ - "black", + "ruff", "pre-commit", ] diff --git a/src/spikeinterface/benchmark/benchmark_base.py b/src/spikeinterface/benchmark/benchmark_base.py index 47ec6a70cd..e301019699 100644 --- a/src/spikeinterface/benchmark/benchmark_base.py +++ b/src/spikeinterface/benchmark/benchmark_base.py @@ -8,8 +8,6 @@ from spikeinterface.core import SortingAnalyzer, ChannelSparsity, NumpySorting -from spikeinterface.core import SortingAnalyzer, NumpySorting -from spikeinterface.core.job_tools import fix_job_kwargs, split_job_kwargs from spikeinterface import load, create_sorting_analyzer, load_sorting_analyzer from spikeinterface.widgets import get_some_colors @@ -332,7 +330,6 @@ def run(self, case_keys=None, keep=True, verbose=False, **job_kwargs): job_keys = [] for key in case_keys: - result_folder = self.folder / "results" / self.key_to_str(key) sorter_folder = self.folder / "sorters" / self.key_to_str(key) @@ -443,9 +440,9 @@ def get_grouped_keys_mapping(self, levels_to_group_by=None, case_keys=None): keys_mapping = {key: [key] for key in case_keys} else: study_levels = self.levels - assert np.all( - [l in study_levels for l in levels_to_group_by] - ), f"levels_to_group_by must be in {study_levels}, got {levels_to_group_by}" + assert np.all([l in study_levels for l in levels_to_group_by]), ( + f"levels_to_group_by must be in {study_levels}, got {levels_to_group_by}" + ) keys_mapping = {} for key in case_keys: new_key = tuple(key[list(study_levels).index(level)] for level in levels_to_group_by) @@ -480,7 +477,6 @@ def compute_results(self, case_keys=None, verbose=False, **result_params): if case_keys is None: case_keys = list(self.cases.keys()) - job_keys = [] for key in case_keys: if verbose: print("### Compute result", key, "###") @@ -546,7 +542,7 @@ def compute_metrics(self, case_keys=None, metric_names=["snr", "firing_rate"], f qm_ext = sorting_analyzer.compute("quality_metrics", metric_names=metric_names, **job_kwargs) # TODO remove this metics CSV file!!!! - metrics = qm_ext.get_data() + # _ = qm_ext.get_data() # metrics.to_csv(filename, sep="\t", index=True) def get_metrics(self, key): @@ -609,7 +605,6 @@ def get_pairs_by_level(self, level): pairs = [] for key in self.cases.keys(): - case0 = list(key) case1 = list(key) case0[level_index] = possible_values[0] @@ -702,7 +697,6 @@ def load_folder(cls, folder): zarr_folder = folder / k if zarr_folder.exists(): - result[k] = Templates.from_zarr(zarr_folder) elif format == "sorting_analyzer": analyzer_folder = folder / k diff --git a/src/spikeinterface/benchmark/benchmark_clustering.py b/src/spikeinterface/benchmark/benchmark_clustering.py index 8b5b6de3b8..0af908ff20 100644 --- a/src/spikeinterface/benchmark/benchmark_clustering.py +++ b/src/spikeinterface/benchmark/benchmark_clustering.py @@ -1,20 +1,15 @@ from spikeinterface.sortingcomponents.clustering import find_clusters_from_peaks from spikeinterface.core import NumpySorting from spikeinterface.comparison import GroundTruthComparison -from spikeinterface.widgets import ( - plot_probe_map, - plot_agreement_matrix, -) import numpy as np -from spikeinterface.core.job_tools import fix_job_kwargs, split_job_kwargs +from spikeinterface.core.job_tools import fix_job_kwargs from .benchmark_base import Benchmark, BenchmarkStudy, MixinStudyUnitCount from spikeinterface.core.sortinganalyzer import create_sorting_analyzer class ClusteringBenchmark(Benchmark): - def __init__(self, recording, gt_sorting, params, indices, peaks, exhaustive_gt=True): self.recording = recording self.gt_sorting = gt_sorting @@ -238,7 +233,6 @@ def plot_error_metrics(self, metric="cosine", case_keys=None, figsize=(15, 5)): fig, axes = plt.subplots(ncols=len(case_keys), nrows=1, figsize=figsize, squeeze=False) for count, key in enumerate(case_keys): - result = self.get_result(key) scores = result["gt_comparison"].get_ordered_agreement_scores() @@ -279,7 +273,6 @@ def plot_metrics_vs_snr(self, metric="agreement", case_keys=None, figsize=(15, 5 fig = None for count, key in enumerate(case_keys): - result = self.get_result(key) scores = result["gt_comparison"].agreement_scores @@ -334,7 +327,6 @@ def plot_metrics_vs_depth_and_snr(self, metric="agreement", case_keys=None, figs fig, axes = plt.subplots(ncols=len(case_keys), nrows=1, figsize=figsize, squeeze=False) for count, key in enumerate(case_keys): - result = self.get_result(key) scores = result["gt_comparison"].agreement_scores diff --git a/src/spikeinterface/benchmark/benchmark_matching.py b/src/spikeinterface/benchmark/benchmark_matching.py index 8f28f18a73..c6d4ec4fa5 100644 --- a/src/spikeinterface/benchmark/benchmark_matching.py +++ b/src/spikeinterface/benchmark/benchmark_matching.py @@ -4,7 +4,6 @@ from spikeinterface.core import NumpySorting from spikeinterface.comparison import CollisionGTComparison, compare_sorter_to_ground_truth from spikeinterface.widgets import ( - plot_agreement_matrix, plot_comparison_collision_by_similarity, ) @@ -14,7 +13,6 @@ class MatchingBenchmark(Benchmark): - def __init__(self, recording, gt_sorting, params): self.recording = recording self.gt_sorting = gt_sorting diff --git a/src/spikeinterface/benchmark/benchmark_merging.py b/src/spikeinterface/benchmark/benchmark_merging.py index 5f16ce3cab..0b25d851fa 100644 --- a/src/spikeinterface/benchmark/benchmark_merging.py +++ b/src/spikeinterface/benchmark/benchmark_merging.py @@ -7,12 +7,10 @@ plot_crosscorrelograms, ) -import numpy as np from .benchmark_base import Benchmark, BenchmarkStudy class MergingBenchmark(Benchmark): - def __init__(self, recording, splitted_sorting, params, gt_sorting, splitted_cells=None): self.recording = recording self.splitted_sorting = splitted_sorting @@ -45,7 +43,6 @@ def compute_result(self, match_score=0.5, exhaustive_gt=True): class MergingStudy(BenchmarkStudy): - benchmark_class = MergingBenchmark def create_benchmark(self, key): diff --git a/src/spikeinterface/benchmark/benchmark_motion_estimation.py b/src/spikeinterface/benchmark/benchmark_motion_estimation.py index fabca60b2d..d42be84a88 100644 --- a/src/spikeinterface/benchmark/benchmark_motion_estimation.py +++ b/src/spikeinterface/benchmark/benchmark_motion_estimation.py @@ -1,6 +1,3 @@ -import json -from pathlib import Path -import pickle import time import numpy as np @@ -183,7 +180,6 @@ def plot_drift( case_keys = list(self.cases.keys()) for key in case_keys: - bench = self.benchmarks[key] fig = plt.figure(figsize=figsize) @@ -258,7 +254,6 @@ def plot_errors(self, case_keys=None, figsize=None, lim=None): case_keys = list(self.cases.keys()) for key in case_keys: - bench = self.benchmarks[key] label = self.cases[key]["label"] @@ -329,7 +324,6 @@ def plot_summary_errors(self, case_keys=None, show_legend=True, figsize=(15, 5)) colors = self.get_colors() for count, key in enumerate(case_keys): - bench = self.benchmarks[key] label = self.cases[key]["label"] @@ -357,7 +351,7 @@ def plot_summary_errors(self, case_keys=None, show_legend=True, figsize=(15, 5)) parts[k].set_color(c) axes[2].plot(motion.spatial_bins_um, depth_error, label=label, color=c) - ax0 = ax = axes[0] + ax = axes[0] ax.set_xlabel("Time [s]") ax.set_ylabel("Error [μm]") if show_legend: diff --git a/src/spikeinterface/benchmark/benchmark_motion_interpolation.py b/src/spikeinterface/benchmark/benchmark_motion_interpolation.py index c5e0143961..3e96013e7b 100644 --- a/src/spikeinterface/benchmark/benchmark_motion_interpolation.py +++ b/src/spikeinterface/benchmark/benchmark_motion_interpolation.py @@ -95,7 +95,6 @@ def compute_result(self, exhaustive_gt=True, merging_score=0.2): class MotionInterpolationStudy(BenchmarkStudy): - benchmark_class = MotionInterpolationBenchmark def create_benchmark(self, key): @@ -133,7 +132,6 @@ def plot_sorting_accuracy( if mode == "ordered_accuracy": if ax is None: - fig, ax = plt.subplots(figsize=figsize) else: fig = ax.figure diff --git a/src/spikeinterface/benchmark/benchmark_peak_detection.py b/src/spikeinterface/benchmark/benchmark_peak_detection.py index 4c84304a63..671080b0a7 100644 --- a/src/spikeinterface/benchmark/benchmark_peak_detection.py +++ b/src/spikeinterface/benchmark/benchmark_peak_detection.py @@ -17,7 +17,6 @@ class PeakDetectionBenchmark(Benchmark): - def __init__(self, recording, gt_sorting, params, gt_peaks, exhaustive_gt=True, delta_t_ms=0.2): self.recording = recording self.gt_sorting = gt_sorting @@ -233,9 +232,7 @@ def plot_mean_deltas(self, case_keys=None, figsize=(15, 5), ax=None): import matplotlib.pyplot as plt if ax is None: - fig, ax = plt.subplots(1, figsize=figsize) - else: - fig = ax.get_figure() + _, ax = plt.subplots(1, figsize=figsize) results = {} labels = [] @@ -283,7 +280,6 @@ def plot_template_similarities(self, case_keys=None, metric="l2", figsize=(15, 5 fig = ax.get_figure() for key in case_keys: - import sklearn.metrics gt_templates = self.get_result(key)["gt_templates"] @@ -292,7 +288,6 @@ def plot_template_similarities(self, case_keys=None, metric="l2", figsize=(15, 5 distances = np.zeros(num_templates) for i in range(num_templates): - a = gt_templates[i].flatten() b = found_templates[i].flatten() diff --git a/src/spikeinterface/benchmark/benchmark_peak_localization.py b/src/spikeinterface/benchmark/benchmark_peak_localization.py index f38e1de916..199df36930 100644 --- a/src/spikeinterface/benchmark/benchmark_peak_localization.py +++ b/src/spikeinterface/benchmark/benchmark_peak_localization.py @@ -9,7 +9,6 @@ class PeakLocalizationBenchmark(Benchmark): - def __init__(self, recording, gt_sorting, params, gt_positions, channel_from_template=False): self.recording = recording self.gt_sorting = gt_sorting @@ -69,7 +68,6 @@ def compute_result(self, **result_params): class PeakLocalizationStudy(BenchmarkStudy): - benchmark_class = PeakLocalizationBenchmark def create_benchmark(self, key): @@ -93,14 +91,12 @@ def plot_comparison_positions(self, case_keys=None): metrics = analyzer.get_extension("quality_metrics").get_data() snrs = metrics["snr"].values result = self.get_result(key) - norms = np.linalg.norm(result["templates"].templates_array, axis=(1, 2)) coordinates = self.benchmarks[key].gt_positions[:, :2].copy() coordinates[:, 0] -= coordinates[:, 0].mean() coordinates[:, 1] -= coordinates[:, 1].mean() distances_to_center = np.linalg.norm(coordinates, axis=1) zdx = np.argsort(distances_to_center) - idx = np.argsort(norms) wdx = np.argsort(snrs) @@ -152,7 +148,6 @@ def plot_comparison_positions(self, case_keys=None): class UnitLocalizationBenchmark(Benchmark): - def __init__(self, recording, gt_sorting, params, gt_positions): self.recording = recording self.gt_sorting = gt_sorting @@ -255,16 +250,12 @@ def plot_comparison_positions(self, case_keys=None): metrics = analyzer.get_extension("quality_metrics").get_data() snrs = metrics["snr"].values result = self.get_result(key) - norms = np.linalg.norm(result["templates"].templates_array, axis=(1, 2)) coordinates = self.benchmarks[key].gt_positions[:, :2].copy() coordinates[:, 0] -= coordinates[:, 0].mean() coordinates[:, 1] -= coordinates[:, 1].mean() distances_to_center = np.linalg.norm(coordinates, axis=1) zdx = np.argsort(distances_to_center) - idx = np.argsort(norms) - - from scipy.signal import savgol_filter wdx = np.argsort(snrs) diff --git a/src/spikeinterface/benchmark/benchmark_peak_selection.py b/src/spikeinterface/benchmark/benchmark_peak_selection.py index a18743f81b..a0b0c72c3d 100644 --- a/src/spikeinterface/benchmark/benchmark_peak_selection.py +++ b/src/spikeinterface/benchmark/benchmark_peak_selection.py @@ -1,16 +1,7 @@ -from spikeinterface.sortingcomponents.clustering import find_clusters_from_peaks -from spikeinterface.core import NumpySorting -from spikeinterface.comparison import GroundTruthComparison -from spikeinterface.comparison.comparisontools import make_matching_events -from spikeinterface.core import get_noise_levels - -import numpy as np - from .benchmark_base import Benchmark, BenchmarkStudy class PeakSelectionBenchmark(Benchmark): - def __init__(self, recording, gt_sorting, params, indices, exhaustive_gt=True): pass @@ -34,7 +25,6 @@ def compute_result(self, **result_params): class PeakSelectionStudy(BenchmarkStudy): - benchmark_class = PeakSelectionBenchmark def create_benchmark(self, key): diff --git a/src/spikeinterface/benchmark/benchmark_plot_tools.py b/src/spikeinterface/benchmark/benchmark_plot_tools.py index 7f0fc64cb4..530678da5b 100644 --- a/src/spikeinterface/benchmark/benchmark_plot_tools.py +++ b/src/spikeinterface/benchmark/benchmark_plot_tools.py @@ -1,7 +1,4 @@ -import warnings - import numpy as np -from spikeinterface.widgets import get_some_colors from .benchmark_tools import sigmoid, fit_sigmoid @@ -308,7 +305,7 @@ def plot_unit_counts( else: yerr = None - if not "well_detected" in col and revert_bad: + if "well_detected" not in col and revert_bad: y = -y if i == 0: @@ -455,7 +452,6 @@ def _plot_performances_vs_metric( fig = axs[0].get_figure() for count, performance_name in enumerate(performance_names): - ax = axs[count] if levels_to_group_by is not None: case_group_keys, labels = study.get_grouped_keys_mapping( @@ -467,9 +463,9 @@ def _plot_performances_vs_metric( colors = study.get_colors(levels_to_group_by=levels_to_group_by) - assert all( - [key in colors for key in case_group_keys] - ), f"colors must have a color for each case key: {case_group_keys}" + assert all([key in colors for key in case_group_keys]), ( + f"colors must have a color for each case key: {case_group_keys}" + ) for key, key_list in case_group_keys.items(): color = colors[key] @@ -827,9 +823,9 @@ def plot_performances_swarm( perfs = study.get_performance_by_unit(case_keys=case_keys) perfs, case_keys, _, _ = aggregate_dataframe_by_levels(perfs, study, case_keys, levels_to_group_by) - assert all( - [key in performance_colors for key in performance_names] - ), f"performance_colors must have a color for each performance name: {performance_names}" + assert all([key in performance_colors for key in performance_names]), ( + f"performance_colors must have a color for each performance name: {performance_names}" + ) if ax is None: fig, ax = plt.subplots(figsize=figsize) @@ -897,9 +893,9 @@ def plot_performances_comparison( num_methods = len(case_keys) assert num_methods >= 2, "plot_performances_comparison need at least 2 cases!" - assert all( - [key in performance_colors for key in performance_names] - ), f"performance_colors must have a color for each performance name: {performance_names}" + assert all([key in performance_colors for key in performance_names]), ( + f"performance_colors must have a color for each performance name: {performance_names}" + ) if axs is None: fig, axs = plt.subplots(ncols=num_methods - 1, nrows=num_methods - 1, figsize=figsize, squeeze=False) @@ -1081,7 +1077,6 @@ def plot_performance_losses( fig = axs[0].get_figure() for count, perf_name in enumerate(performance_names): - ax = axs[count] positions = study.get_gt_unit_locations(case0) diff --git a/src/spikeinterface/benchmark/benchmark_sorter.py b/src/spikeinterface/benchmark/benchmark_sorter.py index 932334f209..e22aafae28 100644 --- a/src/spikeinterface/benchmark/benchmark_sorter.py +++ b/src/spikeinterface/benchmark/benchmark_sorter.py @@ -2,7 +2,6 @@ This replace the previous `GroundTruthStudy` """ -import numpy as np from spikeinterface.core import NumpySorting, create_sorting_analyzer from .benchmark_base import Benchmark, BenchmarkStudy, MixinStudyUnitCount from spikeinterface.sorters import run_sorter diff --git a/src/spikeinterface/benchmark/benchmark_sorter_without_gt.py b/src/spikeinterface/benchmark/benchmark_sorter_without_gt.py index 818ed3f009..c9c26b0d29 100644 --- a/src/spikeinterface/benchmark/benchmark_sorter_without_gt.py +++ b/src/spikeinterface/benchmark/benchmark_sorter_without_gt.py @@ -4,7 +4,7 @@ import numpy as np from spikeinterface.core import NumpySorting, create_sorting_analyzer -from .benchmark_base import Benchmark, BenchmarkStudy, MixinStudyUnitCount +from .benchmark_base import Benchmark, BenchmarkStudy from spikeinterface.sorters import run_sorter from spikeinterface.comparison import compare_multiple_sorters @@ -107,7 +107,6 @@ def compute_results( groups = self._get_comparison_groups() for data_key, group in groups.items(): - sorting_list = [self.get_result(key)["sorting"] for key in group] name_list = [key for key in group] multi_comp = compare_multiple_sorters( diff --git a/src/spikeinterface/benchmark/tests/common_benchmark_testing.py b/src/spikeinterface/benchmark/tests/common_benchmark_testing.py index 49f9e9350a..7a77b40342 100644 --- a/src/spikeinterface/benchmark/tests/common_benchmark_testing.py +++ b/src/spikeinterface/benchmark/tests/common_benchmark_testing.py @@ -4,12 +4,9 @@ This only a local testing. """ -import pytest -from pathlib import Path import os from spikeinterface.core.job_tools import fix_job_kwargs -import numpy as np from spikeinterface.core import ( generate_ground_truth_recording, diff --git a/src/spikeinterface/benchmark/tests/test_benchmark_clustering.py b/src/spikeinterface/benchmark/tests/test_benchmark_clustering.py index 971c410807..01ba792fc7 100644 --- a/src/spikeinterface/benchmark/tests/test_benchmark_clustering.py +++ b/src/spikeinterface/benchmark/tests/test_benchmark_clustering.py @@ -26,7 +26,6 @@ def test_benchmark_clustering(create_cache_folder): peaks = {} for dataset, gt_analyzer in datasets.items(): - # recording, gt_sorting = datasets[dataset] # sorting_analyzer = create_sorting_analyzer(gt_sorting, recording, format="memory", sparse=False) diff --git a/src/spikeinterface/benchmark/tests/test_benchmark_merging.py b/src/spikeinterface/benchmark/tests/test_benchmark_merging.py index 022ba18ebd..e09faa10af 100644 --- a/src/spikeinterface/benchmark/tests/test_benchmark_merging.py +++ b/src/spikeinterface/benchmark/tests/test_benchmark_merging.py @@ -1,6 +1,5 @@ import pytest from pathlib import Path -import numpy as np import shutil diff --git a/src/spikeinterface/benchmark/tests/test_benchmark_peak_detection.py b/src/spikeinterface/benchmark/tests/test_benchmark_peak_detection.py index 462ede4375..95f48e9214 100644 --- a/src/spikeinterface/benchmark/tests/test_benchmark_peak_detection.py +++ b/src/spikeinterface/benchmark/tests/test_benchmark_peak_detection.py @@ -23,7 +23,6 @@ def test_benchmark_peak_detection(create_cache_folder): peaks = {} for dataset in datasets.keys(): - recording, gt_sorting = datasets[dataset] sorting_analyzer = create_sorting_analyzer(gt_sorting, recording, format="memory", sparse=False, **job_kwargs) diff --git a/src/spikeinterface/benchmark/tests/test_benchmark_peak_selection.py b/src/spikeinterface/benchmark/tests/test_benchmark_peak_selection.py index a6eb090a9d..d56529269b 100644 --- a/src/spikeinterface/benchmark/tests/test_benchmark_peak_selection.py +++ b/src/spikeinterface/benchmark/tests/test_benchmark_peak_selection.py @@ -5,7 +5,7 @@ @pytest.mark.skip() def test_benchmark_peak_selection(create_cache_folder): - cache_folder = create_cache_folder + pass if __name__ == "__main__": diff --git a/src/spikeinterface/benchmark/tests/test_benchmark_sorter.py b/src/spikeinterface/benchmark/tests/test_benchmark_sorter.py index f95edbaaf9..71e670f79b 100644 --- a/src/spikeinterface/benchmark/tests/test_benchmark_sorter.py +++ b/src/spikeinterface/benchmark/tests/test_benchmark_sorter.py @@ -65,7 +65,7 @@ def _create_simple_study(study_folder, cache_folder): }, } - study = SorterStudy.create( + _ = SorterStudy.create( study_folder, datasets=datasets, cases=cases, levels=["sorter_name", "processing", "probe_type"] ) # print(study) @@ -100,7 +100,7 @@ def _create_very_simple_study(study_folder, cache_folder): }, } - study = SorterStudy.create( + _ = SorterStudy.create( study_folder, datasets=datasets, cases=cases, levels=["sorter_name", "processing", "probe_type"] ) # print(study) @@ -245,7 +245,7 @@ def _create_complex_study(study_folder, cache_folder): }, } - study = SorterStudy.create( + _ = SorterStudy.create( study_folder, datasets=datasets, cases=cases, levels=["sorter_name", "processing", "probe_type"] ) @@ -266,13 +266,16 @@ def test_SorterStudy(create_simple_study): # this is from the base class rt = study.get_run_times() + assert rt is not None # rt = study.plot_run_times() # import matplotlib.pyplot as plt # plt.show() perf_by_unit = study.get_performance_by_unit() + assert perf_by_unit is not None # print(perf_by_unit) count_units = study.get_count_units() + assert count_units is not None # print(count_units) diff --git a/src/spikeinterface/benchmark/tests/test_benchmark_sorter_without_gt.py b/src/spikeinterface/benchmark/tests/test_benchmark_sorter_without_gt.py index 62492cbdbe..4055342a46 100644 --- a/src/spikeinterface/benchmark/tests/test_benchmark_sorter_without_gt.py +++ b/src/spikeinterface/benchmark/tests/test_benchmark_sorter_without_gt.py @@ -3,7 +3,6 @@ from pathlib import Path from spikeinterface import generate_ground_truth_recording -from spikeinterface.preprocessing import bandpass_filter from spikeinterface.benchmark import SorterStudyWithoutGroundTruth @@ -42,7 +41,7 @@ def _create_simple_study_no_gt(study_folder): }, } - study = SorterStudyWithoutGroundTruth.create(study_folder, datasets=datasets, cases=cases) + _ = SorterStudyWithoutGroundTruth.create(study_folder, datasets=datasets, cases=cases) # print(study) diff --git a/src/spikeinterface/benchmark/tests/test_residual_analysis.py b/src/spikeinterface/benchmark/tests/test_residual_analysis.py index 738e4ac3fe..4d01590681 100644 --- a/src/spikeinterface/benchmark/tests/test_residual_analysis.py +++ b/src/spikeinterface/benchmark/tests/test_residual_analysis.py @@ -1,6 +1,4 @@ -import shutil import pytest -from pathlib import Path from spikeinterface.benchmark.tests.common_benchmark_testing import make_dataset diff --git a/src/spikeinterface/comparison/basecomparison.py b/src/spikeinterface/comparison/basecomparison.py index 3b6dd47c5a..4202d31335 100644 --- a/src/spikeinterface/comparison/basecomparison.py +++ b/src/spikeinterface/comparison/basecomparison.py @@ -28,7 +28,6 @@ class BaseMultiComparison(BaseComparison): """ def __init__(self, object_list, name_list, match_score=0.5, chance_score=0.1, verbose=False, n_jobs=1): - import networkx as nx BaseComparison.__init__( self, @@ -187,7 +186,7 @@ def _clean_graph(self): if edge_to_remove[0] in nodes_duplicate: node_to_remove = edge_to_remove[0] else: - node_to_removed = edge_to_remove[1] + node_to_remove = edge_to_remove[1] if node_to_remove in sg.nodes: sg.remove_node(node_to_remove) print(f"Removed node: {node_to_remove}") diff --git a/src/spikeinterface/comparison/collision.py b/src/spikeinterface/comparison/collision.py index f6dfcc2e95..ce803b988e 100644 --- a/src/spikeinterface/comparison/collision.py +++ b/src/spikeinterface/comparison/collision.py @@ -1,5 +1,3 @@ -import importlib - from .paircomparisons import GroundTruthComparison from .comparisontools import make_collision_events @@ -161,7 +159,6 @@ def compute_all_pair_collision_bins(self): loop = tqdm(loop, desc="collision by bin") for c in loop: - score1 = labels_st1[unit_ids1[c]][seg_index][spike_indices1[c]] score2 = labels_st1[unit_ids2[c]][seg_index][spike_indices2[c]] diff --git a/src/spikeinterface/comparison/comparisontools.py b/src/spikeinterface/comparison/comparisontools.py index 4892014575..356976e47c 100644 --- a/src/spikeinterface/comparison/comparisontools.py +++ b/src/spikeinterface/comparison/comparisontools.py @@ -275,9 +275,9 @@ def make_match_count_matrix( num_segments_sorting1 = sorting1.get_num_segments() num_segments_sorting2 = sorting2.get_num_segments() - assert ( - num_segments_sorting1 == num_segments_sorting2 - ), "make_match_count_matrix : sorting1 and sorting2 must have the same segment number" + assert num_segments_sorting1 == num_segments_sorting2, ( + "make_match_count_matrix : sorting1 and sorting2 must have the same segment number" + ) # Segments should be matched one by one for segment_index in range(num_segments_sorting1): @@ -495,7 +495,6 @@ def make_best_match(agreement_scores, min_score) -> "tuple[pd.Series, pd.Series] best_match_21 : pd.Series """ - import pandas as pd unit1_ids = np.array(agreement_scores.index) unit2_ids = np.array(agreement_scores.columns) @@ -539,7 +538,6 @@ def make_hungarian_match(agreement_scores, min_score): hungarian_match_21 : pd.Series """ - import pandas as pd unit1_ids = np.array(agreement_scores.index) unit2_ids = np.array(agreement_scores.columns) @@ -913,7 +911,6 @@ def make_matching_events(times1, times2, delta): mask2 = membership_sorted[inds] == 2 inds2 = inds[mask2] - n2 = np.sum(mask2) matching_event[n1:]["index1"] = spike_index_sorted[inds2 + 1] matching_event[n1:]["index2"] = spike_index_sorted[inds2] matching_event[n1:]["delta_frame"] = times_concat_sorted[inds2] - times_concat_sorted[inds2 + 1] @@ -1328,9 +1325,9 @@ def compute_distance_matrix( num_segments_sorting1 = sorting1.get_num_segments() num_segments_sorting2 = sorting2.get_num_segments() - assert ( - num_segments_sorting1 == num_segments_sorting2 - ), "make_match_count_matrix : sorting1 and sorting2 must have the same number of segments" + assert num_segments_sorting1 == num_segments_sorting2, ( + "make_match_count_matrix : sorting1 and sorting2 must have the same number of segments" + ) squared_norm_1_vector = _compute_spike_vector_squared_norm(spike_vector_per_segment1, num_units1, delta_frames) squared_norm_2_vector = _compute_spike_vector_squared_norm(spike_vector_per_segment2, num_units2, delta_frames) @@ -1401,9 +1398,9 @@ def calculate_generalized_comparison_metrics( num_segments_sorting1 = sorting1.get_num_segments() num_segments_sorting2 = sorting2.get_num_segments() - assert ( - num_segments_sorting1 == num_segments_sorting2 - ), "make_match_count_matrix : sorting1 and sorting2 must have the same number of segments" + assert num_segments_sorting1 == num_segments_sorting2, ( + "make_match_count_matrix : sorting1 and sorting2 must have the same number of segments" + ) squared_norm1 = _compute_spike_vector_squared_norm(spike_vector1_segments, num_units2, delta_frames) squared_norm2 = _compute_spike_vector_squared_norm(spike_vector2_segments, num_units2, delta_frames) diff --git a/src/spikeinterface/comparison/multicomparisons.py b/src/spikeinterface/comparison/multicomparisons.py index a0feda4a52..e3740c7e36 100644 --- a/src/spikeinterface/comparison/multicomparisons.py +++ b/src/spikeinterface/comparison/multicomparisons.py @@ -1,11 +1,6 @@ -from pathlib import Path -import json -import pickle -import warnings - import numpy as np -from spikeinterface.core import load, BaseSorting, BaseSortingSegment +from spikeinterface.core import BaseSorting, BaseSortingSegment from spikeinterface.core.core_tools import define_function_from_class from .basecomparison import BaseMultiComparison, MixinSpikeTrainComparison, MixinTemplateComparison from .paircomparisons import SymmetricSortingComparison, TemplateComparison diff --git a/src/spikeinterface/comparison/paircomparisons.py b/src/spikeinterface/comparison/paircomparisons.py index 47e85a03de..be05ca5d8a 100644 --- a/src/spikeinterface/comparison/paircomparisons.py +++ b/src/spikeinterface/comparison/paircomparisons.py @@ -39,7 +39,7 @@ def __init__( if sorting2_name is None: sorting2_name = "sorting2" assert sorting1.get_num_segments() == sorting2.get_num_segments(), ( - "The two sortings must have the same " "number of segments! " + "The two sortings must have the same number of segments! " ) BasePairComparison.__init__( @@ -100,7 +100,6 @@ def _do_agreement(self): self.match_event_count, self.event_counts1, self.event_counts2 ) elif self.agreement_method == "distance": - self.agreement_scores = calculate_agreement_scores_with_distance( self.sorting1, self.sorting2, @@ -294,7 +293,6 @@ def __init__( compute_misclassifications: bool = False, verbose: bool = False, ): - import pandas as pd if gt_name is None: gt_name = "ground truth" diff --git a/src/spikeinterface/comparison/tests/test_comparisontools.py b/src/spikeinterface/comparison/tests/test_comparisontools.py index 43288415d1..a32bef49ae 100644 --- a/src/spikeinterface/comparison/tests/test_comparisontools.py +++ b/src/spikeinterface/comparison/tests/test_comparisontools.py @@ -80,7 +80,10 @@ def test_make_match_count_matrix_with_mismatched_sortings(): delta_frames = 10 sorting1, sorting2 = make_sorting( - [100, 200, 300, 400], [0, 0, 1, 0], [500, 600, 700, 800], [0, 0, 1, 0] # Completely different spike times + [100, 200, 300, 400], + [0, 0, 1, 0], + [500, 600, 700, 800], + [0, 0, 1, 0], # Completely different spike times ) match_event_count = make_match_count_matrix(sorting1, sorting2, delta_frames) diff --git a/src/spikeinterface/comparison/tests/test_groundtruthcomparison.py b/src/spikeinterface/comparison/tests/test_groundtruthcomparison.py index 27b8f73077..34fe86c1f8 100644 --- a/src/spikeinterface/comparison/tests/test_groundtruthcomparison.py +++ b/src/spikeinterface/comparison/tests/test_groundtruthcomparison.py @@ -1,4 +1,3 @@ -import numpy as np from numpy.testing import assert_array_equal @@ -111,6 +110,7 @@ def test_compare_sorter_to_ground_truth(): bad_ids = sc.get_bad_units() assert_array_equal(bad_ids, [6, 11]) num_bad = sc.count_bad_units() + assert num_bad == 2 # bad units is union of false_positive_units + redundant_units fpu_ids = sc.get_false_positive_units() diff --git a/src/spikeinterface/comparison/tests/test_multisortingcomparison.py b/src/spikeinterface/comparison/tests/test_multisortingcomparison.py index 72f39f74ea..64f4efdc1d 100644 --- a/src/spikeinterface/comparison/tests/test_multisortingcomparison.py +++ b/src/spikeinterface/comparison/tests/test_multisortingcomparison.py @@ -8,7 +8,7 @@ from spikeinterface.core import generate_sorting from spikeinterface.core.job_tools import get_usable_cpu_count from spikeinterface.extractors import NumpySorting -from spikeinterface.comparison import compare_multiple_sorters, MultiSortingComparison +from spikeinterface.comparison import compare_multiple_sorters ON_GITHUB = bool(os.getenv("GITHUB_ACTIONS")) diff --git a/src/spikeinterface/comparison/tests/test_templatecomparison.py b/src/spikeinterface/comparison/tests/test_templatecomparison.py index 001f80f4f6..6879629e6d 100644 --- a/src/spikeinterface/comparison/tests/test_templatecomparison.py +++ b/src/spikeinterface/comparison/tests/test_templatecomparison.py @@ -1,5 +1,3 @@ -import shutil -import pytest import numpy as np from spikeinterface.core import create_sorting_analyzer, generate_ground_truth_recording diff --git a/src/spikeinterface/core/analyzer_extension_core.py b/src/spikeinterface/core/analyzer_extension_core.py index 070176244f..8159c18160 100644 --- a/src/spikeinterface/core/analyzer_extension_core.py +++ b/src/spikeinterface/core/analyzer_extension_core.py @@ -181,7 +181,6 @@ def _run(self, verbose=False, **job_kwargs): self.data.clear() recording = self.sorting_analyzer.recording - sorting = self.sorting_analyzer.sorting # retrieve spike vector and the sampling some_spikes = self.sorting_analyzer.get_extension("random_spikes").get_random_spikes() @@ -252,8 +251,6 @@ def _select_units_extension_data(self, unit_ids): some_spikes = self.sorting_analyzer.get_extension("random_spikes").get_random_spikes() keep_unit_indices = self.sorting_analyzer.sorting.ids_to_indices(unit_ids) - spikes = self.sorting_analyzer.sorting.to_spike_vector() - # some_spikes = spikes[random_spikes_indices] keep_spike_mask = np.isin(some_spikes["unit_index"], keep_unit_indices) new_data = dict() @@ -529,9 +526,9 @@ def _compute_and_append_from_waveforms(self, operators): # spikes = self.sorting_analyzer.sorting.to_spike_vector() # some_spikes = spikes[self.sorting_analyzer.random_spikes_indices] - assert self.sorting_analyzer.has_extension( - "random_spikes" - ), "compute 'templates' requires the random_spikes extension. You can run sorting_analyzer.compute('random_spikes')" + assert self.sorting_analyzer.has_extension("random_spikes"), ( + "compute 'templates' requires the random_spikes extension. You can run sorting_analyzer.compute('random_spikes')" + ) some_spikes = self.sorting_analyzer.get_extension("random_spikes").get_random_spikes() for unit_index, unit_id in enumerate(unit_ids): spike_mask = some_spikes["unit_index"] == unit_index @@ -1359,7 +1356,6 @@ def _run(self, **job_kwargs): # Check if we need to propagate any old metrics. If so, we'll do that. # Otherwise, we'll avoid attempting to load an empty metrics. if set(self.params["metrics_to_compute"]) != set(self.params["metric_names"]): - extension = self.sorting_analyzer.get_extension(self.extension_name) if delete_existing_metrics is False and extension is not None and extension.data.get("metrics") is not None: existing_metrics = extension.params["metric_names"] @@ -1451,7 +1447,6 @@ def _merge_extension_data( dict Dictionary containing the merged metrics DataFrame. """ - import pandas as pd available_metric_names = self.get_available_metric_names() metric_names = [m for m in self.params["metric_names"] if m in available_metric_names] @@ -1497,7 +1492,6 @@ def _split_extension_data( verbose : bool, default: False Whether to print verbose output. """ - import pandas as pd from itertools import chain available_metric_names = [m.metric_name for m in self.metric_list] @@ -1524,7 +1518,6 @@ def _split_extension_data( return new_data def set_data(self, ext_data_name, data): - import pandas as pd if ext_data_name == "metrics": metrics = self._cast_metrics(data) @@ -1629,9 +1622,9 @@ def _get_data(self, outputs="numpy", concatenated=False, return_data_name=None, if return_data_name is None: return_data_name = self.nodepipeline_variables[0] else: - assert ( - return_data_name in self.nodepipeline_variables - ), f"return_data_name {return_data_name} not in nodepipeline_variables {self.nodepipeline_variables}" + assert return_data_name in self.nodepipeline_variables, ( + f"return_data_name {return_data_name} not in nodepipeline_variables {self.nodepipeline_variables}" + ) all_data = self.data[return_data_name] # data gathered directly into a zarr store (e.g. by the node pipeline) is kept as a @@ -1799,12 +1792,10 @@ def _select_channels_sparse_data(old_sorting_analyzer, old_data, new_channel_ids new_data = np.zeros_like(old_data) max_num_active_channels = 0 for data_index, (one_old_data, unit_index) in enumerate(zip(old_data, random_spikes["unit_index"])): - unit_id = unit_ids[unit_index] channel_slice = unit_sparsity_slices[unit_id] if len(channel_slice) > 0: - size_of_new_mask = len(channel_slice) new_data[data_index, :, :size_of_new_mask] = one_old_data[:, channel_slice] diff --git a/src/spikeinterface/core/base.py b/src/spikeinterface/core/base.py index dbecd82bbe..eae31791a3 100644 --- a/src/spikeinterface/core/base.py +++ b/src/spikeinterface/core/base.py @@ -1,5 +1,4 @@ from pathlib import Path -import shutil from typing import Any from collections.abc import Iterable, Sequence import importlib @@ -7,26 +6,19 @@ import weakref import json import pickle -import random -import string from packaging.version import parse from copy import deepcopy import numpy as np -from .globals import get_global_tmp_folder, is_set_global_tmp_folder from .core_tools import ( - clean_zarr_folder_name, is_dict_extractor, SIJsonEncoder, - is_path_remote, make_paths_relative, make_paths_absolute, check_paths_relative, retrieve_importing_provenance, - load_properties_from_folder, ) -from .job_tools import _shared_job_kwargs_doc # base dtypes used throughout spikeinterface base_peak_dtype = [ @@ -87,9 +79,9 @@ def __init__(self, main_ids: Sequence) -> None: # 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" - ), f"Main IDs can only be integers (signed/unsigned) or strings, not {self._main_ids.dtype}" + assert self._main_ids.dtype.kind in "uiSU", ( + f"Main IDs can only be integers (signed/unsigned) or strings, not {self._main_ids.dtype}" + ) self._segments: "list[BaseSegment]" = [] @@ -117,7 +109,7 @@ def _get_common_repr_html(self, common_style): html_annotations = f"
Annotations
    " for key, value in self._annotations.items(): html_annotations += f"
  • {key} : {value}
  • " - html_annotations += f"
" + html_annotations += "" html_properties = f"
Properties
    " for key, value in self._properties.items(): @@ -337,9 +329,9 @@ def set_property( dtype_kind = dtype.kind if ids is None: - assert ( - values.shape[0] == size - ), f"Values must have the same size as the main ids: {size} but got array of size {values.shape[0]}" + assert values.shape[0] == size, ( + f"Values must have the same size as the main ids: {size} but got array of size {values.shape[0]}" + ) self._properties[key] = values else: ids = np.array(ids) @@ -351,7 +343,6 @@ def set_property( # Sam: this is used because you could set all ids (like the None) but with the vector. if ids.size < size: if key not in self._properties: - if missing_value is None: if dtype_kind not in self.default_missing_property_values.keys(): raise ValueError( @@ -386,9 +377,9 @@ def set_property( return else: existing_property = self._properties[key].dtype - assert ( - dtype_kind == existing_property.kind - ), f"Mismatch between existing property dtype {existing_property.kind} and provided values dtype {dtype_kind}." + assert dtype_kind == existing_property.kind, ( + f"Mismatch between existing property dtype {existing_property.kind} and provided values dtype {dtype_kind}." + ) indices = self.ids_to_indices(ids) if dtype_kind == "U": @@ -690,7 +681,7 @@ def _get_file_path(file_path: str | Path, extensions: Sequence) -> Path: folder_path = file_path.parent if Path(file_path).suffix == "": file_path = folder_path / (str(file_path) + ext) - assert file_path.suffix in extensions, "'file_path' should have one of the following extensions:" " %s" % ( + assert file_path.suffix in extensions, "'file_path' should have one of the following extensions: %s" % ( ", ".join(extensions) ) return file_path @@ -964,7 +955,7 @@ def _get_class_from_string(class_string): try: imported_class = getattr(imported_module, class_name) - except: + except Exception: imported_class = None return imported_class diff --git a/src/spikeinterface/core/baseevent.py b/src/spikeinterface/core/baseevent.py index 2e73774c04..78e542705f 100644 --- a/src/spikeinterface/core/baseevent.py +++ b/src/spikeinterface/core/baseevent.py @@ -26,16 +26,16 @@ def __init__(self, channel_ids, structured_dtype): if not isinstance(structured_dtype, dict): structured_dtype = {chan_id: structured_dtype for chan_id in channel_ids} else: - assert all( - chan_id in structured_dtype for chan_id in channel_ids - ), "Missing some channel_ids from structured_dtype dict keys" + assert all(chan_id in structured_dtype for chan_id in channel_ids), ( + "Missing some channel_ids from structured_dtype dict keys" + ) # check dtype fields (if present) for _, dtype in structured_dtype.items(): if dtype.names is not None: - assert ( - "time" in dtype.names or "timestamp" in dtype.names - ), "The event dtype need to have the 'time' or 'timestamp' field" + assert "time" in dtype.names or "timestamp" in dtype.names, ( + "The event dtype need to have the 'time' or 'timestamp' field" + ) self.structured_dtype = structured_dtype diff --git a/src/spikeinterface/core/baserecording.py b/src/spikeinterface/core/baserecording.py index c4f689e9c6..76167ea792 100644 --- a/src/spikeinterface/core/baserecording.py +++ b/src/spikeinterface/core/baserecording.py @@ -7,7 +7,6 @@ from .base import BaseExtractor from .time_series import TimeSeriesSegment, TimeSeries -from .base import BaseExtractor from .core_tools import convert_bytes_to_str, convert_seconds_to_str from .job_tools import split_job_kwargs from .recording_tools import _set_group_property_based_on_probegroup, check_probe_do_not_overlap @@ -111,7 +110,7 @@ def _repr_header(self, display_name=True): sampling_frequency_repr = f"{sf_hz:f} Hz" else: # Khz for high sampling rate and Hz for LFP - sampling_frequency_repr = f"{(sf_hz/1000.0):0.1f}kHz" if sf_hz > 10_000.0 else f"{sf_hz:0.1f}Hz" + sampling_frequency_repr = f"{(sf_hz / 1000.0):0.1f}kHz" if sf_hz > 10_000.0 else f"{sf_hz:0.1f}Hz" if display_name and self.name != self.__class__.__name__: name = f"{self.name} ({self.__class__.__name__})" @@ -591,9 +590,9 @@ def _get_probegroup_based_on_device_channel_indices(self, probegroup: ProbeGroup if not isinstance(probegroup, ProbeGroup): raise ValueError("The input must be a ProbeGroup or dict") - assert all( - probe.device_channel_indices is not None for probe in probegroup.probes - ), "Probe must have device_channel_indices" + assert all(probe.device_channel_indices is not None for probe in probegroup.probes), ( + "Probe must have device_channel_indices" + ) # Remove unconnected contacts and slice the probe group accordingly device_channel_indices = probegroup.get_global_device_channel_indices()["device_channel_indices"] @@ -1100,7 +1099,7 @@ def rename_channels(self, new_channel_ids: list | np.ndarray | tuple) -> "BaseRe from .channelslice import ChannelSliceRecording assert len(new_channel_ids) == self.get_num_channels(), ( - "new_channel_ids must have the same length as the " "number of channels in the recording" + "new_channel_ids must have the same length as the number of channels in the recording" ) return ChannelSliceRecording(self, renamed_channel_ids=new_channel_ids) @@ -1144,9 +1143,9 @@ def time_slice(self, start_time: float | None, end_time: float | None) -> "BaseR A new recording object with only samples between start_time and end_time """ num_segments = self.get_num_segments() - assert ( - num_segments == 1 - ), f"Time slicing is only supported for single segment recordings. Found {num_segments} segments." + assert num_segments == 1, ( + f"Time slicing is only supported for single segment recordings. Found {num_segments} segments." + ) t_start = self.get_start_time() t_end = self.get_end_time() diff --git a/src/spikeinterface/core/basesorting.py b/src/spikeinterface/core/basesorting.py index eb59420139..23a2aa4361 100644 --- a/src/spikeinterface/core/basesorting.py +++ b/src/spikeinterface/core/basesorting.py @@ -4,7 +4,6 @@ import numpy as np -from pathlib import Path from .base import BaseExtractor, BaseSegment, minimum_spike_dtype from .waveform_tools import has_exceeding_spikes @@ -112,9 +111,9 @@ def get_num_samples(self, segment_index=None) -> int: int The number of samples """ - assert ( - self.has_recording() - ), "This methods requires an associated recording. Call self.register_recording() first." + assert self.has_recording(), ( + "This methods requires an associated recording. Call self.register_recording() first." + ) return self._recording.get_num_samples(segment_index=segment_index) def get_total_samples(self) -> int: @@ -138,9 +137,9 @@ def get_total_duration(self) -> float: float The duration in seconds """ - assert ( - self.has_recording() - ), "This methods requires an associated recording. Call self.register_recording() first." + assert self.has_recording(), ( + "This methods requires an associated recording. Call self.register_recording() first." + ) return self._recording.get_total_duration() def search_cached_spikes_sorted( @@ -309,7 +308,6 @@ def get_unit_spike_train_in_seconds( # If sorting has a registered recording, get the frames and get the times from the recording # Note that this take into account the segment start time of the recording if self.has_recording(): - # Get all the spike times and then slice them start_frame = None end_frame = None @@ -378,12 +376,12 @@ def register_recording(self, recording, check_spike_frames: bool = True): check_spike_frames : bool, default: True If True, assert for each segment that all spikes are within the recording's range. """ - assert np.isclose( - self.get_sampling_frequency(), recording.get_sampling_frequency(), atol=0.1 - ), "The recording has a different sampling frequency than the sorting!" - assert ( - self.get_num_segments() == recording.get_num_segments() - ), "The recording has a different number of segments than the sorting!" + assert np.isclose(self.get_sampling_frequency(), recording.get_sampling_frequency(), atol=0.1), ( + "The recording has a different sampling frequency than the sorting!" + ) + assert self.get_num_segments() == recording.get_num_segments(), ( + "The recording has a different number of segments than the sorting!" + ) if check_spike_frames: if has_exceeding_spikes(self, recording): warnings.warn( diff --git a/src/spikeinterface/core/binaryfolder.py b/src/spikeinterface/core/binaryfolder.py index 0dc8eaa1a8..65fe6e153b 100644 --- a/src/spikeinterface/core/binaryfolder.py +++ b/src/spikeinterface/core/binaryfolder.py @@ -1,7 +1,6 @@ from pathlib import Path import json -from copy import deepcopy import shutil import numpy as np @@ -191,7 +190,7 @@ def write_recording( # All properties, annotations, and probe information are already saved in the folder, # so we don't need to include them in the si_folder.json cached = BinaryFolderRecording(folder_path=folder_path) - si_folder_path = folder_path / f"si_folder.json" + si_folder_path = folder_path / "si_folder.json" cached.dump_to_json( file_path=si_folder_path, relative_to=folder_path, diff --git a/src/spikeinterface/core/binaryrecordingextractor.py b/src/spikeinterface/core/binaryrecordingextractor.py index cd1fa88940..cdbf722e90 100644 --- a/src/spikeinterface/core/binaryrecordingextractor.py +++ b/src/spikeinterface/core/binaryrecordingextractor.py @@ -285,7 +285,7 @@ def __del__(self): try: self._time_vector._mmap.close() # Close the underlying mmap object del self._time_vector - except Exception as e: + except Exception: pass diff --git a/src/spikeinterface/core/channelsaggregationrecording.py b/src/spikeinterface/core/channelsaggregationrecording.py index ae7309d1ab..6af28adeed 100644 --- a/src/spikeinterface/core/channelsaggregationrecording.py +++ b/src/spikeinterface/core/channelsaggregationrecording.py @@ -1,5 +1,3 @@ -import warnings - import numpy as np from probeinterface import ProbeGroup @@ -52,12 +50,11 @@ def __init__(self, recording_list_or_dict=None, renamed_channel_ids=None): # Generate a default list of channel ids that are unique and consecutive numbers as strings. num_all_channels = sum(rec.get_num_channels() for rec in recording_list) if renamed_channel_ids is not None: - assert ( - len(np.unique(renamed_channel_ids)) == num_all_channels - ), "'renamed_channel_ids' doesn't have the right size or has duplicates!" + assert len(np.unique(renamed_channel_ids)) == num_all_channels, ( + "'renamed_channel_ids' doesn't have the right size or has duplicates!" + ) channel_ids = list(renamed_channel_ids) else: - # Explicitly check if all channel_ids arrays are either all integers or all strings. all_ids_are_int_dtype = all(np.issubdtype(rec.channel_ids.dtype, np.integer) for rec in recording_list) all_ids_are_str_dtype = all(np.issubdtype(rec.channel_ids.dtype, np.str_) for rec in recording_list) @@ -89,7 +86,7 @@ def __init__(self, recording_list_or_dict=None, renamed_channel_ids=None): property_dict[prop_name] = np.concatenate( (property_dict[prop_name], rec.get_property(prop_name)) ) - except Exception as e: + except Exception: print(f"Skipping property '{prop_name}' for shape inconsistency") del property_dict[prop_name] break @@ -214,7 +211,7 @@ def __init__(self, channel_map, parent_segments): else: for ps in parent_segments: assert ps.get_times_kwargs()["t_start"] == times_kargs0["t_start"], ( - "All segments should have the same " "t_start" + "All segments should have the same t_start" ) BaseRecordingSegment.__init__(self, **times_kargs0) diff --git a/src/spikeinterface/core/channelslice.py b/src/spikeinterface/core/channelslice.py index 13cac8db8d..e1af49a3c2 100644 --- a/src/spikeinterface/core/channelslice.py +++ b/src/spikeinterface/core/channelslice.py @@ -17,9 +17,9 @@ def __init__(self, recording, channel_ids=None, renamed_channel_ids=None): if renamed_channel_ids is None: renamed_channel_ids = channel_ids else: - assert len(renamed_channel_ids) == len( - np.unique(renamed_channel_ids) - ), "renamed_channel_ids must be unique!" + assert len(renamed_channel_ids) == len(np.unique(renamed_channel_ids)), ( + "renamed_channel_ids must be unique!" + ) self._channel_ids = np.asarray(channel_ids) self._renamed_channel_ids = np.asarray(renamed_channel_ids) @@ -29,16 +29,16 @@ def __init__(self, recording, channel_ids=None, renamed_channel_ids=None): # some checks # We use lists to compare numpy scalar types as their python versions (e.g. int vs int64()) channel_ids_not_in_parents = [id for id in self._channel_ids.tolist() if id not in parents_chan_ids.tolist()] - assert ( - len(channel_ids_not_in_parents) == 0 - ), f"ChannelSliceRecording : channel ids {channel_ids_not_in_parents} are not all in parent ids {parents_chan_ids}" - - assert len(self._channel_ids) == len( - self._renamed_channel_ids - ), "ChannelSliceRecording: renamed channel_ids must be the same size" - assert ( - self._channel_ids.size == np.unique(self._channel_ids).size - ), "ChannelSliceRecording : channel_ids are not unique" + assert len(channel_ids_not_in_parents) == 0, ( + f"ChannelSliceRecording : channel ids {channel_ids_not_in_parents} are not all in parent ids {parents_chan_ids}" + ) + + assert len(self._channel_ids) == len(self._renamed_channel_ids), ( + "ChannelSliceRecording: renamed channel_ids must be the same size" + ) + assert self._channel_ids.size == np.unique(self._channel_ids).size, ( + "ChannelSliceRecording : channel_ids are not unique" + ) sampling_frequency = recording.get_sampling_frequency() diff --git a/src/spikeinterface/core/core_tools.py b/src/spikeinterface/core/core_tools.py index 81678308fd..de551ddadd 100644 --- a/src/spikeinterface/core/core_tools.py +++ b/src/spikeinterface/core/core_tools.py @@ -502,7 +502,7 @@ def check_paths_relative(input_dict, relative_folder) -> bool: # check relative is possible try: - p2 = _relative_to(p, relative_folder) + _ = _relative_to(p, relative_folder) except ValueError: not_possible.append(p) continue @@ -562,8 +562,6 @@ def make_paths_absolute(input_dict, base_folder) -> dict: A copy of the input dict with modified paths. """ base_folder = Path(base_folder) - # use as_posix instead of str to make the path unix like even on window - func = lambda p: (base_folder / p).resolve().absolute().as_posix() path_elements_in_dict = [e for e in extractor_dict_iterator(input_dict) if element_is_path(e)] output_dict = deepcopy(input_dict) @@ -981,10 +979,10 @@ def load_annotations_from_folder(folder: str | Path, extractor: "BaseExtractor") def save_provenance_to_folder(folder: str | Path, extractor: "BaseExtractor", relative_to: str | Path | None = None): folder = Path(folder) if extractor.check_serializability("json"): - provenance_file_path = folder / f"provenance.json" + provenance_file_path = folder / "provenance.json" extractor.dump_to_json(file_path=provenance_file_path, relative_to=relative_to) elif extractor.check_serializability("pickle"): - provenance_file = folder / f"provenance.pkl" + provenance_file = folder / "provenance.pkl" extractor.dump_to_pickle(provenance_file, relative_to=folder) else: warnings.warn("The extractor is not serializable to file. The provenance will not be saved.") diff --git a/src/spikeinterface/core/frameslicerecording.py b/src/spikeinterface/core/frameslicerecording.py index bc7913e505..6bb606f5ad 100644 --- a/src/spikeinterface/core/frameslicerecording.py +++ b/src/spikeinterface/core/frameslicerecording.py @@ -34,9 +34,9 @@ def __init__(self, recording, start_frame=None, end_frame=None): assert start_frame >= 0, f"{start_frame=} must be positive" assert start_frame < end_frame, f"{start_frame=} must be smaller than 'end_frame' {end_frame=}!" - assert ( - end_frame <= samples_in_recording - ), f"{end_frame=} must be smaller than or equal to {samples_in_recording=}" + assert end_frame <= samples_in_recording, ( + f"{end_frame=} must be smaller than or equal to {samples_in_recording=}" + ) BaseRecording.__init__( self, diff --git a/src/spikeinterface/core/frameslicesorting.py b/src/spikeinterface/core/frameslicesorting.py index 2d3195e8a5..6d0a99ad46 100644 --- a/src/spikeinterface/core/frameslicesorting.py +++ b/src/spikeinterface/core/frameslicesorting.py @@ -46,12 +46,12 @@ def __init__(self, parent_sorting, start_frame=None, end_frame=None, check_spike parent_n_samples = parent_sorting._recording.get_total_samples() if end_frame is None: end_frame = parent_n_samples - assert ( - end_frame <= parent_n_samples - ), f"`end_frame` should be smaller than the sortings' total number of samples {parent_n_samples}." - assert ( - start_frame <= parent_n_samples - ), "`start_frame` should be smaller than the sortings' total number of samples." + assert end_frame <= parent_n_samples, ( + f"`end_frame` should be smaller than the sortings' total number of samples {parent_n_samples}." + ) + assert start_frame <= parent_n_samples, ( + "`start_frame` should be smaller than the sortings' total number of samples." + ) if check_spike_frames and has_exceeding_spikes(parent_sorting, parent_sorting._recording): raise ValueError( "The sorting object has spikes whose times go beyond the recording duration." diff --git a/src/spikeinterface/core/generate.py b/src/spikeinterface/core/generate.py index eeeb0b91b8..b0c3ad4318 100644 --- a/src/spikeinterface/core/generate.py +++ b/src/spikeinterface/core/generate.py @@ -8,9 +8,9 @@ from .basesorting import SpikeVectorSortingSegment from .numpyextractors import NumpySorting -from probeinterface import Probe, generate_linear_probe, generate_multi_columns_probe +from probeinterface import generate_linear_probe, generate_multi_columns_probe -from spikeinterface.core import BaseRecording, BaseRecordingSegment, BaseSorting +from spikeinterface.core import BaseRecording, BaseRecordingSegment, BaseSorting, BaseSortingSegment from .core_tools import define_function_from_class, ms_to_samples, _ensure_seed @@ -355,11 +355,11 @@ def __init__( if new_unit_ids is not None: new_unit_ids = list(new_unit_ids) - assert ~np.any( - np.isin(new_unit_ids, sorting.unit_ids) - ), "some units ids are already present. Consider using added_spikes_existing_units" + assert ~np.any(np.isin(new_unit_ids, sorting.unit_ids)), ( + "some units ids are already present. Consider using added_spikes_existing_units" + ) if len(new_unit_ids) > 0: - assert type(unit_ids[0]) == type(new_unit_ids[0]), "unit_ids should have the same type" + assert type(unit_ids[0]) is type(new_unit_ids[0]), "unit_ids should have the same type" unit_ids = unit_ids + list(new_unit_ids) BaseSorting.__init__(self, sampling_frequency, unit_ids) @@ -372,10 +372,9 @@ def __init__( self.added_spikes_from_new_mask = np.zeros(len(spikes), dtype=bool) if added_spikes_existing_units is not None and len(added_spikes_existing_units) > 0: - assert ( - added_spikes_existing_units.dtype == minimum_spike_dtype - ), "added_spikes_existing_units should be a spike vector" - added_unit_indices = np.arange(len(self.parent_unit_ids)) + assert added_spikes_existing_units.dtype == minimum_spike_dtype, ( + "added_spikes_existing_units should be a spike vector" + ) spikes = np.concatenate((spikes, added_spikes_existing_units)) self.added_spikes_from_existing_mask = np.concatenate( (self.added_spikes_from_existing_mask, np.ones(len(added_spikes_existing_units), dtype=bool)) @@ -385,9 +384,9 @@ def __init__( ) if added_spikes_new_units is not None and len(added_spikes_new_units) > 0: - assert ( - added_spikes_new_units.dtype == minimum_spike_dtype - ), "added_spikes_new_units should be a spike vector" + assert added_spikes_new_units.dtype == minimum_spike_dtype, ( + "added_spikes_new_units should be a spike vector" + ) spikes = np.concatenate((spikes, added_spikes_new_units)) self.added_spikes_from_existing_mask = np.concatenate( (self.added_spikes_from_existing_mask, np.zeros(len(added_spikes_new_units), dtype=bool)) @@ -455,10 +454,10 @@ def add_from_sorting(sorting1: BaseSorting, sorting2: BaseSorting, refractory_pe of spikes. Any spike times in added_spikes violating the refractory period will be discarded. """ - assert ( - sorting1.get_sampling_frequency() == sorting2.get_sampling_frequency() - ), "sampling_frequency should be the same" - assert type(sorting1.unit_ids[0]) == type(sorting2.unit_ids[0]), "unit_ids should have the same type" + assert sorting1.get_sampling_frequency() == sorting2.get_sampling_frequency(), ( + "sampling_frequency should be the same" + ) + assert type(sorting1.unit_ids[0]) is type(sorting2.unit_ids[0]), "unit_ids should have the same type" # We detect the indices that are shared by the two sortings mask1 = np.isin(sorting2.unit_ids, sorting1.unit_ids) common_ids = sorting2.unit_ids[mask1] @@ -1023,9 +1022,6 @@ def synthesize_amplitude_factor( return None -from spikeinterface.core.basesorting import BaseSortingSegment, BaseSorting - - class SortingGenerator(BaseSorting): def __init__( self, @@ -1690,7 +1686,6 @@ def generate_templates( """ unit_params = unit_params or dict() - rng = np.random.default_rng(seed=seed) # neuron location must be 3D assert units_locations.shape[1] == 3 @@ -2335,9 +2330,7 @@ def generate_ground_truth_recording( prb_kwargs = generate_probe_kwargs.copy() if "num_contact_per_column" in prb_kwargs: - assert ( - prb_kwargs["num_contact_per_column"] * prb_kwargs["num_columns"] - ) == num_channels, ( + assert (prb_kwargs["num_contact_per_column"] * prb_kwargs["num_columns"]) == num_channels, ( "generate_multi_columns_probe : num_channels do not match num_contact_per_column x num_columns" ) elif "num_contact_per_column" not in prb_kwargs and "num_columns" in prb_kwargs: diff --git a/src/spikeinterface/core/globals.py b/src/spikeinterface/core/globals.py index 2712f4db3a..8bfa0f7a06 100644 --- a/src/spikeinterface/core/globals.py +++ b/src/spikeinterface/core/globals.py @@ -131,7 +131,7 @@ def set_global_job_kwargs(**job_kwargs): global global_job_kwargs for k in job_kwargs: assert k in job_keys, ( - f"{k} is not a valid job keyword argument. " f"Available keyword arguments are: {list(job_keys)}" + f"{k} is not a valid job keyword argument. Available keyword arguments are: {list(job_keys)}" ) global_job_kwargs.update(job_kwargs) global global_job_kwargs_set diff --git a/src/spikeinterface/core/job_tools.py b/src/spikeinterface/core/job_tools.py index 59af6fd254..1c3a62b9da 100644 --- a/src/spikeinterface/core/job_tools.py +++ b/src/spikeinterface/core/job_tools.py @@ -144,7 +144,7 @@ def fix_job_kwargs(runtime_job_kwargs): for k in runtime_job_kwargs: assert k in job_keys, ( - f"{k} is not a valid job keyword argument. " f"Available keyword arguments are: {list(job_keys)}" + f"{k} is not a valid job keyword argument. Available keyword arguments are: {list(job_keys)}" ) # remove mutually exclusive from global job kwargs diff --git a/src/spikeinterface/core/loading.py b/src/spikeinterface/core/loading.py index 8cc679d95e..24d0588723 100644 --- a/src/spikeinterface/core/loading.py +++ b/src/spikeinterface/core/loading.py @@ -1,4 +1,3 @@ -import warnings from pathlib import Path import json @@ -99,7 +98,6 @@ def load( return _load_object_from_dict(d, object_type, base_folder=base_folder) elif is_local and file_path.is_dir(): - folder = file_path if folder.suffix == ".zarr": # Local zarr can be @@ -195,7 +193,7 @@ def _guess_object_from_local_folder(folder): elif (folder / "waveforms").is_dir(): # before the SortingAnlazer, it was WaveformExtractor (v<0.101) return "WaveformExtractor" - elif (folder / f"si_folder.json").is_file(): + elif (folder / "si_folder.json").is_file(): # In later versions (0.94 None: if extension_folder.is_dir(): shutil.rmtree(extension_folder) if self.format == "zarr": - zarr_root = self._get_zarr_root(mode="r+") if extension_name in (root := zarr_root["extensions"]): del root[extension_name] @@ -2850,7 +2845,6 @@ def _sort_extensions_by_dependency(extensions): i = 0 while i < len(extensions_list): - extension = extensions_list[i] extension_params = extension_params_list[i] @@ -2875,10 +2869,8 @@ def _sort_extensions_by_dependency(extensions): # Otherwise, should check the dependency which has just been moved => at position i did_nothing = True for dependency in dependencies: - # if dependency is on the right, move it left of the current dependency if dependency in extensions_list[i:]: - dependency_arg = extensions_list.index(dependency) extension_params_list.pop(dependency_arg) @@ -2945,9 +2937,9 @@ def register_result_extension(extension_class): already_registered = any(extension_class is ext for ext in _possible_extensions) if not already_registered: - assert all( - extension_class.extension_name != ext.extension_name for ext in _possible_extensions - ), "Extension name already exists" + assert all(extension_class.extension_name != ext.extension_name for ext in _possible_extensions), ( + "Extension name already exists" + ) _possible_extensions.append(extension_class) @@ -2984,7 +2976,7 @@ def get_extension_class(extension_name: str, auto_import=True): if extension_name in _builtin_extensions: module = _builtin_extensions[extension_name] if auto_import: - imported_module = importlib.import_module(module) + _ = importlib.import_module(module) extensions_dict = {ext.extension_name: ext for ext in _possible_extensions} else: raise ValueError( @@ -3519,7 +3511,6 @@ def run(self, save=True, **kwargs): self._save_run_info() self._save_data() if self.format == "zarr": - zarr.consolidate_metadata(self.sorting_analyzer._get_zarr_root(mode="r+").store) def save(self): @@ -3530,7 +3521,6 @@ def save(self): self._save_data() if self.format == "zarr": - zarr.consolidate_metadata(self.sorting_analyzer._get_zarr_root(mode="r+").store) def _save_data(self): @@ -3545,11 +3535,10 @@ def _save_data(self): import pandas as pd HAS_PANDAS = True - except: + except Exception: HAS_PANDAS = False if self.format == "binary_folder": - extension_folder = self._get_binary_extension_folder() for ext_data_name, ext_data in self.data.items(): if isinstance(ext_data, dict): @@ -3570,10 +3559,9 @@ def _save_data(self): try: with (extension_folder / f"{ext_data_name}.pkl").open("wb") as f: pickle.dump(ext_data, f) - except: + except Exception: raise Exception(f"Could not save {ext_data_name} as extension data") elif self.format == "zarr": - saving_options = self.sorting_analyzer._backend_options.get("saving_options", {}) extension_group = self._get_zarr_extension_group(mode="r+") @@ -3619,7 +3607,7 @@ def _save_data(self): write_pickle_array( extension_group, ext_data_name, ext_data, compressors=saving_options["compressors"] ) - except: + except Exception: raise Exception(f"Could not save {ext_data_name} as extension data") def _reset_extension_folder(self): @@ -3643,7 +3631,6 @@ def _reset_extension_folder(self): extension_folder.mkdir(exist_ok=False, parents=True) elif self.format == "zarr": - zarr_root = self.sorting_analyzer._get_zarr_root(mode="r+") _ = zarr_root["extensions"].create_group(self.extension_name, overwrite=True) zarr.consolidate_metadata(zarr_root.store) @@ -3658,7 +3645,6 @@ def _delete_extension_folder(self): shutil.rmtree(extension_folder) elif self.format == "zarr": - zarr_root = self.sorting_analyzer._get_zarr_root(mode="r+") if self.extension_name in zarr_root["extensions"]: del zarr_root["extensions"][self.extension_name] @@ -3758,16 +3744,16 @@ def _save_run_info(self): extension_group.attrs["run_info"] = run_info def get_pipeline_nodes(self): - assert ( - self.use_nodepipeline - ), "AnalyzerExtension.get_pipeline_nodes() must be called only when use_nodepipeline=True" + assert self.use_nodepipeline, ( + "AnalyzerExtension.get_pipeline_nodes() must be called only when use_nodepipeline=True" + ) return self._get_pipeline_nodes() def get_data(self, *args, **kwargs): if self.run_info is not None: - assert self.run_info[ - "run_completed" - ], f"You must run the extension {self.extension_name} before retrieving data" + assert self.run_info["run_completed"], ( + f"You must run the extension {self.extension_name} before retrieving data" + ) assert len(self.data) > 0, "Extension has been run but no data found." return self._get_data(*args, **kwargs) diff --git a/src/spikeinterface/core/sortingfolder.py b/src/spikeinterface/core/sortingfolder.py index 8879e8e2fc..3c05f52599 100644 --- a/src/spikeinterface/core/sortingfolder.py +++ b/src/spikeinterface/core/sortingfolder.py @@ -96,7 +96,7 @@ def write_sorting( # All properties, annotations, and probe information are already saved in the folder, # so we don't need to include them in the si_folder.json cached = NumpyFolderSorting(folder_path=folder_path, mmap_mode=mmap_mode) - si_folder_path = folder_path / f"si_folder.json" + si_folder_path = folder_path / "si_folder.json" cached.dump_to_json( file_path=si_folder_path, relative_to=folder_path, @@ -176,7 +176,7 @@ def write_sorting(sorting, save_path): # make the si_folder file to make the load() easier cached = NpzFolderSorting(folder_path=save_path) cached._annotations = deepcopy({k: sorting._annotations[k] for k in sorting._annotations.keys()}) - si_folder_path = save_path / f"si_folder.json" + si_folder_path = save_path / "si_folder.json" cached.dump_to_json(file_path=si_folder_path, relative_to=save_path, include_extra_metadata=False) return cached diff --git a/src/spikeinterface/core/sparsity.py b/src/spikeinterface/core/sparsity.py index 9863dfbb77..c109db5cd9 100644 --- a/src/spikeinterface/core/sparsity.py +++ b/src/spikeinterface/core/sparsity.py @@ -4,9 +4,7 @@ from .basesorting import BaseSorting from .baserecording import BaseRecording -from .sorting_tools import random_spikes_selection from .job_tools import _shared_job_kwargs_doc -from .waveform_tools import estimate_templates_with_accumulator from .core_tools import ms_to_samples _sparsity_doc = """ @@ -475,9 +473,9 @@ def from_snr( from .sortinganalyzer import SortingAnalyzer from .template import Templates - assert ( - templates_or_sorting_analyzer.sparsity is None - ), "To compute sparsity you need a dense SortingAnalyzer or Templates" + assert templates_or_sorting_analyzer.sparsity is None, ( + "To compute sparsity you need a dense SortingAnalyzer or Templates" + ) unit_ids = templates_or_sorting_analyzer.unit_ids channel_ids = templates_or_sorting_analyzer.channel_ids @@ -526,9 +524,9 @@ def from_amplitude(cls, templates_or_sorting_analyzer, threshold, amplitude_mode from .sortinganalyzer import SortingAnalyzer from .template import Templates - assert ( - templates_or_sorting_analyzer.sparsity is None - ), "To compute sparsity you need a dense SortingAnalyzer or Templates" + assert templates_or_sorting_analyzer.sparsity is None, ( + "To compute sparsity you need a dense SortingAnalyzer or Templates" + ) unit_ids = templates_or_sorting_analyzer.unit_ids channel_ids = templates_or_sorting_analyzer.channel_ids @@ -625,9 +623,9 @@ def from_property(cls, sorting, recording, by_property): rec_by = recording.split_by(by_property) for unit_ind, unit_id in enumerate(sorting.unit_ids): unit_property = sorting.get_property(by_property)[unit_ind] - assert ( - unit_property in rec_by.keys() - ), f"Unit property {unit_property} cannot be found in the recording properties" + assert unit_property in rec_by.keys(), ( + f"Unit property {unit_property} cannot be found in the recording properties" + ) chan_inds = recording.ids_to_indices(rec_by[unit_property].get_channel_ids()) mask[unit_ind, chan_inds] = True return cls(mask, sorting.unit_ids, recording.channel_ids) @@ -698,26 +696,26 @@ def compute_sparsity( "snr", "amplitude", ): - assert isinstance( - templates_or_sorting_analyzer, (Templates, SortingAnalyzer) - ), f"compute_sparsity(method='{method}') need Templates or SortingAnalyzer" + assert isinstance(templates_or_sorting_analyzer, (Templates, SortingAnalyzer)), ( + f"compute_sparsity(method='{method}') need Templates or SortingAnalyzer" + ) if isinstance(templates_or_sorting_analyzer, Templates): - assert ( - peak_sign is not None - ), "When using `compute_sparsity` with a Templates object, `peak_sign` must be specified." - assert ( - amplitude_mode is not None - ), "When using `compute_sparsity` with a Templates object, `amplitude_mode` must be specified." + assert peak_sign is not None, ( + "When using `compute_sparsity` with a Templates object, `peak_sign` must be specified." + ) + assert amplitude_mode is not None, ( + "When using `compute_sparsity` with a Templates object, `amplitude_mode` must be specified." + ) else: - assert isinstance( - templates_or_sorting_analyzer, SortingAnalyzer - ), f"compute_sparsity(method='{method}') need SortingAnalyzer" - assert ( - peak_sign is None - ), "When using `compute_sparsity` with an analyzer, `peak_sign` must be None. The `peak_sign is set when you create the analyzer." - assert ( - amplitude_mode is None - ), "When using `compute_sparsity` with an analyzer, `amplitude_mode` must be None. The `peak_mode` is set when you create the analyzer." + assert isinstance(templates_or_sorting_analyzer, SortingAnalyzer), ( + f"compute_sparsity(method='{method}') need SortingAnalyzer" + ) + assert peak_sign is None, ( + "When using `compute_sparsity` with an analyzer, `peak_sign` must be None. The `peak_sign is set when you create the analyzer." + ) + assert amplitude_mode is None, ( + "When using `compute_sparsity` with an analyzer, `amplitude_mode` must be None. The `peak_mode` is set when you create the analyzer." + ) if method == "best_channels": assert num_channels is not None, "For the 'best_channels' method, 'num_channels' needs to be given" diff --git a/src/spikeinterface/core/template.py b/src/spikeinterface/core/template.py index a170dd4e02..07462137c4 100644 --- a/src/spikeinterface/core/template.py +++ b/src/spikeinterface/core/template.py @@ -101,17 +101,17 @@ def __post_init__(self): self.channel_ids = np.arange(self.num_channels) else: self.channel_ids = np.asarray(self.channel_ids) - assert ( - len(self.channel_ids) == self.num_channels - ), f"length of channel ids {len(self.channel_ids)} must be equal to the number of channels {self.num_channels}" + assert len(self.channel_ids) == self.num_channels, ( + f"length of channel ids {len(self.channel_ids)} must be equal to the number of channels {self.num_channels}" + ) if self.unit_ids is None: self.unit_ids = np.arange(self.num_units) else: self.unit_ids = np.asarray(self.unit_ids) - assert ( - self.unit_ids.size == self.num_units - ), f"length of units ids {self.unit_ids.size} must be equal to the number of units {self.num_units}" + assert self.unit_ids.size == self.num_units, ( + f"length of units ids {self.unit_ids.size} must be equal to the number of units {self.num_units}" + ) if self.sparsity_mask is not None: self.sparsity = ChannelSparsity( diff --git a/src/spikeinterface/core/template_tools.py b/src/spikeinterface/core/template_tools.py index 4b46b4689e..353a654806 100644 --- a/src/spikeinterface/core/template_tools.py +++ b/src/spikeinterface/core/template_tools.py @@ -129,9 +129,9 @@ def get_template_amplitudes( """ if isinstance(templates_or_sorting_analyzer, SortingAnalyzer): - assert ( - peak_sign is None - ), "get_template_amplitudes() peak_sign is now contained in SortingAnalyzer, should be None here" + assert peak_sign is None, ( + "get_template_amplitudes() peak_sign is now contained in SortingAnalyzer, should be None here" + ) if peak_sign is None: peak_sign = templates_or_sorting_analyzer.peak_sign if peak_mode is None: diff --git a/src/spikeinterface/core/testing.py b/src/spikeinterface/core/testing.py index 6ad7458c37..ddea78d343 100644 --- a/src/spikeinterface/core/testing.py +++ b/src/spikeinterface/core/testing.py @@ -1,4 +1,3 @@ -import warnings import numpy as np from numpy.testing import assert_array_equal from .baserecording import BaseRecording @@ -117,7 +116,6 @@ def check_sortings_equal( (None, max_spike_index - 30), (30, max_spike_index - 30), ]: - slice1 = _slice_spikes(s1, start_frame, end_frame) slice2 = _slice_spikes(s2, start_frame, end_frame) assert np.array_equal(slice1, slice2) diff --git a/src/spikeinterface/core/testing_tools.py b/src/spikeinterface/core/testing_tools.py index 101dfaea46..82be0f58d6 100644 --- a/src/spikeinterface/core/testing_tools.py +++ b/src/spikeinterface/core/testing_tools.py @@ -1,7 +1,7 @@ import warnings warnings.warn( - "The 'testing_tools' submodule is deprecated. " "Use spikeinterface.core.generate instead", + "The 'testing_tools' submodule is deprecated. Use spikeinterface.core.generate instead", FutureWarning, stacklevel=2, ) diff --git a/src/spikeinterface/core/tests/test_analyzer_extension_core.py b/src/spikeinterface/core/tests/test_analyzer_extension_core.py index 6423ce11ce..030f4f50b3 100644 --- a/src/spikeinterface/core/tests/test_analyzer_extension_core.py +++ b/src/spikeinterface/core/tests/test_analyzer_extension_core.py @@ -40,7 +40,7 @@ def get_sorting_analyzer(cache_folder, format="memory", sparse=True): elif format == "binary_folder": folder = cache_folder / f"test_ComputeWaveforms_{format}" elif format == "zarr": - folder = cache_folder / f"test_ComputeWaveforms.zarr" + folder = cache_folder / "test_ComputeWaveforms.zarr" if folder and folder.exists(): shutil.rmtree(folder) @@ -66,12 +66,13 @@ def _check_result_extension(sorting_analyzer, extension_name, cache_folder): folder = None # check unit slice + original_data = sorting_analyzer.get_extension(extension_name).data keep_unit_ids = sorting_analyzer.sorting.unit_ids[::2] sorting_analyzer2 = sorting_analyzer.select_units(unit_ids=keep_unit_ids, format=format, folder=folder) data = sorting_analyzer2.get_extension(extension_name).data - # for k, arr in data.items(): - # print(k, arr.shape) + for k in original_data: + assert k in data @pytest.mark.parametrize("format", ["memory", "binary_folder", "zarr"]) @@ -112,8 +113,7 @@ def test_ComputeWaveforms(format, sparse, create_cache_folder): job_kwargs = dict(n_jobs=2, chunk_duration="1s", progress_bar=True) sorting_analyzer.compute("random_spikes", max_spikes_per_unit=50, seed=2205) - ext = sorting_analyzer.compute("waveforms", **job_kwargs) - wfs = ext.data["waveforms"] + _ = sorting_analyzer.compute("waveforms", **job_kwargs) _check_result_extension(sorting_analyzer, "waveforms", cache_folder) @@ -212,8 +212,10 @@ def test_ComputeTemplates(format, sparse, create_cache_folder): # ask for more operator later temp_ext = sorting_analyzer.get_extension("templates") - templated_median = temp_ext.get_templates(operator="median") + template_median = temp_ext.get_templates(operator="median") + assert template_median is not None templated_per_5 = temp_ext.get_templates(operator="percentile", percentile=5.0) + assert templated_per_5 is not None # they all should be in data data = sorting_analyzer.get_extension("templates").data diff --git a/src/spikeinterface/core/tests/test_base.py b/src/spikeinterface/core/tests/test_base.py index c81d24963c..57a50eb940 100644 --- a/src/spikeinterface/core/tests/test_base.py +++ b/src/spikeinterface/core/tests/test_base.py @@ -94,7 +94,7 @@ def test_name_and_repr(): assert "MyRecording" not in str(test_recording2) assert test_recording2.__class__.__name__ in str(test_recording2) # above 10khz, sampling frequency is printed in kHz - assert f"kHz" in rec_str + assert "kHz" in rec_str # below 10khz sampling frequency is printed in Hz test_rec_low_fs = generate_recording(seed=0, durations=[2], sampling_frequency=5000) rec_str = str(test_rec_low_fs) diff --git a/src/spikeinterface/core/tests/test_baserecording.py b/src/spikeinterface/core/tests/test_baserecording.py index d5aa3c154b..5fa0948a49 100644 --- a/src/spikeinterface/core/tests/test_baserecording.py +++ b/src/spikeinterface/core/tests/test_baserecording.py @@ -11,12 +11,11 @@ import numpy as np from numpy.testing import assert_raises -from probeinterface import Probe, ProbeGroup, generate_linear_probe +from probeinterface import Probe from spikeinterface.core import ( BinaryRecordingExtractor, NumpyRecording, - load, get_default_zarr_compressor, load, ) diff --git a/src/spikeinterface/core/tests/test_basesorting.py b/src/spikeinterface/core/tests/test_basesorting.py index 554d145c4c..cf71afdd88 100644 --- a/src/spikeinterface/core/tests/test_basesorting.py +++ b/src/spikeinterface/core/tests/test_basesorting.py @@ -20,7 +20,6 @@ generate_recording, generate_sorting, create_sorting_npz, - generate_sorting, load, ) from spikeinterface.core.base import BaseExtractor, minimum_spike_dtype, unit_period_dtype @@ -133,9 +132,14 @@ def test_BaseSorting(create_cache_folder): ) assert np.array_equal(spikes[order], ordered_spikes) - num_spikes_per_unit = sorting.count_num_spikes_per_unit(outputs="dict") + num_spikes_per_unit_dict = sorting.count_num_spikes_per_unit(outputs="dict") + assert isinstance(num_spikes_per_unit_dict, dict) + assert all(unit in num_spikes_per_unit_dict for unit in sorting.unit_ids) num_spikes_per_unit = sorting.count_num_spikes_per_unit(outputs="array") + assert isinstance(num_spikes_per_unit, np.ndarray) + assert num_spikes_per_unit.size == sorting.unit_ids.size total_spikes = sorting.count_total_num_spikes() + assert total_spikes == num_spikes_per_unit.sum() # select units keep_units = [0, 1] diff --git a/src/spikeinterface/core/tests/test_binaryfolder.py b/src/spikeinterface/core/tests/test_binaryfolder.py index 8272a7e29d..7fefc68bdf 100644 --- a/src/spikeinterface/core/tests/test_binaryfolder.py +++ b/src/spikeinterface/core/tests/test_binaryfolder.py @@ -1,9 +1,7 @@ import pytest import json -from pathlib import Path import shutil - import numpy as np from spikeinterface.core import load diff --git a/src/spikeinterface/core/tests/test_binaryrecordingextractor.py b/src/spikeinterface/core/tests/test_binaryrecordingextractor.py index 853271066c..869b4a34da 100644 --- a/src/spikeinterface/core/tests/test_binaryrecordingextractor.py +++ b/src/spikeinterface/core/tests/test_binaryrecordingextractor.py @@ -6,7 +6,6 @@ from spikeinterface.core import BinaryRecordingExtractor, MockRecording from spikeinterface.core.base import BaseExtractor from spikeinterface.core.numpyextractors import NumpyRecording -from spikeinterface.core.core_tools import measure_memory_allocation def test_BinaryRecordingExtractor(create_cache_folder): diff --git a/src/spikeinterface/core/tests/test_channelsaggregationrecording.py b/src/spikeinterface/core/tests/test_channelsaggregationrecording.py index 4702acca93..a851925724 100644 --- a/src/spikeinterface/core/tests/test_channelsaggregationrecording.py +++ b/src/spikeinterface/core/tests/test_channelsaggregationrecording.py @@ -40,7 +40,6 @@ def test_channelsaggregationrecording(): ] for recordings_list in recordings_list_possibilities: - # test num channels recording_agg = aggregate_channels(recordings_list) assert len(recording_agg.get_channel_ids()) == 3 * num_channels diff --git a/src/spikeinterface/core/tests/test_channelslicerecording.py b/src/spikeinterface/core/tests/test_channelslicerecording.py index 0f8247e85e..1756c022a6 100644 --- a/src/spikeinterface/core/tests/test_channelslicerecording.py +++ b/src/spikeinterface/core/tests/test_channelslicerecording.py @@ -75,7 +75,7 @@ def test_failure_with_non_unique_channel_ids(): seed = 10 rec = generate_recording(num_channels=4, durations=durations, set_probe=False, seed=seed) with pytest.raises(AssertionError): - rec_sliced = ChannelSliceRecording(rec, channel_ids=["0", "1"], renamed_channel_ids=[0, 0]) + _ = ChannelSliceRecording(rec, channel_ids=["0", "1"], renamed_channel_ids=[0, 0]) def test_remove_channels(): diff --git a/src/spikeinterface/core/tests/test_core_tools.py b/src/spikeinterface/core/tests/test_core_tools.py index 5c2a3b085c..443a262a6d 100644 --- a/src/spikeinterface/core/tests/test_core_tools.py +++ b/src/spikeinterface/core/tests/test_core_tools.py @@ -1,6 +1,5 @@ import platform import math -from pathlib import Path import pytest import numpy as np diff --git a/src/spikeinterface/core/tests/test_frameslicerecording.py b/src/spikeinterface/core/tests/test_frameslicerecording.py index fa0b76862d..248e930b35 100644 --- a/src/spikeinterface/core/tests/test_frameslicerecording.py +++ b/src/spikeinterface/core/tests/test_frameslicerecording.py @@ -1,7 +1,6 @@ -import pytest import numpy as np -from spikeinterface.core import FrameSliceRecording, NumpyRecording +from spikeinterface.core import NumpyRecording def test_FrameSliceRecording(): diff --git a/src/spikeinterface/core/tests/test_generate.py b/src/spikeinterface/core/tests/test_generate.py index 66f84a2914..d1360473dc 100644 --- a/src/spikeinterface/core/tests/test_generate.py +++ b/src/spikeinterface/core/tests/test_generate.py @@ -33,16 +33,6 @@ strategy_list = ["tile_pregenerated", "on_the_fly"] -def test_generate_recording(): - # TODO even this is extensively tested in all other functions - pass - - -def test_generate_sorting(): - # TODO even this is extensively tested in all other functions - pass - - def test_generate_sorting_with_spikes_on_borders(): num_spikes_on_borders = 10 border_size_samples = 10 @@ -108,7 +98,7 @@ def test_memory_sorting_generator(): seed = 0 before_instanciation_MiB = measure_memory_allocation() / bytes_to_MiB_factor - sorting = SortingGenerator( + _ = SortingGenerator( num_units=num_units, sampling_frequency=sampling_frequency, durations=durations, @@ -118,9 +108,9 @@ def test_memory_sorting_generator(): memory_usage_MiB = after_instanciation_MiB - before_instanciation_MiB ratio = memory_usage_MiB / before_instanciation_MiB expected_allocation_MiB = 0 - assert ( - ratio <= 1.0 + relative_tolerance - ), f"SortingGenerator wrong memory {memory_usage_MiB} instead of {expected_allocation_MiB}" + assert ratio <= 1.0 + relative_tolerance, ( + f"SortingGenerator wrong memory {memory_usage_MiB} instead of {expected_allocation_MiB}" + ) def test_sorting_generator_consisency_across_calls(): @@ -175,11 +165,10 @@ def test_noise_generator_memory(): dtype = np.dtype("float32") num_channels = 384 seed = 0 - num_samples = int(durations[0] * sampling_frequency) # case 1 preallocation of noise use one noise block 88M for 60000 sample of 384 before_instanciation_MiB = measure_memory_allocation() / bytes_to_MiB_factor - rec1 = MockRecording( + _ = MockRecording( num_channels=num_channels, sampling_frequency=sampling_frequency, durations=durations, @@ -192,13 +181,13 @@ def test_noise_generator_memory(): memory_usage_MiB = after_instanciation_MiB - before_instanciation_MiB expected_allocation_MiB = dtype.itemsize * num_channels * noise_block_size / bytes_to_MiB_factor ratio = expected_allocation_MiB / expected_allocation_MiB - assert ( - ratio <= 1.0 + relative_tolerance - ), f"MockRecording with 'tile_pregenerated' wrong memory {memory_usage_MiB} instead of {expected_allocation_MiB}" + assert ratio <= 1.0 + relative_tolerance, ( + f"MockRecording with 'tile_pregenerated' wrong memory {memory_usage_MiB} instead of {expected_allocation_MiB}" + ) # case 2: no preallocation very few memory (under 2 MiB) before_instanciation_MiB = measure_memory_allocation() / bytes_to_MiB_factor - rec2 = MockRecording( + _ = MockRecording( num_channels=num_channels, sampling_frequency=sampling_frequency, durations=durations, @@ -370,17 +359,12 @@ def test_noise_generator_consistency_after_dump(strategy, seed): assert np.allclose(traces0, traces1) -def test_generate_recording(): - # check the high level function - rec = generate_recording() - - def test_generate_single_fake_waveform(): sampling_frequency = 30000.0 ms_before = 1.0 ms_after = 3.0 wf = generate_single_fake_waveform(ms_before=ms_before, ms_after=ms_after, sampling_frequency=sampling_frequency) - + assert wf.shape == (int((ms_before + ms_after) / 1000 * sampling_frequency),) # import matplotlib.pyplot as plt # times = np.arange(wf.size) / sampling_frequency * 1000 - ms_before # fig, ax = plt.subplots() diff --git a/src/spikeinterface/core/tests/test_jsonification.py b/src/spikeinterface/core/tests/test_jsonification.py index 316dac3abc..9850156829 100644 --- a/src/spikeinterface/core/tests/test_jsonification.py +++ b/src/spikeinterface/core/tests/test_jsonification.py @@ -7,8 +7,6 @@ from spikeinterface.core.core_tools import SIJsonEncoder from spikeinterface.core.generate import generate_recording, generate_sorting -from pathlib import Path - @pytest.fixture(scope="module") def numpy_generated_sorting(): diff --git a/src/spikeinterface/core/tests/test_loading.py b/src/spikeinterface/core/tests/test_loading.py index 8d57a3412f..340a44674b 100644 --- a/src/spikeinterface/core/tests/test_loading.py +++ b/src/spikeinterface/core/tests/test_loading.py @@ -1,5 +1,6 @@ import pytest import zarr +import importlib.util import numpy as np from spikeinterface import ( @@ -16,13 +17,13 @@ from spikeinterface.core.testing import check_recordings_equal, check_sortings_equal from spikeinterface.core.zarrextractors import ZarrRecordingExtractor -try: - import s3fs +if importlib.util.find_spec("s3fs") is not None: HAVE_S3 = True -except ImportError: +else: HAVE_S3 = False + computed_extensions = ["waveforms", "templates", "noise_levels", "random_spikes"] diff --git a/src/spikeinterface/core/tests/test_motion_core.py b/src/spikeinterface/core/tests/test_motion_core.py index 28d1ef7385..506d2c1e79 100644 --- a/src/spikeinterface/core/tests/test_motion_core.py +++ b/src/spikeinterface/core/tests/test_motion_core.py @@ -1,5 +1,4 @@ import pickle -import shutil import numpy as np from spikeinterface.core.motion import Motion diff --git a/src/spikeinterface/core/tests/test_node_pipeline.py b/src/spikeinterface/core/tests/test_node_pipeline.py index a721fc3367..7ff3fae682 100644 --- a/src/spikeinterface/core/tests/test_node_pipeline.py +++ b/src/spikeinterface/core/tests/test_node_pipeline.py @@ -1,6 +1,5 @@ import pytest import numpy as np -from pathlib import Path import shutil from spikeinterface import create_sorting_analyzer, generate_ground_truth_recording @@ -75,8 +74,6 @@ def test_run_node_pipeline(cache_folder_creation): # job_kwargs = dict(chunk_duration="0.5s", n_jobs=2, progress_bar=False) job_kwargs = dict(chunk_duration="0.5s", n_jobs=1, progress_bar=False) - spikes = sorting.to_spike_vector() - # create peaks from spikes sorting_analyzer = create_sorting_analyzer(sorting, recording, format="memory") sorting_analyzer.compute(["random_spikes", "templates"], **job_kwargs) @@ -269,6 +266,7 @@ def test_run_node_pipeline(cache_folder_creation): pickled_node = pickle.dumps(node) unpickled_node = pickle.loads(pickled_node) + assert isinstance(unpickled_node, type(node)) def test_gather_to_zarr_chunking(tmp_path): diff --git a/src/spikeinterface/core/tests/test_noise_levels_propagation.py b/src/spikeinterface/core/tests/test_noise_levels_propagation.py index 98e7a929fd..d553348d51 100644 --- a/src/spikeinterface/core/tests/test_noise_levels_propagation.py +++ b/src/spikeinterface/core/tests/test_noise_levels_propagation.py @@ -1,18 +1,14 @@ -import pytest from pathlib import Path -import shutil -from spikeinterface import set_global_tmp_folder, get_noise_levels -from spikeinterface.core import generate_recording, concatenate_recordings, aggregate_channels - -import numpy as np +from spikeinterface import get_noise_levels +from spikeinterface.core import generate_recording, concatenate_recordings def test_skip_noise_levels_propagation(create_cache_folder): rec = generate_recording(durations=[5.0], num_channels=4) rec.set_property("test", ["1", "2", "3", "4"]) rec = rec.save(folder=create_cache_folder / "rec_saved_noise") - noise_level_raw = get_noise_levels(rec, return_in_uV=False, method="mad") + _ = get_noise_levels(rec, return_in_uV=False, method="mad") assert "noise_level_mad_raw" in rec.get_property_keys() rec_frame_slice = rec.frame_slice(start_frame=0, end_frame=1000) @@ -22,7 +18,7 @@ def test_skip_noise_levels_propagation(create_cache_folder): # make scaled rec.set_channel_gains([100] * 4) rec.set_channel_offsets([0] * 4) - noise_level_scaled = get_noise_levels(rec, return_in_uV=True, method="std") + _ = get_noise_levels(rec, return_in_uV=True, method="std") assert "noise_level_std_scaled" in rec.get_property_keys() rec_frame_slice = rec.frame_slice(start_frame=0, end_frame=1000) diff --git a/src/spikeinterface/core/tests/test_npzsortingextractor.py b/src/spikeinterface/core/tests/test_npzsortingextractor.py index 4d84ee9a4d..90a8061bb8 100644 --- a/src/spikeinterface/core/tests/test_npzsortingextractor.py +++ b/src/spikeinterface/core/tests/test_npzsortingextractor.py @@ -1,8 +1,6 @@ -import pytest -from pathlib import Path - from spikeinterface.core import NpzSortingExtractor from spikeinterface.core import create_sorting_npz +from spikeinterface.core.testing import check_sortings_equal def test_NpzSortingExtractor(create_cache_folder): @@ -16,12 +14,9 @@ def test_NpzSortingExtractor(create_cache_folder): for segment_index in range(num_seg): for unit_id in (0, 1, 2): - st = sorting.get_unit_spike_train(unit_id, segment_index=segment_index) + _ = sorting.get_unit_spike_train(unit_id, segment_index=segment_index) file_path_copy = cache_folder / "test_NpzSortingExtractor_copy.npz" NpzSortingExtractor.write_sorting(sorting, file_path_copy) sorting_copy = NpzSortingExtractor(file_path_copy) - - -if __name__ == "__main__": - test_NpzSortingExtractor() + check_sortings_equal(sorting, sorting_copy) diff --git a/src/spikeinterface/core/tests/test_numpy_extractors.py b/src/spikeinterface/core/tests/test_numpy_extractors.py index 8ccbaf2a4d..25f5bb063c 100644 --- a/src/spikeinterface/core/tests/test_numpy_extractors.py +++ b/src/spikeinterface/core/tests/test_numpy_extractors.py @@ -27,8 +27,6 @@ def setup_NumpyRecording(tmp_path_factory): rec = NumpyRecording(timeseries_list, sampling_frequency) # print(rec) - - times1 = rec.get_times(1) cache_folder = tmp_path_factory.mktemp("cache_folder") rec.save(folder=cache_folder / "test_NumpyRecording") return cache_folder diff --git a/src/spikeinterface/core/tests/test_read_python_safe.py b/src/spikeinterface/core/tests/test_read_python_safe.py index 63d9a7d73f..1ad8f81861 100644 --- a/src/spikeinterface/core/tests/test_read_python_safe.py +++ b/src/spikeinterface/core/tests/test_read_python_safe.py @@ -6,7 +6,6 @@ Run: pytest test_read_python_safe.py -v """ -import os import re import inspect from spikeinterface.core.core_tools import read_python @@ -15,9 +14,7 @@ def test_read_python_does_not_execute_config(tmp_path): marker = tmp_path / "pwned.txt" p = tmp_path / "params.py" - p.write_text( - "sample_rate = 30000\n" "dtype = 'int16'\n" "import os\n" f"os.system('echo x> {marker.as_posix()}')\n" - ) + p.write_text(f"sample_rate = 30000\ndtype = 'int16'\nimport os\nos.system('echo x> {marker.as_posix()}')\n") md = read_python(str(p)) assert not marker.exists(), "read_python executed code from the config file (CWE-95)" assert md.get("sample_rate") == 30000 # literal assignments still parse diff --git a/src/spikeinterface/core/tests/test_recording_tools.py b/src/spikeinterface/core/tests/test_recording_tools.py index 13d68e3b45..0166c3bfdd 100644 --- a/src/spikeinterface/core/tests/test_recording_tools.py +++ b/src/spikeinterface/core/tests/test_recording_tools.py @@ -1,5 +1,3 @@ -from pathlib import Path -import platform import numpy as np from spikeinterface.core import NumpyRecording, generate_recording, MockRecording @@ -13,7 +11,6 @@ get_random_data_chunks, get_chunk_with_margin, get_closest_channels, - get_channel_distances, get_noise_levels, order_channels_by_depth, do_recording_attributes_match, @@ -176,8 +173,6 @@ def test_get_closest_channels(): closest_channels_inds, distances = get_closest_channels(rec) closest_channels_inds, distances = get_closest_channels(rec, num_channels=4) - dist = get_channel_distances(rec) - def test_get_noise_levels(): job_kwargs = dict(n_jobs=1, progress_bar=True) @@ -188,9 +183,8 @@ def test_get_noise_levels(): rec.set_channel_gains(0.1) rec.set_channel_offsets(0) - noise_levels = get_noise_levels(rec, return_in_uV=True, force_recompute=True, **job_kwargs) - - noise_levels = get_noise_levels(rec, return_in_uV=True, method="std", **job_kwargs) + _ = get_noise_levels(rec, return_in_uV=True, force_recompute=True, **job_kwargs) + _ = get_noise_levels(rec, return_in_uV=True, method="std", **job_kwargs) # Generate a recording following a gaussian distribution to check the result of get_noise. std = 6.0 @@ -302,10 +296,9 @@ def test_order_channels_by_depth(): locations_copy = locations_copy[::-1] rec.set_channel_locations(locations_copy) - order_1d, order_r1d = order_channels_by_depth(rec, dimensions="y") + order_1d, _ = order_channels_by_depth(rec, dimensions="y") order_2d, order_r2d = order_channels_by_depth(rec, dimensions=("x", "y")) - locations_rev = locations_copy[order_1d][order_r1d] - order_2d_fliped, order_r2d_fliped = order_channels_by_depth(rec, dimensions=("x", "y"), flip=True) + order_2d_fliped, _ = order_channels_by_depth(rec, dimensions=("x", "y"), flip=True) assert np.array_equal(locations[:, 1], locations_copy[order_1d][:, 1]) assert np.array_equal(locations_copy[order_1d][:, 1], locations_copy[order_2d][:, 1]) diff --git a/src/spikeinterface/core/tests/test_segmentutils.py b/src/spikeinterface/core/tests/test_segmentutils.py index e2c22fc24c..9e0b82377e 100644 --- a/src/spikeinterface/core/tests/test_segmentutils.py +++ b/src/spikeinterface/core/tests/test_segmentutils.py @@ -1,7 +1,6 @@ import warnings import numpy as np -import pytest from numpy.testing import assert_raises from spikeinterface.core import ( @@ -13,9 +12,7 @@ concatenate_sortings, select_segment_recording, split_recording, - split_sorting, ) -from spikeinterface.core.testing import check_sorted_arrays_equal def test_append_concatenate_recordings(): diff --git a/src/spikeinterface/core/tests/test_sorting_folder.py b/src/spikeinterface/core/tests/test_sorting_folder.py index 8d78a89ebd..5da96a5758 100644 --- a/src/spikeinterface/core/tests/test_sorting_folder.py +++ b/src/spikeinterface/core/tests/test_sorting_folder.py @@ -1,11 +1,10 @@ -import pytest import shutil import numpy as np from spikeinterface.core import NpzFolderSorting, NumpyFolderSorting from spikeinterface.core import generate_sorting -from spikeinterface.core.testing import check_sorted_arrays_equal, check_sortings_equal +from spikeinterface.core.testing import check_sortings_equal def test_NumpyFolderSorting(create_cache_folder): diff --git a/src/spikeinterface/core/tests/test_sorting_tools.py b/src/spikeinterface/core/tests/test_sorting_tools.py index 821b8b1631..1cb413c915 100644 --- a/src/spikeinterface/core/tests/test_sorting_tools.py +++ b/src/spikeinterface/core/tests/test_sorting_tools.py @@ -14,7 +14,6 @@ _get_ids_after_merging, generate_unit_ids_for_merge_group, remap_unit_indices_in_vector, - set_properties_after_merging, set_properties_after_splits, reorder_spike_vector_by_unit_and_segment, get_segment_durations, @@ -192,7 +191,6 @@ def test_random_spikes_selection(): random_spikes_indices = random_spikes_selection( sorting, num_samples, method="uniform", max_spikes_per_unit=max_spikes_per_unit, margin_size=None, seed=2205 ) - random_spikes_indices1 = random_spikes_indices spikes = sorting.to_spike_vector() some_spikes = spikes[random_spikes_indices] for unit_index, unit_id in enumerate(sorting.unit_ids): diff --git a/src/spikeinterface/core/tests/test_sortinganalyzer.py b/src/spikeinterface/core/tests/test_sortinganalyzer.py index 50eb925444..ab01eca320 100644 --- a/src/spikeinterface/core/tests/test_sortinganalyzer.py +++ b/src/spikeinterface/core/tests/test_sortinganalyzer.py @@ -641,12 +641,14 @@ def test_extension_params(): assert ext in computable_extension if mod == "spikeinterface.core": default_params = get_default_analyzer_extension_params(ext) + assert default_params is not None # print(ext, default_params) else: try: default_params = get_default_analyzer_extension_params(ext) + assert default_params is not None # print(ext, default_params) - except: + except Exception: print(f"Failed to import {ext}") @@ -1130,7 +1132,6 @@ def test_select_channels_sparse_waveforms_templates(dataset): selected_waveforms = analyzer_selected.get_extension("waveforms") for unit_index, unit_id in enumerate(sorting_analyzer.unit_ids): - original_units_to_channels = sorting_analyzer.sparsity.unit_id_to_channel_ids[unit_id] selected_units_to_channels = analyzer_selected.sparsity.unit_id_to_channel_ids[unit_id] @@ -1139,7 +1140,6 @@ def test_select_channels_sparse_waveforms_templates(dataset): for channel_id in select_channel_ids: if channel_id in original_units_to_channels: - # Check templates, which are dense original_channel_index = original_id_index_map[channel_id] selected_channel_index = selected_id_index_map[channel_id] diff --git a/src/spikeinterface/core/tests/test_sparsity.py b/src/spikeinterface/core/tests/test_sparsity.py index cc9da07387..99457d4686 100644 --- a/src/spikeinterface/core/tests/test_sparsity.py +++ b/src/spikeinterface/core/tests/test_sparsity.py @@ -299,10 +299,10 @@ def test_compute_sparsity(): # Check that we can still pass sparsity kwargs using the old signature (e.g. passing radius_um) with pytest.warns(FutureWarning): # radius_um is a sparsity kwarg - sorting_analyzer_old_kwargs = create_sorting_analyzer(sorting=sorting, recording=recording, radius_um=50) + _ = create_sorting_analyzer(sorting=sorting, recording=recording, radius_um=50) with pytest.warns(FutureWarning): # n_jobs is a job kwarg - sorting_analyzer_old_kwargs = create_sorting_analyzer(sorting=sorting, recording=recording, n_jobs=2) + _ = create_sorting_analyzer(sorting=sorting, recording=recording, n_jobs=2) sorting_analyzer.compute("random_spikes") sorting_analyzer.compute( @@ -313,30 +313,24 @@ def test_compute_sparsity(): # this is needed for method="energy" # using object SortingAnalyzer - sparsity = compute_sparsity(sorting_analyzer, method="best_channels", num_channels=2) - sparsity = compute_sparsity(sorting_analyzer, method="radius", radius_um=50.0) - sparsity = compute_sparsity(sorting_analyzer, method="closest_channels", num_channels=2) - sparsity = compute_sparsity(sorting_analyzer, method="snr", threshold=5) - sparsity = compute_sparsity(sorting_analyzer, method="amplitude", threshold=5) - sparsity = compute_sparsity(sorting_analyzer, method="energy", threshold=5) - sparsity = compute_sparsity(sorting_analyzer, method="by_property", by_property="group") + _ = compute_sparsity(sorting_analyzer, method="best_channels", num_channels=2) + _ = compute_sparsity(sorting_analyzer, method="radius", radius_um=50.0) + _ = compute_sparsity(sorting_analyzer, method="closest_channels", num_channels=2) + _ = compute_sparsity(sorting_analyzer, method="snr", threshold=5) + _ = compute_sparsity(sorting_analyzer, method="amplitude", threshold=5) + _ = compute_sparsity(sorting_analyzer, method="energy", threshold=5) + _ = compute_sparsity(sorting_analyzer, method="by_property", by_property="group") # using object Templates templates = sorting_analyzer.get_extension("templates").get_data(outputs="Templates") noise_levels = sorting_analyzer.get_extension("noise_levels").get_data() - sparsity = compute_sparsity( - templates, method="best_channels", num_channels=2, peak_sign="neg", amplitude_mode="extremum" - ) - sparsity = compute_sparsity( - templates, method="radius", radius_um=50.0, peak_sign="both", amplitude_mode="peak_to_peak" - ) - sparsity = compute_sparsity( + _ = compute_sparsity(templates, method="best_channels", num_channels=2, peak_sign="neg", amplitude_mode="extremum") + _ = compute_sparsity(templates, method="radius", radius_um=50.0, peak_sign="both", amplitude_mode="peak_to_peak") + _ = compute_sparsity( templates, method="snr", noise_levels=noise_levels, threshold=5, peak_sign="neg", amplitude_mode="extremum" ) - sparsity = compute_sparsity( - templates, method="amplitude", threshold=5, peak_sign="neg", amplitude_mode="peak_to_peak" - ) - sparsity = compute_sparsity( + _ = compute_sparsity(templates, method="amplitude", threshold=5, peak_sign="neg", amplitude_mode="peak_to_peak") + _ = compute_sparsity( templates, method="closest_channels", num_channels=2, peak_sign="neg", amplitude_mode="extremum" ) diff --git a/src/spikeinterface/core/tests/test_template_class.py b/src/spikeinterface/core/tests/test_template_class.py index 953527c8d5..b9b77bc6c7 100644 --- a/src/spikeinterface/core/tests/test_template_class.py +++ b/src/spikeinterface/core/tests/test_template_class.py @@ -112,7 +112,7 @@ def test_get_dense_templates(template_type, is_in_uV): def test_initialization_fail_with_dense_templates(): with pytest.raises(ValueError, match="Sparsity mask passed but the templates are not sparse"): - template = generate_test_template(template_type="sparse_with_dense_templates") + _ = generate_test_template(template_type="sparse_with_dense_templates") @pytest.mark.parametrize("is_in_uV", [True, False]) diff --git a/src/spikeinterface/core/tests/test_time_handling.py b/src/spikeinterface/core/tests/test_time_handling.py index 2f3cc1a6bf..eb872a6f4a 100644 --- a/src/spikeinterface/core/tests/test_time_handling.py +++ b/src/spikeinterface/core/tests/test_time_handling.py @@ -55,7 +55,6 @@ def _get_time_vector_recording(self, raw_recording): times_recording = raw_recording.clone() all_time_vectors = [] for segment_index in range(raw_recording.get_num_segments()): - t_start = segment_index + 1 * 100 t_stop = t_start + raw_recording.get_duration(segment_index) + segment_index + 1 @@ -80,7 +79,6 @@ def _get_t_start_recording(self, raw_recording): all_t_starts = [] for segment_index in range(raw_recording.get_num_segments()): - t_start = (segment_index + 1) * 100 all_t_starts.append(t_start + t_start_recording.get_times(segment_index)) @@ -110,7 +108,6 @@ def test_has_time_vector(self, time_vector_recording): raw_recording, times_recording, _ = time_vector_recording for segment_idx in range(raw_recording.get_num_segments()): - assert raw_recording.has_time_vector(segment_idx) is False assert times_recording.has_time_vector(segment_idx) is True @@ -169,7 +166,6 @@ def test_times_propagated_to_sorting(self, request, fixture_name): recording_for_durations=raw_recording, recording_to_attach=times_recording ) for segment_index in range(raw_recording.get_num_segments()): - if fixture_name == "time_vector_recording": assert sorting.has_time_vector(segment_index=segment_index) @@ -187,7 +183,6 @@ def test_time_sample_converters(self, request, fixture_name): assert "Provide 'segment_index'" in str(e) for segment_index in range(times_recording.get_num_segments()): - sample_index = np.random.randint(low=0, high=times_recording.get_num_samples(segment_index)) time_ = times_recording.sample_index_to_time(sample_index, segment_index=segment_index) @@ -258,7 +253,6 @@ def test_get_durations(self, time_vector_recording, t_start_recording): all_raw_durations = [] all_vector_durations = [] for segment_index in range(raw_recording.get_num_segments()): - # Test before `t_start` and `t_start` (`t_start` is just an offset, # should not affect duration). raw_duration = all_t_starts[segment_index][-1] - all_t_starts[segment_index][0] + ts @@ -342,7 +336,6 @@ def test_shift_times_different_segments(self, request, fixture_name, shift): # For each segment, shift the segment only and check the # times are updated as expected. for idx in range(num_segments): - scaler = idx + 2 times_recording.shift_times(shift * scaler, segment_index=idx) diff --git a/src/spikeinterface/core/tests/test_unitsaggregationsorting.py b/src/spikeinterface/core/tests/test_unitsaggregationsorting.py index c04c66d60c..f648a25407 100644 --- a/src/spikeinterface/core/tests/test_unitsaggregationsorting.py +++ b/src/spikeinterface/core/tests/test_unitsaggregationsorting.py @@ -26,7 +26,6 @@ def test_unitsaggregationsorting_spiketrains(): # test spike trains for segment_index in range(sorting1.get_num_segments()): - spiketrain1 = sorting1.get_unit_spike_train(unit_ids[1], segment_index=segment_index) assert np.all(spiketrain1 == sorting_agg.get_unit_spike_train(unit_ids[1], segment_index=segment_index)) diff --git a/src/spikeinterface/core/tests/test_unitsselectionsorting.py b/src/spikeinterface/core/tests/test_unitsselectionsorting.py index 890bc0a93e..d01f5d302b 100644 --- a/src/spikeinterface/core/tests/test_unitsselectionsorting.py +++ b/src/spikeinterface/core/tests/test_unitsselectionsorting.py @@ -42,7 +42,7 @@ def test_failure_with_non_unique_unit_ids(): seed = 10 sorting = generate_sorting(num_units=3, durations=[0.100], sampling_frequency=30000.0, seed=seed) with pytest.raises(AssertionError): - sorting2 = UnitsSelectionSorting(sorting, unit_ids=["0", "2"], renamed_unit_ids=["a", "a"]) + _ = UnitsSelectionSorting(sorting, unit_ids=["0", "2"], renamed_unit_ids=["a", "a"]) def test_compute_and_cache_spike_vector(): diff --git a/src/spikeinterface/core/tests/test_waveform_tools.py b/src/spikeinterface/core/tests/test_waveform_tools.py index 6623c92046..24784538ea 100644 --- a/src/spikeinterface/core/tests/test_waveform_tools.py +++ b/src/spikeinterface/core/tests/test_waveform_tools.py @@ -5,7 +5,7 @@ import numpy as np -from spikeinterface.core import generate_recording, generate_sorting, generate_ground_truth_recording, ms_to_samples +from spikeinterface.core import generate_recording, generate_ground_truth_recording, ms_to_samples from spikeinterface.core.waveform_tools import ( extract_waveforms_to_buffers, extract_waveforms_to_single_buffer, diff --git a/src/spikeinterface/core/tests/test_waveforms_extractor_backwards_compatibility.py b/src/spikeinterface/core/tests/test_waveforms_extractor_backwards_compatibility.py index efb3de7464..629778bfd1 100644 --- a/src/spikeinterface/core/tests/test_waveforms_extractor_backwards_compatibility.py +++ b/src/spikeinterface/core/tests/test_waveforms_extractor_backwards_compatibility.py @@ -61,17 +61,16 @@ def test_extract_waveforms(create_cache_folder): print(we_mock) for we in (we_old, we_mock): - - selected_spikes = we.get_sampled_indices(unit_id=sorting.unit_ids[0]) + _ = we.get_sampled_indices(unit_id=sorting.unit_ids[0]) # print(selected_spikes.size, selected_spikes.dtype) - wfs = we.get_waveforms(sorting.unit_ids[0]) + _ = we.get_waveforms(sorting.unit_ids[0]) # print(wfs.shape) - wfs = we.get_waveforms(sorting.unit_ids[0], force_dense=True) + _ = we.get_waveforms(sorting.unit_ids[0], force_dense=True) # print(wfs.shape) - templates = we.get_all_templates() + _ = we.get_all_templates() # print(templates.shape) # test reading old WaveformsExtractor folder diff --git a/src/spikeinterface/core/time_series_tools.py b/src/spikeinterface/core/time_series_tools.py index 5f10107677..bf94bfe82f 100644 --- a/src/spikeinterface/core/time_series_tools.py +++ b/src/spikeinterface/core/time_series_tools.py @@ -352,9 +352,9 @@ def _write_time_series_to_zarr( assert dataset_paths is not None, "Provide 'dataset_paths' to save data in zarr format" if dataset_timestamps_paths is not None: - assert ( - len(dataset_timestamps_paths) == time_series.get_num_segments() - ), "dataset_timestamps_paths should have the same length as the number of segments in the time_series" + assert len(dataset_timestamps_paths) == time_series.get_num_segments(), ( + "dataset_timestamps_paths should have the same length as the number of segments in the time_series" + ) else: dataset_timestamps_paths = [None] * time_series.get_num_segments() @@ -425,8 +425,6 @@ def _write_time_series_to_zarr( def _init_zarr_worker(time_series, zarr_datasets, dtype, buffer_megabytes, zarr_timestamps_datasets=None): - import zarr - # create a local dict per worker worker_ctx = {} worker_ctx["time_series"] = time_series diff --git a/src/spikeinterface/core/unitsaggregationsorting.py b/src/spikeinterface/core/unitsaggregationsorting.py index 3f650cd802..f18c458743 100644 --- a/src/spikeinterface/core/unitsaggregationsorting.py +++ b/src/spikeinterface/core/unitsaggregationsorting.py @@ -38,7 +38,7 @@ def __init__(self, sorting_list, renamed_unit_ids=None, sampling_frequency_max_d num_all_units = sum([sort.get_num_units() for sort in sorting_list]) if renamed_unit_ids is not None: assert len(np.unique(renamed_unit_ids)) == num_all_units, ( - "'renamed_unit_ids' doesn't have the right size" "or has duplicates!" + "'renamed_unit_ids' doesn't have the right sizeor has duplicates!" ) unit_ids = list(renamed_unit_ids) else: @@ -96,7 +96,6 @@ def __init__(self, sorting_list, renamed_unit_ids=None, sampling_frequency_max_d # Check if all the sortings have the same properties properties_set = set(np.concatenate([sorting.get_property_keys() for sorting in sorting_list])) for prop_name in properties_set: - dtypes_per_sorting = [] for sort in sorting_list: if prop_name in sort.get_property_keys(): @@ -110,7 +109,6 @@ def __init__(self, sorting_list, renamed_unit_ids=None, sampling_frequency_max_d all_property_values = [] for sort in sorting_list: - # If one of the sortings doesn't have the property, use the default missing property value if prop_name not in sort.get_property_keys(): try: @@ -118,7 +116,7 @@ def __init__(self, sorting_list, renamed_unit_ids=None, sampling_frequency_max_d sort.get_num_units(), BaseExtractor.default_missing_property_values[dtypes_per_sorting[0]], ) - except: + except Exception: warnings.warn(f"Skipping property '{prop_name}: cannot inpute missing property values.'") break else: diff --git a/src/spikeinterface/core/waveform_tools.py b/src/spikeinterface/core/waveform_tools.py index a557c52ba6..d4ea6bc0db 100644 --- a/src/spikeinterface/core/waveform_tools.py +++ b/src/spikeinterface/core/waveform_tools.py @@ -10,12 +10,9 @@ """ from pathlib import Path -import warnings import numpy as np -from spikeinterface.core.baserecording import BaseRecording - from .baserecording import BaseRecording from .job_tools import TimeSeriesChunkExecutor, _shared_job_kwargs_doc from .core_tools import make_shared_array @@ -367,7 +364,6 @@ def _worker_distribute_buffers(segment_index, start_frame, end_frame, worker_dic num_samples = recording.get_num_samples(segment_index=segment_index) if l1 > l0: - sub_spikes = in_seg_spikes[i0:i1] start = sub_spikes[0]["sample_index"] - nbefore end = sub_spikes[-1]["sample_index"] + nafter @@ -1137,7 +1133,6 @@ def _init_worker_estimate_templates( worker_dict["sparsity_mask"] = sparsity_mask from multiprocessing.shared_memory import SharedMemory - import multiprocessing shm = SharedMemory(shm_name) waveform_accumulator_per_worker = np.ndarray(shape=shape, dtype=dtype, buffer=shm.buf) @@ -1204,7 +1199,6 @@ def _worker_estimate_templates(segment_index, start_frame, end_frame, worker_dic unit_indices = sub_spikes["unit_index"] for sample_index, unit_index in zip(sample_indices, unit_indices): - # sample_index < 0 only near the segment start, near the segment end wf is shorter wf_start = max(0, -sample_index) wf = traces[sample_index + wf_start : sample_index + offset, :] @@ -1222,4 +1216,4 @@ def _worker_estimate_templates(segment_index, start_frame, end_frame, worker_dic if waveform_squared_accumulator_per_worker is not None: waveform_squared_accumulator_per_worker[ worker_index, unit_index, wf_start:wf_end, : wf.shape[1] - ] += (wf**2) + ] += wf**2 diff --git a/src/spikeinterface/core/waveforms_extractor_backwards_compatibility.py b/src/spikeinterface/core/waveforms_extractor_backwards_compatibility.py index 56f2177e70..178e6b4546 100644 --- a/src/spikeinterface/core/waveforms_extractor_backwards_compatibility.py +++ b/src/spikeinterface/core/waveforms_extractor_backwards_compatibility.py @@ -255,9 +255,9 @@ def get_sampled_indices(self, unit_id): selected_spikes = [] for segment_index in range(self.get_num_segments()): # inds = self.sorting_analyzer.get_selected_indices_in_spike_train(unit_id, segment_index) - assert self.sorting_analyzer.has_extension( - "random_spikes" - ), "get_sampled_indices() requires the 'random_spikes' extension." + assert self.sorting_analyzer.has_extension("random_spikes"), ( + "get_sampled_indices() requires the 'random_spikes' extension." + ) inds = self.sorting_analyzer.get_extension("random_spikes").get_selected_indices_in_spike_train( unit_id, segment_index ) @@ -281,9 +281,9 @@ def get_waveforms( ext = self.sorting_analyzer.get_extension("waveforms") unit_index = self.sorting.id_to_index(unit_id) - assert self.sorting_analyzer.has_extension( - "random_spikes" - ), "get_sampled_indices() requires the 'random_spikes' extension." + assert self.sorting_analyzer.has_extension("random_spikes"), ( + "get_sampled_indices() requires the 'random_spikes' extension." + ) some_spikes = self.sorting_analyzer.get_extension("random_spikes").get_random_spikes() @@ -291,9 +291,9 @@ def get_waveforms( wfs = ext.data["waveforms"][spike_mask, :, :] if sparsity is not None: - assert ( - self.sorting_analyzer.sparsity is None - ), "Waveforms are alreayd sparse! Cannot apply an additional sparsity." + assert self.sorting_analyzer.sparsity is None, ( + "Waveforms are alreayd sparse! Cannot apply an additional sparsity." + ) wfs = wfs[:, :, sparsity.mask[self.sorting.id_to_index(unit_id)]] if force_dense: @@ -475,12 +475,12 @@ def _read_old_waveforms_extractor_binary(folder, sorting): if (folder / "recording.json").exists(): try: recording = load(folder / "recording.json", base_folder=folder) - except: + except Exception: pass elif (folder / "recording.pickle").exists(): try: recording = load(folder / "recording.pickle", base_folder=folder) - except: + except Exception: pass # sorting @@ -505,7 +505,6 @@ def _read_old_waveforms_extractor_binary(folder, sorting): # need to concatenate sampled_index and order it waveform_folder = folder / "waveforms" if waveform_folder.exists(): - spikes = sorting.to_spike_vector() random_spike_mask = np.zeros(spikes.size, dtype="bool") @@ -686,7 +685,7 @@ def make_ext_params_up_to_date(ext, old_params, new_params): # try: # recording_dict = waveforms_root.attrs["recording"] # recording = load(recording_dict, base_folder=folder) -# except: +# except Exception: # pass # # sorting diff --git a/src/spikeinterface/core/zarr_tools.py b/src/spikeinterface/core/zarr_tools.py index 41ff57a358..a12c4ceec2 100644 --- a/src/spikeinterface/core/zarr_tools.py +++ b/src/spikeinterface/core/zarr_tools.py @@ -61,9 +61,9 @@ def adjust_chunks_shards_and_job_kwargs( if shards is not None: assert len(shards) == len(chunks), "Shards and chunks must have the same number of dimensions" for dim in range(len(chunks)): - assert ( - shards[dim] >= chunks[dim] and shards[dim] % chunks[dim] == 0 - ), "Shard size must be a multiple of chunk size" + assert shards[dim] >= chunks[dim] and shards[dim] % chunks[dim] == 0, ( + "Shard size must be a multiple of chunk size" + ) # When sharding is used, chunk_size in job_kwargs is used to determine the number of samples per chunk to # write in each job. Each process will write all chunks in a shard. job_kwargs["chunk_size"] = shards[0] diff --git a/src/spikeinterface/core/zarrextractors.py b/src/spikeinterface/core/zarrextractors.py index 2889a47a83..9f06b80e3e 100644 --- a/src/spikeinterface/core/zarrextractors.py +++ b/src/spikeinterface/core/zarrextractors.py @@ -13,7 +13,6 @@ from .core_tools import ( define_function_from_class, check_json, - is_path_remote, retrieve_importing_provenance, is_path_remote, ) @@ -165,9 +164,9 @@ def __init__( cr_by_segment = {} for segment_index in range(num_segments): trace_name = f"traces_seg{segment_index}" - assert ( - len(channel_ids) == self._root[trace_name].shape[1] - ), f"Segment {segment_index} has the wrong number of channels!" + assert len(channel_ids) == self._root[trace_name].shape[1], ( + f"Segment {segment_index} has the wrong number of channels!" + ) time_kwargs = {} time_vector = self._root.get(f"times_seg{segment_index}", None) @@ -944,7 +943,7 @@ def add_recording_to_zarr_group( channel_ids = recording.channel_ids if channel_ids.dtype.kind in ("U", "S"): channel_ids = channel_ids.astype("T") - arr = zarr_group.create_array(name="channel_ids", data=channel_ids, compressors=None) + _ = zarr_group.create_array(name="channel_ids", data=channel_ids, compressors=None) dataset_paths = [f"traces_seg{i}" for i in range(recording.get_num_segments())] dataset_timestamps_paths: list | None = None if any(recording.has_time_vector(i) for i in range(recording.get_num_segments())): diff --git a/src/spikeinterface/curation/auto_merge.py b/src/spikeinterface/curation/auto_merge.py index a31b841882..17a3eb28af 100644 --- a/src/spikeinterface/curation/auto_merge.py +++ b/src/spikeinterface/curation/auto_merge.py @@ -227,7 +227,6 @@ def compute_merge_unit_groups( outs = dict() for step in steps: - if step in _required_extensions: for ext in _required_extensions[step]: if sorting_analyzer.has_extension(ext): @@ -374,7 +373,6 @@ def compute_merge_unit_groups( outs["pairs_decreased_score"] = pairs_decreased_score elif step == "slay_score": - M_ij = compute_slay_matrix( sorting_analyzer, params["k1"], params["k2"], templates_diff=outs["templates_diff"], pair_mask=pair_mask ) @@ -641,7 +639,6 @@ def auto_merge_units( } for to_launch, params in zip(to_be_launched, steps_params): - if launch_mode == "presets": compute_merge_kwargs = {"preset": to_launch} elif launch_mode == "steps": @@ -802,7 +799,7 @@ def smooth_correlogram(correlograms, bins, sigma_smooth_ms=0.6): """ Smooths cross-correlogram with a Gaussian kernel. """ - from scipy.signal import fftconvolve, butter, filtfilt + from scipy.signal import fftconvolve # OLD implementation : smooth correlogram by low pass filter # b, a = butter(N=2, Wn = correlogram_low_pass / (1e3 / bin_ms /2), btype="low") @@ -1432,7 +1429,6 @@ def compute_xcorr_and_rp(sorting_analyzer: SortingAnalyzer, pair_mask: np.ndarra for unit_index_1, _ in enumerate(sorting_analyzer.unit_ids): for unit_index_2, _ in enumerate(sorting_analyzer.unit_ids): - # Don't waste time computing the other metrics if units not candidates merges if not pair_mask[unit_index_1, unit_index_2]: continue diff --git a/src/spikeinterface/curation/bombcell_curation.py b/src/spikeinterface/curation/bombcell_curation.py index f41b25f8e8..a16a1904c2 100644 --- a/src/spikeinterface/curation/bombcell_curation.py +++ b/src/spikeinterface/curation/bombcell_curation.py @@ -245,9 +245,9 @@ def bombcell_label_units( if external_metrics is None: raise ValueError("Either sorting_analyzer or external_metrics must be provided") if isinstance(external_metrics, list): - assert all( - isinstance(df, pd.DataFrame) for df in external_metrics - ), "All items in external_metrics must be DataFrames" + assert all(isinstance(df, pd.DataFrame) for df in external_metrics), ( + "All items in external_metrics must be DataFrames" + ) combined_metrics = pd.concat(external_metrics, axis=1) else: combined_metrics = external_metrics diff --git a/src/spikeinterface/curation/curation_format.py b/src/spikeinterface/curation/curation_format.py index cf5b952376..84ae86ed47 100644 --- a/src/spikeinterface/curation/curation_format.py +++ b/src/spikeinterface/curation/curation_format.py @@ -190,12 +190,12 @@ def apply_curation( curated_sorting_or_analyzer : Sorting | SortingAnalyzer The curated object. """ - assert isinstance( - sorting_or_analyzer, (BaseSorting, SortingAnalyzer) - ), f"`sorting_or_analyzer` must be a Sorting or a SortingAnalyzer, not an object of type {type(sorting_or_analyzer)}" - assert isinstance( - curation_dict_or_model, (dict, list, Curation, SequentialCuration) - ), f"`curation_dict_or_model` must be a dict, Curation or a SequentialCuration not an object of type {type(curation_dict_or_model)}" + assert isinstance(sorting_or_analyzer, (BaseSorting, SortingAnalyzer)), ( + f"`sorting_or_analyzer` must be a Sorting or a SortingAnalyzer, not an object of type {type(sorting_or_analyzer)}" + ) + assert isinstance(curation_dict_or_model, (dict, list, Curation, SequentialCuration)), ( + f"`curation_dict_or_model` must be a dict, Curation or a SequentialCuration not an object of type {type(curation_dict_or_model)}" + ) if isinstance(curation_dict_or_model, dict): curation_model = Curation(**curation_dict_or_model) elif isinstance(curation_dict_or_model, list): diff --git a/src/spikeinterface/curation/curation_model.py b/src/spikeinterface/curation/curation_model.py index 128bc0e6ba..f0e915aa02 100644 --- a/src/spikeinterface/curation/curation_model.py +++ b/src/spikeinterface/curation/curation_model.py @@ -1,7 +1,6 @@ -import warnings from typing import Literal, List from itertools import chain, combinations -from pydantic import BaseModel, Field, model_validator, field_validator, field_serializer +from pydantic import BaseModel, Field, model_validator, field_validator import numpy as np @@ -504,7 +503,6 @@ def validate_sequential_curation(self): ) for curation_index in range(len(self.curation_steps))[:-1]: - curation_1 = self.curation_steps[curation_index] curation_2 = self.curation_steps[curation_index + 1] @@ -513,7 +511,7 @@ def validate_sequential_curation(self): if not (set(previous_model_final_ids) == set(next_model_initial_ids)): raise ValueError( - f"The initial unit_ids of curation {curation_index+1} do not match the final unit_ids of curation {curation_index}." + f"The initial unit_ids of curation {curation_index + 1} do not match the final unit_ids of curation {curation_index}." ) return self diff --git a/src/spikeinterface/curation/curationsorting.py b/src/spikeinterface/curation/curationsorting.py index 1e0e8fc1d0..52b879fb64 100644 --- a/src/spikeinterface/curation/curationsorting.py +++ b/src/spikeinterface/curation/curationsorting.py @@ -119,7 +119,7 @@ def merge(self, units_to_merge, new_unit_id=None, delta_time_ms=0.4): if new_unit_id is None: new_unit_id = self._get_unused_id()[0] elif new_unit_id not in units_to_merge: - assert new_unit_id not in current_sorting.unit_ids, f"new_unit_id already exists!" + assert new_unit_id not in current_sorting.unit_ids, "new_unit_id already exists!" new_sorting = MergeUnitsSorting( sorting=current_sorting, units_to_merge=units_to_merge, diff --git a/src/spikeinterface/curation/mergeunitssorting.py b/src/spikeinterface/curation/mergeunitssorting.py index 314a1a417e..4d8fdddb82 100644 --- a/src/spikeinterface/curation/mergeunitssorting.py +++ b/src/spikeinterface/curation/mergeunitssorting.py @@ -59,7 +59,7 @@ def __init__(self, sorting, units_to_merge, new_unit_ids=None, properties_policy # some checks for ids in units_to_merge: assert all(u in parents_unit_ids for u in ids), "units to merge are not all in parent" - assert properties_policy in ("keep", "remove"), "properties_policy must be " "keep" " or " "remove" "" + assert properties_policy in ("keep", "remove"), "properties_policy must be keep or remove" # new units are put at the end unit_ids = keep_unit_ids + list(new_unit_ids) diff --git a/src/spikeinterface/curation/model_based_curation.py b/src/spikeinterface/curation/model_based_curation.py index 69c7f75419..b1f1184d16 100644 --- a/src/spikeinterface/curation/model_based_curation.py +++ b/src/spikeinterface/curation/model_based_curation.py @@ -1,7 +1,6 @@ from pathlib import Path import json import warnings -import re from packaging.version import parse from copy import deepcopy @@ -141,7 +140,7 @@ def predict_labels( label_conversion = {} for key, value in string_label_conversion.items(): label_conversion[int(key)] = value - except: + except Exception: warnings.warn("Could not find `label_conversion` key in `model_info.json` file") metrics = _format_metric_dataframe(metrics) @@ -190,13 +189,11 @@ def _check_params_for_classification(self, enforce_metric_params=False, model_in metric_extensions = [self.sorting_analyzer.get_extension(extension_name) for extension_name in extension_names] for metric_extension, extension_name in zip(metric_extensions, extension_names): - # remove the 's' at the end of the extension name extension_name = extension_name[:-1] model_extension_params = model_info["metric_params"].get(extension_name + "_params") if metric_extension is not None and model_extension_params is not None: - metric_params = metric_extension.params["metric_params"] inconsistent_metrics = [] @@ -450,7 +447,6 @@ def _load_model_from_folder(model_folder=None, model_name=None, trust_model=Fals """ import skops.io as skio - from skops.io.exceptions import UntrustedTypesFoundException folder = Path(model_folder) assert folder.is_dir(), f"The folder {folder}, does not exist." diff --git a/src/spikeinterface/curation/remove_duplicated_spikes.py b/src/spikeinterface/curation/remove_duplicated_spikes.py index f8716ba54a..e494e43ddb 100644 --- a/src/spikeinterface/curation/remove_duplicated_spikes.py +++ b/src/spikeinterface/curation/remove_duplicated_spikes.py @@ -80,9 +80,9 @@ def get_unit_spike_train(self, unit_id, start_frame: int | None = None, end_fram spike_train = np.delete(spike_train, self._duplicated_spikes[unit_id]) - if start_frame == None: + if start_frame is None: start_frame = 0 - if end_frame == None: + if end_frame is None: end_frame = spike_train[-1] if len(spike_train) > 0 else 0 start = np.searchsorted(spike_train, start_frame, side="left") diff --git a/src/spikeinterface/curation/remove_excess_spikes.py b/src/spikeinterface/curation/remove_excess_spikes.py index a2b8ebb20a..13c2c761f4 100644 --- a/src/spikeinterface/curation/remove_excess_spikes.py +++ b/src/spikeinterface/curation/remove_excess_spikes.py @@ -25,9 +25,9 @@ class RemoveExcessSpikesSorting(BaseSorting): def __init__(self, sorting: BaseSorting, recording: BaseRecording) -> None: super().__init__(sorting.get_sampling_frequency(), sorting.unit_ids) - assert ( - sorting.get_num_segments() == recording.get_num_segments() - ), "The sorting and recording objects must have the same number of samples!" + assert sorting.get_num_segments() == recording.get_num_segments(), ( + "The sorting and recording objects must have the same number of samples!" + ) self._parent_sorting = sorting self._num_samples = np.empty(sorting.get_num_segments(), dtype=np.int64) diff --git a/src/spikeinterface/curation/sortingview_curation.py b/src/spikeinterface/curation/sortingview_curation.py index 657dcb9cde..7cde276936 100644 --- a/src/spikeinterface/curation/sortingview_curation.py +++ b/src/spikeinterface/curation/sortingview_curation.py @@ -74,7 +74,7 @@ def apply_sortingview_curation( try: curation_dict = ka.load_json(uri=uri_or_json) - except: + except Exception: raise Exception(f"Could not retrieve curation from SortingView uri: {uri_or_json}") if curation_dict is None: diff --git a/src/spikeinterface/curation/splitunitsorting.py b/src/spikeinterface/curation/splitunitsorting.py index 087a808b02..a7af7c8994 100644 --- a/src/spikeinterface/curation/splitunitsorting.py +++ b/src/spikeinterface/curation/splitunitsorting.py @@ -38,9 +38,9 @@ def __init__(self, sorting, split_unit_id, indices_list, new_unit_ids=None, prop if type(indices_list) is not list: indices_list = [indices_list] parents_unit_ids = sorting.unit_ids - assert sorting.get_num_segments() == len( - indices_list - ), "The length of indices_list must be the same as parent_sorting.get_num_segments" + assert sorting.get_num_segments() == len(indices_list), ( + "The length of indices_list must be the same as parent_sorting.get_num_segments" + ) split_unit_indices = np.unique([np.unique(v) for v in indices_list]) tot_splits = len(split_unit_indices) unchanged_units = parents_unit_ids[parents_unit_ids != split_unit_id] @@ -63,12 +63,10 @@ def __init__(self, sorting, split_unit_id, indices_list, new_unit_ids=None, prop assert len(new_unit_ids) <= tot_splits, "indices_list has more id indices than the length of new_unit_ids" assert split_unit_id in parents_unit_ids, "Unit to split must be in parent sorting" - assert properties_policy == "keep" or properties_policy == "remove", ( - "properties_policy must be " "keep" " or " "remove" "" + assert properties_policy == "keep" or properties_policy == "remove", "properties_policy must be keep or remove" + assert not any(np.isin(new_unit_ids, unchanged_units)), ( + "new_unit_ids should be new unit ids or no more than one unit id can be found in split_unit_id" ) - assert not any( - np.isin(new_unit_ids, unchanged_units) - ), "new_unit_ids should be new unit ids or no more than one unit id can be found in split_unit_id" sampling_frequency = sorting.get_sampling_frequency() units_ids = np.concatenate([unchanged_units, new_unit_ids]) @@ -76,9 +74,9 @@ def __init__(self, sorting, split_unit_id, indices_list, new_unit_ids=None, prop self._parent_sorting = sorting BaseSorting.__init__(self, sampling_frequency, units_ids) - assert all( - np.isin(unchanged_units, self.unit_ids) - ), "new_unit_ids should have a compatible format with the parent ids" + assert all(np.isin(unchanged_units, self.unit_ids)), ( + "new_unit_ids should have a compatible format with the parent ids" + ) for si, parent_segment in enumerate(self._parent_sorting.segments): sub_segment = SplitSortingUnitSegment(parent_segment, split_unit_id, indices_zero_based[si], new_unit_ids) diff --git a/src/spikeinterface/curation/tests/common.py b/src/spikeinterface/curation/tests/common.py index 20dbd2f1f2..e69de29bb2 100644 --- a/src/spikeinterface/curation/tests/common.py +++ b/src/spikeinterface/curation/tests/common.py @@ -1,124 +0,0 @@ -import pytest - -from spikeinterface.core import generate_ground_truth_recording, create_sorting_analyzer, aggregate_units -from spikeinterface.core.generate import inject_some_split_units -from spikeinterface.curation import train_model -from pathlib import Path - -extensions = [ - "noise_levels", - "random_spikes", - "waveforms", - "templates", - "unit_locations", - "spike_amplitudes", - "spike_locations", - "correlograms", - "template_similarity", -] - - -def make_sorting_analyzer(sparse=True, num_units=5, durations=[300.0]): - recording, sorting = generate_ground_truth_recording( - durations=durations, - sampling_frequency=30000.0, - num_channels=4, - num_units=num_units, - generate_sorting_kwargs=dict(firing_rates=20.0, refractory_period_ms=4.0), - noise_kwargs=dict(noise_levels=5.0, strategy="on_the_fly"), - seed=2205, - ) - - sorting_analyzer = create_sorting_analyzer( - sorting=sorting, - recording=recording, - format="memory", - sparse=sparse, - ) - sorting_analyzer.compute(extensions) - - return sorting_analyzer - - -def make_sorting_analyzer_with_splits(sorting_analyzer, num_unit_splitted=1, num_split=2): - sorting = sorting_analyzer.sorting - - split_ids = sorting.unit_ids[:num_unit_splitted] - sorting_with_split, other_ids = inject_some_split_units( - sorting, - split_ids=split_ids, - num_split=num_split, - output_ids=True, - seed=42, - ) - - sorting_analyzer_with_splits = create_sorting_analyzer( - sorting=sorting_with_split, recording=sorting_analyzer.recording, format="memory", sparse=True - ) - sorting_analyzer_with_splits.compute(extensions) - - return sorting_analyzer_with_splits, num_unit_splitted, other_ids - - -@pytest.fixture(scope="module") -def sorting_analyzer_for_curation(): - return make_sorting_analyzer(sparse=True) - - -@pytest.fixture(scope="module") -def sorting_analyzer_for_unitrefine_curation(): - """Makes an analyzer whose first 10 units are good normal units, and 10 which are noise. We make them - noise by using a spike trains which are uncorrelated with the recording for `sorting2`.""" - - recording, sorting_1 = generate_ground_truth_recording(num_channels=4, seed=1, num_units=6) - _, sorting_2 = generate_ground_truth_recording(num_channels=4, seed=2, num_units=6) - both_sortings = aggregate_units([sorting_1, sorting_2]) - analyzer = create_sorting_analyzer(sorting=both_sortings, recording=recording) - analyzer.compute(["random_spikes", "noise_levels", "templates"]) - return analyzer - - -@pytest.fixture(scope="module") -def sorting_analyzer_multi_segment_for_curation(): - return make_sorting_analyzer(sparse=True, durations=[50.0, 30.0]) - - -@pytest.fixture(scope="module") -def sorting_analyzer_with_splits(): - sorting_analyzer = make_sorting_analyzer(sparse=True, durations=[50.0]) - return make_sorting_analyzer_with_splits(sorting_analyzer) - - -@pytest.fixture(scope="module") -def trained_pipeline_path(sorting_analyzer_for_unitrefine_curation): - """ - Makes a model saved at "./trained_pipeline" which will be used by other tests in the module. - If the model already exists, this function does nothing. - """ - trained_model_folder = Path(__file__).parent / Path("trained_pipeline") - if trained_model_folder.is_dir(): - yield trained_model_folder - else: - analyzer = sorting_analyzer_for_unitrefine_curation - analyzer.compute( - { - "quality_metrics": {"metric_names": ["snr"]}, - "template_metrics": {"metric_names": ["half_width", "peak_to_trough_duration", "number_of_peaks"]}, - } - ) - train_model( - analyzers=[analyzer] * 5, - folder=trained_model_folder, - labels=[[1] * 6 + [0] * 6] * 5, - imputation_strategies=["median"], - scaling_techniques=["standard_scaler"], - classifiers=["RandomForestClassifier"], - overwrite=True, - search_kwargs={"cv": 3, "scoring": "balanced_accuracy", "n_iter": 2}, - ) - yield trained_model_folder - - -if __name__ == "__main__": - sorting_analyzer = make_sorting_analyzer(sparse=False) - print(sorting_analyzer) diff --git a/src/spikeinterface/curation/tests/conftest.py b/src/spikeinterface/curation/tests/conftest.py new file mode 100644 index 0000000000..ad8c42a884 --- /dev/null +++ b/src/spikeinterface/curation/tests/conftest.py @@ -0,0 +1,120 @@ +import pytest +from pathlib import Path + +from spikeinterface.core import generate_ground_truth_recording, create_sorting_analyzer, aggregate_units +from spikeinterface.curation import train_model +from spikeinterface.core.generate import inject_some_split_units + + +extensions = [ + "noise_levels", + "random_spikes", + "waveforms", + "templates", + "unit_locations", + "spike_amplitudes", + "spike_locations", + "correlograms", + "template_similarity", +] + + +def make_sorting_analyzer(sparse=True, num_units=5, durations=[300.0]): + recording, sorting = generate_ground_truth_recording( + durations=durations, + sampling_frequency=30000.0, + num_channels=4, + num_units=num_units, + generate_sorting_kwargs=dict(firing_rates=20.0, refractory_period_ms=4.0), + noise_kwargs=dict(noise_levels=5.0, strategy="on_the_fly"), + seed=2205, + ) + + sorting_analyzer = create_sorting_analyzer( + sorting=sorting, + recording=recording, + format="memory", + sparse=sparse, + ) + sorting_analyzer.compute(extensions) + + return sorting_analyzer + + +def make_sorting_analyzer_with_splits(sorting_analyzer, num_unit_splitted=1, num_split=2): + sorting = sorting_analyzer.sorting + + split_ids = sorting.unit_ids[:num_unit_splitted] + sorting_with_split, other_ids = inject_some_split_units( + sorting, + split_ids=split_ids, + num_split=num_split, + output_ids=True, + seed=42, + ) + + sorting_analyzer_with_splits = create_sorting_analyzer( + sorting=sorting_with_split, recording=sorting_analyzer.recording, format="memory", sparse=True + ) + sorting_analyzer_with_splits.compute(extensions) + + return sorting_analyzer_with_splits, num_unit_splitted, other_ids + + +@pytest.fixture(scope="module") +def sorting_analyzer_for_curation(): + return make_sorting_analyzer(sparse=True) + + +@pytest.fixture(scope="module") +def sorting_analyzer_for_unitrefine_curation(): + """Makes an analyzer whose first 10 units are good normal units, and 10 which are noise. We make them + noise by using a spike trains which are uncorrelated with the recording for `sorting2`.""" + + recording, sorting_1 = generate_ground_truth_recording(num_channels=4, seed=1, num_units=6) + _, sorting_2 = generate_ground_truth_recording(num_channels=4, seed=2, num_units=6) + both_sortings = aggregate_units([sorting_1, sorting_2]) + analyzer = create_sorting_analyzer(sorting=both_sortings, recording=recording) + analyzer.compute(["random_spikes", "noise_levels", "templates"]) + return analyzer + + +@pytest.fixture(scope="module") +def sorting_analyzer_multi_segment_for_curation(): + return make_sorting_analyzer(sparse=True, durations=[50.0, 30.0]) + + +@pytest.fixture(scope="module") +def sorting_analyzer_with_splits(): + sorting_analyzer = make_sorting_analyzer(sparse=True, durations=[50.0]) + return make_sorting_analyzer_with_splits(sorting_analyzer) + + +@pytest.fixture(scope="module") +def trained_pipeline_path(sorting_analyzer_for_unitrefine_curation): + """ + Makes a model saved at "./trained_pipeline" which will be used by other tests in the module. + If the model already exists, this function does nothing. + """ + trained_model_folder = Path(__file__).parent / Path("trained_pipeline") + if trained_model_folder.is_dir(): + yield trained_model_folder + else: + analyzer = sorting_analyzer_for_unitrefine_curation + analyzer.compute( + { + "quality_metrics": {"metric_names": ["snr"]}, + "template_metrics": {"metric_names": ["half_width", "peak_to_trough_duration", "number_of_peaks"]}, + } + ) + train_model( + analyzers=[analyzer] * 5, + folder=trained_model_folder, + labels=[[1] * 6 + [0] * 6] * 5, + imputation_strategies=["median"], + scaling_techniques=["standard_scaler"], + classifiers=["RandomForestClassifier"], + overwrite=True, + search_kwargs={"cv": 3, "scoring": "balanced_accuracy", "n_iter": 2}, + ) + yield trained_model_folder diff --git a/src/spikeinterface/curation/tests/test_auto_merge.py b/src/spikeinterface/curation/tests/test_auto_merge.py index cab508f4fb..05d5a22994 100644 --- a/src/spikeinterface/curation/tests/test_auto_merge.py +++ b/src/spikeinterface/curation/tests/test_auto_merge.py @@ -6,14 +6,6 @@ from spikeinterface.generation import split_sorting_by_times -from spikeinterface.curation.tests.common import ( - make_sorting_analyzer, - sorting_analyzer_for_curation, - sorting_analyzer_with_splits, - sorting_analyzer_multi_segment_for_curation, -) - - @pytest.mark.parametrize( "preset", ["x_contaminations", "feature_neighbors", "temporal_splits", "similarity_correlograms", "slay", None] ) @@ -62,7 +54,7 @@ def test_compute_merge_unit_groups_multi_segment(sorting_analyzer_multi_segment_ sorting_analyzer = sorting_analyzer_multi_segment_for_curation print(sorting_analyzer) - merge_unit_groups = compute_merge_unit_groups( + _ = compute_merge_unit_groups( sorting_analyzer, preset=preset, ) diff --git a/src/spikeinterface/curation/tests/test_bombcell_curation.py b/src/spikeinterface/curation/tests/test_bombcell_curation.py index 768d28c143..6a3d9f2c6c 100644 --- a/src/spikeinterface/curation/tests/test_bombcell_curation.py +++ b/src/spikeinterface/curation/tests/test_bombcell_curation.py @@ -1,6 +1,4 @@ import pytest -from pathlib import Path -from spikeinterface.curation.tests.common import sorting_analyzer_for_curation, trained_pipeline_path from spikeinterface.curation.bombcell_curation import bombcell_label_units @@ -31,7 +29,6 @@ def test_bombcell_label_units_with_external_metrics(sorting_analyzer_with_metric sorting_analyzer = sorting_analyzer_with_metrics # Create external metrics DataFrame - import pandas as pd metrics_df = sorting_analyzer.get_metrics_extension_data() diff --git a/src/spikeinterface/curation/tests/test_curation_format.py b/src/spikeinterface/curation/tests/test_curation_format.py index 40e0a9b2b7..e3d6dcb262 100644 --- a/src/spikeinterface/curation/tests/test_curation_format.py +++ b/src/spikeinterface/curation/tests/test_curation_format.py @@ -234,7 +234,6 @@ def test_to_from_json_file(tmp_path): for curation_index, curation_dict in enumerate( [curation_ids_int, curation_ids_str, curation_ids_int_dict, curation_with_splits] ): - temp_filepath = tmp_path / f"data_{curation_index}.json" with open(temp_filepath, "w") as f: @@ -331,7 +330,6 @@ def test_apply_curation_with_split(): def test_apply_curation_with_split_multi_segment(): recording, sorting = generate_ground_truth_recording(durations=[10.0, 10.0], num_units=9, seed=2205) sorting = sorting.rename_units(np.array([1, 2, 3, 6, 10, 14, 20, 31, 42])) - analyzer = create_sorting_analyzer(sorting, recording, sparse=False) num_segments = sorting.get_num_segments() curation_with_splits_multi_segment = curation_with_splits.copy() diff --git a/src/spikeinterface/curation/tests/test_curation_model.py b/src/spikeinterface/curation/tests/test_curation_model.py index 48102096a6..5005cfa3fc 100644 --- a/src/spikeinterface/curation/tests/test_curation_model.py +++ b/src/spikeinterface/curation/tests/test_curation_model.py @@ -1,7 +1,6 @@ import pytest from pydantic import ValidationError -import numpy as np from spikeinterface.curation.curation_model import Curation, SequentialCuration, LabelDefinition diff --git a/src/spikeinterface/curation/tests/test_curationsorting.py b/src/spikeinterface/curation/tests/test_curationsorting.py index cca3407ef5..b1a063eac5 100644 --- a/src/spikeinterface/curation/tests/test_curationsorting.py +++ b/src/spikeinterface/curation/tests/test_curationsorting.py @@ -52,13 +52,12 @@ def test_split_merge(): merged = MergeUnitsSorting(splitted, units_to_merge=[[8, 10]], new_unit_ids=[4], properties_policy="keep") for i in range(len(spikestimes)): - assert ( - all(parent_sort.get_unit_spike_train(4, segment_index=i) == merged.get_unit_spike_train(4, segment_index=i)) - == True + assert all( + parent_sort.get_unit_spike_train(4, segment_index=i) == merged.get_unit_spike_train(4, segment_index=i) ), "splir or merge error" - assert parent_sort.get_unit_property(4, "someprop") == merged.get_unit_property( - 4, "someprop" - ), "property wasn't kept" + assert parent_sort.get_unit_property(4, "someprop") == merged.get_unit_property(4, "someprop"), ( + "property wasn't kept" + ) # 1d assert merged.get_unit_property(4, "some_str_prop") == "", "error with array property" assert merged.get_unit_property(4, "some_prop_to_keep") == 1, "error with array property" @@ -67,9 +66,9 @@ def test_split_merge(): # 2d assert np.array_equal(merged.get_unit_property(4, "some_array_prop_to_keep"), [1, 1]), "error with array property" assert np.all(np.isnan(merged.get_unit_property(4, "some_array_prop_to_remove"))), "error with array property" - assert np.array_equal( - merged.get_unit_property(4, "some_array_prop_to_none"), [None, None] - ), "error with array property" + assert np.array_equal(merged.get_unit_property(4, "some_array_prop_to_none"), [None, None]), ( + "error with array property" + ) merged_with_dups = MergeUnitsSorting( parent_sort, new_unit_ids=[8], units_to_merge=[[0, 1]], properties_policy="remove", delta_time_ms=0.5 @@ -139,7 +138,7 @@ def test_curation(): ) # Test with empty sorting - empty_sorting = CurationSorting(NumpySorting.from_unit_dict({}, parent_sort.sampling_frequency)) + _ = CurationSorting(NumpySorting.from_unit_dict({}, parent_sort.sampling_frequency)) if __name__ == "__main__": diff --git a/src/spikeinterface/curation/tests/test_model_based_curation.py b/src/spikeinterface/curation/tests/test_model_based_curation.py index 800817cdda..8563c8130e 100644 --- a/src/spikeinterface/curation/tests/test_model_based_curation.py +++ b/src/spikeinterface/curation/tests/test_model_based_curation.py @@ -1,7 +1,6 @@ import pytest from pathlib import Path -from spikeinterface.curation.tests.common import sorting_analyzer_for_unitrefine_curation, trained_pipeline_path from spikeinterface.curation.model_based_curation import ModelBasedClassification from spikeinterface.curation import ( model_based_label_units, @@ -97,9 +96,7 @@ def test_model_based_classification_get_metrics_for_classification( all_metric_names, all_metric_columns, qm_names, tm_names = required_metrics - model_based_classification = ModelBasedClassification( - sorting_analyzer=sorting_analyzer_for_unitrefine_curation, pipeline=model[0] - ) + _ = ModelBasedClassification(sorting_analyzer=sorting_analyzer_for_unitrefine_curation, pipeline=model[0]) # Compute some (but not all) of the required metrics in sorting_analyzer, should still error sorting_analyzer_for_unitrefine_curation.compute("quality_metrics", metric_names=[all_metric_names[0]]) @@ -158,7 +155,7 @@ def test_predict_labels_with_phy_export(sorting_analyzer_for_unitrefine_curation model_based_classification = ModelBasedClassification( sorting_analyzer=sorting_analyzer_for_unitrefine_curation, pipeline=model[0] ) - classified_units = model_based_classification.predict_labels(export_to_phy=True, phy_folder=phy_folder) + _ = model_based_classification.predict_labels(export_to_phy=True, phy_folder=phy_folder) # Check that the cluster_prediction.tsv file was created in the specified phy_folder assert (phy_folder / "cluster_prediction.tsv").exists() diff --git a/src/spikeinterface/curation/tests/test_remove_redundant.py b/src/spikeinterface/curation/tests/test_remove_redundant.py index 43a7cd1951..4e74a738a5 100644 --- a/src/spikeinterface/curation/tests/test_remove_redundant.py +++ b/src/spikeinterface/curation/tests/test_remove_redundant.py @@ -2,8 +2,6 @@ from spikeinterface import create_sorting_analyzer from spikeinterface.core.generate import inject_some_duplicate_units -from spikeinterface.curation.tests.common import make_sorting_analyzer, sorting_analyzer_for_curation - from spikeinterface.curation import remove_redundant_units @@ -22,8 +20,3 @@ def test_remove_redundant_units(sorting_analyzer_for_curation): for remove_strategy in ("max_spikes", "minimum_shift", "highest_amplitude"): sorting_clean = remove_redundant_units(sorting_analyzer, remove_strategy=remove_strategy) assert np.all(sorting_clean.unit_ids == sorting.unit_ids) - - -if __name__ == "__main__": - sorting_analyzer = make_sorting_analyzer(sparse=True) - test_remove_redundant_units(sorting_analyzer) diff --git a/src/spikeinterface/curation/tests/test_sortingview_curation.py b/src/spikeinterface/curation/tests/test_sortingview_curation.py index 9b1305205a..22ce09f7b8 100644 --- a/src/spikeinterface/curation/tests/test_sortingview_curation.py +++ b/src/spikeinterface/curation/tests/test_sortingview_curation.py @@ -4,16 +4,8 @@ import importlib.util import numpy as np -import spikeinterface as si from spikeinterface.core import generate_sorting import spikeinterface.extractors as se -from spikeinterface import set_global_tmp_folder -from spikeinterface.postprocessing import ( - compute_correlograms, - compute_unit_locations, - compute_template_similarity, - compute_spike_amplitudes, -) from spikeinterface.curation import apply_sortingview_curation parent_folder = Path(__file__).parent @@ -103,7 +95,6 @@ def test_sha1_curation(): assert "accept" in sorting_curated_sha1.get_property_keys() assert "mua" in sorting_curated_sha1.get_property_keys() assert "artifact" in sorting_curated_sha1.get_property_keys() - unit_ids = sorting_curated_sha1.unit_ids sorting_curated_sha1_accepted = apply_sortingview_curation(sorting, uri_or_json=sha1_uri, include_labels=["accept"]) sorting_curated_sha1_mua = apply_sortingview_curation(sorting, uri_or_json=sha1_uri, exclude_labels=["mua"]) sorting_curated_sha1_art_mua = apply_sortingview_curation( @@ -263,7 +254,7 @@ def test_json_no_merge_curation(): sorting = sorting.rename_units(new_unit_ids=unit_ids_as_int) json_file = parent_folder / "sv-sorting-curation-no-merge.json" - sorting_curated = apply_sortingview_curation(sorting, uri_or_json=json_file) + _ = apply_sortingview_curation(sorting, uri_or_json=json_file) if __name__ == "__main__": diff --git a/src/spikeinterface/curation/tests/test_train_manual_curation.py b/src/spikeinterface/curation/tests/test_train_manual_curation.py index 21df26128a..65c0be3947 100644 --- a/src/spikeinterface/curation/tests/test_train_manual_curation.py +++ b/src/spikeinterface/curation/tests/test_train_manual_curation.py @@ -1,9 +1,10 @@ import pytest import numpy as np -import tempfile, csv +import tempfile +import csv from pathlib import Path -from spikeinterface.curation.tests.common import make_sorting_analyzer +from spikeinterface.curation.tests.conftest import make_sorting_analyzer from spikeinterface.curation.train_manual_curation import CurationTrainer, train_model diff --git a/src/spikeinterface/curation/tests/test_unitrefine_curation.py b/src/spikeinterface/curation/tests/test_unitrefine_curation.py index 314fcb5878..7c8fb29705 100644 --- a/src/spikeinterface/curation/tests/test_unitrefine_curation.py +++ b/src/spikeinterface/curation/tests/test_unitrefine_curation.py @@ -1,6 +1,5 @@ import pytest -from spikeinterface.curation.tests.common import sorting_analyzer_for_unitrefine_curation, trained_pipeline_path from spikeinterface.curation import unitrefine_label_units @@ -49,7 +48,7 @@ def test_unitrefine_label_units_hf(sorting_analyzer_for_unitrefine_curation): # test passing none with pytest.raises(ValueError): - labels = unitrefine_label_units( + _ = unitrefine_label_units( sorting_analyzer_for_unitrefine_curation, noise_neural_classifier=None, sua_mua_classifier=None, @@ -57,14 +56,14 @@ def test_unitrefine_label_units_hf(sorting_analyzer_for_unitrefine_curation): # test warnings when unexpected labels are returned with pytest.warns(UserWarning): - labels = unitrefine_label_units( + _ = unitrefine_label_units( sorting_analyzer_for_unitrefine_curation, noise_neural_classifier="SpikeInterface/UnitRefine_sua_mua_classifier_lightweight", sua_mua_classifier=None, ) with pytest.warns(UserWarning): - labels = unitrefine_label_units( + _ = unitrefine_label_units( sorting_analyzer_for_unitrefine_curation, noise_neural_classifier=None, sua_mua_classifier="SpikeInterface/UnitRefine_noise_neural_classifier_lightweight", @@ -79,13 +78,13 @@ def test_unitrefine_label_units_with_local_models(sorting_analyzer_for_unitrefin sorting_analyzer_for_unitrefine_curation.compute("quality_metrics") # test passing model folder - labels = unitrefine_label_units( + _ = unitrefine_label_units( sorting_analyzer_for_unitrefine_curation, noise_neural_classifier=trained_pipeline_path, ) # test passing model folder - labels = unitrefine_label_units( + _ = unitrefine_label_units( sorting_analyzer_for_unitrefine_curation, noise_neural_classifier=trained_pipeline_path / "best_model.skops", ) diff --git a/src/spikeinterface/curation/threshold_metrics_curation.py b/src/spikeinterface/curation/threshold_metrics_curation.py index b9b5ca1a86..9a76dbc3f4 100644 --- a/src/spikeinterface/curation/threshold_metrics_curation.py +++ b/src/spikeinterface/curation/threshold_metrics_curation.py @@ -3,7 +3,6 @@ import numpy as np -from spikeinterface.core.analyzer_extension_core import SortingAnalyzer from .curation_tools import is_threshold_disabled diff --git a/src/spikeinterface/curation/train_manual_curation.py b/src/spikeinterface/curation/train_manual_curation.py index e34951820a..f6dd01e161 100644 --- a/src/spikeinterface/curation/train_manual_curation.py +++ b/src/spikeinterface/curation/train_manual_curation.py @@ -265,7 +265,6 @@ def load_and_preprocess_analyzers(self, analyzers, enforce_metric_params): metric_extensions = [analyzers[0].get_extension(extension_name) for extension_name in extension_names] for metric_extension, extension_name in zip(metric_extensions, extension_names): - # remove the 's' at the end of the extension name extension_name = extension_name[:-1] if metric_extension is not None: @@ -289,11 +288,9 @@ def _check_metrics_parameters(self, analyzers, enforce_metric_params): conflicting_metrics = [] for analyzer_index_1, analyzer_1 in enumerate(analyzers): for analyzer_index_2, analyzer_2 in enumerate(analyzers): - if analyzer_index_1 <= analyzer_index_2: continue else: - metric_params_1 = {} metric_params_2 = {} @@ -389,7 +386,7 @@ def process_test_data_for_classification(self): def apply_scaling_imputation(self, imputation_strategy, scaling_technique, X_train, X_test, y_train, y_test): """Impute and scale the data using the specified techniques.""" - from sklearn.experimental import enable_iterative_imputer + from sklearn.experimental import enable_iterative_imputer # noqa: F401 (side-effect import, required by IterativeImputer) from sklearn.impute import SimpleImputer, KNNImputer, IterativeImputer from sklearn.ensemble import HistGradientBoostingRegressor from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler @@ -587,14 +584,14 @@ def _save(self): import pandas as pd # export training data and labels - pd.DataFrame(self.X).to_csv(self.folder / f"training_data.csv", index_label="unit_id") - pd.DataFrame(self.y).to_csv(self.folder / f"labels.csv", index_label="unit_index") + pd.DataFrame(self.X).to_csv(self.folder / "training_data.csv", index_label="unit_id") + pd.DataFrame(self.y).to_csv(self.folder / "labels.csv", index_label="unit_index") self.requirements["scikit-learn"] = sklearn.__version__ # Dump to skops if folder is provided - dump(self.best_pipeline, self.folder / f"best_model.skops") - self.test_accuracies_df.to_csv(self.folder / f"model_accuracies.csv", float_format="%.4f") + dump(self.best_pipeline, self.folder / "best_model.skops") + self.test_accuracies_df.to_csv(self.folder / "model_accuracies.csv", float_format="%.4f") model_info = {} model_info["metric_params"] = self.metrics_params @@ -629,7 +626,7 @@ def _train_and_evaluate( random_state=self.seed, **search_kwargs, ) - except: + except Exception: if self.verbose is True: print("BayesSearchCV from scikit-optimize not available, using RandomizedSearchCV") from sklearn.model_selection import RandomizedSearchCV @@ -787,7 +784,7 @@ def try_to_get_metrics_from_analyzer(sorting_analyzer): for metric_extension in metric_extensions: try: metric_extensions_data.append(metric_extension.get_data()) - except: + except Exception: metric_extensions_data.append(None) return metric_extensions_data diff --git a/src/spikeinterface/exporters/report.py b/src/spikeinterface/exporters/report.py index ae1341afbc..95a184917c 100644 --- a/src/spikeinterface/exporters/report.py +++ b/src/spikeinterface/exporters/report.py @@ -71,12 +71,9 @@ def export_report( ) # load or compute correlograms - if sorting_analyzer.has_extension("correlograms"): - correlograms, bins = sorting_analyzer.get_extension("correlograms").get_data() - elif force_computation: - correlograms, bins = compute_correlograms(sorting_analyzer, window_ms=100.0, bin_ms=1.0) + if not sorting_analyzer.has_extension("correlograms") and force_computation: + _ = compute_correlograms(sorting_analyzer, window_ms=100.0, bin_ms=1.0) else: - correlograms = None warnings.warn( "export_report(): correlograms will not be exported. Use sorting_analyzer.compute('correlograms') if you want to include them." ) @@ -107,13 +104,13 @@ def export_report( # global figures fig = plt.figure(figsize=(20, 10)) - w = sw.plot_unit_locations(sorting_analyzer, figure=fig, unit_colors=unit_colors) + _ = sw.plot_unit_locations(sorting_analyzer, figure=fig, unit_colors=unit_colors) fig.savefig(output_folder / f"unit_locations.{format}") if not show_figures: plt.close(fig) fig, ax = plt.subplots(figsize=(20, 10)) - sw.plot_unit_depths(sorting_analyzer, ax=ax, unit_colors=unit_colors) + _ = sw.plot_unit_depths(sorting_analyzer, ax=ax, unit_colors=unit_colors) fig.savefig(output_folder / f"unit_depths.{format}") if not show_figures: plt.close(fig) diff --git a/src/spikeinterface/exporters/tests/common.py b/src/spikeinterface/exporters/tests/common.py index 3b85c11d54..e69de29bb2 100644 --- a/src/spikeinterface/exporters/tests/common.py +++ b/src/spikeinterface/exporters/tests/common.py @@ -1,79 +0,0 @@ -import pytest -from pathlib import Path - -from spikeinterface.core import generate_ground_truth_recording, create_sorting_analyzer, compute_sparsity - - -def make_sorting_analyzer(sparse=True, with_group=False): - recording, sorting = generate_ground_truth_recording( - durations=[30.0], - sampling_frequency=28000.0, - num_channels=8, - num_units=4, - generate_probe_kwargs=dict( - num_columns=2, - xpitch=20, - ypitch=20, - contact_shapes="circle", - contact_shape_params={"radius": 6}, - ), - generate_sorting_kwargs=dict(firing_rates=10.0, refractory_period_ms=4.0), - noise_kwargs=dict(noise_levels=5.0, strategy="on_the_fly"), - seed=2205, - ) - - if with_group: - - # this is a bit painful. We need to figure out which units belong to which group - initial_sorting_analyzer = create_sorting_analyzer( - sorting=sorting, recording=recording, format="memory", sparse=True - ) - main_channels = initial_sorting_analyzer.main_channel_indices - sorting_groups = [0 if main_channel < 4 else 1 for main_channel in main_channels] - recording.set_channel_groups([0, 0, 0, 0, 1, 1, 1, 1]) - sorting.set_property("group", sorting_groups) - - # Now we know that, we can make an analyzer with a working sparsity_group - sorting_analyzer_unused = create_sorting_analyzer( - sorting=sorting, recording=recording, format="memory", sparse=False, sparsity=None - ) - sparsity_group = compute_sparsity(sorting_analyzer_unused, method="by_property", by_property="group") - sorting_analyzer = create_sorting_analyzer( - sorting=sorting, recording=recording, format="memory", sparse=False, sparsity=sparsity_group - ) - else: - sorting_analyzer = create_sorting_analyzer(sorting=sorting, recording=recording, format="memory", sparse=sparse) - - sorting_analyzer.compute("random_spikes") - sorting_analyzer.compute("waveforms") - sorting_analyzer.compute("templates") - sorting_analyzer.compute("noise_levels") - sorting_analyzer.compute("principal_components") - sorting_analyzer.compute("template_similarity") - sorting_analyzer.compute("spike_amplitudes") - sorting_analyzer.compute( - "quality_metrics", metric_names=["snr", "amplitude_median", "isi_violation", "amplitude_cutoff"] - ) - sorting_analyzer.compute(["spike_amplitudes", "spike_locations"]) - - return sorting_analyzer - - -@pytest.fixture(scope="module") -def sorting_analyzer_dense_for_export(): - return make_sorting_analyzer(sparse=False) - - -@pytest.fixture(scope="module") -def sorting_analyzer_with_group_for_export(): - return make_sorting_analyzer(sparse=False, with_group=True) - - -@pytest.fixture(scope="module") -def sorting_analyzer_sparse_for_export(): - return make_sorting_analyzer(sparse=True) - - -if __name__ == "__main__": - sorting_analyzer = make_sorting_analyzer(sparse=False) - print(sorting_analyzer) diff --git a/src/spikeinterface/exporters/tests/conftest.py b/src/spikeinterface/exporters/tests/conftest.py new file mode 100644 index 0000000000..a524c3b965 --- /dev/null +++ b/src/spikeinterface/exporters/tests/conftest.py @@ -0,0 +1,72 @@ +import pytest + +from spikeinterface.core import generate_ground_truth_recording, create_sorting_analyzer, compute_sparsity + + +def make_sorting_analyzer(sparse=True, with_group=False): + recording, sorting = generate_ground_truth_recording( + durations=[30.0], + sampling_frequency=28000.0, + num_channels=8, + num_units=4, + generate_probe_kwargs=dict( + num_columns=2, + xpitch=20, + ypitch=20, + contact_shapes="circle", + contact_shape_params={"radius": 6}, + ), + generate_sorting_kwargs=dict(firing_rates=10.0, refractory_period_ms=4.0), + noise_kwargs=dict(noise_levels=5.0, strategy="on_the_fly"), + seed=2205, + ) + + if with_group: + # this is a bit painful. We need to figure out which units belong to which group + initial_sorting_analyzer = create_sorting_analyzer( + sorting=sorting, recording=recording, format="memory", sparse=True + ) + main_channels = initial_sorting_analyzer.main_channel_indices + sorting_groups = [0 if main_channel < 4 else 1 for main_channel in main_channels] + recording.set_channel_groups([0, 0, 0, 0, 1, 1, 1, 1]) + sorting.set_property("group", sorting_groups) + + # Now we know that, we can make an analyzer with a working sparsity_group + sorting_analyzer_unused = create_sorting_analyzer( + sorting=sorting, recording=recording, format="memory", sparse=False, sparsity=None + ) + sparsity_group = compute_sparsity(sorting_analyzer_unused, method="by_property", by_property="group") + sorting_analyzer = create_sorting_analyzer( + sorting=sorting, recording=recording, format="memory", sparse=False, sparsity=sparsity_group + ) + else: + sorting_analyzer = create_sorting_analyzer(sorting=sorting, recording=recording, format="memory", sparse=sparse) + + sorting_analyzer.compute("random_spikes") + sorting_analyzer.compute("waveforms") + sorting_analyzer.compute("templates") + sorting_analyzer.compute("noise_levels") + sorting_analyzer.compute("principal_components") + sorting_analyzer.compute("template_similarity") + sorting_analyzer.compute("spike_amplitudes") + sorting_analyzer.compute( + "quality_metrics", metric_names=["snr", "amplitude_median", "isi_violation", "amplitude_cutoff"] + ) + sorting_analyzer.compute(["spike_amplitudes", "spike_locations"]) + + return sorting_analyzer + + +@pytest.fixture(scope="module") +def sorting_analyzer_dense_for_export(): + return make_sorting_analyzer(sparse=False) + + +@pytest.fixture(scope="module") +def sorting_analyzer_with_group_for_export(): + return make_sorting_analyzer(sparse=False, with_group=True) + + +@pytest.fixture(scope="module") +def sorting_analyzer_sparse_for_export(): + return make_sorting_analyzer(sparse=True) diff --git a/src/spikeinterface/exporters/tests/test_export_to_ibl.py b/src/spikeinterface/exporters/tests/test_export_to_ibl.py index c7be6911cc..ee11d40695 100644 --- a/src/spikeinterface/exporters/tests/test_export_to_ibl.py +++ b/src/spikeinterface/exporters/tests/test_export_to_ibl.py @@ -2,10 +2,7 @@ from spikeinterface.preprocessing import bandpass_filter, decimate from spikeinterface.exporters import export_to_ibl_gui -from spikeinterface.exporters.tests.common import ( - make_sorting_analyzer, - sorting_analyzer_sparse_for_export, -) + required_output_files = [ "spikes.times.npy", @@ -107,8 +104,3 @@ def test_missing_info(sorting_analyzer_sparse_for_export, create_cache_folder): with pytest.raises(ValueError, match="Missing required extension"): export_to_ibl_gui(sorting_analyzer, output_folder, n_jobs=-1) - - -if __name__ == "__main__": - sorting_analyzer = make_sorting_analyzer(sparse=True) - test_export_ap_to_ibl(sorting_analyzer) diff --git a/src/spikeinterface/exporters/tests/test_export_to_phy.py b/src/spikeinterface/exporters/tests/test_export_to_phy.py index f46ecd3260..08c91fa0f2 100644 --- a/src/spikeinterface/exporters/tests/test_export_to_phy.py +++ b/src/spikeinterface/exporters/tests/test_export_to_phy.py @@ -6,13 +6,6 @@ from spikeinterface.core import generate_ground_truth_recording, create_sorting_analyzer from spikeinterface.exporters import export_to_phy -from spikeinterface.exporters.tests.common import ( - make_sorting_analyzer, - sorting_analyzer_dense_for_export, - sorting_analyzer_sparse_for_export, - sorting_analyzer_with_group_for_export, -) - def test_export_to_phy_dense(sorting_analyzer_dense_for_export, create_cache_folder): cache_folder = create_cache_folder @@ -286,13 +279,3 @@ def test_export_to_phy_add_waveforms_missing_extension(create_cache_folder): assert not (output_folder / "_phy_spikes_subset.spikes.npy").is_file() assert not (output_folder / "_phy_spikes_subset.channels.npy").is_file() assert not (output_folder / "_phy_spikes_subset.waveforms.npy").is_file() - - -if __name__ == "__main__": - sorting_analyzer_sparse = make_sorting_analyzer(sparse=True) - sorting_analyzer_group = make_sorting_analyzer(sparse=False, with_group=True) - sorting_analyzer_dense = make_sorting_analyzer(sparse=False) - - test_export_to_phy_dense(sorting_analyzer_dense) - test_export_to_phy_sparse(sorting_analyzer_sparse) - test_export_to_phy_by_property(sorting_analyzer_group) diff --git a/src/spikeinterface/exporters/tests/test_report.py b/src/spikeinterface/exporters/tests/test_report.py index a2ee9e885c..7f9e7636d6 100644 --- a/src/spikeinterface/exporters/tests/test_report.py +++ b/src/spikeinterface/exporters/tests/test_report.py @@ -1,12 +1,6 @@ import shutil from spikeinterface.exporters import export_report -from spikeinterface.exporters.tests.common import ( - make_sorting_analyzer, - sorting_analyzer_dense_for_export, - sorting_analyzer_sparse_for_export, - sorting_analyzer_with_group_for_export, -) def test_export_report(sorting_analyzer_sparse_for_export, create_cache_folder): @@ -19,8 +13,3 @@ def test_export_report(sorting_analyzer_sparse_for_export, create_cache_folder): job_kwargs = dict(n_jobs=1, chunk_size=30000, progress_bar=True) export_report(sorting_analyzer, report_folder, force_computation=True, **job_kwargs) - - -if __name__ == "__main__": - sorting_analyzer = make_sorting_analyzer(sparse=True) - test_export_report(sorting_analyzer) diff --git a/src/spikeinterface/exporters/to_phy.py b/src/spikeinterface/exporters/to_phy.py index c6ea703770..40dae800f1 100644 --- a/src/spikeinterface/exporters/to_phy.py +++ b/src/spikeinterface/exporters/to_phy.py @@ -79,9 +79,9 @@ def export_to_phy( assert isinstance(sorting_analyzer, SortingAnalyzer), "sorting_analyzer must be a SortingAnalyzer object" sorting = sorting_analyzer.sorting - assert ( - sorting_analyzer.get_num_segments() == 1 - ), f"Export to phy only works with one segment, your extractor has {sorting_analyzer.get_num_segments()} segments" + assert sorting_analyzer.get_num_segments() == 1, ( + f"Export to phy only works with one segment, your extractor has {sorting_analyzer.get_num_segments()} segments" + ) num_chans = sorting_analyzer.get_num_channels() fs = sorting_analyzer.sampling_frequency @@ -159,7 +159,7 @@ def export_to_phy( with (output_folder / "params.py").open("w") as f: if use_relative_path: if copy_binary: - f.write(f"dat_path = r'recording.dat'\n") + f.write("dat_path = r'recording.dat'\n") elif rec_path == "None": f.write(f"dat_path = {rec_path}\n") else: @@ -168,7 +168,7 @@ def export_to_phy( f.write(f"dat_path = r'{str(rec_path)}'\n") f.write(f"n_channels_dat = {num_chans}\n") f.write(f"dtype = '{dtype_str}'\n") - f.write(f"offset = 0\n") + f.write("offset = 0\n") f.write(f"sample_rate = {fs}\n") f.write(f"hp_filtered = {sorting_analyzer.is_filtered()}") diff --git a/src/spikeinterface/extractors/cbin_ibl.py b/src/spikeinterface/extractors/cbin_ibl.py index adf04f366a..0a47d7efab 100644 --- a/src/spikeinterface/extractors/cbin_ibl.py +++ b/src/spikeinterface/extractors/cbin_ibl.py @@ -1,6 +1,5 @@ from pathlib import Path import re -import warnings import numpy as np import probeinterface @@ -142,9 +141,9 @@ def __init__(self, folder_path=None, load_sync_channel=False, stream_name="ap", # snippets downloaded from IBL have the .stream.cbin suffix cbin_stream_files = list(folder_path.glob(f"*.{stream_name}.stream.cbin")) curr_cbin_files = cbin_stream_files if len(cbin_stream_files) > len(cbin_files) else cbin_files - assert ( - len(curr_cbin_files) == 1 - ), f"There should only be one `*.cbin` file in the folder, but {print(curr_cbin_files)} have been found" + assert len(curr_cbin_files) == 1, ( + f"There should only be one `*.cbin` file in the folder, but {print(curr_cbin_files)} have been found" + ) cbin_file_path = curr_cbin_files[0] else: cbin_file_path = Path(cbin_file_path) @@ -274,7 +273,7 @@ def extract_stream_info(meta_file, meta): gain_factor = float(meta["imAiRangeMax"]) / max_int channel_gains = gain_factor * per_channel_gain * 1e6 else: - raise NotImplementedError("This meta file version of spikeglx" " is not implemented") + raise NotImplementedError("This meta file version of spikeglx is not implemented") info = {} info["fname"] = fname diff --git a/src/spikeinterface/extractors/cellexplorersortingextractor.py b/src/spikeinterface/extractors/cellexplorersortingextractor.py index 8659baded8..953c9c315a 100644 --- a/src/spikeinterface/extractors/cellexplorersortingextractor.py +++ b/src/spikeinterface/extractors/cellexplorersortingextractor.py @@ -157,9 +157,9 @@ def _retrieve_sampling_frequency_from_session_info_file(self) -> float: self.session_info_file_path = self.session_path / f"{self.session_id}.sessionInfo.mat" self.session_info_file_path = Path(self.session_info_file_path).absolute() - assert ( - self.session_info_file_path.is_file() - ), f"No {self.session_id}.sessionInfo.mat file found in the {self.session_path}!, can't inferr sampling rate, please pass the sampling rate at initialization" + assert self.session_info_file_path.is_file(), ( + f"No {self.session_id}.sessionInfo.mat file found in the {self.session_path}!, can't inferr sampling rate, please pass the sampling rate at initialization" + ) session_info_mat = read_mat(self.session_info_file_path) rates = session_info_mat["sessionInfo"]["rates"] diff --git a/src/spikeinterface/extractors/combinatoextractors.py b/src/spikeinterface/extractors/combinatoextractors.py index 5ecc5cdf24..011af94ba9 100644 --- a/src/spikeinterface/extractors/combinatoextractors.py +++ b/src/spikeinterface/extractors/combinatoextractors.py @@ -56,7 +56,6 @@ def __init__(self, folder_path, sampling_frequency=None, user="simple", det_sign unit_counter = 0 spiketrains = {} metadata = {} - unsorted = [] with h5py.File(det_file, mode="r") as fdet: for sign, sfile in sort_cat_files: with h5py.File(sfile, mode="r") as f: diff --git a/src/spikeinterface/extractors/extractor_classes.py b/src/spikeinterface/extractors/extractor_classes.py index 21c383309f..e398300f8e 100644 --- a/src/spikeinterface/extractors/extractor_classes.py +++ b/src/spikeinterface/extractors/extractor_classes.py @@ -18,7 +18,7 @@ # sorting/recording/event from neo from .neoextractors import * -from .neoextractors import read_neuroscope +from .neoextractors import neo_recording_extractors_dict, neo_sorting_extractors_dict, neo_event_extractors_dict from .neoextractors.intan import read_split_intan_files, IntanSplitFilesRecordingExtractor # non-NEO objects implemented in neo folder diff --git a/src/spikeinterface/extractors/iblextractors.py b/src/spikeinterface/extractors/iblextractors.py index 8a57e40ec3..69c072931b 100644 --- a/src/spikeinterface/extractors/iblextractors.py +++ b/src/spikeinterface/extractors/iblextractors.py @@ -172,9 +172,9 @@ def __init__( else: stream_names = IblRecordingExtractor.get_stream_names(eid=eid, cache_folder=cache_folder, one=one) if len(stream_names) > 1: - assert ( - stream_name is not None - ), f"Multiple streams found for session. Please specify a stream name from {stream_names}." + assert stream_name is not None, ( + f"Multiple streams found for session. Please specify a stream name from {stream_names}." + ) assert stream_name in stream_names, ( f"The `stream_name` '{stream_name}' is not available for this experiment {eid}! " f"Please choose one of {stream_names}." @@ -320,7 +320,7 @@ class IblSortingExtractor(BaseSorting): The loaded data. """ - installation_mesg = "IBL extractors require ibllib as a dependency." " To install, run: \n\n pip install ibllib\n\n" + installation_mesg = "IBL extractors require ibllib as a dependency. To install, run: \n\n pip install ibllib\n\n" def __init__( self, pid: str, good_clusters_only: bool = False, load_unit_properties: bool = True, one=None, **kwargs diff --git a/src/spikeinterface/extractors/klustaextractors.py b/src/spikeinterface/extractors/klustaextractors.py index d18c8d831f..604e31bad5 100644 --- a/src/spikeinterface/extractors/klustaextractors.py +++ b/src/spikeinterface/extractors/klustaextractors.py @@ -61,7 +61,7 @@ def __init__(self, file_or_folder_path, exclude_cluster_groups=None): config_file = [f for f in klustafolder.iterdir() if f.suffix == ".prm"][0] config = read_python(str(config_file)) sampling_frequency = config["traces"]["sample_rate"] - except Exception as e: + except Exception: print("Could not load sampling frequency info") kf_reader = h5py.File(kwikfile, "r") @@ -96,9 +96,9 @@ def __init__(self, file_or_folder_path, exclude_cluster_groups=None): "cluster_group" ] - assert ( - cluster_group in self.default_cluster_groups.keys() - ), f'cluster_group not in "default_dict: {cluster_group}' + assert cluster_group in self.default_cluster_groups.keys(), ( + f'cluster_group not in "default_dict: {cluster_group}' + ) cluster_group_name = self.default_cluster_groups[cluster_group] if cluster_group_name.lower() in cs_to_exclude: diff --git a/src/spikeinterface/extractors/matlabhelpers.py b/src/spikeinterface/extractors/matlabhelpers.py index f7ffb45065..8ffe31d665 100644 --- a/src/spikeinterface/extractors/matlabhelpers.py +++ b/src/spikeinterface/extractors/matlabhelpers.py @@ -18,7 +18,8 @@ class MatlabHelper: installation_mesg = ( - "To use the MATSortingExtractor install h5py and scipy: " "\n\n pip install h5py scipy\n\n" + "To use the MATSortingExtractor install h5py and scipy: " + "\n\n pip install h5py scipy\n\n" ) # error message when not installed def __init__(self, file_path): diff --git a/src/spikeinterface/extractors/mcsh5extractors.py b/src/spikeinterface/extractors/mcsh5extractors.py index 3e295f33b4..df0004f09a 100644 --- a/src/spikeinterface/extractors/mcsh5extractors.py +++ b/src/spikeinterface/extractors/mcsh5extractors.py @@ -111,7 +111,7 @@ def openMCSH5File(filename, stream_id): stream_name = "Stream_" + str(stream_id) analog_stream_names = list(rf.require_group("/Data/Recording_0/AnalogStream").keys()) assert stream_name in analog_stream_names, ( - f"Specified stream does not exist. " f"Available streams: {analog_stream_names}" + f"Specified stream does not exist. Available streams: {analog_stream_names}" ) stream = rf.require_group("/Data/Recording_0/AnalogStream/" + stream_name) @@ -141,9 +141,9 @@ def openMCSH5File(filename, stream_id): timestep_avg = np.mean(TimeVals[1:] - TimeVals[0:-1]) timestep_min = np.min(TimeVals[1:] - TimeVals[0:-1]) timestep_max = np.min(TimeVals[1:] - TimeVals[0:-1]) - assert all( - np.abs(np.array((timestep_min, timestep_max)) - timestep_avg) / timestep_avg < 1e-6 - ), "Time steps vary by more than 1 ppm" + assert all(np.abs(np.array((timestep_min, timestep_max)) - timestep_avg) / timestep_avg < 1e-6), ( + "Time steps vary by more than 1 ppm" + ) samplingRate = 1.0 / timestep_avg mcs_info = { diff --git a/src/spikeinterface/extractors/mdaextractors.py b/src/spikeinterface/extractors/mdaextractors.py index 12a7474df7..639c77597f 100644 --- a/src/spikeinterface/extractors/mdaextractors.py +++ b/src/spikeinterface/extractors/mdaextractors.py @@ -43,8 +43,7 @@ def __init__(self, folder_path, raw_fname="raw.mda", params_fname="params.json", dtype = self._diskreadmda.dt() num_channels = self._diskreadmda.N1() assert geom.shape[0] == self._diskreadmda.N1(), ( - f"Incompatible dimensions between geom.csv and timeseries " - f"file: {geom.shape[0]} <> {self._diskreadmda.N1()}" + f"Incompatible dimensions between geom.csv and timeseries file: {geom.shape[0]} <> {self._diskreadmda.N1()}" ) sampling_frequency = float(self._dataset_params["samplerate"]) BaseRecording.__init__( @@ -102,7 +101,7 @@ def write_recording( """ job_kwargs = fix_job_kwargs(job_kwargs) assert recording.get_num_segments() == 1, ( - "MdaRecording.write_recording() can only write a single segment " "recording" + "MdaRecording.write_recording() can only write a single segment recording" ) save_path = Path(save_path) save_path.mkdir(parents=True, exist_ok=True) @@ -434,7 +433,7 @@ def _read_chunk_1d(self, i, N): tmp_fname = _download_bytes_to_tmpfile(self._path, offset, offset + self._header.num_bytes_per_entry * N) try: ret = self._read_chunk_1d_helper(tmp_fname, N, offset=0) - except: + except Exception: ret = None return ret return self._read_chunk_1d_helper(self._path, N, offset=offset) @@ -482,7 +481,7 @@ def _read_header(path): raise Exception("Problem downloading bytes from " + path) try: ret = _read_header(tmp_fname) - except: + except Exception: ret = None Path(tmp_fname).unlink() return ret @@ -490,7 +489,7 @@ def _read_header(path): f = open(path, "rb") try: dt_code = _read_int32(f) - num_bytes_per_entry = _read_int32(f) + _read_int32(f) # num_bytes_per_entry: unused, but must be read to advance the file pointer num_dims = _read_int32(f) uses64bitdims = False if num_dims < 0: @@ -689,7 +688,7 @@ def _writemda(X, fname, dt): print(f"Unexpected data type: {dt}") return False - if type(fname) == str: + if type(fname) is str: f = open(fname, "wb") else: f = fname @@ -706,13 +705,13 @@ def _writemda(X, fname, dt): bytes0 = X.astype(dt).tobytes(order="F") f.write(bytes0) - if type(fname) == str: + if type(fname) is str: f.close() return True except Exception as e: # catch *all* exceptions traceback.print_exc() print(e) - if type(fname) == str: + if type(fname) is str: f.close() return False @@ -791,7 +790,7 @@ def appendmda(X, path): def file_extension(fname): - if type(fname) == str: + if type(fname) is str: filename, ext = os.path.splitext(fname) return ext else: @@ -817,7 +816,7 @@ def _write_int64(f, val): def _header_from_file(f): try: dt_code = _read_int32(f) - num_bytes_per_entry = _read_int32(f) + _read_int32(f) # num_bytes_per_entry: unused, but must be read to advance the file pointer num_dims = _read_int32(f) uses64bitdims = False if num_dims < 0: diff --git a/src/spikeinterface/extractors/neoextractors/intan.py b/src/spikeinterface/extractors/neoextractors/intan.py index 877f7f33b2..4f0fd31ea5 100644 --- a/src/spikeinterface/extractors/neoextractors/intan.py +++ b/src/spikeinterface/extractors/neoextractors/intan.py @@ -156,7 +156,7 @@ def __init__( if mode not in ("append", "concatenate"): mode_error = ( - "Possible options for the `mode` argument are 'concatenate' or 'append', you have entered " f"{mode}." + f"Possible options for the `mode` argument are 'concatenate' or 'append', you have entered {mode}." ) raise ValueError(mode_error) diff --git a/src/spikeinterface/extractors/neoextractors/neo_utils.py b/src/spikeinterface/extractors/neoextractors/neo_utils.py index 9a0a01e50a..1bc1e486eb 100644 --- a/src/spikeinterface/extractors/neoextractors/neo_utils.py +++ b/src/spikeinterface/extractors/neoextractors/neo_utils.py @@ -1,6 +1,3 @@ -from .neobaseextractor import NeoBaseRecordingExtractor - - def get_neo_streams(extractor_name, *args, **kwargs): """Returns the NEO streams (stream names and stream ids) associated to a dataset. For multi-stream datasets, the `stream_id` or `stream_name` arguments can be used @@ -57,7 +54,7 @@ def get_neo_extractor(extractor_name): from spikeinterface.extractors.neoextractors import neo_recording_class_dict assert extractor_name in neo_recording_class_dict, ( - f"{extractor_name} not an extractor name:" f"\n{list(neo_recording_class_dict.keys())}" + f"{extractor_name} not an extractor name:\n{list(neo_recording_class_dict.keys())}" ) neo_extractor = neo_recording_class_dict[extractor_name] return neo_extractor diff --git a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py index b9832f7fe8..7e70adcbda 100644 --- a/src/spikeinterface/extractors/neoextractors/neobaseextractor.py +++ b/src/spikeinterface/extractors/neoextractors/neobaseextractor.py @@ -230,9 +230,9 @@ def __init__( if use_names_as_ids: chan_names = signal_channels["name"] - assert ( - chan_names.size == np.unique(chan_names).size - ), "use_names_as_ids=True is not possible, channel names are not unique" + assert chan_names.size == np.unique(chan_names).size, ( + "use_names_as_ids=True is not possible, channel names are not unique" + ) chan_ids = chan_names else: # unique in all cases @@ -577,9 +577,7 @@ def _infer_t_start_from_signal_stream(self, segment_index: int, stream_id: str | if len(unique_t_starts) == 0: t_start = None - warning_message = ( - "No stream ids with corresponding sampling frequency found \n " "Setting t_start to None. \n" - ) + warning_message = "No stream ids with corresponding sampling frequency found \n Setting t_start to None. \n" warnings.warn(warning_message) if len(unique_t_starts) == 1: @@ -671,9 +669,9 @@ def __init__(self, block_index=None, use_names_as_ids: bool = False, **neo_kwarg if use_names_as_ids: channel_ids = event_channels["name"] - assert ( - event_channels.size == np.unique(channel_ids).size - ), "use_name_as_ids=True is not possible, channel names are not unique" + assert event_channels.size == np.unique(channel_ids).size, ( + "use_name_as_ids=True is not possible, channel names are not unique" + ) else: channel_ids = event_channels["id"] diff --git a/src/spikeinterface/extractors/neoextractors/neuroscope.py b/src/spikeinterface/extractors/neoextractors/neuroscope.py index 7064ea1303..bc02faa0e3 100644 --- a/src/spikeinterface/extractors/neoextractors/neuroscope.py +++ b/src/spikeinterface/extractors/neoextractors/neuroscope.py @@ -188,21 +188,20 @@ def __init__( ): from lxml import etree as et - assert not ( - folder_path is None and resfile_path is None and clufile_path is None - ), "Either pass a single folder_path location, or a pair of resfile_path and clufile_path! None received." + assert not (folder_path is None and resfile_path is None and clufile_path is None), ( + "Either pass a single folder_path location, or a pair of resfile_path and clufile_path! None received." + ) if resfile_path is not None: assert clufile_path is not None, "If passing resfile_path or clufile_path, both are required!" resfile_path = Path(resfile_path) clufile_path = Path(clufile_path) - assert ( - resfile_path.is_file() and clufile_path.is_file() - ), f"The resfile_path ({resfile_path}) and clufile_path ({clufile_path}) must be .res and .clu files!" + assert resfile_path.is_file() and clufile_path.is_file(), ( + f"The resfile_path ({resfile_path}) and clufile_path ({clufile_path}) must be .res and .clu files!" + ) assert folder_path is None, ( - "Pass either a single folder_path location, " - "or a pair of resfile_path and clufile_path! All received." + "Pass either a single folder_path location, or a pair of resfile_path and clufile_path! All received." ) folder_path_passed = False folder_path = resfile_path.parent @@ -225,9 +224,9 @@ def __init__( folder_path_passed = True # flag for setting kwargs for proper dumping if exclude_shanks is not None: # dumping checks do not like having an empty list as default - assert all( - [isinstance(x, (int, np.integer)) and x >= 0 for x in exclude_shanks] - ), "Optional argument 'exclude_shanks' must contain positive integers only!" + assert all([isinstance(x, (int, np.integer)) and x >= 0 for x in exclude_shanks]), ( + "Optional argument 'exclude_shanks' must contain positive integers only!" + ) else: exclude_shanks = [] xml_file_path = _handle_xml_file_path(folder_path=folder_path, initial_xml_file_path=xml_file_path) @@ -248,9 +247,9 @@ def __init__( resfile_names = [x.name[: x.name.find(".res")] for x in res_files] clufile_names = [x.name[: x.name.find(".clu")] for x in clu_files] - assert np.all( - r == c for (r, c) in zip(resfile_names, clufile_names) - ), "Some of the .res.%i and .clu.%i files do not share the same name!" + assert np.all(r == c for (r, c) in zip(resfile_names, clufile_names)), ( + "Some of the .res.%i and .clu.%i files do not share the same name!" + ) all_unit_ids = [] all_spiketrains = [] @@ -272,9 +271,9 @@ def __init__( n_clu = clu[0] clu = np.delete(clu, 0) unique_ids = np.unique(clu) - assert ( - len(unique_ids) == n_clu - ), "First value of .clu file ({clufile_path}) does not match number of unique IDs!" + assert len(unique_ids) == n_clu, ( + "First value of .clu file ({clufile_path}) does not match number of unique IDs!" + ) unit_map = dict(zip(unique_ids, list(range(1, n_clu + 1)))) if 0 in unique_ids: diff --git a/src/spikeinterface/extractors/neoextractors/spike2.py b/src/spikeinterface/extractors/neoextractors/spike2.py index 6283176def..e41dac547d 100644 --- a/src/spikeinterface/extractors/neoextractors/spike2.py +++ b/src/spikeinterface/extractors/neoextractors/spike2.py @@ -2,7 +2,7 @@ from spikeinterface.core.core_tools import define_function_from_class -from .neobaseextractor import NeoBaseRecordingExtractor, NeoBaseSortingExtractor +from .neobaseextractor import NeoBaseRecordingExtractor class Spike2RecordingExtractor(NeoBaseRecordingExtractor): diff --git a/src/spikeinterface/extractors/neuropixels_utils.py b/src/spikeinterface/extractors/neuropixels_utils.py index df66230548..115a43be4b 100644 --- a/src/spikeinterface/extractors/neuropixels_utils.py +++ b/src/spikeinterface/extractors/neuropixels_utils.py @@ -90,33 +90,33 @@ def compute_saturation_threshold_from_probe(probe: Probe, stream_name: str) -> f return None -def synchronize_neuropixel_streams(recording_ref, recording_other): - """ - Use the last "sync" channel from spikeglx or openephys neuropixels to synchronize - recordings. - - Method used : - 1. detect pulse times on both streams. - 2. make a linear regression from "other" to "ref". - The slope is nclose to 1 and corresponds to the sample rate correction - The intercept is close to 0 and corresponds to the delta time start - - """ - # This will be done very very soon, I promise. - raise NotImplementedError - - synhcro_chan_id = recording_ref.channel_ids[-1] - trig_ref = recording_ref.get_traces(channel_ids=[synhcro_chan_id], return_in_uV=False) - trig_ref = trig_ref[:, 0] - times_ref = recording_ref.get_times() - - synhcro_chan_id = recording_other.channel_ids[-1] - trig_other = recording_other.get_traces(channel_ids=[synhcro_chan_id], return_in_uV=False) - trig_other = trig_other[:, 0] - times_other = recording_other.get_times() - - # import matplotlib.pyplot as plt - # fig, ax = plt.subplots() - # ax.plot(times_ref, trig_ref) - # ax.plot(times_other, trig_other) - # plt.show() +# def synchronize_neuropixel_streams(recording_ref, recording_other): +# """ +# Use the last "sync" channel from spikeglx or openephys neuropixels to synchronize +# recordings. + +# Method used : +# 1. detect pulse times on both streams. +# 2. make a linear regression from "other" to "ref". +# The slope is nclose to 1 and corresponds to the sample rate correction +# The intercept is close to 0 and corresponds to the delta time start + +# """ +# # This will be done very very soon, I promise. +# raise NotImplementedError + +# synhcro_chan_id = recording_ref.channel_ids[-1] +# trig_ref = recording_ref.get_traces(channel_ids=[synhcro_chan_id], return_in_uV=False) +# trig_ref = trig_ref[:, 0] +# times_ref = recording_ref.get_times() + +# synhcro_chan_id = recording_other.channel_ids[-1] +# trig_other = recording_other.get_traces(channel_ids=[synhcro_chan_id], return_in_uV=False) +# trig_other = trig_other[:, 0] +# times_other = recording_other.get_times() + +# # import matplotlib.pyplot as plt +# # fig, ax = plt.subplots() +# # ax.plot(times_ref, trig_ref) +# # ax.plot(times_other, trig_other) +# # plt.show() diff --git a/src/spikeinterface/extractors/nwbextractors.py b/src/spikeinterface/extractors/nwbextractors.py index 2ed8d490b5..c8536b35e4 100644 --- a/src/spikeinterface/extractors/nwbextractors.py +++ b/src/spikeinterface/extractors/nwbextractors.py @@ -420,8 +420,6 @@ def _retrieve_electrodes_indices_from_electrical_series_backend(open_file, elect """ if "electrodes" not in electrical_series: if backend == "zarr": - import zarr - # links must be resolved zarr_links = electrical_series.attrs.get("_LINKS", electrical_series.attrs.get("zarr_link", [])) electrodes_path = None @@ -658,9 +656,7 @@ def _locate_units_table(self, backend): return self.file[self.unit_table_path] except KeyError: available = _find_neurodata_type_from_backend(self.file, neurodata_type="Units", backend=backend) - raise ValueError( - f"{self.unit_table_path} not found in the NWB file!" f"Available options are: {available}." - ) + raise ValueError(f"{self.unit_table_path} not found in the NWB file!Available options are: {available}.") @staticmethod def available_units_tables(file_path, stream_mode=None, storage_options=None): @@ -838,7 +834,7 @@ def _locate_electrical_series(self, backend): except KeyError: available = _find_neurodata_type_from_backend(self.file, neurodata_type="ElectricalSeries", backend=backend) raise ValueError( - f"{self.electrical_series_path} not found in the NWB file!" f"Available options are: {available}." + f"{self.electrical_series_path} not found in the NWB file!Available options are: {available}." ) # --- electrodes table ---------------------------------------------------------------------- diff --git a/src/spikeinterface/extractors/phykilosortextractors.py b/src/spikeinterface/extractors/phykilosortextractors.py index 300a9b4662..995ffffe31 100644 --- a/src/spikeinterface/extractors/phykilosortextractors.py +++ b/src/spikeinterface/extractors/phykilosortextractors.py @@ -17,7 +17,7 @@ from spikeinterface.core.core_tools import define_function_from_class from spikeinterface.core.base import minimum_spike_dtype -from spikeinterface.postprocessing import ComputeSpikeAmplitudes, ComputeSpikeLocations +from spikeinterface.postprocessing import ComputeSpikeLocations from probeinterface import read_prb, Probe, ProbeGroup @@ -164,7 +164,6 @@ def __init__( del cluster_info["id"] if remove_empty_units: - unique_unit_ids_list = [int(clust) for clust in unique_unit_ids] cluster_info = cluster_info.query(f"cluster_id in {unique_unit_ids_list}") @@ -574,7 +573,6 @@ def _make_templates( # Used for kilosort 2, 2.5 and 3 else: - warnings.warn("Can't extract `ms_before` and `ms_after` from Kilosort output. Guessing a sensible value.") samples_in_templates = np.shape(new_templates)[1] diff --git a/src/spikeinterface/extractors/shybridextractors.py b/src/spikeinterface/extractors/shybridextractors.py index eca7d46724..9aa7439fab 100644 --- a/src/spikeinterface/extractors/shybridextractors.py +++ b/src/spikeinterface/extractors/shybridextractors.py @@ -41,9 +41,7 @@ class SHYBRIDRecordingExtractor(BinaryRecordingExtractor): Loaded data. """ - installation_mesg = ( - "To use the SHYBRID extractors, install SHYBRID and pyyaml: " "\n\n pip install shybrid pyyaml\n\n" - ) + installation_mesg = "To use the SHYBRID extractors, install SHYBRID and pyyaml: \n\n pip install shybrid pyyaml\n\n" def __init__(self, file_path): if HAVE_SHYBRID: diff --git a/src/spikeinterface/extractors/sinapsrecordingextractors.py b/src/spikeinterface/extractors/sinapsrecordingextractors.py index 3e50a17fb0..b3e55437bb 100644 --- a/src/spikeinterface/extractors/sinapsrecordingextractors.py +++ b/src/spikeinterface/extractors/sinapsrecordingextractors.py @@ -276,7 +276,7 @@ def get_sinaps_probe(probe_type: str) -> Probe: try: probe = get_probe(manufacturer="sinaps-research-platform", probe_name=f"{probe_type}") - except: + except Exception: # check if custom version of probe was used such as "p256s1_camera" if "_" in probe_type: probe_type = probe_type.split("_")[0] @@ -287,7 +287,7 @@ def get_sinaps_probe(probe_type: str) -> Probe: try: probe = get_probe(manufacturer="sinaps-research-platform", probe_name=f"{probe_type}") - except: + except Exception: warnings.warn( f"Could not load probe information for {probe_type}. Probe needs to be linked manually with rec.set_probe()" ) @@ -322,13 +322,13 @@ def parse_sinaps_meta(meta_file: str | Path) -> dict: val = val.replace("\n", "") try: val = int(val) - except: + except Exception: pass try: val = ast.literal_eval(val) if isinstance(val, tuple): val = float(str(val[0]) + "." + str(val[1])) - except: + except Exception: pass sinaps_info[key] = val return sinaps_info diff --git a/src/spikeinterface/extractors/tests/common_tests.py b/src/spikeinterface/extractors/tests/common_tests.py index ea733a368b..0741785d9f 100644 --- a/src/spikeinterface/extractors/tests/common_tests.py +++ b/src/spikeinterface/extractors/tests/common_tests.py @@ -102,7 +102,7 @@ def test_neo_annotations(self): path = entity kwargs = {} if hasattr(self.ExtractorClass, "NeoRawIOClass"): - rec = self.ExtractorClass(self.get_full_path(path), all_annotations=True, **kwargs) + _ = self.ExtractorClass(self.get_full_path(path), all_annotations=True, **kwargs) def test_pickling(self): for entity in self.entities: diff --git a/src/spikeinterface/extractors/tests/test_bidsextractors.py b/src/spikeinterface/extractors/tests/test_bidsextractors.py index 2c78c844ce..075c8e7166 100644 --- a/src/spikeinterface/extractors/tests/test_bidsextractors.py +++ b/src/spikeinterface/extractors/tests/test_bidsextractors.py @@ -5,6 +5,7 @@ @pytest.mark.skip("BIDS is tested locally only at the moment") def test_read_bids_folder(): + import spikeinterface.full as si # gin get NeuralEnsemble/BEP032-examples # cd BEP032-examples # gin get NeuralEnsemble/BEP032-examples @@ -16,12 +17,10 @@ def test_read_bids_folder(): recordings = read_bids(folder_path) # ~ print(recordings) - rec0 = recordings[0] + _ = recordings[0] rec1 = recordings[1] rec2 = recordings[2] - import spikeinterface.full as si - sorting = si.run_sorter("herdingspikes", rec1) print(sorting) exit() @@ -32,7 +31,6 @@ def test_read_bids_folder(): import matplotlib.pyplot as plt from probeinterface.plotting import plot_probe_group - fig, ax = plt.subplots() probegroup = rec2.get_probegroup() print(probegroup) plot_probe_group( diff --git a/src/spikeinterface/extractors/tests/test_cbin_ibl_extractors.py b/src/spikeinterface/extractors/tests/test_cbin_ibl_extractors.py index bc508979b9..b3f6036373 100644 --- a/src/spikeinterface/extractors/tests/test_cbin_ibl_extractors.py +++ b/src/spikeinterface/extractors/tests/test_cbin_ibl_extractors.py @@ -3,7 +3,7 @@ import numpy as np -from spikeinterface.extractors.extractor_classes import CompressedBinaryIblExtractor, read_cbin_ibl +from spikeinterface.extractors.extractor_classes import CompressedBinaryIblExtractor from spikeinterface.extractors.cbin_ibl import ( _get_saved_channel_indices, @@ -13,7 +13,7 @@ extract_stream_info, ) -from spikeinterface.extractors.tests.common_tests import RecordingCommonTestSuite, SortingCommonTestSuite +from spikeinterface.extractors.tests.common_tests import RecordingCommonTestSuite class CompressedBinaryIblExtractorTest(RecordingCommonTestSuite, unittest.TestCase): diff --git a/src/spikeinterface/extractors/tests/test_datalad_downloading.py b/src/spikeinterface/extractors/tests/test_datalad_downloading.py index 8abccc6707..082fe52da3 100644 --- a/src/spikeinterface/extractors/tests/test_datalad_downloading.py +++ b/src/spikeinterface/extractors/tests/test_datalad_downloading.py @@ -13,6 +13,7 @@ def test_download_dataset(): # local_folder automatic local_path = download_dataset(repo=repo, remote_path=remote_path, local_folder=None) + assert local_path is not None if __name__ == "__main__": diff --git a/src/spikeinterface/extractors/tests/test_herdingspikesextractors.py b/src/spikeinterface/extractors/tests/test_herdingspikesextractors.py index 2286e229c0..15828c4c70 100644 --- a/src/spikeinterface/extractors/tests/test_herdingspikesextractors.py +++ b/src/spikeinterface/extractors/tests/test_herdingspikesextractors.py @@ -1,7 +1,5 @@ import pytest -from spikeinterface.extractors import * - @pytest.mark.skip("HerdingSpikes can be tested after running run_herdingspikes()") def test_herdingspikesextractors(): diff --git a/src/spikeinterface/extractors/tests/test_iblextractors.py b/src/spikeinterface/extractors/tests/test_iblextractors.py index eb87b34829..f09ebf8354 100644 --- a/src/spikeinterface/extractors/tests/test_iblextractors.py +++ b/src/spikeinterface/extractors/tests/test_iblextractors.py @@ -1,4 +1,3 @@ -import sys from re import escape from unittest import TestCase @@ -27,7 +26,7 @@ def setUpClass(cls): silent=True, cache_dir=None, ) - except: + except Exception: print("Skipping test due to server being down.") pytest.skip("Skipping test due to server being down.") try: @@ -124,7 +123,7 @@ def setUpClass(cls): silent=True, cache_dir=None, ) - except: + except Exception: pytest.skip("Skipping test due to server being down.") cls.recording = read_ibl_recording(eid=cls.eid, stream_name="probe00.ap", load_sync_channel=True, one=cls.one) cls.small_scaled_trace = cls.recording.get_traces(start_frame=5, end_frame=26, return_in_uV=True) @@ -200,7 +199,7 @@ def test_ibl_sorting_extractor(self): silent=True, cache_dir=None, ) - except: + except Exception: pytest.skip("Skipping test due to server being down.") sorting = read_ibl_sorting(pid=PID, one=one, revision="2023-12-05") assert len(sorting.unit_ids) == 733 diff --git a/src/spikeinterface/extractors/tests/test_mdaextractors.py b/src/spikeinterface/extractors/tests/test_mdaextractors.py index 88daddeab4..e0db494eb2 100644 --- a/src/spikeinterface/extractors/tests/test_mdaextractors.py +++ b/src/spikeinterface/extractors/tests/test_mdaextractors.py @@ -17,7 +17,7 @@ def test_mda_extractors(create_cache_folder): MdaRecordingExtractor.write_recording(rec, cache_folder / "mdatest") rec_mda = MdaRecordingExtractor(cache_folder / "mdatest") - probe = rec_mda.get_probe() + assert rec_mda.has_probe() check_recordings_equal(rec, rec_mda, return_in_uV=False) diff --git a/src/spikeinterface/extractors/tests/test_neoextractors.py b/src/spikeinterface/extractors/tests/test_neoextractors.py index 228409b8f9..d7833c90cd 100644 --- a/src/spikeinterface/extractors/tests/test_neoextractors.py +++ b/src/spikeinterface/extractors/tests/test_neoextractors.py @@ -2,7 +2,6 @@ import platform import subprocess import os -from packaging import version import importlib.util import pytest @@ -37,7 +36,6 @@ AxonaRecordingExtractor, Plexon2EventExtractor, MaxwellRecordingExtractor, - CedRecordingExtractor, AlphaOmegaRecordingExtractor, Spike2RecordingExtractor, EDFRecordingExtractor, diff --git a/src/spikeinterface/extractors/tests/test_nwbextractors.py b/src/spikeinterface/extractors/tests/test_nwbextractors.py index b442216d86..ba724b4731 100644 --- a/src/spikeinterface/extractors/tests/test_nwbextractors.py +++ b/src/spikeinterface/extractors/tests/test_nwbextractors.py @@ -447,7 +447,7 @@ def test_failure_with_wrong_electrical_series_path(generate_nwbfile, use_pynwb): """Test that the extractor raises an error if the electrical series name is not found.""" path_to_nwbfile, _ = generate_nwbfile with pytest.raises(ValueError): - recording_extractor = NwbRecordingExtractor( + _ = NwbRecordingExtractor( path_to_nwbfile, electrical_series_path="acquisition/ElectricalSeries3", use_pynwb=use_pynwb, @@ -627,7 +627,7 @@ def test_sorting_extraction_start_time(tmp_path, use_pynwb): def test_sorting_extraction_start_time_from_series(tmp_path, use_pynwb): from pynwb import NWBHDF5IO from pynwb.testing.mock.file import mock_NWBFile - from pynwb.ecephys import ElectricalSeries, LFP, FilteredEphys + from pynwb.ecephys import ElectricalSeries from pynwb.testing.mock.ecephys import mock_electrodes @@ -860,7 +860,7 @@ def test_sorting_electrical_series_path_and_time_base_are_mutually_exclusive(tmp **extra_kwarg, ) expected_error = ( - "Provide either 'electrical_series_path' or the time base ('sampling_frequency' and " "'t_start'), not both." + "Provide either 'electrical_series_path' or the time base ('sampling_frequency' and 't_start'), not both." ) assert str(exc_info.value) == expected_error @@ -1097,7 +1097,7 @@ def test_multiple_unit_tables(tmp_path, use_pynwb): # passing a non existing unit table name should raise an error with pytest.raises(ValueError): - sorting_extractor = NwbSortingExtractor( + _ = NwbSortingExtractor( file_path=file_path, sampling_frequency=10.0, t_start=0, use_pynwb=use_pynwb, unit_table_path="units2" ) diff --git a/src/spikeinterface/extractors/tests/test_nwbextractors_streaming.py b/src/spikeinterface/extractors/tests/test_nwbextractors_streaming.py index 7d43253acf..691f0c978b 100644 --- a/src/spikeinterface/extractors/tests/test_nwbextractors_streaming.py +++ b/src/spikeinterface/extractors/tests/test_nwbextractors_streaming.py @@ -10,7 +10,7 @@ from spikeinterface import load from spikeinterface.core.testing import check_recordings_equal -from spikeinterface.core.testing import check_recordings_equal, check_sortings_equal +from spikeinterface.core.testing import check_sortings_equal from spikeinterface.extractors.extractor_classes import NwbRecordingExtractor, NwbSortingExtractor py_version = sys.version_info @@ -42,8 +42,6 @@ def test_recording_s3_nwb_fsspec(tmp_path, cache): dtype = rec.get_dtype() for segment_index in range(num_seg): - num_samples = rec.get_num_samples(segment_index=segment_index) - full_traces = rec.get_traces(segment_index=segment_index, start_frame=start_frame, end_frame=end_frame) assert full_traces.shape == (num_frames, num_chans) assert full_traces.dtype == dtype @@ -78,8 +76,6 @@ def test_recording_s3_nwb_remfile(): dtype = rec.get_dtype() for segment_index in range(num_seg): - num_samples = rec.get_num_samples(segment_index=segment_index) - full_traces = rec.get_traces(segment_index=segment_index, start_frame=start_frame, end_frame=end_frame) assert full_traces.shape == (num_frames, num_chans) assert full_traces.dtype == dtype @@ -108,8 +104,6 @@ def test_recording_s3_nwb_remfile_file_like(tmp_path): dtype = rec.get_dtype() for segment_index in range(num_seg): - num_samples = rec.get_num_samples(segment_index=segment_index) - full_traces = rec.get_traces(segment_index=segment_index, start_frame=start_frame, end_frame=end_frame) assert full_traces.shape == (num_frames, num_chans) assert full_traces.dtype == dtype diff --git a/src/spikeinterface/extractors/tests/test_shybridextractors.py b/src/spikeinterface/extractors/tests/test_shybridextractors.py index e4458f0b36..b69e37cdbd 100644 --- a/src/spikeinterface/extractors/tests/test_shybridextractors.py +++ b/src/spikeinterface/extractors/tests/test_shybridextractors.py @@ -22,6 +22,7 @@ def test_shybrid_extractors(create_cache_folder): ) rec_shybrid = SHYBRIDRecordingExtractor(cache_folder / "shybridtest" / "recording.yml") probe = rec_shybrid.get_probe() + assert probe is not None check_recordings_equal(rec, rec_shybrid, return_in_uV=False) diff --git a/src/spikeinterface/extractors/tests/test_toy_example.py b/src/spikeinterface/extractors/tests/test_toy_example.py index fccb977c85..f863d89cdb 100644 --- a/src/spikeinterface/extractors/tests/test_toy_example.py +++ b/src/spikeinterface/extractors/tests/test_toy_example.py @@ -12,6 +12,7 @@ def test_toy_example(): assert sorting.get_num_segments() == 1 probe = rec.get_probe() + assert probe is not None if __name__ == "__main__": diff --git a/src/spikeinterface/extractors/yassextractors.py b/src/spikeinterface/extractors/yassextractors.py index 38efeae996..e03a0ba969 100644 --- a/src/spikeinterface/extractors/yassextractors.py +++ b/src/spikeinterface/extractors/yassextractors.py @@ -25,7 +25,7 @@ class YassSortingExtractor(BaseSorting): def __init__(self, folder_path): try: import yaml - except: + except Exception: raise ImportError(self.installation_mesg) folder_path = Path(folder_path) diff --git a/src/spikeinterface/generation/drift_tools.py b/src/spikeinterface/generation/drift_tools.py index 6b95ac3834..da0e85cc32 100644 --- a/src/spikeinterface/generation/drift_tools.py +++ b/src/spikeinterface/generation/drift_tools.py @@ -71,7 +71,6 @@ def interpolate_templates( template = templates_array[template_index, sample_index, :] if interpolation_method == "thin_plate": - if "neighbors" not in interpolation_kwargs: # If neighbors it not passed, `RBFInterpolator` uses all channels. # This works poorly for standard ephys template interpolation. @@ -389,9 +388,9 @@ def __init__( ): from scipy.spatial import distance - assert isinstance( - drifting_templates, DriftingTemplates - ), "drifting_templates must be a DriftingTemplates object" + assert isinstance(drifting_templates, DriftingTemplates), ( + "drifting_templates must be a DriftingTemplates object" + ) self.drifting_templates = drifting_templates if parent_recording is None: @@ -419,15 +418,15 @@ def __init__( amplitude_vector = amplitude_factor if parent_recording is not None: - assert ( - parent_recording.get_num_segments() == sorting.get_num_segments() - ), "parent_recording must have the same number of segments as sorting" - assert ( - parent_recording.get_sampling_frequency() == sorting.get_sampling_frequency() - ), "parent_recording must have the same sampling frequency as sorting" - assert ( - parent_recording.get_num_channels() == drifting_templates.num_channels - ), "parent_recording must have the same number of channels as templates" + assert parent_recording.get_num_segments() == sorting.get_num_segments(), ( + "parent_recording must have the same number of segments as sorting" + ) + assert parent_recording.get_sampling_frequency() == sorting.get_sampling_frequency(), ( + "parent_recording must have the same sampling frequency as sorting" + ) + assert parent_recording.get_num_channels() == drifting_templates.num_channels, ( + "parent_recording must have the same number of channels as templates" + ) parent_recording.copy_metadata(self) if num_samples is None: @@ -441,29 +440,29 @@ def __init__( num_samples = [num_samples] # check drift vector shape and length - assert ( - len(displacement_vectors) == sorting.get_num_segments() - ), "displacement_vectors must have the same number of segments as sorting" + assert len(displacement_vectors) == sorting.get_num_segments(), ( + "displacement_vectors must have the same number of segments as sorting" + ) if displacement_unit_factor is None: displacement_unit_factor = np.ones(sorting.get_num_units(), dtype="float32") - assert displacement_unit_factor.shape[0] == len( - sorting.unit_ids - ), "displacement_unit_factor must have the same number of units as sorting" + assert displacement_unit_factor.shape[0] == len(sorting.unit_ids), ( + "displacement_unit_factor must have the same number of units as sorting" + ) # displacement_vectors_indices = [] for num_segment in range(sorting.get_num_segments()): duration = displacement_vectors[num_segment].shape[0] / displacement_sampling_frequency - assert ( - duration >= num_samples[num_segment] / sorting.get_sampling_frequency() - ), "displacement_vectors duration must span the entire recording segment" - assert ( - displacement_vectors[num_segment].shape[2] == displacement_unit_factor.shape[1] - ), "displacement_vectors and displacement_unit_factor must have the same number of motions" + assert duration >= num_samples[num_segment] / sorting.get_sampling_frequency(), ( + "displacement_vectors duration must span the entire recording segment" + ) + assert displacement_vectors[num_segment].shape[2] == displacement_unit_factor.shape[1], ( + "displacement_vectors and displacement_unit_factor must have the same number of motions" + ) # TODO SharedMem for templates if mode == "precompute": - assert ( - drifting_templates.templates_array_moved is not None - ), "drifting_templates must have precomputed displacements" + assert drifting_templates.templates_array_moved is not None, ( + "drifting_templates must have precomputed displacements" + ) displacements = drifting_templates.displacements # compute the displacement indices diff --git a/src/spikeinterface/generation/drifting_generator.py b/src/spikeinterface/generation/drifting_generator.py index f217dda1b3..1d3cda2e16 100644 --- a/src/spikeinterface/generation/drifting_generator.py +++ b/src/spikeinterface/generation/drifting_generator.py @@ -124,8 +124,8 @@ def make_one_displacement_vector( t_start_drift = 0.0 if t_start_drift is None else t_start_drift t_end_drift = duration if t_end_drift is None else t_end_drift - assert t_start_drift < duration, f"'t_start_drift' must preceed 'duration'!" - assert t_end_drift <= duration, f"'t_end_drift' must preceed 'duration'!" + assert t_start_drift < duration, "'t_start_drift' must preceed 'duration'!" + assert t_end_drift <= duration, "'t_end_drift' must preceed 'duration'!" start_drift_index = int(t_start_drift * displacement_sampling_frequency) end_drift_index = int(t_end_drift * displacement_sampling_frequency) @@ -133,7 +133,6 @@ def make_one_displacement_vector( displacement_vector = np.zeros(num_samples, dtype="float32") if drift_mode == "zigzag": - times = np.arange(end_drift_index - start_drift_index) / displacement_sampling_frequency freq = 1.0 / period_s @@ -455,9 +454,9 @@ def generate_drifting_recording( num_units = sorting.get_num_units() sampling_frequency = sorting.sampling_frequency if sorting._recording is not None: - assert ( - sorting.get_total_duration() == duration - ), "Sorting should have the same duration as the generated data" + assert sorting.get_total_duration() == duration, ( + "Sorting should have the same duration as the generated data" + ) # probe if probe is None: diff --git a/src/spikeinterface/generation/hybrid_tools.py b/src/spikeinterface/generation/hybrid_tools.py index 426699f743..7fad61ee48 100644 --- a/src/spikeinterface/generation/hybrid_tools.py +++ b/src/spikeinterface/generation/hybrid_tools.py @@ -121,9 +121,9 @@ def select_templates( Templates The selected templates """ - assert ( - min_amplitude is not None or max_amplitude is not None or min_depth is not None or max_depth is not None - ), "At least one of min_amplitude, max_amplitude, min_depth, max_depth should be provided" + assert min_amplitude is not None or max_amplitude is not None or min_depth is not None or max_depth is not None, ( + "At least one of min_amplitude, max_amplitude, min_depth, max_depth should be provided" + ) # get template amplitudes and depth main_channel_indices = templates.get_main_channels(outputs="index", with_dict=False) @@ -400,9 +400,9 @@ def generate_hybrid_recording( durations = num_samples / sampling_frequency channel_locations = probe.contact_positions - assert ( - templates is not None or sorting is not None or generate_sorting_kwargs is not None - ), "Provide templates or sorting or generate_sorting_kwargs" + assert templates is not None or sorting is not None or generate_sorting_kwargs is not None, ( + "Provide templates or sorting or generate_sorting_kwargs" + ) # check num_units num_units = None @@ -444,9 +444,9 @@ def generate_hybrid_recording( from spikeinterface.postprocessing.localization_tools import compute_monopolar_triangulation assert isinstance(templates, Templates), "templates should be a Templates object" - assert ( - templates.num_channels == recording.get_num_channels() - ), "templates and recording should have the same number of channels" + assert templates.num_channels == recording.get_num_channels(), ( + "templates and recording should have the same number of channels" + ) nbefore = templates.nbefore nafter = templates.nafter unit_locations = compute_monopolar_triangulation(templates, peak_sign="both", peak_mode="extremum") @@ -485,9 +485,9 @@ def generate_hybrid_recording( num_spikes = sorting.to_spike_vector().size sorting.set_property("gt_unit_locations", unit_locations) - assert (nbefore + nafter) == templates_array.shape[ - 1 - ], "templates and ms_before, ms_after should have the same length" + assert (nbefore + nafter) == templates_array.shape[1], ( + "templates and ms_before, ms_after should have the same length" + ) if templates_array.ndim == 3: upsample_vector = None diff --git a/src/spikeinterface/generation/noise_tools.py b/src/spikeinterface/generation/noise_tools.py index 7fbecf0c9b..3820c55b20 100644 --- a/src/spikeinterface/generation/noise_tools.py +++ b/src/spikeinterface/generation/noise_tools.py @@ -81,9 +81,9 @@ def __init__( num_segments = len(durations) if cov_matrix is not None: - assert ( - cov_matrix.shape[0] == cov_matrix.shape[1] == num_channels - ), "cov_matrix should have a size (num_channels, num_channels)" + assert cov_matrix.shape[0] == cov_matrix.shape[1] == num_channels, ( + "cov_matrix should have a size (num_channels, num_channels)" + ) # very important here when multiprocessing and dump/load seed = _ensure_seed(seed) diff --git a/src/spikeinterface/generation/template_database.py b/src/spikeinterface/generation/template_database.py index 83fb42fe38..999f46ebf3 100644 --- a/src/spikeinterface/generation/template_database.py +++ b/src/spikeinterface/generation/template_database.py @@ -109,12 +109,12 @@ def query_templates_from_database(template_df: "pandas.DataFrame", verbose: bool current_channel_locations = templates.get_channel_locations() current_sampling_frequency = templates.sampling_frequency - assert ( - current_nbefore == nbefore - ), f"Number of samples before the peak is not consistent across datasets: {current_nbefore} != {nbefore}" - assert ( - current_sampling_frequency == sampling_frequency - ), f"Sampling frequency is not consistent across datasets: {current_sampling_frequency} != {sampling_frequency}" + assert current_nbefore == nbefore, ( + f"Number of samples before the peak is not consistent across datasets: {current_nbefore} != {nbefore}" + ) + assert current_sampling_frequency == sampling_frequency, ( + f"Sampling frequency is not consistent across datasets: {current_sampling_frequency} != {sampling_frequency}" + ) assert np.array_equal( current_channel_locations - current_channel_locations[0], channel_locations - channel_locations[0], diff --git a/src/spikeinterface/generation/tests/test_drifing_generator.py b/src/spikeinterface/generation/tests/test_drifing_generator.py index 5eb49a04c6..99210abb6b 100644 --- a/src/spikeinterface/generation/tests/test_drifing_generator.py +++ b/src/spikeinterface/generation/tests/test_drifing_generator.py @@ -9,17 +9,13 @@ def test_make_one_displacement_vector(): - displacement_vector = make_one_displacement_vector( - drift_mode="zigzag", duration=700.0, period_s=300, t_start_drift=100.0 - ) + _ = make_one_displacement_vector(drift_mode="zigzag", duration=700.0, period_s=300, t_start_drift=100.0) - displacement_vector = make_one_displacement_vector( + _ = make_one_displacement_vector( drift_mode="bump", duration=700.0, period_s=300, bump_interval_s=(30, 90.0), t_start_drift=100.0, seed=2205 ) - displacement_vector = make_one_displacement_vector( - drift_mode="random_walk", duration=700.0, t_start_drift=100.0, seed=2205 - ) + _ = make_one_displacement_vector(drift_mode="random_walk", duration=700.0, t_start_drift=100.0, seed=2205) # import matplotlib.pyplot as plt # fig, ax = plt.subplots() diff --git a/src/spikeinterface/generation/tests/test_noise_tools.py b/src/spikeinterface/generation/tests/test_noise_tools.py index f633ed1de4..d09ea86fde 100644 --- a/src/spikeinterface/generation/tests/test_noise_tools.py +++ b/src/spikeinterface/generation/tests/test_noise_tools.py @@ -8,7 +8,7 @@ def test_generate_noise(): probe = probeinterface.generate_multi_columns_probe() - noise = generate_noise( + _ = generate_noise( probe, sampling_frequency=25000.0, durations=[10.0], @@ -18,7 +18,7 @@ def test_generate_noise(): seed=2205, ) - noise = generate_noise( + _ = generate_noise( probe, sampling_frequency=25000.0, durations=[10.0], diff --git a/src/spikeinterface/metrics/quality/misc_metrics.py b/src/spikeinterface/metrics/quality/misc_metrics.py index 9c5c3fa258..016a2d24f9 100644 --- a/src/spikeinterface/metrics/quality/misc_metrics.py +++ b/src/spikeinterface/metrics/quality/misc_metrics.py @@ -88,7 +88,7 @@ def compute_presence_ratios( mean_fr_ratio_thresh = float(mean_fr_ratio_thresh) if mean_fr_ratio_thresh < 0: raise ValueError( - f"Expected positive float for `mean_fr_ratio_thresh` param." f"Provided value: {mean_fr_ratio_thresh}" + f"Expected positive float for `mean_fr_ratio_thresh` param.Provided value: {mean_fr_ratio_thresh}" ) if mean_fr_ratio_thresh > 1: warnings.warn("`mean_fr_ratio_thres` parameter above 1 might lead to low presence ratios.") @@ -96,11 +96,10 @@ def compute_presence_ratios( presence_ratios = {} if total_samples < bin_duration_samples: warnings.warn( - f"Bin duration of {bin_duration_s}s is larger than recording duration. " f"Presence ratios are set to NaN." + f"Bin duration of {bin_duration_s}s is larger than recording duration. Presence ratios are set to NaN." ) presence_ratios = {unit_id: np.nan for unit_id in unit_ids} else: - for unit_id in unit_ids: if num_spikes[unit_id] == 0: presence_ratios[unit_id] = np.nan @@ -1240,9 +1239,7 @@ def compute_drift_metrics( segment_samples = [sorting_analyzer.get_num_samples(i) for i in range(sorting_analyzer.get_num_segments())] data = spike_locations_by_unit[unit_ids[0]] - assert direction in data.dtype.names, ( - f"Direction {direction} is invalid. Available directions: " f"{data.dtype.names}" - ) + assert direction in data.dtype.names, f"Direction {direction} is invalid. Available directions: {data.dtype.names}" bin_edges_for_units = compute_bin_edges_per_unit( sorting, segment_samples=segment_samples, periods=periods, bin_duration_s=interval_s, concatenated=False ) diff --git a/src/spikeinterface/metrics/quality/pca_metrics.py b/src/spikeinterface/metrics/quality/pca_metrics.py index 9134648fe1..d9f5a4a904 100644 --- a/src/spikeinterface/metrics/quality/pca_metrics.py +++ b/src/spikeinterface/metrics/quality/pca_metrics.py @@ -31,7 +31,7 @@ def _mahalanobis_metrics_function(sorting_analyzer, unit_ids, tmp_data, **metric try: isolation_distance, l_ratio = mahalanobis_metrics(pcs_flat, labels, unit_id) - except: + except Exception: isolation_distance = np.nan l_ratio = np.nan @@ -71,7 +71,7 @@ def _d_prime_metric_function(sorting_analyzer, unit_ids, tmp_data, **metric_para try: d_prime = d_prime_metric(pcs_flat, labels, unit_id) - except: + except Exception: d_prime = np.nan d_prime_dict[unit_id] = d_prime @@ -94,7 +94,7 @@ def _nn_one_unit(args): try: nn_hit_rate, nn_miss_rate = nearest_neighbors_metrics(pcs_flat, labels, unit_id, **metric_params) - except: + except Exception: nn_hit_rate = np.nan nn_miss_rate = np.nan @@ -116,7 +116,7 @@ def _nearest_neighbor_metric_function(sorting_analyzer, unit_ids, tmp_data, **me try: nn_hit_rate, nn_miss_rate = nearest_neighbors_metrics(pcs_flat, labels, unit_id, **metric_params) - except: + except Exception: nn_hit_rate = np.nan nn_miss_rate = np.nan @@ -176,7 +176,7 @@ def _nn_advanced_one_unit(args): seed=seed, **nn_isolation_params, ) - except: + except Exception: nn_isolation, nn_unit_id = np.nan, np.nan # NN Noise Overlap @@ -189,7 +189,7 @@ def _nn_advanced_one_unit(args): seed=seed, **nn_noise_params, ) - except: + except Exception: nn_noise_overlap = np.nan return unit_id, nn_isolation, nn_unit_id, nn_noise_overlap @@ -321,7 +321,7 @@ def _silhouette_metric_function(sorting_analyzer, unit_ids, tmp_data, **metric_p silhouette_value = simplified_silhouette_score(pcs_flat, labels, unit_id) else: # method == "full" silhouette_value = silhouette_score(pcs_flat, labels, unit_id) - except: + except Exception: silhouette_value = np.nan silhouette_dict[unit_id] = silhouette_value diff --git a/src/spikeinterface/metrics/quality/tests/test_metrics_functions.py b/src/spikeinterface/metrics/quality/tests/test_metrics_functions.py index 4e793f130b..6d69324ae9 100644 --- a/src/spikeinterface/metrics/quality/tests/test_metrics_functions.py +++ b/src/spikeinterface/metrics/quality/tests/test_metrics_functions.py @@ -315,7 +315,7 @@ def test_calculate_firing_range(sorting_analyzer_simple): firing_ranges_empty = compute_firing_ranges(sorting_analyzer, periods=empty_periods) assert np.all(np.isnan(np.array(list(firing_ranges_empty.values())))) - with pytest.warns(UserWarning) as w: + with pytest.warns(UserWarning): firing_ranges_nan = compute_firing_ranges( sorting_analyzer, bin_size_s=sorting_analyzer.get_total_duration() + 1 ) @@ -400,6 +400,7 @@ def test_calculate_amplitude_cv_metrics(sorting_analyzer_simple, periods_simple) def test_calculate_snrs(sorting_analyzer_simple, periods_simple): sorting_analyzer = sorting_analyzer_simple snrs = compute_snrs(sorting_analyzer) + assert isinstance(snrs, dict) # SNR doesn't support periods # testing method accuracy with magic number is not a good pratcice, I remove this. @@ -786,7 +787,7 @@ def test_unit_structure_in_output(small_sorting_analyzer): metric_fun = metric.metric_function try: qm_param = qm_params[metric_name] - except: + except Exception: qm_param = {} result_all = metric_fun(sorting_analyzer=small_sorting_analyzer, **qm_param) @@ -802,7 +803,6 @@ def test_unit_structure_in_output(small_sorting_analyzer): else: for result_ind, result in enumerate(result_sub): - assert list(result_all[result_ind].keys()) == ["#3", "#9", "#4"], error assert result_sub[result_ind].keys() == set(["#4", "#9"]), error diff --git a/src/spikeinterface/metrics/quality/tests/test_quality_metric_calculator.py b/src/spikeinterface/metrics/quality/tests/test_quality_metric_calculator.py index 823d53f347..2f45a45449 100644 --- a/src/spikeinterface/metrics/quality/tests/test_quality_metric_calculator.py +++ b/src/spikeinterface/metrics/quality/tests/test_quality_metric_calculator.py @@ -217,7 +217,7 @@ def test_quality_metrics_with_periods(): periods[idx]["end_sample_index"] = period_end periods[idx]["segment_index"] = segment_index - metrics_ext_periods = compute_quality_metrics( + _ = compute_quality_metrics( sorting_analyzer, metric_names=None, skip_pc_metrics=True, @@ -239,7 +239,7 @@ def test_quality_metrics_with_periods(): # should not fail if external periods are the same as valid unit periods valid_periods = sorting_analyzer.get_extension("valid_unit_periods").get_data(outputs="numpy") - metrics_ext_periods = compute_quality_metrics( + _ = compute_quality_metrics( sorting_analyzer, metric_names=None, skip_pc_metrics=True, @@ -261,7 +261,6 @@ def test_quality_metrics_with_periods(): if __name__ == "__main__": - sorting_analyzer = get_sorting_analyzer() print(sorting_analyzer) diff --git a/src/spikeinterface/metrics/template/template_metrics.py b/src/spikeinterface/metrics/template/template_metrics.py index a23343d0ec..dd79983949 100644 --- a/src/spikeinterface/metrics/template/template_metrics.py +++ b/src/spikeinterface/metrics/template/template_metrics.py @@ -88,7 +88,6 @@ def _handle_backward_compatibility_on_load(self): # For backwards compatibility - this reformats metrics_kwargs as metric_params if (metrics_kwargs := self.params.get("metrics_kwargs")) is not None: - metric_params = {} for metric_name in self.params["metric_names"]: metric_params[metric_name] = deepcopy(metrics_kwargs) diff --git a/src/spikeinterface/metrics/template/tests/test_template_metrics.py b/src/spikeinterface/metrics/template/tests/test_template_metrics.py index 30314615d1..75204e543d 100644 --- a/src/spikeinterface/metrics/template/tests/test_template_metrics.py +++ b/src/spikeinterface/metrics/template/tests/test_template_metrics.py @@ -6,7 +6,7 @@ compute_template_metrics, get_single_channel_template_metric_names, ) -from spikeinterface.metrics.template.metrics import single_channel_metrics, multi_channel_metrics +from spikeinterface.metrics.template.metrics import single_channel_metrics template_metrics = get_single_channel_template_metric_names() @@ -137,7 +137,6 @@ def test_save_template_metrics(small_sorting_analyzer, create_cache_folder): class TestTemplateMetrics(AnalyzerExtensionCommonTestSuite): - @pytest.mark.parametrize( "params", [ diff --git a/src/spikeinterface/postprocessing/__init__.py b/src/spikeinterface/postprocessing/__init__.py index 2495536d03..fc5c878fe0 100644 --- a/src/spikeinterface/postprocessing/__init__.py +++ b/src/spikeinterface/postprocessing/__init__.py @@ -41,8 +41,6 @@ from .alignsorting import align_sorting, AlignSortingExtractor -from .noise_level import compute_noise_levels, ComputeNoiseLevels - from .valid_unit_periods import ( ComputeValidUnitPeriods, compute_valid_unit_periods, diff --git a/src/spikeinterface/postprocessing/amplitude_scalings.py b/src/spikeinterface/postprocessing/amplitude_scalings.py index 3b6653f70c..6e555c512e 100644 --- a/src/spikeinterface/postprocessing/amplitude_scalings.py +++ b/src/spikeinterface/postprocessing/amplitude_scalings.py @@ -93,22 +93,20 @@ def _get_pipeline_nodes(self): # if ms_before / ms_after are set in params then the original templates are shorten if self.params["ms_before"] is not None: cut_out_before = ms_to_samples(self.params["ms_before"], self.sorting_analyzer.sampling_frequency) - assert ( - cut_out_before <= nbefore - ), f"`ms_before` must be smaller than `ms_before` used in ComputeTemplates: {nbefore}" + assert cut_out_before <= nbefore, ( + f"`ms_before` must be smaller than `ms_before` used in ComputeTemplates: {nbefore}" + ) else: cut_out_before = nbefore if self.params["ms_after"] is not None: cut_out_after = ms_to_samples(self.params["ms_after"], self.sorting_analyzer.sampling_frequency) - assert ( - cut_out_after <= nafter - ), f"`ms_after` must be smaller than `ms_after` used in templates: {templates_ext.params['ms_after']}" + assert cut_out_after <= nafter, ( + f"`ms_after` must be smaller than `ms_after` used in templates: {templates_ext.params['ms_after']}" + ) else: cut_out_after = nafter - extremum_channels_indices = self.sorting_analyzer.get_main_channels(outputs="index", with_dict=True) - # collisions handle_collisions = self.params["handle_collisions"] delta_collision_ms = self.params["delta_collision_ms"] @@ -120,9 +118,9 @@ def _get_pipeline_nodes(self): sparsity = self.params["sparsity"] # assert provided sparsity is sparser than the one in the waveform extractor waveform_sparsity = self.sorting_analyzer.sparsity - assert np.all( - np.sum(waveform_sparsity.mask, 1) - np.sum(sparsity.mask, 1) > 0 - ), "The provided sparsity needs to be sparser than the one in the waveform extractor!" + assert np.all(np.sum(waveform_sparsity.mask, 1) - np.sum(sparsity.mask, 1) > 0), ( + "The provided sparsity needs to be sparser than the one in the waveform extractor!" + ) elif not self.sorting_analyzer.is_sparse() and self.params["sparsity"] is not None: sparsity = self.params["sparsity"] else: @@ -189,9 +187,9 @@ def __init__( self._offsets = None self._dtype = np.float32 spike_retriever = find_parent_of_type(parents, SpikeRetriever) - assert isinstance( - spike_retriever, SpikeRetriever - ), "SpikeAmplitudeNode needs a single SpikeRetriever as a parent" + assert isinstance(spike_retriever, SpikeRetriever), ( + "SpikeAmplitudeNode needs a single SpikeRetriever as a parent" + ) assert spike_retriever.include_spikes_in_margin, "Need SpikeRetriever with include_spikes_in_margin=True" if not handle_collisions: self._margin = max(nbefore, nafter) @@ -659,7 +657,6 @@ def fit_collision( y = local_waveform.T.flatten() X = np.zeros((len(y), len(collision))) for i, spike in enumerate(collision): - # float64 like X, so templates are not truncated to the dtype of unscaled integer or float16 traces full_template = np.zeros(local_waveform.shape) @@ -716,14 +713,14 @@ def _plot_collisions(sorting_analyzer, sparsity=None, num_collisions=None): # TODO: this is broken, sac no longer (06/06/2024) # has _extension_data and its collisions attribute is unused - collisions = sac._extension_data[f"collisions"] + collisions = sac._extension_data["collisions"] collision_keys = list(collisions.keys()) num_collisions = num_collisions or len(collisions) num_collisions = min(num_collisions, len(collisions)) for i in range(num_collisions): overlapping_spikes = collisions[collision_keys[i]] - ax = _plot_one_collision( + _ = _plot_one_collision( sorting_analyzer, collision_keys[i], overlapping_spikes, spikes, scalings=scalings, sparsity=sparsity ) diff --git a/src/spikeinterface/postprocessing/localization_tools.py b/src/spikeinterface/postprocessing/localization_tools.py index 60746c11e9..06af4a46bd 100644 --- a/src/spikeinterface/postprocessing/localization_tools.py +++ b/src/spikeinterface/postprocessing/localization_tools.py @@ -1,5 +1,3 @@ -from typing import Literal - import warnings import importlib.util @@ -110,9 +108,6 @@ def compute_monopolar_triangulation( for i, unit_id in enumerate(unit_ids): chan_inds = sparsity.unit_id_to_channel_indices[unit_id] neighbours_mask[i, chan_inds] = True - enforce_decrease_radial_parents = make_radial_order_parents(contact_locations, neighbours_mask) - - best_channels = sorting_analyzer_or_templates.get_main_channels(outputs="index", with_dict=True) unit_location = np.zeros((unit_ids.size, 4), dtype="float64") for i, unit_id in enumerate(unit_ids): diff --git a/src/spikeinterface/postprocessing/noise_level.py b/src/spikeinterface/postprocessing/noise_level.py deleted file mode 100644 index 59ede21fcb..0000000000 --- a/src/spikeinterface/postprocessing/noise_level.py +++ /dev/null @@ -1,3 +0,0 @@ -# "noise_levels" extensions is now in core -# this is kept name space compatibility but should be removed soon -from spikeinterface.core.analyzer_extension_core import ComputeNoiseLevels, compute_noise_levels diff --git a/src/spikeinterface/postprocessing/principal_component.py b/src/spikeinterface/postprocessing/principal_component.py index 225b37c9f0..63bc0ee26d 100644 --- a/src/spikeinterface/postprocessing/principal_component.py +++ b/src/spikeinterface/postprocessing/principal_component.py @@ -394,9 +394,9 @@ def run_for_all_spikes(self, file_path=None, verbose=False, **job_kwargs): p = self.params sorting_analyzer = self.sorting_analyzer sorting = sorting_analyzer.sorting - assert ( - sorting_analyzer.has_recording() or sorting_analyzer.has_temporary_recording() - ), "To compute PCA projections for all spikes, the sorting analyzer needs the recording" + assert sorting_analyzer.has_recording() or sorting_analyzer.has_temporary_recording(), ( + "To compute PCA projections for all spikes, the sorting analyzer needs the recording" + ) recording = sorting_analyzer.recording # assert sorting.get_num_segments() == 1 @@ -422,7 +422,7 @@ def run_for_all_spikes(self, file_path=None, verbose=False, **job_kwargs): num_spikes = sorting.to_spike_vector().size shape = (num_spikes, p["n_components"], max_channels_per_template) - all_pcs = np.lib.format.open_memmap(filename=file_path, mode="w+", dtype="float32", shape=shape) + _ = np.lib.format.open_memmap(filename=file_path, mode="w+", dtype="float32", shape=shape) all_pcs_args = dict(filename=file_path, mode="r+", dtype="float32", shape=shape) waveforms_ext = self.sorting_analyzer.get_extension("waveforms") @@ -578,7 +578,7 @@ def _transform_waveforms(self, spikes, waveforms, pca_model, progress_bar): try: proj = pca_model.transform(wfs[:, :, wf_ind]) pca_projection[:, :, wf_ind][spike_mask, :] = proj - except: + except Exception: # this could happen if len(wfs) is less then n_comp for a channel project_on_non_fitted = True if project_on_non_fitted: diff --git a/src/spikeinterface/postprocessing/spike_amplitudes.py b/src/spikeinterface/postprocessing/spike_amplitudes.py index 3c2020a64e..0621419835 100644 --- a/src/spikeinterface/postprocessing/spike_amplitudes.py +++ b/src/spikeinterface/postprocessing/spike_amplitudes.py @@ -75,9 +75,9 @@ def __init__( self._gains = None self._offsets = None spike_retriever = find_parent_of_type(parents, SpikeRetriever) - assert isinstance( - spike_retriever, SpikeRetriever - ), "SpikeAmplitudeNode needs a single SpikeRetriever as a parent" + assert isinstance(spike_retriever, SpikeRetriever), ( + "SpikeAmplitudeNode needs a single SpikeRetriever as a parent" + ) # put peak_shifts in vector way self._peak_shifts = np.array(list(peak_shifts.values()), dtype="int64") self._margin = np.max(np.abs(self._peak_shifts)) diff --git a/src/spikeinterface/postprocessing/template_similarity.py b/src/spikeinterface/postprocessing/template_similarity.py index ef40671b1f..a65bd8fb54 100644 --- a/src/spikeinterface/postprocessing/template_similarity.py +++ b/src/spikeinterface/postprocessing/template_similarity.py @@ -1,5 +1,4 @@ import numpy as np -import warnings from itertools import chain import importlib.util from spikeinterface.core.core_tools import slice_rows, materialize_array @@ -259,7 +258,6 @@ def _compute_similarity_matrix_numpy( if HAVE_NUMBA: - from math import sqrt from numba import jit, typed, prange @@ -304,7 +302,6 @@ def _compute_similarity_matrix_numba( for src_unit in range(num_templates): start = src_unit if same_array else 0 for tgt_unit in range(start, other_num_templates): - if support == "intersection": ch = np.where(sparsity_mask[src_unit] & other_sparsity_mask[tgt_unit])[0].astype(np.uint16) @@ -417,12 +414,12 @@ def compute_similarity_with_templates_array( if method not in all_metrics: raise ValueError(f"compute_template_similarity (method {method}) not exists") - assert ( - templates_array.shape[1] == other_templates_array.shape[1] - ), "The number of samples in the templates should be the same for both arrays" - assert ( - templates_array.shape[2] == other_templates_array.shape[2] - ), "The number of channels in the templates should be the same for both arrays" + assert templates_array.shape[1] == other_templates_array.shape[1], ( + "The number of samples in the templates should be the same for both arrays" + ) + assert templates_array.shape[2] == other_templates_array.shape[2], ( + "The number of channels in the templates should be the same for both arrays" + ) # num_templates = templates_array.shape[0] num_samples = templates_array.shape[1] # num_channels = templates_array.shape[2] diff --git a/src/spikeinterface/postprocessing/tests/test_amplitude_scalings.py b/src/spikeinterface/postprocessing/tests/test_amplitude_scalings.py index cb523038df..d5f0bf947a 100644 --- a/src/spikeinterface/postprocessing/tests/test_amplitude_scalings.py +++ b/src/spikeinterface/postprocessing/tests/test_amplitude_scalings.py @@ -139,7 +139,6 @@ def test_unit_pair_overlap_matrix_matches_naive_reference(): class TestAmplitudeScalingsExtension(AnalyzerExtensionCommonTestSuite): - @pytest.mark.parametrize("params", [dict(handle_collisions=True), dict(handle_collisions=False)]) def test_extension(self, params): self.run_extension_tests(ComputeAmplitudeScalings, params) diff --git a/src/spikeinterface/postprocessing/tests/test_correlograms.py b/src/spikeinterface/postprocessing/tests/test_correlograms.py index 5b3410ed39..e93f97d5c1 100644 --- a/src/spikeinterface/postprocessing/tests/test_correlograms.py +++ b/src/spikeinterface/postprocessing/tests/test_correlograms.py @@ -1,21 +1,7 @@ -import numpy as np -import importlib.util - -numba_spec = importlib.util.find_spec("numba") -if numba_spec is not None: - HAVE_NUMBA = True -else: - HAVE_NUMBA = False - -npyx_spec = importlib.util.find_spec("npyx") -if npyx_spec is not None: - HAVE_NPYX = True -else: - HAVE_NPYX = False - - import pytest from pytest import param +import numpy as np +import importlib.util from spikeinterface import NumpySorting, generate_sorting from spikeinterface.postprocessing import ComputeACG3D, ComputeCorrelograms, ComputeAutoCorrelograms @@ -32,6 +18,19 @@ ) from spikeinterface.postprocessing.tests.common_extension_tests import AnalyzerExtensionCommonTestSuite + +numba_spec = importlib.util.find_spec("numba") +if numba_spec is not None: + HAVE_NUMBA = True +else: + HAVE_NUMBA = False + +npyx_spec = importlib.util.find_spec("npyx") +if npyx_spec is not None: + HAVE_NPYX = True +else: + HAVE_NPYX = False + SKIP_NUMBA = pytest.mark.skipif(not HAVE_NUMBA, reason="Numba not available") @@ -254,27 +253,6 @@ def test_equal_results_auto_correlograms(window_and_bin_ms): assert np.array_equal(result_numpy, result_numba) -@pytest.mark.skipif(not HAVE_NUMBA, reason="Numba not available") -@pytest.mark.parametrize("window_and_bin_ms", [(60.0, 2.0), (3.57, 1.6421)]) -def test_equal_results_auto_correlograms(window_and_bin_ms): - """ - Test that the 2 methods have same results with some varied time bins - that are not tested in other tests. - """ - - window_ms, bin_ms = window_and_bin_ms - sorting = generate_sorting(num_units=5, sampling_frequency=30000.0, durations=[10.325, 3.5], seed=0) - - result_numpy, bins_numpy = _compute_auto_correlograms_on_sorting( - sorting, window_ms=window_ms, bin_ms=bin_ms, method="numpy" - ) - result_numba, bins_numba = _compute_auto_correlograms_on_sorting( - sorting, window_ms=window_ms, bin_ms=bin_ms, method="numba" - ) - - assert np.array_equal(result_numpy, result_numba) - - @pytest.mark.parametrize("method", ["numpy", param("numba", marks=SKIP_NUMBA)]) def test_flat_cross_correlogram(method): """ @@ -647,9 +625,9 @@ def test_acgs_3d_original_implementation(window_ms, bin_ms, num_firing_rate_quan ) assert np.allclose(npyx_3dacg, acg_3d, rtol=1e-2, atol=1e-2), "3D-ACG result does not match original implementation" - assert np.allclose( - npyx_quantiles, firing_rate_quantiles, rtol=1e-5, atol=1e-5 - ), "3D-ACG quantiles do not match original implementation" + assert np.allclose(npyx_quantiles, firing_rate_quantiles, rtol=1e-5, atol=1e-5), ( + "3D-ACG quantiles do not match original implementation" + ) # Check in the case where we have segments @@ -693,6 +671,6 @@ def test_acgs_3d_original_implementation_with_segments(window_ms, bin_ms, num_fi ) # Use a less strict tolerance here as we are only simulating a single segment - assert np.allclose( - npyx_3dacg, acg_3d, rtol=5e-2, atol=5e-2 - ), f"3D-ACG result for {segments} segments does not match original implementation with concatenated times" + assert np.allclose(npyx_3dacg, acg_3d, rtol=5e-2, atol=5e-2), ( + f"3D-ACG result for {segments} segments does not match original implementation with concatenated times" + ) diff --git a/src/spikeinterface/postprocessing/tests/test_extension_merges.py b/src/spikeinterface/postprocessing/tests/test_extension_merges.py index e4f858223e..ca47d7dd26 100644 --- a/src/spikeinterface/postprocessing/tests/test_extension_merges.py +++ b/src/spikeinterface/postprocessing/tests/test_extension_merges.py @@ -27,7 +27,6 @@ def test_correlograms_merge(): for new_id_strategy in ["append", "take_first", "user"]: for merge_unit_groups, new_unit_id in zip(trial_merges, new_unit_ids): - # first, compute the correlograms of the merged units using the merge method if new_id_strategy == "user": merged_sorting_analyzer = sorting_analyzer.merge_units( @@ -87,7 +86,6 @@ def test_acgs_3d_merge(sparse): for new_id_strategy in ["append", "take_first"]: for merge_unit_groups in trial_merges: - merged_sorting_analyzer = sorting_analyzer.merge_units( merge_unit_groups=merge_unit_groups, new_id_strategy=new_id_strategy ) diff --git a/src/spikeinterface/postprocessing/tests/test_isi.py b/src/spikeinterface/postprocessing/tests/test_isi.py index b24a3b0405..f426569a33 100644 --- a/src/spikeinterface/postprocessing/tests/test_isi.py +++ b/src/spikeinterface/postprocessing/tests/test_isi.py @@ -15,7 +15,6 @@ class TestComputeISIHistograms(AnalyzerExtensionCommonTestSuite): - @pytest.mark.parametrize( "params", [ diff --git a/src/spikeinterface/postprocessing/tests/test_multi_extensions.py b/src/spikeinterface/postprocessing/tests/test_multi_extensions.py index 17f51fd1ce..d8180b6e1d 100644 --- a/src/spikeinterface/postprocessing/tests/test_multi_extensions.py +++ b/src/spikeinterface/postprocessing/tests/test_multi_extensions.py @@ -1,6 +1,5 @@ import pytest -import time import numpy as np from spikeinterface import ( @@ -140,7 +139,7 @@ def test_SortingAnalyzer_merge_all_extensions(dataset_to_merge, lazy, sparse, fo set_global_job_kwargs(n_jobs=1) - rng = np.random.default_rng(seed=2308) + _ = np.random.default_rng(seed=2308) recording, sorting, other_ids = dataset_to_merge diff --git a/src/spikeinterface/postprocessing/tests/test_principal_component.py b/src/spikeinterface/postprocessing/tests/test_principal_component.py index 879f4ff055..493f36e797 100644 --- a/src/spikeinterface/postprocessing/tests/test_principal_component.py +++ b/src/spikeinterface/postprocessing/tests/test_principal_component.py @@ -8,7 +8,6 @@ class TestPrincipalComponentsExtension(AnalyzerExtensionCommonTestSuite): - @pytest.mark.parametrize( "params", [ @@ -223,7 +222,6 @@ def test_select_channels_sparse_pca(): selected_pca = analyzer_selected.get_extension("principal_components") for unit_id in sorting_analyzer.unit_ids: - original_units_to_channels = sorting_analyzer.sparsity.unit_id_to_channel_ids[unit_id] selected_units_to_channels = analyzer_selected.sparsity.unit_id_to_channel_ids[unit_id] @@ -232,7 +230,6 @@ def test_select_channels_sparse_pca(): for channel_id in select_channel_ids: if channel_id in original_units_to_channels: - # Now check waveforms and PCs, which are sparse channel_index_in_original = np.where(original_units_to_channels == channel_id)[0][0] original_unit_pca = original_pca_one_unit[:, :, channel_index_in_original] diff --git a/src/spikeinterface/postprocessing/tests/test_spike_amplitudes.py b/src/spikeinterface/postprocessing/tests/test_spike_amplitudes.py index a68483a1b2..4ab77f2b0a 100644 --- a/src/spikeinterface/postprocessing/tests/test_spike_amplitudes.py +++ b/src/spikeinterface/postprocessing/tests/test_spike_amplitudes.py @@ -3,6 +3,5 @@ class TestComputeSpikeAmplitudes(AnalyzerExtensionCommonTestSuite): - def test_extension(self): self.run_extension_tests(ComputeSpikeAmplitudes, params=dict()) diff --git a/src/spikeinterface/postprocessing/tests/test_spike_locations.py b/src/spikeinterface/postprocessing/tests/test_spike_locations.py index 3810a470be..33871d90dc 100644 --- a/src/spikeinterface/postprocessing/tests/test_spike_locations.py +++ b/src/spikeinterface/postprocessing/tests/test_spike_locations.py @@ -4,7 +4,6 @@ class TestSpikeLocationsExtension(AnalyzerExtensionCommonTestSuite): - @pytest.mark.parametrize( "params", [ diff --git a/src/spikeinterface/postprocessing/tests/test_template_similarity.py b/src/spikeinterface/postprocessing/tests/test_template_similarity.py index fd963fa013..ef35858fbb 100644 --- a/src/spikeinterface/postprocessing/tests/test_template_similarity.py +++ b/src/spikeinterface/postprocessing/tests/test_template_similarity.py @@ -14,7 +14,6 @@ ) if importlib.util.find_spec("numba") is not None: - HAVE_NUMBA = True from spikeinterface.postprocessing.template_similarity import _compute_similarity_matrix_numba else: @@ -25,7 +24,6 @@ class TestSimilarityExtension(AnalyzerExtensionCommonTestSuite): - @pytest.mark.parametrize( "params", [ diff --git a/src/spikeinterface/postprocessing/tests/test_unit_locations.py b/src/spikeinterface/postprocessing/tests/test_unit_locations.py index 5f0a90d966..4c7db3bbd3 100644 --- a/src/spikeinterface/postprocessing/tests/test_unit_locations.py +++ b/src/spikeinterface/postprocessing/tests/test_unit_locations.py @@ -7,7 +7,6 @@ class TestUnitLocationsExtension(AnalyzerExtensionCommonTestSuite): - @pytest.mark.parametrize( "params", [ @@ -60,7 +59,6 @@ def test_2d_and_3d_unit_localization(): analyzer_2D.compute(["random_spikes", "templates"]) for method in ["center_of_mass", "grid_convolution", "monopolar_triangulation", "max_channel"]: - analyzer_2D.compute("unit_locations", method=method) analyzer_3D.compute("unit_locations", method=method) unit_locations_2D = analyzer_2D.get_extension("unit_locations").get_data() diff --git a/src/spikeinterface/postprocessing/tests/test_valid_unit_periods.py b/src/spikeinterface/postprocessing/tests/test_valid_unit_periods.py index 3ba057d059..a929f01881 100644 --- a/src/spikeinterface/postprocessing/tests/test_valid_unit_periods.py +++ b/src/spikeinterface/postprocessing/tests/test_valid_unit_periods.py @@ -7,7 +7,6 @@ class TestComputeValidUnitPeriods(AnalyzerExtensionCommonTestSuite): - @pytest.mark.parametrize( "params", [ diff --git a/src/spikeinterface/postprocessing/unit_locations.py b/src/spikeinterface/postprocessing/unit_locations.py index 7cd94d7ee9..da4e39730c 100644 --- a/src/spikeinterface/postprocessing/unit_locations.py +++ b/src/spikeinterface/postprocessing/unit_locations.py @@ -1,7 +1,7 @@ import numpy as np from itertools import chain -from spikeinterface.core.core_tools import slice_rows, materialize_array +from spikeinterface.core.core_tools import slice_rows from spikeinterface.core.sortinganalyzer import register_result_extension, AnalyzerExtension from .localization_tools import _unit_location_methods diff --git a/src/spikeinterface/postprocessing/valid_unit_periods.py b/src/spikeinterface/postprocessing/valid_unit_periods.py index da28b20e00..d24f206e2b 100644 --- a/src/spikeinterface/postprocessing/valid_unit_periods.py +++ b/src/spikeinterface/postprocessing/valid_unit_periods.py @@ -137,9 +137,9 @@ def _set_params( # subperiods assert period_mode in ("absolute", "relative"), f"Invalid subperiod_size_mode: {period_mode}" - assert ( - period_duration_s_absolute > 0 or period_target_num_spikes > 0 - ), "Either period_duration_s_absolute or period_target_num_spikes must be positive." + assert period_duration_s_absolute > 0 or period_target_num_spikes > 0, ( + "Either period_duration_s_absolute or period_target_num_spikes must be positive." + ) assert isinstance(period_target_num_spikes, (int)), "period_target_num_spikes must be an integer." # user_defined_periods formatting @@ -147,7 +147,7 @@ def _set_params( if user_defined_periods is not None: try: user_defined_periods = np.asarray(user_defined_periods) - except Exception as e: + except Exception: raise ValueError( ( "user_defined_periods must be some (n_periods, 3) [unit, good_period_start, good_period_end] " @@ -362,12 +362,10 @@ def _run(self, unit_ids=None, verbose=False, **job_kwargs): def _compute_valid_periods(self, sorting_analyzer, unit_ids=None, **job_kwargs): if self.params["method"] == "user_defined": - # directly use user defined periods return self.user_defined_periods, None, None, None elif self.params["method"] in ["false_positives_and_negatives", "combined"]: - # dict: unit_id -> list of subperiod, each subperiod is an array of dtype unit_period_dtype with 4 fields all_periods, all_periods_w_margins = compute_subperiods( sorting_analyzer, @@ -394,7 +392,7 @@ def _compute_valid_periods(self, sorting_analyzer, unit_ids=None, **job_kwargs): # Each item is one computation of fp and fn for one period and one unit items = [(period,) for period in all_periods_w_margins] - job_name = f"computing false positives and negatives" + job_name = "computing false positives and negatives" # parallel with ProcessPoolExecutor( diff --git a/src/spikeinterface/preprocessing/average_across_direction.py b/src/spikeinterface/preprocessing/average_across_direction.py index f87a79e2b4..2fb1c36dcf 100644 --- a/src/spikeinterface/preprocessing/average_across_direction.py +++ b/src/spikeinterface/preprocessing/average_across_direction.py @@ -5,7 +5,6 @@ class AverageAcrossDirectionRecording(BaseRecording): - def __init__( self, recording: BaseRecording, diff --git a/src/spikeinterface/preprocessing/common_reference.py b/src/spikeinterface/preprocessing/common_reference.py index 6da823d0e4..9ca5143409 100644 --- a/src/spikeinterface/preprocessing/common_reference.py +++ b/src/spikeinterface/preprocessing/common_reference.py @@ -139,13 +139,13 @@ def __init__( if np.isscalar(ref_channel_ids): ref_channel_ids = [ref_channel_ids] else: - assert ( - len(ref_channel_ids) == 1 - ), "'ref_channel_ids' with no 'groups' must be a single channel id or a list of one element" + assert len(ref_channel_ids) == 1, ( + "'ref_channel_ids' with no 'groups' must be a single channel id or a list of one element" + ) ref_channel_ids = np.asarray(ref_channel_ids) - assert np.all( - [ch in recording.channel_ids for ch in ref_channel_ids] - ), "Some 'ref_channel_ids' are wrong!" + assert np.all([ch in recording.channel_ids for ch in ref_channel_ids]), ( + "Some 'ref_channel_ids' are wrong!" + ) elif reference == "local": assert groups is None, "With 'local' CAR, the group option should not be used." closest_inds, dist = get_closest_channels(recording) diff --git a/src/spikeinterface/preprocessing/decimate.py b/src/spikeinterface/preprocessing/decimate.py index 147e685118..16bd21445d 100644 --- a/src/spikeinterface/preprocessing/decimate.py +++ b/src/spikeinterface/preprocessing/decimate.py @@ -70,7 +70,7 @@ def __init__( # Original sampling frequency self._orig_samp_freq = recording.get_sampling_frequency() if not isinstance(decimation_factor, int) or decimation_factor <= 0: - raise ValueError(f"Expecting strictly positive integer for `decimation_factor` arg") + raise ValueError("Expecting strictly positive integer for `decimation_factor` arg") self._decimation_factor = decimation_factor if not isinstance(decimation_offset, int) or decimation_offset < 0: raise ValueError("Expecting a nonnegative integer for `decimation_offset` arg") @@ -79,8 +79,8 @@ def __init__( ) if decimation_offset >= decimation_factor or decimation_offset >= parent_min_n_samp: raise ValueError( - f"Expecting `decimation_offset` < `decimation_factor` and `decimation_offset` < parent_segment.get_num_samples() for all segments. " - f"Consider combining DecimateRecording with FrameSliceRecording for fine control on the recording start/end frames." + "Expecting `decimation_offset` < `decimation_factor` and `decimation_offset` < parent_segment.get_num_samples() for all segments. " + "Consider combining DecimateRecording with FrameSliceRecording for fine control on the recording start/end frames." ) self._decimation_offset = decimation_offset decimated_sampling_frequency = self._orig_samp_freq / self._decimation_factor @@ -179,9 +179,7 @@ def get_traces(self, start_frame, end_frame, channel_indices): parent_start_frame, parent_end_frame, channel_indices, - )[ - :: self._decimation_factor - ].astype(self._dtype) + )[:: self._decimation_factor].astype(self._dtype) return get_polyphase_resampled_traces( self._parent_segment, diff --git a/src/spikeinterface/preprocessing/deepinterpolation/deepinterpolation.py b/src/spikeinterface/preprocessing/deepinterpolation/deepinterpolation.py index e324048c5a..cc9802df90 100644 --- a/src/spikeinterface/preprocessing/deepinterpolation/deepinterpolation.py +++ b/src/spikeinterface/preprocessing/deepinterpolation/deepinterpolation.py @@ -64,9 +64,9 @@ def __init__( if parse(importlib.metadata.version("deepinterpolation")) < parse("0.2.0"): raise ImportError("DeepInterpolation version must be at least 0.2.0") - assert has_tf( - use_gpu, disable_tf_logger, memory_gpu - ), "To use DeepInterpolation, you first need to install `tensorflow`." + assert has_tf(use_gpu, disable_tf_logger, memory_gpu), ( + "To use DeepInterpolation, you first need to install `tensorflow`." + ) self.tf = import_tf(use_gpu, disable_tf_logger, memory_gpu=memory_gpu) @@ -80,12 +80,12 @@ def __init__( # check shape (this will need to be done at inference) network_input_shape = model.get_config()["layers"][0]["config"]["batch_input_shape"] desired_shape = network_input_shape[1:3] - assert ( - desired_shape[0] * desired_shape[1] == recording.get_num_channels() - ), "The desired shape of the network input must match the number of channels in the recording" - assert ( - network_input_shape[-1] == pre_frame + post_frame - ), "The desired shape of the network input must match the pre and post frames" + assert desired_shape[0] * desired_shape[1] == recording.get_num_channels(), ( + "The desired shape of the network input must match the number of channels in the recording" + ) + assert network_input_shape[-1] == pre_frame + post_frame, ( + "The desired shape of the network input must match the pre and post frames" + ) self.model = model # add segment diff --git a/src/spikeinterface/preprocessing/deepinterpolation/generators.py b/src/spikeinterface/preprocessing/deepinterpolation/generators.py index dbf869997d..2520a62f39 100644 --- a/src/spikeinterface/preprocessing/deepinterpolation/generators.py +++ b/src/spikeinterface/preprocessing/deepinterpolation/generators.py @@ -28,9 +28,9 @@ def __init__( recordings = [recordings] self.recordings = recordings if len(recordings) > 1: - assert ( - r.get_num_channels() == recordings[0].get_num_channels() for r in recordings[1:] - ), "All recordings must have the same number of channels" + assert (r.get_num_channels() == recordings[0].get_num_channels() for r in recordings[1:]), ( + "All recordings must have the same number of channels" + ) total_num_samples = sum([r.get_total_samples() for r in recordings]) # In case of multiple recordings and/or multiple segments, we calculate the frame periods to be excluded (borders) @@ -58,9 +58,9 @@ def __init__( ) self.total_samples = int(total_valid_samples) if total_samples == -1 else total_samples assert len(desired_shape) == 2, "desired_shape should be 2D" - assert ( - desired_shape[0] * desired_shape[1] == recording.get_num_channels() - ), f"The product of desired_shape dimensions should be the number of channels: {recording.get_num_channels()}" + assert desired_shape[0] * desired_shape[1] == recording.get_num_channels(), ( + f"The product of desired_shape dimensions should be the number of channels: {recording.get_num_channels()}" + ) self.desired_shape = desired_shape start_frame = start_frame if start_frame is not None else 0 diff --git a/src/spikeinterface/preprocessing/deepinterpolation/tests/test_deepinterpolation.py b/src/spikeinterface/preprocessing/deepinterpolation/tests/test_deepinterpolation.py index 8d2558531f..d61aca4239 100644 --- a/src/spikeinterface/preprocessing/deepinterpolation/tests/test_deepinterpolation.py +++ b/src/spikeinterface/preprocessing/deepinterpolation/tests/test_deepinterpolation.py @@ -11,7 +11,6 @@ from spikeinterface.preprocessing import depth_order, zscore from spikeinterface.preprocessing.deepinterpolation import train_deepinterpolation, deepinterpolate -from spikeinterface.preprocessing.deepinterpolation.train import train_deepinterpolation_process tensorflow_spec = importlib.util.find_spec("tensorflow") deepinter_spec = importlib.util.find_spec("deepinterpolation") @@ -98,12 +97,8 @@ def deepinterpolation_model(recording_and_shape_fixture, create_cache_folder): @pytest.mark.skipif(not HAVE_DEEPINTERPOLATION, reason="requires deepinterpolation") -def test_deepinterpolation_transfer( - recording_and_shape_fixture, tmp_path, create_cache_folder, deepinterpolation_model -): +def test_deepinterpolation_transfer(recording_and_shape_fixture, tmp_path, deepinterpolation_model): recording, desired_shape = recording_and_shape_fixture - cache_folder = create_cache_folder - existing_model_path = deepinterpolation_model model_folder = Path(tmp_path) / "transfer" @@ -128,10 +123,9 @@ def test_deepinterpolation_transfer( @pytest.mark.skipif(not HAVE_DEEPINTERPOLATION, reason="requires deepinterpolation") -def test_deepinterpolation_inference(recording_and_shape_fixture, create_cache_folder, deepinterpolation_model): +def test_deepinterpolation_inference(recording_and_shape_fixture, deepinterpolation_model): recording, _ = recording_and_shape_fixture pre_frame = post_frame = 20 - cache_folder = create_cache_folder existing_model_path = deepinterpolation_model recording_di = deepinterpolate( recording, model_path=existing_model_path, pre_frame=pre_frame, post_frame=post_frame, pre_post_omission=1 diff --git a/src/spikeinterface/preprocessing/detect_artifacts.py b/src/spikeinterface/preprocessing/detect_artifacts.py index 80aa88c73c..cbe5488bb9 100644 --- a/src/spikeinterface/preprocessing/detect_artifacts.py +++ b/src/spikeinterface/preprocessing/detect_artifacts.py @@ -671,9 +671,9 @@ def detect_artifact_periods( Array with dtype ``artifact_dtype`` describing each detected artifact period. """ - assert ( - method in _method_to_function - ), f"Method {method} not recognized. Valid methods are: {_method_to_function.keys()}" + assert method in _method_to_function, ( + f"Method {method} not recognized. Valid methods are: {_method_to_function.keys()}" + ) if method_kwargs is None: method_kwargs = dict() diff --git a/src/spikeinterface/preprocessing/directional_derivative.py b/src/spikeinterface/preprocessing/directional_derivative.py index f302708055..457c6edc69 100644 --- a/src/spikeinterface/preprocessing/directional_derivative.py +++ b/src/spikeinterface/preprocessing/directional_derivative.py @@ -5,7 +5,6 @@ class DirectionalDerivativeRecording(BasePreprocessor): - def __init__( self, recording: BaseRecording, diff --git a/src/spikeinterface/preprocessing/highpass_spatial_filter.py b/src/spikeinterface/preprocessing/highpass_spatial_filter.py index 979bb00908..838672ab4b 100644 --- a/src/spikeinterface/preprocessing/highpass_spatial_filter.py +++ b/src/spikeinterface/preprocessing/highpass_spatial_filter.py @@ -112,13 +112,13 @@ def __init__( # Fix channel padding and tapering n_channels = recording.get_num_channels() n_channel_pad = 0 if n_channel_pad is None else int(n_channel_pad) - assert ( - n_channel_pad <= recording.get_num_channels() - ), "'n_channel_pad' must be less than the number of channels in recording." + assert n_channel_pad <= recording.get_num_channels(), ( + "'n_channel_pad' must be less than the number of channels in recording." + ) n_channel_taper = n_channel_pad if n_channel_taper is None else int(n_channel_taper) - assert ( - n_channel_taper <= recording.get_num_channels() - ), "'n_channel_taper' must be less than the number of channels in recording." + assert n_channel_taper <= recording.get_num_channels(), ( + "'n_channel_taper' must be less than the number of channels in recording." + ) # Fix Automatic Gain Control options sampling_interval = 1 / recording.sampling_frequency diff --git a/src/spikeinterface/preprocessing/interpolate_bad_channels.py b/src/spikeinterface/preprocessing/interpolate_bad_channels.py index f2ae77f3d7..a5eb206f70 100644 --- a/src/spikeinterface/preprocessing/interpolate_bad_channels.py +++ b/src/spikeinterface/preprocessing/interpolate_bad_channels.py @@ -8,7 +8,6 @@ detect_bad_channels, _get_all_detect_bad_channel_kwargs, ) -from inspect import signature class InterpolateBadChannelsRecording(BasePreprocessor): diff --git a/src/spikeinterface/preprocessing/motion.py b/src/spikeinterface/preprocessing/motion.py index 388605c166..2629b118c1 100644 --- a/src/spikeinterface/preprocessing/motion.py +++ b/src/spikeinterface/preprocessing/motion.py @@ -12,7 +12,6 @@ from spikeinterface.core import get_noise_levels, fix_job_kwargs from spikeinterface.core.job_tools import _shared_job_kwargs_doc from spikeinterface.core.core_tools import SIJsonEncoder -from spikeinterface.core.job_tools import _shared_job_kwargs_doc from spikeinterface.core import BaseRecording motion_options_preset = { @@ -336,7 +335,7 @@ def compute_motion( from spikeinterface.sortingcomponents.peak_selection import select_peaks from spikeinterface.sortingcomponents.peak_localization import localize_peaks, peak_localization_methods from spikeinterface.core.node_pipeline import ExtractDenseWaveforms, run_node_pipeline - from spikeinterface.sortingcomponents.motion.motion_estimation import estimate_motion, estimate_motion_methods + from spikeinterface.sortingcomponents.motion.motion_estimation import estimate_motion # get preset params and update if necessary detect_kwargs, select_kwargs, localize_peaks_kwargs, estimate_motion_kwargs = _update_motion_kwargs( @@ -643,7 +642,6 @@ def load_motion_info(folder): if (folder / "motion").is_dir(): motion = Motion.load(folder / "motion") else: - is_legacy_format = True required_files = ["spatial_bins.npy", "temporal_bins.npy", "motion.npy"] for required_file in required_files: @@ -651,7 +649,6 @@ def load_motion_info(folder): is_legacy_format = False if is_legacy_format: - warnings.warn("Trying to load Motion from the legacy format") spatial_bins_um = np.load(folder / "spatial_bins.npy") @@ -661,7 +658,6 @@ def load_motion_info(folder): motion = Motion(displacement=displacement, temporal_bins_s=temporal_bins_s, spatial_bins_um=spatial_bins_um) else: - warnings.warn("No `motion` object in folder. `motion_info` is loaded with `motion` equal to `None`.") motion = None diff --git a/src/spikeinterface/preprocessing/phase_shift.py b/src/spikeinterface/preprocessing/phase_shift.py index 273e828da3..949f200f30 100644 --- a/src/spikeinterface/preprocessing/phase_shift.py +++ b/src/spikeinterface/preprocessing/phase_shift.py @@ -69,9 +69,9 @@ def __init__( assert "inter_sample_shift" in recording.get_property_keys(), "'inter_sample_shift' is not a property!" sample_shifts = recording.get_property("inter_sample_shift") else: - assert ( - len(inter_sample_shift) == recording.get_num_channels() - ), "the 'inter_sample_shift' must be same size at the num_channels " + assert len(inter_sample_shift) == recording.get_num_channels(), ( + "the 'inter_sample_shift' must be same size at the num_channels " + ) sample_shifts = np.asarray(inter_sample_shift) dtype = np.dtype(recording.get_dtype() if dtype is None else dtype) diff --git a/src/spikeinterface/preprocessing/pipeline.py b/src/spikeinterface/preprocessing/pipeline.py index b75cae49f8..4ee81f3de0 100644 --- a/src/spikeinterface/preprocessing/pipeline.py +++ b/src/spikeinterface/preprocessing/pipeline.py @@ -5,7 +5,7 @@ from spikeinterface.core.core_tools import is_dict_extractor, is_path_remote from spikeinterface.core.zarrextractors import super_zarr_open from spikeinterface.core.zarr_tools import read_encoded_array -from spikeinterface.preprocessing.preprocessing_classes import preprocessor_dict, _all_preprocesser_dict +from spikeinterface.preprocessing.preprocessing_classes import preprocessor_dict pp_names_to_functions = {preprocessor.__name__: preprocessor for preprocessor in preprocessor_dict.values()} @@ -30,9 +30,9 @@ def __init__(self, preprocessor_list_or_dict): preprocessor_list.append(step) elif isinstance(preprocessor_list_or_dict, list): preprocessor_list = preprocessor_list_or_dict - assert all( - isinstance(step, dict) and "name" in step for step in preprocessor_list - ), "Each step in the preprocessor list must be a dict with 'name' key." + assert all(isinstance(step, dict) and "name" in step for step in preprocessor_list), ( + "Each step in the preprocessor list must be a dict with 'name' key." + ) for step in preprocessor_list: if "params" not in step: @@ -321,7 +321,6 @@ def _make_pipeline_list_from_recording_dict(recording_dict): preprocessing_list = [] for preprocessor in pipeline_dict_from_file: - preprocessor_class_name = preprocessor.split(".")[-1] preprocessor_function = preprocessor_dict.get(preprocessor_class_name) @@ -391,7 +390,6 @@ def _get_all_kwargs_and_values(my_pipeline): all_kwargs_list = [] for preprocessor in my_pipeline.preprocessor_list: - preprocessor_name = preprocessor["name"].split(".")[-1] pp_function = my_pipeline.function_names_to_functions[preprocessor["name"].split(".")[-1]] signature = inspect.signature(pp_function) @@ -407,7 +405,7 @@ def _get_all_kwargs_and_values(my_pipeline): default_value = None else: default_value = default_value[-1] - except: + except Exception: default_value = None preprocessor_index = my_pipeline.preprocessor_list.index(preprocessor) diff --git a/src/spikeinterface/preprocessing/rectify.py b/src/spikeinterface/preprocessing/rectify.py index 7bd91a16d9..1328e21dcf 100644 --- a/src/spikeinterface/preprocessing/rectify.py +++ b/src/spikeinterface/preprocessing/rectify.py @@ -6,7 +6,6 @@ class RectifyRecording(BasePreprocessor): - def __init__(self, recording): BasePreprocessor.__init__(self, recording) for parent_segment in recording.segments: diff --git a/src/spikeinterface/preprocessing/remove_artifacts.py b/src/spikeinterface/preprocessing/remove_artifacts.py index b20f1351b0..55584f3a13 100644 --- a/src/spikeinterface/preprocessing/remove_artifacts.py +++ b/src/spikeinterface/preprocessing/remove_artifacts.py @@ -125,9 +125,9 @@ def __init__( # some checks assert isinstance(list_triggers, list), "'list_triggers' must be a list (one per segment)" assert len(list_triggers) == num_seg, "'list_triggers' must have the same length as the number of segments" - assert all( - isinstance(list_triggers[i], (list, np.ndarray)) for i in range(num_seg) - ), "Each element of 'list_triggers' must be array-like" + assert all(isinstance(list_triggers[i], (list, np.ndarray)) for i in range(num_seg)), ( + "Each element of 'list_triggers' must be array-like" + ) if list_labels is not None: assert isinstance(list_labels, list), "'list_labels' must be a list (one per segment)" @@ -163,9 +163,9 @@ def __init__( for l in np.unique(labels): assert l in artifacts.keys(), f"Artefacts are provided but label {l} has no value!" else: - assert ( - ms_before is not None and ms_after is not None - ), f"ms_before/after should not be None for mode {mode}" + assert ms_before is not None and ms_after is not None, ( + f"ms_before/after should not be None for mode {mode}" + ) sorting = NumpySorting.from_samples_and_labels( list_triggers, list_labels, recording.get_sampling_frequency() ) diff --git a/src/spikeinterface/preprocessing/resample.py b/src/spikeinterface/preprocessing/resample.py index 10783062ed..6dd8c9c3b4 100644 --- a/src/spikeinterface/preprocessing/resample.py +++ b/src/spikeinterface/preprocessing/resample.py @@ -1,5 +1,4 @@ import numpy as np -import warnings from spikeinterface.core.core_tools import define_function_handling_dict_from_class diff --git a/src/spikeinterface/preprocessing/tests/test_astype.py b/src/spikeinterface/preprocessing/tests/test_astype.py index d1d1b11f43..88c80e414a 100644 --- a/src/spikeinterface/preprocessing/tests/test_astype.py +++ b/src/spikeinterface/preprocessing/tests/test_astype.py @@ -1,9 +1,4 @@ -import pytest -from pathlib import Path -import shutil - -from spikeinterface import set_global_tmp_folder, NumpyRecording -from spikeinterface.core import generate_recording +from spikeinterface import NumpyRecording from spikeinterface.preprocessing import astype diff --git a/src/spikeinterface/preprocessing/tests/test_common_reference.py b/src/spikeinterface/preprocessing/tests/test_common_reference.py index 139213056f..d3559d862b 100644 --- a/src/spikeinterface/preprocessing/tests/test_common_reference.py +++ b/src/spikeinterface/preprocessing/tests/test_common_reference.py @@ -1,4 +1,3 @@ -import operator import pytest from spikeinterface.core import generate_recording, NumpyRecording @@ -6,7 +5,6 @@ from spikeinterface.preprocessing import common_reference import numpy as np -from tqdm import trange def _generate_test_recording(): @@ -244,7 +242,7 @@ def test_min_local_radius(): # remove closest channel to first channel recording = recording.remove_channels(recording.channel_ids[1:5]) with pytest.warns(UserWarning): - recording_local_car = common_reference( + _ = common_reference( recording, reference="local", local_radius=(60, 150), operator="average", min_local_neighbors=5 ) diff --git a/src/spikeinterface/preprocessing/tests/test_detect_artifacts.py b/src/spikeinterface/preprocessing/tests/test_detect_artifacts.py index 81f934300a..0f524af3b0 100644 --- a/src/spikeinterface/preprocessing/tests/test_detect_artifacts.py +++ b/src/spikeinterface/preprocessing/tests/test_detect_artifacts.py @@ -1,6 +1,6 @@ import numpy as np -from spikeinterface.core import generate_recording, NumpyRecording +from spikeinterface.core import NumpyRecording from spikeinterface.preprocessing import ( detect_artifact_periods, detect_saturation_periods, @@ -41,7 +41,6 @@ def test_detect_artifact_by_envelope(debug_plots): ) if debug_plots: - import matplotlib import matplotlib.pyplot as plt plt.plot(envelope.get_traces(), color="r", lw=3) @@ -151,7 +150,6 @@ def test_detect_saturation_periods(debug_plots): offset = 0 if debug_plots: - import matplotlib import matplotlib.pyplot as plt plt.plot(data_seg_1) @@ -206,12 +204,12 @@ def test_detect_saturation_periods(debug_plots): for seg_periods, seg_offset in zip([seg_1_periods, seg_2_periods], offsets): slow_period_idx = np.argmin(np.abs(seg_periods["start_sample_index"] - start_slow_artifact)) slow_period = seg_periods[slow_period_idx] - assert ( - slow_period["start_sample_index"] >= start_rising_sample + tolerance_samples - ), "Slow artifact period starts in the rising phase" - assert ( - slow_period["end_sample_index"] <= stop_falling_sample + seg_offset - tolerance_samples - ), "Slow artifact period ends in the falling phase" + assert slow_period["start_sample_index"] >= start_rising_sample + tolerance_samples, ( + "Slow artifact period starts in the rising phase" + ) + assert slow_period["end_sample_index"] <= stop_falling_sample + seg_offset - tolerance_samples, ( + "Slow artifact period ends in the falling phase" + ) # Just do a quick test that a threshold slightly over the sat value is not detected. # In this case we only see the derivative threshold detection. We do not play around with this diff --git a/src/spikeinterface/preprocessing/tests/test_detect_bad_channels.py b/src/spikeinterface/preprocessing/tests/test_detect_bad_channels.py index b9c3b83a6f..4a0df49156 100644 --- a/src/spikeinterface/preprocessing/tests/test_detect_bad_channels.py +++ b/src/spikeinterface/preprocessing/tests/test_detect_bad_channels.py @@ -3,12 +3,9 @@ import importlib.util -from spikeinterface import NumpyRecording, get_random_data_chunks from probeinterface import generate_linear_probe -from spikeinterface.generation import generate_recording - -from spikeinterface.core import generate_recording +from spikeinterface.core import generate_recording, get_random_data_chunks, NumpyRecording from spikeinterface.core.base import BaseExtractor from spikeinterface.core.testing import check_recordings_equal from spikeinterface.preprocessing import detect_bad_channels, highpass_filter, detect_and_remove_bad_channels @@ -113,13 +110,13 @@ def test_detect_bad_channels_std_mad(): # Check that the number of segments is maintained after preprocessor assert np.array_equal(rec2.get_num_segments(), rec.get_num_segments()), "wrong numbber of segments." # Check that the size of the segments os maintained after preprocessor - assert np.array_equal( - *([r.get_num_frames(x) for x in range(rec.get_num_segments())] for r in [rec, rec2]) - ), "wrong length of resulting segments." + assert np.array_equal(*([r.get_num_frames(x) for x in range(rec.get_num_segments())] for r in [rec, rec2])), ( + "wrong length of resulting segments." + ) # Check that locations are mantained - assert np.array_equal( - rec.get_channel_locations()[[0, 2, 3]], rec2.get_channel_locations() - ), "wrong channels locations." + assert np.array_equal(rec.get_channel_locations()[[0, 2, 3]], rec2.get_channel_locations()), ( + "wrong channels locations." + ) @pytest.mark.parametrize("pool_engine", ["thread", "process"]) diff --git a/src/spikeinterface/preprocessing/tests/test_filter.py b/src/spikeinterface/preprocessing/tests/test_filter.py index 3b47d0eb1a..79d3a7b3ce 100644 --- a/src/spikeinterface/preprocessing/tests/test_filter.py +++ b/src/spikeinterface/preprocessing/tests/test_filter.py @@ -2,7 +2,6 @@ import numpy as np from spikeinterface.core import generate_recording -from spikeinterface import NumpyRecording, set_global_tmp_folder from spikeinterface.preprocessing import filter, bandpass_filter, notch_filter, causal_filter @@ -110,8 +109,8 @@ def test_causal_kwarg_error_raised(self, recording_and_data): """ recording, raw_data = recording_and_data - with pytest.raises(BaseException) as e: - filt_data = causal_filter(recording, direction="forward-backward") + with pytest.raises(BaseException): + _ = causal_filter(recording, direction="forward-backward") def _run_iirfilter(self, options, recording): """ @@ -141,36 +140,33 @@ def _get_filter_options(self): def test_filter(create_cache_folder): + from scipy.signal import iirfilter + rec = generate_recording() rec = rec.save(folder=create_cache_folder / "test_filter_recording") rec2 = bandpass_filter(rec, freq_min=300.0, freq_max=6000.0) # compute by chunk - rec2_cached0 = rec2.save( - folder=create_cache_folder / "rec2_cached0", chunk_size=100000, verbose=False, progress_bar=True - ) + _ = rec2.save(folder=create_cache_folder / "rec2_cached0", chunk_size=100000, verbose=False, progress_bar=True) - # compute by chunkf with joblib + # compute by chunk in parallel rec2_cached1 = rec2.save(folder=create_cache_folder / "rec2_cached1", total_memory="10k", n_jobs=4, verbose=True) # compute once - rec2_cached2 = rec2.save(folder=create_cache_folder / "rec2_cached2", verbose=False) + _ = rec2.save(folder=create_cache_folder / "rec2_cached2", verbose=False) trace0 = rec2.get_traces(segment_index=0) trace1 = rec2_cached1.get_traces(segment_index=0) # other filtering types - rec3 = filter(rec, band=500.0, btype="highpass", filter_mode="ba", filter_order=2, margin_ms=5.0) - rec4 = notch_filter(rec, freq=3000, q=30, margin_ms=5.0) + _ = filter(rec, band=500.0, btype="highpass", filter_mode="ba", filter_order=2, margin_ms=5.0) + _ = notch_filter(rec, freq=3000, q=30, margin_ms=5.0) rec5 = causal_filter(rec, direction="forward") rec6 = causal_filter(rec, direction="backward") - # filter from coefficients - from scipy.signal import iirfilter - coeff = iirfilter(8, [0.02, 0.4], rs=30, btype="band", analog=False, ftype="cheby2", output="sos") - rec5 = filter(rec, coeff=coeff, filter_mode="sos", margin_ms=5.0) + rec5 = filter(rec, coeff=coeff, filter_mode="sos", margin_ms=50.0) # compute by chunk rec5_cached0 = rec5.save( @@ -179,7 +175,7 @@ def test_filter(create_cache_folder): trace50 = rec5.get_traces(segment_index=0) trace51 = rec5_cached0.get_traces(segment_index=0) - + np.testing.assert_array_almost_equal(trace50, trace51, decimal=4) assert np.allclose(rec.get_times(0), rec2.get_times(0)) # reflect padding test @@ -215,7 +211,7 @@ def test_filter_opencl(): rec_filtered = rec_filtered.save(chunk_size=1000, progress_bar=True, n_jobs=30) rec2 = filter(rec, engine="opencl") - rec2_cached0 = rec2.save(chunk_size=1000, verbose=False, progress_bar=True, n_jobs=1) + _ = rec2.save(chunk_size=1000, verbose=False, progress_bar=True, n_jobs=1) # rec2_cached0 = rec2.save(chunk_size=1000,verbose=False, progress_bar=True, n_jobs=4) # import matplotlib.pyplot as plt diff --git a/src/spikeinterface/preprocessing/tests/test_filter_gaussian.py b/src/spikeinterface/preprocessing/tests/test_filter_gaussian.py index f3da50671d..4cb822cf07 100644 --- a/src/spikeinterface/preprocessing/tests/test_filter_gaussian.py +++ b/src/spikeinterface/preprocessing/tests/test_filter_gaussian.py @@ -56,7 +56,6 @@ def test_bandpower(freq_min, freq_max, debug=False): fs = 1000 T = 300 - t = np.arange(0, T, 1 / fs) rng = np.random.default_rng() x = rng.standard_normal(T * fs) diff --git a/src/spikeinterface/preprocessing/tests/test_highpass_spatial_filter.py b/src/spikeinterface/preprocessing/tests/test_highpass_spatial_filter.py index 89e8e36cf8..b4579451a1 100644 --- a/src/spikeinterface/preprocessing/tests/test_highpass_spatial_filter.py +++ b/src/spikeinterface/preprocessing/tests/test_highpass_spatial_filter.py @@ -88,8 +88,7 @@ def test_highpass_spatial_filter_synthetic_data(num_channels, ntr_pad, ntr_tap, options = dict(lagc=lagc, ntr_pad=ntr_pad, ntr_tap=ntr_tap, butter_kwargs=butter_kwargs) durations = [2, 2] - rng = np.random.default_rng(seed=100) - si_recording = generate_recording(num_channels=num_channels, durations=durations) + si_recording = generate_recording(num_channels=num_channels, durations=durations, seed=100) _, si_highpass_spatial_filter = run_si_highpass_filter(si_recording, get_traces=False, **options) frames = [(0, 500), (30000, 33000), (57000, 60000)] diff --git a/src/spikeinterface/preprocessing/tests/test_motion.py b/src/spikeinterface/preprocessing/tests/test_motion.py index 07dd810890..01dce124ac 100644 --- a/src/spikeinterface/preprocessing/tests/test_motion.py +++ b/src/spikeinterface/preprocessing/tests/test_motion.py @@ -10,6 +10,7 @@ compute_motion, ) from spikeinterface.preprocessing.motion import _get_default_motion_params +from spikeinterface.sortingcomponents.motion import InterpolateMotionRecording def test_estimate_and_correct_motion(create_cache_folder): @@ -21,6 +22,7 @@ def test_estimate_and_correct_motion(create_cache_folder): shutil.rmtree(folder) rec_corrected = correct_motion(rec, folder=folder, estimate_motion_kwargs={"win_step_um": 50, "win_scale_um": 100}) + assert isinstance(rec_corrected, InterpolateMotionRecording) # test reloading motion info motion_info = load_motion_info(folder) @@ -43,7 +45,7 @@ def test_get_motion_parameters_preset(): from pprint import pprint p = _get_default_motion_params() - # pprint(p) + assert isinstance(p, dict) params = get_motion_parameters_preset("nonrigid_accurate") params = get_motion_parameters_preset("dredge") diff --git a/src/spikeinterface/preprocessing/tests/test_normalize_scale.py b/src/spikeinterface/preprocessing/tests/test_normalize_scale.py index a304a18f18..58d6432ae5 100644 --- a/src/spikeinterface/preprocessing/tests/test_normalize_scale.py +++ b/src/spikeinterface/preprocessing/tests/test_normalize_scale.py @@ -93,8 +93,8 @@ def test_zscore_int(): zscore_recording = zscore(rec_int, dtype="int16", int_scale=256, mode="mean+std", seed=seed) traces = zscore_recording.get_traces(segment_index=0) trace_mean = np.mean(traces, axis=0) - trace_std = np.std(traces, axis=0) assert np.all(np.abs(trace_mean) < 1) + # trace_std = np.std(traces, axis=0) # assert np.all(np.abs(trace_std - 256) < 1) diff --git a/src/spikeinterface/preprocessing/tests/test_phase_shift.py b/src/spikeinterface/preprocessing/tests/test_phase_shift.py index bd8a5b209c..12d4efdecf 100644 --- a/src/spikeinterface/preprocessing/tests/test_phase_shift.py +++ b/src/spikeinterface/preprocessing/tests/test_phase_shift.py @@ -20,7 +20,6 @@ def create_shifted_channel(): ratio = 10 sr = sr_h / ratio - times = times_h[0::ratio] delay_sample = 4 sig0 = sig_h[0::ratio] sig1 = sig_h[delay_sample::ratio] diff --git a/src/spikeinterface/preprocessing/tests/test_pipeline.py b/src/spikeinterface/preprocessing/tests/test_pipeline.py index 1ea89ec749..9cd54ad9fc 100644 --- a/src/spikeinterface/preprocessing/tests/test_pipeline.py +++ b/src/spikeinterface/preprocessing/tests/test_pipeline.py @@ -6,8 +6,6 @@ from spikeinterface.preprocessing import ( apply_preprocessing_pipeline, preprocessor_dict, - bandpass_filter, - common_reference, whiten, detect_and_remove_bad_channels, bandpass_filter, @@ -45,7 +43,6 @@ def test_pipeline_equiv_to_step(): for rec in [single_group_rec, rec_groups.split_by("group")]: for _, pp_wrapper in preprocessor_dict.items(): - pp_name = pp_wrapper.__name__ pp_class = pp_names_to_functions[pp_name] diff --git a/src/spikeinterface/preprocessing/tests/test_preprocessing_tools.py b/src/spikeinterface/preprocessing/tests/test_preprocessing_tools.py index db3df0b7ab..55d4b61037 100644 --- a/src/spikeinterface/preprocessing/tests/test_preprocessing_tools.py +++ b/src/spikeinterface/preprocessing/tests/test_preprocessing_tools.py @@ -1,5 +1,3 @@ -import pytest - import numpy as np from spikeinterface.preprocessing import get_spatial_interpolation_kernel @@ -13,7 +11,6 @@ def test_get_spatial_interpolation_kernel(): target_location[:, 1] = np.linspace(0, 130, 4) for method in ("kriging", "idw", "nearest"): - kernel = get_spatial_interpolation_kernel( source_location, target_location, method=method, force_extrapolate=False ) diff --git a/src/spikeinterface/preprocessing/tests/test_remove_artifacts.py b/src/spikeinterface/preprocessing/tests/test_remove_artifacts.py index 85ba61cdd4..716f173fbb 100644 --- a/src/spikeinterface/preprocessing/tests/test_remove_artifacts.py +++ b/src/spikeinterface/preprocessing/tests/test_remove_artifacts.py @@ -1,5 +1,3 @@ -import pytest - import numpy as np from spikeinterface.core import generate_recording diff --git a/src/spikeinterface/preprocessing/tests/test_resample.py b/src/spikeinterface/preprocessing/tests/test_resample.py index de5f19def4..bfcd27f71e 100644 --- a/src/spikeinterface/preprocessing/tests/test_resample.py +++ b/src/spikeinterface/preprocessing/tests/test_resample.py @@ -143,7 +143,7 @@ def test_resample_freq_domain(): fig, ax = plt.subplots(nrows=1, ncols=1, figsize=[10, 7]) xf, nyf = get_fft(parent_rec.get_traces().ravel(), parent_rec.get_sampling_frequency()) - _ = ax.plot(xf, nyf, color="k", alpha=0.8, label=f"original") + _ = ax.plot(xf, nyf, color="k", alpha=0.8, label="original") for i, rec in enumerate(resamp_recs): rs_rate = int(rec.get_sampling_frequency()) diff --git a/src/spikeinterface/preprocessing/tests/test_silence_periods.py b/src/spikeinterface/preprocessing/tests/test_silence_periods.py index d3531f1a0f..fcc25a8b28 100644 --- a/src/spikeinterface/preprocessing/tests/test_silence_periods.py +++ b/src/spikeinterface/preprocessing/tests/test_silence_periods.py @@ -1,5 +1,3 @@ -import pytest - from spikeinterface.core import generate_recording from spikeinterface.core import get_noise_levels from spikeinterface.core.base import base_period_dtype @@ -11,10 +9,7 @@ from pathlib import Path -def test_silence(create_cache_folder): - - cache_folder = create_cache_folder - +def test_silence(): rec = generate_recording() periods = np.array([(0, 0, 1000), (0, 5000, 6000)], dtype=base_period_dtype) @@ -48,10 +43,7 @@ def test_silence(create_cache_folder): assert not np.all(traces_mix[:-200] == 0) -def test_silence_with_apodization(create_cache_folder): - - cache_folder = create_cache_folder - +def test_silence_with_apodization(): rec = generate_recording() periods = np.array([(0, 0, 1000), (0, 5000, 6000)], dtype=base_period_dtype) diff --git a/src/spikeinterface/preprocessing/tests/test_zero_padding.py b/src/spikeinterface/preprocessing/tests/test_zero_padding.py index b6fcb00f03..724dc255f9 100644 --- a/src/spikeinterface/preprocessing/tests/test_zero_padding.py +++ b/src/spikeinterface/preprocessing/tests/test_zero_padding.py @@ -251,7 +251,6 @@ def test_trace_padded_recording_retrieve_traces_with_partial_padding(recording, @pytest.mark.parametrize("padding_start, padding_end", [(5, 5), (0, 5), (5, 0), (0, 0)]) def test_trace_padded_recording_retrieve_only_start_padding(recording, padding_start, padding_end): - num_samples = recording.get_num_samples() num_channels = recording.get_num_channels() padded_recording = TracePaddedRecording( diff --git a/src/spikeinterface/preprocessing/tests/testing_tools.py b/src/spikeinterface/preprocessing/tests/testing_tools.py index 2257039d43..244a421fe3 100644 --- a/src/spikeinterface/preprocessing/tests/testing_tools.py +++ b/src/spikeinterface/preprocessing/tests/testing_tools.py @@ -1,8 +1,2 @@ -import numpy as np - -from spikeinterface import NumpyRecording - -from probeinterface import generate_linear_probe - if __name__ == "__main__": pass diff --git a/src/spikeinterface/preprocessing/whiten.py b/src/spikeinterface/preprocessing/whiten.py index d3fd699442..bbd30066a6 100644 --- a/src/spikeinterface/preprocessing/whiten.py +++ b/src/spikeinterface/preprocessing/whiten.py @@ -76,9 +76,9 @@ def __init__( dtype_ = fix_dtype(recording, dtype) if dtype_.kind == "i": - assert ( - int_scale is not None - ), "For recording with dtype=int you must set the output dtype to float OR set a int_scale" + assert int_scale is not None, ( + "For recording with dtype=int you must set the output dtype to float OR set a int_scale" + ) if not apply_mean and regularize: raise ValueError("`apply_mean` must be `True` if regularising. `assume_centered` is fixed to `True`.") diff --git a/src/spikeinterface/preprocessing/zero_channel_pad.py b/src/spikeinterface/preprocessing/zero_channel_pad.py index 639e5ccced..fdcce72866 100644 --- a/src/spikeinterface/preprocessing/zero_channel_pad.py +++ b/src/spikeinterface/preprocessing/zero_channel_pad.py @@ -129,7 +129,6 @@ def get_num_samples(self): class ZeroChannelPaddedRecording(BaseRecording): - def __init__(self, recording: BaseRecording, num_channels: int, channel_mapping: list | None = None): """Pads a recording with channels that contain only zero. @@ -147,11 +146,11 @@ def __init__(self, recording: BaseRecording, num_channels: int, channel_mapping: BaseRecording.__init__(self, recording.get_sampling_frequency(), np.arange(num_channels), recording.get_dtype()) if channel_mapping is not None: - assert ( - len(channel_mapping) == recording.get_num_channels() - ), "The new mapping must be specified for all channels." + assert len(channel_mapping) == recording.get_num_channels(), ( + "The new mapping must be specified for all channels." + ) assert max(channel_mapping) < num_channels, ( - "The new mapping cannot exceed total number of channels " "in the zero-chanenl-padded recording." + "The new mapping cannot exceed total number of channels in the zero-chanenl-padded recording." ) else: if recording.has_probe(): diff --git a/src/spikeinterface/sorters/basesorter.py b/src/spikeinterface/sorters/basesorter.py index f25fe33e92..233de7ee46 100644 --- a/src/spikeinterface/sorters/basesorter.py +++ b/src/spikeinterface/sorters/basesorter.py @@ -195,7 +195,7 @@ def set_params_to_folder( invalid_parameters = [k for k in new_params.keys() if k not in valid_parameters] if invalid_parameters: - error_msg = f"Invalid parameters: {invalid_parameters} \n" f"Valid parameters are: {valid_parameters}" + error_msg = f"Invalid parameters: {invalid_parameters} \nValid parameters are: {valid_parameters}" raise ValueError(error_msg) params.update(new_params) @@ -278,7 +278,7 @@ def run_from_folder(cls, output_folder, raise_error, verbose): t1 = time.perf_counter() run_time = float(t1 - t0) has_error = False - except Exception as err: + except Exception: has_error = True run_time = None log["error"] = True diff --git a/src/spikeinterface/sorters/container_tools.py b/src/spikeinterface/sorters/container_tools.py index a75ca57be7..df59f5b71b 100644 --- a/src/spikeinterface/sorters/container_tools.py +++ b/src/spikeinterface/sorters/container_tools.py @@ -102,7 +102,6 @@ def __init__(self, mode, container_image, volumes, py_user_base, extra_kwargs): elif Path(sif_file).exists(): singularity_image = sif_file else: - docker_image = Client.load("docker://" + container_image) if docker_image and len(docker_image.tags) > 0: tag = docker_image.tags[0] @@ -116,7 +115,7 @@ def __init__(self, mode, container_image, volumes, py_user_base, extra_kwargs): raise FileNotFoundError(f"Unable to locate container image {container_image}") # bin options - singularity_bind = ",".join([f'{volume_src}:{volume["bind"]}' for volume_src, volume in volumes.items()]) + singularity_bind = ",".join([f"{volume_src}:{volume['bind']}" for volume_src, volume in volumes.items()]) options = ["--bind", singularity_bind] # gpu options @@ -278,6 +277,6 @@ def install_package_in_container( raise ValueError(f"install_package_incontainer, wrong installation_mode={installation_mode}") if isinstance(res_output, str) and "ERROR" in res_output.upper(): - warnings.warn(f"pip install of {package_name} in container may have failed. " f"pip output:\n{res_output}") + warnings.warn(f"pip install of {package_name} in container may have failed. pip output:\n{res_output}") return res_output diff --git a/src/spikeinterface/sorters/external/combinato.py b/src/spikeinterface/sorters/external/combinato.py index 94fe33b70a..0d9457cfd8 100644 --- a/src/spikeinterface/sorters/external/combinato.py +++ b/src/spikeinterface/sorters/external/combinato.py @@ -52,7 +52,7 @@ class CombinatoSorter(BaseSorter): } _params_description = { - "detect_sign": "Use -1 (negative) or 1 (positive) depending " "on the sign of the spikes in the recording", + "detect_sign": "Use -1 (negative) or 1 (positive) depending on the sign of the spikes in the recording", "MaxClustersPerTemp": "How many clusters can be selected at one temperature", "MinSpikesPerClusterMultiSelect": "How many spikes does a cluster need to be selected", "RecursiveDepth": "How many clustering recursions should be run (1 do not recurse)", @@ -125,7 +125,6 @@ def _setup_recording(cls, recording, sorter_output_folder, params, verbose): # Generate h5 files in the dataset directory chan_ids = recording.get_channel_ids() assert len(chan_ids) == 1, "combinato is a single-channel recording" - chid = chan_ids[0] vcFile_h5 = str(sorter_output_folder / ("recording.h5")) with h5py.File(vcFile_h5, mode="w") as f: f.create_dataset("sr", data=[recording.get_sampling_frequency()], dtype="float32") diff --git a/src/spikeinterface/sorters/external/dartsort.py b/src/spikeinterface/sorters/external/dartsort.py index daad3ec555..8e66f7929b 100644 --- a/src/spikeinterface/sorters/external/dartsort.py +++ b/src/spikeinterface/sorters/external/dartsort.py @@ -1,4 +1,5 @@ from pathlib import Path +import importlib.util import numpy as np @@ -44,14 +45,7 @@ def _dynamic_params(cls): @classmethod def is_installed(cls): - try: - import dartsort - - HAVE_DARTSORT = True - except ImportError: - HAVE_DARTSORT = False - - return HAVE_DARTSORT + return importlib.util.find_spec("dartsort") is not None @staticmethod def get_sorter_version(): diff --git a/src/spikeinterface/sorters/external/hdsort.py b/src/spikeinterface/sorters/external/hdsort.py index 07d59332d2..ae4954785c 100644 --- a/src/spikeinterface/sorters/external/hdsort.py +++ b/src/spikeinterface/sorters/external/hdsort.py @@ -52,7 +52,7 @@ class HDSortSorter(BaseSorter): _params_description = { "detect_threshold": "Threshold for spike detection", - "detect_sign": "Use -1 (negative) or 1 (positive) depending " "on the sign of the spikes in the recording", + "detect_sign": "Use -1 (negative) or 1 (positive) depending on the sign of the spikes in the recording", "filter": "Enable or disable filter", "parfor": "If True, the Matlab parfor is used", "freq_min": "High-pass filter cutoff frequency", @@ -248,7 +248,7 @@ def _get_result_from_folder(cls, sorter_output_folder): def write_hdsort_input_format(cls, recording, save_path, chunk_memory="500M"): try: import h5py - except: + except Exception: raise Exception("To use HDSort, install h5py: pip install h5py") # check if already in write format @@ -294,7 +294,6 @@ def write_hdsort_input_format(cls, recording, save_path, chunk_memory="500M"): mapping[i] = (ch, x[i], y[i], i) ephys.create_dataset("mapping", data=mapping) # save traces - segment_index = 0 write_to_h5_dataset_format( recording, dataset_path="/ephys/signal", diff --git a/src/spikeinterface/sorters/external/herdingspikes.py b/src/spikeinterface/sorters/external/herdingspikes.py index 5f0bfa7dc1..c08907111d 100644 --- a/src/spikeinterface/sorters/external/herdingspikes.py +++ b/src/spikeinterface/sorters/external/herdingspikes.py @@ -128,9 +128,9 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): else: lightning_api = False - assert ( - lightning_api - ), "HerdingSpikes version <0.4.1 is no longer supported. To upgrade, run:\n>>> pip install --upgrade herdingspikes" + assert lightning_api, ( + "HerdingSpikes version <0.4.1 is no longer supported. To upgrade, run:\n>>> pip install --upgrade herdingspikes" + ) recording = cls.load_recording_from_folder(sorter_output_folder.parent, with_warnings=False) diff --git a/src/spikeinterface/sorters/external/ironclust.py b/src/spikeinterface/sorters/external/ironclust.py index e79324a0f8..ac0f0d05d5 100644 --- a/src/spikeinterface/sorters/external/ironclust.py +++ b/src/spikeinterface/sorters/external/ironclust.py @@ -161,8 +161,6 @@ def _check_apply_filter_in_params(cls, params): @classmethod def _setup_recording(cls, recording, sorter_output_folder, params, verbose): - p = params - dataset_dir = sorter_output_folder / "ironclust_dataset" # Generate three files in the dataset directory: raw.mda, geom.csv, params.json MdaRecordingExtractor.write_recording( diff --git a/src/spikeinterface/sorters/external/kilosort.py b/src/spikeinterface/sorters/external/kilosort.py index 1933be38d9..e80e439b17 100644 --- a/src/spikeinterface/sorters/external/kilosort.py +++ b/src/spikeinterface/sorters/external/kilosort.py @@ -256,9 +256,9 @@ def _get_specific_options(cls, ops, params) -> dict: ops["Th"] = params["Th"] # threshold for detecting spikes on template-filtered data ([6 12 12]) ops["lam"] = params["lam"] # large means amplitudes are forced around the mean ([10 30 30]) ops["nannealpasses"] = params["nannealpasses"] # should be less than nfullpasses (4) - assert ( - ops["nannealpasses"] < ops["nfullpasses"] - ), f"{ops['nannealpasses']=} should be less than {ops['nfullpasses']=}" + assert ops["nannealpasses"] < ops["nfullpasses"], ( + f"{ops['nannealpasses']=} should be less than {ops['nfullpasses']=}" + ) ops["momentum"] = params["momentum"] # start with high momentum and anneal (1./[20 1000]) ops["shuffle_clusters"] = params["shuffle_clusters"] # allow merges and splits during optimization (1) ops["mergeT"] = params["mergeT"] # upper threshold for merging (.1) diff --git a/src/spikeinterface/sorters/external/kilosort2.py b/src/spikeinterface/sorters/external/kilosort2.py index 6f4b0eec32..4ee92b5754 100644 --- a/src/spikeinterface/sorters/external/kilosort2.py +++ b/src/spikeinterface/sorters/external/kilosort2.py @@ -209,9 +209,9 @@ def _get_specific_options(cls, ops, params) -> dict: ops["skip_kilosort_preprocessing"] = params["skip_kilosort_preprocessing"] if params["skip_kilosort_preprocessing"]: ops["fproc"] = ops["fbinary"] - assert ( - params["scaleproc"] is not None - ), "When skip_kilosort_preprocessing=True scaleproc must explicitly given" + assert params["scaleproc"] is not None, ( + "When skip_kilosort_preprocessing=True scaleproc must explicitly given" + ) # int16 scaling of whitened data, when None then scaleproc is set to 200. scaleproc = params["scaleproc"] diff --git a/src/spikeinterface/sorters/external/kilosort2_5.py b/src/spikeinterface/sorters/external/kilosort2_5.py index 06a1f07b11..23359796a1 100644 --- a/src/spikeinterface/sorters/external/kilosort2_5.py +++ b/src/spikeinterface/sorters/external/kilosort2_5.py @@ -232,9 +232,9 @@ def _get_specific_options(cls, ops, params) -> dict: ops["skip_kilosort_preprocessing"] = params["skip_kilosort_preprocessing"] if params["skip_kilosort_preprocessing"]: ops["fproc"] = ops["fbinary"] - assert ( - params["scaleproc"] is not None - ), "When skip_kilosort_preprocessing=True scaleproc must explicitly given" + assert params["scaleproc"] is not None, ( + "When skip_kilosort_preprocessing=True scaleproc must explicitly given" + ) # int16 scaling of whitened data, when None then scaleproc is set to 200. scaleproc = params["scaleproc"] diff --git a/src/spikeinterface/sorters/external/kilosort3.py b/src/spikeinterface/sorters/external/kilosort3.py index 95cd145718..be405ae5fc 100644 --- a/src/spikeinterface/sorters/external/kilosort3.py +++ b/src/spikeinterface/sorters/external/kilosort3.py @@ -226,9 +226,9 @@ def _get_specific_options(cls, ops, params) -> dict: ops["skip_kilosort_preprocessing"] = params["skip_kilosort_preprocessing"] if params["skip_kilosort_preprocessing"]: ops["fproc"] = ops["fbinary"] - assert ( - params["scaleproc"] is not None - ), "When skip_kilosort_preprocessing=True scaleproc must explicitly given" + assert params["scaleproc"] is not None, ( + "When skip_kilosort_preprocessing=True scaleproc must explicitly given" + ) # int16 scaling of whitened data, when None then scaleproc is set to 200. scaleproc = params["scaleproc"] diff --git a/src/spikeinterface/sorters/external/kilosort4.py b/src/spikeinterface/sorters/external/kilosort4.py index ea5e596b79..e52b084484 100644 --- a/src/spikeinterface/sorters/external/kilosort4.py +++ b/src/spikeinterface/sorters/external/kilosort4.py @@ -182,9 +182,7 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): if version.parse(cls.get_sorter_version()) < version.parse("4.0.16"): raise RuntimeError( - "Kilosort versions before 4.0.16 are not supported" - "in SpikeInterface. " - "Please upgrade Kilosort version." + "Kilosort versions before 4.0.16 are not supportedin SpikeInterface. Please upgrade Kilosort version." ) # setup kilosort's console and file log handlers @@ -212,7 +210,7 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): # find the stream handler stream_handler = None for handler in logger.handlers: - if type(handler) == logging.StreamHandler: + if type(handler) is logging.StreamHandler: stream_handler = handler break diff --git a/src/spikeinterface/sorters/external/kilosortbase.py b/src/spikeinterface/sorters/external/kilosortbase.py index 15cbf4d3d0..68af4fa61e 100644 --- a/src/spikeinterface/sorters/external/kilosortbase.py +++ b/src/spikeinterface/sorters/external/kilosortbase.py @@ -226,9 +226,9 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): else: tmp_files_to_remove = () else: - assert isinstance( - params["delete_tmp_files"], (tuple, list) - ), "`delete_tmp_files` must be a `Bool`, `Tuple` or `List`." + assert isinstance(params["delete_tmp_files"], (tuple, list)), ( + "`delete_tmp_files` must be a `Bool`, `Tuple` or `List`." + ) for name in params["delete_tmp_files"]: assert name in all_tmp_files, f"{name} is not a valid option, must be one of: {all_tmp_files}" diff --git a/src/spikeinterface/sorters/external/mountainsort4.py b/src/spikeinterface/sorters/external/mountainsort4.py index f2a0e585c2..95d8fc2f04 100644 --- a/src/spikeinterface/sorters/external/mountainsort4.py +++ b/src/spikeinterface/sorters/external/mountainsort4.py @@ -30,7 +30,7 @@ class Mountainsort4Sorter(BaseSorter): } _params_description = { - "detect_sign": "Use -1 (negative) or 1 (positive) depending " "on the sign of the spikes in the recording", + "detect_sign": "Use -1 (negative) or 1 (positive) depending on the sign of the spikes in the recording", # Use -1, 0, or 1, depending on the sign of the spikes in the recording "adjacency_radius": "Radius in um to build channel neighborhood " "(Use -1 to include all channels in every neighborhood)", @@ -126,7 +126,7 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): if p["tempdir"] is not None: p["tempdir"] = str(p["tempdir"]) if verbose: - print(f'Using temporary directory {p["tempdir"]}') + print(f"Using temporary directory {p['tempdir']}") ms4_params.update(tempdir=p["tempdir"]) # Check location no more needed done in basesorter diff --git a/src/spikeinterface/sorters/external/rt_sort.py b/src/spikeinterface/sorters/external/rt_sort.py index 76ab5cc413..99f486c6c7 100644 --- a/src/spikeinterface/sorters/external/rt_sort.py +++ b/src/spikeinterface/sorters/external/rt_sort.py @@ -1,6 +1,5 @@ import importlib.util import os -import numpy as np from ..basesorter import BaseSorter @@ -116,7 +115,7 @@ class RTSortSorter(BaseSorter): This implementation in SpikeInterface only implements RT-Sort's offline sorting. For more information see https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0312438""" - installation_mesg = f"""\nTo use RTSort run:\n + installation_mesg = """\nTo use RTSort run:\n >>> pip install git+https://github.com/braingeneers/braindance#egg=braindance[rt-sort] Additionally, install PyTorch (https://pytorch.org/get-started/locally/) with any version of CUDA as the compute platform. diff --git a/src/spikeinterface/sorters/external/tests/test_combinato.py b/src/spikeinterface/sorters/external/tests/test_combinato.py index 248cf9274d..304f523f18 100644 --- a/src/spikeinterface/sorters/external/tests/test_combinato.py +++ b/src/spikeinterface/sorters/external/tests/test_combinato.py @@ -1,6 +1,6 @@ from spikeinterface.sorters import CombinatoSorter -import os, getpass +import getpass if getpass.getuser() == "samuel": combinato_path = "/home/samuel/Documents/SpikeInterface/combinato/" diff --git a/src/spikeinterface/sorters/external/tests/test_hdsort.py b/src/spikeinterface/sorters/external/tests/test_hdsort.py index d8495339d3..0894a3655e 100644 --- a/src/spikeinterface/sorters/external/tests/test_hdsort.py +++ b/src/spikeinterface/sorters/external/tests/test_hdsort.py @@ -1,6 +1,6 @@ from spikeinterface.sorters import HDSortSorter -import os, getpass +import getpass if getpass.getuser() == "samuel": hdsort_path = "/home/samuel/Documents/SpikeInterface/HDsort/" diff --git a/src/spikeinterface/sorters/external/tests/test_ironclust.py b/src/spikeinterface/sorters/external/tests/test_ironclust.py index 54edae6976..7642bc8f7e 100644 --- a/src/spikeinterface/sorters/external/tests/test_ironclust.py +++ b/src/spikeinterface/sorters/external/tests/test_ironclust.py @@ -1,4 +1,5 @@ -import os, getpass +import os +import getpass if getpass.getuser() == "samuel": ironclust_path = "/home/samuel/Documents/SpikeInterface/ironclust/" diff --git a/src/spikeinterface/sorters/external/tests/test_kilosort2_5.py b/src/spikeinterface/sorters/external/tests/test_kilosort2_5.py index 58d9114930..8f7c7939a5 100644 --- a/src/spikeinterface/sorters/external/tests/test_kilosort2_5.py +++ b/src/spikeinterface/sorters/external/tests/test_kilosort2_5.py @@ -1,6 +1,6 @@ from spikeinterface.sorters import Kilosort2_5Sorter -import os, getpass +import getpass if getpass.getuser() == "samuel": kilosort2_5_path = "/home/samuel/Documents/SpikeInterface/Kilosort2.5" diff --git a/src/spikeinterface/sorters/external/tests/test_singularity_containers_gpu.py b/src/spikeinterface/sorters/external/tests/test_singularity_containers_gpu.py index eb238abdf4..aa3e683199 100644 --- a/src/spikeinterface/sorters/external/tests/test_singularity_containers_gpu.py +++ b/src/spikeinterface/sorters/external/tests/test_singularity_containers_gpu.py @@ -1,5 +1,4 @@ import os -import shutil import pytest diff --git a/src/spikeinterface/sorters/external/tests/test_tridesclous.py b/src/spikeinterface/sorters/external/tests/test_tridesclous.py index 95c663a20e..b00512879e 100644 --- a/src/spikeinterface/sorters/external/tests/test_tridesclous.py +++ b/src/spikeinterface/sorters/external/tests/test_tridesclous.py @@ -1,7 +1,6 @@ import unittest import pytest -from spikeinterface.extractors import toy_example from spikeinterface.sorters import TridesclousSorter from spikeinterface.sorters.tests.common_tests import SorterCommonTestSuite diff --git a/src/spikeinterface/sorters/external/tests/test_waveclus.py b/src/spikeinterface/sorters/external/tests/test_waveclus.py index 71af12d99f..4d3335a6dd 100644 --- a/src/spikeinterface/sorters/external/tests/test_waveclus.py +++ b/src/spikeinterface/sorters/external/tests/test_waveclus.py @@ -1,4 +1,5 @@ -import os, getpass +import os +import getpass if getpass.getuser() == "samuel": waveclus_path = "/home/samuel/Documents/SpikeInterface/wave_clus/" diff --git a/src/spikeinterface/sorters/external/tridesclous.py b/src/spikeinterface/sorters/external/tridesclous.py index 95a9f2ef43..47c5d90878 100644 --- a/src/spikeinterface/sorters/external/tridesclous.py +++ b/src/spikeinterface/sorters/external/tridesclous.py @@ -31,7 +31,7 @@ class TridesclousSorter(BaseSorter): "freq_min": "High-pass filter cutoff frequency", "freq_max": "Low-pass filter cutoff frequency", "detect_threshold": "Threshold for spike detection", - "detect_sign": "Use -1 (negative) or 1 (positive) depending " "on the sign of the spikes in the recording", + "detect_sign": "Use -1 (negative) or 1 (positive) depending on the sign of the spikes in the recording", "common_ref_removal": "remove common reference with median", } diff --git a/src/spikeinterface/sorters/external/waveclus.py b/src/spikeinterface/sorters/external/waveclus.py index 2d498616b7..df38dfc0f6 100644 --- a/src/spikeinterface/sorters/external/waveclus.py +++ b/src/spikeinterface/sorters/external/waveclus.py @@ -194,7 +194,7 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): """ else: source_dir = Path(__file__).parent - shutil.copy(str(source_dir / f"waveclus_master.m"), str(sorter_output_folder)) + shutil.copy(str(source_dir / "waveclus_master.m"), str(sorter_output_folder)) sorter_path = Path(cls.waveclus_path).absolute() if "win" in sys.platform and sys.platform != "darwin": @@ -290,7 +290,7 @@ def _generate_par_file(params, sorter_output_folder): } par_input = {} for key, value in p.items(): - if type(value) == bool: + if type(value) is bool: value = f"{value}".lower() if key in par_renames: key = par_renames[key] diff --git a/src/spikeinterface/sorters/external/yass.py b/src/spikeinterface/sorters/external/yass.py index 1a1b40b324..77373e8ad9 100644 --- a/src/spikeinterface/sorters/external/yass.py +++ b/src/spikeinterface/sorters/external/yass.py @@ -163,7 +163,7 @@ def _setup_recording(cls, recording, sorter_output_folder, params, verbose): # to yaml fname_config = sorter_output_folder / "config.yaml" with open(fname_config, "w") as file: - documents = yaml.dump(merge_params, file) + _ = yaml.dump(merge_params, file) # RunNN training on existing neural_nets_path = p["neural_nets_path"] diff --git a/src/spikeinterface/sorters/internal/lupin.py b/src/spikeinterface/sorters/internal/lupin.py index f672593510..b266b258ee 100644 --- a/src/spikeinterface/sorters/internal/lupin.py +++ b/src/spikeinterface/sorters/internal/lupin.py @@ -12,7 +12,7 @@ from spikeinterface.core.job_tools import fix_job_kwargs -from spikeinterface.preprocessing import bandpass_filter, common_reference, zscore, whiten +from spikeinterface.preprocessing import bandpass_filter, common_reference, whiten from spikeinterface.core.base import minimum_spike_dtype from spikeinterface.sortingcomponents.tools import cache_preprocessing, clean_cache_preprocessing @@ -177,7 +177,6 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): # preprocessing if params["apply_preprocessing"]: if params["apply_motion_correction"]: - rec_for_motion = recording_raw if params["preprocessing_dict"] is None: rec_for_motion = bandpass_filter( diff --git a/src/spikeinterface/sorters/internal/si_based.py b/src/spikeinterface/sorters/internal/si_based.py index 3860e60fb5..64dc035085 100644 --- a/src/spikeinterface/sorters/internal/si_based.py +++ b/src/spikeinterface/sorters/internal/si_based.py @@ -1,4 +1,4 @@ -from spikeinterface.core import load, NumpyRecording +from spikeinterface.core import load from spikeinterface.sorters import BaseSorter diff --git a/src/spikeinterface/sorters/internal/simplesorter.py b/src/spikeinterface/sorters/internal/simplesorter.py index 0c7414171d..d0b89fe9fb 100644 --- a/src/spikeinterface/sorters/internal/simplesorter.py +++ b/src/spikeinterface/sorters/internal/simplesorter.py @@ -1,9 +1,8 @@ from .si_based import ComponentsBasedSorter -from spikeinterface.core import BaseRecording, get_noise_levels, extract_waveforms, NumpySorting +from spikeinterface.core import get_noise_levels, NumpySorting from spikeinterface.core.job_tools import fix_job_kwargs -from spikeinterface.sortingcomponents.tools import cache_preprocessing -from spikeinterface.preprocessing import bandpass_filter, common_reference, zscore +from spikeinterface.preprocessing import bandpass_filter, zscore import numpy as np diff --git a/src/spikeinterface/sorters/internal/spyking_circus2.py b/src/spikeinterface/sorters/internal/spyking_circus2.py index 06b804b305..f62c9f6259 100644 --- a/src/spikeinterface/sorters/internal/spyking_circus2.py +++ b/src/spikeinterface/sorters/internal/spyking_circus2.py @@ -1,6 +1,7 @@ from .si_based import ComponentsBasedSorter import shutil +import importlib.util import numpy as np from spikeinterface.core import NumpySorting @@ -90,8 +91,6 @@ class Spykingcircus2Sorter(ComponentsBasedSorter): @classmethod def is_installed(cls): - import importlib.util - spykingcircus2_deps = ["scipy", "numba", "hdbscan"] for package_name in spykingcircus2_deps: @@ -107,10 +106,7 @@ def get_sorter_version(cls): @classmethod def _run_from_folder(cls, sorter_output_folder, params, verbose): - try: - import torch - except ImportError: - HAVE_TORCH = False + if importlib.util.find_spec("torch") is None: print("spykingcircus2 could benefit from using torch. Consider installing it") # this is imported only on demand because numba import are too heavy @@ -231,7 +227,7 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): n_peaks_per_channel = selection_params.get("n_peaks_per_channel", 5000) min_n_peaks = selection_params.get("min_n_peaks", 100000) skip_peaks = not params["multi_units_only"] and selection_method == "uniform" - skip_peaks = skip_peaks and not deterministic and not (matching_method is None) + skip_peaks = skip_peaks and not deterministic and matching_method is not None max_n_peaks = n_peaks_per_channel * num_channels n_peaks = max(min_n_peaks, max_n_peaks) selection_params["n_peaks"] = n_peaks @@ -407,7 +403,6 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): del more_outs - before_clean_ids = templates.unit_ids.copy() cleaning_kwargs["max_std_per_channel"] = max_std_per_channel cleaning_kwargs["verbose"] = verbose templates = clean_templates(templates, noise_levels=noise_levels, **cleaning_kwargs) diff --git a/src/spikeinterface/sorters/internal/tests/test_lupin.py b/src/spikeinterface/sorters/internal/tests/test_lupin.py index f838f9f4eb..fca6208bc7 100644 --- a/src/spikeinterface/sorters/internal/tests/test_lupin.py +++ b/src/spikeinterface/sorters/internal/tests/test_lupin.py @@ -1,10 +1,9 @@ import unittest -import pytest from spikeinterface.sorters.tests.common_tests import SorterCommonTestSuite -from spikeinterface.sorters import LupinSorter, run_sorter +from spikeinterface.sorters import LupinSorter from pathlib import Path diff --git a/src/spikeinterface/sorters/internal/tests/test_spykingcircus2.py b/src/spikeinterface/sorters/internal/tests/test_spykingcircus2.py index 5188dd8329..7350809414 100644 --- a/src/spikeinterface/sorters/internal/tests/test_spykingcircus2.py +++ b/src/spikeinterface/sorters/internal/tests/test_spykingcircus2.py @@ -18,7 +18,7 @@ def test_with_numpy_gather(self): sorter_params["matching"]["gather_mode"] = "npy" - sorting = run_sorter( + _ = run_sorter( sorter_name, recording, folder=output_folder, diff --git a/src/spikeinterface/sorters/internal/tests/test_tridesclous2.py b/src/spikeinterface/sorters/internal/tests/test_tridesclous2.py index 6431532b87..73d8e34a42 100644 --- a/src/spikeinterface/sorters/internal/tests/test_tridesclous2.py +++ b/src/spikeinterface/sorters/internal/tests/test_tridesclous2.py @@ -1,6 +1,5 @@ import unittest -import pytest from spikeinterface.sorters.tests.common_tests import SorterCommonTestSuite @@ -26,7 +25,7 @@ def test_with_numpy_gather(self): sorter_params["gather_mode"] = "npy" - sorting = run_sorter( + _ = run_sorter( sorter_name, recording, folder=output_folder, diff --git a/src/spikeinterface/sorters/internal/tridesclous2.py b/src/spikeinterface/sorters/internal/tridesclous2.py index 56a506b293..20d6c4e6e3 100644 --- a/src/spikeinterface/sorters/internal/tridesclous2.py +++ b/src/spikeinterface/sorters/internal/tridesclous2.py @@ -1,6 +1,3 @@ -import shutil -import importlib - from .si_based import ComponentsBasedSorter from copy import deepcopy @@ -10,13 +7,12 @@ NumpySorting, estimate_templates_with_accumulator, Templates, - compute_sparsity, ms_to_samples, ) from spikeinterface.core.job_tools import fix_job_kwargs -from spikeinterface.preprocessing import bandpass_filter, common_reference, zscore, whiten +from spikeinterface.preprocessing import bandpass_filter, common_reference, whiten from spikeinterface.core.base import minimum_spike_dtype from spikeinterface.sortingcomponents.tools import cache_preprocessing, clean_cache_preprocessing @@ -142,7 +138,6 @@ def _run_from_folder(cls, sorter_output_folder, params, verbose): # preprocessing if params["apply_preprocessing"]: if params["apply_motion_correction"]: - rec_for_motion = recording_raw if params["preprocessing_dict"] is None: rec_for_motion = bandpass_filter( diff --git a/src/spikeinterface/sorters/launcher.py b/src/spikeinterface/sorters/launcher.py index e1b5921746..8dc295e1fc 100644 --- a/src/spikeinterface/sorters/launcher.py +++ b/src/spikeinterface/sorters/launcher.py @@ -290,7 +290,7 @@ def run_sorter_by_property( working_folder = Path(folder).absolute() assert grouping_property in recording.get_property_keys(), ( - f"The 'grouping_property' {grouping_property} is not " f"a recording property!" + f"The 'grouping_property' {grouping_property} is not a recording property!" ) recording_dict = recording.split_by(grouping_property) diff --git a/src/spikeinterface/sorters/runsorter.py b/src/spikeinterface/sorters/runsorter.py index 9b0e6855f5..c0923f0342 100644 --- a/src/spikeinterface/sorters/runsorter.py +++ b/src/spikeinterface/sorters/runsorter.py @@ -144,7 +144,6 @@ def run_sorter( ) if isinstance(recording, dict): - all_kwargs = common_kwargs all_kwargs.update( dict( @@ -186,8 +185,7 @@ def run_sorter( if not has_singularity(): raise RuntimeError( - "Singularity is not installed. Install singularity " - "on this machine to run sorting with singularity." + "Singularity is not installed. Install singularity on this machine to run sorting with singularity." ) if not has_spython(): @@ -482,9 +480,9 @@ def run_sorter_container( print(f"installation_mode='auto' switching to installation_mode: '{installation_mode}'") if installation_mode == "folder": - assert ( - spikeinterface_folder_source is not None - ), "for installation_mode='folder', spikeinterface_folder_source must be provided" + assert spikeinterface_folder_source is not None, ( + "for installation_mode='folder', spikeinterface_folder_source must be provided" + ) host_folder_source = Path(spikeinterface_folder_source) if installation_mode == "dev": @@ -552,7 +550,7 @@ def run_sorter_container( if need_si_install or installation_mode == "dev": # update pip in container - cmd = f"pip install --user --upgrade pip" + cmd = "pip install --user --upgrade pip" res_output = container_client.run_command(cmd) if installation_mode == "pypi": @@ -678,7 +676,7 @@ def run_sorter_container( if with_output: try: sorting = SorterClass.get_result_from_folder(folder) - except Exception as e: + except Exception: try: sorting = load(in_container_sorting_folder) except FileNotFoundError: diff --git a/src/spikeinterface/sorters/sorterlist.py b/src/spikeinterface/sorters/sorterlist.py index f536967b3b..71f16f1d6c 100644 --- a/src/spikeinterface/sorters/sorterlist.py +++ b/src/spikeinterface/sorters/sorterlist.py @@ -7,7 +7,7 @@ from .external.kilosort2 import Kilosort2Sorter from .external.kilosort2_5 import Kilosort2_5Sorter from .external.kilosort3 import Kilosort3Sorter -from .external.kilosort4 import Kilosort4Sorter, read_kilosort4_motion +from .external.kilosort4 import Kilosort4Sorter from .external.pykilosort import PyKilosortSorter from .external.klusta import KlustaSorter from .external.mountainsort4 import Mountainsort4Sorter diff --git a/src/spikeinterface/sorters/tests/test_container_tools.py b/src/spikeinterface/sorters/tests/test_container_tools.py index 2f3b176cc5..9fa2a69974 100644 --- a/src/spikeinterface/sorters/tests/test_container_tools.py +++ b/src/spikeinterface/sorters/tests/test_container_tools.py @@ -101,24 +101,24 @@ def test_install_package_in_container(): container_client = ContainerClient(mode, container_image, volumes, py_user_base, extra_kwargs) container_client.start() - txt = container_client.run_command("pip install --user --upgrade pip") + _ = container_client.run_command("pip install --user --upgrade pip") # # pypi installation - txt = install_package_in_container(container_client, "neo", installation_mode="pypi", version="0.11.0") + _ = install_package_in_container(container_client, "neo", installation_mode="pypi", version="0.11.0") # print(txt) - txt = container_client.run_command("pip list") + _ = container_client.run_command("pip list") # print(txt) # # github installation - txt = install_package_in_container( + _ = install_package_in_container( container_client, "spikeinterface", extra="[full]", installation_mode="github", version="0.99.0" ) # print(txt) - txt = container_client.run_command("pip list") + _ = container_client.run_command("pip list") # print(txt) # folder installation - txt = install_package_in_container( + _ = install_package_in_container( container_client, "spikeinterface", extra="[full]", @@ -127,7 +127,7 @@ def test_install_package_in_container(): ) # print(txt) - txt = container_client.run_command("pip list") + _ = container_client.run_command("pip list") # print(txt) container_client.stop() diff --git a/src/spikeinterface/sorters/tests/test_launcher.py b/src/spikeinterface/sorters/tests/test_launcher.py index 6619431866..3e13fa0e24 100644 --- a/src/spikeinterface/sorters/tests/test_launcher.py +++ b/src/spikeinterface/sorters/tests/test_launcher.py @@ -16,7 +16,6 @@ def create_recordings(folder, NUM_RECORDINGS=2, base_seed=42): recordings = [] for i in range(NUM_RECORDINGS): - recording, _ = generate_ground_truth_recording(num_channels=8, durations=[10.0], seed=base_seed + i) recording = recording.save(folder=folder / f"rec_for_generate_recording_{i}", format="binary", overwrite=True) diff --git a/src/spikeinterface/sorters/tests/test_runsorter_dependency_checks.py b/src/spikeinterface/sorters/tests/test_runsorter_dependency_checks.py index 12ef8caafd..af164b3f2a 100644 --- a/src/spikeinterface/sorters/tests/test_runsorter_dependency_checks.py +++ b/src/spikeinterface/sorters/tests/test_runsorter_dependency_checks.py @@ -1,7 +1,7 @@ import pytest import platform from spikeinterface import generate_ground_truth_recording -from spikeinterface.sorters.utils import has_spython, has_docker_python, has_docker, has_singularity +from spikeinterface.sorters.utils import has_spython, has_docker_python from spikeinterface.sorters import run_sorter import sys @@ -71,11 +71,11 @@ def uninstall_python_dependency(self, request): try: if dep_name == "spython": - import spython + import spython # noqa: F401 else: - import docker + import docker # noqa: F401 dependency_installed = True - except: + except Exception: dependency_installed = False if dependency_installed: @@ -120,7 +120,7 @@ def test_no_singularity_error_raised(self, recording, monkeypatch): return False. Then, test the expected error is raised when the dependency is not found. """ - monkeypatch.setattr(f"spikeinterface.sorters.runsorter.has_singularity", _monkeypatch_return_false) + monkeypatch.setattr("spikeinterface.sorters.runsorter.has_singularity", _monkeypatch_return_false) with pytest.raises(RuntimeError) as e: run_sorter("kilosort2_5", recording, singularity_image=True) @@ -132,8 +132,8 @@ def test_no_spython_error_raised(self, recording, monkeypatch): See `test_no_singularity_error_raised()`. """ # make sure singularity test returns true as that comes first - monkeypatch.setattr(f"spikeinterface.sorters.runsorter.has_singularity", _monkeypatch_return_true) - monkeypatch.setattr(f"spikeinterface.sorters.runsorter.has_spython", _monkeypatch_return_false) + monkeypatch.setattr("spikeinterface.sorters.runsorter.has_singularity", _monkeypatch_return_true) + monkeypatch.setattr("spikeinterface.sorters.runsorter.has_spython", _monkeypatch_return_false) with pytest.raises(RuntimeError) as e: run_sorter("kilosort2_5", recording, singularity_image=True) @@ -144,7 +144,7 @@ def test_no_docker_error_raised(self, recording, monkeypatch): """ See `test_no_singularity_error_raised()`. """ - monkeypatch.setattr(f"spikeinterface.sorters.runsorter.has_docker", _monkeypatch_return_false) + monkeypatch.setattr("spikeinterface.sorters.runsorter.has_docker", _monkeypatch_return_false) with pytest.raises(RuntimeError) as e: run_sorter("kilosort2_5", recording, docker_image=True) @@ -156,8 +156,8 @@ def test_as_no_docker_python_error_raised(self, recording, monkeypatch): See `test_no_singularity_error_raised()`. """ # make sure docker test returns true as that comes first - monkeypatch.setattr(f"spikeinterface.sorters.runsorter.has_docker", _monkeypatch_return_true) - monkeypatch.setattr(f"spikeinterface.sorters.runsorter.has_docker_python", _monkeypatch_return_false) + monkeypatch.setattr("spikeinterface.sorters.runsorter.has_docker", _monkeypatch_return_true) + monkeypatch.setattr("spikeinterface.sorters.runsorter.has_docker_python", _monkeypatch_return_false) with pytest.raises(RuntimeError) as e: run_sorter("kilosort2_5", recording, docker_image=True) diff --git a/src/spikeinterface/sorters/utils/misc.py b/src/spikeinterface/sorters/utils/misc.py index 162c8f07c2..66e6710260 100644 --- a/src/spikeinterface/sorters/utils/misc.py +++ b/src/spikeinterface/sorters/utils/misc.py @@ -52,7 +52,7 @@ def get_git_commit(git_folder, shorten=True): commit = check_output(["git", "rev-parse", "HEAD"], cwd=git_folder).decode("utf8").strip() if shorten: commit = commit[:12] - except: + except Exception: commit = None return commit diff --git a/src/spikeinterface/sorters/utils/shellscript.py b/src/spikeinterface/sorters/utils/shellscript.py index abd2eaf0b1..5659466b78 100644 --- a/src/spikeinterface/sorters/utils/shellscript.py +++ b/src/spikeinterface/sorters/utils/shellscript.py @@ -106,7 +106,7 @@ def wait(self, timeout=None) -> int | None: try: retcode = self._process.wait(timeout=timeout) return retcode - except: + except Exception: return None def cleanup(self) -> None: @@ -133,7 +133,7 @@ def stop(self) -> None: try: self._process.wait(timeout=0.02) return - except: + except Exception: pass def kill(self) -> None: @@ -144,7 +144,7 @@ def kill(self) -> None: self._process.send_signal(signal.SIGKILL) try: self._process.wait(timeout=1) - except: + except Exception: print("WARNING: unable to kill shell script.") pass @@ -157,7 +157,7 @@ def stopWithSignal(self, sig, timeout) -> bool: try: self._process.wait(timeout=timeout) return True - except: + except Exception: return False def elapsedTimeSinceStart(self) -> float | None: @@ -208,7 +208,7 @@ def _rmdir_with_retries(dirname, num_retries, delay_between_tries=1): try: shutil.rmtree(dirname) break - except: + except Exception: if retry_num < num_retries: print(f"Retrying to remove directory: {dirname}") time.sleep(delay_between_tries) diff --git a/src/spikeinterface/sortingcomponents/clustering/cleaning_tools.py b/src/spikeinterface/sortingcomponents/clustering/cleaning_tools.py index 4f10f51b73..6825b68a72 100644 --- a/src/spikeinterface/sortingcomponents/clustering/cleaning_tools.py +++ b/src/spikeinterface/sortingcomponents/clustering/cleaning_tools.py @@ -5,7 +5,6 @@ import numpy as np from spikeinterface.core.job_tools import fix_job_kwargs from spikeinterface.postprocessing import check_equal_template_with_distribution_overlap -from spikeinterface.core import NumpySorting def _split_waveforms( @@ -50,7 +49,6 @@ def _split_waveforms( if debug: import matplotlib.pyplot as plt - import umap fig, ax = plt.subplots() @@ -122,7 +120,6 @@ def _split_waveforms_nested( # hdbscan on pca clustering = hdbscan.hdbscan(local_feature, **hdbscan_params) active_labels_with_noise = clustering[0] - cluster_probability = clustering[2] (persistent_clusters,) = np.nonzero(clustering[2] > probability_thr) active_labels_with_noise[~np.isin(active_labels_with_noise, persistent_clusters)] = -1 @@ -229,9 +226,6 @@ def auto_split_clustering( Internally used by PositionAndPCAClustering for the second step. """ - import sklearn.decomposition - import hdbscan - split_peak_labels = -1 * np.ones(peak_labels.size, dtype=np.int64) nb_clusters = 0 main_channels = {} @@ -505,7 +499,6 @@ def remove_duplicates( idx = np.argsort(channel_norms)[::-1] explained_norms = np.cumsum(channel_norms[idx] / total_norm) channel = np.searchsorted(explained_norms, sparsify_threshold) - active_channels = np.sort(idx[:channel]) templates[t, :, idx[channel:]] = 0 from sklearn.metrics.pairwise import cosine_similarity @@ -589,11 +582,9 @@ def detect_mixtures(templates, method_kwargs={}, job_kwargs={}, tmp_folder=None, DEBUG = False sub_recording = None # we only do a sub recording if we have data to iterate through while keep_searching: - keep_searching = False for i in list(set(range(nb_templates)).difference(ignore_inds)): - ## Could be speed up by only computing the values for templates that are ## nearby @@ -642,7 +633,6 @@ def detect_mixtures(templates, method_kwargs={}, job_kwargs={}, tmp_folder=None, import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 2) - from spikeinterface.widgets import plot_traces # plot_traces(sub_recording, ax=axes[0]) axes[1].plot(templates_array[i].flatten(), label=f"{ref_norm}") diff --git a/src/spikeinterface/sortingcomponents/clustering/graph_clustering.py b/src/spikeinterface/sortingcomponents/clustering/graph_clustering.py index bea9cda7a2..197f5674ae 100644 --- a/src/spikeinterface/sortingcomponents/clustering/graph_clustering.py +++ b/src/spikeinterface/sortingcomponents/clustering/graph_clustering.py @@ -1,5 +1,3 @@ -from pathlib import Path - import numpy as np @@ -72,7 +70,6 @@ def main_function(cls, recording, peaks, params, job_kwargs=dict()): radius_um = peaks_svd["radius_um"] motion = peaks_svd["motion"] seed = params["seed"] - verbose = params["verbose"] clustering_kwargs = params["clusterer"].copy() graph_kwargs = params["graph_kwargs"].copy() diff --git a/src/spikeinterface/sortingcomponents/clustering/graph_tools.py b/src/spikeinterface/sortingcomponents/clustering/graph_tools.py index a76adec994..df38fdca10 100644 --- a/src/spikeinterface/sortingcomponents/clustering/graph_tools.py +++ b/src/spikeinterface/sortingcomponents/clustering/graph_tools.py @@ -58,7 +58,6 @@ def create_graph_from_peak_features( channel_locations = recording.get_channel_locations() if bin_mode == "channels": - dims = ["xyz".index(i) for i in direction] channel_locs = channel_locations[:, dims] channel_distances = np.linalg.norm(channel_locs[:, np.newaxis] - channel_locs[np.newaxis, :], axis=2) @@ -71,7 +70,6 @@ def create_graph_from_peak_features( loop.append((local_chans, neighbors_indices, target_local_inds)) elif bin_mode == "vertical_bins": - assert len(direction) == 1 dim = "xyz".index(direction) channel_depth = channel_locations[:, dim] @@ -92,7 +90,6 @@ def create_graph_from_peak_features( loop = [] for b in range(bins.size - 1): - # limits for peaks l0, l1 = bins[b], bins[b + 1] # mask = (peak_depths> l0) & (peak_depths<= l1) diff --git a/src/spikeinterface/sortingcomponents/clustering/isosplit_isocut.py b/src/spikeinterface/sortingcomponents/clustering/isosplit_isocut.py index c5dd6654ab..a6be2db181 100644 --- a/src/spikeinterface/sortingcomponents/clustering/isosplit_isocut.py +++ b/src/spikeinterface/sortingcomponents/clustering/isosplit_isocut.py @@ -42,7 +42,6 @@ if HAVE_NUMBA: - ########################## # isocut zone @@ -284,7 +283,6 @@ def isosplit( """ if initial_labels is None: - if n_init >= X.shape[0]: # protect against too high n_init compared to sample size warnings.warn(f"isosplit : n_init {n_init} is too big compared to sample size {X.shape[0]}") @@ -367,7 +365,6 @@ def isosplit( break if active_labels.size > 1: - # Find the pairs to compare on this iteration # These will be closest pairs of active clusters that have not yet # been compared in this pass diff --git a/src/spikeinterface/sortingcomponents/clustering/iterative_isosplit.py b/src/spikeinterface/sortingcomponents/clustering/iterative_isosplit.py index 002de2feeb..4ca8c3616a 100644 --- a/src/spikeinterface/sortingcomponents/clustering/iterative_isosplit.py +++ b/src/spikeinterface/sortingcomponents/clustering/iterative_isosplit.py @@ -271,7 +271,6 @@ def main_function(cls, recording, peaks, params, job_kwargs=dict()): # templates_array = dense_templates.templates_array if params["merge_from_features"] is not None: - merge_from_features_kwargs = params["merge_from_features"].copy() merge_radius_um = merge_from_features_kwargs.pop("merge_radius_um") diff --git a/src/spikeinterface/sortingcomponents/clustering/itersplit_tools.py b/src/spikeinterface/sortingcomponents/clustering/itersplit_tools.py index d34ca8bb4e..5864ae9e68 100644 --- a/src/spikeinterface/sortingcomponents/clustering/itersplit_tools.py +++ b/src/spikeinterface/sortingcomponents/clustering/itersplit_tools.py @@ -1,5 +1,4 @@ import warnings -import importlib.util from multiprocessing import get_context from threadpoolctl import threadpool_limits from tqdm.auto import tqdm @@ -10,11 +9,6 @@ from .tools import aggregate_sparse_features, FeaturesLoader -if importlib.util.find_spec("numba") is not None: - import numba -else: - pass -# isocut requires numba # important all DEBUG and matplotlib are left in the code intentionally @@ -352,7 +346,6 @@ def split( if final_features.shape[1] == 1: final_features = np.hstack((final_features, np.zeros_like(final_features))) - sl = slice(None, None, 100) for k in np.unique(possible_labels): mask = possible_labels == k ax = axs[0] @@ -364,7 +357,7 @@ def split( ax.plot(flatten_wfs[mask].T, color=colors[k], alpha=0.1) if k > -1: ax.plot(np.median(flatten_wfs[mask].T, axis=1), color=colors[k], lw=2) - ax.set_xlabel(f"PCA features") + ax.set_xlabel("PCA features") ax = axs[3] if n_pca_features == 1: diff --git a/src/spikeinterface/sortingcomponents/clustering/main.py b/src/spikeinterface/sortingcomponents/clustering/main.py index 46052fa5ae..c8b8a60a27 100644 --- a/src/spikeinterface/sortingcomponents/clustering/main.py +++ b/src/spikeinterface/sortingcomponents/clustering/main.py @@ -1,4 +1,4 @@ -from spikeinterface.core.job_tools import fix_job_kwargs, _shared_job_kwargs_doc +from spikeinterface.core.job_tools import fix_job_kwargs import copy from ..tools import make_multi_method_doc @@ -39,9 +39,9 @@ def find_clusters_from_peaks( """ job_kwargs = fix_job_kwargs(job_kwargs) - assert ( - method in clustering_methods - ), f"Method for clustering do not exists, should be in {list(clustering_methods.keys())}" + assert method in clustering_methods, ( + f"Method for clustering do not exists, should be in {list(clustering_methods.keys())}" + ) method_class = clustering_methods[method] params = copy.deepcopy(method_class._default_params.copy()) diff --git a/src/spikeinterface/sortingcomponents/clustering/merging_tools.py b/src/spikeinterface/sortingcomponents/clustering/merging_tools.py index 9cc4bd18a3..1b9194d504 100644 --- a/src/spikeinterface/sortingcomponents/clustering/merging_tools.py +++ b/src/spikeinterface/sortingcomponents/clustering/merging_tools.py @@ -7,6 +7,7 @@ import numpy as np from spikeinterface.core.job_tools import get_poolexecutor, fix_job_kwargs +from .tools import aggregate_sparse_features, FeaturesLoader numba_spec = importlib.util.find_spec("numba") networkx_spec = importlib.util.find_spec("networkx") @@ -20,7 +21,6 @@ else: pass -from .tools import aggregate_sparse_features, FeaturesLoader DEBUG = False @@ -45,10 +45,6 @@ def merge_peak_labels_from_features( job_kwargs = fix_job_kwargs(job_kwargs) - features = FeaturesLoader.from_dict_or_folder(features_dict_or_folder) - # sparse_wfs = features["sparse_wfs"] - # sparse_mask = features["sparse_mask"] - labels_set, pair_mask, pair_shift, pair_values = find_merge_pairs_from_features( peaks, peak_labels, @@ -443,7 +439,6 @@ def merge( is_merge = l0 >= l1 merge_value = l0 - l1 elif criteria == "distrib_overlap": - lim0 = min(np.min(feat0), np.min(feat1)) lim1 = max(np.max(feat0), np.max(feat1)) bin_size = (lim1 - lim0) / 200.0 diff --git a/src/spikeinterface/sortingcomponents/clustering/positions.py b/src/spikeinterface/sortingcomponents/clustering/positions.py index b94f6607cb..93e57c27d1 100644 --- a/src/spikeinterface/sortingcomponents/clustering/positions.py +++ b/src/spikeinterface/sortingcomponents/clustering/positions.py @@ -1,5 +1,4 @@ # """Sorting components: clustering""" -from pathlib import Path import importlib.util import numpy as np diff --git a/src/spikeinterface/sortingcomponents/clustering/random_projections.py b/src/spikeinterface/sortingcomponents/clustering/random_projections.py index cd451f4d07..24966fd348 100644 --- a/src/spikeinterface/sortingcomponents/clustering/random_projections.py +++ b/src/spikeinterface/sortingcomponents/clustering/random_projections.py @@ -4,13 +4,6 @@ import importlib import numpy as np -hdbscan_spec = importlib.util.find_spec("hdbscan") -if hdbscan_spec is not None: - HAVE_HDBSCAN = True - import hdbscan -else: - HAVE_HDBSCAN = False - from spikeinterface.core.base import minimum_spike_dtype from spikeinterface.core.core_tools import ms_to_samples from spikeinterface.core.waveform_tools import estimate_templates @@ -25,6 +18,14 @@ ) +hdbscan_spec = importlib.util.find_spec("hdbscan") +if hdbscan_spec is not None: + HAVE_HDBSCAN = True + import hdbscan +else: + HAVE_HDBSCAN = False + + class RandomProjectionClustering: """ hdbscan clustering on peak_locations previously done by localize_peaks() diff --git a/src/spikeinterface/sortingcomponents/clustering/tests/test_clustering.py b/src/spikeinterface/sortingcomponents/clustering/tests/test_clustering.py index 35984f3732..081c6c02d3 100644 --- a/src/spikeinterface/sortingcomponents/clustering/tests/test_clustering.py +++ b/src/spikeinterface/sortingcomponents/clustering/tests/test_clustering.py @@ -107,7 +107,7 @@ def test_templates_from_svd(recording, peaks, job_kwargs): peaks_svd, sparse_mask, svd_model = extract_peaks_svd( recording, peaks, n_components=1, ms_before=1, ms_after=1, job_kwargs=job_kwargs ) - templates = get_templates_from_peaks_and_svd( + _ = get_templates_from_peaks_and_svd( recording, peaks, peaks["channel_index"], diff --git a/src/spikeinterface/sortingcomponents/clustering/tests/test_isosplit_isocut.py b/src/spikeinterface/sortingcomponents/clustering/tests/test_isosplit_isocut.py index 1b1deffc8a..7635b158b6 100644 --- a/src/spikeinterface/sortingcomponents/clustering/tests/test_isosplit_isocut.py +++ b/src/spikeinterface/sortingcomponents/clustering/tests/test_isosplit_isocut.py @@ -147,10 +147,10 @@ def test_isosplit(): # check that numba handle the 2 dtypes data = data.astype("float64") - labels = isosplit(data, isocut_threshold=2.0, n_init=40, seed=2205) + _ = isosplit(data, isocut_threshold=2.0, n_init=40, seed=2205) data = data.astype("float32") - labels = isosplit(data, isocut_threshold=2.0, n_init=40, seed=2205) + _ = isosplit(data, isocut_threshold=2.0, n_init=40, seed=2205) # the beauty is that it discovers the number of clusters automatically, at least for this this seed :) # assert np.unique(labels).size == 3 diff --git a/src/spikeinterface/sortingcomponents/clustering/tests/test_itersplit_tool.py b/src/spikeinterface/sortingcomponents/clustering/tests/test_itersplit_tool.py index 35e2678d13..1476606ec5 100644 --- a/src/spikeinterface/sortingcomponents/clustering/tests/test_itersplit_tool.py +++ b/src/spikeinterface/sortingcomponents/clustering/tests/test_itersplit_tool.py @@ -1,8 +1,3 @@ -import pytest - -from spikeinterface.sortingcomponents.clustering.itersplit_tools import split_clusters - - # TODO def test_split(): pass diff --git a/src/spikeinterface/sortingcomponents/clustering/tests/test_merging_tools.py b/src/spikeinterface/sortingcomponents/clustering/tests/test_merging_tools.py index e462985450..77b1049b7b 100644 --- a/src/spikeinterface/sortingcomponents/clustering/tests/test_merging_tools.py +++ b/src/spikeinterface/sortingcomponents/clustering/tests/test_merging_tools.py @@ -1,11 +1,3 @@ -import pytest - -from spikeinterface.sortingcomponents.clustering.merging_tools import ( - merge_peak_labels_from_features, - merge_peak_labels_from_templates, -) - - # TODO def test_merge(): pass diff --git a/src/spikeinterface/sortingcomponents/clustering/tools.py b/src/spikeinterface/sortingcomponents/clustering/tools.py index 2fb05bbc6b..1df339400f 100644 --- a/src/spikeinterface/sortingcomponents/clustering/tools.py +++ b/src/spikeinterface/sortingcomponents/clustering/tools.py @@ -1,5 +1,4 @@ from pathlib import Path -from typing import Any import numpy as np from spikeinterface.core import Templates, estimate_templates, fix_job_kwargs diff --git a/src/spikeinterface/sortingcomponents/matching/base.py b/src/spikeinterface/sortingcomponents/matching/base.py index 3288417173..e4efa41948 100644 --- a/src/spikeinterface/sortingcomponents/matching/base.py +++ b/src/spikeinterface/sortingcomponents/matching/base.py @@ -16,9 +16,9 @@ def __init__(self, recording, templates, return_output=True): # TODO make a sharedmem of template here # TODO maybe check that channel_id are the same with recording - assert isinstance( - templates, Templates - ), f"The templates supplied is of type {type(templates)} and must be a Templates" + assert isinstance(templates, Templates), ( + f"The templates supplied is of type {type(templates)} and must be a Templates" + ) self.templates = templates self.recording = recording PeakDetector.__init__(self, recording, return_output=return_output, parents=None) diff --git a/src/spikeinterface/sortingcomponents/matching/circus.py b/src/spikeinterface/sortingcomponents/matching/circus.py index cb133e435f..72706dd5f3 100644 --- a/src/spikeinterface/sortingcomponents/matching/circus.py +++ b/src/spikeinterface/sortingcomponents/matching/circus.py @@ -3,6 +3,9 @@ import numpy as np import importlib.util +from .base import BaseTemplateMatching + + spike_dtype = [ ("sample_index", "int64"), ("channel_index", "int64"), @@ -23,8 +26,6 @@ else: HAVE_TORCH = False -from .base import BaseTemplateMatching - def compress_templates( templates_array, approx_rank, remove_mean=False, return_new_templates=True @@ -385,6 +386,7 @@ def compute_matching(self, traces, start_frame, end_frame, segment_index): all_selections = np.empty((2, scalar_products.size), dtype=np.int32) final_amplitudes = np.zeros(scalar_products.shape, dtype=np.float32) num_selection = 0 + selection = all_selections[:, :0] # empty until the first peak is picked full_sps = scalar_products.copy() @@ -406,7 +408,6 @@ def compute_matching(self, traces, start_frame, end_frame, segment_index): do_loop = True while do_loop: - best_cluster_inds = np.argmax(scalar_products, axis=0, keepdims=True) products = np.take_along_axis(scalar_products, best_cluster_inds, axis=0) @@ -419,7 +420,6 @@ def compute_matching(self, traces, start_frame, end_frame, segment_index): break for peak_index in peak_indices: - best_cluster_ind = best_cluster_inds[0, peak_index] if num_selection > 0: @@ -572,224 +572,3 @@ def __del__(self): self.overlaps = None self.shm.close() self.shm = None - - -class CircusPeeler(BaseTemplateMatching): - """ - Greedy Template-matching ported from the Spyking Circus sorter - - https://elifesciences.org/articles/34518 - - This is a Greedy Template Matching algorithm. The idea is to detect - all the peaks (negative, positive or both) above a certain threshold - Then, at every peak (plus or minus some jitter) we look if the signal - can be explained with a scaled template. - The amplitudes allowed, for every templates, are automatically adjusted - in an optimal manner, to enhance the Matthew Correlation Coefficient - between all spikes/templates in the waveformextractor. For speed and - memory optimization, templates are automatically sparsified if the - density of the matrix falls below a given threshold - - Parameters - ---------- - peak_sign : str - Sign of the peak (neg, pos, or both) - exclude_sweep_ms : float - The number of samples before/after to classify a peak (should be low) - jitter : int - The number of samples considered before/after every peak to search for - matches - detect_threshold : int - The detection threshold - max_amplitude : float - Maximal amplitude allowed for every template - min_amplitude : float - Minimal amplitude allowed for every template - use_sparse_matrix_threshold : float - If density of the templates is below a given threshold, sparse matrix - are used (memory efficient) - sparse_kwargs : dict - Parameters to extract a sparsity mask from the waveform_extractor, if not - already sparse. - ----- - - - """ - - def __init__( - self, - recording, - return_output=True, - templates=None, - peak_sign="neg", - exclude_sweep_ms=0.8, - jitter_ms=0.1, - detect_threshold=5, - noise_levels=None, - max_amplitude=1.5, - min_amplitude=0.5, - use_sparse_matrix_threshold=0.25, - ): - - BaseTemplateMatching.__init__(self, recording, templates, return_output=return_output) - sklearn_spec = importlib.util.find_spec("sklearn") is not None - if sklearn_spec is not None: - HAVE_SKLEARN = True - else: - HAVE_SKLEARN = False - - assert HAVE_SKLEARN, "CircusPeeler needs sklearn to work" - - assert (use_sparse_matrix_threshold >= 0) and ( - use_sparse_matrix_threshold <= 1 - ), f"use_sparse_matrix_threshold should be in [0, 1]" - - self.num_channels = recording.get_num_channels() - self.num_samples = templates.num_samples - self.num_templates = len(templates.unit_ids) - - self.abs_threholds = noise_levels * detect_threshold - - self.use_sparse_matrix_threshold = use_sparse_matrix_threshold - self._prepare_templates() - self.overlaps = compute_overlaps( - self.normed_templates, - self.num_samples, - self.num_channels, - self.sparsities, - ) - - self.exclude_sweep_size = int(exclude_sweep_ms * recording.get_sampling_frequency() / 1000.0) - - self.nbefore = templates.nbefore - self.nafter = templates.nafter - self.patch_sizes = (templates.num_samples, self.num_channels) - self.sym_patch = self.nbefore == self.nafter - self.jitter = int(jitter_ms * recording.get_sampling_frequency() / 1000.0) - - self.amplitudes = np.zeros((self.num_templates, 2), dtype=np.float32) - self.amplitudes[:, 0] = min_amplitude - self.amplitudes[:, 1] = max_amplitude - - self.margin = max(self.nbefore, self.nafter) * 2 - self.peak_sign = peak_sign - - def _prepare_templates(self): - - from scipy.sparse import csr_matrix - - self.norms = np.zeros(self.num_templates, dtype=np.float32) - - all_units = self.templates.unit_ids - - sparsity = self.templates.sparsity.mask - - templates_array = self.templates.get_dense_templates() - self.sparsities = {} - self.normed_templates = {} - - for count, unit_id in enumerate(all_units): - self.sparsities[count] = np.flatnonzero(sparsity[count]) - self.norms[count] = np.linalg.norm(templates_array[count]) - templates_array[count] /= self.norms[count] - self.normed_templates[count] = templates_array[count][:, sparsity[count]] - - templates_array = templates_array.reshape(self.num_templates, -1) - - nnz = np.sum(templates_array != 0) / (self.num_templates * self.num_samples * self.num_channels) - if nnz <= self.use_sparse_matrix_threshold: - templates_array = csr_matrix(templates_array) - print(f"Templates are automatically sparsified (sparsity level is {nnz})") - self.is_dense = False - else: - self.is_dense = True - - self.circus_templates = templates_array - - def get_margin(self): - return self.margin - - def compute_matching(self, traces, start_frame, end_frame, segment_index): - - neighbor_window = self.num_samples - 1 - - peak_traces = traces[self.margin // 2 : -self.margin // 2, :] - peak_sample_index, peak_chan_ind = DetectPeakByChannel.detect_peaks( - peak_traces, self.peak_sign, self.abs_threholds, self.exclude_sweep_size - ) - from sklearn.feature_extraction.image import extract_patches_2d - - if self.jitter > 0: - jittered_peaks = peak_sample_index[:, np.newaxis] + np.arange(-self.jitter, self.jitter) - jittered_channels = peak_chan_ind[:, np.newaxis] + np.zeros(2 * self.jitter) - mask = (jittered_peaks > 0) & (jittered_peaks < len(peak_traces)) - jittered_peaks = jittered_peaks[mask] - jittered_channels = jittered_channels[mask] - peak_sample_index, unique_idx = np.unique(jittered_peaks, return_index=True) - peak_chan_ind = jittered_channels[unique_idx] - else: - peak_sample_index, unique_idx = np.unique(peak_sample_index, return_index=True) - peak_chan_ind = peak_chan_ind[unique_idx] - - num_peaks = len(peak_sample_index) - - if self.sym_patch: - snippets = extract_patches_2d(traces, self.patch_sizes)[peak_sample_index] - peak_sample_index += self.margin // 2 - else: - peak_sample_index += self.margin // 2 - snippet_window = np.arange(-self.nbefore, self.nafter) - snippets = traces[peak_sample_index[:, np.newaxis] + snippet_window] - - if num_peaks > 0: - snippets = snippets.reshape(num_peaks, -1) - scalar_products = self.circus_templates.dot(snippets.T) - else: - scalar_products = np.zeros((self.num_templates, 0), dtype=np.float32) - - num_spikes = 0 - spikes = np.empty(scalar_products.size, dtype=spike_dtype) - idx_lookup = np.arange(scalar_products.size).reshape(self.num_templates, -1) - - min_sps = (self.amplitudes[:, 0] * self.norms)[:, np.newaxis] - max_sps = (self.amplitudes[:, 1] * self.norms)[:, np.newaxis] - - is_valid = (scalar_products > min_sps) & (scalar_products < max_sps) - - cached_overlaps = {} - - while np.any(is_valid): - best_amplitude_ind = scalar_products[is_valid].argmax() - best_cluster_ind, peak_index = np.unravel_index(idx_lookup[is_valid][best_amplitude_ind], idx_lookup.shape) - - best_amplitude = scalar_products[best_cluster_ind, peak_index] - best_peak_sample_index = peak_sample_index[peak_index] - best_peak_chan_ind = peak_chan_ind[peak_index] - - peak_data = peak_sample_index - peak_sample_index[peak_index] - is_valid_nn = np.searchsorted(peak_data, [-neighbor_window, neighbor_window + 1]) - idx_neighbor = peak_data[is_valid_nn[0] : is_valid_nn[1]] + neighbor_window - - if not best_cluster_ind in cached_overlaps.keys(): - cached_overlaps[best_cluster_ind] = self.overlaps[best_cluster_ind].toarray() - - to_add = -best_amplitude * cached_overlaps[best_cluster_ind][:, idx_neighbor] - - scalar_products[:, is_valid_nn[0] : is_valid_nn[1]] += to_add - scalar_products[best_cluster_ind, is_valid_nn[0] : is_valid_nn[1]] = -np.inf - - spikes["sample_index"][num_spikes] = best_peak_sample_index - spikes["channel_index"][num_spikes] = best_peak_chan_ind - spikes["cluster_index"][num_spikes] = best_cluster_ind - spikes["amplitude"][num_spikes] = best_amplitude - num_spikes += 1 - - is_valid = (scalar_products > min_sps) & (scalar_products < max_sps) - - spikes["amplitude"][:num_spikes] /= self.norms[spikes["cluster_index"][:num_spikes]] - - spikes = spikes[:num_spikes] - order = np.argsort(spikes["sample_index"]) - spikes = spikes[order] - - return spikes diff --git a/src/spikeinterface/sortingcomponents/matching/main.py b/src/spikeinterface/sortingcomponents/matching/main.py index 0b054c0638..ec54f91bc7 100644 --- a/src/spikeinterface/sortingcomponents/matching/main.py +++ b/src/spikeinterface/sortingcomponents/matching/main.py @@ -1,7 +1,6 @@ import numpy as np -import warnings -from .method_list import * +from .method_list import matching_methods from spikeinterface.core.node_pipeline import run_node_pipeline @@ -65,9 +64,6 @@ def find_spikes_from_templates( # if method_class.full_convolution: # Maybe we need to automatically adjust the temporal chunks given templates and n_processes - if len(templates.unit_ids) == 0: - return np.zeros(0, dtype=node0.get_dtype()) - if method_class.need_noise_levels: if "noise_levels" not in method_kwargs: raise ValueError(f"find_spikes_from_templates() method {method} need noise_levels") @@ -75,6 +71,9 @@ def find_spikes_from_templates( node0 = method_class(recording, templates=templates, **method_kwargs) nodes = [node0] + if len(templates.unit_ids) == 0: + return np.zeros(0, dtype=node0.get_dtype()) + if pipeline_kwargs is None: pipeline_kwargs = dict() diff --git a/src/spikeinterface/sortingcomponents/matching/nearest.py b/src/spikeinterface/sortingcomponents/matching/nearest.py index 7ca2c3ece4..5221f66e81 100644 --- a/src/spikeinterface/sortingcomponents/matching/nearest.py +++ b/src/spikeinterface/sortingcomponents/matching/nearest.py @@ -1,16 +1,13 @@ """Sorting components: template matching.""" import numpy as np -from spikeinterface.core.template_tools import get_template_extremum_channel -from spikeinterface.core import get_noise_levels, get_channel_distances -from spikeinterface.core.sparsity import compute_sparsity +from spikeinterface.core import get_channel_distances from .base import BaseTemplateMatching, _base_matching_dtype class NearestTemplatesPeeler(BaseTemplateMatching): - name = "nearest" need_noise_levels = True # this is because numba @@ -75,18 +72,6 @@ def __init__( self.neighborhood_mask = np.ones((num_channels, num_templates), dtype=bool) if support_radius_um is not None: - if not templates.are_templates_sparse(): - from spikeinterface.core.sparsity import compute_sparsity - - sparsity = compute_sparsity( - templates, - method="radius", - radius_um=sparsity_radius_um, - peak_sign=self.peak_sign, - ) - else: - sparsity = templates.sparsity - channel_locations = recording.get_channel_locations() channel_distances = np.linalg.norm(channel_locations[:, None] - channel_locations[np.newaxis, :], axis=2) self.sparsity_support_mask = channel_distances <= self.support_radius_um @@ -153,16 +138,18 @@ def compute_matching(self, traces, start_frame, end_frame, segment_index): class NearestTemplatesSVDPeeler(NearestTemplatesPeeler): - name = "nearest-svd" need_noise_levels = True - params_doc = NearestTemplatesPeeler.params_doc + """ + params_doc = ( + NearestTemplatesPeeler.params_doc + + """ svd_model : The svd model used to project the waveforms The radius to use to select neighbour channels for locally exclusive detection. svd_radius_um : float The radius in um of the local neighboorhood used, centered on every detected peaks, to compute the distances with all the templates in the SVD space """ + ) def __init__( self, diff --git a/src/spikeinterface/sortingcomponents/matching/tdc_peeler.py b/src/spikeinterface/sortingcomponents/matching/tdc_peeler.py index cff99020fd..3101af0485 100644 --- a/src/spikeinterface/sortingcomponents/matching/tdc_peeler.py +++ b/src/spikeinterface/sortingcomponents/matching/tdc_peeler.py @@ -418,7 +418,6 @@ def compute_matching(self, traces, start_frame, end_frame, segment_index): all_spikes = [] for start, stop, channel_motions in loop: - local_residuals = residuals[start:stop] spikes_in_time_bin = [] @@ -782,7 +781,6 @@ def get_neighbors_spikes(sample_inds, chan_inds, delta_sample, near_chan_mask): neighbors_spikes_inds = [] for i in range(sample_inds.size): - inds = np.flatnonzero(np.abs(sample_inds - sample_inds[i]) < delta_sample) neighb = [] for ind in inds: @@ -817,7 +815,6 @@ def fit_one_amplitude_with_neighbors( amplitude = np.sum(template.flatten() * wf.flatten()) / template_norms[cluster_index] else: - lim0 = min(start, np.min(neighbors_spikes["sample_index"]) - nbefore) lim1 = max(stop, np.max(neighbors_spikes["sample_index"]) + nafter) @@ -833,7 +830,6 @@ def fit_one_amplitude_with_neighbors( num_spikes_to_fit = 1 + np.sum(mask_not_fitted) x = np.zeros((lim1 - lim0, num_chans, num_spikes_to_fit), dtype="float32") - wanted_channel_mask = chan_sparsity_mask construct_prediction_sparse( np.array([local_spike]), x[:, :, 0], diff --git a/src/spikeinterface/sortingcomponents/matching/tests/test_template_matching.py b/src/spikeinterface/sortingcomponents/matching/tests/test_template_matching.py index 0fb3e6bc61..3fbf404907 100644 --- a/src/spikeinterface/sortingcomponents/matching/tests/test_template_matching.py +++ b/src/spikeinterface/sortingcomponents/matching/tests/test_template_matching.py @@ -1,8 +1,7 @@ import pytest import numpy as np -from pathlib import Path -from spikeinterface import NumpySorting, create_sorting_analyzer, compute_sparsity, get_noise_levels +from spikeinterface import create_sorting_analyzer, compute_sparsity, get_noise_levels from spikeinterface.sortingcomponents.matching import find_spikes_from_templates from spikeinterface.sortingcomponents.matching.method_list import matching_methods @@ -90,28 +89,25 @@ def test_find_spikes_from_templates(method, sorting_analyzer): # print(info) # DEBUG = True - DEBUG = False + # DEBUG = False - if DEBUG: - import matplotlib.pyplot as plt - import spikeinterface.full as si + # if DEBUG: + # sorting_analyzer.compute("waveforms") + # sorting_analyzer.compute("templates") - sorting_analyzer.compute("waveforms") - sorting_analyzer.compute("templates") + # gt_sorting = sorting_analyzer.sorting - gt_sorting = sorting_analyzer.sorting + # sorting = NumpySorting.from_samples_and_labels( + # spikes["sample_index"], spikes["cluster_index"], recording.sampling_frequency + # ) - sorting = NumpySorting.from_samples_and_labels( - spikes["sample_index"], spikes["cluster_index"], recording.sampling_frequency - ) + # #metrics = si.compute_quality_metrics(sorting_analyzer, metric_names=["snr"]) - ##metrics = si.compute_quality_metrics(sorting_analyzer, metric_names=["snr"]) - - # fig, ax = plt.subplots() - # comp = si.compare_sorter_to_ground_truth(gt_sorting, sorting) - # si.plot_agreement_matrix(comp, ax=ax) - # ax.set_title(method) - # plt.show() + # fig, ax = plt.subplots() + # comp = si.compare_sorter_to_ground_truth(gt_sorting, sorting) + # si.plot_agreement_matrix(comp, ax=ax) + # ax.set_title(method) + # plt.show() if __name__ == "__main__": diff --git a/src/spikeinterface/sortingcomponents/matching/tests/test_wobble.py b/src/spikeinterface/sortingcomponents/matching/tests/test_wobble.py index 36d5452933..f3a7a2e4f9 100644 --- a/src/spikeinterface/sortingcomponents/matching/tests/test_wobble.py +++ b/src/spikeinterface/sortingcomponents/matching/tests/test_wobble.py @@ -1,6 +1,5 @@ from types import SimpleNamespace -import pytest import numpy as np from spikeinterface.sortingcomponents.matching import wobble @@ -326,7 +325,6 @@ def test_compute_scale_amplitudes(): rng = np.random.default_rng(seed) num_spikes = rng.integers(0, 100) norm_peaks = rng.random(num_spikes) - num_jittered = rng.integers(1, 100) peak_window_size = rng.integers(1, 100) high_resolution_conv = rng.random((peak_window_size, num_spikes)) scale_min = rng.random() * 10 diff --git a/src/spikeinterface/sortingcomponents/matching/wobble.py b/src/spikeinterface/sortingcomponents/matching/wobble.py index e9ee961c3e..9a42f3d9b3 100644 --- a/src/spikeinterface/sortingcomponents/matching/wobble.py +++ b/src/spikeinterface/sortingcomponents/matching/wobble.py @@ -171,9 +171,9 @@ def from_parameters_and_templates(cls, params, templates): if params.template_indices2unit_indices is None: # Trivial grouping of templates = units template_indices2unit_indices = np.arange(num_templates) else: - assert params.template_indices2unit_indices.shape == ( - templates.shape[0], - ), "template_indices2unit_indices must have shape (num_templates,)" + assert params.template_indices2unit_indices.shape == (templates.shape[0],), ( + "template_indices2unit_indices must have shape (num_templates,)" + ) template_indices2unit_indices = params.template_indices2unit_indices unit_indices = np.unique(template_indices2unit_indices) num_units = len(unit_indices) diff --git a/src/spikeinterface/sortingcomponents/motion/decentralized.py b/src/spikeinterface/sortingcomponents/motion/decentralized.py index 076d3658de..509841e6f6 100644 --- a/src/spikeinterface/sortingcomponents/motion/decentralized.py +++ b/src/spikeinterface/sortingcomponents/motion/decentralized.py @@ -3,7 +3,7 @@ from tqdm.auto import tqdm, trange from spikeinterface.core.motion import Motion -from .motion_utils import get_spatial_windows, get_spatial_bin_edges, make_2d_motion_histogram, scipy_conv1d +from .motion_utils import get_spatial_windows, get_spatial_bin_edges, make_2d_motion_histogram from .dredge import normxcorr1d @@ -328,7 +328,7 @@ def compute_pairwise_displacement( if conv_engine == "torch": import torch - assert conv_engine in ("torch", "numpy"), f"'conv_engine' must be 'torch' or 'numpy'" + assert conv_engine in ("torch", "numpy"), "'conv_engine' must be 'torch' or 'numpy'" size = motion_hist.shape[0] pairwise_displacement = np.zeros((size, size), dtype="float32") @@ -509,7 +509,6 @@ def jac(p): displacement = res.x elif convergence_method == "lsqr_robust": - if sparse_mask is not None: I, J = np.nonzero(sparse_mask > 0) elif pairwise_displacement_weight is not None: diff --git a/src/spikeinterface/sortingcomponents/motion/dredge.py b/src/spikeinterface/sortingcomponents/motion/dredge.py index 6d9cc1afdf..b6a0529776 100644 --- a/src/spikeinterface/sortingcomponents/motion/dredge.py +++ b/src/spikeinterface/sortingcomponents/motion/dredge.py @@ -296,7 +296,6 @@ def dredge_ap( threshold_kw = dict(bin_s=bin_s) if batching_mode == "full": - displacement, extra = compute_displacement_full( raster, windows, @@ -313,7 +312,6 @@ def dredge_ap( ) elif batching_mode == "online": - # T_total is number of bin_s in recording T_total = raster.shape[1] T_chunk = max(1, int(np.ceil(chunk_len_s / bin_s))) diff --git a/src/spikeinterface/sortingcomponents/motion/medicine.py b/src/spikeinterface/sortingcomponents/motion/medicine.py index 8be18f7502..0cfc44f5a1 100644 --- a/src/spikeinterface/sortingcomponents/motion/medicine.py +++ b/src/spikeinterface/sortingcomponents/motion/medicine.py @@ -1,11 +1,7 @@ import numpy as np -import tempfile -import shutil -from pathlib import Path from spikeinterface.core.motion import Motion -from spikeinterface.sortingcomponents.motion.motion_utils import get_spatial_windows class MedicineRegistration: diff --git a/src/spikeinterface/sortingcomponents/motion/motion_estimation.py b/src/spikeinterface/sortingcomponents/motion/motion_estimation.py index 7e48ef146e..6f309281d7 100644 --- a/src/spikeinterface/sortingcomponents/motion/motion_estimation.py +++ b/src/spikeinterface/sortingcomponents/motion/motion_estimation.py @@ -1,5 +1,4 @@ import warnings -import numpy as np from spikeinterface.sortingcomponents.tools import make_multi_method_doc diff --git a/src/spikeinterface/sortingcomponents/motion/motion_interpolation.py b/src/spikeinterface/sortingcomponents/motion/motion_interpolation.py index 0eb63b8b6b..dc2b9ae2a2 100644 --- a/src/spikeinterface/sortingcomponents/motion/motion_interpolation.py +++ b/src/spikeinterface/sortingcomponents/motion/motion_interpolation.py @@ -359,8 +359,7 @@ def __init__( channel_locations = recording.get_channel_locations() assert channel_locations.ndim >= motion.dim, ( - f"'direction' {motion.direction} not available. " - f"Channel locations have {channel_locations.ndim} dimensions." + f"'direction' {motion.direction} not available. Channel locations have {channel_locations.ndim} dimensions." ) spatial_interpolation_kwargs = dict( sigma_um=sigma_um, p=p, num_closest=num_closest, **spatial_interpolation_kwargs diff --git a/src/spikeinterface/sortingcomponents/motion/motion_utils.py b/src/spikeinterface/sortingcomponents/motion/motion_utils.py index c58322d2c6..ab08326c56 100644 --- a/src/spikeinterface/sortingcomponents/motion/motion_utils.py +++ b/src/spikeinterface/sortingcomponents/motion/motion_utils.py @@ -1,7 +1,6 @@ import warnings import numpy as np -from spikeinterface.core.core_tools import check_json def get_spatial_windows( @@ -58,8 +57,6 @@ def get_spatial_windows( Here by default we use gaussian window. """ - n = spatial_bin_centers.size - if rigid: # win_shape = 'rect' is forced windows, window_centers = get_rigid_windows(spatial_bin_centers) diff --git a/src/spikeinterface/sortingcomponents/motion/tests/test_drege.py b/src/spikeinterface/sortingcomponents/motion/tests/test_drege.py index 8133c1fa6b..202ae63a64 100644 --- a/src/spikeinterface/sortingcomponents/motion/tests/test_drege.py +++ b/src/spikeinterface/sortingcomponents/motion/tests/test_drege.py @@ -1,6 +1,3 @@ -import pytest - - def test_dredge_online_lfp(): pass diff --git a/src/spikeinterface/sortingcomponents/motion/tests/test_medicine.py b/src/spikeinterface/sortingcomponents/motion/tests/test_medicine.py index 4db1d8bfd7..cdbafa504b 100644 --- a/src/spikeinterface/sortingcomponents/motion/tests/test_medicine.py +++ b/src/spikeinterface/sortingcomponents/motion/tests/test_medicine.py @@ -1,9 +1,6 @@ import numpy as np import pytest -torch = pytest.importorskip("torch") -medicine = pytest.importorskip("medicine") - from spikeinterface import get_noise_levels from spikeinterface.core.node_pipeline import ExtractDenseWaveforms, run_node_pipeline from spikeinterface.sortingcomponents.motion import estimate_motion @@ -11,6 +8,10 @@ from spikeinterface.sortingcomponents.peak_localization.method_list import LocalizeCenterOfMass from spikeinterface.sortingcomponents.tests.common import make_dataset + +torch = pytest.importorskip("torch") +medicine = pytest.importorskip("medicine") + # Kept tiny so the model trains in a fraction of a second. Not representative of settings # one would use for real motion estimation. _FAST_TRAINING_KWARGS = dict(batch_size=32, training_steps=15, motion_noise_steps=5) diff --git a/src/spikeinterface/sortingcomponents/motion/tests/test_motion_estimation.py b/src/spikeinterface/sortingcomponents/motion/tests/test_motion_estimation.py index 1ba43e6a13..adff080792 100644 --- a/src/spikeinterface/sortingcomponents/motion/tests/test_motion_estimation.py +++ b/src/spikeinterface/sortingcomponents/motion/tests/test_motion_estimation.py @@ -6,7 +6,7 @@ from spikeinterface import get_noise_levels from spikeinterface.core.node_pipeline import ExtractDenseWaveforms, run_node_pipeline from spikeinterface.sortingcomponents.motion import estimate_motion -from spikeinterface.sortingcomponents.peak_detection import detect_peaks, detect_peak_methods +from spikeinterface.sortingcomponents.peak_detection import detect_peak_methods from spikeinterface.sortingcomponents.peak_localization.method_list import LocalizeCenterOfMass from spikeinterface.sortingcomponents.tests.common import make_dataset diff --git a/src/spikeinterface/sortingcomponents/peak_detection/locally_exclusive.py b/src/spikeinterface/sortingcomponents/peak_detection/locally_exclusive.py index bafb526a8c..d25007c02c 100644 --- a/src/spikeinterface/sortingcomponents/peak_detection/locally_exclusive.py +++ b/src/spikeinterface/sortingcomponents/peak_detection/locally_exclusive.py @@ -1,18 +1,18 @@ import numpy as np import importlib.util +from spikeinterface.core.node_pipeline import ( + PeakDetector, +) +from spikeinterface.core.recording_tools import get_channel_distances +from .by_channel import ByChannelTorchPeakDetector, ByChannelPeakDetector + numba_spec = importlib.util.find_spec("numba") if numba_spec is not None: HAVE_NUMBA = True else: HAVE_NUMBA = False -from spikeinterface.core.node_pipeline import ( - PeakDetector, -) -from spikeinterface.core.recording_tools import get_channel_distances -from .by_channel import ByChannelTorchPeakDetector - torch_spec = importlib.util.find_spec("torch") if torch_spec is not None: torch_nn_functional_spec = importlib.util.find_spec("torch.nn") @@ -29,8 +29,6 @@ else: HAVE_PYOPENCL = False -from .by_channel import ByChannelPeakDetector - class LocallyExclusivePeakDetector(PeakDetector): """Detect peaks using the "locally exclusive" method.""" @@ -42,10 +40,13 @@ class LocallyExclusivePeakDetector(PeakDetector): # this is because numba need_first_call_before_pipeline = True - params_doc = ByChannelPeakDetector.params_doc + """ + params_doc = ( + ByChannelPeakDetector.params_doc + + """ radius_um: float The radius to use to select neighbour channels for locally exclusive detection. """ + ) def __init__( self, @@ -148,7 +149,6 @@ def detect_peaks_numba_locally_exclusive_on_chunk( keep_peak = np.ones(npeaks, dtype="bool") next_start = 0 for i in range(npeaks): - if (samples_inds[i] < exclude_sweep_size + 1) or ( samples_inds[i] >= (num_samples - exclude_sweep_size - 1) ): @@ -195,10 +195,13 @@ class LocallyExclusiveTorchPeakDetector(ByChannelTorchPeakDetector): engine = "torch" need_noise_levels = True preferred_mp_context = "spawn" - params_doc = ByChannelPeakDetector.params_doc + """ + params_doc = ( + ByChannelPeakDetector.params_doc + + """ radius_um: float The radius to use to select neighbour channels for locally exclusive detection. """ + ) def __init__( self, @@ -265,10 +268,13 @@ class LocallyExclusiveOpenCLPeakDetector(LocallyExclusivePeakDetector): engine = "opencl" preferred_mp_context = None need_noise_levels = True - params_doc = LocallyExclusiveTorchPeakDetector.params_doc + """ + params_doc = ( + LocallyExclusiveTorchPeakDetector.params_doc + + """ opencl_context_kwargs: None or dict kwargs to create the opencl context """ + ) def __init__( self, diff --git a/src/spikeinterface/sortingcomponents/peak_detection/main.py b/src/spikeinterface/sortingcomponents/peak_detection/main.py index 4332acac0f..0fc554efea 100644 --- a/src/spikeinterface/sortingcomponents/peak_detection/main.py +++ b/src/spikeinterface/sortingcomponents/peak_detection/main.py @@ -2,7 +2,7 @@ from .method_list import detect_peak_methods -from spikeinterface.core.job_tools import split_job_kwargs, fix_job_kwargs +from spikeinterface.core.job_tools import fix_job_kwargs from ..tools import make_multi_method_doc diff --git a/src/spikeinterface/sortingcomponents/peak_detection/matched_filtering.py b/src/spikeinterface/sortingcomponents/peak_detection/matched_filtering.py index a7ce981ed3..13849cf700 100644 --- a/src/spikeinterface/sortingcomponents/peak_detection/matched_filtering.py +++ b/src/spikeinterface/sortingcomponents/peak_detection/matched_filtering.py @@ -8,6 +8,7 @@ from spikeinterface.core.node_pipeline import PeakDetector from spikeinterface.core.recording_tools import get_channel_distances, get_random_data_chunks from spikeinterface.postprocessing.localization_tools import get_convolution_weights +from .by_channel import ByChannelPeakDetector numba_spec = importlib.util.find_spec("numba") if numba_spec is not None: @@ -15,8 +16,6 @@ else: HAVE_NUMBA = False -from .by_channel import ByChannelPeakDetector - class MatchedFilteringPeakDetector(PeakDetector): """Detect peaks using the 'matched_filtering' method.""" @@ -25,7 +24,9 @@ class MatchedFilteringPeakDetector(PeakDetector): engine = "numba" need_noise_levels = False preferred_mp_context = None - params_doc = ByChannelPeakDetector.params_doc + """ + params_doc = ( + ByChannelPeakDetector.params_doc + + """ radius_um : float The radius to use to select neighbour channels for locally exclusive detection. prototype : array @@ -37,6 +38,7 @@ class MatchedFilteringPeakDetector(PeakDetector): in order to know how to estimate the positions. One argument is mode that could be either gaussian_2d (KS like) or exponential_3d (default) """ + ) def __init__( self, diff --git a/src/spikeinterface/sortingcomponents/peak_detection/tests/test_peak_detection.py b/src/spikeinterface/sortingcomponents/peak_detection/tests/test_peak_detection.py index 25b9d9515a..7f25299476 100644 --- a/src/spikeinterface/sortingcomponents/peak_detection/tests/test_peak_detection.py +++ b/src/spikeinterface/sortingcomponents/peak_detection/tests/test_peak_detection.py @@ -327,7 +327,7 @@ def test_detect_peaks_locally_exclusive(recording, job_kwargs, torch_job_kwargs) assert np.isclose(np.array(len(peaks_local_numba)), np.array(len(peaks_local_torch)), rtol=0.1) if HAVE_PYOPENCL: - peaks_local_cl = detect_peaks( + _ = detect_peaks( recording, method="locally_exclusive_cl", method_kwargs=dict( diff --git a/src/spikeinterface/sortingcomponents/peak_localization/base.py b/src/spikeinterface/sortingcomponents/peak_localization/base.py index 5e6a16fe4c..04d4307ffc 100644 --- a/src/spikeinterface/sortingcomponents/peak_localization/base.py +++ b/src/spikeinterface/sortingcomponents/peak_localization/base.py @@ -6,7 +6,6 @@ class LocalizeBase(PipelineNode): - def __init__(self, recording, parents, return_output=True, radius_um=75.0): PipelineNode.__init__(self, recording, parents=parents, return_output=return_output) self.recording = recording diff --git a/src/spikeinterface/sortingcomponents/peak_localization/grid.py b/src/spikeinterface/sortingcomponents/peak_localization/grid.py index c55b6b712e..94bcd38af2 100644 --- a/src/spikeinterface/sortingcomponents/peak_localization/grid.py +++ b/src/spikeinterface/sortingcomponents/peak_localization/grid.py @@ -4,7 +4,6 @@ from spikeinterface.core.node_pipeline import ( find_parent_of_type, - PipelineNode, WaveformsNode, ) diff --git a/src/spikeinterface/sortingcomponents/peak_localization/main.py b/src/spikeinterface/sortingcomponents/peak_localization/main.py index d75f4a8a55..1cb8d8629d 100644 --- a/src/spikeinterface/sortingcomponents/peak_localization/main.py +++ b/src/spikeinterface/sortingcomponents/peak_localization/main.py @@ -4,7 +4,7 @@ from .method_list import peak_localization_methods from ..tools import make_multi_method_doc -from spikeinterface.core.job_tools import split_job_kwargs, fix_job_kwargs +from spikeinterface.core.job_tools import fix_job_kwargs from spikeinterface.core.node_pipeline import ( @@ -30,9 +30,9 @@ def get_localization_pipeline_nodes( seed=None, ): - assert ( - method in peak_localization_methods - ), f"Method {method} is not supported. Choose from {peak_localization_methods.keys()}" + assert method in peak_localization_methods, ( + f"Method {method} is not supported. Choose from {peak_localization_methods.keys()}" + ) assert method_kwargs is not None @@ -152,9 +152,9 @@ def localize_peaks( job_kwargs = fix_job_kwargs(job_kwargs) - assert ( - method in peak_localization_methods - ), f"Method {method} is not supported. Choose from {peak_localization_methods.keys()}" + assert method in peak_localization_methods, ( + f"Method {method} is not supported. Choose from {peak_localization_methods.keys()}" + ) peak_source = PeakRetriever(recording, peaks) diff --git a/src/spikeinterface/sortingcomponents/peak_localization/tests/test_peak_localization.py b/src/spikeinterface/sortingcomponents/peak_localization/tests/test_peak_localization.py index 9db0588f6d..15d0476e65 100644 --- a/src/spikeinterface/sortingcomponents/peak_localization/tests/test_peak_localization.py +++ b/src/spikeinterface/sortingcomponents/peak_localization/tests/test_peak_localization.py @@ -1,6 +1,3 @@ -import pytest -import numpy as np - from spikeinterface.sortingcomponents.peak_detection import detect_peaks from spikeinterface.sortingcomponents.peak_localization import localize_peaks diff --git a/src/spikeinterface/sortingcomponents/peak_selection.py b/src/spikeinterface/sortingcomponents/peak_selection.py index 018e627217..b260e7ef5e 100644 --- a/src/spikeinterface/sortingcomponents/peak_selection.py +++ b/src/spikeinterface/sortingcomponents/peak_selection.py @@ -288,7 +288,7 @@ def select_peak_indices(peaks, method, seed, **method_kwargs): else: raise NotImplementedError( - f"The 'method' {method} does not exist for peaks selection." f" possible methods are {_possible_methods}" + f"The 'method' {method} does not exist for peaks selection. possible methods are {_possible_methods}" ) selected_indices = np.concatenate(selected_indices) diff --git a/src/spikeinterface/sortingcomponents/tests/test_peak_selection.py b/src/spikeinterface/sortingcomponents/tests/test_peak_selection.py index e9d8f1987b..94db8bc510 100644 --- a/src/spikeinterface/sortingcomponents/tests/test_peak_selection.py +++ b/src/spikeinterface/sortingcomponents/tests/test_peak_selection.py @@ -1,4 +1,3 @@ -import pytest import numpy as np @@ -52,37 +51,37 @@ def test_select_peaks(): ] for method in select_methods: selected_peaks = select_peaks(peaks, method=method, **select_kwargs) - assert ( - selected_peaks.size <= n_peaks - ), "selected_peaks is not the right size when return_indices=False, select_per_channel=False" + assert selected_peaks.size <= n_peaks, ( + "selected_peaks is not the right size when return_indices=False, select_per_channel=False" + ) selected_peaks = select_peaks(peaks, recording=recording, method=method, margin=(10, 10), **select_kwargs) - assert ( - selected_peaks.size <= n_peaks - ), "selected_peaks is not the right size when return_indices=False, select_per_channel=False" + assert selected_peaks.size <= n_peaks, ( + "selected_peaks is not the right size when return_indices=False, select_per_channel=False" + ) selected_peaks = select_peaks(peaks, method=method, select_per_channel=True, **select_kwargs) - assert selected_peaks.size <= ( - n_peaks * recording.get_num_channels() - ), "selected_peaks is not the right size when return_indices=False, select_per_channel=True" + assert selected_peaks.size <= (n_peaks * recording.get_num_channels()), ( + "selected_peaks is not the right size when return_indices=False, select_per_channel=True" + ) selected_peaks, selected_indices = select_peaks(peaks, method=method, return_indices=True, **select_kwargs) - assert ( - selected_peaks.size <= n_peaks - ), "selected_peaks is not the right size when return_indices=True, select_per_channel=False" - assert np.all( - selected_peaks == peaks[selected_indices] - ), "selection_indices differ from selected_peaks when select_per_channel=False" + assert selected_peaks.size <= n_peaks, ( + "selected_peaks is not the right size when return_indices=True, select_per_channel=False" + ) + assert np.all(selected_peaks == peaks[selected_indices]), ( + "selection_indices differ from selected_peaks when select_per_channel=False" + ) selected_peaks, selected_indices = select_peaks( peaks, method=method, return_indices=True, select_per_channel=True, **select_kwargs ) - assert selected_peaks.size <= ( - n_peaks * recording.get_num_channels() - ), "selected_peaks is not the right size when return_indices=True, select_per_channel=True" - assert np.all( - selected_peaks == peaks[selected_indices] - ), "selection_indices differ from selected_peaks when select_per_channel=True" + assert selected_peaks.size <= (n_peaks * recording.get_num_channels()), ( + "selected_peaks is not the right size when return_indices=True, select_per_channel=True" + ) + assert np.all(selected_peaks == peaks[selected_indices]), ( + "selection_indices differ from selected_peaks when select_per_channel=True" + ) if __name__ == "__main__": diff --git a/src/spikeinterface/sortingcomponents/waveforms/features_from_peaks.py b/src/spikeinterface/sortingcomponents/waveforms/features_from_peaks.py index 0c7ffe7447..ec750d8c95 100644 --- a/src/spikeinterface/sortingcomponents/waveforms/features_from_peaks.py +++ b/src/spikeinterface/sortingcomponents/waveforms/features_from_peaks.py @@ -6,7 +6,6 @@ from spikeinterface.core import get_channel_distances from spikeinterface.sortingcomponents.peak_localization.method_list import ( LocalizeCenterOfMass, - LocalizeMonopolarTriangulation, ) from spikeinterface.core.node_pipeline import ( run_node_pipeline, @@ -70,9 +69,9 @@ def compute_features_from_peaks( extract_dense_waveforms, ] for feature_name in feature_list: - assert ( - feature_name in _features_class.keys() - ), f"Feature {feature_name} in 'feature_list' is not possible. Possible features are {list(_features_class.keys())}" + assert feature_name in _features_class.keys(), ( + f"Feature {feature_name} in 'feature_list' is not possible. Possible features are {list(_features_class.keys())}" + ) Class = _features_class[feature_name] params = feature_params.get(feature_name, {}).copy() node = Class(recording, parents=[peak_retriever, extract_dense_waveforms], **params) diff --git a/src/spikeinterface/sortingcomponents/waveforms/neural_network_denoiser.py b/src/spikeinterface/sortingcomponents/waveforms/neural_network_denoiser.py index 7a889780b9..b5d6a45a03 100644 --- a/src/spikeinterface/sortingcomponents/waveforms/neural_network_denoiser.py +++ b/src/spikeinterface/sortingcomponents/waveforms/neural_network_denoiser.py @@ -82,9 +82,9 @@ def __init__( self.denoiser, model_relative_path = self.load_model( model_folder=model_folder, repo_id=repo_id, model_name=model_name, spike_size=spike_size ) - except RuntimeError as e: + except RuntimeError: raise ValueError( - f"Failed to load model. Check consistency between waveform node shapes and model output layer" + "Failed to load model. Check consistency between waveform node shapes and model output layer" ) self.assert_model_and_waveform_temporal_match( @@ -122,7 +122,7 @@ def assert_model_and_waveform_temporal_match( try: filename = str(model_relative_path).replace(".pt", ".json") json_file_path = hf_hub_download(repo_id=repo_id, filename=filename) - except Exception as e: + except Exception: warnings.warn(f"Could not download json file from repo {repo_id}. Model might misbehave") if json_file_path is None or not Path(json_file_path).exists(): @@ -179,9 +179,9 @@ def load_model( else: if model_name is not None: raise ValueError(f"Multiple models found in {model_folder}. Please specify model_name") - assert ( - model_name is not None - ), "If there are multiple .pt files in the repo, you need to specify the model_name" + assert model_name is not None, ( + "If there are multiple .pt files in the repo, you need to specify the model_name" + ) filename = [f for f in pt_files if model_name in f] if len(filename) == 0: raise ValueError(f"Model {model_name} not found in repo {repo_id}") @@ -199,9 +199,9 @@ def load_model( if len(pt_files) == 1: filename = pt_files[0] else: - assert ( - model_name is not None - ), "If there are multiple .pt files in the repo, you need to specify the model_name" + assert model_name is not None, ( + "If there are multiple .pt files in the repo, you need to specify the model_name" + ) filename = [f for f in pt_files if model_name in f] if len(filename) == 0: raise ValueError(f"Model {model_name} not found in repo {repo_id}") diff --git a/src/spikeinterface/sortingcomponents/waveforms/tests/test_features_from_peaks.py b/src/spikeinterface/sortingcomponents/waveforms/tests/test_features_from_peaks.py index 736b040a26..79f48932c5 100644 --- a/src/spikeinterface/sortingcomponents/waveforms/tests/test_features_from_peaks.py +++ b/src/spikeinterface/sortingcomponents/waveforms/tests/test_features_from_peaks.py @@ -1,5 +1,3 @@ -import pytest - from spikeinterface.sortingcomponents.waveforms.features_from_peaks import compute_features_from_peaks from spikeinterface.core import get_noise_levels from spikeinterface.sortingcomponents.peak_detection import detect_peaks diff --git a/src/spikeinterface/sortingcomponents/waveforms/tests/test_hanning_filter.py b/src/spikeinterface/sortingcomponents/waveforms/tests/test_hanning_filter.py index 1b006af429..83848881a1 100644 --- a/src/spikeinterface/sortingcomponents/waveforms/tests/test_hanning_filter.py +++ b/src/spikeinterface/sortingcomponents/waveforms/tests/test_hanning_filter.py @@ -1,6 +1,3 @@ -import pytest - - from spikeinterface.sortingcomponents.waveforms.hanning_filter import HanningFilter from spikeinterface.core.node_pipeline import ( diff --git a/src/spikeinterface/sortingcomponents/waveforms/tests/test_neural_network_denoiser.py b/src/spikeinterface/sortingcomponents/waveforms/tests/test_neural_network_denoiser.py index b481a39ca6..d2cd517f86 100644 --- a/src/spikeinterface/sortingcomponents/waveforms/tests/test_neural_network_denoiser.py +++ b/src/spikeinterface/sortingcomponents/waveforms/tests/test_neural_network_denoiser.py @@ -83,7 +83,7 @@ def test_single_channel_yass_denoiser_wrong_shape(generated_recording_30khz, det recording, parents=[peak_retriever], nbefore=nbefore, nafter=nafter, return_output=True ) with pytest.raises(ValueError): - yass_denoiser = SingleChannelDenoiser( + _ = SingleChannelDenoiser( recording, parents=[peak_retriever, waveform_extraction], repo_id="spikeinterface/waveform_denoiser", @@ -96,4 +96,4 @@ def test_single_channel_yass_denoiser_wrong_shape(generated_recording_30khz, det model_name="yass_ibl", ) with pytest.raises(ValueError): - yass_denoiser = SingleChannelDenoiser(recording, parents=[peak_retriever, waveform_extraction], model=model) + _ = SingleChannelDenoiser(recording, parents=[peak_retriever, waveform_extraction], model=model) diff --git a/src/spikeinterface/sortingcomponents/waveforms/tests/test_savgol_denoiser.py b/src/spikeinterface/sortingcomponents/waveforms/tests/test_savgol_denoiser.py index 651b681078..fc2787a3d6 100644 --- a/src/spikeinterface/sortingcomponents/waveforms/tests/test_savgol_denoiser.py +++ b/src/spikeinterface/sortingcomponents/waveforms/tests/test_savgol_denoiser.py @@ -1,6 +1,3 @@ -import pytest - - from spikeinterface.sortingcomponents.waveforms.savgol_denoiser import SavGolDenoiser from spikeinterface.core.node_pipeline import ( diff --git a/src/spikeinterface/sortingcomponents/waveforms/tests/test_temporal_pca.py b/src/spikeinterface/sortingcomponents/waveforms/tests/test_temporal_pca.py index dc01ab3431..e3d99a5e1d 100644 --- a/src/spikeinterface/sortingcomponents/waveforms/tests/test_temporal_pca.py +++ b/src/spikeinterface/sortingcomponents/waveforms/tests/test_temporal_pca.py @@ -180,9 +180,6 @@ def test_initialization_with_wrong_parents_failure(generated_recording, model_pa recording = generated_recording model_folder_path = model_path_of_trained_pca dummy_parent = PipelineNode(recording) - extract_waveforms = ExtractSparseWaveforms( - recording=recording, ms_before=1, ms_after=1, radius_um=40, return_output=True - ) match_error = f"TemporalPCA should have a single {WaveformsNode.__name__} in its parents" diff --git a/src/spikeinterface/sortingcomponents/waveforms/waveform_thresholder.py b/src/spikeinterface/sortingcomponents/waveforms/waveform_thresholder.py index ec223d0047..b6fb38350b 100644 --- a/src/spikeinterface/sortingcomponents/waveforms/waveform_thresholder.py +++ b/src/spikeinterface/sortingcomponents/waveforms/waveform_thresholder.py @@ -59,7 +59,7 @@ def __init__( parents=parents, ) assert feature in ["ptp", "mean", "energy", "peak_voltage"], ( - f"{feature} is not a valid feature" " must be one of 'ptp', 'mean', 'energy'," " or 'peak_voltage'" + f"{feature} is not a valid feature must be one of 'ptp', 'mean', 'energy', or 'peak_voltage'" ) self.threshold = threshold diff --git a/src/spikeinterface/widgets/all_amplitudes_distributions.py b/src/spikeinterface/widgets/all_amplitudes_distributions.py index b3cf2cfc02..c4d3eb4b69 100644 --- a/src/spikeinterface/widgets/all_amplitudes_distributions.py +++ b/src/spikeinterface/widgets/all_amplitudes_distributions.py @@ -55,7 +55,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) diff --git a/src/spikeinterface/widgets/amplitudes.py b/src/spikeinterface/widgets/amplitudes.py index 1983253299..6091214a66 100644 --- a/src/spikeinterface/widgets/amplitudes.py +++ b/src/spikeinterface/widgets/amplitudes.py @@ -159,7 +159,6 @@ def plot_figpack(self, data_plot, **backend_kwargs): make_serializable, handle_display_and_url, import_figpack_or_sortingview, - generate_unit_table_view, ) use_sortingview = backend_kwargs.get("use_sortingview", False) diff --git a/src/spikeinterface/widgets/autocorrelograms.py b/src/spikeinterface/widgets/autocorrelograms.py index d83afeb259..1380d0119f 100644 --- a/src/spikeinterface/widgets/autocorrelograms.py +++ b/src/spikeinterface/widgets/autocorrelograms.py @@ -16,7 +16,6 @@ def __init__(self, *args, **kargs): ) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) @@ -46,7 +45,6 @@ def plot_figpack(self, data_plot, **backend_kwargs): make_serializable, handle_display_and_url, import_figpack_or_sortingview, - generate_unit_table_view, ) use_sortingview = backend_kwargs.get("use_sortingview", False) diff --git a/src/spikeinterface/widgets/base.py b/src/spikeinterface/widgets/base.py index 646e46a7a7..e6d75222e5 100644 --- a/src/spikeinterface/widgets/base.py +++ b/src/spikeinterface/widgets/base.py @@ -1,10 +1,11 @@ -global default_backend_ -default_backend_ = "matplotlib" - from spikeinterface.core import SortingAnalyzer, BaseSorting from spikeinterface.core.waveforms_extractor_backwards_compatibility import MockWaveformExtractor +global default_backend_ +default_backend_ = "matplotlib" + + def get_default_plotter_backend(): """Return the default backend for spikeinterface widgets. The default backend is "matplotlib" at init. @@ -105,7 +106,7 @@ def check_backend(self, backend): if backend is None: backend = get_default_plotter_backend() assert backend in self.get_possible_backends(), ( - f"{backend} backend not available! Available backends are: " f"{self.get_possible_backends()}" + f"{backend} backend not available! Available backends are: {self.get_possible_backends()}" ) return backend diff --git a/src/spikeinterface/widgets/bombcell_curation.py b/src/spikeinterface/widgets/bombcell_curation.py index 38b4e6c751..3f06b88684 100644 --- a/src/spikeinterface/widgets/bombcell_curation.py +++ b/src/spikeinterface/widgets/bombcell_curation.py @@ -85,7 +85,6 @@ def _get_metrics_for_unit_label(self, unit_label, thresholds): def plot_matplotlib(self, data_plot, **backend_kwargs): import matplotlib.pyplot as plt - import pandas as pd dp = to_attr(data_plot) metrics = dp.metrics @@ -239,8 +238,7 @@ def plot_bombcell_unit_labeling_all( dict Dictionary with keys 'histograms', 'waveforms', 'upset' containing widget objects. """ - from pathlib import Path - from spikeinterface.curation import bombcell_get_default_thresholds, save_bombcell_results + from spikeinterface.curation import bombcell_get_default_thresholds if thresholds is None: thresholds = bombcell_get_default_thresholds() diff --git a/src/spikeinterface/widgets/collision.py b/src/spikeinterface/widgets/collision.py index ce1f263cce..ad02f36b08 100644 --- a/src/spikeinterface/widgets/collision.py +++ b/src/spikeinterface/widgets/collision.py @@ -67,7 +67,6 @@ def __init__( def plot_matplotlib(self, data_plot, **backend_kwargs): import matplotlib.pyplot as plt - import sklearn import matplotlib from .utils_matplotlib import make_mpl_figure @@ -87,7 +86,6 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): template_inds = [all_unit_ids.index(u) for u in dp.unit_ids] templates_array = dp.templates_array[template_inds, :, :].copy() - flat_templates = templates_array.reshape(templates_array.shape[0], -1) similarity_matrix, _ = compute_similarity_with_templates_array( templates_array, @@ -107,8 +105,6 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): fs = comp.sorting1.get_sampling_frequency() lags = comp.bins / fs * 1000 - n = len(dp.unit_ids) - similarities, recall_scores, pair_names = comp.compute_collision_by_similarity( similarity_matrix, unit_ids=dp.unit_ids, good_only=dp.good_only, min_accuracy=dp.min_accuracy ) @@ -239,7 +235,6 @@ def __init__( def plot_matplotlib(self, data_plot, **backend_kwargs): import matplotlib.pyplot as plt - import sklearn import matplotlib from .utils_matplotlib import make_mpl_figure diff --git a/src/spikeinterface/widgets/comparison.py b/src/spikeinterface/widgets/comparison.py index d111124522..2784cd09a2 100644 --- a/src/spikeinterface/widgets/comparison.py +++ b/src/spikeinterface/widgets/comparison.py @@ -27,7 +27,6 @@ def __init__(self, gt_comparison, count_text=True, unit_ticks=True, backend=None BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) @@ -108,7 +107,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) diff --git a/src/spikeinterface/widgets/crosscorrelograms.py b/src/spikeinterface/widgets/crosscorrelograms.py index 438239ab88..ed818b7800 100644 --- a/src/spikeinterface/widgets/crosscorrelograms.py +++ b/src/spikeinterface/widgets/crosscorrelograms.py @@ -86,7 +86,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) @@ -131,7 +130,6 @@ def plot_figpack(self, data_plot, **backend_kwargs): make_serializable, handle_display_and_url, import_figpack_or_sortingview, - generate_unit_table_view, ) use_sortingview = backend_kwargs.get("use_sortingview", False) diff --git a/src/spikeinterface/widgets/drift_templates.py b/src/spikeinterface/widgets/drift_templates.py index dda0371e52..297c24d287 100644 --- a/src/spikeinterface/widgets/drift_templates.py +++ b/src/spikeinterface/widgets/drift_templates.py @@ -69,7 +69,7 @@ def plot_ipywidgets(self, data_plot, **backend_kwargs): max=arr.shape[0] - 1, readout=False, continuous_update=True, - layout=widgets.Layout(width=f"100%"), + layout=widgets.Layout(width="100%"), ) self.widget = widgets.AppLayout( diff --git a/src/spikeinterface/widgets/isi_distribution.py b/src/spikeinterface/widgets/isi_distribution.py index 65bda2341e..6e6c1e1cbd 100644 --- a/src/spikeinterface/widgets/isi_distribution.py +++ b/src/spikeinterface/widgets/isi_distribution.py @@ -1,5 +1,4 @@ import numpy as np -from warnings import warn from spikeinterface.core import SortingAnalyzer, BaseSorting @@ -48,7 +47,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) diff --git a/src/spikeinterface/widgets/metrics.py b/src/spikeinterface/widgets/metrics.py index 0631dc52c9..23317fdc4e 100644 --- a/src/spikeinterface/widgets/metrics.py +++ b/src/spikeinterface/widgets/metrics.py @@ -82,7 +82,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) @@ -376,9 +375,9 @@ def __init__( for category, subdict in thresholds.items(): assert isinstance(subdict, dict), "Each category in thresholds should be a dict of metric thresholds." for metric_name, thresh in subdict.items(): - assert isinstance(thresh, dict) and ( - "greater" in thresh or "less" in thresh - ), "Each threshold entry should be a dict with 'greater' and/or 'less' keys." + assert isinstance(thresh, dict) and ("greater" in thresh or "less" in thresh), ( + "Each threshold entry should be a dict with 'greater' and/or 'less' keys." + ) flat_thresholds[metric_name] = thresh if metrics_to_plot is None: diff --git a/src/spikeinterface/widgets/motion.py b/src/spikeinterface/widgets/motion.py index a08c4b789a..4ac8c9b030 100644 --- a/src/spikeinterface/widgets/motion.py +++ b/src/spikeinterface/widgets/motion.py @@ -180,9 +180,9 @@ def __init__( recording = None sampling_frequency = sorting_analyzer.sampling_frequency peaks = sorting_analyzer.sorting.to_spike_vector() - assert sorting_analyzer.has_extension( - "spike_locations" - ), "The sorting analyzer must have the 'spike_locations' extension to use this function" + assert sorting_analyzer.has_extension("spike_locations"), ( + "The sorting analyzer must have the 'spike_locations' extension to use this function" + ) peak_locations = sorting_analyzer.get_extension("spike_locations").get_data() if color_amplitude: assert sorting_analyzer.has_extension("spike_amplitudes"), ( @@ -348,9 +348,9 @@ def __init__( raise ValueError( "plot drift map : the Motion object is multi-segment you must provide segment_index=XX" ) - assert recording.get_num_segments() == len( - motion.displacement - ), "The number of segments in the recording must be the same as the number of segments in the motion object" + assert recording.get_num_segments() == len(motion.displacement), ( + "The number of segments in the recording must be the same as the number of segments in the motion object" + ) plot_data = dict( sampling_frequency=motion_info["parameters"]["sampling_frequency"], diff --git a/src/spikeinterface/widgets/multicomparison.py b/src/spikeinterface/widgets/multicomparison.py index 38d1b28e54..b0878914f7 100644 --- a/src/spikeinterface/widgets/multicomparison.py +++ b/src/spikeinterface/widgets/multicomparison.py @@ -1,8 +1,6 @@ import numpy as np -from warnings import warn from .base import BaseWidget, to_attr -from .utils import get_unit_colors class MultiCompGraphWidget(BaseWidget): @@ -228,7 +226,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.colors as mpl_colors import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure diff --git a/src/spikeinterface/widgets/peak_activity.py b/src/spikeinterface/widgets/peak_activity.py index f7582b4042..117df2073a 100644 --- a/src/spikeinterface/widgets/peak_activity.py +++ b/src/spikeinterface/widgets/peak_activity.py @@ -204,6 +204,6 @@ def _plot_one_bin( artists = artists + (im,) if with_color_bar: - self.cbar = self.figure.colorbar(im, ax=self.ax, label=f"Peak rate (Hz)") + self.cbar = self.figure.colorbar(im, ax=self.ax, label="Peak rate (Hz)") return artists diff --git a/src/spikeinterface/widgets/peaks_on_probe.py b/src/spikeinterface/widgets/peaks_on_probe.py index ea707c30ed..8f19b4a7eb 100644 --- a/src/spikeinterface/widgets/peaks_on_probe.py +++ b/src/spikeinterface/widgets/peaks_on_probe.py @@ -79,12 +79,10 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): dp.peaks, dp.peak_locations, ) - fs = dp.recording.get_sampling_frequency() num_plots = len(peaks) # Set the maximum time to the end time of the longest segment if dp.time_range is None: - time_range = self._get_min_and_max_times_in_recording(dp.recording) else: time_range = dp.time_range @@ -98,7 +96,6 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): # Plot each passed peaks / peak_locations over the probe on a separate subplot for ax_idx, (peaks_to_plot, peak_locs_to_plot) in enumerate(zip(peaks, peak_locations)): - ax = self.axes[ax_idx] plot_probe_map(dp.recording, ax=ax) @@ -138,7 +135,7 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): ax.set_ylim(ylim[0], ylim[1]) - self.figure.suptitle(f"Peaks on Probe Plot") + self.figure.suptitle("Peaks on Probe Plot") def _get_peaks_time_mask(self, recording, time_range, peaks_to_plot): """ @@ -152,7 +149,6 @@ def _get_peaks_time_mask(self, recording, time_range, peaks_to_plot): time_mask = np.zeros(peaks_to_plot.size, dtype=bool) for seg_idx in range(recording.get_num_segments()): - segment = recording.select_segments(seg_idx) t_start_sample = segment.time_to_sample_index(time_range[0]) @@ -175,7 +171,6 @@ def _get_min_and_max_times_in_recording(self, recording): t_starts = [] t_stops = [] for seg_idx in range(recording.get_num_segments()): - segment = recording.select_segments(seg_idx) t_starts.append(segment.sample_index_to_time(0)) diff --git a/src/spikeinterface/widgets/potential_merges.py b/src/spikeinterface/widgets/potential_merges.py index 370efa57eb..ce4e23e2f7 100644 --- a/src/spikeinterface/widgets/potential_merges.py +++ b/src/spikeinterface/widgets/potential_merges.py @@ -1,5 +1,4 @@ import numpy as np -from warnings import warn from .base import BaseWidget, default_backend_kwargs diff --git a/src/spikeinterface/widgets/probe_map.py b/src/spikeinterface/widgets/probe_map.py index 53f18af814..afc6224756 100644 --- a/src/spikeinterface/widgets/probe_map.py +++ b/src/spikeinterface/widgets/probe_map.py @@ -41,7 +41,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure from probeinterface.plotting import get_auto_lims, plot_probe diff --git a/src/spikeinterface/widgets/rasters.py b/src/spikeinterface/widgets/rasters.py index e302674845..eda75cef9e 100644 --- a/src/spikeinterface/widgets/rasters.py +++ b/src/spikeinterface/widgets/rasters.py @@ -1,10 +1,9 @@ import numpy as np -from warnings import warn from spikeinterface.core import SortingAnalyzer, BaseSorting from spikeinterface.core.sorting_tools import get_segment_durations -from .base import BaseWidget, to_attr, default_backend_kwargs +from .base import BaseWidget, to_attr from .utils import ( get_some_colors, validate_segment_indices, @@ -185,8 +184,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt - from matplotlib.colors import Normalize from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) @@ -267,10 +264,8 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): # Add segment boundary lines if provided and handle x limits if dp.segment_start_stop_times is not None: - segment_times = np.array(list(dp.segment_start_stop_times.values())) if len(segment_times) > 1: - segment_times = segment_times - dp.segment_time_offsets[:, None] self._set_segment_time_ticks(scatter_ax, segment_times, dp.segment_time_offsets) @@ -471,7 +466,7 @@ def __init__( if isinstance(sorting_analyzer_or_sorting, SortingAnalyzer): if not sorting_analyzer_or_sorting.has_extension("unit_locations"): if sort_by_depth: - raise AttributeError(f"'unit_locations' necessary for `sort_by_depth=True`") + raise AttributeError("'unit_locations' necessary for `sort_by_depth=True`") else: depths = sorting_analyzer_or_sorting.get_extension("unit_locations").get_data(outputs="numpy") s_args_depths = np.argsort(depths[:, 1]) diff --git a/src/spikeinterface/widgets/spike_locations.py b/src/spikeinterface/widgets/spike_locations.py index f589d86896..af2956522c 100644 --- a/src/spikeinterface/widgets/spike_locations.py +++ b/src/spikeinterface/widgets/spike_locations.py @@ -106,7 +106,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure from matplotlib.lines import Line2D diff --git a/src/spikeinterface/widgets/spike_locations_by_time.py b/src/spikeinterface/widgets/spike_locations_by_time.py index 5b35888852..c1f3b7d277 100644 --- a/src/spikeinterface/widgets/spike_locations_by_time.py +++ b/src/spikeinterface/widgets/spike_locations_by_time.py @@ -114,7 +114,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) @@ -167,7 +166,7 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): scatter_ax.set_xlim(0, dp.total_duration) scatter_ax.set_xlabel("Times [s]") - scatter_ax.set_ylabel(f"Location [um]") + scatter_ax.set_ylabel("Location [um]") scatter_ax.spines["top"].set_visible(False) scatter_ax.spines["right"].set_visible(False) self.figure.subplots_adjust(bottom=0.1, top=0.9, left=0.1) diff --git a/src/spikeinterface/widgets/spikes_on_traces.py b/src/spikeinterface/widgets/spikes_on_traces.py index b28fe25e9d..86e1a26faf 100644 --- a/src/spikeinterface/widgets/spikes_on_traces.py +++ b/src/spikeinterface/widgets/spikes_on_traces.py @@ -1,5 +1,3 @@ -import warnings - import numpy as np from .base import BaseWidget, to_attr @@ -147,8 +145,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt - from .utils_matplotlib import make_mpl_figure from matplotlib.patches import Ellipse from matplotlib.lines import Line2D @@ -237,7 +233,6 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): label_set = True def plot_ipywidgets(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt import ipywidgets.widgets as widgets from IPython.display import display from .utils_ipywidgets import check_ipywidget_backend, UnitSelector @@ -254,8 +249,6 @@ def plot_ipywidgets(self, data_plot, **backend_kwargs): backend_kwargs_ts = backend_kwargs.copy() backend_kwargs_ts["width_cm"] = ratios[1] * backend_kwargs_ts["width_cm"] backend_kwargs_ts["display"] = False - height_cm = backend_kwargs["height_cm"] - width_cm = backend_kwargs["width_cm"] # plot timeseries self._traces_widget = TracesWidget( diff --git a/src/spikeinterface/widgets/template_similarity.py b/src/spikeinterface/widgets/template_similarity.py index 749afe0334..a9283d40b3 100644 --- a/src/spikeinterface/widgets/template_similarity.py +++ b/src/spikeinterface/widgets/template_similarity.py @@ -63,7 +63,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) diff --git a/src/spikeinterface/widgets/tests/test_widgets.py b/src/spikeinterface/widgets/tests/test_widgets.py index 8ece826de9..fcac517d46 100644 --- a/src/spikeinterface/widgets/tests/test_widgets.py +++ b/src/spikeinterface/widgets/tests/test_widgets.py @@ -37,7 +37,6 @@ class TestWidgets(unittest.TestCase): - @classmethod def setUpClass(cls): @@ -759,7 +758,6 @@ def test_plot_bombcell_labels_upset(self): if __name__ == "__main__": # unittest.main() - import matplotlib.pyplot as plt TestWidgets.setUpClass() mytest = TestWidgets() diff --git a/src/spikeinterface/widgets/tests/test_widgets_utils.py b/src/spikeinterface/widgets/tests/test_widgets_utils.py index c1905f3ac8..144fae8de9 100644 --- a/src/spikeinterface/widgets/tests/test_widgets_utils.py +++ b/src/spikeinterface/widgets/tests/test_widgets_utils.py @@ -5,24 +5,23 @@ get_some_colors, validate_segment_indices, ) -import numpy as np def test_get_some_colors(): keys = ["a", "b", "c", "d"] - colors = get_some_colors(keys, color_engine="auto") + _ = get_some_colors(keys, color_engine="auto") # print(colors) - colors = get_some_colors(keys, color_engine="distinctipy") + _ = get_some_colors(keys, color_engine="distinctipy") # print(colors) - colors = get_some_colors(keys, color_engine="matplotlib", shuffle=None) + _ = get_some_colors(keys, color_engine="matplotlib", shuffle=None) # print(colors) - colors = get_some_colors(keys, color_engine="matplotlib", shuffle=False) - colors = get_some_colors(keys, color_engine="matplotlib", shuffle=True) + _ = get_some_colors(keys, color_engine="matplotlib", shuffle=False) + _ = get_some_colors(keys, color_engine="matplotlib", shuffle=True) - colors = get_some_colors(keys, color_engine="colorsys") + _ = get_some_colors(keys, color_engine="colorsys") # print(colors) diff --git a/src/spikeinterface/widgets/traces.py b/src/spikeinterface/widgets/traces.py index 62f221b6ca..8106e7e1d3 100644 --- a/src/spikeinterface/widgets/traces.py +++ b/src/spikeinterface/widgets/traces.py @@ -141,7 +141,7 @@ def __init__( time_range = np.array(time_range, dtype=np.float64) if time_range[1] > t_end: warnings.warn( - "You have selected a time after the end of the segment. The range will be clipped to " f"{t_end}" + f"You have selected a time after the end of the segment. The range will be clipped to {t_end}" ) time_range[1] = t_end @@ -209,9 +209,9 @@ def __init__( if isinstance(clim, tuple): clims = {layer_key: clim for layer_key in layer_keys} elif isinstance(clim, dict): - assert all( - layer_key in clim for layer_key in layer_keys - ), f"all recordings must be a key in `clim` if `clim` is a dict. Provide keys {layer_keys} in clim" + assert all(layer_key in clim for layer_key in layer_keys), ( + f"all recordings must be a key in `clim` if `clim` is a dict. Provide keys {layer_keys} in clim" + ) clims = clim else: raise TypeError(f"'clim' can be None, tuple, or dict! Unsupported type {type(clim)}") @@ -220,9 +220,9 @@ def __init__( if events is not None: num_segments = rec0.get_num_segments() if num_segments > 1: - assert ( - len(events) == num_segments - ), f"events must be a list with the events for each of the {num_segments} segments" + assert len(events) == num_segments, ( + f"events must be a list with the events for each of the {num_segments} segments" + ) evensts_w_dtype = events else: if isinstance(events, np.ndarray): @@ -272,7 +272,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from matplotlib.ticker import MaxNLocator from .utils_matplotlib import make_mpl_figure @@ -283,7 +282,7 @@ def plot_matplotlib(self, data_plot, **backend_kwargs): if self.cb is not None: try: self.cb.remove() - except: + except Exception: pass ax = self.ax @@ -618,7 +617,7 @@ def plot_figpack(self, data_plot, **backend_kwargs): if not dp.order_channel_by_depth: warnings.warn( - "It is recommended to set 'order_channel_by_depth' to True " "when using the sortingview backend" + "It is recommended to set 'order_channel_by_depth' to True when using the sortingview backend" ) tiled_layers = [] @@ -673,9 +672,9 @@ def _get_trace_list(recordings, channel_ids, segment_index, time_range=None, ret rec0 = recordings[k0] if return_in_uV: - assert all( - rec.has_scaleable_traces() for rec in recordings.values() - ), "Some recording layers do not have scaled traces. Use `return_in_uV=False`" + assert all(rec.has_scaleable_traces() for rec in recordings.values()), ( + "Some recording layers do not have scaled traces. Use `return_in_uV=False`" + ) assert time_range is not None or frame_range is not None, "You must provide either time_range or frame_range" diff --git a/src/spikeinterface/widgets/unit_depths.py b/src/spikeinterface/widgets/unit_depths.py index 6f6b24cc07..cd113cfca6 100644 --- a/src/spikeinterface/widgets/unit_depths.py +++ b/src/spikeinterface/widgets/unit_depths.py @@ -54,7 +54,6 @@ def __init__(self, sorting_analyzer, unit_colors=None, depth_axis=1, backend=Non BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) diff --git a/src/spikeinterface/widgets/unit_labels.py b/src/spikeinterface/widgets/unit_labels.py index 348f0e3b8d..40a028ca8c 100644 --- a/src/spikeinterface/widgets/unit_labels.py +++ b/src/spikeinterface/widgets/unit_labels.py @@ -2,7 +2,6 @@ import numpy as np -from spikeinterface.curation.curation_tools import is_threshold_disabled from .base import BaseWidget, to_attr @@ -38,9 +37,9 @@ def __init__( self.check_extensions(sorting_analyzer, "templates") if labels_order is not None: assert len(labels_order) == len(np.unique(unit_labels)), "labels_order length must match unique unit types" - assert all( - [label in np.unique(unit_labels) for label in labels_order] - ), "All labels in labels_order must be present in unit_labels" + assert all([label in np.unique(unit_labels) for label in labels_order]), ( + "All labels in labels_order must be present in unit_labels" + ) else: labels_order = np.unique(unit_labels) plot_data = dict( diff --git a/src/spikeinterface/widgets/unit_locations.py b/src/spikeinterface/widgets/unit_locations.py index 7d88a523d4..4785f36251 100644 --- a/src/spikeinterface/widgets/unit_locations.py +++ b/src/spikeinterface/widgets/unit_locations.py @@ -109,7 +109,6 @@ def __init__( BaseWidget.__init__(self, data_plot, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure from probeinterface.plotting import plot_probe diff --git a/src/spikeinterface/widgets/unit_presence.py b/src/spikeinterface/widgets/unit_presence.py index 72a9603544..0baf14914d 100644 --- a/src/spikeinterface/widgets/unit_presence.py +++ b/src/spikeinterface/widgets/unit_presence.py @@ -1,5 +1,4 @@ import numpy as np -from warnings import warn from spikeinterface.core import SortingAnalyzer, BaseSorting from .base import BaseWidget, to_attr @@ -55,7 +54,6 @@ def __init__( BaseWidget.__init__(self, data_plot, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) diff --git a/src/spikeinterface/widgets/unit_probe_map.py b/src/spikeinterface/widgets/unit_probe_map.py index 944331ad92..eb6a219295 100644 --- a/src/spikeinterface/widgets/unit_probe_map.py +++ b/src/spikeinterface/widgets/unit_probe_map.py @@ -59,7 +59,6 @@ def __init__( BaseWidget.__init__(self, data_plot, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure from probeinterface.plotting import plot_probe diff --git a/src/spikeinterface/widgets/unit_summary.py b/src/spikeinterface/widgets/unit_summary.py index 821260eba7..e0ac78d66b 100644 --- a/src/spikeinterface/widgets/unit_summary.py +++ b/src/spikeinterface/widgets/unit_summary.py @@ -80,7 +80,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) diff --git a/src/spikeinterface/widgets/unit_valid_periods.py b/src/spikeinterface/widgets/unit_valid_periods.py index 7c54e93fdc..5835497174 100644 --- a/src/spikeinterface/widgets/unit_valid_periods.py +++ b/src/spikeinterface/widgets/unit_valid_periods.py @@ -59,7 +59,6 @@ def __init__( BaseWidget.__init__(self, data_plot, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) diff --git a/src/spikeinterface/widgets/unit_waveforms.py b/src/spikeinterface/widgets/unit_waveforms.py index 5f9da5dc97..cfdd27b93e 100644 --- a/src/spikeinterface/widgets/unit_waveforms.py +++ b/src/spikeinterface/widgets/unit_waveforms.py @@ -6,7 +6,6 @@ from .utils import get_unit_colors from spikeinterface.core import ChannelSparsity, SortingAnalyzer, Templates -from spikeinterface.core.basesorting import BaseSorting class UnitWaveformsWidget(BaseWidget): @@ -236,7 +235,6 @@ def __init__( BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs) def plot_matplotlib(self, data_plot, **backend_kwargs): - import matplotlib.pyplot as plt from .utils_matplotlib import make_mpl_figure dp = to_attr(data_plot) @@ -548,12 +546,12 @@ def _get_template_shadings(self, unit_ids, templates_percentile_shading): if isinstance(templates_percentile_shading, (int, float)): templates_percentile_shading = [templates_percentile_shading, 100 - templates_percentile_shading] else: - assert isinstance( - templates_percentile_shading, (list, tuple) - ), "'templates_percentile_shading' should be a float, a list/tuple of floats, or None!" - assert ( - np.mod(len(templates_percentile_shading), 2) == 0 - ), "'templates_percentile_shading' should be a have an even number of elements." + assert isinstance(templates_percentile_shading, (list, tuple)), ( + "'templates_percentile_shading' should be a float, a list/tuple of floats, or None!" + ) + assert np.mod(len(templates_percentile_shading), 2) == 0, ( + "'templates_percentile_shading' should be a have an even number of elements." + ) templates_shading = [] for percentile in templates_percentile_shading: template_percentile = self.templates_ext.get_templates( diff --git a/src/spikeinterface/widgets/utils.py b/src/spikeinterface/widgets/utils.py index 82c35dafc0..824579179c 100644 --- a/src/spikeinterface/widgets/utils.py +++ b/src/spikeinterface/widgets/utils.py @@ -226,8 +226,8 @@ def array_to_image( font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMono.ttf", fontsize) else: font = ImageFont.truetype("arial.ttf", fontsize) - except: - print(f"Could not load font to use in scalebar. Scalebar will not be drawn.") + except Exception: + print("Could not load font to use in scalebar. Scalebar will not be drawn.") font = None if font is not None: diff --git a/src/spikeinterface/widgets/utils_ipywidgets.py b/src/spikeinterface/widgets/utils_ipywidgets.py index 25c67d36bd..7da6bec865 100644 --- a/src/spikeinterface/widgets/utils_ipywidgets.py +++ b/src/spikeinterface/widgets/utils_ipywidgets.py @@ -8,9 +8,9 @@ def check_ipywidget_backend(): import matplotlib mpl_backend = matplotlib.get_backend() - assert ( - "ipympl" in mpl_backend or "widget" in mpl_backend - ), "To use the 'ipywidgets' backend, you have to set %matplotlib widget" + assert "ipympl" in mpl_backend or "widget" in mpl_backend, ( + "To use the 'ipywidgets' backend, you have to set %matplotlib widget" + ) class TimeSlider(W.HBox): @@ -80,7 +80,7 @@ def __init__(self, durations, sampling_frequency, frame_range, rec0=None, t_star max=self.frame_limits[self.segment_index] - 1, readout=False, continuous_update=False, - layout=W.Layout(width=f"70%"), + layout=W.Layout(width="70%"), ) self.slider.observe(self.slider_moved, names="value", type="change") @@ -184,7 +184,7 @@ def update_time(self, new_frame=None, new_time=None, update_slider=False, update def time_label_changed(self, change=None): try: new_time = float(self.time_label.value) - except: + except Exception: new_time = None if new_time is not None: self.update_time(new_time=new_time, update_slider=True) diff --git a/src/spikeinterface/widgets/widget_list.py b/src/spikeinterface/widgets/widget_list.py index 6cd6bbfd23..988019fbac 100644 --- a/src/spikeinterface/widgets/widget_list.py +++ b/src/spikeinterface/widgets/widget_list.py @@ -38,7 +38,7 @@ from .collision import ComparisonCollisionBySimilarityWidget, StudyComparisonCollisionBySimilarityWidget from .unit_labels import WaveformOverlayByLabelWidget from .unit_valid_periods import ValidUnitPeriodsWidget -from .bombcell_curation import BombcellUpsetPlotWidget, plot_bombcell_unit_labeling_all +from .bombcell_curation import BombcellUpsetPlotWidget widget_list = [ AgreementMatrixWidget,