swatgenx 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: swatgenx
3
+ Version: 0.1.0
4
+ Summary: Python client for SWATGenX — automated SWAT+/MODFLOW watershed models and open national water datasets for the conterminous US
5
+ Author-email: Vahid Rafiei <info@swatgenx.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://www.swatgenx.com
8
+ Project-URL: Documentation, https://www.swatgenx.com/developer-api
9
+ Project-URL: MCP server (agent access), https://www.swatgenx.com/mcp
10
+ Keywords: SWAT+,MODFLOW,hydrology,watershed,groundwater,PFAS,USGS
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering :: Hydrology
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: requests>=2.28
19
+
20
+ # swatgenx
21
+
22
+ Python client for [SWATGenX](https://www.swatgenx.com) — automated SWAT+ / MODFLOW 6
23
+ watershed models and open national water datasets for the conterminous United States.
24
+
25
+ ```
26
+ pip install swatgenx
27
+ ```
28
+
29
+ ## Public data — no account needed
30
+
31
+ ```python
32
+ import swatgenx as sg
33
+
34
+ # Example-model catalog: built SWAT+ models with calibration/validation metrics
35
+ models = sg.catalog(state="FL", calibrated_only=True)
36
+ sg.calibration("01451800")
37
+ # {'mode': 'engineer', 'cal_daily_nse': 0.642, 'val_daily_nse': 0.748, ...}
38
+
39
+ # National groundwater inventory: 28.8M lithology intervals, 7.9M wells, 46 states
40
+ sg.groundwater_at(42.73, -84.55) # nearest well + lithology log
41
+ sg.groundwater_summary()
42
+
43
+ # National PFAS monitoring inventory
44
+ sg.pfas_stations(huc8="0405")
45
+ sg.pfas_summary()
46
+ ```
47
+
48
+ ## Order and download models — free account + API key
49
+
50
+ Sign in at [swatgenx.com](https://www.swatgenx.com) → dashboard → API keys, then:
51
+
52
+ ```python
53
+ c = sg.Client(api_key="...") # or env SWATGENX_API_KEY
54
+
55
+ order = c.order(usgs_station="04124500") # any of 25,000+ USGS gauges
56
+ c.wait(order["order_id"]) # typical build: 20 min – 2 h
57
+ c.download("04124500", vpuid="0406", dest="model.zip") # ZIP straight to your disk
58
+ ```
59
+
60
+ Builds run on SWATGenX cloud infrastructure from national data (NHDPlus HR, 3DEP,
61
+ gSSURGO, NLCD, PRISM, USGS NWIS); delivery is pull-based — no email round-trip.
62
+
63
+ ## Access ladder
64
+
65
+ | tier | requires | unlocks |
66
+ |---|---|---|
67
+ | guest | nothing | all public data functions |
68
+ | member | free account + API key | model orders (fair-use), downloads |
69
+ | extended | request via info@swatgenx.com | HUC8 whole-basin, SWAT+MODFLOW-6, HUC14 30 m site models |
70
+ | calibration | account credit | cloud calibration campaigns |
71
+
72
+ `sg.access_info()` returns this ladder programmatically; quota/tier errors raise
73
+ `SwatGenXError` with upgrade guidance.
74
+
75
+ ## AI agents
76
+
77
+ The same platform is agent-native via a public MCP server:
78
+ **https://www.swatgenx.com/mcp** (see the site's `llms.txt`). This package and the MCP
79
+ server expose the same surface, enforced by the same server-side quotas.
80
+
81
+ ## Data citations
82
+
83
+ - Groundwater inventory: Zenodo DOI [10.5281/zenodo.21196958](https://doi.org/10.5281/zenodo.21196958)
84
+ - Soil PFAS inventory: Zenodo DOI [10.5281/zenodo.21096358](https://doi.org/10.5281/zenodo.21096358)
85
+
86
+ MIT-licensed client; platform terms at swatgenx.com.
@@ -0,0 +1,67 @@
1
+ # swatgenx
2
+
3
+ Python client for [SWATGenX](https://www.swatgenx.com) — automated SWAT+ / MODFLOW 6
4
+ watershed models and open national water datasets for the conterminous United States.
5
+
6
+ ```
7
+ pip install swatgenx
8
+ ```
9
+
10
+ ## Public data — no account needed
11
+
12
+ ```python
13
+ import swatgenx as sg
14
+
15
+ # Example-model catalog: built SWAT+ models with calibration/validation metrics
16
+ models = sg.catalog(state="FL", calibrated_only=True)
17
+ sg.calibration("01451800")
18
+ # {'mode': 'engineer', 'cal_daily_nse': 0.642, 'val_daily_nse': 0.748, ...}
19
+
20
+ # National groundwater inventory: 28.8M lithology intervals, 7.9M wells, 46 states
21
+ sg.groundwater_at(42.73, -84.55) # nearest well + lithology log
22
+ sg.groundwater_summary()
23
+
24
+ # National PFAS monitoring inventory
25
+ sg.pfas_stations(huc8="0405")
26
+ sg.pfas_summary()
27
+ ```
28
+
29
+ ## Order and download models — free account + API key
30
+
31
+ Sign in at [swatgenx.com](https://www.swatgenx.com) → dashboard → API keys, then:
32
+
33
+ ```python
34
+ c = sg.Client(api_key="...") # or env SWATGENX_API_KEY
35
+
36
+ order = c.order(usgs_station="04124500") # any of 25,000+ USGS gauges
37
+ c.wait(order["order_id"]) # typical build: 20 min – 2 h
38
+ c.download("04124500", vpuid="0406", dest="model.zip") # ZIP straight to your disk
39
+ ```
40
+
41
+ Builds run on SWATGenX cloud infrastructure from national data (NHDPlus HR, 3DEP,
42
+ gSSURGO, NLCD, PRISM, USGS NWIS); delivery is pull-based — no email round-trip.
43
+
44
+ ## Access ladder
45
+
46
+ | tier | requires | unlocks |
47
+ |---|---|---|
48
+ | guest | nothing | all public data functions |
49
+ | member | free account + API key | model orders (fair-use), downloads |
50
+ | extended | request via info@swatgenx.com | HUC8 whole-basin, SWAT+MODFLOW-6, HUC14 30 m site models |
51
+ | calibration | account credit | cloud calibration campaigns |
52
+
53
+ `sg.access_info()` returns this ladder programmatically; quota/tier errors raise
54
+ `SwatGenXError` with upgrade guidance.
55
+
56
+ ## AI agents
57
+
58
+ The same platform is agent-native via a public MCP server:
59
+ **https://www.swatgenx.com/mcp** (see the site's `llms.txt`). This package and the MCP
60
+ server expose the same surface, enforced by the same server-side quotas.
61
+
62
+ ## Data citations
63
+
64
+ - Groundwater inventory: Zenodo DOI [10.5281/zenodo.21196958](https://doi.org/10.5281/zenodo.21196958)
65
+ - Soil PFAS inventory: Zenodo DOI [10.5281/zenodo.21096358](https://doi.org/10.5281/zenodo.21096358)
66
+
67
+ MIT-licensed client; platform terms at swatgenx.com.
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "swatgenx"
7
+ version = "0.1.0"
8
+ description = "Python client for SWATGenX — automated SWAT+/MODFLOW watershed models and open national water datasets for the conterminous US"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Vahid Rafiei", email = "info@swatgenx.com" }]
13
+ keywords = ["SWAT+", "MODFLOW", "hydrology", "watershed", "groundwater", "PFAS", "USGS"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Science/Research",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Scientific/Engineering :: Hydrology",
20
+ ]
21
+ dependencies = ["requests>=2.28"]
22
+
23
+ [project.urls]
24
+ Homepage = "https://www.swatgenx.com"
25
+ Documentation = "https://www.swatgenx.com/developer-api"
26
+ "MCP server (agent access)" = "https://www.swatgenx.com/mcp"
27
+
28
+ [tool.setuptools.packages.find]
29
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,40 @@
1
+ """swatgenx — Python client for SWATGenX (https://www.swatgenx.com).
2
+
3
+ Public data needs no account:
4
+
5
+ import swatgenx as sg
6
+ models = sg.catalog(state="FL", calibrated_only=True)
7
+ sg.calibration("01451800") # cal/val NSE, PBIAS, method
8
+ sg.groundwater_at(42.73, -84.55) # nearest well + lithology log
9
+ sg.pfas_stations(huc8="0405") # PFAS monitoring inventory
10
+
11
+ Ordering and downloading models needs a free account + API key
12
+ (sign in at swatgenx.com -> dashboard -> API keys):
13
+
14
+ c = sg.Client(api_key="...") # or env SWATGENX_API_KEY
15
+ order = c.order(usgs_station="04124500")
16
+ c.status(order["order_id"])
17
+ c.download("04124500", vpuid="0406", dest="model.zip")
18
+
19
+ Access ladder: guest (public data) -> member (free key: fair-use orders + downloads)
20
+ -> extended access (info@swatgenx.com: HUC8 / SWAT+MODFLOW-6 / HUC14 site models)
21
+ -> calibration (account credit). AI agents can use the same platform via MCP:
22
+ https://www.swatgenx.com/mcp
23
+ """
24
+ from .client import (
25
+ Client,
26
+ SwatGenXError,
27
+ access_info,
28
+ calibration,
29
+ catalog,
30
+ groundwater_at,
31
+ groundwater_summary,
32
+ pfas_stations,
33
+ pfas_summary,
34
+ )
35
+
36
+ __version__ = "0.1.0"
37
+ __all__ = [
38
+ "Client", "SwatGenXError", "access_info", "calibration", "catalog",
39
+ "groundwater_at", "groundwater_summary", "pfas_stations", "pfas_summary",
40
+ ]
@@ -0,0 +1,211 @@
1
+ """HTTP client for the SWATGenX public API (thin, dependency-light).
2
+
3
+ Every call maps 1:1 onto a documented endpoint at https://www.swatgenx.com — the same
4
+ surface the website and the MCP server (https://www.swatgenx.com/mcp) use. Public
5
+ functions need no account; the Client class carries a per-user API key for actions
6
+ that create state (model orders, downloads), where authentication, ownership, and
7
+ fair-use quotas are enforced server-side.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ import time
13
+ from typing import Any
14
+
15
+ import requests
16
+
17
+ BASE = os.environ.get("SWATGENX_BASE_URL", "https://www.swatgenx.com")
18
+ _UA = {"User-Agent": "swatgenx-python/0.1.0"}
19
+
20
+
21
+ class SwatGenXError(RuntimeError):
22
+ """API error with the server's message and, when relevant, upgrade guidance."""
23
+
24
+ def __init__(self, message: str, status: int | None = None, detail: Any = None):
25
+ super().__init__(message)
26
+ self.status = status
27
+ self.detail = detail
28
+
29
+
30
+ _ACCESS_NOTE = (
31
+ "This action exceeds your current access tier or fair-use allocation. "
32
+ "Free accounts order under daily allocations; extended access (HUC8 whole-basin, "
33
+ "SWAT+MODFLOW-6, HUC14 site models) is granted on request via info@swatgenx.com; "
34
+ "cloud calibration requires account credit."
35
+ )
36
+
37
+
38
+ def _request(method: str, path: str, *, key: str | None = None, json: dict | None = None,
39
+ params: dict | None = None, timeout: int = 90) -> Any:
40
+ headers = dict(_UA)
41
+ if key:
42
+ headers["X-SWATGenX-Api-Key"] = key
43
+ r = requests.request(method, f"{BASE}{path}", json=json, params=params,
44
+ headers=headers, timeout=timeout)
45
+ try:
46
+ body = r.json()
47
+ except ValueError:
48
+ body = {"raw": (r.text or "")[:500]}
49
+ if r.status_code == 401:
50
+ raise SwatGenXError(
51
+ "Authentication failed — invalid or revoked API key. Sign in at "
52
+ "https://www.swatgenx.com -> dashboard -> API keys.", 401, body)
53
+ if r.status_code in (402, 403, 413, 429):
54
+ raise SwatGenXError(_ACCESS_NOTE, r.status_code, body)
55
+ if r.status_code >= 400:
56
+ msg = body.get("message") or body.get("error") or f"HTTP {r.status_code}"
57
+ raise SwatGenXError(str(msg), r.status_code, body)
58
+ return body
59
+
60
+
61
+ # ------------------------------------------------------------------ public (no account)
62
+ def catalog(state: str | None = None, calibrated_only: bool = False,
63
+ min_channels: int | None = None, max_channels: int | None = None) -> list[dict]:
64
+ """Public example-model catalog: built SWAT+ models across the conterminous US,
65
+ each with structure counts and (when calibrated) cal/val NSE. Filter by two-letter
66
+ state, calibration status, and channel-count bounds."""
67
+ payload = _request("GET", "/api/public/example-swat-models")
68
+ out = []
69
+ for m in payload.get("models") or []:
70
+ if state and str(m.get("state") or "").upper() != state.upper():
71
+ continue
72
+ cal = m.get("calibration")
73
+ if calibrated_only and not cal:
74
+ continue
75
+ ch = m.get("n_channels")
76
+ if min_channels is not None and (ch is None or ch < min_channels):
77
+ continue
78
+ if max_channels is not None and (ch is None or ch > max_channels):
79
+ continue
80
+ out.append(m)
81
+ return out
82
+
83
+
84
+ def calibration(site_no: str) -> dict | None:
85
+ """Calibration + held-out validation metrics for one public example model
86
+ (daily/monthly NSE, PBIAS, method, window). None if never calibrated."""
87
+ for m in catalog():
88
+ if str(m.get("site_no")) == str(site_no):
89
+ return m.get("calibration")
90
+ return None
91
+
92
+
93
+ def groundwater_at(lat: float, lon: float, tol_deg: float = 0.05) -> dict:
94
+ """Nearest well to a point from the national groundwater inventory (28.8M lithology
95
+ intervals, 7.9M wells), with its lithology log when available. tol_deg is the search
96
+ box half-width in degrees (~0.05 = 5 km)."""
97
+ return _request("GET", "/api/gw-wells/at",
98
+ params={"lat": lat, "lon": lon, "tol": tol_deg})
99
+
100
+
101
+ def groundwater_summary() -> dict:
102
+ """Live national groundwater-inventory counts (wells, intervals, per-state)."""
103
+ return _request("GET", "/api/gw-wells/summary")
104
+
105
+
106
+ def pfas_stations(bbox: str | None = None, huc12: str | None = None,
107
+ huc8: str | None = None) -> dict:
108
+ """National PFAS monitoring inventory (GeoJSON stations). Filter by bbox
109
+ ('minLon,minLat,maxLon,maxLat'), huc12, or huc8."""
110
+ params = {k: v for k, v in (("bbox", bbox), ("huc12", huc12), ("huc8", huc8)) if v}
111
+ return _request("GET", "/api/pfas/stations", params=params)
112
+
113
+
114
+ def pfas_summary() -> dict:
115
+ """Live PFAS-inventory summary counts."""
116
+ return _request("GET", "/api/pfas/summary")
117
+
118
+
119
+ def access_info() -> dict:
120
+ """The SWATGenX access ladder: what guests, members (free key), extended access,
121
+ and calibration credit each unlock — and how to move up."""
122
+ return {
123
+ "tiers": [
124
+ {"tier": "guest", "requires": "nothing",
125
+ "can": "all public data functions in this package + example-model downloads on the website"},
126
+ {"tier": "member", "requires": "free account + API key (swatgenx.com -> dashboard -> API keys)",
127
+ "can": "Client.order under fair-use daily allocations; Client.download for owned models"},
128
+ {"tier": "extended access", "requires": "granted on request: info@swatgenx.com",
129
+ "can": "HUC8 whole-basin, coupled SWAT+MODFLOW-6, HUC14 30 m site models, higher allocations"},
130
+ {"tier": "calibration", "requires": "account credit",
131
+ "can": "cloud calibration campaigns (website dashboard)"},
132
+ ],
133
+ "agent_access": "AI agents can use the same platform via MCP: https://www.swatgenx.com/mcp",
134
+ }
135
+
136
+
137
+ # ------------------------------------------------------------------ authenticated
138
+ class Client:
139
+ """Authenticated client. Get a key: sign in at swatgenx.com -> dashboard -> API keys,
140
+ or set the SWATGENX_API_KEY environment variable."""
141
+
142
+ def __init__(self, api_key: str | None = None):
143
+ self.api_key = (api_key or os.environ.get("SWATGENX_API_KEY") or "").strip()
144
+ if not self.api_key:
145
+ raise SwatGenXError(
146
+ "API key required: pass Client(api_key=...) or set SWATGENX_API_KEY. "
147
+ "Keys: swatgenx.com -> dashboard -> API keys (free account).")
148
+
149
+ # -- account
150
+ def whoami(self) -> dict:
151
+ """Subscription status for the key's account."""
152
+ return _request("GET", "/api/user/subscription-status", key=self.api_key)
153
+
154
+ # -- ordering
155
+ def order(self, usgs_station: str | None = None, huc12_outlet: str | None = None,
156
+ force_rebuild: bool = False) -> dict:
157
+ """Order a real SWAT+ model build (consumes your fair-use allocation).
158
+ Provide either a USGS gauge id or a 12-digit HUC12 outlet. Returns the order
159
+ record incl. order_id; typical build 20 min - 2 h."""
160
+ if huc12_outlet:
161
+ return _request("POST", "/api/model-settings/explorer-watershed", key=self.api_key,
162
+ json={"outlet_huc12": str(huc12_outlet).strip(),
163
+ "force_rebuild": bool(force_rebuild)})
164
+ if usgs_station:
165
+ return _request("POST", "/api/model-settings", key=self.api_key,
166
+ json={"site_no": str(usgs_station).strip(),
167
+ "force_rebuild": bool(force_rebuild)})
168
+ raise SwatGenXError("provide usgs_station or huc12_outlet")
169
+
170
+ def status(self, order_id: str) -> dict:
171
+ """State/stage/timing of a build order."""
172
+ return _request("GET", f"/api/model-orders/{str(order_id).strip()}", key=self.api_key)
173
+
174
+ def orders(self) -> dict:
175
+ """All of your build orders, newest first."""
176
+ return _request("GET", "/api/model-orders", key=self.api_key)
177
+
178
+ def wait(self, order_id: str, poll_seconds: int = 60, timeout_hours: float = 4.0) -> dict:
179
+ """Block until an order reaches a terminal state; returns the final record."""
180
+ deadline = time.time() + timeout_hours * 3600
181
+ while True:
182
+ rec = self.status(order_id)
183
+ state = str(rec.get("state") or rec.get("order_state") or "").upper()
184
+ if state and not any(s in state for s in ("QUEUED", "RUNNING", "PENDING")):
185
+ return rec
186
+ if time.time() > deadline:
187
+ raise SwatGenXError(f"order {order_id} not terminal after {timeout_hours} h "
188
+ f"(last state: {state or 'unknown'})")
189
+ time.sleep(max(10, poll_seconds))
190
+
191
+ # -- delivery (pull-based: the ZIP lands on YOUR disk; no email needed)
192
+ def download_link(self, site_no: str, vpuid: str, level: str = "usgs_station") -> dict:
193
+ """Mint a fresh 24 h download link for a model you own."""
194
+ return _request("POST", "/api/download_model/link", key=self.api_key,
195
+ json={"site_no": str(site_no).strip(), "vpuid": str(vpuid).strip(),
196
+ "level": level})
197
+
198
+ def download(self, site_no: str, vpuid: str, dest: str,
199
+ level: str = "usgs_station", timeout: int = 1800) -> str:
200
+ """Download a model you own to a local path (streams the ZIP). Returns dest."""
201
+ link = self.download_link(site_no, vpuid, level)
202
+ url = link.get("download_url")
203
+ if not url:
204
+ raise SwatGenXError("no download_url in response", detail=link)
205
+ with requests.get(url, headers=_UA, stream=True, timeout=timeout) as r:
206
+ if r.status_code >= 400:
207
+ raise SwatGenXError(f"download failed: HTTP {r.status_code}", r.status_code)
208
+ with open(dest, "wb") as fh:
209
+ for chunk in r.iter_content(chunk_size=1 << 20):
210
+ fh.write(chunk)
211
+ return dest
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: swatgenx
3
+ Version: 0.1.0
4
+ Summary: Python client for SWATGenX — automated SWAT+/MODFLOW watershed models and open national water datasets for the conterminous US
5
+ Author-email: Vahid Rafiei <info@swatgenx.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://www.swatgenx.com
8
+ Project-URL: Documentation, https://www.swatgenx.com/developer-api
9
+ Project-URL: MCP server (agent access), https://www.swatgenx.com/mcp
10
+ Keywords: SWAT+,MODFLOW,hydrology,watershed,groundwater,PFAS,USGS
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering :: Hydrology
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: requests>=2.28
19
+
20
+ # swatgenx
21
+
22
+ Python client for [SWATGenX](https://www.swatgenx.com) — automated SWAT+ / MODFLOW 6
23
+ watershed models and open national water datasets for the conterminous United States.
24
+
25
+ ```
26
+ pip install swatgenx
27
+ ```
28
+
29
+ ## Public data — no account needed
30
+
31
+ ```python
32
+ import swatgenx as sg
33
+
34
+ # Example-model catalog: built SWAT+ models with calibration/validation metrics
35
+ models = sg.catalog(state="FL", calibrated_only=True)
36
+ sg.calibration("01451800")
37
+ # {'mode': 'engineer', 'cal_daily_nse': 0.642, 'val_daily_nse': 0.748, ...}
38
+
39
+ # National groundwater inventory: 28.8M lithology intervals, 7.9M wells, 46 states
40
+ sg.groundwater_at(42.73, -84.55) # nearest well + lithology log
41
+ sg.groundwater_summary()
42
+
43
+ # National PFAS monitoring inventory
44
+ sg.pfas_stations(huc8="0405")
45
+ sg.pfas_summary()
46
+ ```
47
+
48
+ ## Order and download models — free account + API key
49
+
50
+ Sign in at [swatgenx.com](https://www.swatgenx.com) → dashboard → API keys, then:
51
+
52
+ ```python
53
+ c = sg.Client(api_key="...") # or env SWATGENX_API_KEY
54
+
55
+ order = c.order(usgs_station="04124500") # any of 25,000+ USGS gauges
56
+ c.wait(order["order_id"]) # typical build: 20 min – 2 h
57
+ c.download("04124500", vpuid="0406", dest="model.zip") # ZIP straight to your disk
58
+ ```
59
+
60
+ Builds run on SWATGenX cloud infrastructure from national data (NHDPlus HR, 3DEP,
61
+ gSSURGO, NLCD, PRISM, USGS NWIS); delivery is pull-based — no email round-trip.
62
+
63
+ ## Access ladder
64
+
65
+ | tier | requires | unlocks |
66
+ |---|---|---|
67
+ | guest | nothing | all public data functions |
68
+ | member | free account + API key | model orders (fair-use), downloads |
69
+ | extended | request via info@swatgenx.com | HUC8 whole-basin, SWAT+MODFLOW-6, HUC14 30 m site models |
70
+ | calibration | account credit | cloud calibration campaigns |
71
+
72
+ `sg.access_info()` returns this ladder programmatically; quota/tier errors raise
73
+ `SwatGenXError` with upgrade guidance.
74
+
75
+ ## AI agents
76
+
77
+ The same platform is agent-native via a public MCP server:
78
+ **https://www.swatgenx.com/mcp** (see the site's `llms.txt`). This package and the MCP
79
+ server expose the same surface, enforced by the same server-side quotas.
80
+
81
+ ## Data citations
82
+
83
+ - Groundwater inventory: Zenodo DOI [10.5281/zenodo.21196958](https://doi.org/10.5281/zenodo.21196958)
84
+ - Soil PFAS inventory: Zenodo DOI [10.5281/zenodo.21096358](https://doi.org/10.5281/zenodo.21096358)
85
+
86
+ MIT-licensed client; platform terms at swatgenx.com.
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/swatgenx/__init__.py
4
+ src/swatgenx/client.py
5
+ src/swatgenx.egg-info/PKG-INFO
6
+ src/swatgenx.egg-info/SOURCES.txt
7
+ src/swatgenx.egg-info/dependency_links.txt
8
+ src/swatgenx.egg-info/requires.txt
9
+ src/swatgenx.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.28
@@ -0,0 +1 @@
1
+ swatgenx