This commit is contained in:
Christian Mantha
2026-03-02 19:10:52 -05:00
commit 2ca0b9ef7c
28907 changed files with 5233713 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
import logging
import typing
import warnings
from abc import ABC, abstractmethod
class WidgetUtils(ABC):
def get(self, name: str):
return self._get(name)
@abstractmethod
def _get(self, name: str) -> str:
pass
def getArgument(self, name: str, defaultValue: typing.Optional[str] = None):
try:
return self.get(name)
except Exception:
return defaultValue
def remove(self, name: str):
self._remove(name)
@abstractmethod
def _remove(self, name: str):
pass
def removeAll(self):
self._remove_all()
@abstractmethod
def _remove_all(self):
pass
try:
# We only use ipywidgets if we are in a notebook interactive shell otherwise we raise error,
# to fallback to using default_widgets. Also, users WILL have IPython in their notebooks (jupyter),
# because we DO NOT SUPPORT any other notebook backends, and hence fallback to default_widgets.
from IPython.core.getipython import get_ipython
# Detect if we are in an interactive notebook by iterating over the mro of the current ipython instance,
# to find ZMQInteractiveShell (jupyter). When used from REPL or file, this check will fail, since the
# mro only contains TerminalInteractiveShell.
if (
len(
list(
filter(
lambda i: i.__name__ == "ZMQInteractiveShell",
get_ipython().__class__.__mro__,
)
)
)
== 0
):
logging.debug("Not in an interactive notebook. Skipping ipywidgets implementation for dbutils.")
raise EnvironmentError("Not in an interactive notebook.")
# For import errors in IPyWidgetUtil, we provide a warning message, prompting users to install the
# correct installation group of the sdk.
try:
from .ipywidgets_utils import IPyWidgetUtil
widget_impl = IPyWidgetUtil
logging.debug("Using ipywidgets implementation for dbutils.")
except ImportError as e:
# Since we are certain that we are in an interactive notebook, we can make assumptions about
# formatting and make the warning nicer for the user.
warnings.warn(
"\nTo use databricks widgets interactively in your notebook, please install databricks sdk using:\n"
"\tpip install 'databricks-sdk[notebook]'\n"
"Falling back to default_value_only implementation for databricks widgets."
)
logging.debug(f"{e.msg}. Skipping ipywidgets implementation for dbutils.")
raise e
except:
from .default_widgets_utils import DefaultValueOnlyWidgetUtils
widget_impl = DefaultValueOnlyWidgetUtils
logging.debug("Using default_value_only implementation for dbutils.")

View File

@@ -0,0 +1,48 @@
import typing
from . import WidgetUtils
class DefaultValueOnlyWidgetUtils(WidgetUtils):
def __init__(self) -> None:
self._widgets: typing.Dict[str, str] = {}
def text(self, name: str, defaultValue: str, label: typing.Optional[str] = None):
self._widgets[name] = defaultValue
def dropdown(
self,
name: str,
defaultValue: str,
choices: typing.List[str],
label: typing.Optional[str] = None,
):
self._widgets[name] = defaultValue
def combobox(
self,
name: str,
defaultValue: str,
choices: typing.List[str],
label: typing.Optional[str] = None,
):
self._widgets[name] = defaultValue
def multiselect(
self,
name: str,
defaultValue: str,
choices: typing.List[str],
label: typing.Optional[str] = None,
):
self._widgets[name] = defaultValue
def _get(self, name: str) -> str:
return self._widgets[name]
def _remove(self, name: str):
del self._widgets[name]
def _remove_all(self):
self._widgets = {}

View File

@@ -0,0 +1,110 @@
import typing
from IPython.core.display_functions import display
from ipywidgets.widgets import (ValueWidget, Widget, widget_box,
widget_selection, widget_string)
from .default_widgets_utils import WidgetUtils
class DbUtilsWidget:
def __init__(self, label: str, value_widget: ValueWidget) -> None:
self.label_widget = widget_string.Label(label)
self.value_widget = value_widget
self.box = widget_box.Box([self.label_widget, self.value_widget])
def display(self):
display(self.box)
def close(self):
self.label_widget.close()
self.value_widget.close()
self.box.close()
@property
def value(self):
value = self.value_widget.value
if type(value) == str or value is None:
return value
if type(value) == list or type(value) == tuple:
return ",".join(value)
raise ValueError(f"The returned value has invalid type ({type(value)}).")
class IPyWidgetUtil(WidgetUtils):
def __init__(self) -> None:
self._widgets: typing.Dict[str, DbUtilsWidget] = {}
def _register(
self,
name: str,
widget: ValueWidget,
label: typing.Optional[str] = None,
):
label = label if label is not None else name
w = DbUtilsWidget(label, widget)
if name in self._widgets:
self.remove(name)
self._widgets[name] = w
w.display()
def text(self, name: str, defaultValue: str, label: typing.Optional[str] = None):
self._register(name, widget_string.Text(defaultValue), label)
def dropdown(
self,
name: str,
defaultValue: str,
choices: typing.List[str],
label: typing.Optional[str] = None,
):
self._register(
name,
widget_selection.Dropdown(value=defaultValue, options=choices),
label,
)
def combobox(
self,
name: str,
defaultValue: str,
choices: typing.List[str],
label: typing.Optional[str] = None,
):
self._register(
name,
widget_string.Combobox(value=defaultValue, options=choices),
label,
)
def multiselect(
self,
name: str,
defaultValue: str,
choices: typing.List[str],
label: typing.Optional[str] = None,
):
self._register(
name,
widget_selection.SelectMultiple(
value=(defaultValue,),
options=[("__EMPTY__", ""), *list(zip(choices, choices))],
),
label,
)
def _get(self, name: str) -> str:
return self._widgets[name].value
def _remove(self, name: str):
self._widgets[name].close()
del self._widgets[name]
def _remove_all(self):
Widget.close_all()
self._widgets = {}