Skip to content

Commit 340454b

Browse files
authored
Merge branch 'main' into add_distance_function
2 parents 89cbc66 + 298e57a commit 340454b

655 files changed

Lines changed: 60728 additions & 28583 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/actions/build-test-environment/action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ runs:
2121
python -m pip install -U pip # Official recommended way
2222
source ${{ github.workspace }}/test_env/bin/activate
2323
pip install tabulate # This produces summaries at the end
24-
pip install -e .[test,extractors,full]
24+
pip install -e .[test,extractors,streaming_extractors,test_extractors,full]
2525
shell: bash
2626
- name: Force installation of latest dev from key-packages when running dev (not release)
2727
run: |
2828
source ${{ github.workspace }}/test_env/bin/activate
29-
spikeinterface_is_dev_version=$(python -c "import importlib.metadata; version = importlib.metadata.version('spikeinterface'); print(version.endswith('dev0'))")
29+
spikeinterface_is_dev_version=$(python -c "import spikeinterface; print(spikeinterface.DEV_MODE)")
3030
if [ $spikeinterface_is_dev_version = "True" ]; then
3131
echo "Running spikeinterface dev version"
3232
pip install --no-cache-dir git+https://github.com/NeuralEnsemble/python-neo

.github/actions/install-wine/action.yml

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,29 @@ name: Install packages
22
description: This action installs the package and its dependencies for testing
33

44
inputs:
5-
python-version:
6-
description: 'Python version to set up'
7-
required: false
85
os:
96
description: 'Operating system to set up'
10-
required: false
7+
required: true
118

129
runs:
1310
using: "composite"
1411
steps:
15-
- name: Install wine (needed for Plexon2)
12+
- name: Install wine on Linux
13+
if: runner.os == 'Linux'
1614
run: |
1715
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
1816
sudo dpkg --add-architecture i386
1917
sudo apt-get update -qq
2018
sudo apt-get install -yqq --allow-downgrades libc6:i386 libgcc-s1:i386 libstdc++6:i386 wine
2119
shell: bash
20+
- name: Install wine on macOS
21+
if: runner.os == 'macOS'
22+
run: |
23+
brew install --cask xquartz
24+
brew install --cask wine-stable
25+
shell: bash
26+
27+
- name: Skip installation on Windows
28+
if: ${{ inputs.os == 'Windows' }}
29+
run: echo "Skipping Wine installation on Windows. Not necessary."
30+
shell: bash

.github/actions/show-test-environment/action.yml

Lines changed: 0 additions & 23 deletions
This file was deleted.

.github/import_test.py

Lines changed: 0 additions & 57 deletions
This file was deleted.

.github/run_tests.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
#!/bin/bash
22

33
MARKER=$1
4+
NOVIRTUALENV=$2
5+
6+
# Check if the second argument is provided and if it is equal to --no-virtual-env
7+
if [ -z "$NOVIRTUALENV" ] || [ "$NOVIRTUALENV" != "--no-virtual-env" ]; then
8+
source $GITHUB_WORKSPACE/test_env/bin/activate
9+
fi
410

5-
source $GITHUB_WORKSPACE/test_env/bin/activate
611
pytest -m "$MARKER" -vv -ra --durations=0 --durations-min=0.001 | tee report.txt; test ${PIPESTATUS[0]} -eq 0 || exit 1
712
echo "# Timing profile of ${MARKER}" >> $GITHUB_STEP_SUMMARY
8-
python $GITHUB_WORKSPACE/.github/build_job_summary.py report.txt >> $GITHUB_STEP_SUMMARY
13+
python $GITHUB_WORKSPACE/.github/scripts/build_job_summary.py report.txt >> $GITHUB_STEP_SUMMARY
914
rm report.txt

