Skip to content

Enable ty's invalid-return-type rule - #840

Merged
d-chambers merged 8 commits into
devfrom
ty-return-type
Aug 8, 2026
Merged

Enable ty's invalid-return-type rule#840
d-chambers merged 8 commits into
devfrom
ty-return-type

Conversation

@d-chambers

@d-chambers d-chambers commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Description

Takes ty's invalid-return-type from 26 diagnostics to 0 and enables the rule, following #830 and #836. [tool.ty.rules] is now empty — no rule is ignored any more.

No suppressions were added, and one was removed. The # type: ignore[return-value] in dascore/utils/deprecate.py was the only one in the codebase and did nothing, since no mypy runs here; a cast replaces it.

Six of the 26 turned out to be annotations that lied about runtime behaviour:

  • _yield_attrs_coords declared tuple[dict, CoordManager], but it is a generator yielding three-tuples — both callers already unpack three.
  • CoordManager.drop_disassociated_coords and drop_private_coords declared Self; drop_coords returns (cm, array), and the tests already index [0].
  • get_xarray_data_var_name deliberately returns None for XDAS payloads.
  • _is_dasvader_jld2 returned the empty set rather than False when no data name matched. The one runtime fix, with a test that fails without it.
  • BaseCoord.size returned an np.int64 (and 1.0 for a shapeless coord); it now uses math.prod.
  • BaseCoord.get_next_index declared int while returning an array for sized input.

In three places the type error was pointing at a design smell rather than a missing annotation:

  • sobel_filter, notch_filter and velocity_to_strain_rate_edgeless built their result with a bare dc.Patch(...), dropping any subclass while promising PatchType. pass_filter, in the same module, already used patch.new(...). Equality was verified at runtime for both call shapes.
  • scan_payload already returned _make_scan_payload results, so naming ScanPayload fixed both it and the Sintela FiberIO.
  • _lookup_cache held frozensets and tuples under a discriminating key prefix. Two typed dicts drop the union and a tuple allocation per lookup.

Three casts remain, each documented at the site: CoordManager.update and CoordPartial.change_length build through factories whose declared return is wider than the case at hand, and the deprecate wrapper stands in for the function it wraps in a way (*args, **kwargs) cannot express.

The two remaining @overload sets in the repo (BaseCoord.__getitem__, unbyte) are not verifiable by ty at any annotation: a falsification probe with a deliberately wrong overload produces zero diagnostics, because their honest implementation returns contain Any or an unsolved TypeVar, which absorbs anything. They are left unannotated with a comment saying so, rather than annotated to look checked.

Verified with ty 0.0.65 on Python 3.11, 3.12, 3.13 and 3.14 — the per-version sweep matters, since the pre-commit hook resolves a different interpreter than --python .venv alone implies.

Next: widen [tool.ty.src] to cover tests/.

Changelog

  • changed: BaseCoord.size is a builtin int rather than an np.int64, and 1 rather than 1.0 for a shapeless coord.
  • fixed: Patch.sobel_filter, Patch.notch_filter, and velocity_to_strain_rate_edgeless build their result with patch.new(...), so a Patch subclass survives them as their signatures promised.

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes.
  • documented the new feature with docstrings and/or appropriate doc page.
  • included tests. See testing guidelines.
  • added the "ready_for_review" tag once the PR is ready to be reviewed.

Summary by CodeRabbit

  • New Features

    • Added segmented coordinate support, coordinate concatenation, scan payloads, and expanded scan metadata.
    • Coordinate-dropping operations now return both the updated coordinates and transformed data.
    • Configuration now supports permanent updates and temporary overrides.
  • Bug Fixes

    • Filtering and strain-rate operations now preserve specialized patch types.
    • Improved handling of unitless data, coordinate sizing, indexing, NetCDF variables, and DASvader resources.
    • Corrected scan, write, and payload return behavior.
  • Breaking Changes

    • Removed deprecated I/O, client, indexing, storage, and transformation APIs.
    • dc.scan now returns PatchSummary objects.

