Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: allow interact to use type hint annotations for abbreviations #3907

Open
corranwebster opened this issue Apr 17, 2024 · 0 comments · May be fixed by #3908
Open

Proposal: allow interact to use type hint annotations for abbreviations #3907

corranwebster opened this issue Apr 17, 2024 · 0 comments · May be fixed by #3908

Comments

@corranwebster
Copy link

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

@corranwebster corranwebster linked a pull request Apr 17, 2024 that will close this issue
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant