Skip to content

fix: overloads, WeightingFilter multichannel zi, version sync & SonarCloud CI#45

Merged
jmrplens merged 4 commits intomainfrom
fix/overloads-and-preexisting-issues
Mar 8, 2026
Merged

fix: overloads, WeightingFilter multichannel zi, version sync & SonarCloud CI#45
jmrplens merged 4 commits intomainfrom
fix/overloads-and-preexisting-issues

Conversation

@jmrplens
Copy link
Owner

@jmrplens jmrplens commented Mar 8, 2026

Summary

This PR addresses preexisting issues found after merging PR #42 (stateful block-wise processing).

Fixes

1. Missing @overload signatures in OctaveFilterBank (core.py)

  • Added the missing calculate_level: Literal[True] overloads so that mypy correctly resolves the return type when calling octave_filter_bank(..., calculate_level=True).
  • Now 4 clean overloads covering all sigbands × calculate_level combinations.

2. WeightingFilter multichannel zi bug (parametric_filters.py)

  • The filter state (zi) was initialized with a shape hardcoded for single-channel input (n_sections, 1, 2).
  • scipy.sosfilt requires (n_sections, n_channels, 2) for multichannel signals.
  • Implemented lazy zi initialization: allocation is deferred to the first filter() call where the actual channel count is known, with automatic re-allocation on shape mismatch.

3. Version sync (__init__.py)

  • __version__ was still "1.1.2" — updated to "1.1.4" to match the tagged release.

4. SonarCloud CI fix (.github/workflows/python-app.yml)

  • Pinned SonarSource/sonarqube-scan-action from @master (unstable) to @v7 (stable, recommended by SonarCloud docs).
  • Replaced custom secrets.TOKEN_GH with standard secrets.GITHUB_TOKEN (auto-available in all workflows).

Tests

  • Updated test_weighting_filter_steady_ic_initialization for lazy init pattern.
  • Added test_weighting_filter_multichannel (4-channel, 2 consecutive blocks).
  • All 94 tests pass locally ✅

CI checks (local)

  • ruff
  • mypy ✅ (0 errors)
  • bandit
  • pytest 94/94 ✅

Summary by Sourcery

Align type hints, stateful filtering behavior, versioning, and CI configuration with expected usage and releases.

Bug Fixes:

  • Correct WeightingFilter state initialization to support stateful block-wise processing for both single- and multi-channel inputs.
  • Fix OctaveFilterBank.filter overload signatures so static type checking resolves return types correctly when calculate_level is used.

Enhancements:

  • Update tests to cover lazy initialization of WeightingFilter state and multichannel block-wise processing consistency.

CI:

  • Pin the SonarCloud scan GitHub Action to a stable version and use the standard GITHUB_TOKEN secret.

Chores:

  • Bump the library version constant to 1.1.4 to match the tagged release.

Summary by CodeRabbit

  • Chores

    • Updated package version to 1.1.4
    • Enhanced CI/CD workflow configurations and dependency versions for improved code analysis
  • Improvements

    • Optimized filter state initialization to reduce memory overhead and improve performance
    • Strengthened type annotations for filtering methods to enable better IDE support
  • Tests

    • Expanded test coverage with new stateful filtering scenarios including multichannel audio processing

jmrplens added 2 commits March 8, 2026 06:15
- Add missing calculate_level=True overloads so mypy resolves explicit
  calculate_level=True calls correctly (4 clean overloads covering all
  sigbands × calculate_level combinations)
- Fix WeightingFilter multichannel zi bug: lazy allocation deferred to
  filter() so channel dimension matches actual input shape (same pattern
  as OctaveFilterBank)
- Sync __version__ from '1.1.2' to '1.1.4' to match pyproject.toml
- Update WeightingFilter tests for lazy init + add multichannel test
- Change SonarSource/sonarqube-scan-action@master to @v7 (stable)
- Replace secrets.TOKEN_GH with secrets.GITHUB_TOKEN (auto-available)
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 8, 2026

Reviewer's Guide

Adds missing type overloads for OctaveFilterBank.filter, fixes multichannel state handling in WeightingFilter via lazy zi initialization, updates tests accordingly, bumps the package version to 1.1.4, and stabilizes the SonarCloud GitHub Action configuration.

Sequence diagram for lazy zi initialization in WeightingFilter.filter

sequenceDiagram
    actor Caller
    participant WeightingFilter
    participant SciPy_signal

    Caller->>WeightingFilter: filter(x)
    WeightingFilter->>WeightingFilter: x_proc = _typesignal(x)
    WeightingFilter->>WeightingFilter: if not stateful
    alt stateful is False
        WeightingFilter->>SciPy_signal: sosfilt(sos, x_proc, axis=-1)
        SciPy_signal-->>WeightingFilter: y
        WeightingFilter-->>Caller: y
    else stateful is True
        WeightingFilter->>WeightingFilter: n_sections = sos.shape[0]
        WeightingFilter->>WeightingFilter: needs_init = zi.size == 0
        WeightingFilter->>WeightingFilter: if x_proc is multichannel
        alt multichannel and shape mismatch
            WeightingFilter->>WeightingFilter: needs_init = True
        else no mismatch
            WeightingFilter->>WeightingFilter: keep existing zi
        end
        alt needs_init and x_proc is 1D
            WeightingFilter->>WeightingFilter: init zi (n_sections, 2) or steady sosfilt_zi
        else needs_init and x_proc is 2D
            WeightingFilter->>WeightingFilter: init zi (n_sections, n_channels, 2) or tiled steady zi
        end
        WeightingFilter->>SciPy_signal: sosfilt(sos, x_proc, axis=-1, zi=zi)
        SciPy_signal-->>WeightingFilter: y, zi_new
        WeightingFilter->>WeightingFilter: zi = zi_new
        WeightingFilter-->>Caller: y
    end
Loading

Class diagram for updated WeightingFilter and OctaveFilterBank.filter

classDiagram
    class WeightingFilter {
        - sos: np.ndarray
        - stateful: bool
        - zi: np.ndarray
        - _steady_ic: bool
        + WeightingFilter(fs: int, curve: str, stateful: bool, steady_ic: bool)
        + filter(x: List[float] | np.ndarray) np.ndarray
    }

    class OctaveFilterBank {
        + filter(x: List[float] | np.ndarray, sigbands: bool, mode: str, detrend: bool, calculate_level: bool) Tuple
    }

    WeightingFilter ..> OctaveFilterBank: both provide filter functionality
Loading

File-Level Changes

Change Details Files
Add complete type-safe overloads for OctaveFilterBank.filter to cover calculate_level combinations.
  • Extend existing filter overloads to include calculate_level: Literal[True] in the True/False sigbands variants.
  • Add overloads for calculate_level: Literal[False] for both sigbands True and False cases, adjusting return types appropriately.
  • Align the concrete filter implementation signature with the overloads, including calculate_level defaulting to True.
src/pyoctaveband/core.py
Implement lazy, shape-aware zi initialization for stateful WeightingFilter to correctly support multichannel inputs.
  • Change stateful WeightingFilter init to defer zi allocation and track steady_ic via a new _steady_ic flag.
  • Update filter() to initialize zi on first call based on input dimensionality and channel count, including reallocating when the channel dimension changes.
  • Handle both steady and non-steady initial conditions for 1D and multichannel inputs, using sosfilt_zi and tiling as needed.
  • Document that filter accepts 1D or 2D [channels, samples] input and pass zi into signal.sosfilt for stateful processing.
src/pyoctaveband/parametric_filters.py
Adjust tests to reflect lazy zi initialization and to validate correct multichannel stateful behavior.
  • Update test_weighting_filter_steady_ic_initialization to assert zi is empty before first filter() call, then sized to (n_sections, 2) after filtering a 1D signal.
  • Add test_weighting_filter_multichannel to compare block-wise stateful multichannel filtering against a stateless full-signal reference across multiple blocks.
tests/test_stateful_weighting_filter.py
Synchronize library version constant with the 1.1.4 release.
  • Update version from 1.1.2 to 1.1.4.
src/pyoctaveband/__init__.py
Stabilize SonarCloud CI configuration for GitHub Actions.
  • Pin SonarSource/sonarqube-scan-action from the moving master branch to the v7 tag.
  • Switch SonarCloud job to use the standard secrets.GITHUB_TOKEN instead of a custom TOKEN_GH secret.
.github/workflows/python-app.yml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link

coderabbitai bot commented Mar 8, 2026

Warning

Rate limit exceeded

@jmrplens has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 19 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 41aadabe-9c83-4345-825e-57eb2cef83bf

📥 Commits

Reviewing files that changed from the base of the PR and between 078f313 and ff2f3f5.

📒 Files selected for processing (4)
  • .github/workflows/python-app.yml
  • pyproject.toml
  • src/pyoctaveband/parametric_filters.py
  • tests/test_stateful_weighting_filter.py
