1
1
from __future__ import annotations
2
2
3
+ import warnings
3
4
from collections .abc import Iterable
4
5
from typing import TYPE_CHECKING , Any
5
6
@@ -99,7 +100,7 @@ class PydapDataStore(AbstractDataStore):
99
100
be useful if the netCDF4 library is not available.
100
101
"""
101
102
102
- def __init__ (self , dataset , group = None ):
103
+ def __init__ (self , dataset , group = None , session = None , batch = False , protocol = None ):
103
104
"""
104
105
Parameters
105
106
----------
@@ -109,6 +110,11 @@ def __init__(self, dataset, group=None):
109
110
"""
110
111
self .dataset = dataset
111
112
self .group = group
113
+ self .session = session
114
+ self ._batch = batch
115
+ self ._batch_done = False
116
+ self ._array_cache = {} # holds 1D dimension data
117
+ self ._protocol = protocol
112
118
113
119
@classmethod
114
120
def open (
@@ -121,6 +127,7 @@ def open(
121
127
timeout = None ,
122
128
verify = None ,
123
129
user_charset = None ,
130
+ batch = False ,
124
131
):
125
132
from pydap .client import open_url
126
133
from pydap .net import DEFAULT_TIMEOUT
@@ -135,6 +142,7 @@ def open(
135
142
DeprecationWarning ,
136
143
)
137
144
output_grid = False # new default behavior
145
+
138
146
kwargs = {
139
147
"url" : url ,
140
148
"application" : application ,
@@ -152,12 +160,26 @@ def open(
152
160
dataset = url .ds
153
161
args = {"dataset" : dataset }
154
162
if group :
155
- # only then, change the default
156
163
args ["group" ] = group
164
+ if url .startswith (("https" , "dap2" )):
165
+ args ["protocol" ] = "dap2"
166
+ else :
167
+ args ["protocol" ] = "dap4"
168
+ if batch :
169
+ if args ["protocol" ] == "dap2" :
170
+ warnings .warn (
171
+ f"`batch={ batch } ` is currently only compatible with the `DAP4` "
172
+ "protocol. Make sue the OPeNDAP server implements the `DAP4` "
173
+ "protocol and then replace the scheme of the url with `dap4` "
174
+ "to make use of it. Setting `batch=False`." ,
175
+ stacklevel = 2 ,
176
+ )
177
+ else :
178
+ # only update if dap4
179
+ args ["batch" ] = batch
157
180
return cls (** args )
158
181
159
182
def open_store_variable (self , var ):
160
- data = indexing .LazilyIndexedArray (PydapArrayWrapper (var ))
161
183
try :
162
184
dimensions = [
163
185
dim .split ("/" )[- 1 ] if dim .startswith ("/" ) else dim for dim in var .dims
@@ -166,6 +188,25 @@ def open_store_variable(self, var):
166
188
# GridType does not have a dims attribute - instead get `dimensions`
167
189
# see https://github.com/pydap/pydap/issues/485
168
190
dimensions = var .dimensions
191
+ if (
192
+ self ._protocol == "dap4"
193
+ and var .name in dimensions
194
+ and hasattr (var , "dataset" ) # only True for pydap>3.5.5
195
+ ):
196
+ if not var .dataset ._batch_mode :
197
+ # for dap4, always batch all dimensions at once
198
+ var .dataset .enable_batch_mode ()
199
+ data_array = self ._get_data_array (var )
200
+ data = indexing .LazilyIndexedArray (data_array )
201
+ if not self ._batch and var .dataset ._batch_mode :
202
+ # if `batch=False``, restore it for all other variables
203
+ var .dataset .disable_batch_mode ()
204
+ else :
205
+ # all non-dimension variables
206
+ data = indexing .LazilyIndexedArray (
207
+ PydapArrayWrapper (var , self ._batch , self ._array_cache )
208
+ )
209
+
169
210
return Variable (dimensions , data , var .attributes )
170
211
171
212
def get_variables (self ):
@@ -183,6 +224,7 @@ def get_variables(self):
183
224
# check the key is not a BaseType or GridType
184
225
if not isinstance (self .ds [var ], GroupType )
185
226
]
227
+
186
228
return FrozenDict ((k , self .open_store_variable (self .ds [k ])) for k in _vars )
187
229
188
230
def get_attrs (self ):
@@ -194,9 +236,11 @@ def get_attrs(self):
194
236
"libdap" ,
195
237
"invocation" ,
196
238
"dimensions" ,
239
+ "path" ,
240
+ "Maps" ,
197
241
)
198
- attrs = self .ds .attributes
199
- list (map (attrs .pop , opendap_attrs , [None ] * 6 ))
242
+ attrs = dict ( self .ds .attributes )
243
+ list (map (attrs .pop , opendap_attrs , [None ] * 8 ))
200
244
return Frozen (attrs )
201
245
202
246
def get_dimensions (self ):
@@ -206,6 +250,19 @@ def get_dimensions(self):
206
250
def ds (self ):
207
251
return get_group (self .dataset , self .group )
208
252
253
+ def _get_data_array (self , var ):
254
+ """gets dimension data all at once, storing the numpy
255
+ arrays within a cached dictionary
256
+ """
257
+ from pydap .lib import get_batch_data
258
+
259
+ if not self ._batch_done or var .id not in self ._array_cache :
260
+ # store all dim data into a dict for reuse
261
+ self ._array_cache = get_batch_data (var .parent , self ._array_cache )
262
+ self ._batch_done = True
263
+
264
+ return self ._array_cache [var .id ]
265
+
209
266
210
267
class PydapBackendEntrypoint (BackendEntrypoint ):
211
268
"""
0 commit comments