euroflood 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.
Files changed (177) hide show
  1. euroflood-0.1.0/.github/workflows/ci.yml +73 -0
  2. euroflood-0.1.0/.github/workflows/docs.yml +36 -0
  3. euroflood-0.1.0/.github/workflows/examples.yml +32 -0
  4. euroflood-0.1.0/.github/workflows/release.yml +71 -0
  5. euroflood-0.1.0/.gitignore +223 -0
  6. euroflood-0.1.0/.pre-commit-config.yaml +36 -0
  7. euroflood-0.1.0/.python-version +1 -0
  8. euroflood-0.1.0/CHANGELOG.md +113 -0
  9. euroflood-0.1.0/CITATION.cff +41 -0
  10. euroflood-0.1.0/CONTRIBUTING.md +67 -0
  11. euroflood-0.1.0/LICENSE +21 -0
  12. euroflood-0.1.0/PKG-INFO +189 -0
  13. euroflood-0.1.0/README.md +138 -0
  14. euroflood-0.1.0/RELEASING.md +84 -0
  15. euroflood-0.1.0/docs/assets/favicon.png +0 -0
  16. euroflood-0.1.0/docs/assets/logo.svg +4 -0
  17. euroflood-0.1.0/docs/concepts.md +128 -0
  18. euroflood-0.1.0/docs/getting-started.md +110 -0
  19. euroflood-0.1.0/docs/hpc-runbook.md +190 -0
  20. euroflood-0.1.0/docs/images/depth.png +0 -0
  21. euroflood-0.1.0/docs/images/footprints.png +0 -0
  22. euroflood-0.1.0/docs/images/hazard.png +0 -0
  23. euroflood-0.1.0/docs/images/hero-dark.png +0 -0
  24. euroflood-0.1.0/docs/images/hero.png +0 -0
  25. euroflood-0.1.0/docs/images/recurrence.png +0 -0
  26. euroflood-0.1.0/docs/index.md +125 -0
  27. euroflood-0.1.0/docs/reference/api.md +41 -0
  28. euroflood-0.1.0/docs/reference/cli.md +70 -0
  29. euroflood-0.1.0/docs/reference/configuration.md +20 -0
  30. euroflood-0.1.0/docs/reference/core.md +20 -0
  31. euroflood-0.1.0/docs/reference/floodframe.md +19 -0
  32. euroflood-0.1.0/docs/reference/index.md +31 -0
  33. euroflood-0.1.0/docs/reference/pipelines.md +43 -0
  34. euroflood-0.1.0/docs/reference/services.md +35 -0
  35. euroflood-0.1.0/docs/reference/visualization.md +12 -0
  36. euroflood-0.1.0/docs/stylesheets/extra.css +58 -0
  37. euroflood-0.1.0/docs/tutorials/.gitignore +16 -0
  38. euroflood-0.1.0/docs/tutorials/01_quickstart.ipynb +298 -0
  39. euroflood-0.1.0/docs/tutorials/01_quickstart.py +62 -0
  40. euroflood-0.1.0/docs/tutorials/02_discover_and_filter.ipynb +2211 -0
  41. euroflood-0.1.0/docs/tutorials/02_discover_and_filter.py +117 -0
  42. euroflood-0.1.0/docs/tutorials/03_visualize.ipynb +815 -0
  43. euroflood-0.1.0/docs/tutorials/03_visualize.py +89 -0
  44. euroflood-0.1.0/docs/tutorials/04_download_and_measure.ipynb +751 -0
  45. euroflood-0.1.0/docs/tutorials/04_download_and_measure.py +109 -0
  46. euroflood-0.1.0/docs/tutorials/05_hazard.ipynb +802 -0
  47. euroflood-0.1.0/docs/tutorials/05_hazard.py +73 -0
  48. euroflood-0.1.0/docs/tutorials/06_analysis.ipynb +710 -0
  49. euroflood-0.1.0/docs/tutorials/06_analysis.py +106 -0
  50. euroflood-0.1.0/docs/tutorials/07_cli_and_config.ipynb +332 -0
  51. euroflood-0.1.0/docs/tutorials/07_cli_and_config.py +84 -0
  52. euroflood-0.1.0/docs/tutorials/README.md +71 -0
  53. euroflood-0.1.0/docs/tutorials/thumbs/01_quickstart.png +0 -0
  54. euroflood-0.1.0/docs/tutorials/thumbs/02_discover.png +0 -0
  55. euroflood-0.1.0/docs/tutorials/thumbs/03_visualize.png +0 -0
  56. euroflood-0.1.0/docs/tutorials/thumbs/04_download.png +0 -0
  57. euroflood-0.1.0/docs/tutorials/thumbs/05_hazard.png +0 -0
  58. euroflood-0.1.0/docs/tutorials/thumbs/06_analysis.png +0 -0
  59. euroflood-0.1.0/docs/tutorials/thumbs/07_cli.png +0 -0
  60. euroflood-0.1.0/mkdocs.yml +155 -0
  61. euroflood-0.1.0/pyproject.toml +206 -0
  62. euroflood-0.1.0/scripts/make_doc_images.py +135 -0
  63. euroflood-0.1.0/scripts/make_test_fixtures.py +250 -0
  64. euroflood-0.1.0/scripts/slurm/della_build_index.sbatch +58 -0
  65. euroflood-0.1.0/scripts/slurm/della_build_index_test.sbatch +96 -0
  66. euroflood-0.1.0/scripts/slurm/della_ingest.sbatch +69 -0
  67. euroflood-0.1.0/scripts/slurm/della_mirror.sh +35 -0
  68. euroflood-0.1.0/scripts/slurm/della_test.sbatch +55 -0
  69. euroflood-0.1.0/src/euroflood/__init__.py +98 -0
  70. euroflood-0.1.0/src/euroflood/_data.py +52 -0
  71. euroflood-0.1.0/src/euroflood/_progress.py +187 -0
  72. euroflood-0.1.0/src/euroflood/api.py +223 -0
  73. euroflood-0.1.0/src/euroflood/cli.py +736 -0
  74. euroflood-0.1.0/src/euroflood/config.py +377 -0
  75. euroflood-0.1.0/src/euroflood/console.py +315 -0
  76. euroflood-0.1.0/src/euroflood/core/__init__.py +1 -0
  77. euroflood-0.1.0/src/euroflood/core/grid.py +94 -0
  78. euroflood-0.1.0/src/euroflood/core/manifest.py +189 -0
  79. euroflood-0.1.0/src/euroflood/exceptions.py +55 -0
  80. euroflood-0.1.0/src/euroflood/logging.py +139 -0
  81. euroflood-0.1.0/src/euroflood/pipelines/__init__.py +1 -0
  82. euroflood-0.1.0/src/euroflood/pipelines/discovery.py +696 -0
  83. euroflood-0.1.0/src/euroflood/pipelines/doctor.py +103 -0
  84. euroflood-0.1.0/src/euroflood/pipelines/export.py +382 -0
  85. euroflood-0.1.0/src/euroflood/pipelines/hazard.py +364 -0
  86. euroflood-0.1.0/src/euroflood/pipelines/ingestion.py +298 -0
  87. euroflood-0.1.0/src/euroflood/pipelines/ledger.py +59 -0
  88. euroflood-0.1.0/src/euroflood/pipelines/mirror.py +165 -0
  89. euroflood-0.1.0/src/euroflood/pipelines/product_hero.png +0 -0
  90. euroflood-0.1.0/src/euroflood/pipelines/product_readme.md +78 -0
  91. euroflood-0.1.0/src/euroflood/pipelines/publish.py +279 -0
  92. euroflood-0.1.0/src/euroflood/pipelines/verify.py +196 -0
  93. euroflood-0.1.0/src/euroflood/py.typed +0 -0
  94. euroflood-0.1.0/src/euroflood/schemas.py +49 -0
  95. euroflood-0.1.0/src/euroflood/services/__init__.py +1 -0
  96. euroflood-0.1.0/src/euroflood/services/_duckdb.py +39 -0
  97. euroflood-0.1.0/src/euroflood/services/dictionary_repository.py +79 -0
  98. euroflood-0.1.0/src/euroflood/services/downloader.py +185 -0
  99. euroflood-0.1.0/src/euroflood/services/events_repository.py +67 -0
  100. euroflood-0.1.0/src/euroflood/services/geocoding.py +354 -0
  101. euroflood-0.1.0/src/euroflood/services/hazard_tiles.py +125 -0
  102. euroflood-0.1.0/src/euroflood/services/index_repository.py +172 -0
  103. euroflood-0.1.0/src/euroflood/services/inventory.py +77 -0
  104. euroflood-0.1.0/src/euroflood/services/location.py +178 -0
  105. euroflood-0.1.0/src/euroflood/services/processor.py +181 -0
  106. euroflood-0.1.0/src/euroflood/services/raster_ops.py +319 -0
  107. euroflood-0.1.0/src/euroflood/services/scraper.py +178 -0
  108. euroflood-0.1.0/src/euroflood/services/source_coop.py +97 -0
  109. euroflood-0.1.0/src/euroflood/services/statistics.py +193 -0
  110. euroflood-0.1.0/src/euroflood/services/zenodo.py +93 -0
  111. euroflood-0.1.0/src/euroflood/viz/__init__.py +214 -0
  112. euroflood-0.1.0/src/euroflood/viz/_colormaps.py +65 -0
  113. euroflood-0.1.0/src/euroflood/viz/_deps.py +33 -0
  114. euroflood-0.1.0/src/euroflood/viz/_interactive.py +327 -0
  115. euroflood-0.1.0/src/euroflood/viz/_raster.py +322 -0
  116. euroflood-0.1.0/src/euroflood/viz/_static.py +278 -0
  117. euroflood-0.1.0/tests/conftest.py +365 -0
  118. euroflood-0.1.0/tests/fixtures/realdata/ATTRIBUTION.md +24 -0
  119. euroflood-0.1.0/tests/fixtures/realdata/efas_depth_clip.tif +0 -0
  120. euroflood-0.1.0/tests/fixtures/realdata/index/dictionary_meta.json +8 -0
  121. euroflood-0.1.0/tests/fixtures/realdata/index/europe_flood_index.tif +0 -0
  122. euroflood-0.1.0/tests/fixtures/realdata/index/events.parquet +0 -0
  123. euroflood-0.1.0/tests/fixtures/realdata/index/flood_dictionary.parquet +0 -0
  124. euroflood-0.1.0/tests/fixtures/realdata/index/manifest.json +11 -0
  125. euroflood-0.1.0/tests/fixtures/realdata/nuts_subset.geojson +23 -0
  126. euroflood-0.1.0/tests/integration/__init__.py +0 -0
  127. euroflood-0.1.0/tests/integration/test_realdata.py +152 -0
  128. euroflood-0.1.0/tests/integration/test_regression.py +99 -0
  129. euroflood-0.1.0/tests/integration/test_smoke.py +114 -0
  130. euroflood-0.1.0/tests/online/__init__.py +0 -0
  131. euroflood-0.1.0/tests/online/test_published_index.py +48 -0
  132. euroflood-0.1.0/tests/unit/__init__.py +0 -0
  133. euroflood-0.1.0/tests/unit/core/__init__.py +0 -0
  134. euroflood-0.1.0/tests/unit/core/test_grid.py +126 -0
  135. euroflood-0.1.0/tests/unit/core/test_manifest.py +155 -0
  136. euroflood-0.1.0/tests/unit/pipelines/__init__.py +0 -0
  137. euroflood-0.1.0/tests/unit/pipelines/test_discovery.py +528 -0
  138. euroflood-0.1.0/tests/unit/pipelines/test_doctor.py +155 -0
  139. euroflood-0.1.0/tests/unit/pipelines/test_export.py +283 -0
  140. euroflood-0.1.0/tests/unit/pipelines/test_floodframe_repr.py +78 -0
  141. euroflood-0.1.0/tests/unit/pipelines/test_hazard.py +280 -0
  142. euroflood-0.1.0/tests/unit/pipelines/test_ingestion.py +325 -0
  143. euroflood-0.1.0/tests/unit/pipelines/test_ledger.py +98 -0
  144. euroflood-0.1.0/tests/unit/pipelines/test_mirror.py +248 -0
  145. euroflood-0.1.0/tests/unit/pipelines/test_publish.py +172 -0
  146. euroflood-0.1.0/tests/unit/pipelines/test_verify.py +141 -0
  147. euroflood-0.1.0/tests/unit/services/__init__.py +0 -0
  148. euroflood-0.1.0/tests/unit/services/test_dictionary_repository.py +78 -0
  149. euroflood-0.1.0/tests/unit/services/test_downloader.py +171 -0
  150. euroflood-0.1.0/tests/unit/services/test_duckdb.py +39 -0
  151. euroflood-0.1.0/tests/unit/services/test_events_repository.py +58 -0
  152. euroflood-0.1.0/tests/unit/services/test_geocoding.py +379 -0
  153. euroflood-0.1.0/tests/unit/services/test_hazard_tiles.py +122 -0
  154. euroflood-0.1.0/tests/unit/services/test_index_repository.py +172 -0
  155. euroflood-0.1.0/tests/unit/services/test_inventory.py +47 -0
  156. euroflood-0.1.0/tests/unit/services/test_location.py +161 -0
  157. euroflood-0.1.0/tests/unit/services/test_processor.py +284 -0
  158. euroflood-0.1.0/tests/unit/services/test_raster_ops.py +242 -0
  159. euroflood-0.1.0/tests/unit/services/test_scraper.py +174 -0
  160. euroflood-0.1.0/tests/unit/services/test_source_coop.py +90 -0
  161. euroflood-0.1.0/tests/unit/services/test_statistics.py +234 -0
  162. euroflood-0.1.0/tests/unit/services/test_zenodo.py +58 -0
  163. euroflood-0.1.0/tests/unit/test_cli.py +769 -0
  164. euroflood-0.1.0/tests/unit/test_config.py +94 -0
  165. euroflood-0.1.0/tests/unit/test_console.py +229 -0
  166. euroflood-0.1.0/tests/unit/test_data.py +50 -0
  167. euroflood-0.1.0/tests/unit/test_logging.py +114 -0
  168. euroflood-0.1.0/tests/unit/test_progress.py +135 -0
  169. euroflood-0.1.0/tests/unit/test_public_api.py +56 -0
  170. euroflood-0.1.0/tests/unit/test_schemas.py +63 -0
  171. euroflood-0.1.0/tests/unit/viz/conftest.py +278 -0
  172. euroflood-0.1.0/tests/unit/viz/test_api.py +240 -0
  173. euroflood-0.1.0/tests/unit/viz/test_colormaps.py +30 -0
  174. euroflood-0.1.0/tests/unit/viz/test_interactive.py +106 -0
  175. euroflood-0.1.0/tests/unit/viz/test_raster.py +170 -0
  176. euroflood-0.1.0/tests/unit/viz/test_static.py +111 -0
  177. euroflood-0.1.0/uv.lock +3621 -0
@@ -0,0 +1,73 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ quality:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ # Add "3.14" once rasterio/osmnx/duckdb wheels are available for it.
19
+ python-version: ["3.13"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v5
25
+ with:
26
+ enable-cache: true
27
+ python-version: ${{ matrix.python-version }}
28
+
29
+ - name: Install dependencies
30
+ run: uv sync --extra viz
31
+
32
+ - name: Ruff format check
33
+ run: uv run ruff format --check .
34
+
35
+ - name: Ruff lint
36
+ run: uv run ruff check .
37
+
38
+ - name: Type check (mypy)
39
+ run: uv run mypy src
40
+
41
+ - name: Dependency check (deptry)
42
+ run: uv run deptry .
43
+
44
+ - name: Tests + coverage
45
+ # -n auto parallelises the suite across the runner's cores (pytest-xdist);
46
+ # pytest-cov aggregates per-worker coverage, so fail_under still applies.
47
+ run: uv run pytest -n auto --cov=euroflood --cov-report=xml --cov-report=term-missing
48
+
49
+ - name: Tutorials (offline smoke)
50
+ # Execute the cheap-path tutorials against the committed Cologne fixture with no
51
+ # network. The download/hazard tutorials (04, 05) need the live index -> nightly
52
+ # examples.yml. Absolute paths: nbmake runs each notebook with cwd = examples/.
53
+ env:
54
+ EUROFLOOD_CACHE_DIR: ${{ github.workspace }}/tests/fixtures/realdata/index
55
+ EUROFLOOD_INDEX_MODE: local
56
+ EUROFLOOD_GEOCODER_BACKEND: local
57
+ EUROFLOOD_BOUNDARY_DATASET_PATH: ${{ github.workspace }}/tests/fixtures/realdata/nuts_subset.geojson
58
+ EUROFLOOD_SHOW_PROGRESS: "0"
59
+ run: >-
60
+ uv run pytest --nbmake --nbmake-timeout=120
61
+ examples/01_quickstart.ipynb
62
+ examples/02_discover_and_filter.ipynb
63
+ examples/03_visualize.ipynb
64
+ examples/07_cli_and_config.ipynb
65
+
66
+ - name: Docs build (strict)
67
+ run: uv run mkdocs build --strict
68
+
69
+ - name: Upload coverage to Codecov
70
+ uses: codecov/codecov-action@v4
71
+ continue-on-error: true
72
+ with:
73
+ files: ./coverage.xml
@@ -0,0 +1,36 @@
1
+ name: docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ concurrency:
12
+ group: docs-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ deploy:
17
+ # Docs are hosted from the public mirror (cisgroup.github.io/euroflood). On the
18
+ # private dev repo this job is skipped, so it never deploys a private-repo Pages site.
19
+ if: github.repository == 'cisgroup/euroflood'
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v5
26
+ with:
27
+ enable-cache: true
28
+ python-version: "3.13"
29
+
30
+ - name: Install dependencies
31
+ # Match ci.yml: the viz extra is needed so mkdocstrings can import
32
+ # euroflood.viz and render the visualization reference.
33
+ run: uv sync --extra viz
34
+
35
+ - name: Deploy docs to GitHub Pages
36
+ run: uv run mkdocs gh-deploy --force
@@ -0,0 +1,32 @@
1
+ name: Examples (live)
2
+
3
+ # Nightly execution of ALL tutorials against the LIVE published index (network) — including
4
+ # the download/hazard notebooks (04, 05) that the offline PR smoke in ci.yml can't cover.
5
+ # Also runnable on demand. Mirrors the opt-in philosophy of the `online` test suite.
6
+
7
+ on:
8
+ schedule:
9
+ - cron: "17 5 * * *" # daily 05:17 UTC
10
+ workflow_dispatch:
11
+
12
+ concurrency:
13
+ group: examples-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ tutorials:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Install uv
23
+ uses: astral-sh/setup-uv@v5
24
+ with:
25
+ enable-cache: true
26
+ python-version: "3.13"
27
+
28
+ - name: Install dependencies
29
+ run: uv sync --extra viz
30
+
31
+ - name: Run all tutorials against the live index
32
+ run: uv run pytest --nbmake -n=auto --nbmake-timeout=600 examples/
@@ -0,0 +1,71 @@
1
+ name: Release
2
+
3
+ # Publish to PyPI when a version tag is pushed (e.g. `git tag v1.0.0 && git push --tags`).
4
+ # Uses PyPI Trusted Publishing (OIDC) — no API token stored. One-time setup: add a
5
+ # trusted publisher on PyPI for repo cisgroup/euroflood, workflow `release.yml`,
6
+ # environment `pypi`.
7
+
8
+ on:
9
+ push:
10
+ tags: ["v*"]
11
+
12
+ jobs:
13
+ build:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v5
20
+ with:
21
+ enable-cache: true
22
+ python-version: "3.13"
23
+
24
+ - name: Install dependencies
25
+ # Match ci.yml (--extra viz): the gate runs the full pytest suite + mkdocs, both of
26
+ # which need the viz deps (matplotlib/folium) — without them a viz test errors and
27
+ # the gate (hence the whole release) fails.
28
+ run: uv sync --extra viz
29
+
30
+ - name: Verify tag matches package version
31
+ run: |
32
+ pkg=$(uv run python -c "import tomllib, pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text())['project']['version'])")
33
+ if [ "v$pkg" != "$GITHUB_REF_NAME" ]; then
34
+ echo "::error::Tag $GITHUB_REF_NAME does not match pyproject version v$pkg"
35
+ exit 1
36
+ fi
37
+
38
+ - name: Gate (lint, types, deps, tests, docs)
39
+ run: |
40
+ uv run ruff format --check .
41
+ uv run ruff check .
42
+ uv run mypy src
43
+ uv run deptry .
44
+ uv run pytest -q
45
+ uv run mkdocs build --strict
46
+
47
+ - name: Build sdist + wheel
48
+ run: uv build
49
+
50
+ - uses: actions/upload-artifact@v4
51
+ with:
52
+ name: dist
53
+ path: dist/
54
+
55
+ pypi:
56
+ needs: build
57
+ # Only the public mirror publishes to PyPI (where the trusted publisher is registered).
58
+ # The private dev repo never tags for release, but guard it belt-and-suspenders.
59
+ if: github.repository == 'cisgroup/euroflood'
60
+ runs-on: ubuntu-latest
61
+ environment: pypi
62
+ permissions:
63
+ id-token: write # OIDC — required for trusted publishing
64
+ steps:
65
+ - uses: actions/download-artifact@v4
66
+ with:
67
+ name: dist
68
+ path: dist/
69
+
70
+ - name: Publish to PyPI
71
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,223 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+ #poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ #pdm.lock
116
+ #pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ #pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .envrc
140
+ .venv
141
+ env/
142
+ venv/
143
+ ENV/
144
+ env.bak/
145
+ venv.bak/
146
+
147
+ # Spyder project settings
148
+ .spyderproject
149
+ .spyproject
150
+
151
+ # Rope project settings
152
+ .ropeproject
153
+
154
+ # mkdocs documentation
155
+ /site
156
+
157
+ # mypy
158
+ .mypy_cache/
159
+ .dmypy.json
160
+ dmypy.json
161
+
162
+ # Pyre type checker
163
+ .pyre/
164
+
165
+ # pytype static type analyzer
166
+ .pytype/
167
+
168
+ # Cython debug symbols
169
+ cython_debug/
170
+
171
+ # PyCharm
172
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
173
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
174
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
175
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
176
+ #.idea/
177
+
178
+ # Abstra
179
+ # Abstra is an AI-powered process automation framework.
180
+ # Ignore directories containing user credentials, local state, and settings.
181
+ # Learn more at https://abstra.io/docs
182
+ .abstra/
183
+
184
+ # Visual Studio Code
185
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
188
+ # you could uncomment the following to ignore the entire vscode folder
189
+ # .vscode/
190
+
191
+ # Ruff stuff:
192
+ .ruff_cache/
193
+
194
+ # PyPI configuration file
195
+ .pypirc
196
+
197
+ # Cursor
198
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200
+ # refer to https://docs.cursor.com/context/ignore-files
201
+ .cursorignore
202
+ .cursorindexingignore
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
208
+
209
+ # macOS
210
+ .DS_Store
211
+ **/.DS_Store
212
+
213
+ # SLURM job logs (HPC run outputs — not source)
214
+ logs/
215
+
216
+ # Demo script outputs
217
+ demo_out/
218
+
219
+ # Default download/output directory (settings.output_dir)
220
+ outputs/
221
+
222
+ # Runtime geocode cache written into the test fixture during offline runs
223
+ tests/fixtures/realdata/index/geocode/
@@ -0,0 +1,36 @@
1
+ # Local developer convenience. CI is the enforcement boundary, so a contributor
2
+ # who skips these hooks still cannot merge a violation. mypy is intentionally
3
+ # left to CI only (too slow for the local commit loop).
4
+ repos:
5
+ - repo: https://github.com/astral-sh/ruff-pre-commit
6
+ rev: v0.15.20
7
+ hooks:
8
+ - id: ruff-check
9
+ args: [--fix]
10
+ - id: ruff-format
11
+
12
+ - repo: https://github.com/pre-commit/pre-commit-hooks
13
+ rev: v5.0.0
14
+ hooks:
15
+ - id: trailing-whitespace
16
+ - id: end-of-file-fixer
17
+ - id: check-yaml
18
+ # mkdocs.yml uses mkdocs-material's `!!python/name:` tags, which the
19
+ # safe-loading check-yaml hook can't construct; `mkdocs build --strict`
20
+ # (CI) validates it instead.
21
+ exclude: ^mkdocs\.yml$
22
+ - id: check-toml
23
+ - id: check-added-large-files
24
+ # Tutorial notebooks embed interactive folium maps + plot outputs; the
25
+ # visualize tutorial's recurrence map over the bbox ROI runs ~1.2 MB, so
26
+ # keep a 1.5 MB guard against genuinely large files.
27
+ args: ["--maxkb=1536"]
28
+
29
+ # Keep each tutorial's .py:percent and .ipynb in sync (runs after ruff so any
30
+ # --fix on the .py propagates into the paired notebook).
31
+ - repo: https://github.com/mwouts/jupytext
32
+ rev: v1.19.4
33
+ hooks:
34
+ - id: jupytext
35
+ args: [--sync]
36
+ files: ^examples/.*\.(py|ipynb)$
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,113 @@
1
+ # Changelog
2
+
3
+ All notable changes to EuroFlood are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project aims to
5
+ follow [Semantic Versioning](https://semver.org/) once it reaches a public release.
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+ - **ROI `shape` option**: `floods()`/`hazard()` (and the `floods`/`download`/`hazard` CLI commands via
11
+ `--shape`) take `shape="exact"` (default, the raw admin boundary), `"bbox"` (its bounding rectangle),
12
+ or `"hull"` (its convex hull). Administrative boundaries are legal, not hydrological, shapes — they
13
+ often run down a river (excluding it), are oddly shaped, or split into exclaves; a bbox/hull ROI
14
+ sidesteps that (and collapses a MultiPolygon into one clean shape). Applies to every region input,
15
+ turns `point`+`radius_m` into a bounding square, and composes with `buffer_m` (which then grows the
16
+ chosen shape). Default `"exact"` keeps existing behaviour unchanged.
17
+ - **Tutorials** (`examples/`): a top-level folder of runnable, progressive Jupyter tutorials
18
+ (Quickstart → Discover & filter → Visualize → Download & measure → Hazard → Quantitative
19
+ analysis → CLI & configuration), jupytext-paired (`.py` + `.ipynb`), rendered on the docs
20
+ site (mkdocs-jupyter) and executed as tests — the cheap-path ones offline against a committed
21
+ fixture on every PR, all of them live nightly. Supersedes the old root `demo.py`/`demo.ipynb`.
22
+ - **Notebook/TTY progress bars**: `.download()` shows a transfer bar and the first-query index
23
+ mirror shows activity when running interactively (a Jupyter notebook or a TTY). Toggle with
24
+ `settings.show_progress` / `EUROFLOOD_SHOW_PROGRESS`.
25
+ - **Persistent geocode cache**: resolved place-name geometries are cached on disk
26
+ (`cache_dir/geocode/`), so a repeat `floods("Cologne")` skips the Nominatim round-trip. Toggle
27
+ with `settings.geocode_cache` / `EUROFLOOD_GEOCODE_CACHE`.
28
+ - **Quiet by default**: `import euroflood` no longer leaks structlog / pooch INFO lines to
29
+ stdout — the library is silent unless you call `ef.setup_logging(...)`.
30
+ - **Faster repeat queries**: the index COG is opened once per process and reused (with GDAL's
31
+ in-process block cache), so a repeat `floods()` — and the `.plot()` / `.explore()` /
32
+ `.footprints()` recurrence views, which also read the index — are near-instant (~0.03–0.07s)
33
+ instead of re-opening the remote COG every call.
34
+ - **Publishing** (`euroflood publish`): one-command upload of the built index bundle to
35
+ **Source Cooperative** (the live `/vsicurl` host, via the optional `euroflood[publish]`
36
+ extra) and/or **Zenodo** (citable DOI). The manifest is stamped with the version + public
37
+ URLs, and the hosted index is self-verified after upload. A reusable `verify_published()`
38
+ helper, a `euroflood verify-remote` CLI, and an opt-in `online` test suite check the live
39
+ index end-to-end (manifest, `/vsicurl` COG, a real query) without touching offline CI.
40
+ - **Zero-config remote index**: `DEFAULT_INDEX_BASE_URL` is baked to the published Source
41
+ Cooperative prefix, so a plain `pip install euroflood` reads the index with no setup.
42
+ - `euroflood.__version__` and `euroflood --version`.
43
+ - `RELEASING.md`: the two-track (library → PyPI, index → Source Cooperative / Zenodo)
44
+ release procedure; `release.yml` now fails a release when the git tag ≠ the package version.
45
+ - **Visualization** (optional `euroflood[viz]` extra): a flood-recurrence heatmap
46
+ as the default `FloodFrame.plot()` / `.explore()`; per-event flood extents via
47
+ `.footprints()` (a GeoDataFrame with `extent_km2`); an opt-in downloaded
48
+ depth-map view (`depth=True`, `plot_depth`, `open_depth`, `DepthRaster`); and
49
+ interactive folium maps with hover tooltips. Static via matplotlib, interactive
50
+ via folium.
51
+ - **CLI feedback layer**: a unified `rich` console for result tables, status, and
52
+ progress; global options `-v/--verbose`, `-q/--quiet`, `--json`, `--no-color`;
53
+ clean one-line error messages with per-error-type exit codes (no tracebacks);
54
+ a notebook-friendly `FloodFrame` summary repr.
55
+ - **Documentation**: a Concepts page explaining the index data model; a real
56
+ consumer Getting Started walkthrough; full API reference coverage for the
57
+ consumer API (`floods`, `hazard`, `download`, `FloodFrame`, configuration);
58
+ `CONTRIBUTING.md`, `CITATION.cff`, and this changelog.
59
+
60
+ ### Changed
61
+ - **Leaner `viz` extra.** Removed the unused `mapclassify` dependency from the optional
62
+ `euroflood[viz]` extra, which drops its heavy transitive tail (scikit-learn, scipy, networkx)
63
+ from the install — six fewer packages. `mapclassify` only serves geopandas' choropleth
64
+ *classification* schemes, which EuroFlood never uses (it draws folium via direct `GeoJson`/
65
+ `ImageOverlay`), so `.plot()` / `.explore()` are unchanged.
66
+ - **Documentation overhaul.** A cohesive azure "water" theme (custom palette + `extra.css`, logo +
67
+ favicon, light/dark toggle); a real landing page (hero flood map, feature cards, CTAs, badges) that
68
+ replaces the wall of text; **real Zutphen figures** with a grayscale basemap ("flooding in front of a
69
+ map") generated by `scripts/make_doc_images.py`, replacing the placeholder images; a **lean 5-section
70
+ IA** (Home · Get started · Tutorials · Concepts · API reference) that folds the redundant
71
+ Visualization/Cookbook/Output pages into the tutorials/reference and moves the internal Vision &
72
+ Related-datasets notes off the site; a tutorials **gallery** with thumbnails; and the section renamed
73
+ "Reference" → "API reference". Fixes the raw-`.py` tutorial links (the `docs/tutorials → examples`
74
+ symlink no longer leaks `.py`/run artifacts, via `exclude_docs`) and the inconsistent notebook H1s.
75
+ Docstring cross-references were converted from raw reStructuredText roles (`:func:`/`:class:`, which
76
+ rendered literally under the Google docstring style) to plain code spans, so the API reference reads
77
+ cleanly.
78
+ - **`plot(basemap=True)` fix.** The contextily basemap was drawn *over* the flood raster (muting the
79
+ overlay); it now draws behind it (`zorder=-1`), so the flood reads clearly against the map.
80
+ - **Tutorials & docs now headline Zutphen** (on the IJssel, NL) instead of Cologne/Valencia —
81
+ its recurrent river flooding makes a richer example and motivates `shape="bbox"` (its gemeente
82
+ boundary follows the river). The offline test fixture was regenerated for Zutphen (with an
83
+ appended OSM municipality boundary so the offline geocoder resolves it), tutorial 02 gained an
84
+ executed `shape="bbox"` beat, and a latent `point=(lat, lon)` argument-order slip in the region
85
+ examples was fixed.
86
+ - **Parallel downloads**: `.download()` now fetches source rasters concurrently
87
+ (up to `settings.max_workers_dl`, default 8) instead of one at a time — a roughly
88
+ N× faster wall-clock for multi-event historic catalogues and multi-tile hazard
89
+ layers. Output files, paths, and cache-hit skipping are unchanged; a per-file
90
+ step bar replaces the byte bar for the library (notebook/TTY) path, while the CLI
91
+ keeps its byte bar via `on_bytes`.
92
+ - **Fewer per-call rebuilds**: the DuckDB connection (dictionary + events lookups)
93
+ and the ~14 MB NUTS boundary dataset (offline `local` geocoder) are now cached
94
+ per process instead of being reopened/reloaded on every query — the same
95
+ "reuse, don't re-init" fix already applied to the index COG. Repeat queries and
96
+ `local`-backend batches are correspondingly faster.
97
+ - **Faster hazard stats and streaming reads**: `hazard(...).stats()` / `.summary()`
98
+ read each depth raster once (was twice, to inspect the CRS first), and streaming
99
+ `/vsicurl` hazard reads now run under the same GDAL env as the index COG.
100
+ - `import euroflood` no longer eagerly imports the producer pipelines
101
+ (`ExportPipeline`, `IngestionPipeline`) or their scraper/BeautifulSoup stack —
102
+ they resolve lazily on first use, so the consumer import is lighter.
103
+ - `Settings` fields are now self-documenting via `Field(description=...)` — visible
104
+ in `help()`, IDE tooltips, and the Configuration reference.
105
+ - Replaced `tqdm` with `rich` for progress; `structlog` still owns machine/JSON
106
+ logs on stderr (HPC-friendly), while user-facing output goes to stdout.
107
+
108
+ ### Removed
109
+ - Stale `readme.org` (superseded by `README.md`).
110
+
111
+ ### Fixed
112
+ - Corrected stale docstrings (geocoder default backend, the `extract` CLI verb,
113
+ the legacy `ExtractionPipeline` dictionary format).
@@ -0,0 +1,41 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use EuroFlood, please cite this software and the underlying dataset."
3
+ title: "EuroFlood: query Europe's satellite flood-depth maps by place and time"
4
+ abstract: >-
5
+ A lightweight, cloud-native Python tool that turns the JRC / Copernicus
6
+ CEMS-EFAS Satellite-Derived Flood Depth Maps for Europe into a queryable index:
7
+ discover which flood events touched a region (and when) and download only the
8
+ depth rasters you need.
9
+ type: software
10
+ version: "0.1.0"
11
+ date-released: "2026-07-08"
12
+ authors:
13
+ - family-names: Hackl
14
+ given-names: Jürgen
15
+ orcid: "https://orcid.org/0000-0002-8849-5751"
16
+ affiliation: "Princeton University, Complex Infrastructure Systems Group"
17
+ license: MIT
18
+ repository-code: "https://github.com/cisgroup/euroflood"
19
+ url: "https://cisgroup.github.io/euroflood/"
20
+ keywords:
21
+ - flood
22
+ - flood depth
23
+ - CEMS-EFAS
24
+ - GLOFAS
25
+ - Copernicus
26
+ - Sentinel-1
27
+ - geospatial
28
+ - remote sensing
29
+ references:
30
+ - type: data
31
+ title: "Satellite-Derived Flood Depth Maps for Europe"
32
+ authors:
33
+ - family-names: Betterle
34
+ given-names: Andrea
35
+ - family-names: Salamon
36
+ given-names: Peter
37
+ year: 2025
38
+ publisher:
39
+ name: "European Commission, Joint Research Centre (JRC) / Copernicus EMS"
40
+ url: "https://data.jrc.ec.europa.eu/dataset/0bc96690-b89c-4909-9166-c2c322a20130"
41
+ notes: "Licensed CC-BY-4.0."