📝 Walkthrough

Walkthrough

This PR updates the package version to 1.1.4, refines GitHub Actions workflow configuration for SonarCloud scanning, updates OctaveFilterBank.filter type hints to include the calculate_level parameter in all overloads, implements lazy initialization of filter state in WeightingFilter, and adds comprehensive tests for multichannel stateful filtering behavior.

Changes

Cohort / File(s) Summary
Workflow Configuration
.github/workflows/python-app.yml
Updated SonarCloud action reference from @master to @v7 and changed GITHUB_TOKEN secret reference from TOKEN_GH to GITHUB_TOKEN.
Version Update
src/pyoctaveband/__init__.py
Bumped package version from 1.1.2 to 1.1.4.
Type Hints & Overloads
src/pyoctaveband/core.py
Updated all four filter method overloads in OctaveFilterBank to include the calculate_level parameter with appropriate Literal type hints and adjusted return types accordingly.
Stateful Filter Initialization
src/pyoctaveband/parametric_filters.py
Implemented lazy initialization of filter state (zi) in WeightingFilter, deferring allocation until first call with actual input shape known, supporting both 1D and multichannel 2D inputs.
Stateful Filter Tests
tests/test_stateful_weighting_filter.py
Reworked test expectations for lazy zi initialization and added new test validating multichannel stateful filtering with block-wise processing.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested labels

Review effort 2/5

Poem

🐰 A version hops from two to four,
Type hints bloom and workflows soar!
Filter states now lazy-load with grace,
Multichannel tests find their place. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes all major changes in the PR: overload signatures, WeightingFilter multichannel fix, version sync, and SonarCloud CI updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/overloads-and-preexisting-issues

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves several issues that arose after the introduction of stateful block-wise processing. It enhances type safety by refining method overloads, fixes a critical bug in multichannel filter state management, and ensures the project's version is synchronized. Additionally, it improves the reliability of the continuous integration pipeline.

Highlights

  • Type Hinting Fix: Missing @overload signatures for the OctaveFilterBank.filter method have been added to ensure mypy correctly resolves return types when calculate_level is True.
  • Multichannel Filter State (zi) Bug Fix: The WeightingFilter now uses lazy initialization for its filter state (zi), deferring allocation until the first filter() call. This correctly sizes zi for multichannel inputs, addressing a previous bug where it was hardcoded for single-channel signals.
  • Version Synchronization: The package version in __init__.py has been updated from 1.1.2 to 1.1.4 to match the latest tagged release.
  • CI/CD Pipeline Improvement: The SonarCloud CI workflow has been updated by pinning the SonarSource/sonarqube-scan-action to a stable version (@v7) and replacing secrets.TOKEN_GH with the standard secrets.GITHUB_TOKEN.
Changelog
  • src/pyoctaveband/init.py
    • Updated the package version to 1.1.4.
  • src/pyoctaveband/core.py
    • Added missing @overload signatures for OctaveFilterBank.filter to correctly resolve return types when calculate_level is True.
  • src/pyoctaveband/parametric_filters.py
    • Implemented lazy zi initialization in WeightingFilter to correctly size the filter state for multichannel inputs, resolving a bug where zi was hardcoded for single-channel.
  • tests/test_stateful_weighting_filter.py
    • Updated test_weighting_filter_steady_ic_initialization to account for lazy zi initialization.
    • Added test_weighting_filter_multichannel to verify correct behavior with multichannel signals.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/python-app.yml
Activity
  • Updated test_weighting_filter_steady_ic_initialization to align with the new lazy initialization pattern.
  • Added test_weighting_filter_multichannel to validate multichannel processing.
  • All 94 existing tests passed locally.
  • Local ruff checks passed.
  • Local mypy checks passed with 0 errors.
  • Local bandit checks passed.
  • Local pytest checks passed (94/94 tests).
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/pyoctaveband/parametric_filters.py" line_range="90-99" />
<code_context>
+        # Initialize filter state for stateful block-wise processing.
+        # Uses lazy allocation: zi is sized on first filter() call so that
+        # the channel dimension matches the actual input shape.
         if self.stateful:
-            if not steady_ic:
-                self.zi = np.zeros((self.sos.shape[0], 2))
</code_context>
<issue_to_address>
**issue (bug_risk):** Stateful `zi` shape is not updated when switching from multi-channel to 1D input, which can break `sosfilt`.

