Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
3 changes: 1 addition & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
include LICENSE
include LICENSE.md
include README.md

recursive-include tests *
recursive-include phylib/electrode/probes *.prb
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ clean-pyc:
clean: clean-build clean-pyc

lint:
flake8 phylib
uv run flake8 --jobs=1 phylib

test: lint
py.test --cov-report term-missing --cov=phylib phylib
uv run pytest --cov-report term-missing --cov=phylib phylib

coverage:
coverage --html
uv run coverage html

apidoc:
python tools/api.py
uv run python tools/api.py

build:
python setup.py sdist --formats=zip
uv build

upload:
python setup.py sdist --formats=zip upload
@echo "Build artifacts with 'uv build' and upload them with twine."
23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
Electrophysiological data analysis library used by [phy](https://github.com/kwikteam/phy/), a spike sorting visualization software, and [ibllib](https://github.com/int-brain-lab/ibllib/).


## Contribution

- run all tests using pytest `pytest phylib`
- PR to main
- update `CHANGELOG.md` and version in `phylib\__init__.py`
- publish to pypi:
```shell
rm -R dist
rm -R build
python setup.py sdist bdist_wheel
twine upload dist/*
```
## Contribution

- create a local environment with `uv venv --python 3.12` and `uv sync --extra dev`
- run all tests using `uv run pytest phylib`
- PR to main
- update `CHANGELOG.md` and version in `phylib\__init__.py`
- publish to pypi:
```shell
uv build
twine upload dist/*
```
11 changes: 0 additions & 11 deletions environment.yml

This file was deleted.

10 changes: 7 additions & 3 deletions phylib/io/alf.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,10 +373,11 @@ def get_waveforms_amp(templates):
cha = np.max(templates, axis=1) - np.min(templates, axis=1)
return np.max(cha, axis=1)

# we unwhiten the templates waveforms, this will expand the templates to the original non-sparse size
# Unwhiten templates and expand them to the original non-sparse size.
templates_phy = np.zeros([nclu, templates['waveforms'].shape[1], nch], dtype=np.float32)
for i in np.arange(templates_phy.shape[0]):
templates_phy[i] = np.matmul(templates['waveforms'][i], wm[templates['waveformsChannels'][i], :])
templates_phy[i] = np.matmul(
templates['waveforms'][i], wm[templates['waveformsChannels'][i], :])

# the original templates have a rms of 1.0, so here we just need to normalize by rms
rms_templates = np.sum(np.sum(templates['waveforms'] ** 2, axis=1), axis=1) ** 0.5
Expand All @@ -390,7 +391,10 @@ def get_waveforms_amp(templates):
np.save(target_path.joinpath('channel_map.npy'), np.arange(nch))
np.save(target_path.joinpath('templates.npy'), templates_phy)

np.save(target_path.joinpath('templates_ind.npy'), np.tile(np.arange(nclu)[np.newaxis, :], reps=[nch, 1]))
np.save(
target_path.joinpath('templates_ind.npy'),
np.tile(np.arange(nclu)[np.newaxis, :], reps=[nch, 1]),
)

# if we have metrics information, output the ks2_label information
if alf_path.joinpath('cluster.metrics.pqt').exists():
Expand Down
18 changes: 10 additions & 8 deletions phylib/io/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,8 @@ def __init__(self, **kwargs):
elif not isinstance(self.dat_path, (list, tuple)):
self.dat_path = [self.dat_path]
assert isinstance(self.dat_path, (list, tuple))
self.dat_path = [Path(p).resolve() if not Path(p).is_symlink() else p for p in self.dat_path]
self.dat_path = [
Path(p).resolve() if not Path(p).is_symlink() else p for p in self.dat_path]

self.dtype = getattr(self, 'dtype', np.int16)
if not self.sample_rate: # pragma: no cover
Expand Down Expand Up @@ -973,14 +974,15 @@ def get_waveforms(self, spike_ids, channel_ids=None):
# Load from precomputed spikes.
try:
return get_spike_waveforms(
spike_ids, channel_ids, spike_waveforms=self.spike_waveforms,
n_samples_waveforms=nsw)
spike_ids, channel_ids, spike_waveforms=self.spike_waveforms,
n_samples_waveforms=nsw)
except AssertionError:
logger.warning(
"Error when loading waveforms from precomputed waveforms, trying to load the raw data.")
spike_samples = self.spike_samples[spike_ids]
return extract_waveforms(
self.traces, spike_samples, channel_ids, n_samples_waveforms=nsw)
logger.warning(
"Error when loading waveforms from precomputed waveforms, "
"trying to load the raw data.")
spike_samples = self.spike_samples[spike_ids]
return extract_waveforms(
self.traces, spike_samples, channel_ids, n_samples_waveforms=nsw)
else:
# Or load directly from raw data (slower).
spike_samples = self.spike_samples[spike_ids]
Expand Down
5 changes: 4 additions & 1 deletion phylib/io/tests/test_alf.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ def __init__(self, tempdir):
np.save(p / 'amplitudes.npy', nr.uniform(low=0.5, high=1.5, size=self.ns))
np.save(p / 'channel_positions.npy', np.c_[np.arange(self.nc), np.zeros(self.nc)])
templates = np.random.normal(size=(self.nt, 50, self.nc))
templates = templates / (np.sum(np.sum(templates ** 2, axis=1), axis=1) ** .5)[:, np.newaxis, np.newaxis]
templates = (
templates /
(np.sum(np.sum(templates ** 2, axis=1), axis=1) ** .5)[:, np.newaxis, np.newaxis]
)
np.save(p / 'templates.npy', templates)
np.save(p / 'similar_templates.npy', np.tile(np.arange(self.nt), (self.nt, 1)))
np.save(p / 'channel_map.npy', np.c_[np.arange(self.nc)])
Expand Down
4 changes: 2 additions & 2 deletions phylib/io/tests/test_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ def test_download_file(tempdir, mock_urls):

