File: C:/Users/fred/anaconda3/Lib/site-packages/intake/interface/catalog/add.py
# -----------------------------------------------------------------------------
# Copyright (c) 2012 - 2019, Anaconda, Inc. and Intake contributors
# All rights reserved.
#
# The full license is in the LICENSE file, distributed with this software.
# -----------------------------------------------------------------------------
import ast
import os
from functools import partial
import fsspec
import panel as pn
from fsspec.registry import known_implementations
import intake
from ..base import MAX_WIDTH, Base, enable_widget
class FileSelector(Base):
"""
Panel interface for picking files
The current path is stored in .path and the current selection is stored in
.url.
Parameters
----------
filters: list of string
extentions that are included in the list of files - correspond to
catalog extensions.
done_callback: func, opt
called when the object's main job has completed. In this case,
selecting a file.
Attributes
----------
url: str
path to local catalog file
children: list of panel objects
children that will be used to populate the panel when visible
panel: panel layout object
instance of a panel layout (row or column) that contains children
when visible
watchers: list of param watchers
watchers that are set on children - cleaned up when visible
is set to false.
"""
def __init__(self, filters=["yaml", "yml"], done_callback=None, **kwargs):
self.filters = filters
self.panel = pn.Column(name="Local", width_policy="max", margin=0)
self.done_callback = done_callback
self.fs = fsspec.filesystem("file")
super().__init__(**kwargs)
def setup(self):
self.path_text = pn.widgets.TextInput(value=os.getcwd() + "/", width_policy="max")
self.protocol = pn.widgets.Select(
options=list(sorted(known_implementations)), value="file", name="protocol"
)
self.storage_options = pn.widgets.TextInput(name="kwargs", value="{}")
self.go = pn.widgets.Button(name="⇨")
self.validator = pn.pane.SVG(None, width=25)
self.main = pn.widgets.MultiSelect(size=15, width_policy="max")
self.home = pn.widgets.Button(name="🏠", width=40, height=30)
self.up = pn.widgets.Button(name="‹", width=30, height=30)
self.make_options()
self.watchers = [
self.go.param.watch(self.go_clicked, "clicks"),
self.protocol.param.watch(self.protocol_changed, "value"),
# self.path_text.param.watch(self.validate, ['value']),
# self.path_text.param.watch(self.make_options, ['value']),
self.home.param.watch(self.go_home, "clicks"),
self.up.param.watch(self.move_up, "clicks"),
self.main.param.watch(self.move_down, ["value"]),
]
self.children = [
pn.Row(self.protocol, self.storage_options),
pn.Row(self.home, self.up, self.path_text, self.go, margin=0),
self.main,
]
def protocol_changed(self, *_):
self.path_text.value = ""
self.main.options = []
self.main.value = []
def go_clicked(self, *_):
self.fs = fsspec.filesystem(
self.protocol.value, **ast.literal_eval(self.storage_options.value)
)
self.make_options()
@property
def path(self):
return self.path_text.value
@property
def url(self):
"""Path to local catalog file"""
return self.protocol.value + "://" + os.path.join(self.path, self.main.value[0])
def move_up(self, arg=None):
self.path_text.value = self.fs._parent(self.path_text.value)
self.make_options()
def go_home(self, arg=None):
self.protocol.value = "file"
self.path_text.value = os.getcwd() + os.path.sep
def make_options(self, arg=None):
if self.done_callback:
self.done_callback(False)
out = []
try:
for f in self.fs.ls(self.path, True):
bn = os.path.basename(f["name"].rstrip("/"))
if bn.startswith("."):
continue
elif f["type"] == "directory":
out.append(bn + "/")
elif not self.filters or any(bn.endswith(ext) for ext in self.filters):
out.append(bn)
except Exception as e:
print(e)
self.main.value = []
self.main.options = sorted(out)
def move_down(self, *events):
for event in events:
if event.name == "value" and len(event.new) > 0:
fn = event.new[0]
if fn.endswith("/"):
if self.path_text.value:
self.path_text.value = os.path.join(self.path_text.value, fn)
else:
self.path_text.value = fn
self.make_options()
elif self.done_callback:
self.done_callback(True)
def __getstate__(self):
"""Serialize the current state of the object."""
return {"path": self.path, "selected": self.main.value}
def __setstate__(self, state):
"""Set the current state of the object from the serialized version.
Works inplace. See ``__getstate__`` to get serialized version and
``from_state`` to create a new object."""
self.path_text.value = state["path"]
self.main.value = state["selected"]
return self
class URLSelector(Base):
"""
Panel interface for inputting a URL to a remote catalog
The inputted URL is stored in .url.
Attributes
----------
url: str
url to remote files (including protocol)
children: list of panel objects
children that will be used to populate the panel when visible
panel: panel layout object
instance of a panel layout (row or column) that contains children
when visible
watchers: list of param watchers
watchers that are set on children - cleaned up when visible
is set to false.
"""
def __init__(self, **kwargs):
self.panel = pn.Row(name="URL", width_policy="max", margin=0)
super().__init__(**kwargs)
def setup(self):
self.main = pn.widgets.TextInput(placeholder="Full URL with protocol", width_policy="max")
self.children = ["URL:", self.main]
@property
def url(self):
"""URL to remote files (including protocol)"""
return self.main.value
def __getstate__(self):
"""Serialize the current state of the object."""
return {"url": self.url}
def __setstate__(self, state):
"""Set the current state of the object from the serialized version.
Works inplace. See ``__getstate__`` to get serialized version and
``from_state`` to create a new object."""
self.main.value = state["url"]
return self
class CatAdder(Base):
"""Panel for adding new cats from local file or remote
Parameters
----------
done_callback: function with cat as input
function that is called when the "Add Catalog" button is clicked.
Attributes
----------
cat_url: str
url to remote files or path to local files. Depends on active tab
cat: catalog
catalog object initialized from from cat_url
children: list of panel objects
children that will be used to populate the panel when visible
panel: panel layout object
instance of a panel layout (row or column) that contains children
when visible
watchers: list of param watchers
watchers that are set on children - cleaned up when visible
is set to false.
"""
tabs = None
def __init__(self, done_callback=None, **kwargs):
self.done_callback = done_callback
self.panel = pn.Column(
name="Add Catalog", width_policy="max", max_width=MAX_WIDTH, margin=0
)
self.widget = pn.widgets.Button(name="Add Catalog", disabled=True, width_policy="min")
self.fs = FileSelector(done_callback=partial(enable_widget, self.widget))
self.url = URLSelector()
super().__init__(**kwargs)
def setup(self):
self.selectors = [self.fs, self.url]
self.tabs = pn.Tabs(*map(lambda x: x.panel, self.selectors))
self.watchers = [
self.widget.param.watch(self.add_cat, "clicks"),
]
self.children = [self.tabs, self.widget]
@property
def cat_url(self):
"""URL to remote files or path to local files. Depends on active tab."""
url = self.selectors[self.tabs.active].url
if self.selectors[self.tabs.active] is self.fs:
fs = self.fs.fs
else:
fs = None
return url, fs
@property
def cat(self):
"""Catalog object initialized from from cat_url"""
# might want to do some validation in here
url, fs = self.cat_url
if fs:
return intake.open_catalog(url, fs=fs)
else:
return intake.open_catalog(url)
def add_cat(self, arg=None):
"""Add cat and close panel"""
try:
self.done_callback(self.cat)
self.panel.visible = False
except Exception as e:
raise e