1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
|
import numpy as np
from ..core import indexing
from ..core.pycompat import integer_types
from ..core.utils import Frozen, FrozenDict, is_dict_like
from ..core.variable import Variable
from .common import AbstractDataStore, BackendArray, robust_getitem
class PydapArrayWrapper(BackendArray):
def __init__(self, array):
self.array = array
@property
def shape(self):
return self.array.shape
@property
def dtype(self):
return self.array.dtype
def __getitem__(self, key):
return indexing.explicit_indexing_adapter(
key, self.shape, indexing.IndexingSupport.BASIC, self._getitem
)
def _getitem(self, key):
# pull the data from the array attribute if possible, to avoid
# downloading coordinate data twice
array = getattr(self.array, "array", self.array)
result = robust_getitem(array, key, catch=ValueError)
# in some cases, pydap doesn't squeeze axes automatically like numpy
axis = tuple(n for n, k in enumerate(key) if isinstance(k, integer_types))
if result.ndim + len(axis) != array.ndim and len(axis) > 0:
result = np.squeeze(result, axis)
return result
def _fix_attributes(attributes):
attributes = dict(attributes)
for k in list(attributes):
if k.lower() == "global" or k.lower().endswith("_global"):
# move global attributes to the top level, like the netcdf-C
# DAP client
attributes.update(attributes.pop(k))
elif is_dict_like(attributes[k]):
# Make Hierarchical attributes to a single level with a
# dot-separated key
attributes.update(
{
f"{k}.{k_child}": v_child
for k_child, v_child in attributes.pop(k).items()
}
)
return attributes
class PydapDataStore(AbstractDataStore):
"""Store for accessing OpenDAP datasets with pydap.
This store provides an alternative way to access OpenDAP datasets that may
be useful if the netCDF4 library is not available.
"""
def __init__(self, ds):
"""
Parameters
----------
ds : pydap DatasetType
"""
self.ds = ds
@classmethod
def open(cls, url, session=None):
import pydap.client
ds = pydap.client.open_url(url, session=session)
return cls(ds)
def open_store_variable(self, var):
data = indexing.LazilyOuterIndexedArray(PydapArrayWrapper(var))
return Variable(var.dimensions, data, _fix_attributes(var.attributes))
def get_variables(self):
return FrozenDict(
(k, self.open_store_variable(self.ds[k])) for k in self.ds.keys()
)
def get_attrs(self):
return Frozen(_fix_attributes(self.ds.attributes))
def get_dimensions(self):
return Frozen(self.ds.dimensions)
|