_yield_attrs_coords is a generator yielding three-tuples, not a
two-tuple; both callers already unpack three. The coordmanager drop
helpers delegate to drop_coords, which returns (cm, array), and the
tests already index [0]. get_xarray_data_var_name deliberately returns
None for XDAS payloads. _is_dasvader_jld2 handed back the empty set
instead of False when no data name matched, which is the one runtime
change here.
pass_filter in the same module already does this. dc.Patch(...) drops
any subclass on the floor while the signature promises PatchType;
proc.update constructs through self.__class__, so the promise holds.
Verified equal for both shapes: data-only and data plus coords/attrs.
CoordManager.update and CoordPartial.change_length both build through
a factory whose declared return is wider than the case at hand.
unit_str is None for a coord with no units, size is a builtin int only
if math rather than numpy computes it, and get_next_index hands back an
array for a sized value and a numpy integer otherwise.
A quantity of None survives assert_dtype_compatible_with_units for a
non-time dtype. quant_sequence_to_quant_array really does return a
Quantity; numpy just declares ndarray.__mul__ as returning an ndarray,
so pint's reflected operator is invisible.
One dict held both frozensets and tuples under a discriminating key
prefix; two dicts keep each to a single value type and drop the tuple
allocation per lookup. write returns the path it was handed, which is
whatever path_types allows, not necessarily a Path.
scan_payload already returned _make_scan_payload results, so naming
ScanPayload fixes both it and the sintela FiberIO. The unit filter now
skips None instead of differencing it out, which narrows. The deprecate
wrapper drops the repo's only (and unused, since no mypy runs here)
type: ignore in favor of a cast.
The last ignored ty rule is now on. The overload implementations that
ty cannot verify are documented as such rather than annotated to look
checked.
@d-chambers d-chambers added the ready_for_review PR is ready for review label Aug 8, 2026
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR corrects public and internal type annotations, updates coordinate manager return contracts, preserves patch subclasses through processing operations, separates FiberIO caches, fixes DASvader boolean detection, and documents the API changes.

Changes

Typing and API corrections

Layer / File(s) Summary
Coordinate manager and coordinate contracts
dascore/core/coordmanager.py, dascore/core/coords.py, docs/changelog.qmd
Coordinate return types now include transformed arrays and optional values. Coordinate sizing uses native integers. Factory results use Self casts.
Patch result construction
dascore/proc/filter.py, dascore/transform/strain.py
Filtering and strain conversion use patch.new(...) to construct results.
I/O contracts and FiberIO cache separation
dascore/io/core.py, dascore/io/febus/a1utils.py, dascore/io/netcdf/utils.py, dascore/io/prodml/core.py, dascore/io/sintela/protobuf_utils.py
FiberIO caches are separated by lookup result type. I/O annotations now reflect iterator, optional-name, scan-payload, and path return types.
Units and utility typing
dascore/units.py, dascore/utils/deprecate.py, dascore/utils/misc.py, dascore/io/index/query.py, pyproject.toml
Unit, quantity, wrapper, byte-conversion, compatibility-unit, and type-checker declarations are corrected.
DASvader detection result
dascore/io/dasvader/utils.py, tests/test_io/test_dasvader/test_dasvader.py
Empty data-field intersections now return False, with a regression test for non-data resources.

Possibly related PRs

Suggested labels: bug, documentation, CI, IO, patch

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the purpose, key changes, validation, tests, and checklist status.
Title check ✅ Passed The title clearly identifies the primary change: enabling ty's invalid-return-type rule.
Docstring Coverage ✅ Passed Docstring coverage is 84.21% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ty-return-type

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.

@coderabbitai coderabbitai Bot added bug Something isn't working CI continuous integration documentation Improvements or additions to documentation IO Work for reading/writing different formats patch related to Patch class labels Aug 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dascore/io/core.py`:
- Around line 431-434: Update the key type annotations for _input_type_cache and
_prioritized_cache to str | None, preserving their existing value types and
cache behavior so None keys accepted by yield_fiberio and its helpers are
represented correctly.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a66de8b6-7be4-4d02-9ab7-5d9638e145ee

📥 Commits

Reviewing files that changed from the base of the PR and between 04c42de and 426a2e4.

📒 Files selected for processing (17)
  • dascore/core/coordmanager.py
  • dascore/core/coords.py
  • dascore/io/core.py
  • dascore/io/dasvader/utils.py
  • dascore/io/febus/a1utils.py
  • dascore/io/index/query.py
  • dascore/io/netcdf/utils.py
  • dascore/io/prodml/core.py
  • dascore/io/sintela/protobuf_utils.py
  • dascore/proc/filter.py
  • dascore/transform/strain.py
  • dascore/units.py
  • dascore/utils/deprecate.py
  • dascore/utils/misc.py
  • docs/changelog.qmd
  • pyproject.toml
  • tests/test_io/test_dasvader/test_dasvader.py

Comment thread dascore/io/core.py
Comment on lines +431 to +434
# Kept as two dicts rather than one keyed by a discriminating
# prefix so each stays a single value type.
self._input_type_cache: dict[str, frozenset[FiberIO]] = {}
self._prioritized_cache: dict[str, tuple[FiberIO, ...]] = {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include None in both cache key types.

yield_fiberio accepts input_type: str | None and can pass None to both cache-backed helpers. Both caches can therefore contain a None key, but their declarations allow only str. Change both key types to str | None.

Proposed type correction
-        self._input_type_cache: dict[str, frozenset[FiberIO]] = {}
-        self._prioritized_cache: dict[str, tuple[FiberIO, ...]] = {}
+        self._input_type_cache: dict[str | None, frozenset[FiberIO]] = {}
+        self._prioritized_cache: dict[str | None, tuple[FiberIO, ...]] = {}
📝 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
# Kept as two dicts rather than one keyed by a discriminating
# prefix so each stays a single value type.
self._input_type_cache: dict[str, frozenset[FiberIO]] = {}
self._prioritized_cache: dict[str, tuple[FiberIO, ...]] = {}
# Kept as two dicts rather than one keyed by a discriminating
# prefix so each stays a single value type.
self._input_type_cache: dict[str | None, frozenset[FiberIO]] = {}
self._prioritized_cache: dict[str | None, tuple[FiberIO, ...]] = {}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dascore/io/core.py` around lines 431 - 434, Update the key type annotations
for _input_type_cache and _prioritized_cache to str | None, preserving their
existing value types and cache behavior so None keys accepted by yield_fiberio
and its helpers are represented correctly.

@codecov

codecov Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (04c42de) to head (426a2e4).

Additional details and impacted files
@@            Coverage Diff            @@
##               dev      #840   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          164       164           
  Lines        17945     17948    +3     
=========================================
+ Hits         17945     17948    +3     
Flag Coverage Δ
network 48.51% <66.66%> (-0.01%) ⬇️
unittests 100.00% <100.00%> (ø)

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

☔ View full report in Codecov by Harness.
📢 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.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

✅ Documentation built:
👉 Download
Note: You must be logged in to github and a DASDAE member to access the link.

@d-chambers
d-chambers merged commit 4a26888 into dev Aug 8, 2026
38 checks passed
@d-chambers
d-chambers deleted the ty-return-type branch August 8, 2026 11:19
d-chambers added a commit that referenced this pull request Aug 8, 2026
The segmented coord tests reach for segment-specific attributes on
values the factory declares as BaseCoord; asserting the concrete type
first is also a stronger assertion. dc.write is now generic over the
path type, so handing it a Path gets a Path back rather than the whole
path_types union that #840 widened it to.
@d-chambers d-chambers removed the ready_for_review PR is ready for review label Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working CI continuous integration documentation Improvements or additions to documentation IO Work for reading/writing different formats patch related to Patch class

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant