add unit tests for deterministic logic#13
Open
jl33-ai wants to merge 3 commits into
Open
Conversation
lets you run the pipeline end to end without an acquisition rig. useful for smoke testing a fresh install, working on a laptop, and CI. - realtime_decoder/synthetic.py: SyntheticDataReceiver and SyntheticClient that match the surface of TrodesDataReceiver and TrodesClient. drop in replacements. non-blocking __next__ semantics so the polling loops in encoder/decoder/ripple work unchanged. - runscript.py picks the data source via config['datasource']. defaults to 'trodes' so every existing config keeps working. - config/demo_synthetic.yml is a 5 rank demo wired to the synthetic source. - README adds a 'running without acquisition hardware' section. spikes are poisson, marks gaussian, position walks a triangle wave along a single segment. not biologically realistic, the point is to exercise the data path and message plumbing. to try it: mpiexec -np 5 python -u runscript.py config/demo_synthetic.yml
most of the per-animal yamls duplicate the same sampling rates, ripple filter, gui colors, kinematics smoothing filter, mua, etc. drift is real and 'what is the canonical value of X' is currently unanswerable. - configs can declare `_extends: defaults.yml` and only override what is actually different. nested dicts deep merge key by key, lists and scalars replace. - config/defaults.yml holds the values stable across the SC*/fred/ginny configs. - runscript routes config loading through a new config_loader module that runs a small validator on the resolved dict. catches missing rank.supervisor, unknown algorithm, missing encoder.mark_dim, decoder ranks with no assignment, encoder.mark_dim != synthetic.mark_dim, etc. errors print one readable message and exit 2 before MPI workers spawn, instead of surfacing as IndexError deep in a rank. - config/demo_synthetic.yml now uses _extends, drops about 80 lines. - loader uses stdlib pyyaml instead of oyaml since python 3.7+ dicts preserve order. one fewer dep. backward compatible. verified all 16 existing per-animal configs still load and validate unchanged. follow up not in this PR: the SC*/fred/ginny configs can each be rewritten as _extends + overrides which would shrink them by roughly half. left as a separate diff so per-config behavior changes are auditable on their own.
36 tests covering the pure-python pieces of the codebase. these run on a plain `pip install pytest` without MPI or any acquisition hardware.
coverage:
- utils: normalize_to_probability (incl. nan handling), estimate_new_stats (vs numpy), apply_no_anim_boundary (1d + 2d)
- position: PositionBinStruct edges/centers/get_bin, TrodesPositionMapper (basic + clamp-above-1 edge case), KinematicsEstimator (first-sample, unsmoothed speed, FIR smoothing)
- transitions: sungod_transition_matrix shape, row sums equal 1 or 0, gap rows/cols zeroed, no NaNs in output
- config_loader: deep_merge (nested, list-replace, scalar-overrides-dict), load_config with and without _extends, circular extends detection, validate catches missing required keys / unknown algorithm / decoder rank without assignment / mark_dim mismatch with synthetic
- synthetic: receiver rejects bad datatype, lfp/spike/position emission shapes, returns None before activate, SyntheticClient fires startup callback after delay, records would-be ECU shortcut messages
tests/conftest.py installs a minimal mpi4py stub if the real mpi4py is not importable. several modules (base, position, synthetic) import mpi4py at module top, and mpi4py needs a system MPI build to install. the stub lets the deterministic tests run anywhere; if real mpi4py is present it's used instead.
setup.py: `extras_require={'test': ['pytest']}` and exclude tests from the installed package. also added pyyaml to install_requires since the config_loader uses it.
README: short Tests section.
to run:
pip install -e .[test]
pytest -q
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.
stacked on top of #11 (config defaults). until that lands, the diff here also shows the synthetic source + config_loader; once #10 and #11 merge GitHub will collapse this to just `tests/`, the setup.py edits, and the README section.
36 tests covering the pure-python pieces of the codebase. these run on a plain `pip install pytest` without MPI or any acquisition hardware.
what's covered
the mpi4py stub
several modules (`base`, `position`, `synthetic`) import `mpi4py` at module top, and `mpi4py` needs a system MPI build to install. that makes `pip install pytest` not enough by itself.
`tests/conftest.py` installs a minimal mpi4py stub if the real one is not importable. if real mpi4py is present (developer machine, CI image with MPI), the stub is skipped. the stub's data-path methods raise loudly if anything accidentally tries to use them in a test, so we don't get silent no-ops.
setup.py
README
to run:
```
pip install -e .[test]
pytest -q
```
not in this PR: tests for the MPI paths themselves, the ripple envelope filter (depends on ghostipy filter design), and gui_process. natural follow ups once this lands.