.github/scripts/README.MD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This folder contains test scripts for running in the CI, that are not run as part of the usual
2+
CI because they are too long / heavy. These are run on cron-jobs once per week.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
import re
3+
from pathlib import Path
4+
import requests
5+
import json
6+
from packaging.version import parse
7+
import spikeinterface
8+
9+
def get_pypi_versions(package_name):
10+
"""
11+
Make an API call to pypi to retrieve all
12+
available versions of the kilosort package.
13+
"""
14+
url = f"https://pypi.org/pypi/{package_name}/json"
15+
response = requests.get(url)
16+
response.raise_for_status()
17+
data = response.json()
18+
versions = list(sorted(data["releases"].keys()))
19+
# Filter out versions that are less than 4.0.16
20+
versions = [ver for ver in versions if parse(ver) >= parse("4.0.16")]
21+
return versions
22+
23+
24+
if __name__ == "__main__":
25+
# Get all KS4 versions from pipi and write to file.
26+
package_name = "kilosort"
27+
versions = get_pypi_versions(package_name)
28+
with open(Path(os.path.realpath(__file__)).parent / "kilosort4-latest-version.json", "w") as f:
29+
print(versions)
30+
json.dump(versions, f)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
from pathlib import Path
2+
import argparse
3+
import os
4+
5+
6+
# We get the list of files change as an input
7+
parser = argparse.ArgumentParser()
8+
parser.add_argument("changed_files_in_the_pull_request", nargs="*", help="List of changed files")
9+
args = parser.parse_args()
10+
11+
changed_files_in_the_pull_request = args.changed_files_in_the_pull_request
12+
changed_files_in_the_pull_request_paths = [Path(file) for file in changed_files_in_the_pull_request]
13+
14+
# We assume nothing has been changed
15+
16+
core_changed = False
17+
pyproject_toml_changed = False
18+
neobaseextractor_changed = False
19+
extractors_changed = False
20+
plexon2_changed = False
21+
preprocessing_changed = False
22+
postprocessing_changed = False
23+
qualitymetrics_changed = False
24+
sorters_changed = False
25+
sorters_external_changed = False
26+
sorters_internal_changed = False
27+
comparison_changed = False
28+
curation_changed = False
29+
widgets_changed = False
30+
exporters_changed = False
31+
sortingcomponents_changed = False
32+
generation_changed = False
33+
stream_extractors_changed = False
34+
github_actions_changed = False
35+
36+
37+
for changed_file in changed_files_in_the_pull_request_paths:
38+
39+
file_is_in_src = changed_file.parts[0] == "src"
40+
41+
if changed_file.name == "pyproject.toml":
42+
pyproject_toml_changed = True
43+
elif changed_file.name == "neobaseextractor.py":
44+
neobaseextractor_changed = True
45+
extractors_changed = True
46+
elif changed_file.name == "plexon2.py":
47+
plexon2_changed = True
48+
elif changed_file.name == "nwbextractors.py":
49+
extractors_changed = True # There are NWB tests that are not streaming
50+
stream_extractors_changed = True
51+
elif changed_file.name == "iblextractors.py":
52+
stream_extractors_changed = True
53+
elif "core" in changed_file.parts:
54+
core_changed = True
55+
elif "extractors" in changed_file.parts:
56+
extractors_changed = True
57+
elif "preprocessing" in changed_file.parts:
58+
preprocessing_changed = True
59+
elif "postprocessing" in changed_file.parts:
60+
postprocessing_changed = True
61+
elif "qualitymetrics" in changed_file.parts:
62+
qualitymetrics_changed = True
63+
elif "comparison" in changed_file.parts:
64+
comparison_changed = True
65+
elif "curation" in changed_file.parts:
66+
curation_changed = True
67+
elif "widgets" in changed_file.parts:
68+
widgets_changed = True
69+
elif "exporters" in changed_file.parts:
70+
exporters_changed = True
71+
elif "sortingcomponents" in changed_file.parts:
72+
sortingcomponents_changed = True
73+
elif "generation" in changed_file.parts:
74+
generation_changed = True
75+
elif "sorters" in changed_file.parts:
76+
if "external" in changed_file.parts:
77+
sorters_external_changed = True
78+
elif "internal" in changed_file.parts:
79+
sorters_internal_changed = True
80+
else:
81+
sorters_changed = True
82+
elif ".github" in changed_file.parts:
83+
if "workflows" in changed_file.parts:
84+
github_actions_changed = True
85+
86+
87+
run_everything = core_changed or pyproject_toml_changed or neobaseextractor_changed or github_actions_changed
88+
run_generation_tests = run_everything or generation_changed
89+
run_extractor_tests = run_everything or extractors_changed or plexon2_changed
90+
run_preprocessing_tests = run_everything or preprocessing_changed
91+
run_postprocessing_tests = run_everything or postprocessing_changed
92+
run_qualitymetrics_tests = run_everything or qualitymetrics_changed
93+
run_curation_tests = run_everything or curation_changed
94+
run_sortingcomponents_tests = run_everything or sortingcomponents_changed
95+
96+
run_comparison_test = run_everything or run_generation_tests or comparison_changed
97+
run_widgets_test = run_everything or run_qualitymetrics_tests or run_preprocessing_tests or widgets_changed
98+
run_exporters_test = run_everything or run_widgets_test or exporters_changed
99+
100+
run_sorters_test = run_everything or sorters_changed
101+
run_internal_sorters_test = run_everything or run_sortingcomponents_tests or sorters_internal_changed
102+
103+
run_streaming_extractors_test = stream_extractors_changed or github_actions_changed
104+
105+
install_plexon_dependencies = plexon2_changed
106+
107+
108+
environment_varaiables_to_add = {
109+
"RUN_EXTRACTORS_TESTS": run_extractor_tests,
110+
"RUN_PREPROCESSING_TESTS": run_preprocessing_tests,
111+
"RUN_POSTPROCESSING_TESTS": run_postprocessing_tests,
112+
"RUN_QUALITYMETRICS_TESTS": run_qualitymetrics_tests,
113+
"RUN_CURATION_TESTS": run_curation_tests,
114+
"RUN_SORTINGCOMPONENTS_TESTS": run_sortingcomponents_tests,
115+
"RUN_GENERATION_TESTS": run_generation_tests,
116+
"RUN_COMPARISON_TESTS": run_comparison_test,
117+
"RUN_WIDGETS_TESTS": run_widgets_test,
118+
"RUN_EXPORTERS_TESTS": run_exporters_test,
119+
"RUN_SORTERS_TESTS": run_sorters_test,
120+
"RUN_INTERNAL_SORTERS_TESTS": run_internal_sorters_test,
121+
"INSTALL_PLEXON_DEPENDENCIES": install_plexon_dependencies,
122+
"RUN_STREAMING_EXTRACTORS_TESTS": run_streaming_extractors_test,
123+
}
124+
125+
# Write the conditions to the GITHUB_ENV file
126+
env_file = os.getenv("GITHUB_ENV")
127+
with open(env_file, "a") as f:
128+
for key, value in environment_varaiables_to_add.items():
129+
f.write(f"{key}={value}\n")

