Skip to content

Correct public signatures that misdescribed their inputs and returns - #842

Merged
d-chambers merged 17 commits into
devfrom
ty-tests-scope
Aug 8, 2026
Merged

Correct public signatures that misdescribed their inputs and returns#842
d-chambers merged 17 commits into
devfrom
ty-tests-scope

Conversation

@d-chambers

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

Copy link
Copy Markdown
Contributor

Description

Corrects public signatures that misdescribed what the functions already accepted and returned, and fixes the two real bugs that surfaced along the way. Follows #830, #836 and #840.

These were found by putting tests/ under ty locally. That scope change is not part of this PR — [tool.ty.src] still covers dascore/ only, and the remaining test-side diagnostics land in a follow-up. What is here stands on its own.

Signature corrections

  • get_filter_units declared -> tuple[float, float] but returns (None, 10.0) for an open bound, and accepted None / ... that its parameters denied. Wrong in both directions.
  • filter_df declared -> np.ndarray but returns a pandas.Series for collection and range queries.
  • get_coord accepts a plain list for data, and an int naming a length, neither of which ArrayLike covers.
  • dc.read's time and distance accept the documented (value, ...) open-range form. The tuple types for this already existed, private to the febus reader; they move to dascore.constants as time_select_type / float_select_type and febus now aliases them.
  • dc.write is generic over its path type (_PathT bound to path_types), so a Path in yields a Path out. This repairs a regression from Enable ty's invalid-return-type rule #840, where widening the return to the whole union broke dc.write(...).exists().

Bugs fixed

  • patch.resample(dim=None) divided by get_filter_units' result without checking it, failing later with ValueError: cannot convert float NaN to integer. It now raises ParameterError naming the dimension. Found by the counterpart review, with a regression test.
  • _is_dasvader_jld2 and the other Enable ty's invalid-return-type rule #840 fixes are already on dev; nothing here overlaps them.

Test improvements

Narrowed optionals (assert x is not None before use), assert isinstance(...) before reaching for a coord subclass's attributes, monkeypatch.setattr in place of hand-rolled attribute patching that restored by hand, FiberIO test subclasses conforming to the base signatures they claim to implement, and submodules imported directly rather than reached through their parent package.

What did not survive review

I had overloaded get_quantity / get_quantity_str so that naming a unit typed as producing a Quantity. That was wrong: get_quantity("") returns None, and the empty string is exactly how dascore spells "carries no units". It would also have hidden a real error class, since an unset unit reaching arithmetic is what the optional return is meant to surface. Reverted; the docstrings now say so explicitly.

A counterpart review by Codex is recorded in .scratch/ (untracked). It found the resample bug, a false claim in the filter_df docstring, and a test where a comprehension silently discarded results; all three are fixed here.

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. Full suite 8135 passed / 251 skipped / 2 xfailed; pre-commit run --all-files green.

Changelog

  • changed: several public signatures now describe what they already accepted and returned — get_filter_units open bounds, filter_df's Series return, get_coord's sequence or int data, dc.read's (value, ...) ranges, and dc.write's path type.
  • fixed: patch.resample(dim=None) raises ParameterError naming the dimension instead of failing later with ValueError: cannot convert float NaN to integer.

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.

Only None or Ellipsis yields None, but the single signature made every
result Quantity | None, so get_quantity("m") could not be multiplied
without a narrowing check.
The optional-dependency imports are ignored across tests/, matching what
dascore/ already does. The pydantic extra=allow attribute reads are
ignored in the six files that actually do them, rather than across the
suite, so the rule keeps working on the rest. Also narrows some
optionals in the index edge cases and moves its hand-rolled attribute
patching onto monkeypatch, which restores itself.
febus already defined tuple types admitting ... for an open end; those
move to dascore.constants and dc.read now uses them, so the documented
(value, ...) form type checks. The dasvader test builds structured
arrays from runtime dtypes, which numpy types as float64, so every
field-name index needs a cast to be seen as a void array.
Dropping **kwargs, narrowing a parameter to SpoolType and widening a
return to bool are all real override incompatibilities: a caller using
the base contract would break on these. The dummies ignore their
arguments, so the signatures change and the behaviour does not.
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.
Naming a unit always produces a string; only a null input gives None.
The heterogeneous dicts splatted into typed constructors infer an object
value type, which rejects every field.
Merging a string literal into a dict[str, Any] widens the value type to
Any | str, which none of the record fields accept, so the merges are
bound to annotated locals (and the repeated rebase is now a helper).
get_filter_units takes None or ... for an open bound and returns None
there too, which its annotation denied in both directions. get_coord
takes an int for data, meaning a partial coord of that length.
A plain list is accepted for data but ArrayLike does not cover it. The
tests reaching for range-specific attributes now assert the concrete
coord class first, which is also a stronger assertion.
filter_df returns a Series once any filter applies and a bare array
otherwise; it claimed only the array. The reflected comparison and the
list-plus-timedelta both run through the operand numpy or dascore
owns, so they are written in that order.
dc.utils.downloader.fetch and friends only resolve if something else
has already imported the submodule, which is why the checker calls it
possibly missing; importing the name directly is also how the rest of
the suite spells it.
The source-side signature fixes stand on their own; the scope flip
returns with the remaining tests diagnostics.
get_quantity("") and get_quantity_str("") both return None, and the
empty string is how dascore spells "no units", so typing a str input as
always producing a Quantity was false. It would also have hidden a real
error class: an unset unit reaching arithmetic is a bug the optional
return is supposed to surface.
The test is documented as covering number-first and patch-first; making
both lines patch-first deleted half of it. int.__lt__ is declared to
return bool, so the reflected result is cast instead.
filter_df's docstring named the wrong split: an equality query returns a
bare array too, so the contract is now stated as an opaque boolean
container. The filesystem tests assert nothing was dropped rather than
silently discarding a None. resample divided by get_filter_units' result
without checking it, which the widened return exposed; a null period now
raises ParameterError instead of surfacing as a NaN conversion.
@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

Warning

Review limit reached

@d-chambers, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: db47f0b9-bd06-45e6-b4e4-0167497cd91d

📥 Commits

Reviewing files that changed from the base of the PR and between 4a26888 and 0ca13c3.

📒 Files selected for processing (28)
  • dascore/constants.py
  • dascore/core/coords.py
  • dascore/io/core.py
  • dascore/io/febus/core.py
  • dascore/proc/resample.py
  • dascore/units.py
  • dascore/utils/pd.py
  • docs/changelog.qmd
  • pyproject.toml
  • tests/test_core/test_coord_segmented.py
  • tests/test_core/test_coords.py
  • tests/test_core/test_patch.py
  • tests/test_io/test_dasdae/test_dasdae.py
  • tests/test_io/test_dasvader/test_dasvader.py
  • tests/test_io/test_index/test_index_edge_cases.py
  • tests/test_io/test_index/test_planned.py
  • tests/test_io/test_io_core.py
  • tests/test_io/test_mseed/test_mseed.py
  • tests/test_io/test_prodml/test_prod_ml.py
  • tests/test_io/test_remote_common_io.py
  • tests/test_proc/test_filter.py
  • tests/test_proc/test_resample.py
  • tests/test_units.py
  • tests/test_utils/test_io_utils.py
  • tests/test_utils/test_misc.py
  • tests/test_utils/test_moving.py
  • tests/test_utils/test_patch_utils.py
  • tests/test_utils/test_pd.py

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.

@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 (4a26888) to head (0ca13c3).

Additional details and impacted files
@@            Coverage Diff            @@
##               dev      #842   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          164       164           
  Lines        17948     17953    +5     
=========================================
+ Hits         17948     17953    +5     
Flag Coverage Δ
network 48.51% <78.57%> (-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.

@d-chambers
d-chambers merged commit 5ccdec8 into dev Aug 8, 2026
28 checks passed
@d-chambers
d-chambers deleted the ty-tests-scope branch August 8, 2026 18:52
@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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant