Skip to content

TST: cover the paths excluded by coverage pragmas - #785

Merged
d-chambers merged 3 commits into
devfrom
hdf5-pragmas
Jul 26, 2026
Merged

TST: cover the paths excluded by coverage pragmas#785
d-chambers merged 3 commits into
devfrom
hdf5-pragmas

Conversation

@d-chambers

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

Copy link
Copy Markdown
Contributor

Description

Removes every # pragma: no cover from these files: six are replaced by tests, the last by an assertion.

The markers were hiding code from the coverage report, not from the test suite's reach. That has a cost: a pragma on dead code means coverage cannot tell you it is dead (one such function, _get_remote_cache_dir, is deleted in #781 after exactly that happened), and a pragma on a def line excludes the whole method even when most of it is exercised.

What is now tested

The remote HDF5 writer (_RemoteH5Writer, five markers). All five sat on def lines, so they excluded entire methods, though coverage showed most of __init__ and __exit__ were already being run. New tests cover what was genuinely unreached:

  • committing when the context exits without an error (the upload path),
  • reopening an existing remote file, which downloads it before writing,
  • item assignment and membership on the wrapper,
  • removing the temp file and re-raising when the local h5py open fails.

get_format re-raising RemoteCacheError. The loop over FiberIOs swallows exceptions so a reader which does not recognize a file can be skipped; a failed remote fetch has to escape that handler rather than be reported as an unknown format. The test monkeypatches IOResourceManager.get_resource so it does not depend on which plugins happen to be installed.

The chunk-plan boundary guard becomes an assertion. This one is genuinely unreachable through the public API — sources within a partition are continuous (partitioning splits on gaps) and start-corrected, so the source searchsorted selects always overlaps its output. A test could only reach it by handing _build_members a state the partitioner cannot produce, which is an implementation detail rather than a boundary (thanks @codex for pushing back on the first attempt).

assert lo <= hi is the better shape for that: it states the invariant, runs on every iteration so it needs no exclusion, and fails loudly if the invariant ever breaks. Skipping was the wrong response in any case — dropping a source silently loses data, where an inverted interval would at least be visible. The assertion holds across the whole suite.

Result

No # pragma: no cover remains in dascore/utils/hdf5.py, dascore/utils/chunk_plan.py or dascore/io/core.py, and every line in them is covered. The three markers in dascore/utils/io.py and dascore/utils/remote_io.py are removed by #781, after which the package has none.

Validation

  • Full suite: 8229 passed, 89 skipped, 2 xfailed.
  • Non-network suite (what the coverage flag uploads): 8129 passed, with the only uncovered lines in the whole package being the two pre-existing ones in examples.py that CI covers through the generated doc-code tests.
  • pre-commit run --all: passed.

Changelog

none

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

  • Bug Fixes

    • Remote cache errors encountered during format detection are now propagated correctly instead of being reported as unknown formats.
    • Remote HDF5 writing is more reliable, including proper commit behavior on context-manager exit, safe append behavior, and correct in/item access.
    • Inconsistent chunk interval mapping now fails fast instead of being silently skipped.
  • Tests

    • Added regression coverage for remote cache error propagation.
    • Added remote HDF5 writer tests for commit, append preservation, item access/membership, and cleanup after open failures.

Seven "pragma: no cover" markers hid code from the coverage report
rather than from the test suite's reach. All seven are now tested:

- The remote HDF5 writer: committing on a clean context exit, reopening
  an existing remote file (which downloads it first), item assignment
  and membership, and cleaning up the temp file when the local open
  fails. Its five markers sat on def lines, so they excluded whole
  methods whose other lines were already exercised.
- get_format re-raising RemoteCacheError instead of treating a failed
  fetch as a wrong-format signal.
- The chunk-plan guard against a source disjoint from its output. The
  partitioner splits on gaps so this cannot arise through the public
  API, but _build_members can be handed such a pair directly, which
  pins the behavior the guard exists for.

The suite is now 100% covered without any pragma in these files.
@d-chambers d-chambers added the ready_for_review PR is ready for review label Jul 25, 2026
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Remote I/O validation

Layer / File(s) Summary
Format detection error propagation
dascore/io/core.py, tests/test_io/test_io_core.py
RemoteCacheError remains propagated during format detection, with a regression test covering the exception and message.
Remote HDF5 writer coverage
dascore/utils/hdf5.py, tests/test_utils/test_io_utils.py
Coverage annotations were removed from remote writer methods, and tests cover commits, appends, proxy operations, and temporary-file cleanup.

Chunk mapping validation

Layer / File(s) Summary
Chunk overlap invariant
dascore/utils/chunk_plan.py
Chunk member construction now asserts that computed source and output intervals overlap instead of silently skipping non-overlapping mappings.

Possibly related PRs

Suggested labels: IO, bug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title accurately summarizes the PR's main change: adding tests to cover paths previously hidden by coverage pragmas.
Description check ✅ Passed The description matches the template and includes a clear summary, validation results, and checklist items.
✨ 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 hdf5-pragmas

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25b1e6eb32

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/test_utils/test_chunk.py Outdated
)
outputs = pd.DataFrame({"output_id": [0], "time_min": [3.0], "time_max": [6.0]})

members = _build_members(sub, outputs, "time")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Test the guard through a public boundary

This test directly calls private _build_members with a disjoint source/output state that its own docstring acknowledges public partitioning cannot produce, so it couples coverage to an implementation detail without validating supported chunk-planning behavior. Exercise an equivalent boundary through build_chunk_plan, or retain the coverage exclusion if this is intentionally unreachable defensive code; .agents/agents.md specifically requires tests to focus on boundaries rather than implementation details. .agents/agents.mdL66-L72

Useful? React with 👍 / 👎.

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.

Agreed, and reverted in 005d3cd. Reaching that guard meant handing _build_members a source/output pair the partitioner cannot produce, which is an implementation detail rather than a boundary.

I did check whether it is reachable publicly first: sources within a partition are continuous (partitioning splits on gaps) and start-corrected, so the source searchsorted selects always overlaps the output. That matches the comment already on the guard, so it stays as documented defensive code with its exclusion.

The other six exclusions in this PR are gone, each replaced by a test of real behavior: the remote HDF5 writer's commit, append-downloads-existing, item access and temp-file cleanup paths, and get_format re-raising RemoteCacheError instead of treating a failed fetch as a wrong-format signal.

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.

Follow-up: the guard is now an assertion (523884d), which resolves this without either an artificial test or an exclusion.

assert lo <= hi, f"source {src_num} does not overlap output {out_num}"

The statement runs on every iteration, so it needs no pragma, and it states the invariant rather than hiding it. Skipping was the wrong response anyway: silently dropping a source loses data, where failing is at least visible. It holds across the full suite (8229 passed).

@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (d4a21fc) to head (523884d).
⚠️ Report is 1 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff            @@
##               dev      #785   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          164       164           
  Lines        17589     17619   +30     
=========================================
+ Hits         17589     17619   +30     
Flag Coverage Δ
network 48.27% <85.71%> (-0.05%) ⬇️
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.

Reverts the test which reached that guard by calling _build_members
directly. It could only get there by handing the function a state the
partitioner cannot produce, which tests an implementation detail rather
than a boundary, contrary to .agents/agents.md. Sources within a
partition are continuous and start-corrected, so no public call can
offer a source disjoint from its output; the guard stays as documented
defensive code with its exclusion.

The other six exclusions in this PR are covered by tests of real
behavior and remain removed.
@coderabbitai coderabbitai Bot added the IO Work for reading/writing different formats label Jul 26, 2026
The guard covered a state the partitioner cannot produce: sources within
a partition are continuous and start-corrected, so searchsorted never
offers one which does not overlap its output. Skipping was the wrong
response to that anyway, since dropping a source silently loses data.
Asserting says what the invariant is, fails loudly if it ever breaks,
and needs no coverage exclusion because the statement runs every
iteration. It holds across the whole suite.
@d-chambers d-chambers changed the title TST: test the paths excluded by coverage pragmas TST: cover the paths excluded by coverage pragmas Jul 26, 2026
@coderabbitai coderabbitai Bot added the bug Something isn't working label Jul 26, 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/utils/chunk_plan.py`:
- Around line 428-433: Replace the assert in the chunk-plan source/output
overlap handling with an explicit runtime check that raises the appropriate
failure when lo > hi, preventing an invalid member row from being appended under
python -O. Add a regression test covering this non-overlapping interval with
optimization enabled.
🪄 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: dae5b05c-c2e6-4040-a989-792ce0452bdd

📥 Commits

Reviewing files that changed from the base of the PR and between 005d3cd and 523884d.

📒 Files selected for processing (1)
  • dascore/utils/chunk_plan.py