.github/scripts/import_test.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import subprocess
2+
import math
3+
4+
import_statement_list = [
5+
"import spikeinterface",
6+
"import spikeinterface.core",
7+
"import spikeinterface.extractors",
8+
"import spikeinterface.qualitymetrics",
9+
"import spikeinterface.preprocessing",
10+
"import spikeinterface.comparison",
11+
"import spikeinterface.postprocessing",
12+
"import spikeinterface.sortingcomponents",
13+
"import spikeinterface.curation",
14+
"import spikeinterface.exporters",
15+
"import spikeinterface.widgets",
16+
"import spikeinterface.full",
17+
]
18+
19+
n_samples = 10
20+
# Note that the symbols at the end are for centering the table
21+
markdown_output = f"## \n\n| Imported Module ({n_samples=}) | Importing Time (seconds) | Standard Deviation (seconds) | Times List (seconds) |\n| :--: | :--------------: | :------------------: | :-------------: |\n"
22+
23+
exceptions = []
24+
25+
for import_statement in import_statement_list:
26+
time_taken_list = []
27+
for _ in range(n_samples):
28+
script_to_execute = (
29+
f"import timeit \n"
30+
f"import_statement = '{import_statement}' \n"
31+
f"time_taken = timeit.timeit(import_statement, number=1) \n"
32+
f"print(time_taken) \n"
33+
)
34+
35+
result = subprocess.run(["python", "-c", script_to_execute], capture_output=True, text=True)
36+
37+
if result.returncode != 0:
38+
error_message = (
39+
f"Error when running {import_statement} \n" f"Error in subprocess: {result.stderr.strip()}\n"
40+
)
41+
exceptions.append(error_message)
42+
break
43+
44+
time_taken = float(result.stdout.strip())
45+
time_taken_list.append(time_taken)
46+
47+
for time in time_taken_list:
48+
import_time_threshold = 3.0 # Most of the times is sub-second but there outliers
49+
if time >= import_time_threshold:
50+
exceptions.append(
51+
f"Importing {import_statement} took: {time:.2f} s. Should be <: {import_time_threshold} s."
52+
)
53+
break
54+
55+
56+
if time_taken_list:
57+
avg_time = sum(time_taken_list) / len(time_taken_list)
58+
std_time = math.sqrt(sum((x - avg_time) ** 2 for x in time_taken_list) / len(time_taken_list))
59+
times_list_str = ", ".join(f"{time:.2f}" for time in time_taken_list)
60+
markdown_output += f"| `{import_statement}` | {avg_time:.2f} | {std_time:.2f} | {times_list_str} |\n"
61+
62+
import_time_threshold = 2.0
63+
if avg_time > import_time_threshold:
64+
exceptions.append(
65+
f"Importing {import_statement} took: {avg_time:.2f} s in average. Should be <: {import_time_threshold} s."
66+
)
67+
68+
if exceptions:
69+
raise Exception("\n".join(exceptions))
70+
71+
# This is displayed to GITHUB_STEP_SUMMARY
72+
print(markdown_output)

0 commit comments

Comments
 (0)