Skip to content

nldi: fix several user-visible bugs in get_features, get_flowlines, search#252

Merged
thodson-usgs merged 4 commits intoDOI-USGS:mainfrom
thodson-usgs:fix/nldi-cleanup
May 4, 2026
Merged

nldi: fix several user-visible bugs in get_features, get_flowlines, search#252
thodson-usgs merged 4 commits intoDOI-USGS:mainfrom
thodson-usgs:fix/nldi-cleanup

Conversation

@thodson-usgs
Copy link
Copy Markdown
Collaborator

@thodson-usgs thodson-usgs commented May 3, 2026

Summary

Six discrete fixes to the NLDI module, bundled because they all touch the same file and individually each is small.

  • search(find="flowlines") without navigation_mode crashed with AttributeError: 'NoneType' object has no attribute 'upper' from inside _validate_navigation_mode. _validate_navigation_mode now treats None as a clean ValueError, returns the upper-cased value (so callers use the normalized form rather than silently sending lowercase), and raises ValueError rather than TypeError for invalid modes — these are bad values, not bad types. search also surfaces a clear error before delegating to get_flowlines.
  • get_flowlines(comid=...) silently dropped trim_start: the comid branch built query_params without trimStart. The shared params now live outside the branch.
  • lat=0.0 / long=0.0 / comid=0 were treated as missing because the code used if lat: / if comid: truthiness. Switched to is None checks throughout so the equator/prime meridian / COMID 0 are accepted.
  • The get_features error message had an unbalanced quote (feature_id 'USGS-X, and data source ...). Closing quote restored via a small _features_err_msg helper that the two branches share.
  • Unconditional _validate_data_source(feature_source) in get_features is now guarded by if feature_source: so it doesn't validate None once Fix nldi: validate data source on every call, not just cache-miss #246's cache fix lands.

Test plan

  • Three new regression tests in tests/nldi_test.py: search(find='flowlines') without nav-mode raises ValueError; _validate_navigation_mode raises ValueError on bad input; _validate_navigation_mode normalizes lowercase to uppercase. (Tests for the trim_start, falsy-zero, and unbalanced-quote fixes were dropped as trivial.)
  • All 14 existing nldi tests still pass.
  • Full local test suite passes.

Out of scope

The distance default mismatch between get_flowlines (5km) and search(distance=50) is a behavioral debate (which default should win, or should search simply pass through when unspecified) and worth a separate, focused PR if desired.

Related PRs

…earch

Bundles six discrete fixes to the NLDI module:

* `search(find='flowlines')` without `navigation_mode` crashed with
  `AttributeError: 'NoneType' object has no attribute 'upper'` from inside
  `_validate_navigation_mode`. `_validate_navigation_mode` now treats
  `None` as a clean `ValueError`, returns the upper-cased value (callers
  use the normalized form), and raises `ValueError` rather than
  `TypeError` for invalid modes — these are bad values, not bad types.
  `search` also surfaces a clear error before delegating to
  `get_flowlines`.

* `get_flowlines(comid=...)` silently dropped the `trim_start` argument:
  the `comid` branch built `query_params` without `trimStart`. Move the
  shared params out of the branch.

* `get_features(lat=0.0, ...)` and `search(lat=0.0, ...)` treated the
  equator/prime-meridian as missing because the code used `if lat:` /
  `if comid:` truthiness checks. Switch to `is None` checks throughout
  so coordinates of exactly zero are accepted and `comid=0` is no longer
  conflated with "no comid".

* The error message produced by `get_features` for feature-source +
  data-source paths had an unbalanced quote
  (`"feature_id 'USGS-X, and data source ..."`). Closing quote restored
  via a small `_features_err_msg` helper that the two branches share.

* The unconditional `_validate_data_source(feature_source)` in
  `get_features` is now guarded by `if feature_source:` to avoid
  validating `None` once the cache-bug fix (DOI-USGS#246) lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR applies a set of small, user-visible bug fixes in the nldi module (navigation-mode validation, query parameter handling, and “falsy” input handling) and adds regression tests to prevent reintroductions.

Changes:

  • Normalize and harden navigation_mode validation (handle None, return normalized uppercase value, raise ValueError for bad values).
  • Fix get_flowlines(comid=...) to include trimStart consistently (and refactor shared query params).
  • Fix “falsy” origin handling (accept lat=0.0 / long=0.0 / comid=0) and unify get_features error message formatting; add regression tests.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
dataretrieval/nldi.py Fixes navigation-mode validation/normalization, preserves trimStart for COMID flowline requests, corrects falsy checks for coordinates/COMIDs, and consolidates feature error messages.
tests/nldi_test.py Adds regression coverage for the fixed crashes/parameter drops/falsy handling and the corrected error message formatting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/nldi_test.py Outdated
get_flowlines(navigation_mode="UM", comid=13294314, trim_start=True)

sent = requests_mock.request_history[-1]
assert sent.qs.get("trimstart") == ["true"]
@thodson-usgs
Copy link
Copy Markdown
Collaborator Author

@copilot-pull-request-reviewer thanks for the review. Quick note on the one inline comment:

Declining: trimstart vs trimStart case sensitivity in the test.
The assertion sent.qs.get("trimstart") == ["true"] actually works as written because requests_mock's request.qs attribute is built via urllib.parse.parse_qs with default options, which lowercases keys. I verified this locally by running pytest tests/nldi_test.py::test_get_flowlines_by_comid_includes_trim_start — it passes. I'll keep the existing assertion (which exercises the parsed-key path) and won't switch to a URL-string assertion.

thodson-usgs and others added 3 commits May 4, 2026 10:34
Per /simplify review on PR DOI-USGS#252:
- Hoist `_VALID_NAVIGATION_MODES` to the module-level constants block
  alongside `NLDI_API_BASE_URL`/`_CRS` rather than wedging it between
  two `_validate_*` helpers.
- Drop the redundant `have_latlong` local in `get_features`; inline
  `lat is not None` directly. Hoist the duplicated
  `err_msg = _features_err_msg(...)` to a single call after the
  comid/feature-source if/else branch.
- Drop the unused `mock_request_data_sources` call in
  `test_get_flowlines_by_comid_includes_trim_start` — the comid path
  doesn't hit `_validate_data_source`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The trim_start drop, falsy-zero (lat/long/comid), and unbalanced-quote
fixes are each one-line changes whose regressions are obvious on read.
The remaining three tests (search-without-nav-mode crash, ValueError vs
TypeError, and lowercase normalization) cover behavior that's less
self-evident from the code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thodson-usgs thodson-usgs marked this pull request as ready for review May 4, 2026 18:05
@thodson-usgs thodson-usgs merged commit 5032b6c into DOI-USGS:main May 4, 2026
8 checks passed
@thodson-usgs thodson-usgs deleted the fix/nldi-cleanup branch May 4, 2026 18:07
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.

2 participants