Skip to content

Commit a77372a

Browse files
thodson-usgsclaude
andcommitted
refactor: hoist _default_headers into utils (neutral HTTP layer)
`_default_headers` (the token-aware USGS-API request headers) lived in `ogc/engine.py`, but nothing about it is OGC-specific: it's consumed by the Water Data getters, the stats client, and `wateruse`, and `waterdata/utils` already re-exported it. The new `wateruse` module (a non-OGC CSV API) having to reach into the OGC engine for it was an inverted dependency. Move the definition to `dataretrieval/utils.py` — the package's neutral HTTP foundation, alongside `_get`, `HTTPX_DEFAULTS`, `query`, and `BaseMetadata` — and repoint the importers. `ogc.engine` and `waterdata.utils` re-import it, so `ogc.engine._default_headers` and `waterdata.utils._default_headers` still resolve to the same object; no behavior change. Also drops the now-unused `os` and `__version__` imports from the engine. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sjb14HkwuCydKSKMsaXsgd
1 parent 2d55d48 commit a77372a

5 files changed

Lines changed: 47 additions & 33 deletions

File tree

dataretrieval/ogc/engine.py

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import json
3030
import logging
3131
import numbers
32-
import os
3332
import re
3433
from collections.abc import (
3534
AsyncIterator,
@@ -49,7 +48,6 @@
4948
import pandas as pd
5049
from anyio.from_thread import start_blocking_portal
5150

52-
from dataretrieval import __version__
5351
from dataretrieval.exceptions import DataRetrievalError
5452
from dataretrieval.ogc import chunking
5553
from dataretrieval.ogc import progress as _progress
@@ -61,7 +59,13 @@
6159
from dataretrieval.ogc.errors import _paginated_failure_message, _raise_for_non_200
6260
from dataretrieval.ogc.planning import _safe_elapsed
6361
from dataretrieval.ogc.shaping import GEOPANDAS, _finalize_ogc, _get_resp_data
64-
from dataretrieval.utils import HTTPX_DEFAULTS, BaseMetadata, _get, _network_error
62+
from dataretrieval.utils import (
63+
HTTPX_DEFAULTS,
64+
BaseMetadata,
65+
_default_headers,
66+
_get,
67+
_network_error,
68+
)
6569

6670
# Set up logger for this module
6771
logger = logging.getLogger(__name__)
@@ -242,29 +246,6 @@ def _cql2_param(args: dict[str, Any]) -> str:
242246
return json.dumps(query, separators=(",", ":"))
243247

244248

245-
def _default_headers() -> dict[str, str]:
246-
"""
247-
Generate default HTTP headers for API requests.
248-
249-
Returns
250-
-------
251-
dict
252-
A dictionary containing default headers including 'Accept-Encoding',
253-
'Accept', 'User-Agent', and 'lang'. If the environment variable
254-
'API_USGS_PAT' is set, its value is included as the 'X-Api-Key' header.
255-
"""
256-
headers = {
257-
"Accept-Encoding": "compress, gzip",
258-
"Accept": "application/json",
259-
"User-Agent": f"python-dataretrieval/{__version__}",
260-
"lang": "en-US",
261-
}
262-
token = os.getenv("API_USGS_PAT")
263-
if token:
264-
headers["X-Api-Key"] = token
265-
return headers
266-
267-
268249
def _check_ogc_requests(endpoint: str, req_type: str = "queryables") -> dict[str, Any]:
269250
"""
270251
Sends an HTTP GET request to the specified OGC endpoint and request type,

dataretrieval/utils.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from __future__ import annotations
66

7+
import os
78
import warnings
89
from collections.abc import Iterable
910
from typing import Any
@@ -29,6 +30,35 @@
2930
}
3031

3132

33+
def _default_headers() -> dict[str, str]:
34+
"""Build the default HTTP headers for a USGS web-API request.
35+
36+
Always sets a descriptive ``User-Agent`` plus ``Accept`` /
37+
``Accept-Encoding`` and ``lang``. If the ``API_USGS_PAT`` environment
38+
variable is set, its value is added as the ``X-Api-Key`` header — a USGS
39+
personal access token raises the request rate limit.
40+
41+
Shared by the OGC engine (:mod:`dataretrieval.ogc`), the Water Data getters
42+
(:mod:`dataretrieval.waterdata`), and :mod:`dataretrieval.wateruse`, so the
43+
request identity is consistent across every USGS API the package talks to.
44+
45+
Returns
46+
-------
47+
dict[str, str]
48+
Headers suitable for an ``httpx`` request against a USGS API.
49+
"""
50+
headers = {
51+
"Accept-Encoding": "compress, gzip",
52+
"Accept": "application/json",
53+
"User-Agent": f"python-dataretrieval/{dataretrieval.__version__}",
54+
"lang": "en-US",
55+
}
56+
token = os.getenv("API_USGS_PAT")
57+
if token:
58+
headers["X-Api-Key"] = token
59+
return headers
60+
61+
3262
def to_str(listlike: object, delimiter: str = ",") -> str | None:
3363
"""Translates list-like objects into strings.
3464

dataretrieval/waterdata/stats.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
from dataretrieval.ogc.engine import (
2020
BASE_URL,
21-
_default_headers,
2221
_paginate,
2322
_run_sync,
2423
)
@@ -27,7 +26,7 @@
2726
_attach_coordinates,
2827
_empty_feature_frame,
2928
)
30-
from dataretrieval.utils import BaseMetadata
29+
from dataretrieval.utils import BaseMetadata, _default_headers
3130

3231
# ``_handle_nesting``'s geopandas branch calls ``gpd.GeoDataFrame.from_features``
3332
# directly, so this module needs its own bound ``gpd`` name. Import it under the

dataretrieval/waterdata/utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
_check_ogc_requests,
3838
_construct_api_requests,
3939
_construct_cql_request,
40-
_default_headers,
4140
_next_req_url,
4241
_normalize_str_iterable,
4342
_paginate,
@@ -65,7 +64,7 @@
6564
from dataretrieval.ogc.shaping import (
6665
_finalize_ogc as _engine_finalize_ogc,
6766
)
68-
from dataretrieval.utils import BaseMetadata
67+
from dataretrieval.utils import BaseMetadata, _default_headers
6968
from dataretrieval.waterdata.types import (
7069
PROFILE_LOOKUP,
7170
PROFILES,

dataretrieval/wateruse.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
(:mod:`dataretrieval.ngwmn`), the NWDC is a plain CSV REST service rather than
1313
an OGC API Features collection, so this module talks to it directly instead of
1414
delegating to the shared OGC engine. It still follows the same conventions:
15-
shared request headers (:func:`~dataretrieval.ogc.engine._default_headers`),
15+
shared request headers (:func:`~dataretrieval.utils._default_headers`),
1616
the typed :class:`~dataretrieval.exceptions.DataRetrievalError` taxonomy, and a
1717
``(DataFrame, BaseMetadata)`` return.
1818
@@ -47,8 +47,13 @@
4747
import pandas as pd
4848

4949
from dataretrieval.exceptions import error_for_status
50-
from dataretrieval.ogc.engine import _default_headers
51-
from dataretrieval.utils import HTTPX_DEFAULTS, BaseMetadata, _get, to_str
50+
from dataretrieval.utils import (
51+
HTTPX_DEFAULTS,
52+
BaseMetadata,
53+
_default_headers,
54+
_get,
55+
to_str,
56+
)
5257

5358
if TYPE_CHECKING:
5459
from collections.abc import Iterable

0 commit comments

Comments
 (0)