assert_succeeds = (data_here and data_valid and
((checksum_here == checksum_valid) or
(not(checksum_here) and checksum_valid)))
(not (checksum_here) and checksum_valid)))

download_succeeds = (assert_succeeds or (data_here and
(not(data_valid) and not(checksum_here))))
(not (data_valid) and not (checksum_here))))

if download_succeeds:
data = _dl(path)
Expand Down
4 changes: 2 additions & 2 deletions phylib/utils/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ def silent(self):
"""Prevent all callbacks to be called if events are raised
in the context manager.
"""
self.is_silent = not(self.is_silent)
self.is_silent = not (self.is_silent)
yield
self.is_silent = not(self.is_silent)
self.is_silent = not (self.is_silent)

def connect(self, func=None, event=None, sender=None, **kwargs):
"""Register a callback function to a given event.
Expand Down
79 changes: 79 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
[build-system]
requires = ["setuptools>=69", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "phylib"
dynamic = ["version"]
description = "Ephys data analysis for thousands of channels"
readme = "README.md"
requires-python = ">=3.10"
license = "BSD-3-Clause"
license-files = ["LICENSE.md"]
authors = [
{name = "Cyrille Rossant", email = "cyrille.rossant@gmail.com"},
]
keywords = ["phy", "data analysis", "electrophysiology", "neuroscience"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Natural Language :: English",
"Framework :: IPython",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"joblib",
"mtscomp",
"numpy",
"requests",
"scipy",
"tqdm",
]

[project.optional-dependencies]
dev = [
"coverage",
"coveralls",
"flake8",
"pytest",
"pytest-cov",
"responses",
]

[tool.setuptools.dynamic]
version = {attr = "phylib.__version__"}

[tool.setuptools.packages.find]
include = ["phylib", "phylib.*"]

[tool.setuptools.package-data]
phylib = [
"*.vert",
"*.frag",
"*.glsl",
"*.npy",
"*.gz",
"*.txt",
"*.html",
"*.css",
"*.js",
"*.prb",
]

[tool.pytest.ini_options]
norecursedirs = [
".git",
".venv",
".uv-cache",
"build",
"dist",
]
filterwarnings = [
"default",
"ignore::DeprecationWarning:responses|cookies|socks|matplotlib",
"ignore:numpy.ufunc",
]
6 changes: 0 additions & 6 deletions requirements-dev.txt

This file was deleted.

9 changes: 0 additions & 9 deletions requirements.txt

This file was deleted.

10 changes: 0 additions & 10 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
[wheel]
universal = 1

[tool:pytest]
norecursedirs =
filterwarnings =
default
ignore::DeprecationWarning:responses|cookies|socks|matplotlib
ignore:numpy.ufunc

[flake8]
ignore=E265,E731,E741,W504,W605
max-line-length=99
Expand Down
70 changes: 0 additions & 70 deletions setup.py

This file was deleted.

Loading