Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ Deprecations
Bug Fixes
~~~~~~~~~

- :py:func:`~xarray.open_dataset` now raises an error pointing at
:py:func:`~xarray.open_mfdataset` when it is given a list or tuple of paths,
instead of reporting that no IO backend matched the input (:issue:`6510`).
By `NoiceHex <https://github.com/NoiceHax>`_.
- Fix async zarr tests using ``wraps`` with ``autospec=True`` on async methods,
which caused ``AsyncMock`` objects to leak through instead of real array data
(:pull:`11232`).
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ Claus = "Claus"
Celles = "Celles"
slowy = "slowy"
Commun = "Commun"
Noice = "Noice"

# Tests
Ome = "Ome"
Expand Down
6 changes: 6 additions & 0 deletions xarray/backends/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@ def guess_engine(
if not is_remote_uri(store_spec_str) and not os.path.exists(store_spec_str):
raise FileNotFoundError(f"No such file: '{store_spec_str}'")

if isinstance(store_spec, list | tuple):
raise ValueError(
f"open_dataset opens a single file, but got a {type(store_spec).__name__}. "
"Use open_mfdataset to open multiple files as a single dataset."
)

raise ValueError(error_msg)


Expand Down
10 changes: 10 additions & 0 deletions xarray/tests/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,16 @@ def test_guess_engine_file_not_found() -> None:
plugins.guess_engine("https://example.com/missing.h5")


@mock.patch(
"xarray.backends.plugins.list_engines",
mock.MagicMock(return_value={"dummy": DummyBackendEntrypointArgs()}),
)
@pytest.mark.parametrize("paths", [["a.nc", "b.nc"], ("a.nc", "b.nc")])
def test_guess_engine_sequence_of_paths(paths) -> None:
with pytest.raises(ValueError, match=r"Use open_mfdataset"):
plugins.guess_engine(paths)


@pytest.mark.parametrize("engine", common.BACKEND_ENTRYPOINTS.keys())
def test_get_backend_fastpath_skips_list_engines(engine: str) -> None:
"""Test that built-in engines skip list_engines (fastpath)."""
Expand Down
Loading