xvrt 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.
xvrt-0.1.0/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ .Rproj.user
2
+ .Rhistory
3
+ .Rdata
4
+ .httr-oauth
5
+ .DS_Store
6
+ .quarto
7
+ xvrt.Rproj
8
+ *.tar.gz
9
+ .positai
10
+ __pycache__/
11
+ *.py[cod]
12
+ .pytest_cache/
13
+ *.egg-info/
14
+ build/
15
+ dist/
16
+ # Quarto
17
+ docs/_site/
18
+ docs/.quarto/
19
+ docs/**/*_files/
20
+ docs/**/*.quarto_ipynb
21
+ docs/**/*.vrt
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ First release.
6
+
7
+ - `write_mdim_vrt()`: GDAL multidimensional VRT from an xarray Dataset.
8
+ - Compositions `concat` (files already carry the dimension) and `stack`
9
+ (one file per position of a new dimension, with an optional `index` per
10
+ source for gaps).
11
+ - Every data variable becomes an array; sources may be shared or given per
12
+ variable (`sources={"var": [...]}`); `variables=` selects and orders.
13
+ - NetCDF/HDF5/Zarr array sources (`<SourceArray>`) and GeoTIFF/COG band
14
+ sources (`<SourceBand>` + `<SourceTranspose>`).
15
+ - Packed data: storage dtype, scale, offset and nodata from `.encoding`.
16
+ - Time: decoded datetime and cftime coordinates re-encoded with their CF
17
+ units and calendar.
18
+ - `<SourceSlab>` extents on every source, so reads open only what they need.
19
+ - `<SRS>` with `dataAxisToSRSAxisMapping` computed from the WKT axis order.
20
+ - Coordinates as start/step when regular, inline values otherwise, or read
21
+ from the sources.
22
+ - `from_stac()`: the same from STAC items or a stac-geoparquet file, using
23
+ catalogue fields only (projection and raster extensions).
24
+ - `Dataset.vrt.write_mdim()` accessor (`import xvrt.accessor`).
25
+ - Output validates against GDAL's `gdalvrt.xsd`, except mdim `<BlockSize>`,
26
+ written comma-separated as GDAL's driver requires.
xvrt-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael Sumner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
xvrt-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.5
2
+ Name: xvrt
3
+ Version: 0.1.0
4
+ Summary: Write GDAL multidimensional VRT from xarray Datasets and STAC catalogues (pure Python).
5
+ Project-URL: Documentation, https://hypertidy.github.io/xvrt/
6
+ Project-URL: Source, https://github.com/hypertidy/xvrt
7
+ Project-URL: Issues, https://github.com/hypertidy/xvrt/issues
8
+ Project-URL: Changelog, https://github.com/hypertidy/xvrt/blob/main/CHANGELOG.md
9
+ Author-email: Michael Sumner <mdsumner@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cog,gdal,multidimensional,netcdf,stac,virtual,vrt,xarray
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering :: GIS
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: numpy>=1.24
24
+ Requires-Dist: xarray>=2023.12
25
+ Provides-Extra: cf
26
+ Requires-Dist: cf-xarray; extra == 'cf'
27
+ Provides-Extra: rio
28
+ Requires-Dist: rioxarray; extra == 'rio'
29
+ Provides-Extra: stac
30
+ Requires-Dist: pyarrow; extra == 'stac'
31
+ Requires-Dist: pyproj; extra == 'stac'
32
+ Provides-Extra: test
33
+ Requires-Dist: dask; extra == 'test'
34
+ Requires-Dist: h5netcdf; extra == 'test'
35
+ Requires-Dist: lxml; extra == 'test'
36
+ Requires-Dist: netcdf4; extra == 'test'
37
+ Requires-Dist: pyarrow; extra == 'test'
38
+ Requires-Dist: pyproj; extra == 'test'
39
+ Requires-Dist: pytest; extra == 'test'
40
+ Description-Content-Type: text/markdown
41
+
42
+ # xvrt
43
+
44
+ Write [GDAL multidimensional VRT](https://gdal.org/en/stable/drivers/raster/vrt_multidimensional.html)
45
+ from xarray Datasets and STAC catalogues. Pure Python: no GDAL needed to
46
+ write.
47
+
48
+ Documentation: <https://hypertidy.github.io/xvrt/>
49
+
50
+ A multidimensional VRT is a small XML file that describes a collection of
51
+ files as one n-dimensional dataset: which file supplies which slab of which
52
+ array, plus dimensions, coordinates, CRS, units and packing. It holds no data.
53
+ Any reader of GDAL's multidimensional API opens the whole collection as a
54
+ single cube and reads only the files a request touches.
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ pip install xvrt
60
+ pip install "xvrt[stac]" # adds pyarrow and pyproj for from_stac()
61
+ ```
62
+
63
+ Reading the result needs GDAL 3.x with multidimensional support (for example
64
+ GDAL's Python bindings from conda-forge).
65
+
66
+ ## From xarray
67
+
68
+ Open files the way you normally would, then describe the result:
69
+
70
+ ```python
71
+ import glob
72
+ import xarray as xr
73
+ from xvrt import write_mdim_vrt
74
+
75
+ paths = sorted(glob.glob("oisst-avhrr-v02r01.*.nc")) # one day per file
76
+ ds = xr.open_mfdataset(paths, combine="nested", concat_dim="time")
77
+
78
+ write_mdim_vrt(ds, paths, "oisst.vrt", composition="concat", concat_dim="time")
79
+ ```
80
+
81
+ The same works over HTTP. Ten monthly files of one variable from a THREDDS
82
+ server (URLs become `/vsicurl/` sources):
83
+
84
+ ```python
85
+ PREFIX = "https://thredds.nci.org.au/thredds/fileServer/gb6/BRAN/BRAN2020/daily"
86
+ months = [f"2010_{m:02d}" for m in range(1, 11)]
87
+ paths = [f"{PREFIX}/ocean_temp_{ym}.nc" for ym in months]
88
+
89
+ ds = xr.open_mfdataset(paths, engine="h5netcdf")
90
+ write_mdim_vrt(ds[["temp"]], paths, "bran.vrt",
91
+ composition="concat", concat_dim="Time")
92
+ ```
93
+
94
+ ## From a STAC catalogue
95
+
96
+ `from_stac()` builds the VRT from catalogue fields alone (grid, CRS, item
97
+ datetimes, per-asset band storage) without opening a file:
98
+
99
+ ```python
100
+ from xvrt import from_stac
101
+
102
+ from_stac("https://data.source.coop/ausantarctic/ghrsst-mur-v2/ghrsst-mur-v2.parquet",
103
+ "mur.vrt", block_size=[1, 512, 512])
104
+ ```
105
+
106
+ For the GHRSST MUR collection that is five arrays over 8913 days in a few
107
+ seconds.
108
+
109
+ ## What it handles
110
+
111
+ - **Compositions:** `concat` (files already have the dimension) and `stack`
112
+ (one file per position of a new dimension), with explicit positions and
113
+ gaps.
114
+ - **Packed data:** storage dtype, scale, offset and nodata are recovered from
115
+ xarray's `.encoding`, so GDAL decodes the stored bytes exactly as xarray did.
116
+ - **Time:** decoded times are re-encoded with their original CF units and
117
+ calendar.
118
+ - **Multiple variables:** in the same files, or one source list per variable.
119
+ - **Raster sources:** GeoTIFF/COG bands via `<SourceBand>` and
120
+ `<SourceTranspose>`.
121
+ - **Lazy reads:** every source states its extent (`<SourceSlab>`), so a read
122
+ opens only the files it needs.
123
+ - **CRS:** `<SRS>` with the data-axis-to-SRS-axis mapping computed from the
124
+ WKT axis order.
125
+
126
+ ## Reading the result
127
+
128
+ ```bash
129
+ gdal mdim info oisst.vrt
130
+ ```
131
+
132
+ ```python
133
+ from osgeo import gdal
134
+ ds = gdal.OpenEx("oisst.vrt", gdal.OF_MULTIDIM_RASTER)
135
+ sst = ds.GetRootGroup().OpenMDArray("sst").GetUnscaled()
136
+ ```
137
+
138
+ or with an xarray backend for GDAL, such as
139
+ [gdalxarray](https://github.com/hypertidy/gdalxarray):
140
+ `xr.open_dataset("oisst.vrt", engine="gdalxarray")`.
141
+
142
+ ## Development
143
+
144
+ ```bash
145
+ pip install -e ".[test]"
146
+ pytest tests/
147
+ ```
148
+
149
+ `tests/test_gdal_roundtrip.py` reads every written VRT back through GDAL and
150
+ validates it against GDAL's schema (`schema/gdalvrt.xsd`); it is skipped when
151
+ `osgeo.gdal` is not importable. With conda-forge:
152
+
153
+ ```bash
154
+ micromamba create -n xvrt -c conda-forge python gdal libgdal-netcdf xarray netcdf4 h5netcdf dask lxml pyarrow pyproj pytest
155
+ ```
156
+
157
+ The design notes are in [mdim-vrt-writer-plan.md](mdim-vrt-writer-plan.md);
158
+ the documentation site source is in [docs/](docs/).
159
+
160
+ ## Related
161
+
162
+ - [hypertidy/vrtstack](https://github.com/hypertidy/vrtstack): the R
163
+ counterpart, writing the same VRT format from raster collections and
164
+ catalogues.
165
+ - [hypertidy/gdalxarray](https://github.com/hypertidy/gdalxarray): an xarray
166
+ backend for GDAL that opens these VRTs.
167
+
168
+ ## License
169
+
170
+ MIT
xvrt-0.1.0/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # xvrt
2
+
3
+ Write [GDAL multidimensional VRT](https://gdal.org/en/stable/drivers/raster/vrt_multidimensional.html)
4
+ from xarray Datasets and STAC catalogues. Pure Python: no GDAL needed to
5
+ write.
6
+
7
+ Documentation: <https://hypertidy.github.io/xvrt/>
8
+
9
+ A multidimensional VRT is a small XML file that describes a collection of
10
+ files as one n-dimensional dataset: which file supplies which slab of which
11
+ array, plus dimensions, coordinates, CRS, units and packing. It holds no data.
12
+ Any reader of GDAL's multidimensional API opens the whole collection as a
13
+ single cube and reads only the files a request touches.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pip install xvrt
19
+ pip install "xvrt[stac]" # adds pyarrow and pyproj for from_stac()
20
+ ```
21
+
22
+ Reading the result needs GDAL 3.x with multidimensional support (for example
23
+ GDAL's Python bindings from conda-forge).
24
+
25
+ ## From xarray
26
+
27
+ Open files the way you normally would, then describe the result:
28
+
29
+ ```python
30
+ import glob
31
+ import xarray as xr
32
+ from xvrt import write_mdim_vrt
33
+
34
+ paths = sorted(glob.glob("oisst-avhrr-v02r01.*.nc")) # one day per file
35
+ ds = xr.open_mfdataset(paths, combine="nested", concat_dim="time")
36
+
37
+ write_mdim_vrt(ds, paths, "oisst.vrt", composition="concat", concat_dim="time")
38
+ ```
39
+
40
+ The same works over HTTP. Ten monthly files of one variable from a THREDDS
41
+ server (URLs become `/vsicurl/` sources):
42
+
43
+ ```python
44
+ PREFIX = "https://thredds.nci.org.au/thredds/fileServer/gb6/BRAN/BRAN2020/daily"
45
+ months = [f"2010_{m:02d}" for m in range(1, 11)]
46
+ paths = [f"{PREFIX}/ocean_temp_{ym}.nc" for ym in months]
47
+
48
+ ds = xr.open_mfdataset(paths, engine="h5netcdf")
49
+ write_mdim_vrt(ds[["temp"]], paths, "bran.vrt",
50
+ composition="concat", concat_dim="Time")
51
+ ```
52
+
53
+ ## From a STAC catalogue
54
+
55
+ `from_stac()` builds the VRT from catalogue fields alone (grid, CRS, item
56
+ datetimes, per-asset band storage) without opening a file:
57
+
58
+ ```python
59
+ from xvrt import from_stac
60
+
61
+ from_stac("https://data.source.coop/ausantarctic/ghrsst-mur-v2/ghrsst-mur-v2.parquet",
62
+ "mur.vrt", block_size=[1, 512, 512])
63
+ ```
64
+
65
+ For the GHRSST MUR collection that is five arrays over 8913 days in a few
66
+ seconds.
67
+
68
+ ## What it handles
69
+
70
+ - **Compositions:** `concat` (files already have the dimension) and `stack`
71
+ (one file per position of a new dimension), with explicit positions and
72
+ gaps.
73
+ - **Packed data:** storage dtype, scale, offset and nodata are recovered from
74
+ xarray's `.encoding`, so GDAL decodes the stored bytes exactly as xarray did.
75
+ - **Time:** decoded times are re-encoded with their original CF units and
76
+ calendar.
77
+ - **Multiple variables:** in the same files, or one source list per variable.
78
+ - **Raster sources:** GeoTIFF/COG bands via `<SourceBand>` and
79
+ `<SourceTranspose>`.
80
+ - **Lazy reads:** every source states its extent (`<SourceSlab>`), so a read
81
+ opens only the files it needs.
82
+ - **CRS:** `<SRS>` with the data-axis-to-SRS-axis mapping computed from the
83
+ WKT axis order.
84
+
85
+ ## Reading the result
86
+
87
+ ```bash
88
+ gdal mdim info oisst.vrt
89
+ ```
90
+
91
+ ```python
92
+ from osgeo import gdal
93
+ ds = gdal.OpenEx("oisst.vrt", gdal.OF_MULTIDIM_RASTER)
94
+ sst = ds.GetRootGroup().OpenMDArray("sst").GetUnscaled()
95
+ ```
96
+
97
+ or with an xarray backend for GDAL, such as
98
+ [gdalxarray](https://github.com/hypertidy/gdalxarray):
99
+ `xr.open_dataset("oisst.vrt", engine="gdalxarray")`.
100
+
101
+ ## Development
102
+
103
+ ```bash
104
+ pip install -e ".[test]"
105
+ pytest tests/
106
+ ```
107
+
108
+ `tests/test_gdal_roundtrip.py` reads every written VRT back through GDAL and
109
+ validates it against GDAL's schema (`schema/gdalvrt.xsd`); it is skipped when
110
+ `osgeo.gdal` is not importable. With conda-forge:
111
+
112
+ ```bash
113
+ micromamba create -n xvrt -c conda-forge python gdal libgdal-netcdf xarray netcdf4 h5netcdf dask lxml pyarrow pyproj pytest
114
+ ```
115
+
116
+ The design notes are in [mdim-vrt-writer-plan.md](mdim-vrt-writer-plan.md);
117
+ the documentation site source is in [docs/](docs/).
118
+
119
+ ## Related
120
+
121
+ - [hypertidy/vrtstack](https://github.com/hypertidy/vrtstack): the R
122
+ counterpart, writing the same VRT format from raster collections and
123
+ catalogues.
124
+ - [hypertidy/gdalxarray](https://github.com/hypertidy/gdalxarray): an xarray
125
+ backend for GDAL that opens these VRTs.
126
+
127
+ ## License
128
+
129
+ MIT
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "xvrt"
7
+ dynamic = ["version"]
8
+ description = "Write GDAL multidimensional VRT from xarray Datasets and STAC catalogues (pure Python)."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Michael Sumner", email = "mdsumner@gmail.com" }]
14
+ keywords = ["gdal", "vrt", "multidimensional", "xarray", "stac", "netcdf", "cog", "virtual"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Science/Research",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Scientific/Engineering :: GIS",
25
+ ]
26
+ dependencies = [
27
+ "numpy>=1.24",
28
+ "xarray>=2023.12",
29
+ ]
30
+
31
+ [project.optional-dependencies]
32
+ # from_stac(): reading stac-geoparquet, and EPSG codes -> WKT.
33
+ stac = ["pyarrow", "pyproj"]
34
+ # Tests. The GDAL round-trip tests also need osgeo.gdal (conda-forge);
35
+ # they are skipped without it.
36
+ test = ["lxml", "netCDF4", "h5netcdf", "dask", "pytest", "pyarrow", "pyproj"]
37
+ # Extra CRS sources.
38
+ cf = ["cf_xarray"]
39
+ rio = ["rioxarray"]
40
+
41
+ [project.urls]
42
+ Documentation = "https://hypertidy.github.io/xvrt/"
43
+ Source = "https://github.com/hypertidy/xvrt"
44
+ Issues = "https://github.com/hypertidy/xvrt/issues"
45
+ Changelog = "https://github.com/hypertidy/xvrt/blob/main/CHANGELOG.md"
46
+
47
+ [tool.hatch.version]
48
+ path = "xvrt/__init__.py"
49
+
50
+ [tool.hatch.build.targets.wheel]
51
+ packages = ["xvrt"]
52
+
53
+ [tool.hatch.build.targets.sdist]
54
+ include = ["/xvrt", "/tests", "/schema", "/README.md", "/LICENSE", "/CHANGELOG.md"]
@@ -0,0 +1,13 @@
1
+ # Pinned schema
2
+
3
+ `gdalvrt.xsd` here is GDAL's own schema, copied from the GDAL 3.13.3
4
+ conda-forge build (`share/gdal/gdalvrt.xsd`). Upstream source:
5
+
6
+ https://github.com/OSGeo/gdal/blob/master/frmts/vrt/data/gdalvrt.xsd
7
+
8
+ `tests/test_gdal_roundtrip.py` validates every VRT it writes against this
9
+ file; the writer itself never reads it.
10
+
11
+ Known disagreement: the schema types mdim `<BlockSize>` as a space-separated
12
+ `integerList`, but the VRT driver only parses comma-separated values. xvrt
13
+ follows the driver, and the tests ignore that one schema error.