Skip to content

Commit 3fb5cbb

Browse files
mrpgraaeshoyer
authored andcommitted
Support opening password protected datasets over Opendap (Fixes #1068) (#1570)
* Use the PydapDataStore.open() classmethod * Added test for pydap password support * Added pydap password change to whats-new.rst * Changed test_password to test_session * Documented type of ds in PydapDataStore * Fixed documentation * Removed unused import * Added docs for using sessions with pydap * Fixed typo * Fixed formatting after merge
1 parent ae4df1d commit 3fb5cbb

File tree

5 files changed

+62
-3
lines changed

5 files changed

+62
-3
lines changed

doc/io.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,38 @@ over the network until we look at particular values:
388388

389389
.. image:: _static/opendap-prism-tmax.png
390390

391+
Some servers require authentication before we can access the data. For this
392+
purpose we can explicitly create a :py:class:`~xarray.backends.PydapDataStore`
393+
and pass in a `Requests`__ session object. For example for
394+
HTTP Basic authentication::
395+
396+
import xarray as xr
397+
import requests
398+
399+
session = requests.Session()
400+
session.auth = ('username', 'password')
401+
402+
store = xr.backends.PydapDataStore.open('http://example.com/data',
403+
session=session)
404+
ds = xr.open_dataset(store)
405+
406+
`Pydap's cas module`__ has functions that generate custom sessions for
407+
servers that use CAS single sign-on. For example, to connect to servers
408+
that require NASA's URS authentication::
409+
410+
import xarray as xr
411+
from pydata.cas.urs import setup_session
412+
413+
ds_url = 'https://gpm1.gesdisc.eosdis.nasa.gov/opendap/hyrax/example.nc'
414+
415+
session = setup_session('username', 'password', check_url=ds_url)
416+
store = xr.backends.PydapDataStore.open(ds_url, session=session)
417+
418+
ds = xr.open_dataset(store)
419+
420+
__ http://docs.python-requests.org
421+
__ http://pydap.readthedocs.io/en/latest/client.html#authentication
422+
391423
.. _io.rasterio:
392424

393425
Rasterio

doc/whats-new.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ Enhancements
111111
By `Joe Hamman <https://github.com/jhamman>`_ and
112112
`Gerrit Holl <https://github.com/gerritholl>`_.
113113

114+
- Changed :py:class:`~xarray.backends.PydapDataStore` to take a Pydap dataset.
115+
This permits opening Opendap datasets that require authentication, by
116+
instantiating a Pydap dataset with a session object. Also added
117+
:py:meth:`xarray.backends.PydapDataStore.open` which takes a url and session
118+
object (:issue:`1068`).
119+
By `Philip Graae <https://github.com/mrpgraae>`_.
120+
114121
- Support applying rolling window operations using bottleneck's moving window
115122
functions on data stored as dask arrays (:issue:`1279`).
116123
By `Joe Hamman <https://github.com/jhamman>`_.

xarray/backends/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ def maybe_decode_store(store, lock=False):
288288
store = backends.ScipyDataStore(filename_or_obj,
289289
autoclose=autoclose)
290290
elif engine == 'pydap':
291-
store = backends.PydapDataStore(filename_or_obj)
291+
store = backends.PydapDataStore.open(filename_or_obj)
292292
elif engine == 'h5netcdf':
293293
store = backends.H5NetCDFStore(filename_or_obj, group=group,
294294
autoclose=autoclose)

xarray/backends/pydap_.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,19 @@ class PydapDataStore(AbstractDataStore):
6060
This store provides an alternative way to access OpenDAP datasets that may
6161
be useful if the netCDF4 library is not available.
6262
"""
63-
def __init__(self, url):
63+
def __init__(self, ds):
64+
"""
65+
Parameters
66+
----------
67+
ds : pydap DatasetType
68+
"""
69+
self.ds = ds
70+
71+
@classmethod
72+
def open(cls, url, session=None):
6473
import pydap.client
65-
self.ds = pydap.client.open_url(url)
74+
ds = pydap.client.open_url(url, session=session)
75+
return cls(ds)
6676

6777
def open_store_variable(self, var):
6878
data = indexing.LazilyIndexedArray(PydapArrayWrapper(var))

xarray/tests/test_backends.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
assert_identical)
3232
from .test_dataset import create_test_data
3333

34+
from xarray.tests import mock
35+
3436
try:
3537
import netCDF4 as nc4
3638
except ImportError:
@@ -1509,6 +1511,14 @@ def test_cmp_local_file(self):
15091511
self.assertDatasetEqual(actual.isel(j=slice(1, 2)),
15101512
expected.isel(j=slice(1, 2)))
15111513

1514+
def test_session(self):
1515+
from pydap.cas.urs import setup_session
1516+
1517+
session = setup_session('XarrayTestUser', 'Xarray2017')
1518+
with mock.patch('pydap.client.open_url') as mock_func:
1519+
xr.backends.PydapDataStore.open('http://test.url', session=session)
1520+
mock_func.assert_called_with('http://test.url', session=session)
1521+
15121522
@requires_dask
15131523
def test_dask(self):
15141524
with self.create_datasets(chunks={'j': 2}) as (actual, expected):

0 commit comments

Comments
 (0)