Repository navigation
Add sonpipe: CLI bridge for reading CED Spike2 files via sonpy - #1
Merged
Merged
Conversation
Build a standalone command-line bridge that reads CED Spike2 files (both 32-bit .smr and 64-bit .smrx) via CED's sonpy and streams data as raw binary for fast, chunked ingestion by MATLAB. Python CLI (src/sonpipe): - header / sampleinterval / read / channels sub-commands imitating the ndr.format.ced.* reading functions - raw little-endian binary output for waveforms and event times; JSON for metadata and markers - sample-based (--start/--count) and time-based (--t0/--t1) chunking - reads all main Spike2 channel kinds (Adc, Event, Marker, AdcMark, RealMark, TextMark, RealWave); Spike2 1-based channel numbers mapped to sonpy's 0-based indices - warns when a read exceeds 50 MB (pipe can be slow); --no-size-warning - sonpy declared as a pip dependency, not vendored, per CED's license MATLAB client (matlab/+sonpipe): - read_SOMSMR_header / read_SOMSMR_sampleinterval / read_SOMSMR_datafile drop-in analogues of ndr.format.ced.*, plus channels/channelinfo/executable - invokes the CLI and reads binary output back with fread/typecast Tests and CI: - Python tests with a fake sonpy shim (no CED binaries needed) - MATLAB matlab.unittest suite in test/+sonpipe/+unittest driving a fake CLI - matbox-style workflows (mirroring NDR-matlab) that compile and test both the CLI and MATLAB code on Linux, Windows, macOS Intel, and macOS Apple Silicon Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
- CI (both cli-tests and matlab-tests) now triggers on push to main, pull requests targeting main, and manual workflow_dispatch, matching NDR-matlab. - Add sonpipe.runcmd: run system commands with LD_LIBRARY_PATH / DYLD_LIBRARY_PATH cleared, so a child Python launched from MATLAB does not inherit MATLAB's bundled shared libraries and fail to start (a common cause of Python crashes when shelling out from MATLAB on Linux/macOS). Route the CLI invokers, executable lookup, and the test harness through it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
The default Python/MATLAB suites use a synthetic fake sonpy (no real Spike2 files, deterministic, cross-platform). Add an opt-in integration suite that exercises the real CED sonpy against a real .smr/.smrx file, gated on the SONPIPE_TEST_FILE environment variable and sonpy being importable (skipped otherwise). Document both in the README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
The MATLAB wrappers only shell out to the CLI, so there is nothing to compile on the MATLAB side; running the unit tests already loads and parses every function. Remove the pcode "compile" step (the CLI build step already compiles the actual tool). Also drop the batch-license secret plumbing: matlab-actions provides MathWorks licensing for free on public repositories, so no secret is needed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
- Add example/spike2data.smrx, a real 64-bit Spike2 file, as the default fixture for the integration tests. - Expand the integration suite to exercise the real CED sonpy end-to-end: the SmrxFile wrapper (header, waveform/event/marker reads, count-limited reads) and the CLI as a subprocess (raw-binary pipe). Defaults to the checked-in example file; SONPIPE_TEST_FILE overrides it. - Add integration-tests.yml running the real sonpy on Linux, Windows, macOS Intel and macOS Apple Silicon using Python 3.14, for which CED ships sonpy wheels on every platform. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
Add install.sh (Linux/macOS) and install.ps1 (Windows) that install sonpipe into an isolated virtual environment and expose the `sonpipe` command on the user's PATH: - Linux/macOS: venv at ~/.local/share/sonpipe/venv, command symlinked at ~/.local/bin/sonpipe (the console script's shebang targets the venv, so it runs correctly from anywhere, including MATLAB). - Windows: venv under %LOCALAPPDATA%\sonpipe, with optional -AddToPath. Both prefer Python 3.14 (where CED ships sonpy wheels on every platform), verify the CLI and the real sonpy import, warn clearly when no sonpy wheel exists for the chosen Python, and print the sonpipe.executable(...) line for MATLAB. Document the scripts and the recommended install location in the README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
Empty commit to kick a fresh workflow run now that MATLAB CI can obtain a license on the public repository. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
The integration runs revealed that CED packages sonpy inconsistently: the Windows wheel exposes the API at the top level (sonpy.SonFile), while the Linux cp314 wheel ships an empty __init__ and puts the API in the compiled submodule sonpy.sonpy. Neither provides the sonpy.lib submodule the code assumed, so `from sonpy import lib` failed everywhere real sonpy was present. - load_sonpy now probes sonpy, sonpy.lib, and sonpy.sonpy and returns the module that actually exposes SonFile; factor the resolution into _resolve_son_module and cover all three layouts (plus not-found) with unit tests that need no real sonpy. - Fix the integration workflow's verification step (the old one referenced sonpy.__version__, which some wheels do not define) to instead confirm load_sonpy() finds SonFile. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
The real-sonpy integration passed on Linux and Windows, confirming the sonpy binding is correct. It failed only on macos-14 because CED's macOS wheel, though tagged universal2, ships an x86_64-only binary that cannot load on arm64. Force architecture x64 across the integration matrix: native on Linux, Windows and macOS Intel, and x86_64-under-Rosetta on Apple Silicon, so the real-sonpy suite is green on all four platforms. Document the Apple Silicon limitation in the README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
architecture: x64 alone did not yield an x86_64 interpreter on the macos-14 runner (setup-python fell back to the arm64 framework Python), so CED's x86_64-only sonpy still failed to load. That framework Python is universal2, so run every Python command on macos-14 through `arch -x86_64` to execute its x86_64 slice under Rosetta 2, where the x86_64 sonpy loads. Native x86_64 Python is used on the other platforms. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
Intel macOS runners are scarce and queue for a long time. macos-14 (Apple Silicon) already covers both architectures: the CLI and MATLAB fake-based suites run natively on arm64, and the real-sonpy integration runs x86_64 under Rosetta 2 (arch -x86_64) — the same x86_64 sonpy binary a native Intel Mac would load. Remove macos-13 from all three workflows and update the docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR introduces sonpipe, a complete command-line bridge for reading Cambridge Electronic Design (CED) Spike2 data files (both 32-bit
.smrand 64-bit.smrxformats) via CED's proprietarysonpylibrary. The tool streams data as raw binary bytes to stdout for efficient ingestion by MATLAB and other host environments, with accompanying MATLAB wrappers that provide drop-in compatibility with NDR-matlab'sndr.format.cedfunctions.Key Changes
Core Python Implementation
src/sonpipe/sonfile.py: Thin, testable wrapper aroundsonpy.SonFilethat isolates all proprietary library calls. Handles channel numbering (Spike2's 1-based convention vs. sonpy's 0-based indexing), metadata extraction, and data reading for waveforms, events, and markers.src/sonpipe/cli.py: Command-line interface with four sub-commands:header: Emit file and channel metadata as JSONsampleinterval: Query timing info for a single channelread: Stream channel data as raw binary (waveforms/events) or JSON (markers)channels: List available channelssrc/sonpipe/channels.py: CED channel-type code definitions and mappings (ADC, RealWave, Event, Marker, TextMark, etc.) that align with sonpy'sDataTypeenum and NDR-matlab conventions.src/sonpipe/errors.py: Custom exception hierarchy.src/sonpipe/__init__.pyand__main__.py: Package initialization and CLI entry point.Testing Infrastructure
tests/fakesonpy.py: Synthetic in-memory fake of thesonpy.libmodule with a minimal Spike2 file layout (ADC, RealWave, Event, Marker, TextMark channels). Enables full test coverage without CED's proprietary binaries.tests/test_sonfile.py: Unit tests forSmrxFilewrapper (channel discovery, metadata, waveform/event/marker reads).tests/test_cli.py: End-to-end CLI tests (header, sampleinterval, read sub-commands with various options).tests/test_integration.py: Integration tests against realsonpyand a real Spike2 file (skipped if sonpy unavailable).tests/conftest.py: Pytest fixtures that inject the fake sonpy for unit tests.MATLAB Wrappers
matlab/+sonpipe/read_SOMSMR_header.m: Read file and channel metadata (JSON).matlab/+sonpipe/read_SOMSMR_datafile.m: Stream channel data (waveforms, events, markers).matlab/+sonpipe/read_SOMSMR_sampleinterval.m: Query sample interval and duration.matlab/+sonpipe/channels.m: List channels in NDR-style struct format.matlab/+sonpipe/executable.m: Locate and cache the sonpipe CLI executable.matlab/+sonpipe/runcmd.m: Run system commands with a Python-safe environment (clears LD_LIBRARY_PATH/DYLD_LIBRARY_PATH).matlab/+sonpipe/private/invoke_binary.mandinvoke_text.m: Helpers to capture binary and text output from the CLI.matlab/+sonpipe/Contents.mandchannelinfo.m: Package documentation and utility functions.MATLAB Unit Tests
test/+sonpipe/+unittest/TestCase.m: Base fixture that configures a fake CLI for testing without CED binaries.test/+sonpipe/+unittest/HeaderTest.m, **`DatafileTest.https://claude.ai/code/session_01VTQEJGfiSxeVG1J5GSmaTy