Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Backend entrypoint #3166

Closed
wants to merge 8 commits into from
Closed
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
1 change: 1 addition & 0 deletions ci/requirements/py36-hypothesis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ dependencies:
- zarr
- pydap
- lxml
- entrypoints
1 change: 1 addition & 0 deletions ci/requirements/py36.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ dependencies:
- iris>=1.10
- pydap
- lxml
- entrypoints
- pip:
- mypy==0.711
1 change: 1 addition & 0 deletions ci/requirements/py37-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ dependencies:
- rasterio
- boto3
- zarr
- entrypoints
1 change: 1 addition & 0 deletions ci/requirements/py37.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies:
- cfgrib>=0.9.2
- lxml
- pydap
- entrypoints
- pip:
- mypy==0.650
- numbagg
1 change: 1 addition & 0 deletions doc/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ dependencies:
- pillow=5.4.1
- sphinx_rtd_theme=0.4.2
- mock=2.0.0
- entrypoints=0.3
- pip
14 changes: 13 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@
- SciPy2015 talk: https://www.youtube.com/watch?v=X0pAhJgySxk
""" # noqa

ENTRY_POINTS = {
'xarray.backends': [
'netcdf4 = xarray.backends:NetCDF4DataStore.open',
'scipy = xarray.backends:ScipyDataStore',
'pydap = xarray.backends:PydapDataStore.open',
'h5netcdf = xarray.backends:H5NetCDFStore',
'pynio = xarray.backends:NioDataStore',
'pseudonetcdf = xarray.backends:PseudoNetCDFDataStore.open',
'cfgrib = xarray.backends:CfGribDataStore',
]
}

setup(name=DISTNAME,
version=versioneer.get_version(),
Expand All @@ -104,4 +115,5 @@
tests_require=TESTS_REQUIRE,
url=URL,
packages=find_packages(),
package_data={'xarray': ['py.typed', 'tests/data/*']})
package_data={'xarray': ['py.typed', 'tests/data/*']},
entry_points=ENTRY_POINTS)
74 changes: 32 additions & 42 deletions xarray/backends/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,17 @@ def _get_default_engine(path, allow_remote=False):
return engine


def _get_backend_cls(engine):
import entrypoints
try:
return entrypoints.get_single('xarray.backends', engine).load()
except entrypoints.NoSuchEntryPoint:
all_entrypoints = entrypoints.get_group_named('xarray.backends')
raise ValueError('unrecognized engine for open_dataset: {}\n'
'must be one of: {}'
.format(engine, list(all_entrypoints.keys())))


def _normalize_path(path):
if is_remote_uri(path):
return path
Expand Down Expand Up @@ -352,12 +363,6 @@ def open_dataset(filename_or_obj, group=None, decode_cf=True,
--------
open_mfdataset
"""
engines = [None, 'netcdf4', 'scipy', 'pydap', 'h5netcdf', 'pynio',
'cfgrib', 'pseudonetcdf']
if engine not in engines:
raise ValueError('unrecognized engine for open_dataset: {}\n'
'must be one of: {}'
.format(engine, engines))

if autoclose is not None:
warnings.warn(
Expand All @@ -382,6 +387,7 @@ def open_dataset(filename_or_obj, group=None, decode_cf=True,

if backend_kwargs is None:
backend_kwargs = {}
extra_kwargs = {}

def maybe_decode_store(store, lock=False):
ds = conventions.decode_cf(
Expand Down Expand Up @@ -417,44 +423,28 @@ def maybe_decode_store(store, lock=False):

if isinstance(filename_or_obj, AbstractDataStore):
store = filename_or_obj
else:
if isinstance(filename_or_obj, str):
filename_or_obj = _normalize_path(filename_or_obj)

elif isinstance(filename_or_obj, str):
filename_or_obj = _normalize_path(filename_or_obj)

if engine is None:
engine = _get_default_engine(filename_or_obj,
allow_remote=True)
if engine == 'netcdf4':
store = backends.NetCDF4DataStore.open(
filename_or_obj, group=group, lock=lock, **backend_kwargs)
elif engine == 'scipy':
store = backends.ScipyDataStore(filename_or_obj, **backend_kwargs)
elif engine == 'pydap':
store = backends.PydapDataStore.open(
filename_or_obj, **backend_kwargs)
elif engine == 'h5netcdf':
store = backends.H5NetCDFStore(
filename_or_obj, group=group, lock=lock, **backend_kwargs)
elif engine == 'pynio':
store = backends.NioDataStore(
filename_or_obj, lock=lock, **backend_kwargs)
elif engine == 'pseudonetcdf':
store = backends.PseudoNetCDFDataStore.open(
filename_or_obj, lock=lock, **backend_kwargs)
elif engine == 'cfgrib':
store = backends.CfGribDataStore(
filename_or_obj, lock=lock, **backend_kwargs)
if engine is None:
engine = _get_default_engine(filename_or_obj,
allow_remote=True)

else:
if engine not in [None, 'scipy', 'h5netcdf']:
raise ValueError("can only read bytes or file-like objects "
"with engine='scipy' or 'h5netcdf'")
engine = _get_engine_from_magic_number(filename_or_obj)
if engine == 'scipy':
store = backends.ScipyDataStore(filename_or_obj, **backend_kwargs)
elif engine == 'h5netcdf':
store = backends.H5NetCDFStore(filename_or_obj, group=group,
lock=lock, **backend_kwargs)
else:
if engine not in [None, 'scipy', 'h5netcdf']:
raise ValueError("can only read bytes or file-like objects "
"with engine='scipy' or 'h5netcdf'")
engine = _get_engine_from_magic_number(filename_or_obj)

if engine in ['netcdf4', 'h5netcdf']:
extra_kwargs['group'] = group
extra_kwargs['lock'] = lock
elif engine in ['pynio', 'pseudonetcdf', 'cfgrib']:
extra_kwargs['lock'] = lock

opener = _get_backend_cls(engine)
store = opener(filename_or_obj, **backend_kwargs, **extra_kwargs)

with close_on_error(store):
ds = maybe_decode_store(store)
Expand Down
2 changes: 1 addition & 1 deletion xarray/tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -2019,7 +2019,7 @@ def test_engine(self):
open_dataset(tmp_file, engine='foobar')

netcdf_bytes = data.to_netcdf()
with raises_regex(ValueError, 'unrecognized engine'):
with raises_regex(ValueError, 'can only read bytes or file-like'):
open_dataset(BytesIO(netcdf_bytes), engine='foobar')

def test_cross_engine_read_write_netcdf3(self):
Expand Down