3636
3737
3838class PydapArrayWrapper (BackendArray ):
39- def __init__ (self , array ):
39+ def __init__ (self , array , checksums = True ):
4040 self .array = array
4141
4242 @property
@@ -54,12 +54,10 @@ def __getitem__(self, key):
5454
5555 def _getitem (self , key ):
5656 result = robust_getitem (self .array , key , catch = ValueError )
57- # in some cases, pydap doesn't squeeze axes automatically like numpy
58- result = np .asarray (result )
57+ result = np .asarray (result .data )
5958 axis = tuple (n for n , k in enumerate (key ) if isinstance (k , integer_types ))
6059 if result .ndim + len (axis ) != self .array .ndim and axis :
6160 result = np .squeeze (result , axis )
62-
6361 return result
6462
6563
@@ -82,7 +80,14 @@ class PydapDataStore(AbstractDataStore):
8280 be useful if the netCDF4 library is not available.
8381 """
8482
85- def __init__ (self , dataset , group = None ):
83+ def __init__ (
84+ self ,
85+ dataset ,
86+ group = None ,
87+ session = None ,
88+ protocol = None ,
89+ checksums = True ,
90+ ):
8691 """
8792 Parameters
8893 ----------
@@ -92,6 +97,8 @@ def __init__(self, dataset, group=None):
9297 """
9398 self .dataset = dataset
9499 self .group = group
100+ self ._protocol = protocol
101+ self ._checksums = checksums # true by default
95102
96103 @classmethod
97104 def open (
@@ -104,6 +111,7 @@ def open(
104111 timeout = None ,
105112 verify = None ,
106113 user_charset = None ,
114+ checksums = True ,
107115 ):
108116 from pydap .client import open_url
109117 from pydap .net import DEFAULT_TIMEOUT
@@ -118,6 +126,7 @@ def open(
118126 DeprecationWarning ,
119127 )
120128 output_grid = False # new default behavior
129+
121130 kwargs = {
122131 "url" : url ,
123132 "application" : application ,
@@ -133,22 +142,37 @@ def open(
133142 elif hasattr (url , "ds" ):
134143 # pydap dataset
135144 dataset = url .ds
136- args = {"dataset" : dataset }
145+ args = {"dataset" : dataset , "checksums" : checksums }
137146 if group :
138- # only then, change the default
139147 args ["group" ] = group
148+ if url .startswith (("http" , "dap2" )):
149+ args ["protocol" ] = "dap2"
150+ elif url .startswith ("dap4" ):
151+ args ["protocol" ] = "dap4"
140152 return cls (** args )
141153
142154 def open_store_variable (self , var ):
143- data = indexing .LazilyIndexedArray (PydapArrayWrapper (var ))
144- try :
155+ if hasattr (var , "dims" ):
145156 dimensions = [
146157 dim .split ("/" )[- 1 ] if dim .startswith ("/" ) else dim for dim in var .dims
147158 ]
148- except AttributeError :
159+ else :
149160 # GridType does not have a dims attribute - instead get `dimensions`
150161 # see https://github.com/pydap/pydap/issues/485
151162 dimensions = var .dimensions
163+ if (
164+ self ._protocol == "dap4"
165+ and var .name in dimensions
166+ and hasattr (var , "dataset" ) # only True for pydap>3.5.5
167+ ):
168+ var .dataset .enable_batch_mode ()
169+ data_array = self ._get_data_array (var )
170+ data = indexing .LazilyIndexedArray (data_array )
171+ var .dataset .disable_batch_mode ()
172+ else :
173+ # all non-dimension variables
174+ data = indexing .LazilyIndexedArray (PydapArrayWrapper (var ))
175+
152176 return Variable (dimensions , data , var .attributes )
153177
154178 def get_variables (self ):
@@ -166,6 +190,7 @@ def get_variables(self):
166190 # check the key is not a BaseType or GridType
167191 if not isinstance (self .ds [var ], GroupType )
168192 ]
193+
169194 return FrozenDict ((k , self .open_store_variable (self .ds [k ])) for k in _vars )
170195
171196 def get_attrs (self ):
@@ -177,18 +202,33 @@ def get_attrs(self):
177202 "libdap" ,
178203 "invocation" ,
179204 "dimensions" ,
205+ "path" ,
206+ "Maps" ,
180207 )
181- attrs = self .ds .attributes
182- list (map (attrs .pop , opendap_attrs , [None ] * 6 ))
208+ attrs = dict ( self .ds .attributes )
209+ list (map (attrs .pop , opendap_attrs , [None ] * len ( opendap_attrs ) ))
183210 return Frozen (attrs )
184211
185212 def get_dimensions (self ):
186- return Frozen (self .ds .dimensions )
213+ return Frozen (sorted ( self .ds .dimensions ) )
187214
188215 @property
189216 def ds (self ):
190217 return get_group (self .dataset , self .group )
191218
219+ def _get_data_array (self , var ):
220+ """gets dimension data all at once, storing the numpy
221+ arrays within a cached dictionary
222+ """
223+ from pydap .client import get_batch_data
224+
225+ if not var ._is_data_loaded ():
226+ # data has not been deserialized yet
227+ # runs only once per store/hierarchy
228+ get_batch_data (var , checksums = self ._checksums )
229+
230+ return self .dataset [var .id ].data
231+
192232
193233class PydapBackendEntrypoint (BackendEntrypoint ):
194234 """
@@ -250,6 +290,7 @@ def open_dataset(
250290 timeout = None ,
251291 verify = None ,
252292 user_charset = None ,
293+ checksums = True ,
253294 ) -> Dataset :
254295 store = PydapDataStore .open (
255296 url = filename_or_obj ,
@@ -260,6 +301,7 @@ def open_dataset(
260301 timeout = timeout ,
261302 verify = verify ,
262303 user_charset = user_charset ,
304+ checksums = checksums ,
263305 )
264306 store_entrypoint = StoreBackendEntrypoint ()
265307 with close_on_error (store ):
@@ -292,6 +334,7 @@ def open_datatree(
292334 timeout = None ,
293335 verify = None ,
294336 user_charset = None ,
337+ checksums = True ,
295338 ) -> DataTree :
296339 groups_dict = self .open_groups_as_dict (
297340 filename_or_obj ,
@@ -303,11 +346,12 @@ def open_datatree(
303346 use_cftime = use_cftime ,
304347 decode_timedelta = decode_timedelta ,
305348 group = group ,
306- application = None ,
307- session = None ,
308- timeout = None ,
309- verify = None ,
310- user_charset = None ,
349+ application = application ,
350+ session = session ,
351+ timeout = timeout ,
352+ verify = verify ,
353+ user_charset = user_charset ,
354+ checksums = checksums ,
311355 )
312356
313357 return datatree_from_dict_with_io_cleanup (groups_dict )
@@ -329,6 +373,7 @@ def open_groups_as_dict(
329373 timeout = None ,
330374 verify = None ,
331375 user_charset = None ,
376+ checksums = True ,
332377 ) -> dict [str , Dataset ]:
333378 from xarray .core .treenode import NodePath
334379
@@ -340,6 +385,7 @@ def open_groups_as_dict(
340385 timeout = timeout ,
341386 verify = verify ,
342387 user_charset = user_charset ,
388+ checksums = checksums ,
343389 )
344390
345391 # Check for a group and make it a parent if it exists
0 commit comments