Skip to content

Commit e2e1b29

Browse files
headtr1ckdcherianjhamman
authored
allow refreshing of backends (#7523)
* allow refreshing of backends * fix forgotten inheritance * fix typing * fix typing in tests * add refresh func to xr.backends * add to whats-new * add func to api * add tests for list_engines and refresh_engines * try fixing test issues * fallback for pyhton 3.9 * use sys.version instead of try * use sys.version in TYPE_CHECKING as well * try fixing type errors in python 3.9 * check if clearing cache makes test pass * add sys.version logic to test * try fixing parallel test fail * refactor BackEntrypoint available logic * remove obsolete code * fix typing * fix typing2 * update api-hidden * remove comma * update whats-new to 2023.04 * Delete cfgrib_.py * Update xarray/tests/test_plugins.py Co-authored-by: Joe Hamman <[email protected]> * Update xarray/tests/test_plugins.py Co-authored-by: Joe Hamman <[email protected]> --------- Co-authored-by: Deepak Cherian <[email protected]> Co-authored-by: Joe Hamman <[email protected]>
1 parent 850156c commit e2e1b29

16 files changed

+304
-131
lines changed

doc/api-hidden.rst

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,6 @@
484484
backends.NetCDF4DataStore.is_remote
485485
backends.NetCDF4DataStore.lock
486486

487-
backends.NetCDF4BackendEntrypoint.available
488487
backends.NetCDF4BackendEntrypoint.description
489488
backends.NetCDF4BackendEntrypoint.url
490489
backends.NetCDF4BackendEntrypoint.guess_can_open
@@ -517,7 +516,6 @@
517516
backends.H5NetCDFStore.sync
518517
backends.H5NetCDFStore.ds
519518

520-
backends.H5netcdfBackendEntrypoint.available
521519
backends.H5netcdfBackendEntrypoint.description
522520
backends.H5netcdfBackendEntrypoint.url
523521
backends.H5netcdfBackendEntrypoint.guess_can_open
@@ -532,7 +530,6 @@
532530
backends.PseudoNetCDFDataStore.open_store_variable
533531
backends.PseudoNetCDFDataStore.ds
534532

535-
backends.PseudoNetCDFBackendEntrypoint.available
536533
backends.PseudoNetCDFBackendEntrypoint.description
537534
backends.PseudoNetCDFBackendEntrypoint.url
538535
backends.PseudoNetCDFBackendEntrypoint.guess_can_open
@@ -547,7 +544,6 @@
547544
backends.PydapDataStore.open
548545
backends.PydapDataStore.open_store_variable
549546

550-
backends.PydapBackendEntrypoint.available
551547
backends.PydapBackendEntrypoint.description
552548
backends.PydapBackendEntrypoint.url
553549
backends.PydapBackendEntrypoint.guess_can_open
@@ -575,7 +571,6 @@
575571
backends.ScipyDataStore.sync
576572
backends.ScipyDataStore.ds
577573

578-
backends.ScipyBackendEntrypoint.available
579574
backends.ScipyBackendEntrypoint.description
580575
backends.ScipyBackendEntrypoint.url
581576
backends.ScipyBackendEntrypoint.guess_can_open
@@ -596,13 +591,11 @@
596591
backends.ZarrStore.sync
597592
backends.ZarrStore.ds
598593

599-
backends.ZarrBackendEntrypoint.available
600594
backends.ZarrBackendEntrypoint.description
601595
backends.ZarrBackendEntrypoint.url
602596
backends.ZarrBackendEntrypoint.guess_can_open
603597
backends.ZarrBackendEntrypoint.open_dataset
604598

605-
backends.StoreBackendEntrypoint.available
606599
backends.StoreBackendEntrypoint.description
607600
backends.StoreBackendEntrypoint.url
608601
backends.StoreBackendEntrypoint.guess_can_open

doc/api.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ Advanced API
10961096
backends.BackendArray
10971097
backends.BackendEntrypoint
10981098
backends.list_engines
1099+
backends.refresh_engines
10991100

11001101
Default, pandas-backed indexes built-in Xarray:
11011102

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ New Features
2626
(:issue:`7686`, :pull:`7689`).
2727
By `Joe Hamman <https://github.com/jhamman>`_.
2828

29+
- Allow refreshing backend engines with :py:meth:`xarray.backends.refresh_engines` (:issue:`7478`, :pull:`7523`).
30+
By `Michael Niklas <https://github.com/headtr1ck>`_.
2931

3032
Breaking changes
3133
~~~~~~~~~~~~~~~~

xarray/backends/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from xarray.backends.h5netcdf_ import H5netcdfBackendEntrypoint, H5NetCDFStore
1313
from xarray.backends.memory import InMemoryDataStore
1414
from xarray.backends.netCDF4_ import NetCDF4BackendEntrypoint, NetCDF4DataStore
15-
from xarray.backends.plugins import list_engines
15+
from xarray.backends.plugins import list_engines, refresh_engines
1616
from xarray.backends.pseudonetcdf_ import (
1717
PseudoNetCDFBackendEntrypoint,
1818
PseudoNetCDFDataStore,
@@ -46,4 +46,5 @@
4646
"StoreBackendEntrypoint",
4747
"ZarrBackendEntrypoint",
4848
"list_engines",
49+
"refresh_engines",
4950
]

xarray/backends/common.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
if TYPE_CHECKING:
1818
from io import BufferedIOBase
1919

20+
from xarray.core.dataset import Dataset
21+
2022
# Create a logger object, but don't add any handlers. Leave that to user code.
2123
logger = logging.getLogger(__name__)
2224

@@ -377,9 +379,6 @@ class BackendEntrypoint:
377379
Attributes
378380
----------
379381
380-
available : bool, default: True
381-
Indicate wether this backend is available given the installed packages.
382-
The setting of this attribute is not mandatory.
383382
open_dataset_parameters : tuple, default: None
384383
A list of ``open_dataset`` method parameters.
385384
The setting of this attribute is not mandatory.
@@ -391,8 +390,6 @@ class BackendEntrypoint:
391390
The setting of this attribute is not mandatory.
392391
"""
393392

394-
available: ClassVar[bool] = True
395-
396393
open_dataset_parameters: ClassVar[tuple | None] = None
397394
description: ClassVar[str] = ""
398395
url: ClassVar[str] = ""
@@ -408,9 +405,10 @@ def __repr__(self) -> str:
408405
def open_dataset(
409406
self,
410407
filename_or_obj: str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore,
408+
*,
411409
drop_variables: str | Iterable[str] | None = None,
412410
**kwargs: Any,
413-
):
411+
) -> Dataset:
414412
"""
415413
Backend open_dataset method used by Xarray in :py:func:`~xarray.open_dataset`.
416414
"""
@@ -420,12 +418,13 @@ def open_dataset(
420418
def guess_can_open(
421419
self,
422420
filename_or_obj: str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore,
423-
):
421+
) -> bool:
424422
"""
425423
Backend open_dataset method used by Xarray in :py:func:`~xarray.open_dataset`.
426424
"""
427425

428426
return False
429427

430428

431-
BACKEND_ENTRYPOINTS: dict[str, type[BackendEntrypoint]] = {}
429+
# mapping of engine name to (module name, BackendEntrypoint Class)
430+
BACKEND_ENTRYPOINTS: dict[str, tuple[str | None, type[BackendEntrypoint]]] = {}

xarray/backends/h5netcdf_.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import functools
44
import io
55
import os
6+
from collections.abc import Iterable
7+
from typing import TYPE_CHECKING, Any
68

79
from packaging.version import Version
810

@@ -27,12 +29,17 @@
2729
from xarray.core.utils import (
2830
FrozenDict,
2931
is_remote_uri,
30-
module_available,
3132
read_magic_number_from_file,
3233
try_read_magic_number_from_file_or_path,
3334
)
3435
from xarray.core.variable import Variable
3536

37+
if TYPE_CHECKING:
38+
from io import BufferedIOBase
39+
40+
from xarray.backends.common import AbstractDataStore
41+
from xarray.core.dataset import Dataset
42+
3643

3744
class H5NetCDFArrayWrapper(BaseNetCDF4Array):
3845
def get_array(self, needs_lock=True):
@@ -365,33 +372,34 @@ class H5netcdfBackendEntrypoint(BackendEntrypoint):
365372
backends.ScipyBackendEntrypoint
366373
"""
367374

368-
available = module_available("h5netcdf")
369375
description = (
370376
"Open netCDF (.nc, .nc4 and .cdf) and most HDF5 files using h5netcdf in Xarray"
371377
)
372378
url = "https://docs.xarray.dev/en/stable/generated/xarray.backends.H5netcdfBackendEntrypoint.html"
373379

374-
def guess_can_open(self, filename_or_obj):
380+
def guess_can_open(
381+
self,
382+
filename_or_obj: str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore,
383+
) -> bool:
375384
magic_number = try_read_magic_number_from_file_or_path(filename_or_obj)
376385
if magic_number is not None:
377386
return magic_number.startswith(b"\211HDF\r\n\032\n")
378387

379-
try:
388+
if isinstance(filename_or_obj, (str, os.PathLike)):
380389
_, ext = os.path.splitext(filename_or_obj)
381-
except TypeError:
382-
return False
390+
return ext in {".nc", ".nc4", ".cdf"}
383391

384-
return ext in {".nc", ".nc4", ".cdf"}
392+
return False
385393

386-
def open_dataset(
394+
def open_dataset( # type: ignore[override] # allow LSP violation, not supporting **kwargs
387395
self,
388-
filename_or_obj,
396+
filename_or_obj: str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore,
389397
*,
390398
mask_and_scale=True,
391399
decode_times=True,
392400
concat_characters=True,
393401
decode_coords=True,
394-
drop_variables=None,
402+
drop_variables: str | Iterable[str] | None = None,
395403
use_cftime=None,
396404
decode_timedelta=None,
397405
format=None,
@@ -400,7 +408,7 @@ def open_dataset(
400408
invalid_netcdf=None,
401409
phony_dims=None,
402410
decode_vlen_strings=True,
403-
):
411+
) -> Dataset:
404412
filename_or_obj = _normalize_path(filename_or_obj)
405413
store = H5NetCDFStore.open(
406414
filename_or_obj,
@@ -427,4 +435,4 @@ def open_dataset(
427435
return ds
428436

429437

430-
BACKEND_ENTRYPOINTS["h5netcdf"] = H5netcdfBackendEntrypoint
438+
BACKEND_ENTRYPOINTS["h5netcdf"] = ("h5netcdf", H5netcdfBackendEntrypoint)

xarray/backends/netCDF4_.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import functools
44
import operator
55
import os
6+
from collections.abc import Iterable
67
from contextlib import suppress
8+
from typing import TYPE_CHECKING, Any
79

810
import numpy as np
911

@@ -33,11 +35,16 @@
3335
FrozenDict,
3436
close_on_error,
3537
is_remote_uri,
36-
module_available,
3738
try_read_magic_number_from_path,
3839
)
3940
from xarray.core.variable import Variable
4041

42+
if TYPE_CHECKING:
43+
from io import BufferedIOBase
44+
45+
from xarray.backends.common import AbstractDataStore
46+
from xarray.core.dataset import Dataset
47+
4148
# This lookup table maps from dtype.byteorder to a readable endian
4249
# string used by netCDF4.
4350
_endian_lookup = {"=": "native", ">": "big", "<": "little", "|": "native"}
@@ -535,33 +542,37 @@ class NetCDF4BackendEntrypoint(BackendEntrypoint):
535542
backends.ScipyBackendEntrypoint
536543
"""
537544

538-
available = module_available("netCDF4")
539545
description = (
540546
"Open netCDF (.nc, .nc4 and .cdf) and most HDF5 files using netCDF4 in Xarray"
541547
)
542548
url = "https://docs.xarray.dev/en/stable/generated/xarray.backends.NetCDF4BackendEntrypoint.html"
543549

544-
def guess_can_open(self, filename_or_obj):
550+
def guess_can_open(
551+
self,
552+
filename_or_obj: str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore,
553+
) -> bool:
545554
if isinstance(filename_or_obj, str) and is_remote_uri(filename_or_obj):
546555
return True
547556
magic_number = try_read_magic_number_from_path(filename_or_obj)
548557
if magic_number is not None:
549558
# netcdf 3 or HDF5
550559
return magic_number.startswith((b"CDF", b"\211HDF\r\n\032\n"))
551-
try:
560+
561+
if isinstance(filename_or_obj, (str, os.PathLike)):
552562
_, ext = os.path.splitext(filename_or_obj)
553-
except TypeError:
554-
return False
555-
return ext in {".nc", ".nc4", ".cdf"}
563+
return ext in {".nc", ".nc4", ".cdf"}
564+
565+
return False
556566

557-
def open_dataset(
567+
def open_dataset( # type: ignore[override] # allow LSP violation, not supporting **kwargs
558568
self,
559-
filename_or_obj,
569+
filename_or_obj: str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore,
570+
*,
560571
mask_and_scale=True,
561572
decode_times=True,
562573
concat_characters=True,
563574
decode_coords=True,
564-
drop_variables=None,
575+
drop_variables: str | Iterable[str] | None = None,
565576
use_cftime=None,
566577
decode_timedelta=None,
567578
group=None,
@@ -572,7 +583,7 @@ def open_dataset(
572583
persist=False,
573584
lock=None,
574585
autoclose=False,
575-
):
586+
) -> Dataset:
576587
filename_or_obj = _normalize_path(filename_or_obj)
577588
store = NetCDF4DataStore.open(
578589
filename_or_obj,
@@ -601,4 +612,4 @@ def open_dataset(
601612
return ds
602613

603614

604-
BACKEND_ENTRYPOINTS["netcdf4"] = NetCDF4BackendEntrypoint
615+
BACKEND_ENTRYPOINTS["netcdf4"] = ("netCDF4", NetCDF4BackendEntrypoint)

0 commit comments

Comments
 (0)