Repository: intake/intake

Issue:
Regression: internals require API that is not always defined
It seems as if not all Catalogs implement `_container`, and so this change

```diff
-            return e(name=key)
+            if e._container == 'catalog':
+                return e(name=key)
+            return e()
```

in https://github.com/intake/intake/commit/4aa561c86503d609ed73a5ae9c7e9256b6560bb4 creates some issues. Here's a minimal reproducible example using only built-in intake objects.

```py
In [1]: import pandas

In [2]: df = pandas.DataFrame({'a': [1,2,3], 'b': [4,5,6]})

In [3]: df.to_csv('file.csv')

In [4]: from intake.source.csv import CSVSource

In [5]: from intake import Catalog
/home/dallan/Repos/bnl/intake/intake/__init__.py:43: UserWarning: deprecation: intake.Catalog now references the base class intake.catalog.base.Catalog
 If you want to open a generic URL, you should use intake.open_catalog
  warnings.warn('deprecation: intake.Catalog now references the base class intake.catalog.base.Catalog\n '

In [6]: catalog = Catalog.from_dict({'stuff': CSVSource('file.csv')})

In [7]: catalog['stuff']
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-ad23fb20a5f6> in <module>
----> 1 catalog['stuff']

~/Repos/bnl/intake/intake/catalog/base.py in __getitem__(self, key)
    386             e._catalog = self
    387             e._pmode = self.pmode
--> 388             if e._container == 'catalog':
    389                 return e(name=key)
    390             return e()

AttributeError: 'CSVSource' object has no attribute '_container'
```

We see the same issue with databroker's Catalogs. I haven't found a workaround yet (chasing that in https://github.com/bluesky/databroker/pull/619). It seems worth fixing upstream anyway.

Discussion:

Patch:
diff --git a/docs/source/api_other.rst b/docs/source/api_other.rst
index e0d578e..28fa692 100644
--- a/docs/source/api_other.rst
+++ b/docs/source/api_other.rst
@@ -86,60 +86,60 @@ GUI
 
 .. autosummary::
 
-   intake.interface.base.Base
-   intake.interface.base.BaseSelector
-   intake.interface.base.BaseView
-   intake.interface.catalog.add.FileSelector
-   intake.interface.catalog.add.URLSelector
-   intake.interface.catalog.add.CatAdder
-   intake.interface.catalog.gui.CatGUI
-   intake.interface.catalog.search.Search
-   intake.interface.catalog.search.SearchInputs
-   intake.interface.catalog.select.CatSelector
-   intake.interface.source.defined_plots.Plots
-   intake.interface.source.gui.SourceGUI
-   intake.interface.source.description.Description
-   intake.interface.source.select.SourceSelector
+   intake.gui.base.Base
+   intake.gui.base.BaseSelector
+   intake.gui.base.BaseView
+   intake.gui.catalog.add.FileSelector
+   intake.gui.catalog.add.URLSelector
+   intake.gui.catalog.add.CatAdder
+   intake.gui.catalog.gui.CatGUI
+   intake.gui.catalog.search.Search
+   intake.gui.catalog.search.SearchInputs
+   intake.gui.catalog.select.CatSelector
+   intake.gui.source.defined_plots.Plots
+   intake.gui.source.gui.SourceGUI
+   intake.gui.source.description.Description
+   intake.gui.source.select.SourceSelector
 
-.. autoclass:: intake.interface.base.Base
+.. autoclass:: intake.gui.base.Base
    :members:
 
-.. autoclass:: intake.interface.base.BaseSelector
+.. autoclass:: intake.gui.base.BaseSelector
    :members:
 
-.. autoclass:: intake.interface.base.BaseView
+.. autoclass:: intake.gui.base.BaseView
    :members:
 
-.. autoclass:: intake.interface.catalog.add.FileSelector
+.. autoclass:: intake.gui.catalog.add.FileSelector
    :members:
 
-.. autoclass:: intake.interface.catalog.add.URLSelector
+.. autoclass:: intake.gui.catalog.add.URLSelector
    :members:
 
-.. autoclass:: intake.interface.catalog.add.CatAdder
+.. autoclass:: intake.gui.catalog.add.CatAdder
    :members:
 
-.. autoclass:: intake.interface.catalog.gui.CatGUI
+.. autoclass:: intake.gui.catalog.gui.CatGUI
    :members:
 
-.. autoclass:: intake.interface.catalog.search.Search
+.. autoclass:: intake.gui.catalog.search.Search
    :members:
 
-.. autoclass:: intake.interface.catalog.search.SearchInputs
+.. autoclass:: intake.gui.catalog.search.SearchInputs
    :members:
 
-.. autoclass:: intake.interface.catalog.select.CatSelector
+.. autoclass:: intake.gui.catalog.select.CatSelector
    :members:
 
-.. autoclass:: intake.interface.source.defined_plots.Plots
+.. autoclass:: intake.gui.source.defined_plots.Plots
    :members:
 
-.. autoclass:: intake.interface.source.gui.SourceGUI
+.. autoclass:: intake.gui.source.gui.SourceGUI
    :members:
 
-.. autoclass:: intake.interface.source.description.Description
+.. autoclass:: intake.gui.source.description.Description
    :members:
 
-.. autoclass:: intake.interface.source.select.SourceSelector
+.. autoclass:: intake.gui.source.select.SourceSelector
    :members:
 
diff --git a/docs/source/api_user.rst b/docs/source/api_user.rst
index 1b93ae1..515da56 100644
--- a/docs/source/api_user.rst
+++ b/docs/source/api_user.rst
@@ -17,7 +17,7 @@ These are reference class and function definitions likely to be useful to everyo
    intake.catalog.local.YAMLFileCatalog
    intake.catalog.local.YAMLFilesCatalog
    intake.catalog.zarr.ZarrGroupCatalog
-   intake.interface.gui.GUI
+   intake.gui.gui.GUI
 
 .. autofunction::
    intake.open_catalog
@@ -36,7 +36,7 @@ These are reference class and function definitions likely to be useful to everyo
 .. autofunction::
    intake.upload
 
-.. autoclass:: intake.interface.gui.GUI
+.. autoclass:: intake.gui.gui.GUI
    :members:
 
 Source classes
diff --git a/docs/source/gui.rst b/docs/source/gui.rst
index e905aa2..1cc79a9 100644
--- a/docs/source/gui.rst
+++ b/docs/source/gui.rst
@@ -13,7 +13,7 @@ automatically display the last object in a code cell).
 
 .. image:: _static/images/gui_builtin.png
 
-New instances of the GUI are also available by instantiating ``intake.interface.gui.GUI``,
+New instances of the GUI are also available by instantiating ``intake.GUI``,
 where you can specify a list of catalogs to initially include.
 
 The GUI contains three main areas:
@@ -116,7 +116,7 @@ checking the box next to "show yaml".
 
 .. image:: _static/images/gui_plot_yaml.png
 
-The holoviews object can be retrieved from the gui using ``intake.interface.source.plot.pane.object``,
+The holoviews object can be retrieved from the gui using ``intake.gui.source.plot.pane.object``,
 and you can then use it in Python or export it to a file.
 
 Interactive Visualization
diff --git a/intake/__init__.py b/intake/__init__.py
index 799ad3e..a526757 100644
--- a/intake/__init__.py
+++ b/intake/__init__.py
@@ -15,7 +15,6 @@ __version__ = get_versions()['version']
 del get_versions
 
 from .source import register_driver, registry
-from .catalog.base import Catalog
 
 imports = {
     "DataSource": "intake.source.base:DataSource",
@@ -39,7 +38,12 @@ def __getattr__(attr):
     contents of the ``imports`` and ``openers`` dicts
     """
     gl = globals()
-    if attr in openers:
+    if attr == 'Catalog':
+        from .catalog.base import Catalog
+        warnings.warn('deprecation: intake.Catalog now references the base class intake.catalog.base.Catalog\n '
+                      'If you want to open a generic URL, you should use intake.open_catalog')
+        return Catalog
+    elif attr in openers:
         driver = openers[attr].load()
         gl[attr] = driver
     else:
diff --git a/intake/catalog/base.py b/intake/catalog/base.py
index 3680bf6..0fd6235 100644
--- a/intake/catalog/base.py
+++ b/intake/catalog/base.py
@@ -37,16 +37,15 @@ class Catalog(DataSource):
     # emulate a DataSource
     container = 'catalog'
     name = 'catalog'
-    auth = None
 
-    def __init__(self, entries=None, name=None, description=None, metadata=None,
+    def __init__(self, *args, name=None, description=None, metadata=None,
                  ttl=60, getenv=True, getshell=True,
                  persist_mode='default', storage_options=None):
         """
         Parameters
         ----------
-        entries : dict, optional
-            Mapping of {name: entry}
+        args : str or list(str)
+            A single URI or list of URIs.
         name : str, optional
             Unique identifier for catalog. This takes precedence over whatever
             is stated in the cat file itself. Defaults to None.
@@ -87,16 +86,13 @@ class Catalog(DataSource):
             raise ValueError('Persist mode (%s) not understood' % persist_mode)
         self.pmode = persist_mode
 
-        if entries and isinstance(entries, str):
-            raise ValueError(
-                "The class intake.Catalog does not accept a string for "
-                "`entries`\n"
-                "Did you mean to use `intake.open_catalog`? Note that in "
-                "versions of intake <=0.5.4 `intake.Catalog` was an "
-                "alias for `intake.open_catalog`. It is now the intake base "
-                "Catalog class.")
+        if all(isinstance(a, (tuple, list)) for a in args):
+            args = list(flatten(args))
+        if len(args) == 1:
+            args = args[0]
+        self.args = args
         self.updated = time.time()
-        self._entries = entries if entries is not None else self._make_entries_container()
+        self._entries = self._make_entries_container()
         self.force_reload()
 
     @classmethod
@@ -389,7 +385,7 @@ class Catalog(DataSource):
             e = self._entries[key]
             e._catalog = self
             e._pmode = self.pmode
-            if e._container == 'catalog':
+            if e.container == 'catalog':
                 return e(name=key)
             return e()
         if isinstance(key, str) and '.' in key:


Test patch:
diff --git a/intake/catalog/tests/test_core.py b/intake/catalog/tests/test_core.py
index fefec67..e340bff 100644
--- a/intake/catalog/tests/test_core.py
+++ b/intake/catalog/tests/test_core.py
@@ -1,4 +1,3 @@
-import pytest
 from intake.catalog.base import Catalog
 
 
@@ -6,10 +5,3 @@ def test_no_entry():
     cat = Catalog()
     cat2 = cat.configure_new()
     assert isinstance(cat2, Catalog)
-    assert cat.auth is None
-    assert cat2.auth is None
-
-
-def test_regression():
-    with pytest.raises(ValueError):
-        Catalog("URI")
diff --git a/intake/catalog/tests/test_local.py b/intake/catalog/tests/test_local.py
index 05681d6..1caebd2 100644
--- a/intake/catalog/tests/test_local.py
+++ b/intake/catalog/tests/test_local.py
@@ -664,6 +664,16 @@ def test_filter():
     assert cat2.trial2 == entry2()
 
 
+def test_from_dict_with_data_source():
+    "Check that Catalog.from_dict accepts DataSources not wrapped in Entry."
+    from intake.catalog.base import Catalog
+    fn = os.path.join(tempfile.mkdtemp(), 'mycat.yaml')
+    entry = LocalCatalogEntry(name='trial', description='get this back',
+                              driver='csv', args=dict(urlpath=""))
+    ds = entry()
+    cat = Catalog.from_dict({'trial': ds}, name='mycat')
+
+
 def test_no_instance():
     from intake.catalog.local import LocalCatalogEntry
 
diff --git a/intake/tests/test_top_level.py b/intake/tests/test_top_level.py
index 22abc0d..6ff4216 100644
--- a/intake/tests/test_top_level.py
+++ b/intake/tests/test_top_level.py
@@ -113,8 +113,8 @@ def test_output_notebook():
 
 
 def test_old_usage():
-    assert isinstance(intake.Catalog(), intake.Catalog)
-    assert intake.Catalog is intake.catalog.base.Catalog
+    with pytest.warns(UserWarning):
+        intake.Catalog()
 
 
 def test_no_imports():