basinkit 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.
- basinkit-0.1.0/.github/workflows/ci.yml +27 -0
- basinkit-0.1.0/.github/workflows/docs.yml +15 -0
- basinkit-0.1.0/.github/workflows/network.yml +30 -0
- basinkit-0.1.0/.github/workflows/release.yml +18 -0
- basinkit-0.1.0/.gitignore +11 -0
- basinkit-0.1.0/CHANGELOG.md +165 -0
- basinkit-0.1.0/CITATION.cff +34 -0
- basinkit-0.1.0/CONTRIBUTING.md +47 -0
- basinkit-0.1.0/LICENSE +33 -0
- basinkit-0.1.0/PKG-INFO +350 -0
- basinkit-0.1.0/PUBLISHING.md +175 -0
- basinkit-0.1.0/README.md +284 -0
- basinkit-0.1.0/RELEASE_NOTES.md +43 -0
- basinkit-0.1.0/assets/README.md +78 -0
- basinkit-0.1.0/assets/icon.png +0 -0
- basinkit-0.1.0/assets/logo-128.png +0 -0
- basinkit-0.1.0/assets/logo-256.png +0 -0
- basinkit-0.1.0/assets/logo-32.png +0 -0
- basinkit-0.1.0/assets/logo-512.png +0 -0
- basinkit-0.1.0/assets/logo-64.png +0 -0
- basinkit-0.1.0/assets/logo-animated.svg +64 -0
- basinkit-0.1.0/assets/logo-wordmark-dark.svg +75 -0
- basinkit-0.1.0/assets/logo-wordmark-light.svg +75 -0
- basinkit-0.1.0/assets/logo-wordmark.svg +78 -0
- basinkit-0.1.0/assets/logo.svg +36 -0
- basinkit-0.1.0/basinkit/__init__.py +43 -0
- basinkit-0.1.0/basinkit/basin.py +474 -0
- basinkit-0.1.0/basinkit/cache.py +185 -0
- basinkit-0.1.0/basinkit/catalog.py +416 -0
- basinkit-0.1.0/basinkit/cli.py +153 -0
- basinkit-0.1.0/basinkit/clip.py +201 -0
- basinkit-0.1.0/basinkit/delineate/__init__.py +103 -0
- basinkit-0.1.0/basinkit/delineate/api.py +51 -0
- basinkit-0.1.0/basinkit/delineate/dem.py +184 -0
- basinkit-0.1.0/basinkit/delineate/hydrobasins.py +346 -0
- basinkit-0.1.0/basinkit/exceptions.py +48 -0
- basinkit-0.1.0/basinkit/mosaic.py +125 -0
- basinkit-0.1.0/basinkit/sources/__init__.py +28 -0
- basinkit-0.1.0/basinkit/sources/attributes.py +196 -0
- basinkit-0.1.0/basinkit/sources/climate.py +358 -0
- basinkit-0.1.0/basinkit/sources/dem.py +169 -0
- basinkit-0.1.0/basinkit/sources/landcover.py +127 -0
- basinkit-0.1.0/basinkit/sources/soil.py +153 -0
- basinkit-0.1.0/basinkit/sources/stac.py +354 -0
- basinkit-0.1.0/basinkit/sources/vectors.py +81 -0
- basinkit-0.1.0/basinkit/sources/water.py +88 -0
- basinkit-0.1.0/basinkit/viz.py +152 -0
- basinkit-0.1.0/docs/api.md +11 -0
- basinkit-0.1.0/docs/assets/logo-32.png +0 -0
- basinkit-0.1.0/docs/assets/logo-animated.svg +64 -0
- basinkit-0.1.0/docs/assets/logo-wordmark-dark.svg +71 -0
- basinkit-0.1.0/docs/assets/logo-wordmark-light.svg +71 -0
- basinkit-0.1.0/docs/assets/logo.svg +36 -0
- basinkit-0.1.0/docs/catalogue.md +423 -0
- basinkit-0.1.0/docs/delineation.md +83 -0
- basinkit-0.1.0/docs/index.md +268 -0
- basinkit-0.1.0/docs/notebooks/01_quickstart.ipynb +327 -0
- basinkit-0.1.0/docs/related-work.md +144 -0
- basinkit-0.1.0/docs/tutorial.md +330 -0
- basinkit-0.1.0/docs/verification.md +215 -0
- basinkit-0.1.0/docs/why.md +83 -0
- basinkit-0.1.0/mkdocs.yml +55 -0
- basinkit-0.1.0/notebooks/01_quickstart.ipynb +327 -0
- basinkit-0.1.0/pyproject.toml +70 -0
- basinkit-0.1.0/qgis_plugin/LICENSE +33 -0
- basinkit-0.1.0/qgis_plugin/README.md +98 -0
- basinkit-0.1.0/qgis_plugin/__init__.py +11 -0
- basinkit-0.1.0/qgis_plugin/compat.py +63 -0
- basinkit-0.1.0/qgis_plugin/deps.py +89 -0
- basinkit-0.1.0/qgis_plugin/icon.png +0 -0
- basinkit-0.1.0/qgis_plugin/metadata.txt +31 -0
- basinkit-0.1.0/qgis_plugin/plugin.py +66 -0
- basinkit-0.1.0/qgis_plugin/processing_provider/__init__.py +0 -0
- basinkit-0.1.0/qgis_plugin/processing_provider/algorithms/__init__.py +0 -0
- basinkit-0.1.0/qgis_plugin/processing_provider/algorithms/base.py +70 -0
- basinkit-0.1.0/qgis_plugin/processing_provider/algorithms/delineate.py +227 -0
- basinkit-0.1.0/qgis_plugin/processing_provider/algorithms/fetch_layers.py +248 -0
- basinkit-0.1.0/qgis_plugin/processing_provider/algorithms/statistics.py +187 -0
- basinkit-0.1.0/qgis_plugin/processing_provider/provider.py +37 -0
- basinkit-0.1.0/tests/conftest.py +65 -0
- basinkit-0.1.0/tests/test_basinkit.py +782 -0
- basinkit-0.1.0/tests/test_qgis_plugin.py +121 -0
- basinkit-0.1.0/verify/README.md +34 -0
- basinkit-0.1.0/verify/basins.py +28 -0
- basinkit-0.1.0/verify/qgis_stub/qgis/PyQt/QtCore.py +10 -0
- basinkit-0.1.0/verify/qgis_stub/qgis/PyQt/QtGui.py +3 -0
- basinkit-0.1.0/verify/qgis_stub/qgis/PyQt/__init__.py +0 -0
- basinkit-0.1.0/verify/qgis_stub/qgis/__init__.py +0 -0
- basinkit-0.1.0/verify/qgis_stub/qgis/core.py +230 -0
- basinkit-0.1.0/verify/run_delineation.py +45 -0
- basinkit-0.1.0/verify/run_qgis_algorithms.py +137 -0
- basinkit-0.1.0/verify/run_qgis_wiring.py +80 -0
- basinkit-0.1.0/verify/run_rest.py +73 -0
- basinkit-0.1.0/verify/run_sources.py +63 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push: { branches: [main] }
|
|
5
|
+
pull_request: { branches: [main] }
|
|
6
|
+
|
|
7
|
+
# What this workflow answers: does basinkit's own code work, on every platform
|
|
8
|
+
# and Python we claim to support? Nothing here touches the network, so a red
|
|
9
|
+
# badge always means a defect in this repository and never that a data server
|
|
10
|
+
# was having a bad afternoon. The live-source checks live in network.yml.
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ${{ matrix.os }}
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
18
|
+
python: ["3.10", "3.11", "3.12", "3.13"]
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v5
|
|
21
|
+
- uses: actions/setup-python@v6
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python }}
|
|
24
|
+
- run: pip install -e ".[all,dev]"
|
|
25
|
+
- run: ruff check basinkit tests
|
|
26
|
+
- name: Offline tests
|
|
27
|
+
run: pytest -q -m "not network" --cov=basinkit --cov-report=term-missing
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push: { branches: [main] }
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
deploy:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
permissions: { contents: write }
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v5
|
|
12
|
+
- uses: actions/setup-python@v6
|
|
13
|
+
with: { python-version: "3.12" }
|
|
14
|
+
- run: pip install -e ".[all,dev]"
|
|
15
|
+
- run: mkdocs gh-deploy --force
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Data sources
|
|
2
|
+
|
|
3
|
+
# Remote endpoints move without warning -- CDSE deprecated a STAC endpoint,
|
|
4
|
+
# LP DAAC retired its Data Pool, sentinelsat's backend closed entirely. This is
|
|
5
|
+
# the early-warning system for that, and it is deliberately NOT on every push:
|
|
6
|
+
#
|
|
7
|
+
# * it is slow (roughly seven minutes of real downloads), and
|
|
8
|
+
# * some sources refuse GitHub's datacenter addresses outright. HydroSHEDS
|
|
9
|
+
# answers 403 to Actions runners while serving the identical request to a
|
|
10
|
+
# laptop, so gating every push on it would paint the badge red for a reason
|
|
11
|
+
# that has nothing to do with this repository.
|
|
12
|
+
#
|
|
13
|
+
# tests/conftest.py reports an upstream refusal as a skip and a wrong number as
|
|
14
|
+
# a failure, so red here means basinkit is returning something incorrect.
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
schedule:
|
|
18
|
+
- cron: "0 6 * * 1" # Mondays, 06:00 UTC
|
|
19
|
+
workflow_dispatch: # and whenever you want to ask
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
network:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v5
|
|
26
|
+
- uses: actions/setup-python@v6
|
|
27
|
+
with: { python-version: "3.12" }
|
|
28
|
+
- run: pip install -e ".[all,dev]"
|
|
29
|
+
- name: Live source tests
|
|
30
|
+
run: pytest -q -m network -rs
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write # trusted publishing, no API token to leak
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v5
|
|
15
|
+
- uses: actions/setup-python@v6
|
|
16
|
+
with: { python-version: "3.12" }
|
|
17
|
+
- run: pip install build && python -m build
|
|
18
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (unreleased)
|
|
4
|
+
|
|
5
|
+
First release.
|
|
6
|
+
|
|
7
|
+
### Delineation
|
|
8
|
+
- Three global backends: HydroBASINS graph traversal (default), D8 routing over
|
|
9
|
+
Copernicus DEM via pyflwdir, and the Global Watersheds API.
|
|
10
|
+
- `backend="auto"` falls back to DEM routing when a basin sits at the
|
|
11
|
+
HydroBASINS level-12 resolution floor.
|
|
12
|
+
- Outlet snapping to the local maximum of upstream area, with a minimum
|
|
13
|
+
drainage threshold so a hillslope point fails loudly instead of returning a
|
|
14
|
+
few hectares.
|
|
15
|
+
- Adaptive window growth when a DEM-routed basin reaches the window edge.
|
|
16
|
+
- Off-channel advisory: when a unit at least `river_snap_ratio` times larger
|
|
17
|
+
sits within 20 km but outside the snap radius, basinkit warns and records
|
|
18
|
+
`off_channel_candidate` in the provenance *without* moving the point. Found
|
|
19
|
+
by running the README's own example: `from_point(26.5, 85.2)`, advertised as
|
|
20
|
+
"14,384 km2", is 16 km off the Bagmati channel and returns 434 km2. The
|
|
21
|
+
delineation was correct; the coordinate and the documented figure were not,
|
|
22
|
+
and nothing warned. Every user-facing example now uses the Chatara outlet,
|
|
23
|
+
which the network suite checks against the published 54,100 km2, and an
|
|
24
|
+
offline test pins the documented coordinate to that one.
|
|
25
|
+
|
|
26
|
+
### Testing and CI
|
|
27
|
+
- The live-source suite moved out of `CI` into its own weekly `Data sources`
|
|
28
|
+
workflow. Some hosts refuse GitHub's datacenter addresses -- HydroSHEDS
|
|
29
|
+
answers 403 to Actions runners while serving the identical request to a
|
|
30
|
+
laptop -- so gating every push on it painted the badge red for a reason that
|
|
31
|
+
had nothing to do with this repository. `CI` is now purely offline across
|
|
32
|
+
three operating systems and Python 3.10 to 3.13, and red there always means a
|
|
33
|
+
defect here.
|
|
34
|
+
- `tests/conftest.py` reports an upstream refusal (403, 404, 429, 5xx, timeout)
|
|
35
|
+
as a *skip* with the reason attached, and leaves a wrong number a failure. A
|
|
36
|
+
monitor you stop reading is not a monitor.
|
|
37
|
+
|
|
38
|
+
### Data
|
|
39
|
+
- Anonymous access to 20 datasets: Copernicus DEM GLO-30/90, NASADEM, SRTM,
|
|
40
|
+
HydroBASINS/RIVERS/LAKES/ATLAS, ESA WorldCover, ESRI annual LULC, SoilGrids,
|
|
41
|
+
CHIRPS v3.0, PERSIANN-CDR, TerraClimate, JRC Global Surface Water,
|
|
42
|
+
Sentinel-2, Sentinel-1 RTC, Landsat C2 L2, HLS.
|
|
43
|
+
- Everything is clipped and masked to the basin polygon, not its bounding box.
|
|
44
|
+
- Cosine-latitude weighting in zonal means; equal-area projection for areas.
|
|
45
|
+
- Memory-budgeted mosaicking with automatic coarsening above 100 Mpx.
|
|
46
|
+
- CHIRPS read through HTTP range requests, so only the basin window transfers.
|
|
47
|
+
|
|
48
|
+
### Fixed during multi-continent verification
|
|
49
|
+
- **Outlet snapping for HydroBASINS.** A coordinate on a big river's bank falls
|
|
50
|
+
in a small lateral unit: Rhine at Lobith returned 271 km2 instead of 160,800,
|
|
51
|
+
Godavari at Polavaram 353 instead of 307,800. Now snaps when a unit within
|
|
52
|
+
1 km drains at least 10x more, warns, and records the jump in provenance.
|
|
53
|
+
- **Sentinel-2 offset applied twice.** Earth Search pre-applies the baseline
|
|
54
|
+
04.00 BOA offset and flags it while still publishing the nominal -0.1;
|
|
55
|
+
applying both gave negative surface reflectance.
|
|
56
|
+
- **Nodata averaged into composites.** Optical nodata is 0, so an unmasked
|
|
57
|
+
median over a basin spanning several MGRS tiles came back 87% zero. Now
|
|
58
|
+
loaded as float32 with NaN, and grouped by solar day.
|
|
59
|
+
- **Clip failed on every Dataset.** `Dataset` has no `.values` array, so every
|
|
60
|
+
multi-band STAC result raised. The check is now Dataset-aware and never
|
|
61
|
+
forces a lazy cube.
|
|
62
|
+
- **Exported rasters carried no nodata**, so the clip stopped existing outside
|
|
63
|
+
Python. Now declared in the file header.
|
|
64
|
+
- **255 averaged into JRC surface water**, producing occurrence above 100%.
|
|
65
|
+
- **`outlets="min"` in DEM routing** pulled flow networks toward the window's
|
|
66
|
+
lowest cell.
|
|
67
|
+
|
|
68
|
+
### Performance
|
|
69
|
+
- CHIRPS via HTTP range reads rather than whole-globe downloads: a three-year
|
|
70
|
+
basin series went from 116 s to 24 s.
|
|
71
|
+
- TerraClimate fetches its per-variable, per-year files concurrently.
|
|
72
|
+
- Pixel budgets on the STAC path, with a lower one for Sentinel-1 RTC, whose
|
|
73
|
+
float32 10 m frames cost far more per pixel than optical COGs.
|
|
74
|
+
|
|
75
|
+
### Corrections after external review
|
|
76
|
+
- **The same basin was quoted with two different reference areas.** The Roadmap
|
|
77
|
+
compared the Koshi against `reported_up_area_km2` (54,581 km2 -- HydroBASINS'
|
|
78
|
+
own bookkeeping) and headlined the resulting 0.15%; Verification correctly
|
|
79
|
+
used the published 54,100 km2 and 0.73%. The first comparison is close to
|
|
80
|
+
circular, since both numbers come from the same polygons. Every document now
|
|
81
|
+
uses the published reference, and `docs/delineation.md` says plainly that the
|
|
82
|
+
internal check is not an accuracy figure. Two regression tests guard it.
|
|
83
|
+
- **Accuracy is now reported as a distribution.** n = 12, median 0.74%, eight
|
|
84
|
+
within 1%, nine within 3% -- instead of the single most flattering basin. The
|
|
85
|
+
sample size and its bias (large, well-mapped rivers with published areas) are
|
|
86
|
+
stated.
|
|
87
|
+
- **"Not one of these raised an exception" was false.** Two of the ten defects
|
|
88
|
+
did; both were found by auditing untested methods rather than by the suite.
|
|
89
|
+
- **Every delineation figure now traces to one run** of
|
|
90
|
+
`verify/run_delineation.py`, not to a mixture of runs. The Rhine row had been
|
|
91
|
+
carried over from before the distance fix.
|
|
92
|
+
- **The base grid of each backend is stated**, in the module docstring, the
|
|
93
|
+
README and both reports. HydroBASINS is extracted from HydroSHEDS at 15
|
|
94
|
+
arc-seconds, so the default routes on a ~460 m grid built from February 2000
|
|
95
|
+
SRTM. It was the most load-bearing undisclosed fact about the package.
|
|
96
|
+
- **MERIT-Hydro is reframed from cross-check to migration path.** At 3
|
|
97
|
+
arc-seconds it is five times finer than the default and hydrologically
|
|
98
|
+
conditioned; the `api` backend already implements that path. What blocks it
|
|
99
|
+
as a default is its non-commercial licence and unautomatable acquisition, not
|
|
100
|
+
the routing.
|
|
101
|
+
- Both reports carry a byline and an anchor date.
|
|
102
|
+
|
|
103
|
+
### Logo
|
|
104
|
+
- An animated multicolour mark in `assets/`: four coloured tributaries joining
|
|
105
|
+
one river inside a basin divide. The colour carries the idea -- many open
|
|
106
|
+
data sources, one basin -- rather than decorating it.
|
|
107
|
+
- Respects `prefers-reduced-motion`, follows the viewer's colour scheme, and
|
|
108
|
+
ships pinned light and dark wordmarks because GitHub's theme and the
|
|
109
|
+
browser's `prefers-color-scheme` can disagree.
|
|
110
|
+
- Lettering is Archivo glyph outlines, not live text: an SVG shown through
|
|
111
|
+
`<img>` cannot load a web font.
|
|
112
|
+
- Geometry is generated rather than hand-drawn -- a wobbling polar radius for
|
|
113
|
+
the divide, endpoints clamped against it so nothing pokes through, and plain
|
|
114
|
+
downstream-sagging arcs for the tributaries.
|
|
115
|
+
|
|
116
|
+
### QGIS plugin
|
|
117
|
+
- A Processing provider in `qgis_plugin/`: delineate a basin from a canvas
|
|
118
|
+
click, fetch layers clipped to it, and basin statistics with an HTML report.
|
|
119
|
+
- Registration happens in `initProcessing()` with `initGui()` forwarding to it,
|
|
120
|
+
so the algorithms are visible to `qgis_process` and headless runs, not only
|
|
121
|
+
to the desktop GUI.
|
|
122
|
+
- `compat.py` covers two silent breakages across supported QGIS versions:
|
|
123
|
+
`QgsField` took a `QMetaType` argument from 3.38 (and Qt6, which QGIS 4 uses,
|
|
124
|
+
removed `QVariant.Type` outright), and `Qgis.WkbType` replaced
|
|
125
|
+
`QgsWkbTypes.Type` in 3.30.
|
|
126
|
+
- Checked against stubbed bindings at four QGIS versions, plus an end-to-end
|
|
127
|
+
run of the real `processAlgorithm` bodies. 22 further tests validate the
|
|
128
|
+
metadata against what plugins.qgis.org actually enforces -- which is not what
|
|
129
|
+
its documentation table says.
|
|
130
|
+
|
|
131
|
+
### Honesty pass on the catalogue
|
|
132
|
+
- Every entry now carries an explicit `implemented` flag. Seven datasets were
|
|
133
|
+
listed as if they were fetchable when no fetcher existed; asking for one now
|
|
134
|
+
raises `NotImplementedSource` carrying the access route, the licence and what
|
|
135
|
+
to do with the data once you have it. `basinkit catalog` marks them `DOC`.
|
|
136
|
+
- `grace` was listed as needing no account. The reliable route is JPL via
|
|
137
|
+
Earthdata Login; the CSR anonymous mirror was unreachable when checked.
|
|
138
|
+
Corrected rather than left optimistic.
|
|
139
|
+
- A test asserts every key in `DEFAULT_STACK` is anonymous, commercially safe,
|
|
140
|
+
redistributable **and** implemented.
|
|
141
|
+
|
|
142
|
+
### Added
|
|
143
|
+
- **BasinATLAS** (`Basin.attributes()`): 281 pre-computed environmental
|
|
144
|
+
variables per sub-basin. The `_u` columns are already aggregated upstream, so
|
|
145
|
+
one lookup characterises a whole catchment without touching a raster. Its
|
|
146
|
+
mean elevation for the Koshi agrees with basinkit's own COP-DEM computation
|
|
147
|
+
to 0.1%.
|
|
148
|
+
- Scaled integers are decoded: read raw, the Koshi appears to average 50 degrees
|
|
149
|
+
Celsius and a 204 degree slope.
|
|
150
|
+
- `Basin.plot()` crashed on NumPy 2.x (`ndarray.ptp()` was removed in 2.0) and
|
|
151
|
+
had never been executed by any test. Fixed, with a test that scans the
|
|
152
|
+
package for every NumPy-2-removed API.
|
|
153
|
+
|
|
154
|
+
### Verified
|
|
155
|
+
- Test suite run on Python 3.10, 3.11 and 3.12 — the CI matrix previously
|
|
156
|
+
claimed three versions and only one had ever run.
|
|
157
|
+
- Paths an audit found untested and now covered: `explore()` with leafmap,
|
|
158
|
+
`plot()`, `from_file()` including reprojection, the DEM backend's window-edge
|
|
159
|
+
exclusion and its refusal to return a truncated basin.
|
|
160
|
+
|
|
161
|
+
### Licensing
|
|
162
|
+
- Machine-readable catalogue driving the fetchers, the CLI and
|
|
163
|
+
`Basin.license_report()`.
|
|
164
|
+
- `Basin.check_license()` raises on restricted use.
|
|
165
|
+
- MERIT Hydro, FABDEM, MSWEP and GRDC are catalogued but opt-in and flagged.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Citation metadata. GitHub renders this as a "Cite this repository" button on
|
|
2
|
+
# the repo page, and Zenodo reads it when minting the DOI.
|
|
3
|
+
#
|
|
4
|
+
# Two fields are placeholders until the first release exists:
|
|
5
|
+
# doi — filled in after Zenodo mints it (see PUBLISHING.md step 6)
|
|
6
|
+
# date-released — the date you actually cut v0.1.0
|
|
7
|
+
cff-version: 1.2.0
|
|
8
|
+
message: "If you use basinkit in published work, please cite it as below, and cite the underlying datasets — Basin.license_report() prints those."
|
|
9
|
+
title: "basinkit: basin-scale acquisition of open Earth observation data"
|
|
10
|
+
abstract: >-
|
|
11
|
+
A Python package that delineates the upstream river basin of any coordinate
|
|
12
|
+
on Earth and returns open Earth observation layers clipped and masked to that
|
|
13
|
+
polygon rather than to its bounding box. Nineteen datasets are reachable
|
|
14
|
+
without an account. Delineation is validated against published gauge areas on
|
|
15
|
+
six continents.
|
|
16
|
+
type: software
|
|
17
|
+
authors:
|
|
18
|
+
- given-names: Pradeepika
|
|
19
|
+
family-names: Kaushik
|
|
20
|
+
# orcid: "https://orcid.org/0000-0000-0000-0000" # add yours
|
|
21
|
+
version: 0.1.0
|
|
22
|
+
date-released: 2026-08-30
|
|
23
|
+
license: MIT
|
|
24
|
+
repository-code: "https://github.com/Praddy-GByte/basinkit"
|
|
25
|
+
url: "https://github.com/Praddy-GByte/basinkit"
|
|
26
|
+
keywords:
|
|
27
|
+
- hydrology
|
|
28
|
+
- watershed delineation
|
|
29
|
+
- river basin
|
|
30
|
+
- remote sensing
|
|
31
|
+
- earth observation
|
|
32
|
+
- open data
|
|
33
|
+
- gis
|
|
34
|
+
- qgis
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Adding a data source
|
|
4
|
+
|
|
5
|
+
Two rules, and they are what the package is for.
|
|
6
|
+
|
|
7
|
+
1. **Register it in `basinkit/catalog.py` first.** Resolution, coverage,
|
|
8
|
+
licence, auth requirement, whether it can be redistributed and used
|
|
9
|
+
commercially. That table is not documentation — the fetchers and the CLI
|
|
10
|
+
read from it, so it cannot drift from reality.
|
|
11
|
+
2. **Set `implemented` honestly.** If there is no fetcher, the entry is
|
|
12
|
+
`implemented=False` and asking for it raises `NotImplementedSource` with the
|
|
13
|
+
access route. A catalogue that lists datasets it cannot deliver reads as a
|
|
14
|
+
feature list, which is worse than a shorter catalogue.
|
|
15
|
+
3. **Anonymous or opt-in.** If a source needs an account or its licence
|
|
16
|
+
restricts use, it does not go in `DEFAULT_STACK`. It gets `auth` set
|
|
17
|
+
accurately and a `notes` string explaining what the user is walking into,
|
|
18
|
+
and it announces itself before the first byte moves.
|
|
19
|
+
|
|
20
|
+
New adapters go in `basinkit/sources/` grouped by *access pattern* (STAC,
|
|
21
|
+
tiled COG, WCS, NetCDF-over-HTTP, vector download), not by dataset.
|
|
22
|
+
|
|
23
|
+
Every fetcher takes a geometry and clips to it. Bounding boxes are for finding
|
|
24
|
+
tiles, never for what comes back.
|
|
25
|
+
|
|
26
|
+
## Tests
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pytest -m "not network" # fast, runs everywhere
|
|
30
|
+
pytest -m network # hits real endpoints
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Prefer tests that check against an **independently known value** — the Koshi
|
|
34
|
+
basin's published area, its documented mean annual rainfall, the fact that
|
|
35
|
+
water occurrence is a percentage — over snapshots of whatever the code
|
|
36
|
+
currently produces. A snapshot test passes happily while the answer is wrong.
|
|
37
|
+
|
|
38
|
+
The network suite runs weekly in CI on purpose. Remote endpoints move without
|
|
39
|
+
warning: CDSE deprecated a STAC endpoint, LP DAAC retired its Data Pool,
|
|
40
|
+
sentinelsat's entire backend closed. The scheduled run is how we find out
|
|
41
|
+
before users do.
|
|
42
|
+
|
|
43
|
+
## Style
|
|
44
|
+
|
|
45
|
+
`ruff check basinkit tests` must be clean. Comments should explain *why* — the
|
|
46
|
+
non-obvious constraint, the failure mode being guarded against — not restate
|
|
47
|
+
what the line does.
|
basinkit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pradeepika Kaushik
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
NOTE ON DATA LICENCES
|
|
26
|
+
|
|
27
|
+
This licence covers the basinkit source code only. The datasets basinkit
|
|
28
|
+
fetches carry their own terms. Everything in the default stack is CC BY 4.0 or
|
|
29
|
+
more permissive and requires attribution; a few opt-in datasets (MERIT Hydro,
|
|
30
|
+
FABDEM, MSWEP, GRDC) restrict commercial use or redistribution outright.
|
|
31
|
+
|
|
32
|
+
Run `basinkit catalog` or `Basin.license_report()` for the current terms of
|
|
33
|
+
every layer you used.
|