From 6b2fc33eab701aa1cec33c3ce9269b65102cacd0 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Wed, 17 Jun 2026 05:39:14 -0700 Subject: [PATCH 1/5] Add xarray backend entry point for open_geotiff (#3365) --- setup.cfg | 2 + xrspatial/geotiff/_xarray_backend.py | 91 ++++++++++ .../geotiff/tests/test_xarray_backend_3365.py | 164 ++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 xrspatial/geotiff/_xarray_backend.py create mode 100644 xrspatial/geotiff/tests/test_xarray_backend_3365.py diff --git a/setup.cfg b/setup.cfg index 1000b7d82..2219fd13c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,6 +33,8 @@ zip_safe = False [options.entry_points] console_scripts = xrspatial = xrspatial.__main__:main +xarray.backends = + xrspatial_geotiff = xrspatial.geotiff._xarray_backend:GeoTIFFBackendEntrypoint [options.extras_require] doc = diff --git a/xrspatial/geotiff/_xarray_backend.py b/xrspatial/geotiff/_xarray_backend.py new file mode 100644 index 000000000..9d70443f6 --- /dev/null +++ b/xrspatial/geotiff/_xarray_backend.py @@ -0,0 +1,91 @@ +"""xarray backend entry point for the native GeoTIFF/COG/VRT reader. + +Registers :func:`open_geotiff` under xarray's pluggable backend API so a +GeoTIFF source can be opened through the standard entry point:: + + import xarray as xr + + xr.open_dataset("dem.tif", engine="xrspatial_geotiff") + xr.open_mfdataset("*.tif", engine="xrspatial_geotiff") + +The entry point is declared in ``setup.cfg`` under +``[options.entry_points] xarray.backends``. ``open_geotiff`` returns a +:class:`~xarray.DataArray`; xarray backends must return a +:class:`~xarray.Dataset`, so this wrapper promotes the single array to a +one-variable dataset. + +GeoTIFF-specific read options (``gpu``, ``masked``, ``band``, +``overview_level``, ``window``, ``bbox``, ``stable_only``, ...) are +forwarded to :func:`open_geotiff` through xarray's ``backend_kwargs``:: + + xr.open_dataset( + "dem.tif", engine="xrspatial_geotiff", + backend_kwargs={"masked": True, "overview_level": 1}, + ) + +``chunks`` is the one exception: xarray reserves it as a top-level +argument to ``open_dataset``, so it cannot travel through +``backend_kwargs``. Pass ``chunks=`` directly to ``open_dataset`` to get +a dask-backed dataset (xarray wraps the eager read):: + + xr.open_dataset("dem.tif", engine="xrspatial_geotiff", chunks={}) +""" +from __future__ import annotations + +import os + +from xarray.backends import BackendEntrypoint + +# Name for the one data variable when ``open_geotiff`` cannot derive one +# from the source (e.g. an in-memory file-like object with no path). +_DEFAULT_VARIABLE_NAME = "band_data" + +# Extensions ``guess_can_open`` claims so ``xr.open_dataset`` / +# ``open_mfdataset`` can auto-select this engine without ``engine=``. +_SUPPORTED_EXTENSIONS = (".tif", ".tiff", ".vrt") + + +class GeoTIFFBackendEntrypoint(BackendEntrypoint): + """Open GeoTIFF / COG / VRT files with xrspatial's no-GDAL reader. + + Thin wrapper that calls :func:`xrspatial.geotiff.open_geotiff` and + promotes its ``DataArray`` to a one-variable ``Dataset``. + """ + + description = ( + "Open GeoTIFF/COG/VRT files using xrspatial's native (no-GDAL) " + "reader via xrspatial.geotiff.open_geotiff" + ) + url = "https://github.com/xarray-contrib/xarray-spatial" + # ``open_geotiff`` takes ~30 keyword options forwarded verbatim via + # ``**kwargs``, so the parameter list is declared explicitly here: + # xarray's signature introspection (``detect_parameters``) raises on an + # ``open_dataset`` that uses ``**kwargs`` without this attribute set. It + # also stops xarray from injecting its CF decoders -- in particular + # ``mask_and_scale``, which would collide with open_geotiff's deprecated + # alias of the same name. GeoTIFF read options come in through + # ``backend_kwargs`` instead. + open_dataset_parameters = ("filename_or_obj", "drop_variables") + + def open_dataset(self, filename_or_obj, *, drop_variables=None, **kwargs): + # Imported here rather than at module scope so importing this + # backend module stays cheap; the heavy reader package only loads + # when a source is actually opened. + from . import open_geotiff + + da = open_geotiff(filename_or_obj, **kwargs) + name = da.name if da.name is not None else _DEFAULT_VARIABLE_NAME + ds = da.to_dataset(name=name) + if drop_variables is not None: + ds = ds.drop_vars(drop_variables, errors="ignore") + return ds + + def guess_can_open(self, filename_or_obj): + if isinstance(filename_or_obj, os.PathLike): + filename_or_obj = os.fspath(filename_or_obj) + if not isinstance(filename_or_obj, str): + return False + # Strip any query string / fragment so COG URLs such as + # "https://host/dem.tif?token=..." still match on extension. + path = filename_or_obj.split("?", 1)[0].split("#", 1)[0] + return path.lower().endswith(_SUPPORTED_EXTENSIONS) diff --git a/xrspatial/geotiff/tests/test_xarray_backend_3365.py b/xrspatial/geotiff/tests/test_xarray_backend_3365.py new file mode 100644 index 000000000..7cfe0e509 --- /dev/null +++ b/xrspatial/geotiff/tests/test_xarray_backend_3365.py @@ -0,0 +1,164 @@ +"""xarray ``BackendEntrypoint`` for the native GeoTIFF reader. + +Coverage for issue #3365: ``open_geotiff`` is exposed under xarray's +pluggable backend API so a GeoTIFF / COG / VRT source opens through the +standard entry point:: + + xr.open_dataset("dem.tif", engine="xrspatial_geotiff") + +``open_geotiff`` returns a ``DataArray``; the backend promotes it to a +one-variable ``Dataset``. These tests drive the wrapper by passing the +entrypoint class as ``engine=`` so they exercise the worktree code +without depending on the installed ``xarray.backends`` entry point. A +separate test confirms the entry point registers once the package is +installed (the path CI exercises). +""" +from __future__ import annotations + +import importlib.metadata +import io + +import numpy as np +import pytest +import xarray as xr + +from xrspatial.geotiff import open_geotiff +from xrspatial.geotiff._xarray_backend import _DEFAULT_VARIABLE_NAME, GeoTIFFBackendEntrypoint +from xrspatial.geotiff.tests._helpers.tiff_builders import make_minimal_tiff + + +@pytest.fixture +def geo_tiff_path(tmp_path): + """Write a stable-codec georeferenced GeoTIFF; yield its path.""" + payload = make_minimal_tiff( + 4, 4, np.dtype("float32"), + geo_transform=(-120.0, 45.0, 0.001, -0.001), + epsg=4326, + ) + path = tmp_path / "backend_3365.tif" + path.write_bytes(payload) + return str(path) + + +def test_open_dataset_returns_one_variable_dataset(geo_tiff_path): + ds = xr.open_dataset(geo_tiff_path, engine=GeoTIFFBackendEntrypoint) + assert isinstance(ds, xr.Dataset) + assert len(ds.data_vars) == 1 + # Variable name comes from open_geotiff's default (the source stem). + assert "backend_3365" in ds.data_vars + + +def test_dataset_matches_open_geotiff(geo_tiff_path): + da = open_geotiff(geo_tiff_path) + ds = xr.open_dataset(geo_tiff_path, engine=GeoTIFFBackendEntrypoint) + var = ds[da.name] + np.testing.assert_array_equal(var.values, da.values) + assert var.dims == da.dims + # Georeferencing survives the DataArray -> Dataset promotion. + assert var.attrs.get("crs") == da.attrs.get("crs") + assert var.attrs.get("transform") == da.attrs.get("transform") + for coord in da.coords: + np.testing.assert_array_equal(ds[coord].values, da[coord].values) + + +def test_file_like_source_falls_back_to_default_name(): + payload = make_minimal_tiff(4, 4, np.dtype("float32")) + ds = xr.open_dataset(io.BytesIO(payload), engine=GeoTIFFBackendEntrypoint) + # A file-like source has no path for open_geotiff to derive a name + # from, so the backend uses its fallback variable name. + assert _DEFAULT_VARIABLE_NAME in ds.data_vars + + +def test_backend_kwargs_forwarded_to_open_geotiff(geo_tiff_path): + # backend_kwargs reach open_geotiff verbatim; default_name renames the + # resulting data variable, which is an unambiguous signal the kwarg + # made it through. + ds = xr.open_dataset( + geo_tiff_path, engine=GeoTIFFBackendEntrypoint, + backend_kwargs={"default_name": "elevation"}, + ) + assert "elevation" in ds.data_vars + + +def test_top_level_chunks_gives_dask_backed_variable(geo_tiff_path): + pytest.importorskip("dask") + # ``chunks`` is reserved by xarray's open_dataset and cannot be passed + # through backend_kwargs; the top-level argument wraps the returned + # variable in dask. + ds = xr.open_dataset( + geo_tiff_path, engine=GeoTIFFBackendEntrypoint, chunks={}, + ) + assert ds["backend_3365"].chunks is not None + + +def test_drop_variables_removes_the_only_variable(geo_tiff_path): + ds = xr.open_dataset( + geo_tiff_path, engine=GeoTIFFBackendEntrypoint, + drop_variables="backend_3365", + ) + assert "backend_3365" not in ds.data_vars + + +def test_open_mfdataset(tmp_path): + pytest.importorskip("dask") + paths = [] + for i in range(2): + payload = make_minimal_tiff( + 4, 4, np.dtype("float32"), + geo_transform=(-120.0, 45.0, 0.001, -0.001), + epsg=4326, + ) + p = tmp_path / f"mf_3365_{i}.tif" + p.write_bytes(payload) + paths.append(str(p)) + + # Each file opens as a one-variable Dataset, so concatenation along a + # new dimension works through the standard multi-file API. + ds = xr.open_mfdataset( + paths, engine=GeoTIFFBackendEntrypoint, + combine="nested", concat_dim="tile", + ) + assert isinstance(ds, xr.Dataset) + assert ds.sizes["tile"] == 2 + + +@pytest.mark.parametrize( + "name, expected", + [ + ("dem.tif", True), + ("dem.TIF", True), + ("scene.tiff", True), + ("mosaic.vrt", True), + ("https://host/path/dem.tif?token=abc", True), + ("data.nc", False), + ("notes.txt", False), + ("noextension", False), + ], +) +def test_guess_can_open_extensions(name, expected): + assert GeoTIFFBackendEntrypoint().guess_can_open(name) is expected + + +def test_guess_can_open_pathlike(tmp_path): + p = tmp_path / "dem_3365.tif" + assert GeoTIFFBackendEntrypoint().guess_can_open(p) is True + + +def test_guess_can_open_non_string_returns_false(): + assert GeoTIFFBackendEntrypoint().guess_can_open(io.BytesIO(b"")) is False + + +def test_entry_point_registered(): + """The ``xarray.backends`` entry point resolves to the backend class. + + Skips when the installed distribution metadata predates this change + (e.g. an editable install made before the entry point was added). + CI installs the branch fresh, so the assertion runs there. + """ + eps = importlib.metadata.entry_points(group="xarray.backends") + matches = [ep for ep in eps if ep.name == "xrspatial_geotiff"] + if not matches: + pytest.skip( + "xrspatial installed without the xarray.backends entry point; " + "reinstall the package to register 'xrspatial_geotiff'.") + assert matches[0].load() is GeoTIFFBackendEntrypoint From 17e59927dfbae85bf88e2bec6a0142426a6d1a40 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Wed, 17 Jun 2026 05:40:28 -0700 Subject: [PATCH 2/5] Document xarray_geotiff backend engine (#3365) --- README.md | 5 +++++ docs/source/reference/geotiff.rst | 32 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/README.md b/README.md index c7f3df48c..6c270b3d4 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,11 @@ to_geotiff(dask_da, 'mosaic.vrt') # stream Dask to VRT # Accessor methods da.xrs.to_geotiff('out.tif', compression='lzw') # write from DataArray ds.xrs.open_geotiff('large_dem.tif') # read windowed to Dataset extent + +# xarray backend engine +import xarray as xr +xr.open_dataset('dem.tif', engine='xrspatial_geotiff') # open as a Dataset +xr.open_mfdataset('*.tif', engine='xrspatial_geotiff') # open many files ``` **Compression codecs:** Deflate, LZW (Numba JIT), ZSTD, PackBits, JPEG (Pillow, internal-only: requires `allow_internal_only_jpeg=True` and is not readable by GDAL), JPEG 2000 (glymur, experimental: requires `allow_experimental_codecs=True`), uncompressed diff --git a/docs/source/reference/geotiff.rst b/docs/source/reference/geotiff.rst index 0f89f5351..801514022 100644 --- a/docs/source/reference/geotiff.rst +++ b/docs/source/reference/geotiff.rst @@ -226,6 +226,38 @@ the top level, so ``from xrspatial import open_geotiff`` and xrspatial.geotiff.open_geotiff +xarray backend engine +===================== +``open_geotiff`` is also registered as an xarray backend under the +engine name ``xrspatial_geotiff``, so a source can be opened through +xarray's standard API: + +.. code-block:: python + + import xarray as xr + + ds = xr.open_dataset("dem.tif", engine="xrspatial_geotiff") + ds = xr.open_mfdataset("*.tif", engine="xrspatial_geotiff") + +``open_geotiff`` returns a ``DataArray``; the engine promotes it to a +one-variable ``Dataset`` (the variable name is the source stem, or +``band_data`` for an unnamed file-like source). GeoTIFF read options +(``gpu``, ``masked``, ``band``, ``overview_level``, ``window``, +``bbox``, ...) are forwarded through ``backend_kwargs``: + +.. code-block:: python + + xr.open_dataset( + "dem.tif", engine="xrspatial_geotiff", + backend_kwargs={"masked": True, "overview_level": 1}, + ) + +``chunks`` is the exception: xarray reserves it as a top-level argument +to ``open_dataset``, so pass it directly (``chunks={}``) rather than +through ``backend_kwargs`` to get a dask-backed dataset. The ``.tif``, +``.tiff``, and ``.vrt`` extensions are auto-detected, so ``engine=`` can +be omitted for those sources. + Coregistered reads (experimental) ================================= From cf34c6c3f12b4dd7657ab138dc595cf9947dd134 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Wed, 17 Jun 2026 05:43:16 -0700 Subject: [PATCH 3/5] Address review: document open_mfdataset shared-name requirement and autodetect ambiguity (#3365) --- README.md | 3 ++- docs/source/reference/geotiff.rst | 20 +++++++++++++++---- .../geotiff/tests/test_xarray_backend_3365.py | 8 ++++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6c270b3d4..71305e3be 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,8 @@ ds.xrs.open_geotiff('large_dem.tif') # read windowed to Dataset # xarray backend engine import xarray as xr xr.open_dataset('dem.tif', engine='xrspatial_geotiff') # open as a Dataset -xr.open_mfdataset('*.tif', engine='xrspatial_geotiff') # open many files +xr.open_mfdataset('*.tif', engine='xrspatial_geotiff', # share one var name + backend_kwargs={'default_name': 'band_data'}) ``` **Compression codecs:** Deflate, LZW (Numba JIT), ZSTD, PackBits, JPEG (Pillow, internal-only: requires `allow_internal_only_jpeg=True` and is not readable by GDAL), JPEG 2000 (glymur, experimental: requires `allow_experimental_codecs=True`), uncompressed diff --git a/docs/source/reference/geotiff.rst b/docs/source/reference/geotiff.rst index 801514022..e9d753e09 100644 --- a/docs/source/reference/geotiff.rst +++ b/docs/source/reference/geotiff.rst @@ -237,7 +237,9 @@ xarray's standard API: import xarray as xr ds = xr.open_dataset("dem.tif", engine="xrspatial_geotiff") - ds = xr.open_mfdataset("*.tif", engine="xrspatial_geotiff") + ds = xr.open_mfdataset( + "*.tif", engine="xrspatial_geotiff", + backend_kwargs={"default_name": "band_data"}) ``open_geotiff`` returns a ``DataArray``; the engine promotes it to a one-variable ``Dataset`` (the variable name is the source stem, or @@ -254,9 +256,19 @@ one-variable ``Dataset`` (the variable name is the source stem, or ``chunks`` is the exception: xarray reserves it as a top-level argument to ``open_dataset``, so pass it directly (``chunks={}``) rather than -through ``backend_kwargs`` to get a dask-backed dataset. The ``.tif``, -``.tiff``, and ``.vrt`` extensions are auto-detected, so ``engine=`` can -be omitted for those sources. +through ``backend_kwargs`` to get a dask-backed dataset. + +For ``open_mfdataset``, pass a shared ``default_name`` through +``backend_kwargs`` as shown above. Without it the variable in each file's +Dataset takes the source stem, so files with different names concatenate +into one variable per file (each NaN-filled outside its own slice) rather +than a single combined variable. + +The ``.tif``, ``.tiff``, and ``.vrt`` extensions are auto-detected, so +``engine=`` can be omitted for those sources. Bare auto-detection is +ambiguous when another raster backend (e.g. rioxarray's ``rasterio``) is +installed and also claims those extensions; xarray then raises and asks +for an explicit ``engine=``. Coregistered reads (experimental) ================================= diff --git a/xrspatial/geotiff/tests/test_xarray_backend_3365.py b/xrspatial/geotiff/tests/test_xarray_backend_3365.py index 7cfe0e509..39d98d021 100644 --- a/xrspatial/geotiff/tests/test_xarray_backend_3365.py +++ b/xrspatial/geotiff/tests/test_xarray_backend_3365.py @@ -112,13 +112,17 @@ def test_open_mfdataset(tmp_path): p.write_bytes(payload) paths.append(str(p)) - # Each file opens as a one-variable Dataset, so concatenation along a - # new dimension works through the standard multi-file API. + # A shared default_name keeps every file's data variable identically + # named, so the files concatenate into one variable along the new + # dimension. Without it each file's variable takes its own stem and the + # result has one variable per file instead. ds = xr.open_mfdataset( paths, engine=GeoTIFFBackendEntrypoint, combine="nested", concat_dim="tile", + backend_kwargs={"default_name": "band_data"}, ) assert isinstance(ds, xr.Dataset) + assert list(ds.data_vars) == ["band_data"] assert ds.sizes["tile"] == 2 From 0f0299f597d7ed733b1add766db0e6df3dd269fa Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Wed, 17 Jun 2026 07:39:09 -0700 Subject: [PATCH 4/5] Document that coregister/auto_reproject are accessor-only, not on the engine (#3365) --- docs/source/reference/geotiff.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/source/reference/geotiff.rst b/docs/source/reference/geotiff.rst index e9d753e09..23ba0d718 100644 --- a/docs/source/reference/geotiff.rst +++ b/docs/source/reference/geotiff.rst @@ -270,6 +270,15 @@ ambiguous when another raster backend (e.g. rioxarray's ``rasterio``) is installed and also claims those extensions; xarray then raises and asks for an explicit ``engine=``. +The engine forwards to the standalone ``open_geotiff`` function, so the +coregistered-read options (``coregister``, ``auto_reproject``, +``resampling``) are *not* available through it; they live on the +``.xrs.open_geotiff`` accessor because they reproject and resample onto a +target array's grid, and the engine opens a single source from scratch +with no target. Passing them through ``backend_kwargs`` raises +``TypeError``. Use the accessor on the target array instead, e.g. +``target.xrs.open_geotiff("scene.tif", coregister=True)``. + Coregistered reads (experimental) ================================= From b7a47bceaf199d423b64c54ac45c112c5582c6ed Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Wed, 17 Jun 2026 08:57:47 -0700 Subject: [PATCH 5/5] Rename backend engine from "xrspatial_geotiff" to "xrspatial" (#3365) --- README.md | 4 ++-- docs/source/reference/geotiff.rst | 8 ++++---- setup.cfg | 2 +- xrspatial/geotiff/_xarray_backend.py | 8 ++++---- xrspatial/geotiff/tests/test_xarray_backend_3365.py | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 71305e3be..5ab744b09 100644 --- a/README.md +++ b/README.md @@ -201,8 +201,8 @@ ds.xrs.open_geotiff('large_dem.tif') # read windowed to Dataset # xarray backend engine import xarray as xr -xr.open_dataset('dem.tif', engine='xrspatial_geotiff') # open as a Dataset -xr.open_mfdataset('*.tif', engine='xrspatial_geotiff', # share one var name +xr.open_dataset('dem.tif', engine='xrspatial') # open as a Dataset +xr.open_mfdataset('*.tif', engine='xrspatial', # share one var name backend_kwargs={'default_name': 'band_data'}) ``` diff --git a/docs/source/reference/geotiff.rst b/docs/source/reference/geotiff.rst index 23ba0d718..1617cadcc 100644 --- a/docs/source/reference/geotiff.rst +++ b/docs/source/reference/geotiff.rst @@ -229,16 +229,16 @@ the top level, so ``from xrspatial import open_geotiff`` and xarray backend engine ===================== ``open_geotiff`` is also registered as an xarray backend under the -engine name ``xrspatial_geotiff``, so a source can be opened through +engine name ``xrspatial``, so a source can be opened through xarray's standard API: .. code-block:: python import xarray as xr - ds = xr.open_dataset("dem.tif", engine="xrspatial_geotiff") + ds = xr.open_dataset("dem.tif", engine="xrspatial") ds = xr.open_mfdataset( - "*.tif", engine="xrspatial_geotiff", + "*.tif", engine="xrspatial", backend_kwargs={"default_name": "band_data"}) ``open_geotiff`` returns a ``DataArray``; the engine promotes it to a @@ -250,7 +250,7 @@ one-variable ``Dataset`` (the variable name is the source stem, or .. code-block:: python xr.open_dataset( - "dem.tif", engine="xrspatial_geotiff", + "dem.tif", engine="xrspatial", backend_kwargs={"masked": True, "overview_level": 1}, ) diff --git a/setup.cfg b/setup.cfg index 2219fd13c..ef9e1ed2a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,7 +34,7 @@ zip_safe = False console_scripts = xrspatial = xrspatial.__main__:main xarray.backends = - xrspatial_geotiff = xrspatial.geotiff._xarray_backend:GeoTIFFBackendEntrypoint + xrspatial = xrspatial.geotiff._xarray_backend:GeoTIFFBackendEntrypoint [options.extras_require] doc = diff --git a/xrspatial/geotiff/_xarray_backend.py b/xrspatial/geotiff/_xarray_backend.py index 9d70443f6..220b5c548 100644 --- a/xrspatial/geotiff/_xarray_backend.py +++ b/xrspatial/geotiff/_xarray_backend.py @@ -5,8 +5,8 @@ import xarray as xr - xr.open_dataset("dem.tif", engine="xrspatial_geotiff") - xr.open_mfdataset("*.tif", engine="xrspatial_geotiff") + xr.open_dataset("dem.tif", engine="xrspatial") + xr.open_mfdataset("*.tif", engine="xrspatial") The entry point is declared in ``setup.cfg`` under ``[options.entry_points] xarray.backends``. ``open_geotiff`` returns a @@ -19,7 +19,7 @@ forwarded to :func:`open_geotiff` through xarray's ``backend_kwargs``:: xr.open_dataset( - "dem.tif", engine="xrspatial_geotiff", + "dem.tif", engine="xrspatial", backend_kwargs={"masked": True, "overview_level": 1}, ) @@ -28,7 +28,7 @@ ``backend_kwargs``. Pass ``chunks=`` directly to ``open_dataset`` to get a dask-backed dataset (xarray wraps the eager read):: - xr.open_dataset("dem.tif", engine="xrspatial_geotiff", chunks={}) + xr.open_dataset("dem.tif", engine="xrspatial", chunks={}) """ from __future__ import annotations diff --git a/xrspatial/geotiff/tests/test_xarray_backend_3365.py b/xrspatial/geotiff/tests/test_xarray_backend_3365.py index 39d98d021..c31803ef8 100644 --- a/xrspatial/geotiff/tests/test_xarray_backend_3365.py +++ b/xrspatial/geotiff/tests/test_xarray_backend_3365.py @@ -4,7 +4,7 @@ pluggable backend API so a GeoTIFF / COG / VRT source opens through the standard entry point:: - xr.open_dataset("dem.tif", engine="xrspatial_geotiff") + xr.open_dataset("dem.tif", engine="xrspatial") ``open_geotiff`` returns a ``DataArray``; the backend promotes it to a one-variable ``Dataset``. These tests drive the wrapper by passing the @@ -160,9 +160,9 @@ def test_entry_point_registered(): CI installs the branch fresh, so the assertion runs there. """ eps = importlib.metadata.entry_points(group="xarray.backends") - matches = [ep for ep in eps if ep.name == "xrspatial_geotiff"] + matches = [ep for ep in eps if ep.name == "xrspatial"] if not matches: pytest.skip( "xrspatial installed without the xarray.backends entry point; " - "reinstall the package to register 'xrspatial_geotiff'.") + "reinstall the package to register the 'xrspatial' engine.") assert matches[0].load() is GeoTIFFBackendEntrypoint