Skip to content

Commit e2f81a5

Browse files
authored
Add request partitioning to waterdata_client. (#325)
* specify chunk size * update templates so that generate query returns a list of queries * regenerate clients and models * add and test method for grouping iterable of strings * add and test iterable field type * add basic sequence validation for monitoring location id * update build scripts with new validated type * pass client chunk size into query generation * fallback to default location id set by user if not list * tweaks to streamline code * bump version to 0.9.0b0
1 parent 87c1131 commit e2f81a5

81 files changed

Lines changed: 962 additions & 386 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

python/waterdata_client/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ readme = "README.md"
1212
requires-python = ">=3.11"
1313
license = "Apache-2.0"
1414
classifiers = [
15-
"Development Status :: 3 - Alpha",
15+
"Development Status :: 4 - Beta",
1616
"Intended Audience :: Education",
1717
"Intended Audience :: Science/Research",
1818
"Programming Language :: Python :: 3.11",

python/waterdata_client/scripts/build_clients.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@
2626
from hydrotools.waterdata_client._version import __version__
2727

2828
TYPE_OVERRIDES: dict[str, str] = {
29-
"datetime": "str | DateTimeInput"
29+
"datetime": "str | DateTimeInput",
30+
"monitoring_location_id": "str | StringList"
3031
}
3132
"""Mapping from specific arguments to special type hints. This facilitates
3233
various query interventions.
3334
"""
3435

3536
EXTRA_IMPORTS: dict[str, str] = {
36-
"datetime": "from hydrotools.waterdata_client.datetime_utilities import DateTimeInput"
37+
"datetime": "from hydrotools.waterdata_client.datetime_utilities import DateTimeInput",
38+
"monitoring_location_id": "from hydrotools.waterdata_client.request_partitioning import StringList"
3739
}
3840
"""Mapping from specific arguments to extra required imports."""
3941

python/waterdata_client/scripts/build_request_models.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@
2626
from hydrotools.waterdata_client._version import __version__
2727

2828
TYPE_OVERRIDES: dict[str, str] = {
29-
"datetime": "DateTimeField"
29+
"datetime": "DateTimeField",
30+
"monitoring_location_id": "StringList"
3031
}
3132
"""Mapping from specific arguments to special type hints. This facilitates
3233
various query interventions.
3334
"""
3435

3536
EXTRA_IMPORTS: dict[str, str] = {
36-
"datetime": "from hydrotools.waterdata_client.datetime_utilities import DateTimeField"
37+
"datetime": "from hydrotools.waterdata_client.datetime_utilities import DateTimeField",
38+
"monitoring_location_id": "from hydrotools.waterdata_client.request_partitioning import StringList"
3739
}
3840
"""Mapping from specific arguments to extra required imports."""
3941

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
"""Track dynamic package versions here."""
2-
__version__ = "0.8.3a0"
2+
__version__ = "0.9.0b0"

python/waterdata_client/src/hydrotools/waterdata_client/base_client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,15 @@ def __init__(
4949
max_retries: int = SETTINGS.default_retries,
5050
timeout_seconds: int = SETTINGS.timeout_seconds,
5151
ssl_context: Optional[ssl.SSLContext] = None,
52-
transformer: Optional[ResponseTransformer[TransformedResponseT_co]] = check_features
52+
transformer: Optional[ResponseTransformer[TransformedResponseT_co]] = check_features,
53+
chunk_size: int = SETTINGS.chunk_size
5354
) -> None:
5455
self.concurrency_limit = concurrency_limit
5556
self.max_retries = max_retries
5657
self.timeout_seconds = timeout_seconds
5758
self.ssl_context = ssl_context
5859
self.transformer = transformer
60+
self.chunk_size = chunk_size
5961

6062
# Setup request builder
6163
self._builder = partial(

python/waterdata_client/src/hydrotools/waterdata_client/client_config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class EnvironmentKey(StrEnum):
7373
TIMEOUT = f"{_KEY_START}TIMEOUT"
7474
API_KEY = f"{_KEY_START}USGS_API_KEY"
7575
MAX_PAGES = f"{_KEY_START}MAX_PAGES"
76+
CHUNK_SIZE = f"{_KEY_START}CHUNK_SIZE"
7677

7778
@classmethod
7879
def describe_keys(cls) -> str:
@@ -115,6 +116,7 @@ class _Settings:
115116
cache_expires.
116117
max_pages: Maximum number of times to follow paginated 'next' links
117118
in JSON responses.
119+
chunk_size: Size of request chunks for arguments that accept Sequences.
118120
"""
119121
usgs_base_url: URL = URL("https://api.waterdata.usgs.gov/ogcapi/v0")
120122
schema_path: str = "openapi"
@@ -129,6 +131,7 @@ class _Settings:
129131
timeout_seconds: int = 900
130132
usgs_api_key: Optional[str] = None
131133
max_pages: int = 20
134+
chunk_size: int = 5
132135

133136
@classmethod
134137
def from_env(cls) -> Self:
@@ -154,7 +157,8 @@ def from_env(cls) -> Self:
154157
default_retries=int(os.getenv(EnvironmentKey.RETRIES, cls.default_retries)),
155158
timeout_seconds=int(os.getenv(EnvironmentKey.TIMEOUT, cls.timeout_seconds)),
156159
usgs_api_key=os.getenv(EnvironmentKey.API_KEY, cls.usgs_api_key),
157-
max_pages=int(os.getenv(EnvironmentKey.MAX_PAGES, cls.max_pages))
160+
max_pages=int(os.getenv(EnvironmentKey.MAX_PAGES, cls.max_pages)),
161+
chunk_size=int(os.getenv(EnvironmentKey.CHUNK_SIZE, cls.chunk_size))
158162
)
159163

160164
@cached_property

python/waterdata_client/src/hydrotools/waterdata_client/clients/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
client classes for USGS OGC API items endpoints. These classes are generated
44
by inspecting the USGS OGC API JSON schema and identifying all "items" endpoints.
55
6-
Package version: 0.8.0a0
6+
Package version: 0.9.0b0
77
Generation script: build_clients.py
8-
Generated: 2026-05-20 18:31:11 Z
8+
Generated: 2026-05-29 15:52:35 Z
99
JSON Schema source: https://api.waterdata.usgs.gov/ogcapi/v0/openapi?f=json
1010
JSON Schema version: 0.49.2
1111
OpenAPI version: 3.0.2

python/waterdata_client/src/hydrotools/waterdata_client/clients/agency_codes.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
client classes for USGS OGC API items endpoints. These classes are generated
44
by inspecting the USGS OGC API JSON schema and identifying all "items" endpoints.
55
6-
Package version: 0.8.0a0
6+
Package version: 0.9.0b0
77
Generation script: build_clients.py
8-
Generated: 2026-05-20 18:31:11 Z
8+
Generated: 2026-05-29 15:52:35 Z
99
JSON Schema source: https://api.waterdata.usgs.gov/ogcapi/v0/openapi?f=json
1010
JSON Schema version: 0.49.2
1111
OpenAPI version: 3.0.2
@@ -96,7 +96,7 @@ def get(
9696
our APIs. You can obtain an API key at https://api.waterdata.usgs.gov/signup
9797
"""
9898
# Validate query
99-
query = AgencyCodesRequest(
99+
queries = AgencyCodesRequest(
100100
agency_name=agency_name,
101101
bbox=bbox,
102102
bbox_crs=bbox_crs,
@@ -111,10 +111,10 @@ def get(
111111
skipgeometry=skipgeometry,
112112
sortby=sortby,
113113
api_key=api_key if api_key else SETTINGS.usgs_api_key
114-
).generate_query()
114+
).generate_queries()
115115

116116
# Get responses
117-
data = self._get_json_responses(queries=[query])
117+
data = self._get_json_responses(queries=queries)
118118

119119
# Transform
120120
return self._handle_response(data)

python/waterdata_client/src/hydrotools/waterdata_client/clients/altitude_datums.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
client classes for USGS OGC API items endpoints. These classes are generated
44
by inspecting the USGS OGC API JSON schema and identifying all "items" endpoints.
55
6-
Package version: 0.8.0a0
6+
Package version: 0.9.0b0
77
Generation script: build_clients.py
8-
Generated: 2026-05-20 18:31:11 Z
8+
Generated: 2026-05-29 15:52:35 Z
99
JSON Schema source: https://api.waterdata.usgs.gov/ogcapi/v0/openapi?f=json
1010
JSON Schema version: 0.49.2
1111
OpenAPI version: 3.0.2
@@ -100,7 +100,7 @@ def get(
100100
our APIs. You can obtain an API key at https://api.waterdata.usgs.gov/signup
101101
"""
102102
# Validate query
103-
query = AltitudeDatumsRequest(
103+
queries = AltitudeDatumsRequest(
104104
altitude_datum_description=altitude_datum_description,
105105
bbox=bbox,
106106
bbox_crs=bbox_crs,
@@ -115,10 +115,10 @@ def get(
115115
skipgeometry=skipgeometry,
116116
sortby=sortby,
117117
api_key=api_key if api_key else SETTINGS.usgs_api_key
118-
).generate_query()
118+
).generate_queries()
119119

120120
# Get responses
121-
data = self._get_json_responses(queries=[query])
121+
data = self._get_json_responses(queries=queries)
122122

123123
# Transform
124124
return self._handle_response(data)

python/waterdata_client/src/hydrotools/waterdata_client/clients/aquifer_codes.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
client classes for USGS OGC API items endpoints. These classes are generated
44
by inspecting the USGS OGC API JSON schema and identifying all "items" endpoints.
55
6-
Package version: 0.8.0a0
6+
Package version: 0.9.0b0
77
Generation script: build_clients.py
8-
Generated: 2026-05-20 18:31:11 Z
8+
Generated: 2026-05-29 15:52:35 Z
99
JSON Schema source: https://api.waterdata.usgs.gov/ogcapi/v0/openapi?f=json
1010
JSON Schema version: 0.49.2
1111
OpenAPI version: 3.0.2
@@ -110,7 +110,7 @@ def get(
110110
our APIs. You can obtain an API key at https://api.waterdata.usgs.gov/signup
111111
"""
112112
# Validate query
113-
query = AquiferCodesRequest(
113+
queries = AquiferCodesRequest(
114114
aquifer_name=aquifer_name,
115115
bbox=bbox,
116116
bbox_crs=bbox_crs,
@@ -125,10 +125,10 @@ def get(
125125
skipgeometry=skipgeometry,
126126
sortby=sortby,
127127
api_key=api_key if api_key else SETTINGS.usgs_api_key
128-
).generate_query()
128+
).generate_queries()
129129

130130
# Get responses
131-
data = self._get_json_responses(queries=[query])
131+
data = self._get_json_responses(queries=queries)
132132

133133
# Transform
134134
return self._handle_response(data)

0 commit comments

Comments
 (0)