Skip to content

Restore 100% coverage and enforce it in codecov - #767

Merged
d-chambers merged 5 commits into
devfrom
coverage-restore-100
Jul 23, 2026
Merged

Restore 100% coverage and enforce it in codecov#767
d-chambers merged 5 commits into
devfrom
coverage-restore-100

Conversation

@d-chambers

@d-chambers d-chambers commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Why

dev coverage slipped below 100% and CI never flagged it. Tracing Codecov history, coverage was a clean 100.0% through #758 and first read 99.96% at #759 ("Prune dead code and collapse single-implementation abstractions"), whose patch coverage was 89.29% — it added 6 uncovered defensive lines in dascore/io/index/indexer.py.

It slipped through because codecov.yml never set an explicit coverage target. The 100% "gate" was only Codecov's default auto status, which compares against the base commit rather than an absolute floor. Since the network-test split (#752) + after_n_builds: 7 (#751) made per-commit uploads land as partial (unittests-only, ~48%), #759's head (99.96%) was compared against a broken ~48% base and read as an increase — so both project and patch checks passed.

What

  1. Make the gate absolute and deterministic. Add explicit project + patch target: 100% (threshold 0%), scoped to the unittests flag — the non-network + doctest suite, which now covers every line. The gate no longer depends on the carried-forward network upload, so a skipped or stale network report cannot mask a drop.
  2. Restore coverage to 100%. Cover every previously-uncovered line with non-network tests:
    • indexer.py (the Prune dead code and collapse single-implementation abstractions #759 regression): atomic-swap temp-file cleanup, and the _walk guard that skips a file deleted mid-scan.
    • _coord_record_from_row: empty-string units normalize to None.
    • suppress_warnings: the message-filter branch.
    • _warn_remote_cache_download: metadata-scope guidance text.
    • ProdML: relative (non-datetime) time rejected on write; non-positive optional measures dropped; _get_prodml_version_str returns "" for a non-ProdML file.
  3. Remove one unreachable branch from the count. The _round_times_to_microseconds NaT guard is marked # pragma: no cover: a NaT breaks even sampling, so _get_single_patch's require_evenly_sampled check rejects such coords first (raising CoordError, a PatchError subclass), making the guard unreachable via dc.write.

Verification

  • Non-network suite: 8028 passed; combined with the doctest suite (both upload under the unittests flag), coverage is 100.0% — 0 misses.
  • codecov.yml validated against Codecov's validator (Valid!).
  • Lint (ruff, ruff-format, pre-commit hooks): pass.

Network tests aren't run locally (no credentials); the network flag remains informational and no longer participates in the gate.

Summary by CodeRabbit

  • Bug Fixes

    • Improved filesystem indexing resilience when files are removed during scanning or updates fail, preventing leftover temporary files and partial results.
    • Improved handling of coordinate records with empty unit values.
    • Clarified validation for PRODML time coordinates and optional measurement values.
  • Tests

    • Expanded coverage for filesystem indexing, PRODML detection and writing, remote metadata warnings, warning suppression, and coordinate handling.
    • Enforced 100% unit-test coverage for project and patch changes.

Changelog

none

dev coverage slipped to 99.96% at #759, which added two uncovered
defensive branches in the directory indexer. Codecov did not block it:
codecov.yml never set an explicit coverage target, so the default
`auto` status only compares against the base commit, and a partial
base upload made the drop read as an increase.

- Add explicit project + patch `target: 100%` (threshold 0%) so the
  gate is absolute instead of relative to a possibly-partial base.
- Cover the two previously-missed indexer branches: the atomic-swap
  temp-file cleanup in `_update_index_map`, and the `_walk` stat guard
  that skips a file deleted between the walk and its stat.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 498de643-6a6b-4798-a353-8df0f92fb04a

📥 Commits

Reviewing files that changed from the base of the PR and between 169ff00 and 4024759.

📒 Files selected for processing (3)
  • codecov.yml
  • dascore/io/prodml/utils.py
  • tests/test_io/test_indexer.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/test_io/test_indexer.py
  • dascore/io/prodml/utils.py

📝 Walkthrough

Walkthrough

Changes

The pull request adds 100% unittest coverage gates and edge-case coverage for indexer updates, PRODML handling, coordinate indexing, remote-cache warnings, and warning suppression.

CI and indexer resilience

Layer / File(s) Summary
Absolute unittest coverage gates
codecov.yml
Codecov project and patch checks require 100% coverage for the unittests flag.
Indexer failure and walk resilience
tests/test_io/test_indexer.py
Tests verify cleanup after atomic replacement failure and skipping files removed during directory walking.

PRODML edge cases

Layer / File(s) Summary
PRODML validation and detection coverage
dascore/io/prodml/utils.py, tests/test_io/test_prodml/*
PRODML handling documents earlier NaT validation, tests missing fingerprint attributes and relative-time rejection, and verifies omission of non-positive optional measures.

Coordinate and utility edge cases

Layer / File(s) Summary
Coordinate normalization and warning behavior
tests/test_io/test_index/test_planned.py, tests/test_utils/test_io_utils.py, tests/test_utils/test_misc.py
Tests cover empty coordinate units, metadata-scoped cache warning guidance, and warning-message action filtering.

Possibly related PRs

  • DASDAE/dascore#541: Both PRs extend indexer test coverage around DirectoryIndexer.update.
  • DASDAE/dascore#748: Related datetime and NaT handling supports the earlier validation referenced by this change.
  • DASDAE/dascore#759: Both PRs cover atomic index updates and files disappearing during directory traversal.

Suggested labels: CI

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: restoring 100% coverage and enforcing it via Codecov.
Description check ✅ Passed The PR description is detailed and covers motivation, changes, and verification, though it uses different headings and omits the checklist.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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 coverage-restore-100

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
codecov.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


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 the CI continuous integration label Jul 23, 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 `@tests/test_io/test_indexer.py`:
- Around line 205-214: The test’s global Path.is_dir patch can delete
vanisher.h5 before _walk reaches its stat() error handler. Update the test
around is_dir_then_vanish to mock the iterator used by _iter_local_filesystem so
it deterministically yields both candidate paths, then make the vanished path’s
stat() raise the expected OSError and assert that _walk handles it while
preserving the normal candidate behavior.
🪄 Autofix (Beta)

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: cadf1244-f756-4db0-b0d5-e1cfd728e74d

📥 Commits

Reviewing files that changed from the base of the PR and between 687dfbe and de59d6f.

📒 Files selected for processing (2)
  • codecov.yml
  • tests/test_io/test_indexer.py

Comment thread tests/test_io/test_indexer.py Outdated
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (687dfbe) to head (4024759).

Additional details and impacted files
@@             Coverage Diff              @@
##              dev      #767       +/-   ##
============================================
+ Coverage   48.75%   100.00%   +51.24%     
============================================
  Files         163       163               
  Lines       17081     17221      +140     
============================================
+ Hits         8327     17221     +8894     
+ Misses       8754         0     -8754     
Flag Coverage Δ
network 48.52% <ø> (-0.23%) ⬇️
unittests 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.

Add non-network tests for every line that was previously exercised only
by the network suite, so the deterministic unittests + doctest coverage
reaches 100% on its own:

- planned `_coord_record_from_row`: empty-string units normalize to None.
- misc `suppress_warnings`: the message-filter branch.
- remote_io `_warn_remote_cache_download`: metadata-scope guidance text.
- prodml relative (non-datetime) time is rejected on write.
- prodml non-positive optional measures are dropped rather than written.
- prodml `_get_prodml_version_str` returns "" for a non-ProdML file.

Mark the `_round_times_to_microseconds` NaT guard `# pragma: no cover`:
a NaT breaks even sampling, so `_get_single_patch`'s evenly-sampled check
rejects such coords first, making the guard unreachable via `dc.write`.

Scope the codecov project + patch 100% gate to the `unittests` flag so it
no longer depends on the carried-forward network upload; a skipped or
stale network report can no longer mask a real coverage drop.
@coderabbitai coderabbitai Bot added the IO Work for reading/writing different formats label Jul 23, 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 `@tests/test_utils/test_misc.py`:
- Around line 578-582: Update test_message_filter_applies_action to pass an
explicit stacklevel argument to warnings.warn, using the appropriate positive
level while preserving the existing UserWarning and message matching behavior.
🪄 Autofix (Beta)

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: c411970f-ad73-4911-a291-4d306393e89b

📥 Commits

Reviewing files that changed from the base of the PR and between de59d6f and 169ff00.

📒 Files selected for processing (7)
  • codecov.yml
  • dascore/io/prodml/utils.py
  • tests/test_io/test_index/test_planned.py
  • tests/test_io/test_prodml/test_prod_ml.py
  • tests/test_io/test_prodml/test_prodml_write.py
  • tests/test_utils/test_io_utils.py
  • tests/test_utils/test_misc.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • codecov.yml

Comment on lines +578 to +582
def test_message_filter_applies_action(self):
"""A message pattern applies the action to matching warnings."""
with suppress_warnings(message="boom", action="error"):
with pytest.raises(UserWarning, match="boom"):
warnings.warn("boom", UserWarning)

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add an explicit stacklevel to satisfy Ruff B028.

-                warnings.warn("boom", UserWarning)
+                warnings.warn("boom", UserWarning, stacklevel=2)
📝 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_message_filter_applies_action(self):
"""A message pattern applies the action to matching warnings."""
with suppress_warnings(message="boom", action="error"):
with pytest.raises(UserWarning, match="boom"):
warnings.warn("boom", UserWarning)
def test_message_filter_applies_action(self):
"""A message pattern applies the action to matching warnings."""
with suppress_warnings(message="boom", action="error"):
with pytest.raises(UserWarning, match="boom"):
warnings.warn("boom", UserWarning, stacklevel=2)
🧰 Tools
🪛 Ruff (0.15.21)

[warning] 582-582: No explicit stacklevel keyword argument found

Set stacklevel=2

(B028)

🤖 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 `@tests/test_utils/test_misc.py` around lines 578 - 582, Update
test_message_filter_applies_action to pass an explicit stacklevel argument to
warnings.warn, using the appropriate positive level while preserving the
existing UserWarning and message matching behavior.

Source: Linters/SAST tools

The NaT check in _round_times_to_microseconds can never fire: a NaT makes
the time coordinate unevenly sampled, so _get_single_patch's
require_evenly_sampled check rejects it first (CoordError). Remove the
dead branch instead of excluding it from coverage; test_nat_time still
verifies NaT is rejected via the earlier guard.
Replace the global Path.is_dir patch and mid-test file deletion with a
mocked _iter_filesystem that yields a real file plus a never-created
"vanished" path. The vanished path's real stat() raises FileNotFoundError,
exercising the concurrent-deletion guard without depending on is_dir/stat
call ordering or filesystem timing.
Comment thread codecov.yml Outdated
Comment on lines +9 to +13
# relative to the base commit, so a regression cannot slip through when a base
# upload is partial (see the coverage drop introduced by #759). The gate is
# scoped to the `unittests` flag (the deterministic non-network + doctest
# suite, which covers every line): it never depends on the carried-forward
# `network` upload, so a skipped or stale network report cannot mask a drop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

remove these lines; too verbose.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 4024759 — trimmed to a single line.

Drop the multi-line rationale block to a single line per review.
@coderabbitai coderabbitai Bot removed the IO Work for reading/writing different formats label Jul 23, 2026
@d-chambers
d-chambers merged commit 4474c28 into dev Jul 23, 2026
28 checks passed
@d-chambers
d-chambers deleted the coverage-restore-100 branch July 23, 2026 12:58
@d-chambers d-chambers mentioned this pull request Jul 24, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI continuous integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants