mirror of
https://github.com/jupyter/notebook.git
synced 2025-02-05 12:19:58 +08:00
remove positional arg support from interact
This commit is contained in:
parent
81281d6205
commit
3053a855a9
@ -115,68 +115,50 @@ def _widget_from_abbrev(abbrev):
|
||||
raise ValueError("%r cannot be transformed to a Widget" % abbrev)
|
||||
return widget
|
||||
|
||||
def _yield_abbreviations_for_parameter(param, args, kwargs):
|
||||
def _yield_abbreviations_for_parameter(param, kwargs):
|
||||
"""Get an abbreviation for a function parameter."""
|
||||
# print(param, args, kwargs)
|
||||
name = param.name
|
||||
kind = param.kind
|
||||
ann = param.annotation
|
||||
default = param.default
|
||||
empty = Parameter.empty
|
||||
if kind == Parameter.POSITIONAL_ONLY:
|
||||
if args:
|
||||
yield name, args.pop(0), False
|
||||
elif ann is not empty:
|
||||
yield name, ann, False
|
||||
else:
|
||||
yield None, None, None
|
||||
elif kind == Parameter.POSITIONAL_OR_KEYWORD:
|
||||
not_found = (None, None)
|
||||
if kind == Parameter.POSITIONAL_OR_KEYWORD:
|
||||
if name in kwargs:
|
||||
yield name, kwargs.pop(name), True
|
||||
elif args:
|
||||
yield name, args.pop(0), False
|
||||
yield name, kwargs.pop(name)
|
||||
elif ann is not empty:
|
||||
if default is empty:
|
||||
yield name, ann, False
|
||||
yield name, ann
|
||||
else:
|
||||
yield name, ann, True
|
||||
yield name, ann
|
||||
elif default is not empty:
|
||||
yield name, default, True
|
||||
yield name, default
|
||||
else:
|
||||
yield None, None, None
|
||||
elif kind == Parameter.VAR_POSITIONAL:
|
||||
# In this case name=args or something and we don't actually know the names.
|
||||
for item in args[::]:
|
||||
args.pop(0)
|
||||
yield '', item, False
|
||||
yield not_found
|
||||
elif kind == Parameter.KEYWORD_ONLY:
|
||||
if name in kwargs:
|
||||
yield name, kwargs.pop(name), True
|
||||
yield name, kwargs.pop(name)
|
||||
elif ann is not empty:
|
||||
yield name, ann, True
|
||||
yield name, ann
|
||||
elif default is not empty:
|
||||
yield name, default, True
|
||||
yield name, default
|
||||
else:
|
||||
yield None, None, None
|
||||
yield not_found
|
||||
elif kind == Parameter.VAR_KEYWORD:
|
||||
# In this case name=kwargs and we yield the items in kwargs with their keys.
|
||||
for k, v in kwargs.copy().items():
|
||||
kwargs.pop(k)
|
||||
yield k, v, True
|
||||
yield k, v
|
||||
|
||||
def _find_abbreviations(f, args, kwargs):
|
||||
"""Find the abbreviations for a function and args/kwargs passed to interact."""
|
||||
new_args = []
|
||||
def _find_abbreviations(f, kwargs):
|
||||
"""Find the abbreviations for a function and kwargs passed to interact."""
|
||||
new_kwargs = []
|
||||
for param in signature(f).parameters.values():
|
||||
for name, value, kw in _yield_abbreviations_for_parameter(param, args, kwargs):
|
||||
for name, value in _yield_abbreviations_for_parameter(param, kwargs):
|
||||
if value is None:
|
||||
raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
|
||||
if kw:
|
||||
new_kwargs.append((name, value))
|
||||
else:
|
||||
new_args.append((name, value))
|
||||
return new_args, new_kwargs
|
||||
new_kwargs.append((name, value))
|
||||
return new_kwargs
|
||||
|
||||
def _widgets_from_abbreviations(seq):
|
||||
"""Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
|
||||
@ -187,41 +169,35 @@ def _widgets_from_abbreviations(seq):
|
||||
result.append(widget)
|
||||
return result
|
||||
|
||||
def interactive(f, *args, **kwargs):
|
||||
def interactive(__interact_f, **kwargs):
|
||||
"""Build a group of widgets to interact with a function."""
|
||||
f = __interact_f
|
||||
co = kwargs.pop('clear_output', True)
|
||||
args_widgets = []
|
||||
kwargs_widgets = []
|
||||
container = ContainerWidget()
|
||||
container.result = None
|
||||
container.args = []
|
||||
container.kwargs = dict()
|
||||
# We need this to be a list as we iteratively pop elements off it
|
||||
args = list(args)
|
||||
kwargs = kwargs.copy()
|
||||
|
||||
new_args, new_kwargs = _find_abbreviations(f, args, kwargs)
|
||||
new_kwargs = _find_abbreviations(f, kwargs)
|
||||
# Before we proceed, let's make sure that the user has passed a set of args+kwargs
|
||||
# that will lead to a valid call of the function. This protects against unspecified
|
||||
# and doubly-specified arguments.
|
||||
getcallargs(f, *[v for n,v in new_args], **{n:v for n,v in new_kwargs})
|
||||
getcallargs(f, **{n:v for n,v in new_kwargs})
|
||||
# Now build the widgets from the abbreviations.
|
||||
args_widgets.extend(_widgets_from_abbreviations(new_args))
|
||||
kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
|
||||
kwargs_widgets.extend(_widgets_from_abbreviations(sorted(kwargs.items(), key = lambda x: x[0])))
|
||||
|
||||
# This has to be done as an assignment, not using container.children.append,
|
||||
# so that traitlets notices the update. We skip any objects (such as const) that
|
||||
# are not DOMWidgets.
|
||||
c = [w for w in args_widgets+kwargs_widgets if isinstance(w, DOMWidget)]
|
||||
c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
|
||||
container.children = c
|
||||
|
||||
# Build the callback
|
||||
def call_f(name, old, new):
|
||||
container.args = []
|
||||
for widget in args_widgets:
|
||||
value = widget.value
|
||||
container.args.append(value)
|
||||
for widget in kwargs_widgets:
|
||||
value = widget.value
|
||||
container.kwargs[widget.description] = value
|
||||
@ -230,8 +206,6 @@ def interactive(f, *args, **kwargs):
|
||||
container.result = f(*container.args, **container.kwargs)
|
||||
|
||||
# Wire up the widgets
|
||||
for widget in args_widgets:
|
||||
widget.on_trait_change(call_f, 'value')
|
||||
for widget in kwargs_widgets:
|
||||
widget.on_trait_change(call_f, 'value')
|
||||
|
||||
@ -239,25 +213,28 @@ def interactive(f, *args, **kwargs):
|
||||
|
||||
return container
|
||||
|
||||
def interact(*args, **kwargs):
|
||||
"""Interact with a function using widgets."""
|
||||
if args and callable(args[0]):
|
||||
def interact(__interact_f=None, **kwargs):
|
||||
"""interact(f, **kwargs)
|
||||
|
||||
Interact with a function using widgets."""
|
||||
# positional arg support in: https://gist.github.com/8851331
|
||||
if __interact_f is not None:
|
||||
# This branch handles the cases:
|
||||
# 1. interact(f, *args, **kwargs)
|
||||
# 1. interact(f, **kwargs)
|
||||
# 2. @interact
|
||||
# def f(*args, **kwargs):
|
||||
# ...
|
||||
f = args[0]
|
||||
w = interactive(f, *args[1:], **kwargs)
|
||||
f = __interact_f
|
||||
w = interactive(f, **kwargs)
|
||||
f.widget = w
|
||||
display(w)
|
||||
else:
|
||||
# This branch handles the case:
|
||||
# @interact(10, 20, a=30, b=40)
|
||||
# @interact(a=30, b=40)
|
||||
# def f(*args, **kwargs):
|
||||
# ...
|
||||
def dec(f):
|
||||
w = interactive(f, *args, **kwargs)
|
||||
w = interactive(f, **kwargs)
|
||||
f.widget = w
|
||||
display(w)
|
||||
return f
|
||||
|
Loading…
Reference in New Issue
Block a user