Skip to content

Drop elephant; add NumPy 2.x and Python 3.13 support#17

Merged
RaulSimpetru merged 13 commits into
mainfrom
drop-elephant-binning
May 31, 2026
Merged

Drop elephant; add NumPy 2.x and Python 3.13 support#17
RaulSimpetru merged 13 commits into
mainfrom
drop-elephant-binning

Conversation

@RaulSimpetru

@RaulSimpetru RaulSimpetru commented May 31, 2026

Copy link
Copy Markdown
Member

A modernization pass unlocked by removing the elephant dependency.

Closes #16. Addresses #15 (numpy<2.0) — the pin is lifted here; the already-published 0.9.0 wheels stay <2.0 until the next release rebuilds them.

1. Remove elephant (and viziphant) entirely

  • New dependency-free myogen/utils/bin_spike_trains replaces elephant.conversion.BinnedSpikeTrain at all 4 binning sites (surface + intramuscular EMG dense; both force models sparse) — verified bit-identical to elephant, and removes the warning-suppression hack.
  • utils/helper.py: elephant.statistics.isinumpy.diff (confirmed identical against elephant's source for sorted spike trains).
  • Examples migrated off elephant/viziphant: mean_firing_rate → len/duration, time_histogram → native numpy PSTH, instantaneous_rate (Gaussian KDE) → scipy.ndimage.gaussian_filter1d, BinnedSpikeTrainbin_spike_trains, viziphant.rasterplot_rates → a small native matplotlib raster (the KDE/raster are cosmetic and look slightly different).
  • Dropped the [elephant] extra and the elephant/viziphant dev & docs deps; updated doc snippets. import myogen, the test suite, and the docs build no longer require elephant.

2. NumPy 2.x support

  • Runtime numpy>=1.26,<2.0numpy>=1.26; build-system now compiles against numpy>=2.0.
  • Verified: the wheel builds against NumPy 2.4, and the compiled extension imports under both NumPy 2.4 and 1.26 (the NumPy-2.0 backward-compatible ABI).
  • scipy<1.17 (build-only, manylinux2014 wheel availability — unrelated to elephant) is intentionally left in place; it does not restrict users.

3. Python 3.13 support

  • requires-python>=3.12,<3.14, Python :: 3.13 classifier, and CI test + wheel matrices extended to 3.13 (cp312-* cp313-*).
  • Verified: NEURON 8.2.7 ships cp313 wheels (imports on 3.13), and the Cython extensions build + import under Python 3.13 against NumPy 2.x.

Verification

  • Full suite 89 passed / 3 skipped; ruff clean; import myogen works elephant-free.
  • Binning has a 20-case equivalence/golden test; Codex reconfirmed the binning algorithm, the isi/example/dep changes, and the 2 example bugs it found are fixed.

Known follow-ups (not in this PR)

  • The compiled _cython/*.so are tracked in git, so wheels package stale-ABI .so (harmless at runtime, bloats wheels) — worth untracking separately.
  • Lifting scipy<1.17 would need a manylinux2014 → manylinux_2_28 base bump (drops glibc<2.28) — separate CI change.

…ee helper

Add myogen.utils.bin_spike_trains, a dependency-free boolean spike-occupancy
binner that exactly reproduces elephant.conversion.BinnedSpikeTrain (including its
floating-point tolerance edge-snap and right-edge discard) without emitting the
"shifting spikes to the next bin" warnings.

Use it at the four spike-binning sites -- surface and intramuscular EMG (dense)
and both force models (sparse) -- and remove the elephant import, the
HAS_ELEPHANT guard, and the elephant-warning logger-suppression at each. elephant
remains an optional extra (still used for firing-rate isi in utils/helper.py).

Add an equivalence test asserting bit-identical output to elephant across grid,
multi-train, fp-awkward, t_stop-edge, fractional-bin, sub-range-bounds,
duplicate-spike and empty-train cases.

Closes #16.
…tats

calculate_firing_rate_statistics now derives inter-spike intervals with
np.diff over the (sorted) spike times -- identical to elephant.statistics.isi
for sorted SpikeTrains -- removing the last elephant import from the library.
Restructure test_binning into self-contained golden tests (always run) plus
elephant-equivalence tests gated on elephant being installed.
Replace elephant.statistics.mean_firing_rate with len/duration, time_histogram
with a native numpy PSTH, instantaneous_rate (Gaussian KDE) with scipy
gaussian_filter1d, and BinnedSpikeTrain with myogen.utils.bin_spike_trains. The
viziphant rasterplot_rates in example 02 is replaced by a small native
matplotlib raster (raster + marginal axes).
Remove the [elephant] optional extra and the elephant/viziphant entries from
the dev and docs dependency-groups, and update the neo-block docs snippets to
compute firing rate natively. import myogen, the test suite, and the docs build
no longer require elephant. Add a CHANGELOG entry.
@RaulSimpetru RaulSimpetru changed the title Drop elephant BinnedSpikeTrain dependency (custom binning helper) (#16) Remove the elephant dependency entirely (#16) May 31, 2026
Address review: pass explicit lineoffsets to eventplot so each spike train
renders on its own raster row, and drop spikes on the right bin edge (t_stop)
before np.histogram so the native PSTH matches the old elephant binning.
With elephant removed (the reason for the cap), relax the runtime numpy
requirement to >=1.26 and build the Cython extensions against numpy>=2.0.
Wheels built against NumPy 2.0 stay backward-compatible with NumPy 1.x at
runtime (verified: the compiled _gto extension imports under both NumPy 2.4 and
1.26). The scipy<1.17 build cap is unrelated (manylinux2014 wheel availability)
and is left in place.

Relates to #15.
Widen requires-python to >=3.12,<3.14, add the Python 3.13 classifier, and
extend the CI test matrix and cibuildwheel build (cp312-* cp313-*) to 3.13.
NEURON 8.2.7 already ships cp313 wheels, and the Cython extensions build and
import under Python 3.13 against NumPy 2.x (verified locally on macOS arm64).
@RaulSimpetru RaulSimpetru changed the title Remove the elephant dependency entirely (#16) Drop elephant; add NumPy 2.x and Python 3.13 support May 31, 2026
Now that build_wheels produces both cp312 and cp313 wheels, the test_wheels
'pip install dist/*.whl' tried to install both and pip rejected the wheel for
the other ABI. Select the wheel matching the runner's Python tag instead.
…rtifacts v6/v7)

Node 20 actions are deprecated (forced to Node 24 on 2026-06-16). Move
actions/checkout to v5, actions/setup-python to v6, actions/upload-artifact to
v6, and actions/download-artifact to v7 -- the minimal majors that run on
Node 24 (artifact v5 and download v6 are still Node 20).
peaceiris/actions-gh-pages@v3 was node16 and softprops/action-gh-release@v1
was node16 (v2 is still node20); move to v4 and v3 respectively, both node24.
Inputs are unchanged (github_token/publish_dir for peaceiris, files for
softprops). pypa/cibuildwheel and pypa/gh-action-pypi-publish are composite
actions and unaffected by the Node 20 deprecation.
scipy >= 1.17 only ships manylinux_2_28 wheels, so the cibuildwheel Linux
base moves manylinux2014 -> manylinux_2_28 (glibc >= 2.28; drops EOL
CentOS/RHEL 7) and the build-system scipy<1.17 cap is removed. The repair step
tags wheels manylinux_2_28, and openblas-devel is dropped from the Linux
pre-build deps (only needed for the old scipy source-build fallback, which no
longer happens now that scipy installs from a wheel).
…7, py3.13)

Regenerate the lockfile for the updated dependency set: elephant and
viziphant removed, requires-python widened to >=3.12,<3.14, and numpy/scipy
upgraded to 2.4.6 / 1.17.1 now that the <2.0 / <1.17 caps are gone.
np.trapz was removed in NumPy 2.0, which broke fiber_simulation under the
upgraded lock (numpy 2.4). scipy.integrate.trapezoid has the same signature and
works on both NumPy 1.26 and 2.x. Verified: full suite passes on numpy 2.4.6 /
scipy 1.17.1.
@RaulSimpetru RaulSimpetru merged commit bd3a540 into main May 31, 2026
12 checks passed
@RaulSimpetru RaulSimpetru deleted the drop-elephant-binning branch May 31, 2026 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Drop the elephant dependency in simulate_surface_emg() (replace BinnedSpikeTrain with custom binning)

1 participant