jupyter-widgets / ipywidgets

Interactive Widgets for the Jupyter Notebook

Home Page:https://ipywidgets.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: allow `interact` to use type hint annotations for abbreviations

corranwebster opened this issue · comments

Problem

Type hint annotations are rapidly approaching maturity in the Python world, to the point where it is common for functions to provide these for the arguments.

Currently if you have a function with type annotations like:

def f(x: int) -> int:
    return x**2

the interact function and related infrastructure can't infer anything from the annotation of the argument types, so

interact(f)

fails: the user must supply additional information. It seems like it would be reasonable in this situation to use basic type hints (eg. int, float, etc.) to provide a basic Widget for the argument (although maybe not a slider: something like IntText might be better), ie. to have behaviour which is equivalent to

interact(f, x=IntText())

Since interact is fairly basic, it probably only makes sense to support str, int, float, bool, and Enum - anything more complex should be ignored.

Proposed Solution

I think this can be achieved in a fairly straightforward way without changing current working behaviour as follows:

  • in _yield_abbreviations_for_parameter add an additional branch to this block
    if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY):
    if name in kwargs:
    value = kwargs.pop(name)
    elif default is not empty:
    value = default
    else:
    yield not_found
    yield (name, value, default)
    which looks something like:
    elif param.annotation:
        value = param.annotation
    at line 128.
  • add a new method interactive.widget_from_annotation which branches on the type to create appropriate widgets for each supported type. Since there is no value or default supplied, this will use the default value of the widget type (eg. empty string for Text, 0 for IntText, etc.). This might look something like this:
        @staticmethod
        def widget_from_annotation(t):
            """Make widgets from type annotation and optional default value."""
            if t is str:
                return Text()
            elif t is bool:
                return Checkbox()
            elif t in {int, Integral}:
                return IntText()
            elif t in {float, Real}:
                return FloatText()
            elif isinstance(t, EnumType):
                return Dropdown(options={option.name: option for option in t})
            else:
                return None
  • call this new method from interactive.widget_from_abbrev in this section
    if isinstance(abbrev, tuple):
    widget = cls.widget_from_tuple(abbrev)
    if default is not empty:
    try:
    widget.value = default
    except Exception:
    # ignore failure to set default
    pass
    return widget
    # Try single value
    widget = cls.widget_from_single_value(abbrev)
    if widget is not None:
    return widget
    around line 307

Because the annotations are only considered as abbreviations after all other possibilites have failed, existing working code will continue to produce the same results.

Additional context

I have a basic implemention along these lines working in this branch: https://github.com/corranwebster/ipywidgets/tree/feat/interact-type-hints

image