diff --git a/IPython/html/widgets/interact.py b/IPython/html/widgets/interact.py index 3707d09..8d60d11 100644 --- a/IPython/html/widgets/interact.py +++ b/IPython/html/widgets/interact.py @@ -13,6 +13,11 @@ # Imports #----------------------------------------------------------------------------- +try: # Python >= 3.3 + from inspect import signature, Parameter +except ImportError: + from IPython.utils.signatures import signature, Parameter + from IPython.html.widgets import (Widget, TextWidget, FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget, ContainerWidget) @@ -48,13 +53,13 @@ def _get_min_max_value(min, max, value): elif isinstance(value, int): min, max = -value, 3*value else: - raise TypeError('expected a number, got: %r' % number) + raise TypeError('expected a number, got: %r' % value) else: raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value)) return min, max, value - -def _widget_abbrev(o): +def _widget_abbrev_single_value(o): + """Make widgets from single values, which can be used written as parameter defaults.""" if isinstance(o, string_types): return TextWidget(value=unicode_type(o)) elif isinstance(o, dict): @@ -72,6 +77,9 @@ def _widget_abbrev(o): elif isinstance(o, int): min, max, value = _get_min_max_value(None, None, o) return IntSliderWidget(value=o, min=min, max=max) + +def _widget_abbrev(o): + """Make widgets from abbreviations: single values, lists or tuples.""" if isinstance(o, (list, tuple)): if _matches(o, (int, int)): min, max, value = _get_min_max_value(o[0], o[1], None) @@ -92,9 +100,45 @@ def _widget_abbrev(o): return DropdownWidget(value=unicode_type(o[0]), values=[unicode_type(k) for k in o]) + else: + return _widget_abbrev_single_value(o) + +def _widget_or_abbrev(value): + if isinstance(value, Widget): + return value + + widget = _widget_abbrev(value) + if widget is None: + raise ValueError("%r cannot be transformed to a Widget" % value) + return widget + +def _widget_for_param(param, kwargs): + """Get a widget for a parameter. + + We look for, in this order: + - keyword arguments passed to interact[ive]() that match the parameter name. + - function annotations + - default values + + Returns an instance of Widget, or None if nothing suitable is found. + + Raises ValueError if the kwargs or annotation value cannot be made into + a widget. + """ + if param.name in kwargs: + return _widget_or_abbrev(kwargs.pop(param.name)) + + if param.annotation is not Parameter.empty: + return _widget_or_abbrev(param.annotation) + + if param.default is not Parameter.empty: + # Returns None if it's not suitable + return _widget_abbrev_single_value(param.default) + + return None def interactive(f, **kwargs): - """Interact with a function using widgets.""" + """Build a group of widgets for setting the inputs to a function.""" co = kwargs.pop('clear_output', True) # First convert all args to Widget instances @@ -102,31 +146,37 @@ def interactive(f, **kwargs): container = ContainerWidget() container.result = None container.kwargs = dict() - for key, value in kwargs.items(): - if isinstance(value, Widget): - widget = value - else: - widget = _widget_abbrev(value) - if widget is None: - raise ValueError("Object cannot be transformed to a Widget") - widget.description = key - widgets.append((key,widget)) - widgets.sort(key=lambda e: e[1].__class__.__name__) - container.children = [e[1] for e in widgets] + + # Extract parameters from the function signature + for param in signature(f).parameters.values(): + param_widget = _widget_for_param(param, kwargs) + if param_widget is not None: + param_widget.description = param.name + widgets.append(param_widget) + + # Extra parameters from keyword args - we assume f takes **kwargs + for name, value in sorted(kwargs.items(), key = lambda x: x[0]): + widget = _widget_or_abbrev(value) + widget.description = name + widgets.append(widget) + + # This has to be done as an assignment, not using container.children.append, + # so that traitlets notices the update. + container.children = widgets # Build the callback def call_f(name, old, new): actual_kwargs = {} - for key, widget in widgets: + for widget in widgets: value = widget.value - container.kwargs[key] = value - actual_kwargs[key] = value + container.kwargs[widget.description] = value + actual_kwargs[widget.description] = value if co: clear_output(wait=True) container.result = f(**actual_kwargs) # Wire up the widgets - for key, widget in widgets: + for widget in widgets: widget.on_trait_change(call_f, 'value') container.on_displayed(lambda _: call_f(None, None, None)) @@ -134,6 +184,7 @@ def interactive(f, **kwargs): return container def interact(f, **kwargs): + """Interact with a function using widgets.""" w = interactive(f, **kwargs) f.widget = w display(w) diff --git a/IPython/utils/signatures.py b/IPython/utils/signatures.py new file mode 100644 index 0000000..f37b31c --- /dev/null +++ b/IPython/utils/signatures.py @@ -0,0 +1,819 @@ +"""Function signature objects for callables + +Back port of Python 3.3's function signature tools from the inspect module, +modified to be compatible with Python 2.6, 2.7 and 3.2+. +""" + +#----------------------------------------------------------------------------- +# Python 3.3 stdlib inspect.py is public domain +# +# Backports Copyright (C) 2013 Aaron Iles +# Used under Apache License Version 2.0 +# +# Further Changes are Copyright (C) 2013 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#----------------------------------------------------------------------------- + +from __future__ import absolute_import, division, print_function +import itertools +import functools +import re +import types + + +# patch for single-file +# we don't support 2.6, so we can just import OrderedDict +from collections import OrderedDict + +__version__ = '0.3' +# end patch + +__all__ = ['BoundArguments', 'Parameter', 'Signature', 'signature'] + + +_WrapperDescriptor = type(type.__call__) +_MethodWrapper = type(all.__call__) + +_NonUserDefinedCallables = (_WrapperDescriptor, + _MethodWrapper, + types.BuiltinFunctionType) + + +def formatannotation(annotation, base_module=None): + if isinstance(annotation, type): + if annotation.__module__ in ('builtins', '__builtin__', base_module): + return annotation.__name__ + return annotation.__module__+'.'+annotation.__name__ + return repr(annotation) + + +def _get_user_defined_method(cls, method_name, *nested): + try: + if cls is type: + return + meth = getattr(cls, method_name) + for name in nested: + meth = getattr(meth, name, meth) + except AttributeError: + return + else: + if not isinstance(meth, _NonUserDefinedCallables): + # Once '__signature__' will be added to 'C'-level + # callables, this check won't be necessary + return meth + + +def signature(obj): + '''Get a signature object for the passed callable.''' + + if not callable(obj): + raise TypeError('{0!r} is not a callable object'.format(obj)) + + if isinstance(obj, types.MethodType): + # In this case we skip the first parameter of the underlying + # function (usually `self` or `cls`). + sig = signature(obj.__func__) + return sig.replace(parameters=tuple(sig.parameters.values())[1:]) + + try: + sig = obj.__signature__ + except AttributeError: + pass + else: + if sig is not None: + return sig + + try: + # Was this function wrapped by a decorator? + wrapped = obj.__wrapped__ + except AttributeError: + pass + else: + return signature(wrapped) + + if isinstance(obj, types.FunctionType): + return Signature.from_function(obj) + + if isinstance(obj, functools.partial): + sig = signature(obj.func) + + new_params = OrderedDict(sig.parameters.items()) + + partial_args = obj.args or () + partial_keywords = obj.keywords or {} + try: + ba = sig.bind_partial(*partial_args, **partial_keywords) + except TypeError as ex: + msg = 'partial object {0!r} has incorrect arguments'.format(obj) + raise ValueError(msg) + + for arg_name, arg_value in ba.arguments.items(): + param = new_params[arg_name] + if arg_name in partial_keywords: + # We set a new default value, because the following code + # is correct: + # + # >>> def foo(a): print(a) + # >>> print(partial(partial(foo, a=10), a=20)()) + # 20 + # >>> print(partial(partial(foo, a=10), a=20)(a=30)) + # 30 + # + # So, with 'partial' objects, passing a keyword argument is + # like setting a new default value for the corresponding + # parameter + # + # We also mark this parameter with '_partial_kwarg' + # flag. Later, in '_bind', the 'default' value of this + # parameter will be added to 'kwargs', to simulate + # the 'functools.partial' real call. + new_params[arg_name] = param.replace(default=arg_value, + _partial_kwarg=True) + + elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and + not param._partial_kwarg): + new_params.pop(arg_name) + + return sig.replace(parameters=new_params.values()) + + sig = None + if isinstance(obj, type): + # obj is a class or a metaclass + + # First, let's see if it has an overloaded __call__ defined + # in its metaclass + call = _get_user_defined_method(type(obj), '__call__') + if call is not None: + sig = signature(call) + else: + # Now we check if the 'obj' class has a '__new__' method + new = _get_user_defined_method(obj, '__new__') + if new is not None: + sig = signature(new) + else: + # Finally, we should have at least __init__ implemented + init = _get_user_defined_method(obj, '__init__') + if init is not None: + sig = signature(init) + elif not isinstance(obj, _NonUserDefinedCallables): + # An object with __call__ + # We also check that the 'obj' is not an instance of + # _WrapperDescriptor or _MethodWrapper to avoid + # infinite recursion (and even potential segfault) + call = _get_user_defined_method(type(obj), '__call__', 'im_func') + if call is not None: + sig = signature(call) + + if sig is not None: + return sig + + if isinstance(obj, types.BuiltinFunctionType): + # Raise a nicer error message for builtins + msg = 'no signature found for builtin function {0!r}'.format(obj) + raise ValueError(msg) + + raise ValueError('callable {0!r} is not supported by signature'.format(obj)) + + +class _void(object): + '''A private marker - used in Parameter & Signature''' + + +class _empty(object): + pass + + +class _ParameterKind(int): + def __new__(self, *args, **kwargs): + obj = int.__new__(self, *args) + obj._name = kwargs['name'] + return obj + + def __str__(self): + return self._name + + def __repr__(self): + return '<_ParameterKind: {0!r}>'.format(self._name) + + +_POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') +_POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') +_VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL') +_KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY') +_VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD') + + +class Parameter(object): + '''Represents a parameter in a function signature. + + Has the following public attributes: + + * name : str + The name of the parameter as a string. + * default : object + The default value for the parameter if specified. If the + parameter has no default value, this attribute is not set. + * annotation + The annotation for the parameter if specified. If the + parameter has no annotation, this attribute is not set. + * kind : str + Describes how argument values are bound to the parameter. + Possible values: `Parameter.POSITIONAL_ONLY`, + `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`, + `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`. + ''' + + __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg') + + POSITIONAL_ONLY = _POSITIONAL_ONLY + POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD + VAR_POSITIONAL = _VAR_POSITIONAL + KEYWORD_ONLY = _KEYWORD_ONLY + VAR_KEYWORD = _VAR_KEYWORD + + empty = _empty + + def __init__(self, name, kind, default=_empty, annotation=_empty, + _partial_kwarg=False): + + if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD, + _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD): + raise ValueError("invalid value for 'Parameter.kind' attribute") + self._kind = kind + + if default is not _empty: + if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): + msg = '{0} parameters cannot have default values'.format(kind) + raise ValueError(msg) + self._default = default + self._annotation = annotation + + if name is None: + if kind != _POSITIONAL_ONLY: + raise ValueError("None is not a valid name for a " + "non-positional-only parameter") + self._name = name + else: + name = str(name) + if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I): + msg = '{0!r} is not a valid parameter name'.format(name) + raise ValueError(msg) + self._name = name + + self._partial_kwarg = _partial_kwarg + + @property + def name(self): + return self._name + + @property + def default(self): + return self._default + + @property + def annotation(self): + return self._annotation + + @property + def kind(self): + return self._kind + + def replace(self, name=_void, kind=_void, annotation=_void, + default=_void, _partial_kwarg=_void): + '''Creates a customized copy of the Parameter.''' + + if name is _void: + name = self._name + + if kind is _void: + kind = self._kind + + if annotation is _void: + annotation = self._annotation + + if default is _void: + default = self._default + + if _partial_kwarg is _void: + _partial_kwarg = self._partial_kwarg + + return type(self)(name, kind, default=default, annotation=annotation, + _partial_kwarg=_partial_kwarg) + + def __str__(self): + kind = self.kind + + formatted = self._name + if kind == _POSITIONAL_ONLY: + if formatted is None: + formatted = '' + formatted = '<{0}>'.format(formatted) + + # Add annotation and default value + if self._annotation is not _empty: + formatted = '{0}:{1}'.format(formatted, + formatannotation(self._annotation)) + + if self._default is not _empty: + formatted = '{0}={1}'.format(formatted, repr(self._default)) + + if kind == _VAR_POSITIONAL: + formatted = '*' + formatted + elif kind == _VAR_KEYWORD: + formatted = '**' + formatted + + return formatted + + def __repr__(self): + return '<{0} at {1:#x} {2!r}>'.format(self.__class__.__name__, + id(self), self.name) + + def __hash__(self): + msg = "unhashable type: '{0}'".format(self.__class__.__name__) + raise TypeError(msg) + + def __eq__(self, other): + return (issubclass(other.__class__, Parameter) and + self._name == other._name and + self._kind == other._kind and + self._default == other._default and + self._annotation == other._annotation) + + def __ne__(self, other): + return not self.__eq__(other) + + +class BoundArguments(object): + '''Result of `Signature.bind` call. Holds the mapping of arguments + to the function's parameters. + + Has the following public attributes: + + * arguments : OrderedDict + An ordered mutable mapping of parameters' names to arguments' values. + Does not contain arguments' default values. + * signature : Signature + The Signature object that created this instance. + * args : tuple + Tuple of positional arguments values. + * kwargs : dict + Dict of keyword arguments values. + ''' + + def __init__(self, signature, arguments): + self.arguments = arguments + self._signature = signature + + @property + def signature(self): + return self._signature + + @property + def args(self): + args = [] + for param_name, param in self._signature.parameters.items(): + if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or + param._partial_kwarg): + # Keyword arguments mapped by 'functools.partial' + # (Parameter._partial_kwarg is True) are mapped + # in 'BoundArguments.kwargs', along with VAR_KEYWORD & + # KEYWORD_ONLY + break + + try: + arg = self.arguments[param_name] + except KeyError: + # We're done here. Other arguments + # will be mapped in 'BoundArguments.kwargs' + break + else: + if param.kind == _VAR_POSITIONAL: + # *args + args.extend(arg) + else: + # plain argument + args.append(arg) + + return tuple(args) + + @property + def kwargs(self): + kwargs = {} + kwargs_started = False + for param_name, param in self._signature.parameters.items(): + if not kwargs_started: + if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or + param._partial_kwarg): + kwargs_started = True + else: + if param_name not in self.arguments: + kwargs_started = True + continue + + if not kwargs_started: + continue + + try: + arg = self.arguments[param_name] + except KeyError: + pass + else: + if param.kind == _VAR_KEYWORD: + # **kwargs + kwargs.update(arg) + else: + # plain keyword argument + kwargs[param_name] = arg + + return kwargs + + def __hash__(self): + msg = "unhashable type: '{0}'".format(self.__class__.__name__) + raise TypeError(msg) + + def __eq__(self, other): + return (issubclass(other.__class__, BoundArguments) and + self.signature == other.signature and + self.arguments == other.arguments) + + def __ne__(self, other): + return not self.__eq__(other) + + +class Signature(object): + '''A Signature object represents the overall signature of a function. + It stores a Parameter object for each parameter accepted by the + function, as well as information specific to the function itself. + + A Signature object has the following public attributes and methods: + + * parameters : OrderedDict + An ordered mapping of parameters' names to the corresponding + Parameter objects (keyword-only arguments are in the same order + as listed in `code.co_varnames`). + * return_annotation : object + The annotation for the return type of the function if specified. + If the function has no annotation for its return type, this + attribute is not set. + * bind(*args, **kwargs) -> BoundArguments + Creates a mapping from positional and keyword arguments to + parameters. + * bind_partial(*args, **kwargs) -> BoundArguments + Creates a partial mapping from positional and keyword arguments + to parameters (simulating 'functools.partial' behavior.) + ''' + + __slots__ = ('_return_annotation', '_parameters') + + _parameter_cls = Parameter + _bound_arguments_cls = BoundArguments + + empty = _empty + + def __init__(self, parameters=None, return_annotation=_empty, + __validate_parameters__=True): + '''Constructs Signature from the given list of Parameter + objects and 'return_annotation'. All arguments are optional. + ''' + + if parameters is None: + params = OrderedDict() + else: + if __validate_parameters__: + params = OrderedDict() + top_kind = _POSITIONAL_ONLY + + for idx, param in enumerate(parameters): + kind = param.kind + if kind < top_kind: + msg = 'wrong parameter order: {0} before {1}' + msg = msg.format(top_kind, param.kind) + raise ValueError(msg) + else: + top_kind = kind + + name = param.name + if name is None: + name = str(idx) + param = param.replace(name=name) + + if name in params: + msg = 'duplicate parameter name: {0!r}'.format(name) + raise ValueError(msg) + params[name] = param + else: + params = OrderedDict(((param.name, param) + for param in parameters)) + + self._parameters = params + self._return_annotation = return_annotation + + @classmethod + def from_function(cls, func): + '''Constructs Signature for the given python function''' + + if not isinstance(func, types.FunctionType): + raise TypeError('{0!r} is not a Python function'.format(func)) + + Parameter = cls._parameter_cls + + # Parameter information. + func_code = func.__code__ + pos_count = func_code.co_argcount + arg_names = func_code.co_varnames + positional = tuple(arg_names[:pos_count]) + keyword_only_count = getattr(func_code, 'co_kwonlyargcount', 0) + keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)] + annotations = getattr(func, '__annotations__', {}) + defaults = func.__defaults__ + kwdefaults = getattr(func, '__kwdefaults__', None) + + if defaults: + pos_default_count = len(defaults) + else: + pos_default_count = 0 + + parameters = [] + + # Non-keyword-only parameters w/o defaults. + non_default_count = pos_count - pos_default_count + for name in positional[:non_default_count]: + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_POSITIONAL_OR_KEYWORD)) + + # ... w/ defaults. + for offset, name in enumerate(positional[non_default_count:]): + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_POSITIONAL_OR_KEYWORD, + default=defaults[offset])) + + # *args + if func_code.co_flags & 0x04: + name = arg_names[pos_count + keyword_only_count] + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_VAR_POSITIONAL)) + + # Keyword-only parameters. + for name in keyword_only: + default = _empty + if kwdefaults is not None: + default = kwdefaults.get(name, _empty) + + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_KEYWORD_ONLY, + default=default)) + # **kwargs + if func_code.co_flags & 0x08: + index = pos_count + keyword_only_count + if func_code.co_flags & 0x04: + index += 1 + + name = arg_names[index] + annotation = annotations.get(name, _empty) + parameters.append(Parameter(name, annotation=annotation, + kind=_VAR_KEYWORD)) + + return cls(parameters, + return_annotation=annotations.get('return', _empty), + __validate_parameters__=False) + + @property + def parameters(self): + try: + return types.MappingProxyType(self._parameters) + except AttributeError: + return OrderedDict(self._parameters.items()) + + @property + def return_annotation(self): + return self._return_annotation + + def replace(self, parameters=_void, return_annotation=_void): + '''Creates a customized copy of the Signature. + Pass 'parameters' and/or 'return_annotation' arguments + to override them in the new copy. + ''' + + if parameters is _void: + parameters = self.parameters.values() + + if return_annotation is _void: + return_annotation = self._return_annotation + + return type(self)(parameters, + return_annotation=return_annotation) + + def __hash__(self): + msg = "unhashable type: '{0}'".format(self.__class__.__name__) + raise TypeError(msg) + + def __eq__(self, other): + if (not issubclass(type(other), Signature) or + self.return_annotation != other.return_annotation or + len(self.parameters) != len(other.parameters)): + return False + + other_positions = dict((param, idx) + for idx, param in enumerate(other.parameters.keys())) + + for idx, (param_name, param) in enumerate(self.parameters.items()): + if param.kind == _KEYWORD_ONLY: + try: + other_param = other.parameters[param_name] + except KeyError: + return False + else: + if param != other_param: + return False + else: + try: + other_idx = other_positions[param_name] + except KeyError: + return False + else: + if (idx != other_idx or + param != other.parameters[param_name]): + return False + + return True + + def __ne__(self, other): + return not self.__eq__(other) + + def _bind(self, args, kwargs, partial=False): + '''Private method. Don't use directly.''' + + arguments = OrderedDict() + + parameters = iter(self.parameters.values()) + parameters_ex = () + arg_vals = iter(args) + + if partial: + # Support for binding arguments to 'functools.partial' objects. + # See 'functools.partial' case in 'signature()' implementation + # for details. + for param_name, param in self.parameters.items(): + if (param._partial_kwarg and param_name not in kwargs): + # Simulating 'functools.partial' behavior + kwargs[param_name] = param.default + + while True: + # Let's iterate through the positional arguments and corresponding + # parameters + try: + arg_val = next(arg_vals) + except StopIteration: + # No more positional arguments + try: + param = next(parameters) + except StopIteration: + # No more parameters. That's it. Just need to check that + # we have no `kwargs` after this while loop + break + else: + if param.kind == _VAR_POSITIONAL: + # That's OK, just empty *args. Let's start parsing + # kwargs + break + elif param.name in kwargs: + if param.kind == _POSITIONAL_ONLY: + msg = '{arg!r} parameter is positional only, ' \ + 'but was passed as a keyword' + msg = msg.format(arg=param.name) + raise TypeError(msg) + parameters_ex = (param,) + break + elif (param.kind == _VAR_KEYWORD or + param.default is not _empty): + # That's fine too - we have a default value for this + # parameter. So, lets start parsing `kwargs`, starting + # with the current parameter + parameters_ex = (param,) + break + else: + if partial: + parameters_ex = (param,) + break + else: + msg = '{arg!r} parameter lacking default value' + msg = msg.format(arg=param.name) + raise TypeError(msg) + else: + # We have a positional argument to process + try: + param = next(parameters) + except StopIteration: + raise TypeError('too many positional arguments') + else: + if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY): + # Looks like we have no parameter for this positional + # argument + raise TypeError('too many positional arguments') + + if param.kind == _VAR_POSITIONAL: + # We have an '*args'-like argument, let's fill it with + # all positional arguments we have left and move on to + # the next phase + values = [arg_val] + values.extend(arg_vals) + arguments[param.name] = tuple(values) + break + + if param.name in kwargs: + raise TypeError('multiple values for argument ' + '{arg!r}'.format(arg=param.name)) + + arguments[param.name] = arg_val + + # Now, we iterate through the remaining parameters to process + # keyword arguments + kwargs_param = None + for param in itertools.chain(parameters_ex, parameters): + if param.kind == _POSITIONAL_ONLY: + # This should never happen in case of a properly built + # Signature object (but let's have this check here + # to ensure correct behaviour just in case) + raise TypeError('{arg!r} parameter is positional only, ' + 'but was passed as a keyword'. \ + format(arg=param.name)) + + if param.kind == _VAR_KEYWORD: + # Memorize that we have a '**kwargs'-like parameter + kwargs_param = param + continue + + param_name = param.name + try: + arg_val = kwargs.pop(param_name) + except KeyError: + # We have no value for this parameter. It's fine though, + # if it has a default value, or it is an '*args'-like + # parameter, left alone by the processing of positional + # arguments. + if (not partial and param.kind != _VAR_POSITIONAL and + param.default is _empty): + raise TypeError('{arg!r} parameter lacking default value'. \ + format(arg=param_name)) + + else: + arguments[param_name] = arg_val + + if kwargs: + if kwargs_param is not None: + # Process our '**kwargs'-like parameter + arguments[kwargs_param.name] = kwargs + else: + raise TypeError('too many keyword arguments') + + return self._bound_arguments_cls(self, arguments) + + def bind(self, *args, **kwargs): + '''Get a BoundArguments object, that maps the passed `args` + and `kwargs` to the function's signature. Raises `TypeError` + if the passed arguments can not be bound. + ''' + return self._bind(args, kwargs) + + def bind_partial(self, *args, **kwargs): + '''Get a BoundArguments object, that partially maps the + passed `args` and `kwargs` to the function's signature. + Raises `TypeError` if the passed arguments can not be bound. + ''' + return self._bind(args, kwargs, partial=True) + + def __str__(self): + result = [] + render_kw_only_separator = True + for idx, param in enumerate(self.parameters.values()): + formatted = str(param) + + kind = param.kind + if kind == _VAR_POSITIONAL: + # OK, we have an '*args'-like parameter, so we won't need + # a '*' to separate keyword-only arguments + render_kw_only_separator = False + elif kind == _KEYWORD_ONLY and render_kw_only_separator: + # We have a keyword-only parameter to render and we haven't + # rendered an '*args'-like parameter before, so add a '*' + # separator to the parameters list ("foo(arg1, *, arg2)" case) + result.append('*') + # This condition should be only triggered once, so + # reset the flag + render_kw_only_separator = False + + result.append(formatted) + + rendered = '({0})'.format(', '.join(result)) + + if self.return_annotation is not _empty: + anno = formatannotation(self.return_annotation) + rendered += ' -> {0}'.format(anno) + + return rendered diff --git a/examples/widgets/Interact.ipynb b/examples/widgets/Interact.ipynb index ca2e9ed..6d7fc19 100644 --- a/examples/widgets/Interact.ipynb +++ b/examples/widgets/Interact.ipynb @@ -39,7 +39,8 @@ ] } ], - "prompt_number": 1 + "prompt_number": 1, + "trusted": true }, { "cell_type": "code", @@ -52,7 +53,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 2 + "prompt_number": 2, + "trusted": true }, { "cell_type": "heading", @@ -83,7 +85,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 3 + "prompt_number": 3, + "trusted": true }, { "cell_type": "code", @@ -97,19 +100,20 @@ { "html": [ "

Arguments:

\n", - "\n", - "\n", "\n", + "\n", + "\n", "
a10
cTrue
bHi There
cTrue
a10
" ], "metadata": {}, "output_type": "display_data", "text": [ - "" + "" ] } ], - "prompt_number": 4 + "prompt_number": 4, + "trusted": true }, { "cell_type": "markdown", @@ -127,32 +131,15 @@ " Current=(0.,10.,0.01),\n", " z=True,\n", " Text=u'Type here!',\n", - " Algorithm=['This','That','Other'],\n", + " #Algorithm=['This','That','Other'],\n", " a=widgets.FloatSliderWidget(min=-10.0, max=10.0, step=0.1, value=5.0)\n", " )" ], "language": "python", "metadata": {}, - "outputs": [ - { - "html": [ - "

Arguments:

\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
a0.3
AlgorithmThis
Temp5
TextType here!
Current5.0
zTrue
" - ], - "metadata": {}, - "output_type": "display_data", - "text": [ - "" - ] - } - ], - "prompt_number": 5 + "outputs": [], + "prompt_number": 6, + "trusted": true }, { "cell_type": "markdown", @@ -186,7 +173,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 6 + "prompt_number": 6, + "trusted": true }, { "cell_type": "code", @@ -197,7 +185,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 7 + "prompt_number": 7, + "trusted": true }, { "cell_type": "code", @@ -209,7 +198,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 8 + "prompt_number": 8, + "trusted": true }, { "cell_type": "markdown", @@ -222,28 +212,45 @@ "cell_type": "code", "collapsed": false, "input": [ - "interact(factorit, n=(2,40))" + "factorit(12)" ], "language": "python", "metadata": {}, "outputs": [ { + "output_type": "stream", + "stream": "stderr", + "text": [ + "/home/takluyver/.local/lib/python3.3/site-packages/IPython/core/formatters.py:199: FormatterWarning: Exception in image/png formatter: string argument expected, got 'bytes'\n", + " FormatterWarning,\n" + ] + }, + { "latex": [ - "$$x^{21} - 1 = \\left(x - 1\\right) \\left(x^{2} + x + 1\\right) \\left(x^{6} + x^{5} + x^{4} + x^{3} + x^{2} + x + 1\\right) \\left(x^{12} - x^{11} + x^{9} - x^{8} + x^{6} - x^{4} + x^{3} - x + 1\\right)$$" + "$$x^{12} - 1 = \\left(x - 1\\right) \\left(x + 1\\right) \\left(x^{2} + 1\\right) \\left(x^{2} - x + 1\\right) \\left(x^{2} + x + 1\\right) \\left(x^{4} - x^{2} + 1\\right)$$" ], "metadata": {}, "output_type": "display_data", - "png": "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\n", "text": [ - " 21 \u239b 2 \u239e \u239b 6 5 4 3 2 \u239e \u239b 12 11 \n", - "x - 1 = (x - 1)\u22c5\u239dx + x + 1\u23a0\u22c5\u239dx + x + x + x + x + x + 1\u23a0\u22c5\u239dx - x + x\n", - "\n", - "9 8 6 4 3 \u239e\n", - " - x + x - x + x - x + 1\u23a0" + " 12 \u239b 2 \u239e \u239b 2 \u239e \u239b 2 \u239e \u239b 4 2 \u239e\n", + "x - 1 = (x - 1)\u22c5(x + 1)\u22c5\u239dx + 1\u23a0\u22c5\u239dx - x + 1\u23a0\u22c5\u239dx + x + 1\u23a0\u22c5\u239dx - x + 1\u23a0" ] } ], - "prompt_number": 9 + "prompt_number": 11, + "trusted": true + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "interact(factorit, n=(2,40))" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 9, + "trusted": true }, { "cell_type": "heading", @@ -269,7 +276,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 10 + "prompt_number": 10, + "trusted": false }, { "cell_type": "markdown", @@ -287,7 +295,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 11 + "prompt_number": 11, + "trusted": false }, { "cell_type": "code", @@ -304,7 +313,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 12 + "prompt_number": 12, + "trusted": false }, { "cell_type": "code", @@ -324,7 +334,8 @@ ] } ], - "prompt_number": 13 + "prompt_number": 13, + "trusted": false }, { "cell_type": "heading", @@ -350,7 +361,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 14 + "prompt_number": 14, + "trusted": false }, { "cell_type": "code", @@ -364,7 +376,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 15 + "prompt_number": 15, + "trusted": false }, { "cell_type": "code", @@ -377,29 +390,8 @@ ], "language": "python", "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "Labels list must be the same size as the values list.", - "output_type": "pyerr", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m generator={'gnp': nx.gnp_random_graph,\n\u001b[1;32m 3\u001b[0m \u001b[0;34m'erdos_renyi'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mnx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0merdos_renyi_graph\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m 'binomial': nx.binomial_graph})\n\u001b[0m", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/html/widgets/interact.py\u001b[0m in \u001b[0;36minteract\u001b[0;34m(f, **kwargs)\u001b[0m\n\u001b[1;32m 135\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 136\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0minteract\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 137\u001b[0;31m \u001b[0mw\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minteractive\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 138\u001b[0m \u001b[0mdisplay\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/html/widgets/interact.py\u001b[0m in \u001b[0;36minteractive\u001b[0;34m(f, **kwargs)\u001b[0m\n\u001b[1;32m 107\u001b[0m \u001b[0mwidget\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 108\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 109\u001b[0;31m \u001b[0mwidget\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_widget_abbrev\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 110\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mwidget\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 111\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Object cannot be transformed to a Widget\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/html/widgets/interact.py\u001b[0m in \u001b[0;36m_widget_abbrev\u001b[0;34m(o)\u001b[0m\n\u001b[1;32m 61\u001b[0m \u001b[0mlabels\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0municode_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mk\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mk\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mo\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0mvalues\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mo\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 63\u001b[0;31m \u001b[0mw\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mDropdownWidget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalues\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlabels\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlabels\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 64\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mw\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 65\u001b[0m \u001b[0;31m# Special case float and int == 0.0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/html/widgets/widget_selection.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, *pargs, **kwargs)\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalue_lock\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mLock\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mon_trait_change\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_string_value_set\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'_value'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 39\u001b[0;31m \u001b[0mDOMWidget\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0mpargs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 40\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_labels_changed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mold\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/html/widgets/widget.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 103\u001b[0m \u001b[0;34m\"\"\"Public constructor\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 104\u001b[0;31m \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mWidget\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 105\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 106\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mon_trait_change\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_handle_property_changed\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/config/configurable.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 100\u001b[0m \u001b[0;31m# This should go second so individual keyword arguments override\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 101\u001b[0m \u001b[0;31m# the values in config.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 102\u001b[0;31m \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mConfigurable\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 103\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 104\u001b[0m \u001b[0;31m#-------------------------------------------------------------------------\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/utils/traitlets.pyc\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, *args, **kw)\u001b[0m\n\u001b[1;32m 430\u001b[0m \u001b[0;31m# notifications.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 431\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m \u001b[0;32min\u001b[0m \u001b[0miteritems\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkw\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 432\u001b[0;31m \u001b[0msetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mkey\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 433\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 434\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_notify_trait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mold_value\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew_value\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/utils/traitlets.pyc\u001b[0m in \u001b[0;36m__set__\u001b[0;34m(self, obj, value)\u001b[0m\n\u001b[1;32m 318\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_trait_values\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnew_value\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 319\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mold_value\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mnew_value\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 320\u001b[0;31m \u001b[0mobj\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_notify_trait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mold_value\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew_value\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 321\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 322\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_validate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/utils/traitlets.pyc\u001b[0m in \u001b[0;36m_notify_trait\u001b[0;34m(self, name, old_value, new_value)\u001b[0m\n\u001b[1;32m 467\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew_value\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 468\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mnargs\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0moffset\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 469\u001b[0;31m \u001b[0mc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mold_value\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew_value\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 470\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 471\u001b[0m raise TraitError('a trait changed callback '\n", - "\u001b[0;32m/Users/bgranger/Documents/Computing/IPython/code/ipython/IPython/html/widgets/widget_selection.pyc\u001b[0m in \u001b[0;36m_labels_changed\u001b[0;34m(self, name, old, new)\u001b[0m\n\u001b[1;32m 45\u001b[0m value for the value_names Dict.\"\"\"\n\u001b[1;32m 46\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnew\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 47\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Labels list must be the same size as the values list.'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_values_changed\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mold\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnew\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m: Labels list must be the same size as the values list." - ] - } - ], - "prompt_number": 16 + "outputs": [], + "trusted": true }, { "cell_type": "heading", @@ -426,7 +418,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 18 + "prompt_number": 18, + "trusted": false }, { "cell_type": "code", @@ -437,7 +430,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 19 + "prompt_number": 19, + "trusted": false }, { "cell_type": "code", @@ -513,7 +507,8 @@ ] } ], - "prompt_number": 20 + "prompt_number": 20, + "trusted": false }, { "cell_type": "code", @@ -534,7 +529,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 21 + "prompt_number": 21, + "trusted": false }, { "cell_type": "code", @@ -545,7 +541,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 22 + "prompt_number": 22, + "trusted": false }, { "cell_type": "code", @@ -612,7 +609,8 @@ ] } ], - "prompt_number": 24 + "prompt_number": 24, + "trusted": false }, { "cell_type": "code", @@ -636,7 +634,8 @@ ] } ], - "prompt_number": 25 + "prompt_number": 25, + "trusted": false }, { "cell_type": "code", @@ -704,7 +703,8 @@ ] } ], - "prompt_number": 26 + "prompt_number": 26, + "trusted": false }, { "cell_type": "heading", @@ -731,7 +731,8 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 27 + "prompt_number": 14, + "trusted": true }, { "cell_type": "code", @@ -742,14 +743,15 @@ " rate = 8000\n", " times = np.linspace(0,max_time,rate*max_time)\n", " signal = np.sin(2*np.pi*f1*times) + np.sin(2*np.pi*f2*times)\n", - " print f1, f2, abs(f1-f2)\n", + " print(f1, f2, abs(f1-f2))\n", " display(Audio(data=signal, rate=rate))\n", " return signal" ], "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 30 + "prompt_number": 17, + "trusted": true }, { "cell_type": "code", @@ -765,14 +767,14 @@ "output_type": "stream", "stream": "stdout", "text": [ - "265.1 250.0 15.1\n" + "245.4 250.0 4.599999999999994\n" ] }, { "html": [ "\n", " \n", " " @@ -780,11 +782,12 @@ "metadata": {}, "output_type": "display_data", "text": [ - "" + "" ] } ], - "prompt_number": 31 + "prompt_number": 18, + "trusted": true }, { "cell_type": "code", @@ -794,7 +797,26 @@ ], "language": "python", "metadata": {}, - "outputs": [] + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 19, + "text": [ + "[]" + ] + }, + { + "metadata": {}, + "output_type": "display_data", + "png": "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\n", + "text": [ + "" + ] + } + ], + "prompt_number": 19, + "trusted": true } ], "metadata": {}