Skip to content

Commit 04d94fd

Browse files
thodson-usgsclaude
andauthored
Add CQL filter passthrough to OGC waterdata getters (#238)
Last login: Sat Apr 18 10:01:59 on ttys007 c% thodson@IGSASC167LTTOH2 spherely % cd ~/Desktop/research/manuscripts/adaptive-rating/package thodson@IGSASC167LTTOH2 package % git status On branch main Your branch is ahead of 'origin/main' by 1 commit. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: src/adaptive_rating/kalman.py modified: src/adaptive_rating/model.py modified: src/adaptive_rating/spline.py modified: tests/test_model.py Untracked files: (use "git add <file>..." to include in what will be committed) camels_name.txt rating_demo_multisite.png rating_demo_single_10154200.png scripts/ablation_provo.py scripts/compare_usgs_03339000.py scripts/log_transform_comparison.py scripts/monospline_test.png scripts/rating_gp_demo.py scripts/stress_test_camels.py scripts/stress_test_control.py scripts/stress_test_direct.py scripts/stress_test_final.py scripts/stress_test_v2.py scripts/stress_test_v3.py scripts/stress_test_v4.py src/adaptive_rating/preprocessing.py stress_test_best.png stress_test_worst.png tests/test_preprocessing.py usgs_03339000_obs.png usgs_03339000_slices.png usgs_03339000_winter.png no changes added to commit (use "git add" and/or "git commit -a") thodson@IGSASC167LTTOH2 package % git add src/adaptive_rating/*.py thodson@IGSASC167LTTOH2 package % git commit -m"WIP" [main 58e17d4] WIP 4 files changed, 391 insertions(+), 140 deletions(-) create mode 100644 src/adaptive_rating/preprocessing.py thodson@IGSASC167LTTOH2 package % git push Enumerating objects: 22, done. Counting objects: 100% (22/22), done. Delta compression using up to 12 threads Compressing objects: 100% (12/12), done. Writing objects: 100% (14/14), 8.61 KiB | 4.30 MiB/s, done. Total 14 (delta 7), reused 0 (delta 0), pack-reused 0 (from 0) remote: Resolving deltas: 100% (7/7), completed with 6 local objects. To nodohs:nodohs/adaptive-rating.git 8719958..58e17d4 main -> main thodson@IGSASC167LTTOH2 package % git branch jump-process * main thodson@IGSASC167LTTOH2 package % cd ~/Desktop/dev/software/xarray thodson@IGSASC167LTTOH2 xarray % claude ▗ ▗ ▖ ▖ Claude Code v2.1.114 Opus 4.7 (1M context) with xhigh effort · Claude Max ▘▘ ▝▝ ~/Desktop/dev/software/xarray ❯ I started https://github.com/pydata/xarray/pull/11306 . Can you think about this change one more time and whether it might introduce any other bugs or failure modes. Thank you ⏺ Bash(git log -1 --stat f647a5cb) ⎿  commit f647a5cb27a65b4be18df6b6724bc5caa7ce148a Author: thodson-usgs <thodson@usgs.gov> Date: Sat Apr 18 09:42:37 2026 -0500 … +16 lines (ctrl+o to expand) ⏺ Bash(git show f647a5cb -- xarray/core/coordinates.py) ⎿  commit f647a5cb27a65b4be18df6b6724bc5caa7ce148a Author: thodson-usgs <thodson@usgs.gov> Date: Sat Apr 18 09:42:37 2026 -0500 … +25 lines (ctrl+o to expand) Read 1 file (ctrl+o to expand) ⏺ Bash(git log --all --oneline -- xarray/core/coordinates.py | head -15) ⎿  f647a5cb Fix Coordinates.to_index performance regression 97254417 Add an `arithmetic_compat` option to `xr.set_options` (#10943) 8bed33fe Fix mypy errors with newer pandas-stubs (#11066) … +12 lines (ctrl+o to expand) ⏺ Bash(git show a13a2556 -- xarray/core/coordinates.py | head -40) ⎿  commit a13a2556a29b3c5ba342a402b2598bab42939b46 Author: Maximilian Roos <5635139+max-sixty@users.noreply.github.com> Date: Wed Sep 3 19:48:28 2025 -0700 … +34 lines (ctrl+o to expand) Searched for 2 patterns (ctrl+o to expand) ⏺ Bash(uv run pytest xarray/tests/test_dataarray.py xarray/tests/test_dataset.py -k "to_index or stack or multi" -x -q 2>&1 | tail -30) ⎿  pyenv: uv: command not found The `uv' command exists in these Python versions: … +4 lines (ctrl+o to expand) ⏺ Bash(pyenv shell 3.13.3 && uv run pytest xarray/tests/test_dataarray.py xarray/tests/test_dataset.py -k "to_index or stack" -x -q 2>&1 | tail -15) ⎿  ............................... [100%] 31 passed, 1039 deselected in 2.43s ⏺ Reviewing the one-line change: codes=code_list, # was [list(c) for c in code_list] Where code_list is list[np.ndarray], each element freshly built via np.tile(np.repeat(code, …)). Failure modes I checked: 1. Value correctness — identical. list(ndarray) just produced numpy scalars that pandas re-packed; no data change. 2. Dtype — subtle behavioral shift: list(c) effectively widened codes to int64 inside pandas, whereas ndarrays keep their original dtype (int8/16/32 from MultiIndex.codes, int64 from pd.factorize). pandas' MultiIndex.__new__ accepts any integer dtype and fits them to the level size anyway, so this is a memory win, not a bug. 3. Empty cartesian product (cumprod_lengths[-1] == 0) — np.repeat(code, 0) → empty ndarray → np.tile preserves empty. pandas handles empty codes; the old [list(c) …] path hit the same branch. 4. NaN / -1 sentinels from pd.factorize — preserved either way. 5. Aliasing — each ndarray is freshly constructed inside the list-comp, nothing external holds a reference, so handing them to pandas is safe. 6. MultiIndex validation (verify_integrity=True default) — same codes, same levels, same result. Pre-existing, unrelated to this PR: repeat_counts is float64 from the cumprod_lengths[-1] / cumprod_lengths division, and np.repeat(code, float) will eventually be rejected by numpy. Worth noting but not in scope. Tests pass (-k "to_index or stack", 31 passed). I don't see a new failure mode — the fix is tight. ✻ Crunched for 1m 51s ※ recap: You're shipping PR #11306 to fix the Coordinates.to_index performance regression, and asked me to sanity-check the one-line change for new bugs. I reviewed it and found none; next step is yours to merge or request more checks. (disable recaps in /config) ❯ and you verified the timing improvement is real? Read 1 file (ctrl+o to expand) ⏺ Bash(pyenv shell 3.13.3 && uv run python -c " import timeit, numpy as np, xarray as xr…) ⎿  NEW (codes=code_list): min=0.224s, median=0.230s ⏺ Update(xarray/core/coordinates.py) ⎿  Added 1 line, removed 1 line 194 195 return pd.MultiIndex( 196 levels=level_list, # type: ignore[arg-type,unused-ignore] 197 - codes=code_list, # type: ignore[arg-type,unused-ignore] 197 + codes=[list(c) for c in code_list], 198 names=names, 199 ) 200 ⏺ Bash(pyenv shell 3.13.3 && uv run python -c " import timeit, numpy as np, xarray as xr…) ⎿  OLD (list comprehension): min=9.575s, median=9.686s ⏺ Update(xarray/core/coordinates.py) ⎿  Added 1 line, removed 1 line 194 195 return pd.MultiIndex( 196 levels=level_list, # type: ignore[arg-type,unused-ignore] 197 - codes=[list(c) for c in code_list], 197 + codes=code_list, # type: ignore[arg-type,unused-ignore] 198 names=names, 199 ) 200 ⏺ Yes, just verified on a 100×2000×300 DataArray (to_dataframe): - OLD ([list(c) for c in code_list]): median 9.69s - NEW (codes=code_list): median 0.23s ~42× speedup on this shape — consistent with the ~13s → sub-second figure in the commit message. Restored the file to the fixed version afterward. ✻ Churned for 1m 9s ※ recap: You're reviewing PR #11306 (fix for Coordinates.to_index perf regression) for any new bugs. I found none and confirmed a ~42× speedup benchmark. Next: decide whether the PR is ready to merge. (disable recaps in /config) ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ❯ /exit ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── /exit Exit the CLI /extra-usage Configure extra usage to keep working when limits are hit /context Visualize current context usage as a colored grid /claude-api Build, debug, and optimize Claude API / Anthropic SDK apps. Apps built with this skill should include pro… /memory Edit Claude memory files /ultraplan a few minutes · Claude Code on the web drafts a plan you can edit and approve. See https://code.claude.co… Resume this session with: claude --resume 4ee8f3cf-e067-490b-8b95-a006572fecab thodson@IGSASC167LTTOH2 xarray % cd .. thodson@IGSASC167LTTOH2 software % ls claude-code dataretrieval-python fluegg gumbridge ratingcurve spherely cubed DataRetrieval.jl fluegg_prev hytest schwarz-bridge xarray cubed-clone discontinuum frmc_mobile lithops schwarz-bridge-gpt xarray-regrid cubed-xarray discontinuum-delete frmc_python model_evaluation_kit schwarz-demo xdscore dataRetrieval earth2mip gplm_python numcodecs scratch zarr-python thodson@IGSASC167LTTOH2 software % cd dataretrieval-python thodson@IGSASC167LTTOH2 dataretrieval-python % git pull Already up to date. thodson@IGSASC167LTTOH2 dataretrieval-python % cd ../xarray thodson@IGSASC167LTTOH2 xarray % ls __pycache__ CODE_OF_CONDUCT.md HOW_TO_RELEASE.md script.py _stubtest conftest.py LICENSE uv.lock AI_POLICY.md CONTRIBUTING.md licenses xarray asv_bench CORE_TEAM_GUIDE.md pixi.toml xarray.egg-info ci DATATREE_MIGRATION_GUIDE.md properties CITATION.cff design_notes pyproject.toml CLAUDE.md doc README.md thodson@IGSASC167LTTOH2 xarray % claude ▗ ▗ ▖ ▖ Claude Code v2.1.116 Opus 4.7 (1M context) with xhigh effort · Claude Max ▘▘ ▝▝ ~/Desktop/dev/software/xarray ! git branch ⎿  * fix/11305-to-index-perf-regression main ! git checkout fix-sortby-tuple-4821 ⎿  Switched to a new branch 'fix-sortby-tuple-4821' branch 'fix-sortby-tuple-4821' set up to track 'origin/fix-sortby-tuple-4821'. ❯ Refer to https://github.com/pydata/xarray/pull/11297 I' submitted a bugfix to pytest-mypy-plugins, can you run the mypy tests locally (after updating the environment) and see if that fixes the failure. ⏺ Bash(gh pr view 11297 --json title,body,files,state,headRefName,statusCheckRollup) ⎿  Error: Exit code 1 GraphQL: Could not resolve to a PullRequest with the number of 11297. (repository.pullRequest) ⏺ Bash(gh pr view 11297 --repo pydata/xarray --json title,body,files,state,headRefName,statusCheckRollup) ⎿  {"body":"## Summary\n\n- Fixes `da.sortby(da.dims)` raising `KeyError` when `da.dims` is a tuple (e.g. `('x', 'y')`)\n- Tuples are now treated as iterables of variable names, consistent with the `str | Iterable[Hashable]` convention established in #6142\n\nCloses #482 1\n\n### Usage example\n\n```python\n>>> import xarray as xr\n>>> da = xr.DataArray(\n... [[1, 2], [3, 4], [5, 6]],\n... coord … +101 lines (ctrl+o to expand) ⏺ Let me get the details on the failing mypy test. ⏺ Bash(gh run view 24522563933 --repo pydata/xarray --log-failed 2>&1 | head -200) ⎿  ubuntu-latest | test-py311-with-typing (mypy) UNKNOWN STEP 2026-04-16T16:46:15.1164683Z Current runner version: '2.333.1' ubuntu-latest | test-py311-with-typing (mypy) UNKNOWN STEP 2026-04-16T16:46:15.1196068Z ##[group]Runner Image Provisioner ubuntu-latest | test-py311-with-typing (mypy) UNKNOWN STEP 2026-04-16T16:46:15.1197310Z Hosted Compute Agent … +211 lines (ctrl+o to expand) ⏺ Bash(gh run view 24522563933 --repo pydata/xarray --log-failed 2>&1 | grep -iE "(error|fail|mypy)" | head -50) ⎿  ubuntu-latest | test-py311-with-typing (mypy) UNKNOWN STEP 2026-04-16T16:46:15.1164683Z Current runner version: '2.333.1' ubuntu-latest | test-py311-with-typing (mypy) UNKNOWN STEP 2026-04-16T16:46:15.1196068Z ##[group]Runner Image Provisioner ubuntu-latest | test-py311-with-typing (mypy) UNKNOWN STEP 2026-04-16T16:46:15.1197310Z Hosted Compute Agent … +47 lines (ctrl+o to expand) ⏺ Bash(gh run view 24522563933 --repo pydata/xarray --log-failed --job 71684084342 2>&1 > /tmp/mypy_fail_log.txt; wc -l /tmp/mypy_fail_log.txt) ⎿   4173 /tmp/mypy_fail_log.txt Searched for 1 pattern, read 1 file (ctrl+o to expand) ⏺ Confirmed the CI failure: pytest_mypy_plugins/item.py:404 store.close() -> AttributeError: 'FilesystemMetadataStore' object has no attribute 'close' with pytest-mypy-plugins 4.0.1. Let me find how to run these tests locally. Searched for 4 patterns, listed 1 directory (ctrl+o to expand) ⏺ Bash(uv pip show pytest-mypy-plugins 2>&1 | head -20) ⎿  pyenv: uv: command not found The `uv' command exists in these Python versions: … +4 lines (ctrl+o to expand) ⏺ Bash(which -a uv python3; pyenv versions 2>/dev/null | head) ⎿  /Users/thodson/.pyenv/shims/uv /Users/thodson/.pyenv/shims/python3 /opt/homebrew/bin/python3 … +6 lines (ctrl+o to expand) ⏺ Bash(ls /Users/thodson/.pyenv/versions/3.13.3/bin/uv 2>/dev/null; /Users/thodson/.pyenv/versions/3.13.3/bin/uv --version) ⎿  /Users/thodson/.pyenv/versions/3.13.3/bin/uv uv 0.11.7 (9d177269e 2026-04-15 aarch64-apple-darwin) ⏺ Bash(/Users/thodson/.pyenv/versions/3.13.3/bin/uv pip show pytest-mypy-plugins 2>&1 | head -20) ⎿  Name: pytest-mypy-plugins Version: 4.0.2 Location: /Users/thodson/Desktop/dev/software/xarray/.venv/lib/python3.13/site-packages … +2 lines (ctrl+o to expand) ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv sync 2>&1 | tail -30) ⎿  Resolved 151 packages in 3ms Checked 145 packages in 274ms ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv pip install --upgrade pytest-mypy-plugins 2>&1 | tail -20) ⎿  Resolved 22 packages in 260ms Downloading mypy (12.7MiB) Downloaded mypy … +5 lines (ctrl+o to expand) ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv pip show pytest-mypy-plugins | head -5) ⎿  Name: pytest-mypy-plugins Version: 4.0.2 Location: /Users/thodson/Desktop/dev/software/xarray/.venv/lib/python3.13/site-packages … +2 lines (ctrl+o to expand) Read 1 file (ctrl+o to expand) ⏺ The fix is already in 4.0.2 (getattr(store, "close", None) guard at line 406). Let me run the mypy tests locally now. ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv run pytest xarray/tests/test_dataarray_typing.yml xarray/tests/test_dataset_typing.yml xarray/…) ⎿  Uninstalled 1 package in 176ms Installed 1 package in 37ms ============================= test session starts ============================== … +30 lines (ctrl+o to expand) ⎿  (timeout 10m) ⏺ The tests are all skipped. Let me find out why. Searched for 1 pattern (ctrl+o to expand) ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv run pytest xarray/tests/test_dataarray_typing.yml xarray/tests/test_dataset_typing.yml xarray/…) ⎿  E pytest_mypy_plugins.utils.TypecheckAssertionError: Invalid output: E Actual: E ../../../../../../Users/thodson/Desktop/dev/software/xarray/xarray/core/utils:117: error: Unused "type: ignore" comment [unused … +36 lines (ctrl+o to expand) ⎿  (timeout 10m) ⏺ The original FilesystemMetadataStore.close bug is gone — the fix is in 4.0.2. The new failures are unrelated (Unused "type: ignore") — they're caused by mypy 1.20.1 vs the CI-pinned 1.19.1. Let me downgrade mypy to match CI. ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv pip install "mypy==1.19.1" 2>&1 | tail -10) ⎿  Checked 1 package in 39ms ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv run --no-sync pytest xarray/tests/test_dataarray_typing.yml xarray/tests/test_dataset_typing.y…) ⎿  FAILED xarray/tests/test_dataset_typing.yml::test_mypy_pipe_function_missing_kwarg FAILED xarray/tests/test_dataset_typing.yml::test_mypy_pipe_function_missing_keyword FAILED xarray/tests/test_dataset_typing.yml::test_mypy_pipe_tuple_return_type_dataset … +17 lines (ctrl+o to expand) ⎿  (timeout 10m) ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv run --no-sync pytest xarray/tests/test_dataarray_typing.yml::test_mypy_pipe_lambda_noarg_retur…) ⎿  ============================= test session starts ============================== platform darwin -- Python 3.13.3, pytest-9.0.3, pluggy-1.6.0 rootdir: /Users/thodson/Desktop/dev/software/xarray … +24 lines (ctrl+o to expand) ⎿  (timeout 2m) ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv pip show mypy | head -3) ⎿  Name: mypy Version: 1.19.1 Location: /Users/thodson/Desktop/dev/software/xarray/.venv/lib/python3.13/site-packages Read 2 files (ctrl+o to expand) ⏺ Let me verify the Unused "type: ignore" errors are a pre-existing local env issue (pandas-stubs mismatch) and not caused by the sortby PR. ⏺ Bash(git stash -u 2>&1 | head -3; git checkout main 2>&1 | tail -3) ⎿  Saved working directory and index state WIP on fix-sortby-tuple-4821: 704014dc Fix type hints Switched to branch 'main' Your branch is up to date with 'origin/main'. ⏺ Bash(export PATH="/Users/thodson/.pyenv/versions/3.13.3/bin:$PATH"; uv run --no-sync pytest xarray/tests/test_dataarray_typing.yml::test_mypy_pipe_lambda_noarg_retur…) ⎿  xarray/tests/test_dataarray_typing.yml F [100%] =================================== FAILURES =================================== … +18 lines (ctrl+o to expand) ⎿  (timeout 2m) ⏺ Same failure on main — so the Unused "type: ignore" noise is a pre-existing local env issue (pandas-stubs mismatch with CI's pixi env), not caused by the sortby PR. Restoring the branch. ⏺ Bash(git checkout fix-sortby-tuple-4821 2>&1 | tail -3; git stash pop 2>&1 | tail -5) ⎿  Switched to branch 'fix-sortby-tuple-4821' Your branch is up to date with 'origin/fix-sortby-tuple-4821'. (use "git add <file>..." to include in what will be committed) … +4 lines (ctrl+o to expand) ⏺ Here's what I found: Yes, your pytest-mypy-plugins bugfix resolves the CI failure. The CI error was AttributeError: 'FilesystemMetadataStore' object has no attribute 'close' at pytest_mypy_plugins/item.py:404 store.close(). CI was pinned to pytest-mypy-plugins==4.0.1. Locally with pytest-mypy-plugins==4.0.2 (which uv sync picks up — pyproject.toml already pins >=4.0.0), that same file now wraps the call in a getattr(store, "close", None) guard at item.py:406-408. Running the 39 typing tests against your branch no longer crashes at teardown — so the FilesystemMetadataStore.close failure is gone. However, the tests still fail locally with a different, unrelated issue: xarray/core/utils:117: error: Unused "type: ignore" comment [unused-ignore] xarray/core/variable:73: error: Unused "type: ignore" comment [unused-ignore] I confirmed this happens on main too (with the fixed plugin), so it's noise from my local env (pandas-stubs divergence from CI's pixi test-py311-with-typing env, which pins mypy==1.19.1 plus specific stubs) — not caused by your sortby PR. Recommendation: once CI picks up pytest-mypy-plugins>=4.0.2 (either by re-resolving the pixi lockfile or bumping the floor in pixi.toml/pyproject.toml), the test-py311-with-typing (mypy) job should run the 39 pipe typing cases instead of crashing in teardown — so the sortby PR should go green without any change to the PR itself. ✻ Baked for 9m 34s ※ recap: Verifying whether your pytest-mypy-plugins bugfix resolves the mypy CI failure on PR 11297; confirmed it does (4.0.2 removes the FilesystemMetadataStore.close crash). Next: bump the pinned floor to pytest-mypy-plugins>=4.0.2 in pixi.toml so CI picks it up. (disable recaps in /config) ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ❯  ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ? for shortcuts control this session from your phone · /remote-control ⎿  Switched to branch 'fix-sortby-tuple-4821' Your branch is up to date with 'origin/fix-sortby-tuple-4821'. (use "git add <file>..." to include in what will be committed) … +4 lines (ctrl+o to expand) ⏺ Here's what I found: Yes, your pytest-mypy-plugins bugfix resolves the CI failure. The CI error was AttributeError: 'FilesystemMetadataStore' object has no attribute 'close' at pytest_mypy_plugins/item.py:404 store.close(). CI was pinned to pytest-mypy-plugins==4.0.1. Locally with pytest-mypy-plugins==4.0.2 (which uv sync picks up — pyproject.toml already pins >=4.0.0), that same file now wraps the call in a getattr(store, "close", None) guard at item.py:406-408. Running the 39 typing tests against your branch no longer crashes at teardown — so the FilesystemMetadataStore.close failure is gone. However, the tests still fail locally with a different, unrelated issue: xarray/core/utils:117: error: Unused "type: ignore" comment [unused-ignore] xarray/core/variable:73: error: Unused "type: ignore" comment [unused-ignore] I confirmed this happens on main too (with the fixed plugin), so it's noise from my local env (pandas-stubs divergence from CI's pixi test-py311-with-typing env, which pins mypy==1.19.1 plus specific stubs) — not caused by your sortby PR. Recommendation: once CI picks up pytest-mypy-plugins>=4.0.2 (either by re-resolving the pixi lockfile or bumping the floor in pixi.toml/pyproject.toml), the test-py311-with-typing (mypy) job should run the 39 pipe typing cases instead of crashing in teardown — so the sortby PR should go green without any change to the PR itself. ✻ Baked for 9m 34s ※ recap: Verifying whether your pytest-mypy-plugins bugfix resolves the mypy CI failure on PR 11297; confirmed it does (4.0.2 removes the FilesystemMetadataStore.close crash). Next: bump the pinned floor to pytest-mypy-plugins>=4.0.2 in pixi.toml so CI picks it up. (disable recaps in /config) ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ❯  ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ? for shortcuts control this session from your phone · /remote-control (use "git add <file>..." to include in what will be committed) … +4 lines (ctrl+o to expand) ⏺ Here's what I found: Yes, your pytest-mypy-plugins bugfix resolves the CI failure. The CI error was AttributeError: 'FilesystemMetadataStore' object has no attribute 'close' at pytest_mypy_plugins/item.py:404 store.close(). CI was pinned to pytest-mypy-plugins==4.0.1. Locally with pytest-mypy-plugins==4.0.2 (which uv sync picks up — pyproject.toml already pins >=4.0.0), that same file now wraps the call in a getattr(store, "close", None) guard at item.py:406-408. Running the 39 typing tests against your branch no longer crashes at teardown — so the FilesystemMetadataStore.close failure is gone. However, the tests still fail locally with a different, unrelated issue: xarray/core/utils:117: error: Unused "type: ignore" comment [unused-ignore] xarray/core/variable:73: error: Unused "type: ignore" comment [unused-ignore] I confirmed this happens on main too (with the fixed plugin), so it's noise from my local env (pandas-stubs divergence from CI's pixi test-py311-with-typing env, which pins mypy==1.19.1 plus specific stubs) — not caused by your sortby PR. Recommendation: once CI picks up pytest-mypy-plugins>=4.0.2 (either by re-resolving the pixi lockfile or bumping the floor in pixi.toml/pyproject.toml), the test-py311-with-typing (mypy) job should run the 39 pipe typing cases instead of crashing in teardown — so the sortby PR should go green without any change to the PR itself. ✻ Baked for 9m 34s ※ recap: Verifying whether your pytest-mypy-plugins bugfix resolves the mypy CI failure on PR 11297; confirmed it does (4.0.2 removes the FilesystemMetadataStore.close crash). Next: bump the pinned floor to pytest-mypy-plugins>=4.0.2 in pixi.toml so CI picks it up. (disable recaps in /config) ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ❯  ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ? for shortcuts control this session from your phone · /remote-control ⎿  (timeout 2m) ⏺ Same failure on main — so the Unused "type: ignore" noise is a pre-existing local env issue (pandas-stubs mismatch with CI's pixi env), not caused by the sortby PR. Restoring the branch. ⏺ Bash(git checkout fix-sortby-tuple-4821 2>&1 | tail -3; git stash pop 2>&1 | tail -5) ⎿  Switched to branch 'fix-sortby-tuple-4821' Your branch is up to date with 'origin/fix-sortby-tuple-4821'. (use "git add <file>..." to include in what will be committed) … +4 lines (ctrl+o to expand) ⏺ Here's what I found: Yes, your pytest-mypy-plugins bugfix resolves the CI failure. The CI error was AttributeError: 'FilesystemMetadataStore' object has no attribute 'close' at pytest_mypy_plugins/item.py:404 store.close(). CI was pinned to pytest-mypy-plugins==4.0.1. Locally with pytest-mypy-plugins==4.0.2 (which uv sync picks up — pyproject.toml already pins >=4.0.0), that same file now wraps the call in a getattr(store, "close", None) guard at item.py:406-408. Running the 39 typing tests against your branch no longer crashes at teardown — so the FilesystemMetadataStore.close failure is gone. However, the tests still fail locally with a different, unrelated issue: xarray/core/utils:117: error: Unused "type: ignore" comment [unused-ignore] xarray/core/variable:73: error: Unused "type: ignore" comment [unused-ignore] I confirmed this happens on main too (with the fixed plugin), so it's noise from my local env (pandas-stubs divergence from CI's pixi test-py311-with-typing env, which pins mypy==1.19.1 plus specific stubs) — not caused by your sortby PR. Recommendation: once CI picks up pytest-mypy-plugins>=4.0.2 (either by re-resolving the pixi lockfile or bumping the floor in pixi.toml/pyproject.toml), the test-py311-with-typing (mypy) job should run the 39 pipe typing cases instead of crashing in teardown — so the sortby PR should go green without any change to the PR itself. ✻ Baked for 9m 34s ※ recap: Verifying whether your pytest-mypy-plugins bugfix resolves the mypy CI failure on PR 11297; confirmed it does (4.0.2 removes the FilesystemMetadataStore.close crash). Next: bump the pinned floor to pytest-mypy-plugins>=4.0.2 in pixi.toml so CI picks it up. (disable recaps in /config) ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ❯  ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ? for shortcuts control this session from your phone · /remote-control (use "git add <file>..." to include in what will be committed) … +4 lines (ctrl+o to expand) ⏺ Here's what I found: Yes, your pytest-mypy-plugins bugfix resolves the CI failure. The CI error was AttributeError: 'FilesystemMetadataStore' object has no attribute 'close' at pytest_mypy_plugins/item.py:404 store.close(). CI was pinned to pytest-mypy-plugins==4.0.1. Locally with pytest-mypy-plugins==4.0.2 (which uv sync picks up — pyproject.toml already pins >=4.0.0), that same file now wraps the call in a getattr(store, "close", None) guard at item.py:406-408. Running the 39 typing tests against your branch no longer crashes at teardown — so the FilesystemMetadataStore.close failure is gone. However, the tests still fail locally with a different, unrelated issue: xarray/core/utils:117: error: Unused "type: ignore" comment [unused-ignore] xarray/core/variable:73: error: Unused "type: ignore" comment [unused-ignore] I confirmed this happens on main too (with the fixed plugin), so it's noise from my local env (pandas-stubs divergence from CI's pixi test-py311-with-typing env, which pins mypy==1.19.1 plus specific stubs) — not caused by your sortby PR. Recommendation: once CI picks up pytest-mypy-plugins>=4.0.2 (either by re-resolving the pixi lockfile or bumping the floor in pixi.toml/pyproject.toml), the test-py311-with-typing (mypy) job should run the 39 pipe typing cases instead of crashing in teardown — so the sortby PR should go green without any change to the PR itself. ✻ Baked for 9m 34s ※ recap: Verifying whether your pytest-mypy-plugins bugfix resolves the mypy CI failure on PR 11297; confirmed it does (4.0.2 removes the FilesystemMetadataStore.close crash). Next: bump the pinned floor to pytest-mypy-plugins>=4.0.2 in pixi.toml so CI picks it up. (disable recaps in /config) ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ❯ /exit ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── /exit Exit the CLI /extra-usage Configure extra usage to keep working when limits are hit /context Visualize current context usage as a colored grid /claude-api Build, debug, and optimize Claude API / Anthropic SDK apps. Apps built with this skill should include prompt … /memory Edit Claude memory files /ultraplan a few minutes · Claude Code on the web drafts a plan you can edit and approve. See https://code.claude.com/do… Resume this session with: claude --resume d7e3e421-faa6-4d82-bc55-0dc4683f21d7 thodson@IGSASC167LTTOH2 xarray % cd .. thodson@IGSASC167LTTOH2 software % ls claude-code dataretrieval-python fluegg gumbridge ratingcurve spherely cubed DataRetrieval.jl fluegg_prev hytest schwarz-bridge xarray cubed-clone discontinuum frmc_mobile lithops schwarz-bridge-gpt xarray-regrid cubed-xarray discontinuum-delete frmc_python model_evaluation_kit schwarz-demo xdscore dataRetrieval earth2mip gplm_python numcodecs scratch zarr-python thodson@IGSASC167LTTOH2 software % git clone --depth 10 git@github.com:thodson-usgs/sparse.git Cloning into 'sparse'... remote: Enumerating objects: 206, done. remote: Counting objects: 100% (206/206), done. remote: Compressing objects: 100% (186/186), done. remote: Total 206 (delta 40), reused 92 (delta 11), pack-reused 0 (from 0) Receiving objects: 100% (206/206), 748.15 KiB | 5.12 MiB/s, done. Resolving deltas: 100% (40/40), done. thodson@IGSASC167LTTOH2 software % cd sparse thodson@IGSASC167LTTOH2 sparse % ls benchmarks docs mkdocs.yml pyproject.toml release-procedure.md sparse benchmarks_original examples pixi.lock pytest.ini scripts tox.ini conftest.py LICENSE pixi.toml README.md setup.cfg xp-tests thodson@IGSASC167LTTOH2 sparse % claude ╭─── Claude Code v2.1.116 ───────────────────────────────────────────────────────────────────────────────────────────────╮ │ │ Tips for getting started │ │ Welcome back Timothy! │ Run /init to create a CLAUDE.md file with instructions for Claude │ │ │ ───────────────────────────────────────────────────────────────── │ │ ▗ ▗ ▖ ▖ │ Recent activity │ │ │ No recent activity │ │ ▘▘ ▝▝ │ │ │ Opus 4.7 (1M context) with xh… · Claude Max · │ │ │ tohodson@gmail.com's Organization │ │ │ ~/Desktop/dev/software/sparse │ │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ❯ /init and review the contribution guidelines and dev environment config and set up a local dev environment for this repo Read 6 files, listed 4 directories (ctrl+o to expand) Read 7 files, listed 1 directory (ctrl+o to expand) ⏺ Bash(which pixi 2>/dev/null; pixi --version 2>/dev/null || echo "pixi not installed") ⎿  Running… 4 tasks (0 done, 1 in progress, 3 open) ◼ Explore repo architecture and dev docs ◻ Review contribution guidelines ◻ Set up local dev environment ◻ Write CLAUDE.md ──────────────────────────────────────────────────────────────────────────────────────…
1 parent 224f4bc commit 04d94fd

6 files changed

Lines changed: 859 additions & 16 deletions

File tree

NEWS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
**04/22/2026:** Highlights since the `v1.1.0` release (2025-11-26), which shipped the `waterdata` module:
2+
3+
- Added `get_channel` for channel-measurement data (#218) and `get_stats_por` / `get_stats_date_range` for period-of-record and daily statistics (#207).
4+
- Added `get_reference_table` (and made it considerably simpler and faster in #209), then extended it to accept arbitrary collections-API query parameters (#214).
5+
- Removed the deprecated `waterwatch` module (#228) and several defunct NWIS stubs (#222, #225), and added `py.typed` so `dataretrieval` ships type information to downstream users (#186).
6+
- Now supports `pandas` 3.x (#221).
7+
- The OGC `waterdata` getters (`get_continuous`, `get_daily`, `get_field_measurements`, and the six others built on the same OGC collections) now accept `filter` and `filter_lang` kwargs that are passed through to the service's CQL filter parameter. This enables advanced server-side filtering that isn't expressible via the other kwargs — most commonly, OR'ing multiple time ranges into a single request. A long expression made up of a top-level `OR` chain is transparently split into multiple requests that each fit under the server's URI length limit, and the results are concatenated.
8+
19
**12/04/2025:** The `get_continuous()` function was added to the `waterdata` module, which provides access to measurements collected via automated sensors at a high frequency (often 15 minute intervals) at a monitoring location. This is an early version of the continuous endpoint and should be used with caution as the API team improves its performance. In the future, we anticipate the addition of an endpoint(s) specifically for handling large data requests, so it may make sense for power users to hold off on heavy development using the new continuous endpoint.
210

311
**11/24/2025:** `dataretrieval` is pleased to offer a new module, `waterdata`, which gives users access USGS's modernized [Water Data APIs](https://api.waterdata.usgs.gov/). The Water Data API endpoints include daily values, instantaneous values, field measurements (modernized groundwater levels service), time series metadata, and discrete water quality data from the Samples database. Though there will be a period of overlap, the functions within `waterdata` will eventually replace the `nwis` module, which currently provides access to the legacy [NWIS Water Services](https://waterservices.usgs.gov/). More example workflows and functions coming soon. Check `help(waterdata)` for more information.

dataretrieval/waterdata/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@
2727
)
2828
from .types import (
2929
CODE_SERVICES,
30+
FILTER_LANG,
3031
PROFILE_LOOKUP,
3132
PROFILES,
3233
SERVICES,
3334
)
3435

3536
__all__ = [
3637
"CODE_SERVICES",
38+
"FILTER_LANG",
3739
"PROFILES",
3840
"PROFILE_LOOKUP",
3941
"SERVICES",

dataretrieval/waterdata/api.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from dataretrieval.utils import BaseMetadata, to_str
1919
from dataretrieval.waterdata.types import (
2020
CODE_SERVICES,
21+
FILTER_LANG,
2122
METADATA_COLLECTIONS,
2223
PROFILES,
2324
SERVICES,
@@ -51,6 +52,8 @@ def get_daily(
5152
time: str | list[str] | None = None,
5253
bbox: list[float] | None = None,
5354
limit: int | None = None,
55+
filter: str | None = None,
56+
filter_lang: FILTER_LANG | None = None,
5457
convert_type: bool = True,
5558
) -> tuple[pd.DataFrame, BaseMetadata]:
5659
"""Daily data provide one data value to represent water conditions for the
@@ -177,6 +180,18 @@ def get_daily(
177180
allowable limit is 50000. It may be beneficial to set this number lower
178181
if your internet connection is spotty. The default (NA) will set the
179182
limit to the maximum allowable limit for the service.
183+
filter : string, optional
184+
A CQL text or JSON expression passed through to the OGC API
185+
``filter`` query parameter. Commonly used to OR several time
186+
ranges into a single request. At the time of writing the server
187+
accepts ``cql-text`` (default) and ``cql-json``; ``cql2-text`` /
188+
``cql2-json`` are not yet supported. A long expression made up
189+
of a top-level ``OR`` chain is automatically split into
190+
multiple requests that each fit under the server's URI length
191+
limit; the results are concatenated.
192+
filter_lang : string, optional
193+
Language of the ``filter`` expression, for example ``cql-text``
194+
(default) or ``cql-json``. Sent as ``filter-lang`` in the URL.
180195
convert_type : boolean, optional
181196
If True, converts columns to appropriate types.
182197
@@ -228,6 +243,8 @@ def get_continuous(
228243
last_modified: str | None = None,
229244
time: str | list[str] | None = None,
230245
limit: int | None = None,
246+
filter: str | None = None,
247+
filter_lang: FILTER_LANG | None = None,
231248
convert_type: bool = True,
232249
) -> tuple[pd.DataFrame, BaseMetadata]:
233250
"""
@@ -348,6 +365,18 @@ def get_continuous(
348365
allowable limit is 10000. It may be beneficial to set this number lower
349366
if your internet connection is spotty. The default (NA) will set the
350367
limit to the maximum allowable limit for the service.
368+
filter : string, optional
369+
A CQL text or JSON expression passed through to the OGC API
370+
``filter`` query parameter. Commonly used to OR several time
371+
ranges into a single request. At the time of writing the server
372+
accepts ``cql-text`` (default) and ``cql-json``; ``cql2-text`` /
373+
``cql2-json`` are not yet supported. A long expression made up
374+
of a top-level ``OR`` chain is automatically split into
375+
multiple requests that each fit under the server's URI length
376+
limit; the results are concatenated.
377+
filter_lang : string, optional
378+
Language of the ``filter`` expression, for example ``cql-text``
379+
(default) or ``cql-json``. Sent as ``filter-lang`` in the URL.
351380
convert_type : boolean, optional
352381
If True, the function will convert the data to dates and qualifier to
353382
string vector
@@ -370,6 +399,37 @@ def get_continuous(
370399
... parameter_code="00065",
371400
... time="2021-01-01T00:00:00Z/2022-01-01T00:00:00Z",
372401
... )
402+
403+
>>> # The ``time`` parameter accepts a single instant or a single
404+
>>> # interval. To pull several disjoint windows in one call, pass a
405+
>>> # CQL-text ``filter`` expression instead:
406+
>>> df, md = dataretrieval.waterdata.get_continuous(
407+
... monitoring_location_id="USGS-02238500",
408+
... parameter_code="00060",
409+
... filter=(
410+
... "(time >= '2023-06-01T12:00:00Z' "
411+
... "AND time <= '2023-06-01T13:00:00Z') "
412+
... "OR (time >= '2023-06-15T12:00:00Z' "
413+
... "AND time <= '2023-06-15T13:00:00Z')"
414+
... ),
415+
... filter_lang="cql-text",
416+
... )
417+
418+
>>> # Long top-level ``OR`` chains (e.g. one window per discrete
419+
>>> # measurement timestamp) are built up the same way. If the
420+
>>> # resulting URL would exceed the server's length limit, the
421+
>>> # client transparently splits it into multiple sub-requests and
422+
>>> # returns the concatenated, deduplicated result.
423+
>>> windows = [
424+
... f"(time >= '2023-{m:02d}-15T00:00:00Z' "
425+
... f"AND time <= '2023-{m:02d}-15T00:30:00Z')"
426+
... for m in range(1, 13)
427+
... ]
428+
>>> df, md = dataretrieval.waterdata.get_continuous(
429+
... monitoring_location_id="USGS-02238500",
430+
... parameter_code="00060",
431+
... filter=" OR ".join(windows),
432+
... )
373433
"""
374434
service = "continuous"
375435
output_id = "continuous_id"
@@ -426,6 +486,8 @@ def get_monitoring_locations(
426486
time: str | list[str] | None = None,
427487
bbox: list[float] | None = None,
428488
limit: int | None = None,
489+
filter: str | None = None,
490+
filter_lang: FILTER_LANG | None = None,
429491
convert_type: bool = True,
430492
) -> tuple[pd.DataFrame, BaseMetadata]:
431493
"""Location information is basic information about the monitoring location
@@ -635,6 +697,18 @@ def get_monitoring_locations(
635697
The returning object will be a data frame with no spatial information.
636698
Note that the USGS Water Data APIs use camelCase "skipGeometry" in
637699
CQL2 queries.
700+
filter : string, optional
701+
A CQL text or JSON expression passed through to the OGC API
702+
``filter`` query parameter. Commonly used to OR several time
703+
ranges into a single request. At the time of writing the server
704+
accepts ``cql-text`` (default) and ``cql-json``; ``cql2-text`` /
705+
``cql2-json`` are not yet supported. A long expression made up
706+
of a top-level ``OR`` chain is automatically split into
707+
multiple requests that each fit under the server's URI length
708+
limit; the results are concatenated.
709+
filter_lang : string, optional
710+
Language of the ``filter`` expression, for example ``cql-text``
711+
(default) or ``cql-json``. Sent as ``filter-lang`` in the URL.
638712
convert_type : boolean, optional
639713
If True, converts columns to appropriate types.
640714
@@ -697,6 +771,8 @@ def get_time_series_metadata(
697771
time: str | list[str] | None = None,
698772
bbox: list[float] | None = None,
699773
limit: int | None = None,
774+
filter: str | None = None,
775+
filter_lang: FILTER_LANG | None = None,
700776
convert_type: bool = True,
701777
) -> tuple[pd.DataFrame, BaseMetadata]:
702778
"""Daily data and continuous measurements are grouped into time series,
@@ -851,6 +927,18 @@ def get_time_series_metadata(
851927
allowable limit is 50000. It may be beneficial to set this number lower
852928
if your internet connection is spotty. The default (None) will set the
853929
limit to the maximum allowable limit for the service.
930+
filter : string, optional
931+
A CQL text or JSON expression passed through to the OGC API
932+
``filter`` query parameter. Commonly used to OR several time
933+
ranges into a single request. At the time of writing the server
934+
accepts ``cql-text`` (default) and ``cql-json``; ``cql2-text`` /
935+
``cql2-json`` are not yet supported. A long expression made up
936+
of a top-level ``OR`` chain is automatically split into
937+
multiple requests that each fit under the server's URI length
938+
limit; the results are concatenated.
939+
filter_lang : string, optional
940+
Language of the ``filter`` expression, for example ``cql-text``
941+
(default) or ``cql-json``. Sent as ``filter-lang`` in the URL.
854942
convert_type : boolean, optional
855943
If True, converts columns to appropriate types.
856944
@@ -903,6 +991,8 @@ def get_latest_continuous(
903991
time: str | list[str] | None = None,
904992
bbox: list[float] | None = None,
905993
limit: int | None = None,
994+
filter: str | None = None,
995+
filter_lang: FILTER_LANG | None = None,
906996
convert_type: bool = True,
907997
) -> tuple[pd.DataFrame, BaseMetadata]:
908998
"""This endpoint provides the most recent observation for each time series
@@ -1026,6 +1116,18 @@ def get_latest_continuous(
10261116
allowable limit is 50000. It may be beneficial to set this number lower
10271117
if your internet connection is spotty. The default (None) will set the
10281118
limit to the maximum allowable limit for the service.
1119+
filter : string, optional
1120+
A CQL text or JSON expression passed through to the OGC API
1121+
``filter`` query parameter. Commonly used to OR several time
1122+
ranges into a single request. At the time of writing the server
1123+
accepts ``cql-text`` (default) and ``cql-json``; ``cql2-text`` /
1124+
``cql2-json`` are not yet supported. A long expression made up
1125+
of a top-level ``OR`` chain is automatically split into
1126+
multiple requests that each fit under the server's URI length
1127+
limit; the results are concatenated.
1128+
filter_lang : string, optional
1129+
Language of the ``filter`` expression, for example ``cql-text``
1130+
(default) or ``cql-json``. Sent as ``filter-lang`` in the URL.
10291131
convert_type : boolean, optional
10301132
If True, converts columns to appropriate types.
10311133
@@ -1075,6 +1177,8 @@ def get_latest_daily(
10751177
time: str | list[str] | None = None,
10761178
bbox: list[float] | None = None,
10771179
limit: int | None = None,
1180+
filter: str | None = None,
1181+
filter_lang: FILTER_LANG | None = None,
10781182
convert_type: bool = True,
10791183
) -> tuple[pd.DataFrame, BaseMetadata]:
10801184
"""Daily data provide one data value to represent water conditions for the
@@ -1200,6 +1304,18 @@ def get_latest_daily(
12001304
allowable limit is 50000. It may be beneficial to set this number lower
12011305
if your internet connection is spotty. The default (None) will set the
12021306
limit to the maximum allowable limit for the service.
1307+
filter : string, optional
1308+
A CQL text or JSON expression passed through to the OGC API
1309+
``filter`` query parameter. Commonly used to OR several time
1310+
ranges into a single request. At the time of writing the server
1311+
accepts ``cql-text`` (default) and ``cql-json``; ``cql2-text`` /
1312+
``cql2-json`` are not yet supported. A long expression made up
1313+
of a top-level ``OR`` chain is automatically split into
1314+
multiple requests that each fit under the server's URI length
1315+
limit; the results are concatenated.
1316+
filter_lang : string, optional
1317+
Language of the ``filter`` expression, for example ``cql-text``
1318+
(default) or ``cql-json``. Sent as ``filter-lang`` in the URL.
12031319
convert_type : boolean, optional
12041320
If True, converts columns to appropriate types.
12051321
@@ -1251,6 +1367,8 @@ def get_field_measurements(
12511367
time: str | list[str] | None = None,
12521368
bbox: list[float] | None = None,
12531369
limit: int | None = None,
1370+
filter: str | None = None,
1371+
filter_lang: FILTER_LANG | None = None,
12541372
convert_type: bool = True,
12551373
) -> tuple[pd.DataFrame, BaseMetadata]:
12561374
"""Field measurements are physically measured values collected during a
@@ -1366,6 +1484,18 @@ def get_field_measurements(
13661484
allowable limit is 50000. It may be beneficial to set this number lower
13671485
if your internet connection is spotty. The default (None) will set the
13681486
limit to the maximum allowable limit for the service.
1487+
filter : string, optional
1488+
A CQL text or JSON expression passed through to the OGC API
1489+
``filter`` query parameter. Commonly used to OR several time
1490+
ranges into a single request. At the time of writing the server
1491+
accepts ``cql-text`` (default) and ``cql-json``; ``cql2-text`` /
1492+
``cql2-json`` are not yet supported. A long expression made up
1493+
of a top-level ``OR`` chain is automatically split into
1494+
multiple requests that each fit under the server's URI length
1495+
limit; the results are concatenated.
1496+
filter_lang : string, optional
1497+
Language of the ``filter`` expression, for example ``cql-text``
1498+
(default) or ``cql-json``. Sent as ``filter-lang`` in the URL.
13691499
convert_type : boolean, optional
13701500
If True, converts columns to appropriate types.
13711501
@@ -2017,6 +2147,8 @@ def get_channel(
20172147
skip_geometry: bool | None = None,
20182148
bbox: list[float] | None = None,
20192149
limit: int | None = None,
2150+
filter: str | None = None,
2151+
filter_lang: FILTER_LANG | None = None,
20202152
convert_type: bool = True,
20212153
) -> tuple[pd.DataFrame, BaseMetadata]:
20222154
"""
@@ -2123,6 +2255,18 @@ def get_channel(
21232255
vertical_velocity_description, longitudinal_velocity_description,
21242256
measurement_type, last_modified, channel_measurement_type. The default (NA) will
21252257
return all columns of the data.
2258+
filter : string, optional
2259+
A CQL text or JSON expression passed through to the OGC API
2260+
``filter`` query parameter. Commonly used to OR several time
2261+
ranges into a single request. At the time of writing the server
2262+
accepts ``cql-text`` (default) and ``cql-json``; ``cql2-text`` /
2263+
``cql2-json`` are not yet supported. A long expression made up
2264+
of a top-level ``OR`` chain is automatically split into
2265+
multiple requests that each fit under the server's URI length
2266+
limit; the results are concatenated.
2267+
filter_lang : string, optional
2268+
Language of the ``filter`` expression, for example ``cql-text``
2269+
(default) or ``cql-json``. Sent as ``filter-lang`` in the URL.
21262270
convert_type : boolean, optional
21272271
If True, the function will convert the data to dates and qualifier to
21282272
string vector

dataretrieval/waterdata/types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
"results",
4141
]
4242

43+
FILTER_LANG = Literal["cql-text", "cql-json"]
44+
4345
PROFILES = Literal[
4446
"actgroup",
4547
"actmetric",

0 commit comments

Comments
 (0)