Skip to content

Validate n_levels contract in contours()#2899

Merged
brendancol merged 2 commits into
mainfrom
issue-2895
Jun 3, 2026
Merged

Validate n_levels contract in contours()#2899
brendancol merged 2 commits into
mainfrom
issue-2895

Conversation

@brendancol

Copy link
Copy Markdown
Contributor

Closes #2895

What changed

  • contours() now validates n_levels on the auto-level branch (when levels is not passed). Non-integers (including bool) raise TypeError; values < 1 raise ValueError. Both messages name the parameter.
  • The check sits inside the if levels is None: block, so callers passing explicit levels are unaffected. n_levels is unused for them and is not validated.
  • The n_levels docstring documents the contract.

Before this, n_levels=0 or -1 silently returned no contours, and n_levels=2.5 leaked a raw numpy TypeError ("'float' object cannot be interpreted as an integer").

Backends

Scalar argument validation in the shared contours() entry point. No backend-specific code paths touched, so numpy / cupy / dask+numpy / dask+cupy all behave the same.

Test plan

  • n_levels=0 and n_levels=-1 raise ValueError
  • n_levels=2.5 and n_levels=True raise TypeError naming the parameter
  • n_levels=1 produces exactly one level
  • explicit levels with n_levels=0 still works (validation skipped)
  • full test_contour.py suite passes (52 tests)

n_levels is only consumed on the auto-level branch (levels is None).
Add a fail-fast check there: reject non-integers (including bool) with
TypeError and values < 1 with ValueError. Explicit-levels callers are
unaffected since n_levels is unused for them.

Previously n_levels=0/-1 silently returned no contours and n_levels=2.5
leaked a raw numpy TypeError.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Jun 3, 2026

@brendancol brendancol left a comment

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.

PR Review: Validate n_levels contract in contours()

Blockers (must fix before merge)

None.

Suggestions (should fix, not blocking)

None.

Nits (optional improvements)

  • Pre-existing, not from this PR: xrspatial/tests/test_contour.py:5 imports _contours_numpy, which flake8 flags as F401 (unused). It is already unused on main, so it is out of scope for this change. Flagging it so it does not get attributed to this PR.

What looks good

  • Validation lives inside the if levels is None: block (contour.py:627-636), so it only fires when n_levels is actually consumed. Passing an explicit levels with a junk n_levels is not rejected, which matches the documented contract and is covered by test_explicit_levels_skip_n_levels_validation.
  • bool is rejected explicitly even though it is an int subclass (contour.py:632). np.bool_ also lands in the TypeError branch since it is neither bool nor np.integer.
  • The type check runs before the < 1 comparison, so the range check never sees a non-int.
  • TypeError for wrong type and ValueError for out-of-range matches the convention in terrain_metrics.landforms and balanced_allocation.
  • Tests cover 0, -1, 2.5, True, the valid n_levels=1 single-level case, and the explicit-levels skip path.
  • Added line is 85 chars, under the repo's 100-char flake8 limit, so no wrap needed.

Checklist

  • Algorithm matches reference/paper (n/a, validation only)
  • All implemented backends produce consistent results (shared entry point, no backend code touched)
  • NaN handling is correct (unchanged)
  • Edge cases are covered by tests
  • Dask chunk boundaries handled correctly (n/a)
  • No premature materialization or unnecessary copies (scalar checks only)
  • Benchmark exists or is not needed (not needed)
  • README feature matrix updated (contours already listed; no change needed)
  • Docstrings present and accurate

@brendancol brendancol merged commit 847b291 into main Jun 3, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

contours(): n_levels has no validation contract

1 participant