Comment on lines +428 to +433
# Sources within a partition are continuous (partitioning
# splits on gaps) and start-corrected, so searchsorted never
# offers a source which does not overlap the output. Assert it
# rather than skipping: silently dropping a source would lose
# data, and the state cannot be reached from the public API.
assert lo <= hi, f"source {src_num} does not overlap output {out_num}"

@coderabbitai coderabbitai Bot Jul 26, 2026

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python -O - <<'PY'
def guard(lo, hi):
    assert lo <= hi
    return "invalid interval accepted"

assert guard(2, 1) == "invalid interval accepted"
PY

Repository: DASDAE/dascore

Length of output: 152


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | rg '(^|/)dascore/utils/chunk_plan\.py$' || true

echo "== relevant source =="
sed -n '400,445p' dascore/utils/chunk_plan.py

echo "== python -O assert semantics demonstration =="
tmpf="$(mktemp)"
cat > "$tmpf" <<'PY'
def guard(lo, hi):
    assert lo <= hi
    return "invalid interval accepted"

print(guard(2, 1))
PY
echo "without -O:"
python3 "$tmpf" || true
echo "with -O:"
python3 -O "$tmpf"
rm "$tmpf"

echo "== inspect pytest/optimize-related config =="
git ls-files | rg '(^|/)(pyproject\.toml|setup\.cfg|tox\.ini|noxfile\.py|pytest\.ini|Makefile)$' || true
for f in $(git ls-files | rg '(^|/)(pyproject\.toml|setup\.cfg|tox\.ini|noxfile\.py|pytest\.ini|Makefile)$'); do
  echo "--- $f ---"
  rg -n "opti|python.O|pytest|assert|noassert|assertions" "$f" || true
done

Repository: DASDAE/dascore

Length of output: 2990


Use an explicit runtime check instead of assert.

assert statements are skipped under python -O, so a non-overlapping lo > hi interval would fall through and append an invalid member row instead of failing.

Proposed fix
-            assert lo <= hi, f"source {src_num} does not overlap output {out_num}"
+            if lo > hi:
+                raise AssertionError(
+                    f"source {src_num} does not overlap output {out_num}"
+                )

Add a regression test for this path with optimization enabled.

📝 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
# Sources within a partition are continuous (partitioning
# splits on gaps) and start-corrected, so searchsorted never
# offers a source which does not overlap the output. Assert it
# rather than skipping: silently dropping a source would lose
# data, and the state cannot be reached from the public API.
assert lo <= hi, f"source {src_num} does not overlap output {out_num}"
# Sources within a partition are continuous (partitioning
# splits on gaps) and start-corrected, so searchsorted never
# offers a source which does not overlap the output. Assert it
# rather than skipping: silently dropping a source would lose
# data, and the state cannot be reached from the public API.
if lo > hi:
raise AssertionError(
f"source {src_num} does not overlap output {out_num}"
)
🤖 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/utils/chunk_plan.py` around lines 428 - 433, Replace the assert in
the chunk-plan source/output overlap handling with an explicit runtime check
that raises the appropriate failure when lo > hi, preventing an invalid member
row from being appended under python -O. Add a regression test covering this
non-overlapping interval with optimization enabled.

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.

Keeping the assert, deliberately.

The -O behaviour is real, but this is an internal invariant of the partitioner rather than validation of anything a caller supplies: sources within a partition are continuous (partitioning splits on gaps) and start-corrected, so searchsorted cannot offer a source disjoint from its output. That is the case asserts exist for, and it holds across the full suite (8229 tests).

An explicit raise would need its own coverage exclusion, since the raising line still never executes — which is what this PR set out to remove. A test could only reach it by handing _build_members a state the public API cannot produce, and @codex rightly pushed back on exactly that earlier in this PR (see the _build_members thread), since .agents/agents.md asks for boundary tests rather than implementation-detail tests.

One thing your comment did surface: dropping the old continue means that under -O an impossible state would append an invalid row instead of being skipped. Worth stating plainly rather than leaving implied — though it trades a check on an unreachable state for a clearer statement of the invariant, and skipping silently would have lost a source's data anyway.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Skipped: comment is from another GitHub bot.

@d-chambers
d-chambers merged commit 86dddf5 into dev Jul 26, 2026
29 checks passed
@d-chambers
d-chambers deleted the hdf5-pragmas branch July 26, 2026 04:48
@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 IO Work for reading/writing different formats

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant