usdata 0.26.0__tar.gz → 0.27.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.
- {usdata-0.26.0 → usdata-0.27.0}/PKG-INFO +11 -10
- {usdata-0.26.0 → usdata-0.27.0}/README.md +9 -8
- {usdata-0.26.0 → usdata-0.27.0}/pyproject.toml +2 -2
- {usdata-0.26.0 → usdata-0.27.0}/pyproject.toml.orig +2 -2
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/_fetch.py +70 -26
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/_grib.py +19 -6
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/_radar.py +3 -2
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/data/registry.yaml +58 -50
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/gfs.py +1 -1
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/hrrr.py +1 -1
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/nbm.py +1 -1
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/rap.py +1 -1
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/pull.py +40 -20
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/readers.py +150 -125
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/__init__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/__main__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/_aqs.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/_files.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/_hurdat2.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/_netcdf.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/_progress.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cache.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cache_ops.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cite.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cli/__init__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cli/app.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cli/cache.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cli/cite.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cli/doctor.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cli/inspect.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/cli/progress.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/data/nexrad_sites.csv +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/data/places.csv +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/data/places.sources.json +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/doctor.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/inspect.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/manifest.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/mirror.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/models.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/protocols/__init__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/protocols/erddap.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/protocols/http.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/protocols/listing.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/protocols/s3.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/provenance.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/__init__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/base.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/credentials.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/epa/__init__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/epa/aqs.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/fema/__init__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/fema/declarations.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/http.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/__init__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/coastwatch.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/coops.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/ghcnd.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/glm.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/goes.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/grib_index.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/gsom.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/gsoy.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/hurdat2.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/ibtracs.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/lcd.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/mrms.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/nexrad.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/nexrad_level3.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/normals.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/nws_vtec.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/sites.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/spc.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/noaa/storm_events.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/params.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/usgs/__init__.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/usgs/daily.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/providers/usgs/earthquakes.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/py.typed +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/query.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/registry.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/selection.py +0 -0
- {usdata-0.26.0 → usdata-0.27.0}/src/usdata/testing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: usdata
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.0
|
|
4
4
|
Summary: Unified Python SDK and CLI for discovering, fetching, and tracking provenance of U.S. public scientific data
|
|
5
5
|
Keywords: noaa,usgs,open-data,scientific-data,provenance,reproducible-research,weather,climate,meteorology
|
|
6
6
|
Author: Jake Van Slyke
|
|
@@ -34,7 +34,7 @@ Requires-Python: >=3.11
|
|
|
34
34
|
Project-URL: Homepage, https://usdata.dev/
|
|
35
35
|
Project-URL: Documentation, https://docs.usdata.dev/
|
|
36
36
|
Project-URL: Repository, https://github.com/jakeryderv/usdata
|
|
37
|
-
Project-URL: Examples, https://usdata.dev/
|
|
37
|
+
Project-URL: Examples, https://usdata.dev/studies/
|
|
38
38
|
Project-URL: Changelog, https://github.com/jakeryderv/usdata/blob/main/CHANGELOG.md
|
|
39
39
|
Project-URL: Issues, https://github.com/jakeryderv/usdata/issues
|
|
40
40
|
Provides-Extra: grib
|
|
@@ -55,12 +55,13 @@ Description-Content-Type: text/markdown
|
|
|
55
55
|
[](https://usdata.dev/)
|
|
56
56
|
|
|
57
57
|
Reproducible acquisition of U.S. public scientific data. One Python SDK and
|
|
58
|
-
CLI discovers curated
|
|
59
|
-
record of every input: a manifest names them,
|
|
60
|
-
and the record of what was fetched is what a
|
|
61
|
-
stays in pandas and xarray; usdata only
|
|
62
|
-
one agency publishes, that agency's own
|
|
63
|
-
|
|
58
|
+
CLI discovers curated datasets from agencies such as NOAA, USGS, and EPA,
|
|
59
|
+
fetches their files, and keeps a record of every input: a manifest names them,
|
|
60
|
+
a lockfile pins them by checksum, and the record of what was fetched is what a
|
|
61
|
+
methods section cites. Analysis stays in pandas and xarray; usdata only
|
|
62
|
+
acquires. If you need every product one agency publishes, that agency's own
|
|
63
|
+
library is the better tool; usdata is for pinning inputs across sources and
|
|
64
|
+
proving later that they have not changed.
|
|
64
65
|
|
|
65
66
|
```sh
|
|
66
67
|
pip install "usdata[pandas]"
|
|
@@ -108,9 +109,9 @@ breaking changes.
|
|
|
108
109
|
|
|
109
110
|
| | |
|
|
110
111
|
| --- | --- |
|
|
111
|
-
| [usdata.dev](https://usdata.dev/) | What it is for: the [dataset browser](https://usdata.dev/datasets/) and [worked examples](https://usdata.dev/
|
|
112
|
+
| [usdata.dev](https://usdata.dev/) | What it is for: the [dataset browser](https://usdata.dev/datasets/) and [worked examples](https://usdata.dev/studies/) with saved results |
|
|
112
113
|
| [docs.usdata.dev](https://docs.usdata.dev/) | How to use it: [install](https://docs.usdata.dev/install/), [getting started](https://docs.usdata.dev/getting-started/), guides, dataset notes, and reference |
|
|
113
|
-
| [Severe-weather case study](https://usdata.dev/
|
|
114
|
+
| [Severe-weather case study](https://usdata.dev/studies/severe-weather-case-study/) | One tornado, six sources, one manifest and lockfile, ending in a citation |
|
|
114
115
|
|
|
115
116
|
Twenty-seven datasets are available today and nineteen more are planned, grouped
|
|
116
117
|
by agency and product family in the [catalog](docs/providers/README.md).
|
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
[](https://usdata.dev/)
|
|
11
11
|
|
|
12
12
|
Reproducible acquisition of U.S. public scientific data. One Python SDK and
|
|
13
|
-
CLI discovers curated
|
|
14
|
-
record of every input: a manifest names them,
|
|
15
|
-
and the record of what was fetched is what a
|
|
16
|
-
stays in pandas and xarray; usdata only
|
|
17
|
-
one agency publishes, that agency's own
|
|
18
|
-
|
|
13
|
+
CLI discovers curated datasets from agencies such as NOAA, USGS, and EPA,
|
|
14
|
+
fetches their files, and keeps a record of every input: a manifest names them,
|
|
15
|
+
a lockfile pins them by checksum, and the record of what was fetched is what a
|
|
16
|
+
methods section cites. Analysis stays in pandas and xarray; usdata only
|
|
17
|
+
acquires. If you need every product one agency publishes, that agency's own
|
|
18
|
+
library is the better tool; usdata is for pinning inputs across sources and
|
|
19
|
+
proving later that they have not changed.
|
|
19
20
|
|
|
20
21
|
```sh
|
|
21
22
|
pip install "usdata[pandas]"
|
|
@@ -63,9 +64,9 @@ breaking changes.
|
|
|
63
64
|
|
|
64
65
|
| | |
|
|
65
66
|
| --- | --- |
|
|
66
|
-
| [usdata.dev](https://usdata.dev/) | What it is for: the [dataset browser](https://usdata.dev/datasets/) and [worked examples](https://usdata.dev/
|
|
67
|
+
| [usdata.dev](https://usdata.dev/) | What it is for: the [dataset browser](https://usdata.dev/datasets/) and [worked examples](https://usdata.dev/studies/) with saved results |
|
|
67
68
|
| [docs.usdata.dev](https://docs.usdata.dev/) | How to use it: [install](https://docs.usdata.dev/install/), [getting started](https://docs.usdata.dev/getting-started/), guides, dataset notes, and reference |
|
|
68
|
-
| [Severe-weather case study](https://usdata.dev/
|
|
69
|
+
| [Severe-weather case study](https://usdata.dev/studies/severe-weather-case-study/) | One tornado, six sources, one manifest and lockfile, ending in a citation |
|
|
69
70
|
|
|
70
71
|
Twenty-seven datasets are available today and nineteen more are planned, grouped
|
|
71
72
|
by agency and product family in the [catalog](docs/providers/README.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "usdata"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.27.0"
|
|
4
4
|
description = "Unified Python SDK and CLI for discovering, fetching, and tracking provenance of U.S. public scientific data"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -59,7 +59,7 @@ grib = [
|
|
|
59
59
|
Homepage = "https://usdata.dev/"
|
|
60
60
|
Documentation = "https://docs.usdata.dev/"
|
|
61
61
|
Repository = "https://github.com/jakeryderv/usdata"
|
|
62
|
-
Examples = "https://usdata.dev/
|
|
62
|
+
Examples = "https://usdata.dev/studies/"
|
|
63
63
|
Changelog = "https://github.com/jakeryderv/usdata/blob/main/CHANGELOG.md"
|
|
64
64
|
Issues = "https://github.com/jakeryderv/usdata/issues"
|
|
65
65
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "usdata"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.27.0"
|
|
4
4
|
description = "Unified Python SDK and CLI for discovering, fetching, and tracking provenance of U.S. public scientific data"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -56,7 +56,7 @@ grib = [
|
|
|
56
56
|
Homepage = "https://usdata.dev/"
|
|
57
57
|
Documentation = "https://docs.usdata.dev/"
|
|
58
58
|
Repository = "https://github.com/jakeryderv/usdata"
|
|
59
|
-
Examples = "https://usdata.dev/
|
|
59
|
+
Examples = "https://usdata.dev/studies/"
|
|
60
60
|
Changelog = "https://github.com/jakeryderv/usdata/blob/main/CHANGELOG.md"
|
|
61
61
|
Issues = "https://github.com/jakeryderv/usdata/issues"
|
|
62
62
|
|
|
@@ -17,6 +17,10 @@ from usdata.models import Asset, Dataset, Provenance, Query
|
|
|
17
17
|
from usdata.providers import Provider, load_adapter
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
|
+
# Each is an optional extra: without it installed the result is simply untyped.
|
|
21
|
+
import pandas as pd # pyright: ignore[reportMissingImports]
|
|
22
|
+
import xarray as xr # pyright: ignore[reportMissingImports]
|
|
23
|
+
|
|
20
24
|
from usdata.inspect import Summary
|
|
21
25
|
|
|
22
26
|
|
|
@@ -32,46 +36,74 @@ class FetchedAsset(BaseModel):
|
|
|
32
36
|
provenance: Provenance
|
|
33
37
|
from_cache: bool
|
|
34
38
|
|
|
35
|
-
def open(
|
|
39
|
+
def open(self) -> Any:
|
|
40
|
+
"""Open local data with the reader its format implies, with that reader's defaults.
|
|
41
|
+
|
|
42
|
+
CSV and ERDDAP CSV, HURDAT2 and AQS daily JSON return a pandas DataFrame;
|
|
43
|
+
NetCDF4 and GRIB2 a loaded xarray Dataset; NEXRAD Level II an xarray
|
|
44
|
+
DataTree. Provenance is kept in the result's ``attrs["usdata"]``. A file
|
|
45
|
+
that needs options, or whose metadata leaves its format ambiguous, is
|
|
46
|
+
opened with the method for its format instead: ``open_csv``,
|
|
47
|
+
``open_nexrad``, ``open_grib2``, or ``open_netcdf``. Cached files and
|
|
48
|
+
provenance sidecars are never changed. See ``usdata.readers.open_asset``.
|
|
49
|
+
"""
|
|
50
|
+
from usdata.readers import open_asset
|
|
51
|
+
|
|
52
|
+
return open_asset(self)
|
|
53
|
+
|
|
54
|
+
def open_csv(
|
|
36
55
|
self,
|
|
37
56
|
*,
|
|
38
|
-
reader: str | None = None,
|
|
39
57
|
dtype: dict[str, str] | None = None,
|
|
40
58
|
parse_dates: list[str] | None = None,
|
|
41
59
|
usecols: list[str] | None = None,
|
|
42
60
|
nrows: int | None = None,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
ERDDAP units are kept in ``frame.attrs["units"]`` and source provenance
|
|
50
|
-
in ``frame.attrs["usdata"]``. NEXRAD returns a xarray DataTree with provenance
|
|
51
|
-
in ``radar.attrs["usdata"]``. NetCDF4 and GRIB2 return a loaded xarray Dataset
|
|
52
|
-
with matching provenance in its attributes, and with units and long names
|
|
53
|
-
the file leaves unstated filled from the registry entry's variables. See
|
|
54
|
-
``usdata.readers.open_asset`` for options. Use ``sweep=0`` or ``sweep=[0, 2]``
|
|
55
|
-
to load selected zero-based radar sweeps, and
|
|
56
|
-
``select={"shortName": "cape", "typeOfLevel": "surface"}``
|
|
57
|
-
to choose GRIB2 messages; ``strict=True`` raises instead of warning when a
|
|
58
|
-
GRIB2 select value matches none of the selected messages. Cached files and
|
|
59
|
-
provenance sidecars are never changed.
|
|
61
|
+
units_row: bool | None = None,
|
|
62
|
+
) -> pd.DataFrame:
|
|
63
|
+
"""Open a CSV as a pandas DataFrame; see ``usdata.readers.open_csv``.
|
|
64
|
+
|
|
65
|
+
``units_row`` says whether a units row follows the header, as in ERDDAP
|
|
66
|
+
CSV, and is inferred when ``None``; the units go to ``frame.attrs["units"]``.
|
|
60
67
|
"""
|
|
61
|
-
from usdata.readers import
|
|
68
|
+
from usdata.readers import open_csv
|
|
62
69
|
|
|
63
|
-
return
|
|
70
|
+
return open_csv(
|
|
64
71
|
self,
|
|
65
|
-
reader=reader,
|
|
66
72
|
dtype=dtype,
|
|
67
73
|
parse_dates=parse_dates,
|
|
68
74
|
usecols=usecols,
|
|
69
75
|
nrows=nrows,
|
|
70
|
-
|
|
71
|
-
select=select,
|
|
72
|
-
strict=strict,
|
|
76
|
+
units_row=units_row,
|
|
73
77
|
)
|
|
74
78
|
|
|
79
|
+
def open_nexrad(self, *, sweep: int | list[int] | None = None) -> xr.DataTree:
|
|
80
|
+
"""Open a NEXRAD Level II volume as an xarray DataTree; see ``usdata.readers.open_nexrad``.
|
|
81
|
+
|
|
82
|
+
Use ``sweep=0`` or ``sweep=[0, 2]`` to load selected zero-based sweeps.
|
|
83
|
+
"""
|
|
84
|
+
from usdata.readers import open_nexrad
|
|
85
|
+
|
|
86
|
+
return open_nexrad(self, sweep=sweep)
|
|
87
|
+
|
|
88
|
+
def open_grib2(
|
|
89
|
+
self, *, select: Mapping[str, Any] | None = None, strict: bool = False
|
|
90
|
+
) -> xr.Dataset:
|
|
91
|
+
"""Open GRIB2 messages as one xarray Dataset; see ``usdata.readers.open_grib2``.
|
|
92
|
+
|
|
93
|
+
``select={"shortName": "cape", "typeOfLevel": "surface"}`` chooses
|
|
94
|
+
messages; ``strict=True`` raises instead of warning when a select value
|
|
95
|
+
matches none of the selected messages.
|
|
96
|
+
"""
|
|
97
|
+
from usdata.readers import open_grib2
|
|
98
|
+
|
|
99
|
+
return open_grib2(self, select=select, strict=strict)
|
|
100
|
+
|
|
101
|
+
def open_netcdf(self) -> xr.Dataset:
|
|
102
|
+
"""Open a NetCDF4 file as an xarray Dataset; see ``usdata.readers.open_netcdf``."""
|
|
103
|
+
from usdata.readers import open_netcdf
|
|
104
|
+
|
|
105
|
+
return open_netcdf(self)
|
|
106
|
+
|
|
75
107
|
def inspect(self) -> Summary:
|
|
76
108
|
"""Summarize this file: provenance, format, and what that format holds.
|
|
77
109
|
|
|
@@ -108,12 +140,18 @@ def _fetch_asset(
|
|
|
108
140
|
root: Path | None = None,
|
|
109
141
|
force: bool = False,
|
|
110
142
|
pinned: Provenance | None = None,
|
|
143
|
+
staging: Path | None = None,
|
|
111
144
|
) -> FetchedAsset:
|
|
112
145
|
"""Fetch one asset through the cache, passing any pinned record to the adapter.
|
|
113
146
|
|
|
114
147
|
``pinned`` is the provenance a lockfile holds for this asset. The adapter sees
|
|
115
148
|
it through ``prepare_fetch``, so an asset that pins byte ranges is reproduced
|
|
116
149
|
from the record rather than by resolving its query again.
|
|
150
|
+
|
|
151
|
+
``staging`` is a root a download is written under instead of the cache. The
|
|
152
|
+
cache at ``root`` is still checked, and a hit is returned from there; a
|
|
153
|
+
miss comes back with its ``path`` under ``staging``, for the caller to move
|
|
154
|
+
home once it can pin it (ADR 0031).
|
|
117
155
|
"""
|
|
118
156
|
if asset.dataset_id != dataset.id:
|
|
119
157
|
raise ValueError(f"asset dataset {asset.dataset_id!r} does not match {dataset.id!r}")
|
|
@@ -138,6 +176,8 @@ def _fetch_asset(
|
|
|
138
176
|
):
|
|
139
177
|
_progress.emit(_progress.AssetProgress(asset.id, "cached", prov.size))
|
|
140
178
|
return FetchedAsset(asset=asset, path=path, provenance=prov, from_cache=True)
|
|
179
|
+
if staging is not None:
|
|
180
|
+
path = asset_path(asset, staging)
|
|
141
181
|
with staged_path(path) as tmp:
|
|
142
182
|
partial = adapter.prepare_fetch(asset, pinned)
|
|
143
183
|
if partial is None:
|
|
@@ -174,15 +214,19 @@ def _fetch_with(
|
|
|
174
214
|
*,
|
|
175
215
|
root: Path | None = None,
|
|
176
216
|
force: bool = False,
|
|
217
|
+
staging: Path | None = None,
|
|
177
218
|
) -> list[FetchedAsset]:
|
|
178
219
|
"""Run the loop on an adapter the caller opened, so one adapter can serve many queries.
|
|
179
220
|
|
|
180
221
|
The listing is put in the order every result promises, by ``asset.time.start``
|
|
181
222
|
then id, so no adapter has to sort and no caller has to sort defensively.
|
|
223
|
+
``staging`` is passed to each fetch; see ``_fetch_asset``.
|
|
182
224
|
"""
|
|
183
225
|
assets = ordered(adapter.list_assets(query))
|
|
184
226
|
_progress.batch([asset.size for asset in assets])
|
|
185
|
-
return [
|
|
227
|
+
return [
|
|
228
|
+
_fetch_asset(dataset, a, adapter, root=root, force=force, staging=staging) for a in assets
|
|
229
|
+
]
|
|
186
230
|
|
|
187
231
|
|
|
188
232
|
def ordered(assets: list[Asset]) -> list[Asset]:
|
|
@@ -9,7 +9,8 @@ repeat, so the same select always yields the same names. Values arrive from
|
|
|
9
9
|
ecCodes as float64, are masked to NaN where the message's bitmap marks them
|
|
10
10
|
missing, and are stored as float32; the float64 array is released before the
|
|
11
11
|
Dataset is returned. Rows are ordered north to south and columns west to east
|
|
12
|
-
regardless of the message's scanning mode
|
|
12
|
+
regardless of the message's scanning mode, including grids whose adjacent rows
|
|
13
|
+
scan in opposite directions. See ADR 0022.
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
16
|
from __future__ import annotations
|
|
@@ -279,6 +280,8 @@ class _Grid:
|
|
|
279
280
|
rows, cols = shape
|
|
280
281
|
self.flip_rows = bool(_get(eccodes, h, "jScansPositively", int))
|
|
281
282
|
self.flip_cols = bool(_get(eccodes, h, "iScansNegatively", int))
|
|
283
|
+
# Adjacent rows scan in opposite directions (NBM's CONUS grid does this).
|
|
284
|
+
self.alternating = bool(_get(eccodes, h, "alternativeRowScanning", int))
|
|
282
285
|
if _get(eccodes, h, "jPointsAreConsecutive", int):
|
|
283
286
|
raise ValueError("grids with consecutive j points are not supported")
|
|
284
287
|
self.regular = self.grid_type == "regular_ll"
|
|
@@ -305,15 +308,25 @@ class _Grid:
|
|
|
305
308
|
value = _get(eccodes, h, key)
|
|
306
309
|
if value is not None:
|
|
307
310
|
self.attrs[key] = value
|
|
308
|
-
self.key = (self.grid_type, self.shape, self.flip_rows, self.flip_cols)
|
|
311
|
+
self.key = (self.grid_type, self.shape, self.flip_rows, self.flip_cols, self.alternating)
|
|
309
312
|
|
|
310
313
|
def _orient(self, numpy: Any, axis: Any, *, rows: bool) -> Any:
|
|
311
314
|
return axis[::-1].copy() if (self.flip_rows if rows else self.flip_cols) else axis
|
|
312
315
|
|
|
313
|
-
def reshape(self, numpy: Any, flat: Any) -> Any:
|
|
316
|
+
def reshape(self, numpy: Any, flat: Any, *, stored: bool = False) -> Any:
|
|
317
|
+
"""Order a flat array north to south and west to east.
|
|
318
|
+
|
|
319
|
+
``stored`` marks data values, which ecCodes returns in the order the
|
|
320
|
+
message stores them: with alternative row scanning every second row
|
|
321
|
+
runs the other way and is reversed here. The latitudes and longitudes
|
|
322
|
+
ecCodes computes do not alternate, so coordinates skip that step.
|
|
323
|
+
"""
|
|
314
324
|
if flat.size != self.shape[0] * self.shape[1]:
|
|
315
325
|
raise ValueError(f"message has {flat.size} values for a {self.shape} grid")
|
|
316
326
|
grid = flat.reshape(self.shape)
|
|
327
|
+
if stored and self.alternating:
|
|
328
|
+
grid = grid.copy()
|
|
329
|
+
grid[1::2] = grid[1::2, ::-1]
|
|
317
330
|
if self.flip_rows:
|
|
318
331
|
grid = grid[::-1, :]
|
|
319
332
|
if self.flip_cols:
|
|
@@ -423,7 +436,7 @@ def open_grib2(
|
|
|
423
436
|
missing = _get(eccodes, h, "missingValue", float)
|
|
424
437
|
if missing is not None:
|
|
425
438
|
values[values == missing] = numpy.nan
|
|
426
|
-
data = grid.reshape(numpy, values).astype(numpy.float32)
|
|
439
|
+
data = grid.reshape(numpy, values, stored=True).astype(numpy.float32)
|
|
427
440
|
del values
|
|
428
441
|
attrs = {
|
|
429
442
|
key: value for key in VARIABLE_KEYS if (value := _get(eccodes, h, key)) is not None
|
|
@@ -454,8 +467,8 @@ def open_grib2(
|
|
|
454
467
|
selected.append(_Field(short=short, data=data, attrs=attrs, message=message))
|
|
455
468
|
if count > 1 and needs_select:
|
|
456
469
|
raise ValueError(
|
|
457
|
-
f"{count} messages; pass select={{...}} with ecCodes keys to
|
|
458
|
-
f"for example select={{'shortName': ..., 'typeOfLevel': ...}}. "
|
|
470
|
+
f"{count} messages; pass select={{...}} to open_grib2 with ecCodes keys to "
|
|
471
|
+
f"choose, for example select={{'shortName': ..., 'typeOfLevel': ...}}. "
|
|
459
472
|
f"Available (shortName, typeOfLevel, level): {_available(fetched.path)}"
|
|
460
473
|
)
|
|
461
474
|
if grid is None or not selected:
|
|
@@ -67,8 +67,9 @@ def _check_sweeps(content: bytes, sweep: int | list[int] | None) -> None:
|
|
|
67
67
|
):
|
|
68
68
|
raise RadarDecodeError(
|
|
69
69
|
f"cannot safely decode sweep {index}: NEXRAD moment and coordinate records "
|
|
70
|
-
"do not agree; select an unaffected sweep explicitly with
|
|
71
|
-
"or use another decoder.
|
|
70
|
+
"do not agree; select an unaffected sweep explicitly with "
|
|
71
|
+
"open_nexrad(sweep=...) or use another decoder. "
|
|
72
|
+
"No sweeps were silently dropped."
|
|
72
73
|
)
|
|
73
74
|
|
|
74
75
|
|