Caravan — API reference#
Caravan large-sample hydrology subpackage — earthlens.caravan.
Background, usage and the available extensions are covered under the other
pages in this section; this page is the rendered API.
earthlens.caravan
#
Caravan large-sample hydrology backend.
Caravan is an open community dataset of per-catchment daily streamflow,
ERA5-Land meteorological forcing, static catchment attributes and basin
polygons, published as static archives on Zenodo. This subpackage fetches
those archives and assembles the requested catchments into a
:class:pandas.DataFrame.
Its headline value is the GRDC-Caravan extension: the Global Runoff Data Centre's raw portal has no API and forbids redistribution, but its openly licensed stations are published here under CC-BY-4.0, so this is the legal, scriptable route to open GRDC discharge.
Caravan is a versioned historical archive, not a live feed — releases land
every 4–12 months and the series lag the present by a year or more. For current
discharge use earthlens.usgs_water (US near-real-time) or GloFAS via
earthlens.ecmwf.
Public surface:
- :class:
Caravan— the backend itself. - :class:
Catalog— the bundled extension / variable catalog, plus :class:Extension, :class:Version, :class:ArchiveFile, :class:Sourceand :class:Variablerows. - :data:
CATALOG_PATH/ :func:clear_catalog_cache— the catalog file and its parse-cache control.
ArchiveFile
#
Bases: BaseModel
One downloadable Zenodo artifact and how it is packaged.
Attributes:
| Name | Type | Description |
|---|---|---|
record |
int
|
The pinned Zenodo version record id the file belongs to.
Held per file because |
name |
str
|
The file name on the record. |
size |
int
|
Size in bytes, as reported by the Zenodo REST API. |
md5 |
str
|
The file's md5 checksum (bare hex, no |
archive_format |
ArchiveFormat
|
|
root_prefix |
str | None
|
The directory every member sits under inside the archive,
or |
Examples:
- The format is what decides whether a fetch is cheap:
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
is_range_readable
property
#
Whether a member can be read without downloading the whole file.
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
|
url
property
#
The Zenodo REST content URL this file is served from.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
|
Examples:
- The URL is composed from the pinned record and file name:
Caravan
#
Bases: AbstractDataSource
Fetch Caravan per-catchment daily hydrology from static Zenodo archives.
Attributes:
| Name | Type | Description |
|---|---|---|
OUTPUT_KIND |
OutputKind
|
|
Examples:
- Construction is offline; the catalog resolves the pinned release:
>>> from earthlens.caravan import Caravan >>> src = Caravan( ... start="2000-01-01", end="2000-12-31", ... variables=["streamflow"], ... lat_lim=[-35.0, -25.0], lon_lim=[15.0, 25.0], ... dataset="grdc", ... ) >>> src.OUTPUT_KIND 'tabular' >>> src.archive_file.archive_format 'zip' >>> src.release.n_catchments 5356
Source code in libs/providers/ocean/src/earthlens/caravan/backend.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | |
transfer_stats
property
#
Requests issued and megabytes transferred for this request.
The public way to check what a fetch actually cost, which is the whole
premise of the range-read design. (0, 0.0) before anything is read,
and for the tar transport, which transfers nothing at read time.
Returns:
| Type | Description |
|---|---|
tuple[int, float]
|
tuple[int, float]: |
__init__(start, end, variables, lat_lim, lon_lim, temporal_resolution='daily', fmt='%Y-%m-%d', path=None, *, dataset='grdc', version=None, gauge_ids=None, country=None, timeseries_format='csv', with_attributes=False, with_geometry=False, allow_full_download=False, write_table=True, client=None, min_interval=DEFAULT_MIN_INTERVAL, cache_root=None, catalog=None)
#
Build a Caravan request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
str
|
Inclusive start date of the window. |
required |
end
|
str
|
Inclusive end date of the window. |
required |
variables
|
dict[str, list[str]] | list[str]
|
Variable names to return — friendly catalog names
( |
required |
lat_lim
|
list[float]
|
|
required |
lon_lim
|
list[float]
|
|
required |
temporal_resolution
|
str
|
Recorded as the resolution label; Caravan is daily throughout. |
'daily'
|
fmt
|
str
|
|
'%Y-%m-%d'
|
path
|
Path | str | None
|
Output directory for the written table. |
None
|
dataset
|
str
|
The extension key — |
'grdc'
|
version
|
str | None
|
A specific release of that extension. |
None
|
gauge_ids
|
list[str] | None
|
Explicit catchment ids. Note GRDC's ids carry an
uppercase prefix ( |
None
|
country
|
str | None
|
Restrict to one country. Matched case-insensitively
against the full English name in |
None
|
timeseries_format
|
str
|
Only |
'csv'
|
with_attributes
|
bool
|
Merge the static catchment attributes onto every row. |
False
|
with_geometry
|
bool
|
Attach the basin polygons, returned alongside the
frame on :attr: |
False
|
allow_full_download
|
bool
|
Permit a release that can only be fetched by
downloading the whole multi-gigabyte archive. Required for
|
False
|
write_table
|
bool
|
Write the assembled frame to |
True
|
client
|
HttpClient | None
|
Transport to read through; injectable for tests. When
|
None
|
min_interval
|
float
|
Minimum seconds between requests to Zenodo, which
rate-limits anonymous callers. Only used when |
DEFAULT_MIN_INTERVAL
|
cache_root
|
Path | None
|
Cache directory for downloaded archives. |
None
|
catalog
|
Catalog | None
|
A pre-built catalog; the bundled one when |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
NotImplementedError
|
If |
Source code in libs/providers/ocean/src/earthlens/caravan/backend.py
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | |
close()
#
Release the opened archive and the HTTP session behind it.
download() deliberately does not call this: the archive carries the
transfer statistics a caller may want to inspect afterwards. Use the
backend as a context manager, or call this when done.
Source code in libs/providers/ocean/src/earthlens/caravan/backend.py
download(progress_bar=True, limit=None)
#
Fetch the selected catchments and return them as one long frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
progress_bar
|
bool
|
Accepted for signature parity with the other backends. Members are read individually and the cost is dominated by the archive index, so no bar is shown. |
True
|
limit
|
int | None
|
Cap on the total rows returned. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
pandas.DataFrame: |
Raises:
| Type | Description |
|---|---|
ValueError
|
On an unbounded request, an unknown catchment id, an
unknown variable, or a release needing |
Source code in libs/providers/ocean/src/earthlens/caravan/backend.py
Catalog
#
Bases: AbstractCatalog
Extension and variable catalog for the Caravan backend.
Reads the bundled caravan_data_catalog.yaml (shipped as package data) and
exposes its extensions: block as :class:Extension rows keyed by the
dataset= name, plus the shared variables: block as :class:Variable
rows. Instantiate with no arguments (Catalog()).
Attributes:
| Name | Type | Description |
|---|---|---|
extensions |
dict[str, Extension]
|
Map from extension key to its :class: |
variables |
dict[str, Variable]
|
Map from friendly variable name to its :class: |
Examples:
- Look up an extension and the archive it would read:
>>> from earthlens.caravan import Catalog >>> cat = Catalog() >>> sorted(cat.extensions) ['base', 'czechia', 'denmark', 'germany', 'grdc', 'israel', 'spain'] >>> archive = cat.get_extension("denmark").resolve_version().file_for("csv") >>> archive.name 'Caravan_extension_DK.zip' >>> archive.is_range_readable True
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | |
available_extensions
property
#
The sorted list of extension keys.
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: Every catalog key, sorted. |
extensions
property
#
The extension map — alias for the base :attr:datasets field.
Returns:
| Type | Description |
|---|---|
dict[str, Extension]
|
dict[str, Extension]: The same mapping stored in :attr: |
get_catalog()
#
Return the extension map (satisfies the abstract contract).
Returns:
| Type | Description |
|---|---|
dict[str, Extension]
|
dict[str, Extension]: Same object as :attr: |
get_extension(key)
#
Resolve an extension key to its row.
Thin wrapper over the inherited :meth:get_dataset, which raises a
ValueError with a did-you-mean hint on an unknown key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
An extension key ( |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Extension |
Extension
|
The matching catalog row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
get_variable(dataset_key, variable_name)
#
Resolve one variable, checking it exists in the extension.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset_key
|
str
|
The extension the variable is requested against. |
required |
variable_name
|
str
|
A friendly variable name, or the real archive column name (which passes through when it matches a known row). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Variable |
Variable
|
The matching variable row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the variable is unknown, or is restricted to source
datasets the extension does not contain (e.g. asking
Caravan-DE's |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
load(catalog_path=None)
classmethod
#
Read the Caravan catalog from disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
catalog_path
|
Path | None
|
Path to the catalog YAML. Defaults to the
module-level :data: |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Catalog |
Catalog
|
A fully-populated catalog. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a required block is missing or a row fails validation. |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
Extension
#
Bases: BaseModel
One Caravan extension — a Zenodo record set with its releases.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
The catalog key used as |
title |
str
|
The record's published title. |
concept_doi |
str
|
The moving concept DOI. Recorded so the refresh tool can discover newer versions; never used to fetch. |
concept_doi_csv |
str
|
The second concept DOI, when a row's CSV and NetCDF
archives live under different Zenodo concepts. Only |
license |
str
|
SPDX-ish licence id (every current row is |
attribution |
str
|
The citation obligation the licence carries. |
license_file |
str
|
Path to the in-archive licence text. |
sources |
dict[str, Source]
|
Archive source directory to its :class: |
default_version |
str
|
Key into :attr: |
versions |
dict[str, Version]
|
Version key to its :class: |
Examples:
- The default release is the one a bare request resolves to:
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | |
source_names
property
#
The archive source directory names, sorted.
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: e.g. |
resolve_version(version=None)
#
Return the requested release, or the row's default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
version
|
str | None
|
A key into :attr: |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Version |
Version
|
The matching release. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
- An unknown release names the valid ones:
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
Source
#
Bases: BaseModel
One source dataset directory inside an archive.
An extension is a Zenodo record; a source is a folder within it. Every
community extension has exactly one, but base bundles seven — CAMELS-US,
CAMELS-AUS, CAMELS-BR, CAMELS-CL, CAMELS-GB, HYSETS and LamaH-CE — which is
why they are not separately downloadable and never appear as their own
catalog rows.
Attributes:
| Name | Type | Description |
|---|---|---|
n_catchments |
int
|
Catchments this source contributes. |
name |
str
|
Human-readable name of the upstream dataset. |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
Variable
#
Bases: BaseModel
One requestable variable and the archive column it maps to.
The friendly name is the parent key in the catalog's variables: block and
is also stored here, so a resolved row is self-describing.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The friendly request name ( |
column |
str
|
The real column name in a current-era archive
( |
legacy_column |
str
|
The column name in a |
units |
str
|
The reporting units ( |
sources |
list[str]
|
Archive source directories this variable exists in. Empty (the
default) means every source has it; |
description |
str
|
One-line human-readable summary. |
Examples:
- The friendly name and the archive column differ for precipitation:
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
column_for(column_set)
#
Return the column name this variable has in column_set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
column_set
|
ColumnSet
|
The archive's column-set variant. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
:attr: |
Examples:
- PET is the one variable whose name changed between eras:
>>> from earthlens.caravan import Variable >>> pet = Variable( ... name="potential_evaporation", ... column="potential_evaporation_sum_ERA5_LAND", ... legacy_column="potential_evaporation_sum", ... ) >>> pet.column_for("current") 'potential_evaporation_sum_ERA5_LAND' >>> pet.column_for("legacy") 'potential_evaporation_sum'
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
Version
#
Bases: BaseModel
One pinned, reproducible release of an extension.
Attributes:
| Name | Type | Description |
|---|---|---|
doi |
str
|
The version DOI (never the concept DOI, which moves). When a
release spans two records - |
release_date |
str
|
Zenodo publication date, |
data_period |
tuple[int, int] | None
|
|
n_catchments |
int
|
Catchments in this release. |
n_catchments_verified |
bool
|
Whether the count was measured from the archive
index or only derived from the changelog. |
column_set |
ColumnSet
|
Which timeseries column-set variant this release ships. |
files |
dict[str, ArchiveFile]
|
Per timeseries format, the :class: |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
file_for(timeseries_format)
#
Return the archive holding this release's timeseries_format data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeseries_format
|
TimeseriesFormat
|
|
required |
Returns:
| Name | Type | Description |
|---|---|---|
ArchiveFile |
ArchiveFile
|
The matching file descriptor. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the release publishes no such format. |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
clear_catalog_cache()
#
Empty the module-level catalog parse cache.
Useful when the catalog is rewritten on disk and a re-parse is wanted
immediately. Production callers do not need this — the cache key includes
the file's st_mtime_ns, so any real edit invalidates the entry on its own.
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
earthlens.caravan.backend
#
Backend that fetches Caravan large-sample hydrology from Zenodo.
Caravan(AbstractDataSource) assembles per-catchment daily streamflow plus
ERA5-Land meteorological forcing into a long :class:pandas.DataFrame, so
OUTPUT_KIND = "tabular" and the :class:earthlens.earthlens.EarthLens facade
rejects an aggregate= argument.
A request names an extension (dataset="grdc"), a set of catchments, a time
window, and the variables wanted. Catchments are selected explicitly
(gauge_ids=[...]), by bounding box, or by country= — the last two resolved
against the archive's own attributes_other_<source>.csv centroid table. An
unbounded request is refused rather than silently pulling every catchment.
Nothing is downloaded for the common case. Every extension ships as a ZIP,
which is read in place over HTTP Range requests: one catchment out of the
8.84 GB GRDC archive costs about 3 MB. The exception is base at v1.6, a
24.8–29.0 GB .tar.gz that cannot be seeked; that row demands
allow_full_download=True, and version="1.2" offers a range-readable
alternative at the cost of being a materially older and smaller dataset.
Caravan is a versioned historical archive, not a live feed. Releases land
every 4–12 months and the series lag the present by a year or more, so use
earthlens.usgs_water (US near-real-time) or GloFAS via earthlens.ecmwf when
current discharge is what is needed.
Caravan
#
Bases: AbstractDataSource
Fetch Caravan per-catchment daily hydrology from static Zenodo archives.
Attributes:
| Name | Type | Description |
|---|---|---|
OUTPUT_KIND |
OutputKind
|
|
Examples:
- Construction is offline; the catalog resolves the pinned release:
>>> from earthlens.caravan import Caravan >>> src = Caravan( ... start="2000-01-01", end="2000-12-31", ... variables=["streamflow"], ... lat_lim=[-35.0, -25.0], lon_lim=[15.0, 25.0], ... dataset="grdc", ... ) >>> src.OUTPUT_KIND 'tabular' >>> src.archive_file.archive_format 'zip' >>> src.release.n_catchments 5356
Source code in libs/providers/ocean/src/earthlens/caravan/backend.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | |
transfer_stats
property
#
Requests issued and megabytes transferred for this request.
The public way to check what a fetch actually cost, which is the whole
premise of the range-read design. (0, 0.0) before anything is read,
and for the tar transport, which transfers nothing at read time.
Returns:
| Type | Description |
|---|---|
tuple[int, float]
|
tuple[int, float]: |
__init__(start, end, variables, lat_lim, lon_lim, temporal_resolution='daily', fmt='%Y-%m-%d', path=None, *, dataset='grdc', version=None, gauge_ids=None, country=None, timeseries_format='csv', with_attributes=False, with_geometry=False, allow_full_download=False, write_table=True, client=None, min_interval=DEFAULT_MIN_INTERVAL, cache_root=None, catalog=None)
#
Build a Caravan request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start
|
str
|
Inclusive start date of the window. |
required |
end
|
str
|
Inclusive end date of the window. |
required |
variables
|
dict[str, list[str]] | list[str]
|
Variable names to return — friendly catalog names
( |
required |
lat_lim
|
list[float]
|
|
required |
lon_lim
|
list[float]
|
|
required |
temporal_resolution
|
str
|
Recorded as the resolution label; Caravan is daily throughout. |
'daily'
|
fmt
|
str
|
|
'%Y-%m-%d'
|
path
|
Path | str | None
|
Output directory for the written table. |
None
|
dataset
|
str
|
The extension key — |
'grdc'
|
version
|
str | None
|
A specific release of that extension. |
None
|
gauge_ids
|
list[str] | None
|
Explicit catchment ids. Note GRDC's ids carry an
uppercase prefix ( |
None
|
country
|
str | None
|
Restrict to one country. Matched case-insensitively
against the full English name in |
None
|
timeseries_format
|
str
|
Only |
'csv'
|
with_attributes
|
bool
|
Merge the static catchment attributes onto every row. |
False
|
with_geometry
|
bool
|
Attach the basin polygons, returned alongside the
frame on :attr: |
False
|
allow_full_download
|
bool
|
Permit a release that can only be fetched by
downloading the whole multi-gigabyte archive. Required for
|
False
|
write_table
|
bool
|
Write the assembled frame to |
True
|
client
|
HttpClient | None
|
Transport to read through; injectable for tests. When
|
None
|
min_interval
|
float
|
Minimum seconds between requests to Zenodo, which
rate-limits anonymous callers. Only used when |
DEFAULT_MIN_INTERVAL
|
cache_root
|
Path | None
|
Cache directory for downloaded archives. |
None
|
catalog
|
Catalog | None
|
A pre-built catalog; the bundled one when |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
NotImplementedError
|
If |
Source code in libs/providers/ocean/src/earthlens/caravan/backend.py
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | |
close()
#
Release the opened archive and the HTTP session behind it.
download() deliberately does not call this: the archive carries the
transfer statistics a caller may want to inspect afterwards. Use the
backend as a context manager, or call this when done.
Source code in libs/providers/ocean/src/earthlens/caravan/backend.py
download(progress_bar=True, limit=None)
#
Fetch the selected catchments and return them as one long frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
progress_bar
|
bool
|
Accepted for signature parity with the other backends. Members are read individually and the cost is dominated by the archive index, so no bar is shown. |
True
|
limit
|
int | None
|
Cap on the total rows returned. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
pandas.DataFrame: |
Raises:
| Type | Description |
|---|---|
ValueError
|
On an unbounded request, an unknown catchment id, an
unknown variable, or a release needing |
Source code in libs/providers/ocean/src/earthlens/caravan/backend.py
earthlens.caravan.catalog
#
Extension and variable catalog for the Caravan backend.
Caravan publishes per-catchment daily streamflow plus ERA5-Land forcing as
static archives on Zenodo. This module is the bridge between the friendly
request vocabulary (dataset="grdc", variables=["streamflow"]) and what the
archives actually contain: a pinned Zenodo record, the file to read, how that
file is packaged, and the real column names inside it.
Three shapes matter and are modelled separately:
- :class:
Extension— one Zenodo record set (base,grdc,germany,denmark,israel), carrying its licence, itssources:map, and one or more :class:Versionentries. - :class:
Version— a specific, reproducible release of an extension. Pinning a version rather than the moving concept DOI is what makes a request repeatable, and it is what carriesdata_period/n_catchments/column_set.basehas two — the current1.6and the range-readable1.2— so the cheap path is data, not a special case in code. - :class:
ArchiveFile— one downloadable artifact with its size, md5, and crucially itsarchive_format. Azipis read in place over HTTP Range requests; atar.gzis a single gzip stream that must be fetched whole.
:data:CATALOG_PATH is the path to the bundled YAML.
ArchiveFile
#
Bases: BaseModel
One downloadable Zenodo artifact and how it is packaged.
Attributes:
| Name | Type | Description |
|---|---|---|
record |
int
|
The pinned Zenodo version record id the file belongs to.
Held per file because |
name |
str
|
The file name on the record. |
size |
int
|
Size in bytes, as reported by the Zenodo REST API. |
md5 |
str
|
The file's md5 checksum (bare hex, no |
archive_format |
ArchiveFormat
|
|
root_prefix |
str | None
|
The directory every member sits under inside the archive,
or |
Examples:
- The format is what decides whether a fetch is cheap:
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
is_range_readable
property
#
Whether a member can be read without downloading the whole file.
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
|
url
property
#
The Zenodo REST content URL this file is served from.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
|
Examples:
- The URL is composed from the pinned record and file name:
Catalog
#
Bases: AbstractCatalog
Extension and variable catalog for the Caravan backend.
Reads the bundled caravan_data_catalog.yaml (shipped as package data) and
exposes its extensions: block as :class:Extension rows keyed by the
dataset= name, plus the shared variables: block as :class:Variable
rows. Instantiate with no arguments (Catalog()).
Attributes:
| Name | Type | Description |
|---|---|---|
extensions |
dict[str, Extension]
|
Map from extension key to its :class: |
variables |
dict[str, Variable]
|
Map from friendly variable name to its :class: |
Examples:
- Look up an extension and the archive it would read:
>>> from earthlens.caravan import Catalog >>> cat = Catalog() >>> sorted(cat.extensions) ['base', 'czechia', 'denmark', 'germany', 'grdc', 'israel', 'spain'] >>> archive = cat.get_extension("denmark").resolve_version().file_for("csv") >>> archive.name 'Caravan_extension_DK.zip' >>> archive.is_range_readable True
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | |
available_extensions
property
#
The sorted list of extension keys.
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: Every catalog key, sorted. |
extensions
property
#
The extension map — alias for the base :attr:datasets field.
Returns:
| Type | Description |
|---|---|
dict[str, Extension]
|
dict[str, Extension]: The same mapping stored in :attr: |
get_catalog()
#
Return the extension map (satisfies the abstract contract).
Returns:
| Type | Description |
|---|---|
dict[str, Extension]
|
dict[str, Extension]: Same object as :attr: |
get_extension(key)
#
Resolve an extension key to its row.
Thin wrapper over the inherited :meth:get_dataset, which raises a
ValueError with a did-you-mean hint on an unknown key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
An extension key ( |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Extension |
Extension
|
The matching catalog row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
get_variable(dataset_key, variable_name)
#
Resolve one variable, checking it exists in the extension.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset_key
|
str
|
The extension the variable is requested against. |
required |
variable_name
|
str
|
A friendly variable name, or the real archive column name (which passes through when it matches a known row). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Variable |
Variable
|
The matching variable row. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the variable is unknown, or is restricted to source
datasets the extension does not contain (e.g. asking
Caravan-DE's |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
load(catalog_path=None)
classmethod
#
Read the Caravan catalog from disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
catalog_path
|
Path | None
|
Path to the catalog YAML. Defaults to the
module-level :data: |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Catalog |
Catalog
|
A fully-populated catalog. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a required block is missing or a row fails validation. |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
Extension
#
Bases: BaseModel
One Caravan extension — a Zenodo record set with its releases.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
The catalog key used as |
title |
str
|
The record's published title. |
concept_doi |
str
|
The moving concept DOI. Recorded so the refresh tool can discover newer versions; never used to fetch. |
concept_doi_csv |
str
|
The second concept DOI, when a row's CSV and NetCDF
archives live under different Zenodo concepts. Only |
license |
str
|
SPDX-ish licence id (every current row is |
attribution |
str
|
The citation obligation the licence carries. |
license_file |
str
|
Path to the in-archive licence text. |
sources |
dict[str, Source]
|
Archive source directory to its :class: |
default_version |
str
|
Key into :attr: |
versions |
dict[str, Version]
|
Version key to its :class: |
Examples:
- The default release is the one a bare request resolves to:
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | |
source_names
property
#
The archive source directory names, sorted.
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: e.g. |
resolve_version(version=None)
#
Return the requested release, or the row's default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
version
|
str | None
|
A key into :attr: |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Version |
Version
|
The matching release. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
- An unknown release names the valid ones:
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
Source
#
Bases: BaseModel
One source dataset directory inside an archive.
An extension is a Zenodo record; a source is a folder within it. Every
community extension has exactly one, but base bundles seven — CAMELS-US,
CAMELS-AUS, CAMELS-BR, CAMELS-CL, CAMELS-GB, HYSETS and LamaH-CE — which is
why they are not separately downloadable and never appear as their own
catalog rows.
Attributes:
| Name | Type | Description |
|---|---|---|
n_catchments |
int
|
Catchments this source contributes. |
name |
str
|
Human-readable name of the upstream dataset. |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
Variable
#
Bases: BaseModel
One requestable variable and the archive column it maps to.
The friendly name is the parent key in the catalog's variables: block and
is also stored here, so a resolved row is self-describing.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The friendly request name ( |
column |
str
|
The real column name in a current-era archive
( |
legacy_column |
str
|
The column name in a |
units |
str
|
The reporting units ( |
sources |
list[str]
|
Archive source directories this variable exists in. Empty (the
default) means every source has it; |
description |
str
|
One-line human-readable summary. |
Examples:
- The friendly name and the archive column differ for precipitation:
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
column_for(column_set)
#
Return the column name this variable has in column_set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
column_set
|
ColumnSet
|
The archive's column-set variant. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
:attr: |
Examples:
- PET is the one variable whose name changed between eras:
>>> from earthlens.caravan import Variable >>> pet = Variable( ... name="potential_evaporation", ... column="potential_evaporation_sum_ERA5_LAND", ... legacy_column="potential_evaporation_sum", ... ) >>> pet.column_for("current") 'potential_evaporation_sum_ERA5_LAND' >>> pet.column_for("legacy") 'potential_evaporation_sum'
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
Version
#
Bases: BaseModel
One pinned, reproducible release of an extension.
Attributes:
| Name | Type | Description |
|---|---|---|
doi |
str
|
The version DOI (never the concept DOI, which moves). When a
release spans two records - |
release_date |
str
|
Zenodo publication date, |
data_period |
tuple[int, int] | None
|
|
n_catchments |
int
|
Catchments in this release. |
n_catchments_verified |
bool
|
Whether the count was measured from the archive
index or only derived from the changelog. |
column_set |
ColumnSet
|
Which timeseries column-set variant this release ships. |
files |
dict[str, ArchiveFile]
|
Per timeseries format, the :class: |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
file_for(timeseries_format)
#
Return the archive holding this release's timeseries_format data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeseries_format
|
TimeseriesFormat
|
|
required |
Returns:
| Name | Type | Description |
|---|---|---|
ArchiveFile |
ArchiveFile
|
The matching file descriptor. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the release publishes no such format. |
Source code in libs/providers/ocean/src/earthlens/caravan/catalog.py
clear_catalog_cache()
#
Empty the module-level catalog parse cache.
Useful when the catalog is rewritten on disk and a re-parse is wanted
immediately. Production callers do not need this — the cache key includes
the file's st_mtime_ns, so any real edit invalidates the entry on its own.