Skip to content

Conversation

@d-chambers
Copy link
Contributor

@d-chambers d-chambers commented Sep 4, 2025

Description

This PR fixes a few small bugs:

  • fixes PatchAttr update when explicitly passed a CoordManager as coords to just use that CoordManager
  • Allows overlap to be None in Patch.stft
  • Added some integration tests.

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes.
  • documented the new feature with docstrings or appropriate doc page.
  • included a test. See testing guidelines.
  • your name has been added to the contributors page (docs/contributors.md).
  • added the "ready_for_review" tag once the PR is ready to be reviewed.

Summary by CodeRabbit

  • New Features

    • STFT now accepts overlap=None (explicit 0-overlap option).
    • Dimension inference improved when updating coordinates/attributes.
  • Bug Fixes

    • Coordinate summaries now stay in sync after updates, removals, and squeeze operations.
    • Update paths handle empty attribute mappings more consistently.
  • Documentation

    • Typos and wording clarified in slope_filter docs.
  • Tests

    • Unit and integration tests added for STFT overlap, coord-summary consistency, and filter interactions.

@d-chambers d-chambers added the bug Something isn't working label Sep 4, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 4, 2025

Walkthrough

PatchAttrs.update now merges coordinates into a new structure and accepts CoordManager inputs; proc.update treats empty attrs as provided and stops explicitly passing dims in one branch; stft accepts overlap=None (zero overlap); minor docstring fixes; and new/updated tests cover coord summaries, STFT overlap=None, filter+STFT integration, squeezing, and concatenation behavior.

Changes

Cohort / File(s) Summary
Core attrs update
dascore/core/attrs.py
PatchAttrs.update builds a new_coords rather than mutating out["coords"]; handles CoordManager inputs, merges coord_info into new_coords, and clears coords when a falsy value is provided. Attr-info update path remains unchanged.
Proc update behavior
dascore/proc/basic.py
update() now treats attrs as provided when not None (so empty mappings follow the attrs-update path) and no longer passes dims explicitly in the non-attrs branch, altering dims inference flow.
Transform STFT overlap handling
dascore/transform/fourier.py
stft signature and logic extended to accept overlap=None (interpreted as zero overlap); overlap computation branches on None to avoid get_sample_count in that case; docs updated.
Filter docstring
dascore/proc/filter.py
Corrects typos and wording in slope_filter docstring only; no behavioral changes.
Core tests
tests/test_core/test_attrs.py, tests/test_core/test_patch.py
Adds test verifying coord-summary updates when coords change; adjusts test to read model_fields from the attrs class.
Integration tests
tests/test_integrations/test_misc_integrations.py
Adds tests exercising STFT with overlap=None and slope_filter applied to banded STFT power using a trained patch.
Proc tests
tests/test_proc/test_proc_coords.py
Adds test ensuring coord summary keys in patch.attrs match patch.coords.coord_map after squeezing.
Transform tests
tests/test_transform/test_fourier.py
Adds test that stft accepts overlap=None and returns a Patch.
Utils tests
tests/test_utils/test_patch_utils.py
Simplifies concatenate test by removing manual propagation of time_min and relying on concatenate behavior.

Suggested labels

ready_for_review, proc

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch attr_update_from_coords

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai bot added proc Related to processing module ready_for_review PR is ready for review labels Sep 4, 2025
Copy link
Contributor

@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)
dascore/proc/filter.py (1)

368-378: Bug: savgol_filter repeatedly filters the original array instead of chaining across axes.
Within the loop you pass x=patch.data; this reuses the original data each time, so only the last axis’ effect survives.

Apply:

