Repository: dask/dask

Issue:
NotImplementedError: Unknown protocol hdfs
After running into issue #1232, I upgraded to the the source version.  hdfs3 is installed and working, but

```
import hdfs3
from dask import dataframe as dd

namenode = 'mynode.com'
port = 8020
hdfs = hdfs3.HDFileSystem(namenode, port)
hdfs.list('/path/to/file.csv')
# returns file node information
data = df.read_csv("hdfs://{0}/path/to/file.csv".format(namenode))
```

This produces the following error

```
NotImplementedErrorTraceback (most recent call last)
<ipython-input-30-2d58fa3887f0> in <module>()
----> 1 data = dd.read_csv('hdfs://{0}/path.to/file.csv'.format(namenode))

/usr/local/share/virtualenvs/cartman/lib/python2.7/site-packages/dask/dataframe/csv.pyc in    read_csv(filename, blocksize, chunkbytes, collection, lineterminator, compression, sample, enforce,  storage_options, **kwargs)

/usr/local/share/virtualenvs/cartman/lib/python2.7/site-packages/dask/bytes/core.pyc in read_bytes(path,   delimiter, not_zero, blocksize, sample, compression, **kwargs)

NotImplementedError: Unknown protocol hdfs://mynode.com/path/to/file.csv
```



Discussion:
You'll have to `import dask.distributed`.  Usually people do this anyway to connect to a remote cluster but we should improve the error messaging regardless.

In particular you need to activate the code in `distributed.hdfs`

We should probably hardcode some of these external paths directly into the `dask.bytes` code.


Resolving patch:
diff --git a/dask/bytes/core.py b/dask/bytes/core.py
--- a/dask/bytes/core.py
+++ b/dask/bytes/core.py
@@ -66,6 +66,7 @@ def read_bytes(urlpath, delimiter=None, not_zero=False, blocksize=2**27,
     storage_options = infer_storage_options(urlpath,
                                             inherit_storage_options=kwargs)
     protocol = storage_options.pop('protocol')
+    ensure_protocol(protocol)
     try:
         read_bytes = _read_bytes[protocol]
     except KeyError:
@@ -137,6 +138,7 @@ def open_files(urlpath, compression=None, **kwargs):
     storage_options = infer_storage_options(urlpath,
                                             inherit_storage_options=kwargs)
     protocol = storage_options.pop('protocol')
+    ensure_protocol(protocol)
     try:
         open_files_backend = _open_files[protocol]
     except KeyError:
@@ -180,6 +182,7 @@ def open_text_files(urlpath, encoding=system_encoding, errors='strict',
                                             inherit_storage_options=kwargs)
     path = storage_options.pop('path')
     protocol = storage_options.pop('protocol')
+    ensure_protocol(protocol)
     if protocol in _open_text_files and compression is None:
         return _open_text_files[protocol](path,
                                           encoding=encoding,
@@ -197,3 +200,28 @@ def open_text_files(urlpath, encoding=system_encoding, errors='strict',
     else:
         raise NotImplementedError("Unknown protocol %s (%s)" %
                                   (protocol, urlpath))
+
+
+def ensure_protocol(protocol):
+    if protocol in _read_bytes or protocol in _open_files:
+        return
+
+    if protocol == 's3':
+        try:
+            import dask.s3
+        except ImportError:
+            raise ImportError("Need to install `s3fs` library for s3 support\n"
+                    "    conda install s3fs -c conda-forge\n"
+                    "    or\n"
+                    "    pip install s3fs")
+
+    elif protocol == 'hdfs':
+        try:
+            import distributed.hdfs
+        except ImportError:
+            raise ImportError("Need to install `distributed` and `hdfs3` "
+                    "for HDFS support\n"
+                    "    conda install distributed hdfs3 -c conda-forge")
+
+    else:
+        raise ValueError("Unknown protocol %s" % protocol)


Test patch:
diff --git a/dask/bytes/tests/test_bytes_utils.py b/dask/bytes/tests/test_bytes_utils.py
--- a/dask/bytes/tests/test_bytes_utils.py
+++ b/dask/bytes/tests/test_bytes_utils.py
@@ -1,5 +1,7 @@
 import io
 
+import pytest
+
 from dask.bytes.utils import read_block, seek_delimiter
 
 
@@ -50,3 +52,17 @@ def test_seek_delimiter_endline():
     f.seek(5)
     seek_delimiter(f, b'\n', 5)
     assert f.tell() == 7
+
+
+def test_ensure_protocol():
+    try:
+        import hdfs3
+        return
+    except ImportError:
+        pass
+
+    dd = pytest.importorskip('dask.dataframe')
+    try:
+        df = dd.read_csv('hdfs://data/*.csv')
+    except ImportError as e:
+        assert "hdfs3" in str(e)