The lazy-init logic correctly handles 1D → multi-channel and channel-count changes, but not the reverse. If `zi` was initialized for multi-channel `(n_sections, n_channels, 2)` and a later call uses 1D input, `needs_init` remains `False` and the 3D `zi` is reused.

For 1D `x_proc` with `axis=-1`, `scipy.signal.sosfilt` requires `zi` of shape `(n_sections, 2)`, so this reuse can cause errors or incorrect filtering. Please extend the `needs_init` condition to also cover multi-channel → 1D transitions, e.g. reset when `self.zi.ndim == 3 and x_proc.ndim == 1`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several valuable fixes, including correcting function overloads, updating the version, and improving the CI workflow. The lazy initialization for the WeightingFilter to support multichannel audio is a great improvement. However, I've identified a bug in the new lazy initialization logic that can cause a crash when switching from multichannel to single-channel processing. I've provided a detailed comment with a suggested fix for this issue.

Comment on lines +108 to +110
needs_init = self.zi.size == 0
if not needs_init and x_proc.ndim > 1:
needs_init = self.zi.ndim < 3 or self.zi.shape[1] != x_proc.shape[0]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current logic for lazy initialization of the filter state zi does not correctly handle switching from a multi-channel input to a single-channel input. If the filter is first used with a 2D array (multi-channel) and then with a 1D array (single-channel), needs_init will remain False. This will cause sosfilt to be called with a 3D zi and a 1D signal, which raises a ValueError.

The logic to determine if zi needs re-initialization should be updated to cover all cases of shape mismatch between the input signal and the filter state. Here is a suggested replacement that correctly handles all transitions between single-channel and multi-channel inputs:

Suggested change
needs_init = self.zi.size == 0
if not needs_init and x_proc.ndim > 1:
needs_init = self.zi.ndim < 3 or self.zi.shape[1] != x_proc.shape[0]
needs_init = self.zi.size == 0
if not needs_init:
if x_proc.ndim == 1:
# Input is 1D, zi must be 2D
if self.zi.ndim != 2:
needs_init = True
else: # x_proc.ndim > 1
# Input is 2D, zi must be 3D with matching channel count
if self.zi.ndim != 3 or self.zi.shape[1] != x_proc.shape[0]:
needs_init = True

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
macos-latest-3.13 94 0 0.0% ✅ Passed
ubuntu-latest-3.13 94 0 0.0% ✅ Passed
windows-latest-3.13 94 0 0.0% ✅ Passed

Technical Benchmark Summary

📊 View Benchmark Details

PyOctaveBand: Technical Benchmark Report

Generated: 2026-03-08 05:26:08

1. Test Signal Parameters

  • Sample Rate: 96.0 kHz
  • Duration: 10.0 seconds
  • Signal Types: White Noise (Stability) / Pure Sine (Precision)
  • Precision: 64-bit Floating Point

2. Crossover (Linkwitz-Riley)

Crossover

  • Flatness Error: 0.000000 dB (Target < 0.01)

3. Precision & Isolation

Precision

Type Error (dB) Isolation Ripple GD Std (ms)
butter 2.46e-03 31.3 dB 0.2705 dB 2847.826
cheby1 3.38e-03 40.5 dB 0.1000 dB 3551.677
cheby2 3.26e-03 57.8 dB 29.4187 dB 4790.013
ellip 9.41e-03 54.2 dB 0.1000 dB 4700.881
bessel 5.20e-01 32.5 dB 5.9845 dB 1380.212

4. Performance

Performance

Channels Exec Time (s) Speedup
1 0.626 1.00x
2 1.231 1.02x
4 2.434 1.03x
8 4.850 1.03x
16 9.673 1.04x

View Full Artifacts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/test_stateful_weighting_filter.py (1)

6-11: ⚠️ Potential issue | 🟡 Minor

Misplaced docstring.

The docstring is placed after the from pyoctaveband import WeightingFilter import statement. Docstrings should be the first statement inside a function, before any other code.

📝 Proposed fix
 `@pytest.mark.parametrize`("block_size", [8, 256, 1024])
 `@pytest.mark.parametrize`("filter_type", ["A", "C", "Z"])
 def test_weighting_filter_block_processing_matches_full_signal(block_size: int, filter_type: str):
+    """
+    Ensure that block-wise processing with preserved filter state
+    produces the same result as filtering the full signal at once.
+    """
     from pyoctaveband import WeightingFilter
-    """
-    Ensure that block-wise processing with preserved filter state
-    produces the same result as filtering the full signal at once.
-    """
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_stateful_weighting_filter.py` around lines 6 - 11, The function
test_weighting_filter_block_processing_matches_full_signal has its docstring
placed after the import; move the triple-quoted docstring to be the first
statement inside the function (before the line "from pyoctaveband import
WeightingFilter") so the docstring is the function's official docstring and the
import follows it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pyoctaveband/parametric_filters.py`:
- Around line 106-124: The lazy init misses the case when input goes from
multichannel to single-channel causing a zi shape mismatch; update the init
check around self.zi and x_proc so that if x_proc.ndim == 1 and self.zi.ndim ==
3 (zi has shape (n_sections, n_channels, 2)) you set needs_init = True (or
otherwise reinitialize/reshape zi to 2D) before calling signal.sosfilt;
reference the existing symbols self.zi, x_proc, n_sections, signal.sosfilt_zi
and signal.sosfilt to locate and implement this additional dimension-mismatch
branch.

In `@tests/test_stateful_weighting_filter.py`:
- Around line 58-61: Move the function docstring so it appears immediately after
the def line in test_weighting_filter_multichannel and before the import;
currently the triple-quoted docstring is placed after the local import of
WeightingFilter, so relocate the docstring to directly follow def
test_weighting_filter_multichannel(): to comply with proper docstring placement
for the test and leave the from pyoctaveband import WeightingFilter import
statement below it.

---