-        data = np_savgol_filter(
-            x=patch.data,
+        data = np_savgol_filter(
+            x=data,
             window_length=size[ax],
             polyorder=polyorder,
             mode=mode,
             cval=cval,
             axis=ax,
         )
🧹 Nitpick comments (7)
dascore/proc/filter.py (1)

449-518: Clean up remaining docstring typos for slope_filter.
Multiple minor typos remain; propose a quick sweep.

Apply:

@@
-    Most commonly this used as an F-K (frequency wavenumber)
+    Most commonly this is used as an F-K (frequency–wavenumber)
@@
-        the filter selects the apparent velocites between 'vb' and 'vc'
+        the filter selects the apparent velocities between 'vb' and 'vc'
@@
-        This can be used for up-down/left-right separation, assuming a
-        near-linear fiber layout.
+        This can be used for up/down or left/right separation, assuming a
+        near-linear fiber layout.
@@
-        specified by the inner `filt` parameterse are attenuated rather
+        specified by the inner `filt` parameters are attenuated rather
@@
-    The [fk recipe](`docs/recipes/fk.qmd`) provides addtional examples.
+    The [FK recipe](`docs/recipes/fk.qmd`) provides additional examples.
dascore/transform/fourier.py (1)

374-381: Type hint and docstring: accept overlap=None explicitly.

The implementation supports None, but the signature says Quantity | int. Update the hint and docstring to avoid confusion.

Example signature tweak:

def stft(
    patch: PatchType,
    taper_window: str | ndarray | tuple[str, Any, ...] = "hann",
    overlap: Quantity | int | None = 50 * percent,
    samples: bool = False,
    detrend: bool = False,
    **kwargs,
):
    """
    ...
    overlap
        The overlap between windows. If None, use 0 (no overlap).
    ...

Also add:

from dascore.exceptions import PatchError, ParameterError

at the import section.

tests/test_integrations/test_misc_integrations.py (5)

14-19: Make train_patch fixture module-scoped and resilient to missing data.

Avoid repeated I/O per test and skip cleanly if the dataset isn’t available (useful for offline CI).

Apply this diff to remove the class-scoped fixture:

-    @pytest.fixture
-    def train_patch(self):
-        """Get an example patch with trains in it."""
-        out = dc.spool(fetch("UoU_lf_urban.hdf5"))[0]
-        return out

Add this module-level fixture outside the class:

# top-level (outside the class)
@pytest.fixture(scope="module")
def train_patch():
    """Get an example patch with trains in it (once per module)."""
    try:
        return dc.spool(fetch("UoU_lf_urban.hdf5"))[0]
    except Exception as exc:
        pytest.skip(f"dataset UoU_lf_urban.hdf5 unavailable: {exc}")

20-26: Avoid shadowing and strengthen assertions.

Rename the local variable to avoid shadowing the stft method name, and assert dims are preserved post-filter.

-        stft = patch.stft(time=0.1, overlap=None)
-        out = stft.pass_filter(time=(0.01, ...))
+        stft_patch = patch.stft(time=0.1, overlap=None)
+        out = stft_patch.pass_filter(time=(0.01, ...))
         assert isinstance(out, dc.Patch)
+        assert out.dims == stft_patch.dims
+        assert "ft_time" in stft_patch.dims

27-35: Rename local variable for clarity.

Minor readability: avoid reusing the name “stft.”

-        stft = train_patch.stft(
+        stft_patch = train_patch.stft(
             time=3, overlap=0.5, taper_window=("tukey", 0.1), detrend=True
         )
-        # Then sum power over 1 to 2 Hz
-        banded_patch = (stft.abs() ** 2).select(ft_time=(1, 2)).sum("ft_time").squeeze()
+        # Then sum power over 1 to 2 Hz
+        banded_patch = (
+            stft_patch.abs() ** 2
+        ).select(ft_time=(1, 2)).sum("ft_time").squeeze()

36-38: Prefer canonical unit spelling to avoid pint parser differences.

“mi/hour” is reliably parsed across pint versions; “miles/hour” can be version/definition dependent.

-        mph = dc.get_quantity("miles/hour")
+        mph = dc.get_quantity("mi/hour")

If you prefer miles/hour textually, confirm your supported environments all parse "miles/hour" equivalently.


27-39: Add simple invariants to catch regressions.

Validate that slope_filter preserves shape/dims and that history is appended.

         sf = banded_patch.slope_filter(filt)
-        assert "slope_filter" in str(sf.attrs.history)
+        assert sf.data.shape == banded_patch.data.shape
+        assert sf.dims == banded_patch.dims
+        assert "slope_filter" in str(sf.attrs.history)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 47f83cc and 29a582f.

📒 Files selected for processing (10)
  • dascore/core/attrs.py (1 hunks)
  • dascore/proc/basic.py (1 hunks)
  • dascore/proc/filter.py (1 hunks)
  • dascore/transform/fourier.py (1 hunks)
  • tests/test_core/test_attrs.py (1 hunks)
  • tests/test_core/test_patch.py (1 hunks)
  • tests/test_integrations/test_misc_integrations.py (1 hunks)
  • tests/test_proc/test_proc_coords.py (1 hunks)
  • tests/test_transform/test_fourier.py (1 hunks)
  • tests/test_utils/test_patch_utils.py (0 hunks)
💤 Files with no reviewable changes (1)
  • tests/test_utils/test_patch_utils.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-02T16:22:22.829Z
Learnt from: d-chambers
PR: DASDAE/dascore#523
File: dascore/transform/fourier.py:433-434
Timestamp: 2025-09-02T16:22:22.829Z
Learning: In dascore STFT implementation, use `require_evenly_sampled=True` on `get_coord` calls instead of manual validation for coord.step to ensure sampling rate calculations are safe.

Applied to files:

  • dascore/transform/fourier.py
🧬 Code graph analysis (8)
tests/test_core/test_patch.py (1)
dascore/core/patch.py (1)
  • attrs (203-205)
dascore/transform/fourier.py (1)
dascore/core/coords.py (1)
  • get_sample_count (753-789)
tests/test_core/test_attrs.py (2)
dascore/core/coordmanager.py (2)
  • drop_coords (451-487)
  • update (230-286)
dascore/core/attrs.py (1)
  • update (234-255)
tests/test_transform/test_fourier.py (2)
dascore/transform/fourier.py (1)
  • stft (374-485)
dascore/core/patch.py (1)
  • Patch (27-384)
tests/test_integrations/test_misc_integrations.py (5)
dascore/utils/downloader.py (1)
  • fetch (40-58)
dascore/transform/fourier.py (1)
  • stft (374-485)
dascore/proc/filter.py (2)
  • pass_filter (97-144)
  • slope_filter (442-604)
dascore/core/patch.py (2)
  • Patch (27-384)
  • attrs (203-205)
dascore/units.py (1)
  • get_quantity (70-94)
tests/test_proc/test_proc_coords.py (4)
dascore/proc/coords.py (1)
  • squeeze (652-666)
dascore/core/coordmanager.py (1)
  • squeeze (877-907)
dascore/core/patch.py (2)
  • attrs (203-205)
  • coords (208-210)
dascore/core/attrs.py (1)
  • get (174-179)
dascore/proc/basic.py (3)
dascore/core/patch.py (3)
  • attrs (203-205)
  • coords (208-210)
  • data (213-215)
dascore/core/coordmanager.py (2)
  • update_from_attrs (291-325)
  • update (230-286)
dascore/core/attrs.py (3)
  • PatchAttrs (65-301)
  • from_dict (193-211)
  • update (234-255)
dascore/core/attrs.py (2)
dascore/core/coordmanager.py (1)
  • update (230-286)
dascore/utils/attrs.py (1)
  • separate_coord_info (251-373)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: test_code (windows-latest, 3.12)
  • GitHub Check: test_code (ubuntu-latest, 3.11)
  • GitHub Check: test_code (windows-latest, 3.13)
  • GitHub Check: test_code (windows-latest, 3.11)
  • GitHub Check: test_code (macos-latest, 3.12)
  • GitHub Check: test_code (windows-latest, 3.10)
  • GitHub Check: test_code (macos-latest, 3.10)
  • GitHub Check: test_code (ubuntu-latest, 3.12)
  • GitHub Check: test_code (ubuntu-latest, 3.10)
  • GitHub Check: test_code (macos-latest, 3.11)
  • GitHub Check: test_code (ubuntu-latest, 3.13)
  • GitHub Check: test_code_min_deps (windows-latest, 3.12)
  • GitHub Check: test_code_min_deps (macos-latest, 3.12)
  • GitHub Check: test_code_min_deps (ubuntu-latest, 3.12)
  • GitHub Check: test_code_min_deps (macos-latest, 3.13)
  • GitHub Check: test_code_min_deps (ubuntu-latest, 3.13)
  • GitHub Check: test_code_min_deps (windows-latest, 3.13)
🔇 Additional comments (8)
dascore/proc/filter.py (1)

473-473: Tiny typo fix in docstring — looks good.
No functional changes here.

dascore/core/attrs.py (1)

253-254: Confirm intent: should an empty dict clear coords?
Current logic clears coords for any falsy value (None, {}, 0). If only None should clear, gate on passed_in_coords is None.

tests/test_core/test_patch.py (1)

125-129: Switching to class-level model_fields is correct.
Accessing model_fields on the class is the canonical Pydantic v2 pattern.

tests/test_proc/test_proc_coords.py (1)

434-441: LGTM: coord summary stays in sync after squeeze.

The assertion correctly checks that squeezed dims are excluded from the attrs coord summary.

tests/test_transform/test_fourier.py (1)

338-342: LGTM: unit test covers overlap=None path.

This guards the None-handling branch in stft and ensures it returns a Patch.

tests/test_core/test_attrs.py (1)

302-309: LGTM: attrs.update(coords=…) propagates coord drops into the summary.

This verifies the intended behavior when passing a CoordManager to PatchAttrs.update.

dascore/proc/basic.py (1)

194-199: Unify attrs/coords merge path for consistent dims
Use coords.update_from_attrs in both branches so that attrs.dims always mirrors coords.dims.

     if attrs is not None:
         coords, attrs = coords.update_from_attrs(attrs)
     else:
-        _attrs = dc.PatchAttrs.from_dict(attrs or self.attrs)
-        attrs = _attrs.update(coords=coords)
+        # Derive attrs from coords as the source of truth for dims/coord summary.
+        _, attrs = coords.update_from_attrs(dc.PatchAttrs.from_dict(self.attrs))
     return self.__class__(data=data, coords=coords, attrs=attrs)

Verify post-change that attrs.dims == coords.dims at all update call sites.

tests/test_integrations/test_misc_integrations.py (1)

1-3: Good integration coverage.

Nice, focused tests validating STFT overlap=None and filter interoperability.

@codecov
Copy link

codecov bot commented Sep 4, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.88%. Comparing base (47f83cc) to head (cdac421).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #527   +/-   ##
=======================================
  Coverage   99.88%   99.88%           
=======================================
  Files         122      122           
  Lines       10027    10033    +6     
=======================================
+ Hits        10015    10021    +6     
  Misses         12       12           
Flag Coverage Δ
unittests 99.88% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@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

🧹 Nitpick comments (1)
dascore/core/attrs.py (1)

252-254: Confirm dims behavior when clearing coords.

When falsy coords are passed, coords are cleared but dims remain unchanged. If the intended invariant is “dims reflect current coords,” consider also updating dims (e.g., to tuple()) or deriving from new_coords.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 29a582f and cdac421.

📒 Files selected for processing (4)
  • dascore/core/attrs.py (1 hunks)
  • dascore/proc/filter.py (4 hunks)
  • dascore/transform/fourier.py (3 hunks)
  • tests/test_integrations/test_misc_integrations.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • dascore/proc/filter.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/test_integrations/test_misc_integrations.py
  • dascore/transform/fourier.py
🧰 Additional context used
🧬 Code graph analysis (1)
dascore/core/attrs.py (2)
dascore/core/coordmanager.py (1)
  • update (230-286)
dascore/utils/attrs.py (1)
  • separate_coord_info (251-373)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: test_code (windows-latest, 3.13)
  • GitHub Check: test_code (macos-latest, 3.12)
  • GitHub Check: test_code (windows-latest, 3.12)
  • GitHub Check: test_code (windows-latest, 3.10)
  • GitHub Check: test_code (windows-latest, 3.11)
  • GitHub Check: test_code (ubuntu-latest, 3.12)
  • GitHub Check: test_code (ubuntu-latest, 3.13)
  • GitHub Check: test_code (macos-latest, 3.11)
  • GitHub Check: test_code (macos-latest, 3.10)
  • GitHub Check: test_code (ubuntu-latest, 3.10)
  • GitHub Check: test_code (ubuntu-latest, 3.11)
  • GitHub Check: test_code_min_deps (macos-latest, 3.12)
  • GitHub Check: test_code_min_deps (windows-latest, 3.12)
  • GitHub Check: test_code_min_deps (ubuntu-latest, 3.12)
  • GitHub Check: test_code_min_deps (windows-latest, 3.13)
  • GitHub Check: test_code_min_deps (ubuntu-latest, 3.13)
  • GitHub Check: test_code_min_deps (macos-latest, 3.13)

@d-chambers d-chambers merged commit 45021e6 into master Sep 9, 2025
22 checks passed
@d-chambers d-chambers deleted the attr_update_from_coords branch September 9, 2025 06:15
@coderabbitai coderabbitai bot mentioned this pull request Sep 22, 2025
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working proc Related to processing module ready_for_review PR is ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants