06/23/2026: Breaking change (1.2.0): the minimum supported Python is now 3.10 (requires-python = ">=3.10"). 3.9 support was already effectively broken — the waterdata module's dependencies (anyio, the test stack) require 3.10+, and the waterdata test modules already skipped on <3.10. anyio is now declared as a direct dependency (it is imported directly by waterdata), and the CI/ruff/mypy targets move to 3.10. Also fully removed the deprecated variable_info metadata property: the NWIS_Metadata override only warned and returned None (it relied on the defunct get_pmcodes), and the BaseMetadata abstract is gone too since nothing implemented it — accessing .variable_info now raises AttributeError. site_info is unaffected.
06/23/2026: Breaking change (1.2.0): removed the nadp module and the deprecated samples module ahead of the 1.2.0 release. nadp was deprecated on 05/01/2026 — NADP is not a USGS data source, so retrieve NADP data directly from https://nadp.slh.wisc.edu/. The samples.get_usgs_samples shim (a deprecated forward to the modern getter) is gone; use waterdata.get_samples() instead. import dataretrieval.nadp / import dataretrieval.samples now raise ModuleNotFoundError.
06/03/2026: The request-error hierarchy is now unified. Every module (nwis, wqp, nldi, waterdata, nadp, streamstats) raises a subclass of dataretrieval.DataRetrievalError on a failed request, so a single except dataretrieval.DataRetrievalError spans them all. An HTTP error status surfaces as an HTTPError carrying .status_code (inspect it to branch on a specific code); the retryable 429/5xx subset is TransientError (RateLimited / ServiceUnavailable, carrying .retry_after); and a request too large to satisfy is a RequestTooLarge (URLTooLong for an over-long single request, Unchunkable when the Water Data chunker cannot split a call small enough). Connection-level failures (timeouts, DNS, refused connections) are wrapped as a NetworkError, with the underlying httpx exception on __cause__. Every DataRetrievalError also exposes .status_code (None when there is no HTTP status), .retry_after, and .retryable, so a single except dataretrieval.DataRetrievalError as e clause can branch on the status or retry transient failures without knowing the concrete subclass. Breaking change: these exceptions no longer multiply-inherit a built-in — code that caught request failures with except ValueError or except RuntimeError should switch to except dataretrieval.DataRetrievalError (or a specific subclass). A no-data result is not an error: the modern getters (waterdata, wqp, nldi) return an empty DataFrame when nothing matches. Only the deprecated nwis (waterservices) path still raises NoSitesError on no data.
05/17/2026: The OGC waterdata getters (get_daily, get_continuous, get_field_measurements, and the rest of the multi-value-capable functions) now transparently chunk requests whose URLs would otherwise exceed the server's ~8 KB byte limit.
05/16/2026: Fixed silent truncation in the paginated waterdata request loops (_walk_pages and get_stats_data). Mid-pagination failures (HTTP 429, 5xx, network error) were previously swallowed — pagination would quietly stop and the function would return whatever rows it had collected, leaving callers with truncated DataFrames they had no way to detect. The loops now status-check every page like the initial request and raise RuntimeError on any failure, with the upstream exception chained as __cause__ and a short menu of recovery actions (wait and retry, reduce the request, or obtain an API token) in the message. Behavior change: callers that previously consumed partial DataFrames on transient upstream blips will now see an exception; retry the call (possibly with a smaller limit or narrower query).
05/07/2026: Bumped the declared minimum Python version from 3.8 to 3.9 (pyproject.toml's requires-python and the ruff target). This brings the manifest in line with what was already being tested — CI's matrix has long covered only 3.9, 3.13, and 3.14, the waterdata test module already skipped itself on Python < 3.10, and several modules already use 3.9-only stdlib (e.g. zoneinfo). Users on 3.8 will no longer be able to install the package; please upgrade.
05/07/2026: waterdata.get_samples() and wqp.get_results() now append a derived <prefix>DateTime UTC column for every Date/Time/TimeZone triplet in the response (e.g. Activity_StartDate + Activity_StartTime + Activity_StartTimeZone → Activity_StartDateTime). Both the WQX3 (<X>Date/<X>Time/<X>TimeZone) and legacy WQP (<X>Date/<X>Time/Time/<X>Time/TimeZoneCode) shapes are recognized; abbreviations like EST/EDT/CST/PST resolve to a UTC Timestamp, unknown codes resolve to NaT, and the original triplet columns are preserved. Returned rows are also now sorted by Activity_StartDateTime (or the legacy ActivityStartDateTime) — the underlying APIs return rows in an unstable order. Mirrors R's create_dateTime and end-of-pipeline sort. Closes #266.
05/06/2026: Each remaining active function in dataretrieval.nwis now emits a per-function DeprecationWarning naming the waterdata replacement to migrate to (visible the first time users call each getter). The nwis module is scheduled for removal on or after 2027-05-06.
05/06/2026: Added waterdata.get_ratings(...) — wraps the new Water Data STAC catalog (api.waterdata.usgs.gov/stac/v0/search) for USGS stage-discharge rating curves. Returns parsed exsa / base / corr rating tables as a dict of DataFrames keyed by feature ID, or just the list of available STAC features when download_and_parse=False. Mirrors R's read_waterdata_ratings.
05/06/2026: Added waterdata.get_field_measurements_metadata(...) — wraps the OGC field-measurements-metadata collection. Returns one row per (location, parameter) field-measurement series describing its period of record, units, etc., without the underlying observations. Discrete-measurement analogue to get_time_series_metadata. Mirrors R's read_waterdata_field_meta.
05/06/2026: Added waterdata.get_peaks(...) — wraps the new OGC peaks collection, returning the annual peak streamflow / stage record for a monitoring location (one row per water year, per parameter). Standard input to flood-frequency analysis. Supports calendar/water-year filters and the usual location/parameter/CQL knobs shared with the other OGC getters.
05/05/2026: Added waterdata.get_combined_metadata(...) — wraps the Water Data API's combined-metadata collection, which joins the monitoring-locations catalog with the time-series-metadata catalog and returns one row per (location, parameter, statistic) inventory entry. This is the most flexible "what data is available" endpoint in the API: any location attribute (state, HUC, site type, drainage area, well-construction depth, …) can be combined with any time-series attribute (parameter code, statistic, data type, period of record, …) in a single query. Mirrors R's read_waterdata_combined_meta.
05/05/2026: Added waterdata.get_samples_summary(monitoringLocationIdentifier=...) — wraps the Samples database /summary/{id} endpoint, returning per-characteristic result and activity counts plus first / most recent activity dates for a single monitoring location. Useful for taking inventory of available discrete-sample data before pulling observations with get_samples.
05/01/2026: The nadp module is now deprecated. Calling any of get_annual_MDN_map, get_annual_NTN_map, or get_zip will emit a DeprecationWarning. The module is scheduled for removal on or after 2026-11-01. NADP is not a USGS data source; users should retrieve NADP data directly from https://nadp.slh.wisc.edu/.
04/23/2026: Added waterdata.get_nearest_continuous(targets, ...) — for each of N target timestamps, fetches the single continuous observation closest to that timestamp in one HTTP round-trip (auto-chunked when the resulting CQL filter is long, via the facility added in #238). The helper is designed for workflows that pair many discrete-measurement timestamps with surrounding instantaneous data, which the OGC time parameter can't express since it only accepts one instant or one interval per request. Ties at window midpoints are resolved per a configurable on_tie ∈ {"first", "last", "mean"}; the default window="PT7M30S" matches a 15-minute continuous gauge.
04/22/2026: Highlights since the v1.1.0 release (2025-11-26), which shipped the waterdata module:
- Added
get_channelfor channel-measurement data (#218) andget_stats_por/get_stats_date_rangefor period-of-record and daily statistics (#207). - Added
get_reference_table(and made it considerably simpler and faster in #209), then extended it to accept arbitrary collections-API query parameters (#214). - Removed the deprecated
waterwatchmodule (#228) and several defunct NWIS stubs (#222, #225), and addedpy.typedsodataretrievalships type information to downstream users (#186). - Now supports
pandas3.x (#221). - The OGC
waterdatagetters (get_continuous,get_daily,get_field_measurements, and the six others built on the same OGC collections) now acceptfilterandfilter_langkwargs 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-levelORchain is transparently split into multiple requests that each fit under the server's URI length limit, and the results are concatenated.
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.
11/24/2025: dataretrieval is pleased to offer a new module, waterdata, which gives users access USGS's modernized Water Data APIs. 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. More example workflows and functions coming soon. Check help(waterdata) for more information.
09/03/2024: The groundwater levels service has switched endpoints, and dataretrieval was updated accordingly in v1.0.10. Older versions using the discontinued endpoint will return 503 errors for nwis.get_gwlevels or the service='gwlevels' argument. Visit Water Data For the Nation for more information.
03/01/2024: USGS data availability and format have changed on Water Quality Portal (WQP). Since March 2024, data obtained from WQP legacy profiles will not include new USGS data or recent updates to existing data. All USGS data (up to and beyond March 2024) are available using the new WQP beta services. You can access the beta services by setting legacy=False in the functions in the wqp module.
To view the status of changes in data availability and code functionality, visit: https://doi-usgs.github.io/dataRetrieval/articles/Status.html