Outside diff comments:
In `@tests/test_stateful_weighting_filter.py`:
- Around line 6-11: The function
test_weighting_filter_block_processing_matches_full_signal has its docstring
placed after the import; move the triple-quoted docstring to be the first
statement inside the function (before the line "from pyoctaveband import
WeightingFilter") so the docstring is the function's official docstring and the
import follows it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 14937585-337c-448d-9593-bc3ffb0e2b9a

📥 Commits

Reviewing files that changed from the base of the PR and between 0a3d317 and 078f313.

📒 Files selected for processing (5)
  • .github/workflows/python-app.yml
  • src/pyoctaveband/__init__.py
  • src/pyoctaveband/core.py
  • src/pyoctaveband/parametric_filters.py
  • tests/test_stateful_weighting_filter.py

Comment on lines +58 to +61
def test_weighting_filter_multichannel():
from pyoctaveband import WeightingFilter
"""Stateful block-wise multichannel weighting must match full-signal processing."""
rng = np.random.default_rng(99)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same docstring placement issue.

The docstring should be moved before the import statement.

📝 Proposed fix
 def test_weighting_filter_multichannel():
+    """Stateful block-wise multichannel weighting must match full-signal processing."""
     from pyoctaveband import WeightingFilter
-    """Stateful block-wise multichannel weighting must match full-signal processing."""
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_weighting_filter_multichannel():
from pyoctaveband import WeightingFilter
"""Stateful block-wise multichannel weighting must match full-signal processing."""
rng = np.random.default_rng(99)
def test_weighting_filter_multichannel():
"""Stateful block-wise multichannel weighting must match full-signal processing."""
from pyoctaveband import WeightingFilter
rng = np.random.default_rng(99)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_stateful_weighting_filter.py` around lines 58 - 61, Move the
function docstring so it appears immediately after the def line in
test_weighting_filter_multichannel and before the import; currently the
triple-quoted docstring is placed after the local import of WeightingFilter, so
relocate the docstring to directly follow def
test_weighting_filter_multichannel(): to comply with proper docstring placement
for the test and leave the from pyoctaveband import WeightingFilter import
statement below it.

…age paths

- Fix needs_init to handle all ndim transitions (1D↔2D) in WeightingFilter
- Add [tool.coverage.run] relative_files=true so coverage.xml uses relative
  source paths matching sonar.sources=src
- Add test_weighting_filter_multichannel_to_mono_transition test
@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
macos-latest-3.13 95 0 0.0% ✅ Passed
ubuntu-latest-3.13 95 0 0.0% ✅ Passed
windows-latest-3.13 95 0 0.0% ✅ Passed

Technical Benchmark Summary

📊 View Benchmark Details

PyOctaveBand: Technical Benchmark Report

Generated: 2026-03-08 05:44:19

1. Test Signal Parameters

  • Sample Rate: 96.0 kHz
  • Duration: 10.0 seconds
  • Signal Types: White Noise (Stability) / Pure Sine (Precision)
  • Precision: 64-bit Floating Point

2. Crossover (Linkwitz-Riley)

Crossover

  • Flatness Error: 0.000000 dB (Target < 0.01)

3. Precision & Isolation

Precision

Type Error (dB) Isolation Ripple GD Std (ms)
butter 2.46e-03 31.3 dB 0.2705 dB 2847.826
cheby1 3.38e-03 40.5 dB 0.1000 dB 3551.677
cheby2 3.26e-03 57.8 dB 29.4187 dB 4790.013
ellip 9.41e-03 54.2 dB 0.1000 dB 4700.881
bessel 5.20e-01 32.5 dB 5.9845 dB 1380.212

4. Performance

Performance

Channels Exec Time (s) Speedup
1 0.631 1.00x
2 1.235 1.02x
4 2.445 1.03x
8 4.882 1.03x
16 9.684 1.04x

View Full Artifacts

…coverage

- Extract _init_filter_state() and _needs_zi_reinit() helpers from filter()
  to reduce Cognitive Complexity from 26 to ~5 (SonarCloud max: 15)
- Change pip install to editable mode (-e) so coverage can trace src/ code
  (fixes 'No data was collected' warning and 0% new_coverage in SonarCloud)
@jmrplens jmrplens force-pushed the fix/overloads-and-preexisting-issues branch from 1308e22 to ff2f3f5 Compare March 8, 2026 05:47
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 8, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
macos-latest-3.13 95 0 99.5% ✅ Passed
ubuntu-latest-3.13 95 0 99.5% ✅ Passed
windows-latest-3.13 95 0 99.5% ✅ Passed

Technical Benchmark Summary

📊 View Benchmark Details

PyOctaveBand: Technical Benchmark Report

Generated: 2026-03-08 05:50:12

1. Test Signal Parameters

  • Sample Rate: 96.0 kHz
  • Duration: 10.0 seconds
  • Signal Types: White Noise (Stability) / Pure Sine (Precision)
  • Precision: 64-bit Floating Point

2. Crossover (Linkwitz-Riley)

Crossover

  • Flatness Error: 0.000000 dB (Target < 0.01)

3. Precision & Isolation

Precision

Type Error (dB) Isolation Ripple GD Std (ms)
butter 2.46e-03 31.3 dB 0.2705 dB 2847.826
cheby1 3.38e-03 40.5 dB 0.1000 dB 3551.677
cheby2 3.26e-03 57.8 dB 29.4187 dB 4790.013
ellip 9.41e-03 54.2 dB 0.1000 dB 4700.881
bessel 5.20e-01 32.5 dB 5.9845 dB 1380.212

4. Performance

Performance

Channels Exec Time (s) Speedup
1 0.638 1.00x
2 1.242 1.03x
4 2.454 1.04x
8 4.874 1.05x
16 9.701 1.05x

View Full Artifacts

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
macos-latest-3.13 95 0 99.5% ✅ Passed
ubuntu-latest-3.13 95 0 99.5% ✅ Passed
windows-latest-3.13 95 0 99.5% ✅ Passed

Technical Benchmark Summary

📊 View Benchmark Details

PyOctaveBand: Technical Benchmark Report

Generated: 2026-03-08 05:51:19

1. Test Signal Parameters

  • Sample Rate: 96.0 kHz
  • Duration: 10.0 seconds
  • Signal Types: White Noise (Stability) / Pure Sine (Precision)
  • Precision: 64-bit Floating Point

2. Crossover (Linkwitz-Riley)

Crossover

  • Flatness Error: 0.000000 dB (Target < 0.01)

3. Precision & Isolation

Precision

Type Error (dB) Isolation Ripple GD Std (ms)
butter 2.46e-03 31.3 dB 0.2705 dB 2847.826
cheby1 3.38e-03 40.5 dB 0.1000 dB 3551.677
cheby2 3.26e-03 57.8 dB 29.4187 dB 4790.013
ellip 9.41e-03 54.2 dB 0.1000 dB 4700.881
bessel 5.20e-01 32.5 dB 5.9845 dB 1380.212

4. Performance

Performance

Channels Exec Time (s) Speedup
1 0.630 1.00x
2 1.231 1.02x
4 2.445 1.03x
8 4.864 1.04x
16 9.680 1.04x

View Full Artifacts

@jmrplens jmrplens merged commit 3b2fded into main Mar 8, 2026
15 checks passed
@jmrplens jmrplens deleted the fix/overloads-and-preexisting-issues branch March 8, 2026 05:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant