From 16312de588a73646ae88fbf40b03fdfb59a94cb7 Mon Sep 17 00:00:00 2001 From: Hamza Abdelhedi Date: Mon, 31 Aug 2026 09:05:36 -0400 Subject: [PATCH 1/5] MAINT add repository agent guidance --- AGENTS.md | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 3 + 2 files changed, 347 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..d7c8b337 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,344 @@ +# AGENTS.md + +This file provides repository-specific guidance to coding agents and other automated assistants working with or on `mne-denoise`. It covers two use cases: helping users apply mne-denoise correctly, and modifying the package, tests, documentation, or repository tooling. + +## What is mne-denoise + +`mne-denoise` provides artifact-suppression and signal-denoising methods for +EEG and MEG. It supports NumPy arrays and optional integration with +MNE-Python containers, and provides scikit-learn-style estimators where that +interface fits the method. The package contains several distinct scientific +methods rather than one universal denoising procedure. + +The scientific semantics and assumptions of each method matter more than implementation convenience. mne-denoise should integrate naturally into the MNE ecosystem and reuse generic MNE behavior rather than reproduce functionality that MNE already owns. + +## Helping users with mne-denoise + +Use the current public API only. Before suggesting an import or workflow, inspect the current public facades and `tests/test_public_api.py`; do not infer the API from filenames or old examples. Importability alone does not make a name public. + +Do not hallucinate stale names from historical documentation or branches. In particular: + +- Do not suggest an object that exists only because a similar name appeared in + an earlier version. +- Public imports must come from current documented facades and their declared + `__all__` values. +- Modules and names beginning with `_` are implementation details and should + not be recommended to users. + +When the context is available, determine the parts of the scientific problem that affect the recommendation: + +- EEG or MEG. +- Raw, Epochs, Evoked, or NumPy input. +- Sampling frequency and channel types. +- Known bad channels. +- The target artifact or noise source. +- Continuous versus epoched data. +- Line frequency, when line-noise removal is relevant. +- Whether the goal is artifact suppression, source extraction, component + enhancement, or another operation. +- Preprocessing already performed, including filtering and referencing. + +Do not ask every question in every conversation, but do not ignore these factors when they change the scientific interpretation or API choice. No method is universally best. Explain relevant assumptions, choose the simplest public workflow that fits the goal, and preserve MNE metadata and container semantics. + +Do not recommend private helpers when a public estimator or function exists. Distinguish established published methods from mne-denoise-specific extensions and experimental research APIs. On current main, `GuidedASR` and `process_guided_asr` are unpublished, unvalidated experimental research prototypes; the estimator requires explicit experimental opt-in. The SSP-SIR estimator has a validated numerical core but is not independently validated on a public real TMS-EEG dataset, so real-data use is experimental. The `ASR` `method="riemannian"` backend is also explicitly experimental; do not describe these APIs as established defaults. + +Artifact attenuation is not evidence that desired neural signal was preserved. Where relevant, encourage users to evaluate both artifact attenuation and preservation of the signal of interest, using suitable controls and scientific knowledge. + +Example code for users must: + +- Use canonical import paths and current constructor parameter names. +- Use the current `fit`, `transform`, `fit_transform`, or functional API + semantics. +- Avoid needless NumPy extraction and MNE-object reconstruction when an + estimator accepts an MNE container directly. +- Never mutate user data unless the public API explicitly documents in-place + behavior. + +## Sources of truth + +Scientific truth and software-contract truth are related but not +interchangeable. + +### Scientific algorithm semantics + +Use this order when resolving a scientific question: + +1. The primary scientific publication. +2. An authoritative or reference implementation, when relevant. +3. The current mne-denoise implementation and scientific tests. +4. Historical branches, historical outputs, fixtures, and old documentation + only when they are needed to resolve an ambiguity. + +Historical output parity is not by itself scientific truth. Do not recreate old substrate, parity, or output-generation machinery merely to preserve historical numerical arrays. If the implementation and the publication or reference implementation appear inconsistent, stop and surface the discrepancy rather than silently choosing one interpretation. + +### mne-denoise software contracts + +Use this order for package behavior and compatibility questions: + +1. The intentional public API and its tests. +2. Shared estimator and MNE-container contract tests. +3. Algorithm-specific tests. +4. Current user documentation. + +Correct documentation when it contradicts the implementation and tests, unless the discrepancy reveals a scientific bug that needs separate investigation. + +## Before writing new code + +Search for an existing owner before adding local machinery: + +1. Search mne-denoise for an existing implementation or helper. +2. Search public MNE-Python APIs. +3. Search NumPy, SciPy, and scikit-learn functionality where appropriate. +4. Only then introduce new local machinery. + +Prefer existing public MNE APIs over local duplication. Generic MNE object, channel, forward, covariance, filter, and container behavior should not be reimplemented here when MNE already owns it. If the needed behavior only exists privately, consider whether an upstream public API or change is more appropriate instead of importing MNE internals. + +Keep logic local when mne-denoise semantics genuinely differ. Do not import MNE private helpers casually to remove a few lines, build wrappers solely for conceptual symmetry, or create an abstraction for one caller unless it materially clarifies ownership. Do not add hypothetical parameters or extension points, and do not add dependencies without a concrete need and discussion. Never promote an optional dependency to a required dependency as a side effect. + +Implement behavior at the highest existing owner layer. For example, a generic estimator invariant belongs in the package-wide estimator contract suite, not in repeated method-specific tests. + +## Keep changes focused + +Optimize for reviewer comprehension and long-term maintenance, not diff size or output volume. Prefer the smallest change that fully satisfies the issue, and avoid opportunistic cleanup of unrelated code. + +If a task starts requiring a new subsystem, dependency, public API family, or many unrelated files, reconsider its scope. Reuse existing test infrastructure before creating new infrastructure. Avoid future-proofing that has no immediate requirement. In particular, do not silently turn a documentation or repository-guidance task into a scientific implementation change. + +## Public API + +The intentional public API is tested in `tests/test_public_api.py`. Current public facades include `mne_denoise`, `asr`, `bss_cca`, `dss`, `dss.denoisers`, `dss.variants`, `dss.segmentation`, `dss.selection`, `icanclean`, `overcorrection`, `progress`, `qa`, `sns`, `sound`, `spectrum_interpolation`, `ssa`, `sspsir`, `viz`, and `zapline`. + +These facades declare `__all__`. Importability alone does not make a symbol public; canonical import paths are tested explicitly. A new public API requires updates to the appropriate facade, `__all__`, API documentation, tests, and user-facing documentation or the changelog when appropriate. + +Private underscore names have no compatibility promise. Experimental APIs +must be clearly identified. Documentation and examples must never invent +public names that are not part of current main. + +## Estimator contracts + +`tests/_contract_cases.py` is the central estimator capability registry, and `tests/test_estimator_contracts.py` executes the shared cases. The registry is capability-based: it does not promise that every estimator has the same interface or output shape. + +The capabilities currently represented are: + +- `cloneable`: scikit-learn `clone` preserves the public constructor + parameters. +- `fit_returns_self`: `fit()` returns the estimator instance. +- `fit_transform_composes`: `fit_transform()` agrees with separate `fit()` then `transform()` calls. AdaptiveASR's deliberately different fit/transform modes are not forced into this group. +- `not_fitted`: the registered pre-fit operation raises the expected `NotFittedError`. DSS and ZapLine intentionally retain their public pre-fit `RuntimeError` behavior and are not placed in this group. +- `numpy_no_mutation`: the public NumPy operation leaves its input unchanged + and returns the expected array shape. +- `numpy_layout`: supported NumPy layouts, including the applicable epoched + layout, are preserved. +- `mne_raw`, `mne_epochs`, and `mne_evoked`: the estimator supports the corresponding MNE container in the shared suite. +- `fitted_channel_count`: a fitted estimator rejects a different channel + count. +- `fitted_channel_order` and `fitted_channel_names`: a fitted MNE estimator + enforces the channel layout guarantees it declares. +- `sfreq_aware`: a fitted operation rejects a sampling-frequency mismatch + where its contract requires that check. +- `callback_transparent`: a callback does not change numerical output, receives `ProgressEvent` objects, and propagates callback failures. + +Before adding an estimator-specific test for generic behavior, check whether the estimator should instead opt into an existing capability in `_contract_cases.py`. Do not repeat tests such as one input-mutation test per estimator when the central contract owns that property. Algorithm-specific tests should cover algorithm-specific science and behavior. + +## MNE container contracts + +Read `tests/test_mne_container_contracts.py` before changing public MNE integration. Raw, Epochs, and Evoked are not merely NumPy arrays with labels; their metadata and lifecycle semantics are part of the public contract. + +The shared suite currently checks, as applicable: + +- The output remains the corresponding MNE container type. +- Transformation returns a new object and does not mutate the input. +- Channel names and order follow the estimator's fitted-layout rules. +- Bad-channel metadata is preserved. +- Untouched channels remain unchanged. +- Raw annotations and `first_samp` are preserved. +- Epochs events, event IDs, baseline, metadata, selection, and drop log are + preserved. +- Evoked timing, `nave`, and comments are preserved. +- Fitted channel-name/order and sampling-frequency checks are enforced where + declared by the estimator. + +Generic MNE-container behavior belongs in this shared contract suite; algorithm-specific numerical behavior belongs in algorithm tests. + +## Progress reporting + +The package-wide progress design is implemented in `mne_denoise/progress.py` and tested by `tests/test_progress.py`, `tests/test_progress_api.py`, and `tests/test_progress_tqdm.py`. + +Algorithm code emits structured progress events through callback support. `ProgressEvent` is the immutable protocol payload. Callbacks are synchronous runtime observers supplied by keyword; their return values are ignored and their exceptions propagate unchanged. Logging is independent: `verbose` controls package logs, while `callback` controls events. + +`TqdmProgress` is an optional presentation adapter that consumes events. Algorithm internals must not own tqdm bars directly. Do not add `print()`-based progress or a second callback interface. New callback-aware methods should follow the existing package convention and should not make callback state an estimator hyperparameter. + +## Optional dependencies and base-install boundary + +The required runtime dependencies are NumPy (`>=1.26,<3`), SciPy (`>=1.13`), +scikit-learn (`>=1.5`), and joblib (`>=1.4`). Published optional extras are: + +- `mne`: MNE-Python (`>=1.12.1`) for MNE container integration. +- `viz`: matplotlib (`>=3.8`) for visualization. +- `progress`: tqdm (`>=4.66`) for the tqdm progress adapter. + +The dependency groups in `pyproject.toml` are `lockfile_extras`, `test`, +`doc`, `build`, `lint`, `changelog`, and `dev`. The lockfile group covers +optional runtime packages for lower-bound checks; `test` adds pytest, +coverage, timeout, pandas, and seaborn; `doc` adds MNE and documentation +tooling; `build` adds distribution tooling; `lint` adds `prek` and `spin`; +`changelog` adds towncrier; and `dev` combines the development groups with +pip. + +The base package must remain usable without MNE, matplotlib, or tqdm. +Optional dependencies must not be imported eagerly in a way that makes base +import fail. MNE-Python integration, plotting, and tqdm remain optional, and +the minimum versions are deliberate compatibility commitments. + +`scripts/check_base_install.py` verifies this boundary, including that the +base installation can import the package and that the visualization namespace +gives actionable optional-dependency guidance. Preserve this boundary in all +changes. + +## Continuous integration + +The matrix in `.github/workflows/tests.yml` protects different compatibility +properties rather than repeating one test run: + +- A lint job runs the complete `prek` hook suite on Ubuntu with Python 3.14. +- A base-install job uses Python 3.12, installs only the package, and runs + `scripts/check_base_install.py`. +- A minimum-dependencies job validates the lower-bound lockfile on Python + 3.12 and runs the tests. +- The stable matrix covers Ubuntu Python 3.13, Ubuntu Python 3.14 with the + coverage upload, Windows Python 3.14, and macOS ARM Python 3.14. +- An MNE-main job installs MNE-Python main over the stable test environment + and runs the tests. +- A scientific-dependency prerelease job upgrades the scientific stack and is + allowed to report failures without blocking required jobs. + +`.github/workflows/docs.yml` builds the full gallery against both released +MNE and MNE main, prefetching the MNE Sample, Somato, and EEGBCI datasets. +The release workflow builds and validates distributions and tests an +installed wheel before publishing on a GitHub release. The changelog workflow +checks Towncrier fragments, and dependency review rejects high-severity +dependency findings. + +Passing one local environment is not sufficient evidence of repository +compatibility. Do not fix CI failures by raising dependency floors without +justification, removing platform coverage, weakening optional-dependency +boundaries, disabling tests, or allowing failures on required jobs. + +## Repository task commands + +Use the current Spin interface in `.spin/cmds.py`: + +```bash +spin test +spin test -- -k +spin lint +spin docs +spin build +spin check +``` + +Spin is the canonical repository task interface. Direct `pytest` commands are +fine for focused development and debugging. `prek` is the hook runner; it is +not a replacement for environment or package installation tooling. Do not +introduce another task runner solely to duplicate these commands. + +## Testing philosophy + +Test scientific, public, and integration contracts rather than private +implementation details. Prefer deterministic behavioral or numerical +assertions to execution-only or shape-only coverage tests. Historical bug +cases are useful when they protect a durable contract, but organize them +under the contract that owns them rather than creating a historical-parity +testing architecture. + +Use parametrization when it represents genuinely equivalent cases. Keep +scientifically distinct regimes separate. Use coverage diagnostically; do not +optimize for a percentage at the expense of meaningful tests. Centralize +shared estimator and MNE-container behavior in their contract suites. + +## Scientific implementations and validation + +Primary scientific literature governs algorithm claims and semantics. Identify +whether behavior is a published method, an established implementation +convention, an mne-denoise-specific extension, or experimental/prototype +behavior. Do not silently describe an extension as if it came from the +original paper. + +Scientific tests should exercise meaningful invariants and behavior, not only +reproduce one historical array. If changing scientific behavior, document why +and cite the relevant source. Parity with old package output is insufficient +evidence of correctness. Numerical tolerances should reflect meaningful +floating-point expectations, not be widened merely to make a test pass. + +## Documentation and docstrings + +Every public function, class, and method docstring is part of the public API +and must match current behavior. Check public docstrings for: + +- A one-line summary. +- Current parameter names and types. +- Accepted container types and expected array shape/layout. +- Defaults, return type, return container/shape, and fitted attributes where + relevant. +- `Raises` entries for meaningful user errors. +- `Notes` where scientific or implementation interpretation is needed. +- References for published scientific methods and `See Also` where genuinely + useful. +- Examples only when they add value beyond the gallery and other docs. + +Use NumPy-style docstrings and the repository's citation conventions. Do not +maintain a complete bibliography manually in every docstring. Do not leave +stale parameter names after API changes, claim Raw/Epochs/Evoked support that +the implementation or contracts do not provide, or misstate copy versus +in-place semantics and `fit`/`transform` lifecycle. Document experimental +status where appropriate. + +PR 2 will perform a callable-by-callable public docstring audit. Existing +docstrings are not authoritative when they disagree with implementation, +tests, or scientific sources. + +## Examples and gallery + +Gallery examples have CI, runtime, and maintenance costs. One new estimator +does not automatically require one new example. Extend an existing example +when it teaches the same concept; add a gallery item when it teaches a +meaningful scientific capability or workflow. Tiny syntax demonstrations +belong in docstrings or method documentation, and tests are not gallery +examples. + +New real-data dependencies must use the documentation data prefetch/cache +mechanism. Add datasets to `scripts/prefetch_docs_data.py` when an example +needs them. Examples must use public APIs and should not preserve obsolete +APIs merely to avoid changing docs. Do not introduce a `tutorials/` directory +as part of this documentation refactor. + +## Repository scripts and generated artifacts + +Scripts under `scripts/` are operational repository helpers. Do not add +substrate or parity-generation scripts without a demonstrated current need. +Generated changelog, release, and citation artifacts should be maintained by +their owning tooling rather than hand-edited where applicable. Old parity +builders are not part of the current architecture. + +## Deferred / out-of-scope architecture + +Do not expand a task into these areas unless the issue or maintainer explicitly +asks for it: + +- A broader SSP-SIR/MNE-Python redesign. +- Upstream generic MNE helper work that is not necessary for the current task. +- A repository-wide typing or type-checker migration. +- Historical parity infrastructure. +- Unrelated new denoising algorithms. + +These are deferred categories, not a prohibition on legitimate future work. + +## Git and pull-request expectations + +Never commit directly to `main`. Keep pull requests focused and use existing +issue or design discussion for substantial behavior changes. User-visible +changes need the repository's changelog mechanism. Do not add AI co-author +trailers unless repository policy explicitly requires them. The human +contributor remains responsible for submitted changes. + +Follow `CONTRIBUTING.md` for human-facing contribution policy, communication, +and AI-assisted contribution expectations. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..8a796c38 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,3 @@ +# CLAUDE.md + +See @AGENTS.md for repository-specific guidance. From 33877044170e9fcafaf2aaaca8a3784b3279eac3 Mon Sep 17 00:00:00 2001 From: Hamza Abdelhedi Date: Mon, 31 Aug 2026 09:05:56 -0400 Subject: [PATCH 2/5] DOC simplify contributor and repository entry points --- CONTRIBUTING.md | 481 +++++-------------------------------- README.md | 219 ++++------------- docs/changes/devel/doc.rst | 1 + 3 files changed, 110 insertions(+), 591 deletions(-) create mode 100644 docs/changes/devel/doc.rst diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5812b32d..7a85f9c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,455 +1,104 @@ # Contributing to mne-denoise -Thank you for your interest in contributing to `mne-denoise`! This guide will help you get started with contributing code, documentation, or bug reports. +Thanks for your interest in contributing. Contributions may include bug +fixes, scientific improvements, tests, documentation, examples, or +maintenance. -## Table of Contents +## Questions, bugs, and feature ideas -- [Code of Conduct](#code-of-conduct) -- [Getting Started](#getting-started) -- [Development Environment](#development-environment) -- [Workflow](#workflow) -- [Code Style](#code-style) -- [Testing](#testing) -- [Documentation](#documentation) -- [Public API and compatibility](#public-api-and-compatibility) -- [Submitting Changes](#submitting-changes) -- [Issue Guidelines](#issue-guidelines) +Please search existing issues and discussions first. -## Code of Conduct +- Usage and support questions belong on the [MNE Forum](https://mne.discourse.group/). +- Reproducible bugs belong in the [bug report form](https://github.com/mne-tools/mne-denoise/blob/main/.github/ISSUE_TEMPLATE/bug_report.yml). +- Feature or scientific enhancement ideas belong in the [feature request form](https://github.com/mne-tools/mne-denoise/blob/main/.github/ISSUE_TEMPLATE/feature_request.yml). +- Documentation problems belong in the [documentation form](https://github.com/mne-tools/mne-denoise/blob/main/.github/ISSUE_TEMPLATE/documentation.yml). -This project follows the [MNE-Python Code of Conduct](https://github.com/mne-tools/mne-python/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. +## Code of Conduct and communication -## Getting Started +Contributors must follow the project's [Code of Conduct](https://github.com/mne-tools/mne-denoise/blob/main/CODE_OF_CONDUCT.md). +GitHub technical review is often concise and matter-of-fact; short feedback +should not automatically be interpreted as a lack of interest or friendliness. +Focus on the technical content, while keeping every interaction consistent +with the Code of Conduct. -### Prerequisites +## AI-assisted contributions -- Python 3.12 or higher -- Git -- A GitHub account +Fully automated issue or pull-request generation without human review is not +acceptable. The contributor is responsible for every submitted line and must +understand, review, and test AI-assisted work. Scientific algorithm changes +deserve particular scrutiny for correctness, provenance, and licensing. -### Fork and Clone +If AI tools were used, disclose the tool, manner, and scope of assistance in +the pull-request description. Do not use AI-generated text as a substitute for +understanding reviewer discussion. -1. **Fork** the repository on GitHub by clicking the "Fork" button. +## Development setup -2. **Clone** your fork locally: - - ```bash - git clone https://github.com//mne-denoise.git - cd mne-denoise - ``` - -3. **Add the upstream remote**: - - ```bash - git remote add upstream https://github.com/mne-tools/mne-denoise.git - ``` - -## Development Environment - -We recommend using a virtual environment for development. - -### Using venv (recommended) - -```bash -# Create virtual environment -python -m venv .venv - -# Activate it -# On macOS/Linux: -source .venv/bin/activate -# On Windows: -.venv\Scripts\activate - -# Upgrade pip -python -m pip install --upgrade pip - -# Install in editable mode with the development dependency group -python -m pip install -e . --group dev - -# Install the repository hooks -prek install -``` - -### Using conda +Use an isolated development environment. The [Scientific Python development +guides](https://learn.scientific-python.org/development/) provide general +environment guidance; this repository-specific setup is: ```bash -# Create environment -conda create -n mne-denoise python=3.12 -conda activate mne-denoise - -# Install in editable mode -python -m pip install --upgrade pip python -m pip install -e . --group dev prek install ``` -### Development commands - -The development dependency group includes `uv`-compatible project tooling, -`spin`, and `prek`. Spin is the project task interface, not an environment -manager: - -```bash -spin test # run pytest -spin test -- -k asr # forward arguments to pytest -spin lint # run every repository hook -spin docs # build docs with warnings as errors -spin build # build and validate distributions -spin check # lint, test, and validate distributions -``` - -Use `prek install` once to install the local Git hooks, and -`prek run --all-files` to run them directly. - -## Workflow - -### 1. Create a Branch - -Always create a new branch for your work: - -```bash -# Sync with upstream first -git fetch upstream -git checkout main -git merge upstream/main - -# Create feature branch -git checkout -b feature/my-new-feature -# or for bug fixes: -git checkout -b fix/issue-123 -``` - -### 2. Make Your Changes - -- Write clean, readable code -- Follow the code style guidelines (see below) -- Add tests for new functionality -- Update documentation as needed - -### 3. Commit Your Changes +## Development commands -Write clear, descriptive commit messages: +Use the canonical repository commands: ```bash -git add . -git commit -m "Add support for custom frequency bands in BandpassBias" -``` - -**Commit message guidelines:** - -- Use present tense ("Add feature" not "Added feature") -- Use imperative mood ("Move cursor to..." not "Moves cursor to...") -- Keep the first line under 72 characters -- Reference issues when relevant ("Fix #123: ...") - -### 4. Keep Your Branch Updated - -```bash -git fetch upstream -git rebase upstream/main -``` - -### 5. Add Changelog Entry - -We use [towncrier](https://towncrier.readthedocs.io/) to manage our changelog. This prevents merge conflicts and ensures standardized release notes. - -When you create a Pull Request, add a changelog fragment in -`docs/changes/devel/`. Name it `..rst`, for example -`123.feature.rst`. During local development, an unnumbered `feature.rst` or -`bugfix.rst` can be renamed with `python scripts/rename_towncrier.py ---pr-number 123`; the pull-request automation performs the same conversion. - -For detailed instructions and available types, see [docs/changes/README.md](https://github.com/mne-tools/mne-denoise/blob/main/docs/changes/README.md). - -**Author Attribution**: We encourage contributors to include their name in the changelog entry if they wish to be highlighted. In Markdown, you can link to your GitHub profile (e.g., `... (by [@YourUser](...))`). - -## Code Style - -We use **Ruff** for linting and formatting, configured to follow PEP 8 with NumPy docstring conventions. - -### Automatic Formatting - -Repository hooks automatically format your code on commit. To run them manually: - -```bash -# Run the complete repository quality suite +spin test spin lint - -# Run hooks directly -prek run --all-files -``` - -### Docstring Style - -We use NumPy-style docstrings. Example: - -```python -def compute_dss(data, bias, n_components=None): - """Compute DSS spatial filters. - - Parameters - ---------- - data : ndarray, shape (n_channels, n_times) - Input data matrix. - bias : LinearDenoiser - Bias function that emphasizes signal of interest. - n_components : int, optional - Number of components to return. If None, returns all. - - Returns - ------- - filters : ndarray, shape (n_channels, n_components) - Spatial filters sorted by eigenvalue. - eigenvalues : ndarray, shape (n_components,) - Corresponding eigenvalues. - - Examples - -------- - >>> from mne_denoise.dss import compute_dss, AverageBias - >>> filters, eigenvalues = compute_dss(data, AverageBias()) - - See Also - -------- - DSS : Scikit-learn compatible transformer. - - References - ---------- - .. [1] de CheveignΓ©, A., & Simon, J. Z. (2008). Denoising based on - spatial filtering. Journal of Neuroscience Methods. - """ -``` - -## Testing - -We use **pytest** for testing. All new code should have tests. - -### Running Tests - -```bash -# Run all tests -pytest - -# Run with coverage -pytest --cov=mne_denoise --cov-report=html - -# Run specific test file -pytest tests/test_linear_dss.py - -# Run specific test -pytest tests/test_linear_dss.py::test_dss_epochs -v - -# Run tests matching a pattern -pytest -k "zapline" -v -``` - -### Writing Tests - -- Place tests in the `tests/` directory -- Name test files `test_*.py` -- Name test functions `test_*` -- Use descriptive test names that explain what is being tested -- Use fixtures for common setup -- Plotting tests use the non-interactive Matplotlib backend configured in - `tests/conftest.py`, and figures are closed automatically after each test -- Pass `show=False` when testing plotting functions -- For optional dependencies, prefer `pytest.importorskip(...)` - -#### Test design principles - -- Organize tests around scientific, public API, and integration contracts. -- Keep historical bug scenarios when they protect a durable contract; give - them the contract's owner rather than a separate regression category. -- Keep each test scenario coherent and meaningful. Parametrize independent - scientific modes or layouts, and use labelled loops for equivalent - validation spellings that do not need separate test nodes. -- Prefer deterministic behavioral or numerical assertions over coverage-only - execution, private implementation details, and shape-only checks. -- Keep shared estimator and MNE-container behavior in the central contract - suites. Test MNE metadata and lifecycle behavior at the public boundary, - and keep algorithm-specific numerical behavior with its algorithm tests. -- Preserve distinct scientific regimes as separate scenarios, including - SSP-SIR's blended artifact-window behavior. - -Example test: - -```python -import numpy as np -import pytest -from mne_denoise.dss import DSS, AverageBias - - -@pytest.fixture -def sample_epochs(): - """Create sample epochs for testing.""" - rng = np.random.default_rng(42) - return rng.standard_normal((10, 32, 1000)) - - -def test_dss_retain_reconstructs_all_components(sample_epochs): - """Retaining every fitted component reconstructs the input.""" - dss = DSS(bias=AverageBias(), component_action="retain") - retained = dss.fit_transform(sample_epochs) - - np.testing.assert_allclose(retained, sample_epochs, rtol=1e-9, atol=1e-9) -``` - -### Coverage Reports - -- Use coverage to find untested behavior, but treat it as a diagnostic rather - than a target that overrides meaningful contract tests. -- The CI will report coverage; check the Codecov report on your PR -- View local coverage report: `open htmlcov/index.html` - -## Documentation - -Documentation is built with Sphinx and hosted on GitHub Pages. - -### Building Docs Locally - -```bash -# Build HTML documentation with warnings as errors spin docs - -# Populate the real-data cache before a full gallery build -python scripts/prefetch_docs_data.py - -# View in browser -open docs/_build/html/index.html # macOS -xdg-open docs/_build/html/index.html # Linux -start docs/_build/html/index.html # Windows -``` - -### Documentation Structure - -- `docs/api.rst` - API reference (auto-generated from docstrings) -- `docs/getting-started.rst` - Installation and quick start -- `docs/dss.md` - DSS module guide -- `examples/` - Gallery examples (rendered by sphinx-gallery) - -Documentation CI executes the complete gallery. Its MNE Sample, Somato, and -EEGBCI downloads are prefetched and cached using an inventory-derived key; a -twice-weekly trusted build keeps that cache available to pull requests. When -adding a new real dataset to an example, also add it to -`scripts/prefetch_docs_data.py` so failures happen before Sphinx starts. - -### Adding Examples - -Examples are Python scripts in the `examples/` directory: - -1. Create a file with prefix `plot_` (e.g., `plot_my_example.py`) -2. Follow the sphinx-gallery format with docstring headers -3. Examples are automatically built and included in the gallery - -Example template: - -```python -""" -Title of Example -================ - -Brief description of what this example demonstrates. -""" - -# %% -# Section Header -# -------------- -# Explanation text... - -import mne_denoise - -# Your code here... +spin build +spin check ``` -## Public API and compatibility - -### Public API - -The public API is defined by intentional documentation and canonical public -namespaces, not by every Python name that happens to be importable. - -### Before 1.0 - -Before version 1.0, a formal warning or deprecation cycle is not required. -Contributors changing public API should still: +Focused `pytest` commands are fine during development and debugging. -- explain the reason for the change; -- update tests; -- update documentation; -- add a changelog fragment; -- provide the replacement path or API where relevant. +## Scientific contributions -### Private and experimental names +Changes to scientific algorithms should: -Names or modules beginning with `_` have no compatibility guarantee. -Experimental or research-prototype APIs may evolve more rapidly. +- identify the primary scientific source(s); +- explain intentional deviations or extensions; +- include meaningful numerical or behavioral tests; +- update scientific documentation and docstrings; and +- avoid treating historical output parity alone as evidence of correctness. -### Starting at 1.0 +See [AGENTS.md](https://github.com/mne-tools/mne-denoise/blob/main/AGENTS.md) for the detailed source hierarchy and test +ownership conventions. -Backward-incompatible changes to stable public API should normally go through -a documented deprecation process. +## Tests and public API -## Submitting Changes +New functionality should have appropriate tests. mne-denoise centralizes +shared estimator, MNE-container, public-API, and progress contracts. Before +adding dedicated tests or new public helpers, read [AGENTS.md](https://github.com/mne-tools/mne-denoise/blob/main/AGENTS.md). -### Pull Request Process - -1. **Push your branch** to your fork: - - ```bash - git push origin feature/my-new-feature - ``` - -2. **Open a Pull Request** on GitHub against the `main` branch. - -3. **Fill out the PR template** with: - - Description of changes - - Related issue(s) - - Type of change - - Checklist items - -4. **Wait for CI** to complete. All checks must pass. - -5. **Address review feedback** by pushing additional commits. - -6. **Squash and merge** once approved (maintainers will do this). - -### PR Checklist - -Before submitting, ensure: - -- [ ] Code follows the project style (`spin lint` passes) -- [ ] All tests pass (`pytest` exits cleanly) -- [ ] New code has tests with good coverage -- [ ] Documentation is updated if needed -- [ ] Documentation builds cleanly (`spin docs`) -- [ ] A numbered Towncrier fragment is included for user-facing changes -- [ ] Commit messages are clear and descriptive - -## Issue Guidelines - -### Reporting Bugs - -When reporting a bug, please include: - -1. **Description**: What happened vs. what you expected -2. **Reproduction steps**: Minimal code to reproduce the issue -3. **Environment**: Python version, OS, package versions -4. **Error message**: Full traceback if applicable +## Documentation -Use the bug report template when creating an issue. +Update public-facing documentation, docstrings, and examples when applicable. +Documentation must build without warnings, and primary scientific sources +should support scientific claims. `spin docs` is the canonical full check. -### Requesting Features +## Changelog -For feature requests: +For changes that need a release note, add a fragment under +`docs/changes/devel/` using the `..rst` naming scheme. The available +types are `feature`, `bugfix`, `doc`, `removal`, and `misc`. Do not edit +`CHANGELOG.md` in a pull request. See [docs/changes/README.md](https://github.com/mne-tools/mne-denoise/blob/main/docs/changes/README.md) +for details and local draft instructions. -1. Check if it already exists or is planned -2. Describe the use case and motivation -3. Provide examples of how it would be used -4. Consider if you'd like to implement it yourself +## Pull requests -## Questions? +Keep the pull request focused, reference an issue where applicable, and +explain what changed and why. Disclose AI assistance as described above, run +the relevant checks, and respond to review feedback. Maintainers merge changes +after approval. -- Open a [Discussion](https://github.com/mne-tools/mne-denoise/discussions) for questions -- Check existing issues and discussions first -- Join the [MNE-Python community](https://mne.tools/stable/overview/get_help.html) +## Repository architecture for agents and advanced contributors -Thank you for contributing! +For repository-specific architecture, public API ownership, shared test +contracts, CI expectations, scientific source hierarchy, and guidance for AI +coding agents, see [AGENTS.md](https://github.com/mne-tools/mne-denoise/blob/main/AGENTS.md). diff --git a/README.md b/README.md index f2f16202..fcf774ef 100644 --- a/README.md +++ b/README.md @@ -9,211 +9,80 @@ [![Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://mne.tools/mne-denoise/) [![Downloads](https://pepy.tech/badge/mne-denoise)](https://pepy.tech/project/mne-denoise) -**Artifact removal and signal denoising for EEG and MEG.** - -`mne-denoise` provides spatial, spectral, and statistical methods for removing -artifacts and suppressing noise in EEG and MEG recordings. - -## Features - -### DSS Module - -- **Linear DSS**: Extract components based on reproducibility across trials or characteristic frequencies -- **Iterative DSS**: Powerful nonlinear separation for complex non-Gaussian sources -- **20+ Pluggable Denoisers**: Spectral, temporal, periodic, and ICA-style bias functions -- **Specialized Variants**: TimeShiftDSS, SSVEP enhancement, and narrowband oscillation extraction - -### ZapLine Module - -- **ZapLine**: Efficient removal of power line noise (50/60 Hz) and harmonics -- **ZapLine-plus**: Fully adaptive mode with automatic frequency detection -- **Per-chunk Processing**: Handles non-stationary noise characteristics -- **Quality Assurance**: Built-in spectral checks to prevent over-cleaning - -### Integration - -- **MNE-Python**: Works directly with `Raw`, `Epochs`, and `Evoked` objects or `numpy` arrays. -- **Scikit-Learn API**: Standard `fit()`, `transform()`, `fit_transform()` interface -- **Visualization**: Built-in plotting for components and cleaning results +`mne-denoise` provides artifact-suppression and signal-denoising methods for +EEG and MEG, with NumPy and MNE-Python integration. + +The package contains several complementary methods for spatial, spectral, +statistical, and source-informed denoising. Many methods accept MNE `Raw`, +`Epochs`, and `Evoked` objects directly, and sklearn-style estimators are +provided where that interface fits the method. + +## Methods + +| Method | Typical purpose | +| --- | --- | +| ASR | Detect and reconstruct transient, high-variance artifact subspaces. | +| BSS-CCA | Suppress lagged-correlation components associated with muscle artifacts. | +| DSS | Extract or suppress components selected by reproducibility, spectral, temporal, or other bias functions. | +| iCanClean | Suppress components shared with reference or pseudo-reference channels. | +| SNS | Suppress sensor-specific noise using spatially correlated neighboring channels. | +| SOUND | Suppress channel-specific noise with a forward-model-based Wiener filter. | +| Spectrum interpolation | Attenuate narrow-band line noise by interpolating FFT amplitudes while preserving phase. | +| SSA | Decompose and reconstruct time series for frequency-guided or local artifact cleaning. | +| SSP-SIR | Project an artifact subspace and reconstruct through a forward model, especially for TMS-evoked muscle artifacts. | +| ZapLine | Remove power-line noise and harmonics with DSS, including an adaptive mode. | + +See the [user guide](https://mne.tools/mne-denoise/getting-started.html) and +[API reference](https://mne.tools/mne-denoise/api.html) to choose and +understand a method. Experimental APIs are identified in the documentation. ## Installation -### Base installation - ```bash pip install mne-denoise ``` -### MNE-Python objects +Optional integrations can be installed with extras: ```bash pip install "mne-denoise[mne]" -``` - -### Visualization - -```bash pip install "mne-denoise[viz]" -``` - -### tqdm progress bars - -```bash pip install "mne-denoise[progress]" ``` -Extras can be combined: +## Quick start -```bash -pip install "mne-denoise[mne,viz,progress]" -``` - -### From source (development) - -```bash -git clone https://github.com/mne-tools/mne-denoise.git -cd mne-denoise -python -m pip install --upgrade pip -python -m pip install -e . --group dev -``` - -## Quick Start - -### DSS: Enhancing Evoked Responses - -DSS finds spatial filters that maximize the ratio of reproducible (evoked) to total power: - -The example below uses the optional MNE-Python integration. +The estimator below operates directly on an MNE `Raw` object. Install the +`mne` extra before running it. ```python import mne -from mne_denoise.dss import DSS, AverageBias - -# Load your epoched data -epochs = mne.read_epochs("sample-epo.fif") - -# Create DSS with trial-average bias -dss = DSS(bias=AverageBias(), n_components=5, component_action="extract") -dss.fit(epochs) - -# Option 1: Extract source time courses -sources = dss.transform(epochs) - -# Option 2: Retain the leading two reproducible components in sensor space -enhancer = DSS( - bias=AverageBias(), - n_components=5, - n_select=2, - component_action="retain", -) -enhanced_epochs = enhancer.fit_transform(epochs) -``` +from mne_denoise.spectrum_interpolation import SpectrumInterpolation -### DSS: Extracting Oscillations - -Isolate specific frequency bands (e.g., alpha rhythm): - -```python -from mne_denoise.dss import DSS, BandpassBias - -# Create bandpass bias for alpha (8-12 Hz) -bias = BandpassBias(sfreq=epochs.info["sfreq"], freq=10, bandwidth=4) - -dss = DSS(bias=bias, n_components=3) -alpha_sources = dss.fit_transform(epochs) -``` - -### ZapLine: Removing Line Noise - -Remove 50/60 Hz power line artifacts: - -```python -import mne -from mne_denoise.zapline import ZapLine - -# Load continuous data raw = mne.io.read_raw_fif("sample-raw.fif", preload=True) - -# Standard mode: specify line frequency -zapline = ZapLine(sfreq=raw.info["sfreq"], line_freq=50.0) -cleaned_data = zapline.fit_transform(raw) - -# Adaptive mode: automatic detection and per-chunk processing -zapline_plus = ZapLine( - sfreq=raw.info["sfreq"], - line_freq=None, # Auto-detect - adaptive=True, +cleaner = SpectrumInterpolation( + line_freq=50.0, + n_harmonics=3, ) -cleaned = zapline_plus.fit_transform(raw) -print(f"Detected line frequency: {zapline_plus.detected_freq_} Hz") +clean_raw = cleaner.fit_transform(raw) ``` ## Documentation -Full documentation is available at **[mne.tools/mne-denoise](https://mne.tools/mne-denoise/)**. - -- [Getting Started Guide](https://mne.tools/mne-denoise/getting-started.html) -- [API Reference](https://mne.tools/mne-denoise/api.html) -- [Example Gallery](https://mne.tools/mne-denoise/auto_examples/index.html) - -## πŸ—οΈ Architecture +- [Documentation](https://mne.tools/mne-denoise/) +- [Getting started](https://mne.tools/mne-denoise/getting-started.html) +- [API reference](https://mne.tools/mne-denoise/api.html) +- [Example gallery](https://mne.tools/mne-denoise/auto_examples/index.html) -``` -mne_denoise/ -β”œβ”€β”€ dss/ # Denoising Source Separation -β”‚ β”œβ”€β”€ linear.py # Core DSS algorithm, DSS estimator -β”‚ β”œβ”€β”€ nonlinear.py # Iterative DSS, IterativeDSS estimator -β”‚ β”œβ”€β”€ denoisers/ # 20+ pluggable bias functions -β”‚ β”‚ β”œβ”€β”€ spectral.py # BandpassBias, LineNoiseBias -β”‚ β”‚ β”œβ”€β”€ temporal.py # LagAverageBias, SmoothingBias -β”‚ β”‚ β”œβ”€β”€ periodic.py # CombFilterBias, PeakFilterBias -β”‚ β”‚ └── ... -β”‚ └── variants/ # Pre-built applications -β”‚ β”œβ”€β”€ tsr.py # Time-shift DSS and temporal smoothing -β”‚ β”œβ”€β”€ ssvep.py # SSVEP enhancement -β”‚ └── narrowband.py # Oscillation extraction -β”œβ”€β”€ zapline/ # Line noise removal -β”‚ β”œβ”€β”€ core.py # ZapLine estimator -β”‚ └── adaptive.py # ZapLine-plus utilities -└── viz/ # Visualization tools -``` - -## Testing - -```bash -# Run tests -pytest +## Citing -# With coverage -pytest --cov=mne_denoise --cov-report=html -``` +See the method documentation and its primary references for how to cite +`mne-denoise` and the scientific method(s) used in your analysis. ## Contributing -We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. - -```bash -# Development setup -git clone https://github.com//mne-denoise.git -cd mne-denoise -python -m pip install --upgrade pip -python -m pip install -e . --group dev -prek install -``` - -## References - -### DSS - -> SΓ€relΓ€, J., & Valpola, H. (2005). Denoising source separation. _Journal of Machine Learning Research_, 6, 233-272. - -> de CheveignΓ©, A., & Simon, J. Z. (2008). Denoising based on spatial filtering. _Journal of Neuroscience Methods_, 171(2), 331-339. - -### ZapLine - -> de CheveignΓ©, A. (2020). ZapLine: A simple and effective method to remove power line artifacts. _NeuroImage_, 207, 116356. - -> Klug, M., & Kloosterman, N. A. (2022). Zapline-plus: A completely automatic and highly effective method for removing power line noise. _Human Brain Mapping_, 43(9), 2743-2758. +Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for the +human contribution guide. ## License diff --git a/docs/changes/devel/doc.rst b/docs/changes/devel/doc.rst new file mode 100644 index 00000000..0d494e99 --- /dev/null +++ b/docs/changes/devel/doc.rst @@ -0,0 +1 @@ +Streamlined repository guidance, contributor documentation, and GitHub contribution templates. From 86f1d4d679a62158f13f50f0b317327add78ce18 Mon Sep 17 00:00:00 2001 From: Hamza Abdelhedi Date: Mon, 31 Aug 2026 09:14:01 -0400 Subject: [PATCH 3/5] MAINT simplify GitHub contribution templates --- .github/ISSUE_TEMPLATE/bug_report.md | 34 ----------- .github/ISSUE_TEMPLATE/bug_report.yml | 65 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++ .github/ISSUE_TEMPLATE/documentation.yml | 27 +++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 19 ------- .github/ISSUE_TEMPLATE/feature_request.yml | 35 ++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 40 ++++--------- 7 files changed, 144 insertions(+), 81 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/documentation.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 6fecbeb8..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: "" -labels: "bug" -assignees: "" ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: - -1. Go to '...' -2. Click on '...' -3. Scroll down to '...' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots/Logs** -If applicable, add screenshots or paste error logs to help explain your problem. - -**Environment (please complete the following information):** - -- OS: [e.g. macOS, Windows] -- Python version: [e.g. 3.9] -- MNE-Python version: [e.g. 1.6] -- mne-denoise version: [e.g. 0.0.1] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..e6b569bf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,65 @@ +name: Bug report +description: Report a reproducible problem in mne-denoise. +title: "[BUG] " +labels: + - bug +body: + - type: markdown + attributes: + value: | + Usage and support questions belong on the [MNE Forum](https://mne.discourse.group/). + Use this form for suspected bugs in mne-denoise. + + - type: textarea + id: description + attributes: + label: Description + description: Describe the incorrect behavior and when it occurs. + placeholder: Tell us what went wrong. + validations: + required: true + + - type: textarea + id: reproducible-example + attributes: + label: Minimal reproducible example + description: Provide the smallest runnable example that reproduces the problem. Use the public API. + render: python + validations: + required: true + + - type: textarea + id: data-context + attributes: + label: Data and context (optional) + description: Include data characteristics or a small sample only when they are needed to reproduce the problem. + + - type: textarea + id: expected-result + attributes: + label: Expected result + description: What did you expect to happen? + validations: + required: true + + - type: textarea + id: actual-result + attributes: + label: Actual result + description: What happened? Include the complete traceback or relevant output when available. + render: text + validations: + required: true + + - type: textarea + id: environment + attributes: + label: Environment + description: Include the versions and operating system used for the reproducer. + placeholder: | + Python: + mne-denoise: + MNE-Python (if relevant): + Operating system: + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..709af905 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: MNE Forum + url: https://mne.discourse.group/ + about: Ask usage and support questions in the MNE community forum. diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 00000000..f9aa8f33 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,27 @@ +name: Documentation issue +description: Report unclear, missing, incorrect, or stale documentation. +title: "[DOC] " +body: + - type: input + id: location + attributes: + label: Documentation location + description: Give the page, docstring, example, or API entry where the problem appears. + placeholder: Paste a URL or file and section name. + validations: + required: true + + - type: textarea + id: problem + attributes: + label: Problem + description: What is incorrect, unclear, missing, or stale? + placeholder: Describe the documentation problem. + validations: + required: true + + - type: textarea + id: suggested-improvement + attributes: + label: Suggested improvement (optional) + description: If you have an idea for a correction, share it here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 9b90523f..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: "" -labels: "enhancement" -assignees: "" ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..e0f38f4f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,35 @@ +name: Feature request +description: Suggest a capability or scientific enhancement for mne-denoise. +title: "[ENH] " +labels: + - enhancement +body: + - type: textarea + id: problem + attributes: + label: Problem or scientific use case + description: What are you trying to accomplish, and what is currently missing? + placeholder: Describe the user or scientific need. + validations: + required: true + + - type: textarea + id: desired-behavior + attributes: + label: Desired behavior + description: What capability or change would help? + placeholder: Describe the outcome you would like. + validations: + required: true + + - type: input + id: scientific-reference + attributes: + label: Scientific reference (optional) + description: Add a paper, DOI, or other reference when the request concerns a published method. + + - type: textarea + id: alternatives + attributes: + label: Alternatives and additional context (optional) + description: Share workarounds, alternatives, examples, or other context. Implementation details are not required. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index af4154b1..16a009bd 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,32 +1,16 @@ -# Pull Request + - - +#### Reference issue (if any) -## Related Issue +#### What does this implement/fix? - - - - - -## Type of Change - - - -- [ ] Bug fix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Documentation update - -## Checklist - - - -- [ ] My code follows the code style of this project (`spin lint`) -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] I have run the full test suite and all tests pass -- [ ] I have updated the documentation accordingly (`spin docs` builds without warnings) -- [ ] I have added a numbered Towncrier fragment in `docs/changes/devel/` (if applicable) +#### Additional information From d657d2167a208cf436aa528d0e208fe8fcf15dd8 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 14:13:56 +0000 Subject: [PATCH 4/5] [autofix.ci] apply automated fixes --- docs/changes/devel/{doc.rst => 115.doc.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/changes/devel/{doc.rst => 115.doc.rst} (100%) diff --git a/docs/changes/devel/doc.rst b/docs/changes/devel/115.doc.rst similarity index 100% rename from docs/changes/devel/doc.rst rename to docs/changes/devel/115.doc.rst From 703910733c9708eb4c0774e5c7ee6eca1cbbdd13 Mon Sep 17 00:00:00 2001 From: Hamza Abdelhedi Date: Mon, 31 Aug 2026 11:11:40 -0400 Subject: [PATCH 5/5] DOC make repository guidance more durable --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/ISSUE_TEMPLATE/documentation.yml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yml | 2 +- AGENTS.md | 128 ++++++++++----------- CONTRIBUTING.md | 6 +- README.md | 18 ++- 6 files changed, 78 insertions(+), 80 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e6b569bf..764d732a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug report description: Report a reproducible problem in mne-denoise. -title: "[BUG] " +title: "" labels: - bug body: diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml index f9aa8f33..cd9bb002 100644 --- a/.github/ISSUE_TEMPLATE/documentation.yml +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -1,6 +1,6 @@ name: Documentation issue description: Report unclear, missing, incorrect, or stale documentation. -title: "[DOC] " +title: "" body: - type: input id: location diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index e0f38f4f..6f342816 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,6 @@ name: Feature request description: Suggest a capability or scientific enhancement for mne-denoise. -title: "[ENH] " +title: "" labels: - enhancement body: diff --git a/AGENTS.md b/AGENTS.md index d7c8b337..53407725 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,7 +40,16 @@ When the context is available, determine the parts of the scientific problem tha Do not ask every question in every conversation, but do not ignore these factors when they change the scientific interpretation or API choice. No method is universally best. Explain relevant assumptions, choose the simplest public workflow that fits the goal, and preserve MNE metadata and container semantics. -Do not recommend private helpers when a public estimator or function exists. Distinguish established published methods from mne-denoise-specific extensions and experimental research APIs. On current main, `GuidedASR` and `process_guided_asr` are unpublished, unvalidated experimental research prototypes; the estimator requires explicit experimental opt-in. The SSP-SIR estimator has a validated numerical core but is not independently validated on a public real TMS-EEG dataset, so real-data use is experimental. The `ASR` `method="riemannian"` backend is also explicitly experimental; do not describe these APIs as established defaults. +Do not recommend private helpers when a public estimator or function exists. Distinguish established published methods from mne-denoise-specific extensions and experimental research APIs. + +Honor experimental-status and validation warnings in the current public +docstrings and method documentation. Public availability does not imply that +an API is an established or independently validated scientific method. Do not +recommend experimental or unvalidated research APIs as established defaults. +When scientific validation status matters, inspect the current method +documentation and primary literature before making a recommendation. For +example, an API such as GuidedASR should be presented with that qualification +whenever its current documentation marks it experimental. Artifact attenuation is not evidence that desired neural signal was preserved. Where relevant, encourage users to evaluate both artifact attenuation and preservation of the signal of interest, using suitable controls and scientific knowledge. @@ -101,13 +110,24 @@ Implement behavior at the highest existing owner layer. For example, a generic e Optimize for reviewer comprehension and long-term maintenance, not diff size or output volume. Prefer the smallest change that fully satisfies the issue, and avoid opportunistic cleanup of unrelated code. -If a task starts requiring a new subsystem, dependency, public API family, or many unrelated files, reconsider its scope. Reuse existing test infrastructure before creating new infrastructure. Avoid future-proofing that has no immediate requirement. In particular, do not silently turn a documentation or repository-guidance task into a scientific implementation change. +If a task starts requiring a new subsystem, dependency, public API family, or many unrelated files, reconsider its scope. Reuse existing test infrastructure before creating new infrastructure. Avoid future-proofing that has no immediate requirement. + +Do not expand a focused task into unrelated architecture, public API, +dependencies, algorithms, or upstream work unless the issue or maintainer +explicitly asks for it. Do not silently turn a documentation or +repository-guidance task into a scientific implementation change. ## Public API -The intentional public API is tested in `tests/test_public_api.py`. Current public facades include `mne_denoise`, `asr`, `bss_cca`, `dss`, `dss.denoisers`, `dss.variants`, `dss.segmentation`, `dss.selection`, `icanclean`, `overcorrection`, `progress`, `qa`, `sns`, `sound`, `spectrum_interpolation`, `ssa`, `sspsir`, `viz`, and `zapline`. +The intentional public API is defined and tested in +`tests/test_public_api.py`. Treat its facade and canonical-path registries, +together with the corresponding `__all__` declarations, as the authoritative +inventory. -These facades declare `__all__`. Importability alone does not make a symbol public; canonical import paths are tested explicitly. A new public API requires updates to the appropriate facade, `__all__`, API documentation, tests, and user-facing documentation or the changelog when appropriate. +Public facades declare `__all__`, and canonical public paths are tested +explicitly. Importability alone does not make a symbol public. A new public API +requires updates to the appropriate facade, `__all__`, API documentation, +tests, and user-facing documentation or the changelog when appropriate. Private underscore names have no compatibility promise. Experimental APIs must be clearly identified. Documentation and examples must never invent @@ -169,59 +189,50 @@ Algorithm code emits structured progress events through callback support. `Progr ## Optional dependencies and base-install boundary -The required runtime dependencies are NumPy (`>=1.26,<3`), SciPy (`>=1.13`), -scikit-learn (`>=1.5`), and joblib (`>=1.4`). Published optional extras are: - -- `mne`: MNE-Python (`>=1.12.1`) for MNE container integration. -- `viz`: matplotlib (`>=3.8`) for visualization. -- `progress`: tqdm (`>=4.66`) for the tqdm progress adapter. +`pyproject.toml` is the authoritative source for dependency declarations, +optional extras, dependency groups, and minimum versions. -The dependency groups in `pyproject.toml` are `lockfile_extras`, `test`, -`doc`, `build`, `lint`, `changelog`, and `dev`. The lockfile group covers -optional runtime packages for lower-bound checks; `test` adds pytest, -coverage, timeout, pandas, and seaborn; `doc` adds MNE and documentation -tooling; `build` adds distribution tooling; `lint` adds `prek` and `spin`; -`changelog` adds towncrier; and `dev` combines the development groups with -pip. +The important compatibility boundary is that the base package remains usable +without optional MNE, visualization, or progress dependencies. MNE +integration, visualization, and the tqdm progress adapter remain optional. +Optional dependencies must not be imported eagerly in a way that breaks base +import. `scripts/check_base_install.py` tests this boundary. -The base package must remain usable without MNE, matplotlib, or tqdm. -Optional dependencies must not be imported eagerly in a way that makes base -import fail. MNE-Python integration, plotting, and tqdm remain optional, and -the minimum versions are deliberate compatibility commitments. - -`scripts/check_base_install.py` verifies this boundary, including that the -base installation can import the package and that the visualization namespace -gives actionable optional-dependency guidance. Preserve this boundary in all -changes. +Do not raise dependency floors or promote an optional dependency to required +without a concrete compatibility reason. ## Continuous integration -The matrix in `.github/workflows/tests.yml` protects different compatibility -properties rather than repeating one test run: - -- A lint job runs the complete `prek` hook suite on Ubuntu with Python 3.14. -- A base-install job uses Python 3.12, installs only the package, and runs - `scripts/check_base_install.py`. -- A minimum-dependencies job validates the lower-bound lockfile on Python - 3.12 and runs the tests. -- The stable matrix covers Ubuntu Python 3.13, Ubuntu Python 3.14 with the - coverage upload, Windows Python 3.14, and macOS ARM Python 3.14. -- An MNE-main job installs MNE-Python main over the stable test environment - and runs the tests. -- A scientific-dependency prerelease job upgrades the scientific stack and is - allowed to report failures without blocking required jobs. - -`.github/workflows/docs.yml` builds the full gallery against both released -MNE and MNE main, prefetching the MNE Sample, Somato, and EEGBCI datasets. +The workflow files are the authoritative source for the exact Python versions, +platforms, and dependency combinations. The matrix in +`.github/workflows/tests.yml` intentionally protects different compatibility +dimensions rather than repeating one test run: + +- Lint checks the complete repository hook suite. +- Base-install checks protect the package boundary without optional extras. +- Minimum-dependency jobs protect declared lower bounds. +- Stable jobs cover supported Python and platform combinations. +- Coverage measures the supported test suite. +- MNE-main jobs check compatibility with upcoming MNE changes. +- Scientific-dependency prereleases expose forward-compatibility problems. + +`.github/workflows/docs.yml` builds the full gallery against both released MNE +and MNE main. Stable-MNE and MNE-main documentation jobs protect both +documentation compatibility dimensions. Documentation CI prefetches and +caches the real datasets required by the gallery; `scripts/prefetch_docs_data.py` +and the docs workflow are the authoritative inventory. When an example +introduces a new real dataset, update the prefetch mechanism in the same +change. + The release workflow builds and validates distributions and tests an installed wheel before publishing on a GitHub release. The changelog workflow checks Towncrier fragments, and dependency review rejects high-severity dependency findings. Passing one local environment is not sufficient evidence of repository -compatibility. Do not fix CI failures by raising dependency floors without -justification, removing platform coverage, weakening optional-dependency -boundaries, disabling tests, or allowing failures on required jobs. +compatibility. Do not weaken CI, remove platform coverage, raise dependency +floors just to fix CI, disable tests, or turn required jobs into informational +jobs. ## Repository task commands @@ -292,9 +303,10 @@ the implementation or contracts do not provide, or misstate copy versus in-place semantics and `fit`/`transform` lifecycle. Document experimental status where appropriate. -PR 2 will perform a callable-by-callable public docstring audit. Existing -docstrings are not authoritative when they disagree with implementation, -tests, or scientific sources. +When changing or reviewing public API, audit public docstrings callable by +callable against the implementation, tests, and relevant scientific sources. +Existing docstrings are not authoritative when they disagree with those +sources of truth. ## Examples and gallery @@ -308,8 +320,9 @@ examples. New real-data dependencies must use the documentation data prefetch/cache mechanism. Add datasets to `scripts/prefetch_docs_data.py` when an example needs them. Examples must use public APIs and should not preserve obsolete -APIs merely to avoid changing docs. Do not introduce a `tutorials/` directory -as part of this documentation refactor. +APIs merely to avoid changing docs. Prefer the existing documentation and +gallery structure unless a change in information architecture is explicitly +part of the task. ## Repository scripts and generated artifacts @@ -319,19 +332,6 @@ Generated changelog, release, and citation artifacts should be maintained by their owning tooling rather than hand-edited where applicable. Old parity builders are not part of the current architecture. -## Deferred / out-of-scope architecture - -Do not expand a task into these areas unless the issue or maintainer explicitly -asks for it: - -- A broader SSP-SIR/MNE-Python redesign. -- Upstream generic MNE helper work that is not necessary for the current task. -- A repository-wide typing or type-checker migration. -- Historical parity infrastructure. -- Unrelated new denoising algorithms. - -These are deferred categories, not a prohibition on legitimate future work. - ## Git and pull-request expectations Never commit directly to `main`. Keep pull requests focused and use existing diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a85f9c9..247140e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,9 +9,9 @@ maintenance. Please search existing issues and discussions first. - Usage and support questions belong on the [MNE Forum](https://mne.discourse.group/). -- Reproducible bugs belong in the [bug report form](https://github.com/mne-tools/mne-denoise/blob/main/.github/ISSUE_TEMPLATE/bug_report.yml). -- Feature or scientific enhancement ideas belong in the [feature request form](https://github.com/mne-tools/mne-denoise/blob/main/.github/ISSUE_TEMPLATE/feature_request.yml). -- Documentation problems belong in the [documentation form](https://github.com/mne-tools/mne-denoise/blob/main/.github/ISSUE_TEMPLATE/documentation.yml). +- Reproducible bugs belong in the [bug report form](https://github.com/mne-tools/mne-denoise/issues/new?template=bug_report.yml). +- Feature or scientific enhancement ideas belong in the [feature request form](https://github.com/mne-tools/mne-denoise/issues/new?template=feature_request.yml). +- Documentation problems belong in the [documentation form](https://github.com/mne-tools/mne-denoise/issues/new?template=documentation.yml). ## Code of Conduct and communication diff --git a/README.md b/README.md index fcf774ef..8e3a9947 100644 --- a/README.md +++ b/README.md @@ -52,18 +52,15 @@ pip install "mne-denoise[progress]" ## Quick start -The estimator below operates directly on an MNE `Raw` object. Install the -`mne` extra before running it. +The example assumes that `raw` is an MNE `Raw` object loaded with +`preload=True`; install the `mne` extra to use it. ```python -import mne from mne_denoise.spectrum_interpolation import SpectrumInterpolation -raw = mne.io.read_raw_fif("sample-raw.fif", preload=True) -cleaner = SpectrumInterpolation( - line_freq=50.0, - n_harmonics=3, -) +# `raw` is an mne.io.Raw object loaded with preload=True. +# Set line_freq to the mains frequency in your recording. +cleaner = SpectrumInterpolation(line_freq=60.0, n_harmonics=3) clean_raw = cleaner.fit_transform(raw) ``` @@ -76,8 +73,9 @@ clean_raw = cleaner.fit_transform(raw) ## Citing -See the method documentation and its primary references for how to cite -`mne-denoise` and the scientific method(s) used in your analysis. +When using mne-denoise in scientific work, cite the primary publication(s) for +the method(s) used in your analysis. Method-specific references are provided +in the documentation. ## Contributing