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

Support opening password protected datasets over Opendap (Fixes #1068) #1570

Merged
merged 12 commits into from
Sep 15, 2017
32 changes: 32 additions & 0 deletions doc/io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,38 @@ over the network until we look at particular values:

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

Some servers require authentication before we can access the data. For this
purpose we can explicitly create a :py:class:`~xarray.backends.PydapDataStore`
and pass in a `Requests`__ session object. For example for
HTTP Basic authentication::

import xarray as xr
import requests

session = requests.Session()
session.auth = ('username', 'password')

store = xr.backends.PydapDataStore.open('http://example.com/data',
session=session)
ds = xr.open_dataset(store)

`Pydap's cas module`__ has functions that generate custom sessions for
servers that use CAS single sign-on. For example, to connect to servers
that require NASA's URS authentication::

import xarray as xr
from pydata.cas.urs import setup_session

ds_url = 'https://gpm1.gesdisc.eosdis.nasa.gov/opendap/hyrax/example.nc'

session = setup_session('username', 'password', check_url=ds_url)
store = xr.backends.PydapDataStore.open(ds_url, session=session)

ds = xr.open_dataset(store)

__ http://docs.python-requests.org
__ http://pydap.readthedocs.io/en/latest/client.html#authentication

.. _io.rasterio:

Rasterio
Expand Down
7 changes: 7 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ Enhancements
By `Joe Hamman <https://github.com/jhamman>`_ and
`Gerrit Holl <https://github.com/gerritholl>`_.

- Changed :py:class:`~xarray.backends.PydapDataStore` to take a Pydap dataset.
This permits opening Opendap datasets that require authentication, by
instantiating a Pydap dataset with a session object. Also added
:py:meth:`xarray.backends.PydapDataStore.open` which takes a url and session
object (:issue:`1068`).
By `Philip Graae <https://github.com/mrpgraae>`_.

- Support applying rolling window operations using bottleneck's moving window
functions on data stored as dask arrays (:issue:`1279`).
By `Joe Hamman <https://github.com/jhamman>`_.
Expand Down
2 changes: 1 addition & 1 deletion xarray/backends/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def maybe_decode_store(store, lock=False):
store = backends.ScipyDataStore(filename_or_obj,
autoclose=autoclose)
elif engine == 'pydap':
store = backends.PydapDataStore(filename_or_obj)
store = backends.PydapDataStore.open(filename_or_obj)
elif engine == 'h5netcdf':
store = backends.H5NetCDFStore(filename_or_obj, group=group,
autoclose=autoclose)
Expand Down
14 changes: 12 additions & 2 deletions xarray/backends/pydap_.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,19 @@ class PydapDataStore(AbstractDataStore):
This store provides an alternative way to access OpenDAP datasets that may
be useful if the netCDF4 library is not available.
"""
def __init__(self, url):
def __init__(self, ds):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add a docstring that mentions the type of ds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It didn't seem like you had any preferred docstring format, so i just used the Numpy style. Hope that's fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do try to stick with numpy-style :)

"""
Parameters
----------
ds : pydap DatasetType
"""
self.ds = ds

@classmethod
def open(cls, url, session=None):
import pydap.client
self.ds = pydap.client.open_url(url)
ds = pydap.client.open_url(url, session=session)
return cls(ds)

def open_store_variable(self, var):
data = indexing.LazilyIndexedArray(PydapArrayWrapper(var))
Expand Down
10 changes: 10 additions & 0 deletions xarray/tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
assert_identical)
from .test_dataset import create_test_data

from xarray.tests import mock

try:
import netCDF4 as nc4
except ImportError:
Expand Down Expand Up @@ -1509,6 +1511,14 @@ def test_cmp_local_file(self):
self.assertDatasetEqual(actual.isel(j=slice(1, 2)),
expected.isel(j=slice(1, 2)))

def test_session(self):
from pydap.cas.urs import setup_session

session = setup_session('XarrayTestUser', 'Xarray2017')
with mock.patch('pydap.client.open_url') as mock_func:
xr.backends.PydapDataStore.open('http://test.url', session=session)
mock_func.assert_called_with('http://test.url', session=session)

@requires_dask
def test_dask(self):
with self.create_datasets(chunks={'j': 2}) as (actual, expected):
Expand Down