[sagemath] 01/01: Undo trac #21267 (SageNB interacts for Jupyter).

Tobias Hansen thansen at moszumanska.debian.org
Sun Mar 26 18:23:17 UTC 2017


This is an automated email from the git hooks/post-receive script.

thansen pushed a commit to branch master
in repository sagemath.

commit 044cd0ba0311e06fb806d078826076a1ea592fb8
Author: Tobias Hansen <thansen at debian.org>
Date:   Sun Mar 26 14:47:49 2017 +0100

    Undo trac #21267 (SageNB interacts for Jupyter).
---
 debian/changelog                                   |    2 +
 ...o-trac-21267-sagenb-interacts-for-jupyter.patch | 1400 ++++++++++++++++++++
 debian/patches/series                              |    1 +
 3 files changed, 1403 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 9ae6417..cdad511 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -16,6 +16,8 @@ sagemath (7.6-1) UNRELEASED; urgency=medium
     - u0-use-local-threejs.patch
     - u0-version-pari-2.9.patch
     - u0-version-pynac-0.7.4.patch
+  * New patches:
+    - dt-undo-trac-21267-sagenb-interacts-for-jupyter.patch
 
  -- Tobias Hansen <thansen at debian.org>  Sat, 18 Mar 2017 12:00:06 +0000
 
diff --git a/debian/patches/dt-undo-trac-21267-sagenb-interacts-for-jupyter.patch b/debian/patches/dt-undo-trac-21267-sagenb-interacts-for-jupyter.patch
new file mode 100644
index 0000000..21aaa69
--- /dev/null
+++ b/debian/patches/dt-undo-trac-21267-sagenb-interacts-for-jupyter.patch
@@ -0,0 +1,1400 @@
+From 30955d2ec72338cc7b13c17922389bb58c8f278c Mon Sep 17 00:00:00 2001
+From: Jeroen Demeyer <jdemeyer at cage.ugent.be>
+Date: Mon, 19 Sep 2016 14:27:28 +0200
+Subject: Port SageNB interacts to Jupyter
+
+---
+ build/make/deps                                |   2 +-
+ src/doc/en/reference/repl/index.rst            |   3 +
+ src/sage/repl/ipython_extension.py             |  36 +-
+ src/sage/repl/ipython_kernel/all_jupyter.py    |   9 +
+ src/sage/repl/ipython_kernel/interact.py       | 242 ++++++++++
+ src/sage/repl/ipython_kernel/kernel.py         |  22 +-
+ src/sage/repl/ipython_kernel/widgets.py        | 407 +++++++++++++++++
+ src/sage/repl/ipython_kernel/widgets_sagenb.py | 584 +++++++++++++++++++++++++
+ 8 files changed, 1299 insertions(+), 6 deletions(-)
+ create mode 100644 src/sage/repl/ipython_kernel/all_jupyter.py
+ create mode 100644 src/sage/repl/ipython_kernel/interact.py
+ create mode 100644 src/sage/repl/ipython_kernel/widgets.py
+ create mode 100644 src/sage/repl/ipython_kernel/widgets_sagenb.py
+
+--- a/sage/build/make/deps
++++ b/sage/build/make/deps
+@@ -201,7 +201,7 @@
+ 	| $(SAGERUNTIME) $(inst_maxima) $(inst_networkx) $(inst_scipy) \
+ 	$(inst_matplotlib) $(inst_pillow) $(inst_mathjax) $(inst_mpmath) \
+ 	$(inst_ipykernel) $(inst_jupyter_client) $(inst_conway_polynomials) \
+-	$(inst_tachyon) $(inst_jmol) $(inst_thebe) $(inst_ipywidgets)
++	$(inst_tachyon) $(inst_jmol) $(inst_thebe)
+ 
+ doc: doc-html
+ 
+--- a/sage/src/doc/en/reference/repl/index.rst
++++ b/sage/src/doc/en/reference/repl/index.rst
+@@ -92,9 +92,6 @@
+    sage/repl/interpreter
+    sage/repl/ipython_extension
+    sage/repl/interface_magic
+-   sage/repl/ipython_kernel/interact
+-   sage/repl/ipython_kernel/widgets
+-   sage/repl/ipython_kernel/widgets_sagenb
+    sage/repl/ipython_kernel/install
+    sage/repl/ipython_kernel/kernel
+    sage/repl/ipython_tests
+--- a/sage/src/sage/repl/ipython_extension.py
++++ b/sage/src/sage/repl/ipython_extension.py
+@@ -400,28 +400,14 @@
+         import atexit
+         atexit.register(quit)
+ 
+-    @staticmethod
+-    def all_globals():
+-        """
+-        Return a Python module containing all globals which should be
+-        made available to the user.
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_extension import SageCustomizations
+-            sage: SageCustomizations.all_globals()
+-            <module 'sage.all_cmdline' ...>
+-        """
+-        from sage import all_cmdline
+-        return all_cmdline
+-
+     def init_environment(self):
+         """
+         Set up Sage command-line environment
+         """
+         # import outside of cell so we don't get a traceback
++        from sage import all_cmdline
+         from sage.repl.user_globals import initialize_globals
+-        initialize_globals(self.all_globals(), self.shell.user_ns)
++        initialize_globals(all_cmdline, self.shell.user_ns)
+         self.run_init()
+ 
+     def run_init(self):
+@@ -456,24 +442,6 @@
+             s.physical_line_transforms.insert(1, SagePromptTransformer())
+             s.python_line_transforms.append(SagePreparseTransformer())
+ 
+-
+-class SageJupyterCustomizations(SageCustomizations):
+-    @staticmethod
+-    def all_globals():
+-        """
+-        Return a Python module containing all globals which should be
+-        made available to the user when running the Jupyter notebook.
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_extension import SageJupyterCustomizations
+-            sage: SageJupyterCustomizations.all_globals()
+-            <module 'sage.repl.ipython_kernel.all_jupyter' ...>
+-        """
+-        from .ipython_kernel import all_jupyter
+-        return all_jupyter
+-
+-
+ # from http://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop
+ from functools import wraps
+ def run_once(func):
+--- a/sage/src/sage/repl/ipython_kernel/all_jupyter.py
++++ /dev/null
+@@ -1,9 +0,0 @@
+-"""
+-All imports for Jupyter
+-"""
+-
+-from sage.all_cmdline import *
+-
+-from .widgets_sagenb import (input_box, text_control, slider,
+-        range_slider, checkbox, selector, input_grid, color_selector)
+-from .interact import interact
+--- a/sage/src/sage/repl/ipython_kernel/interact.py
++++ /dev/null
+@@ -1,242 +0,0 @@
+-r"""
+-Interacts for the Sage Jupyter notebook
+-
+-This is mostly the same as the stock ``ipywidgets.interact``, but with
+-some customizations for Sage.
+-
+-TESTS:
+-
+-We need to setup a proper test environment for widgets::
+-
+-    sage: from ipywidgets.widgets.tests import setup_test_comm
+-    sage: setup_test_comm()
+-
+-EXAMPLES::
+-
+-    sage: from sage.repl.ipython_kernel.interact import interact
+-    sage: @interact
+-    ....: def f(x=(0,10)):
+-    ....:     pass
+-    Interactive function <function f ...> with 1 widget
+-      x: IntSlider(value=5, min=0, max=10, step=1, description=u'x')
+-    sage: f.widget.children
+-    (IntSlider(value=5, min=0, max=10, step=1, description=u'x'), Output())
+-"""
+-
+-#*****************************************************************************
+-#       Copyright (C) 2017 Jeroen Demeyer <jdemeyer at cage.ugent.be>
+-#
+-# This program is free software: you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation, either version 2 of the License, or
+-# (at your option) any later version.
+-#                  http://www.gnu.org/licenses/
+-#*****************************************************************************
+-
+-from ipywidgets.widgets import SelectionSlider, ValueWidget
+-from ipywidgets.widgets.interaction import interactive, signature, ValueWidget
+-from copy import copy
+-from collections import Iterable, Iterator
+-from .widgets import EvalText, SageColorPicker
+-from sage.structure.element import parent
+-from sage.symbolic.ring import SR
+-from sage.plot.colors import Color
+-
+-
+-class sage_interactive(interactive):
+-    """
+-    Wrapper around the ipywidgets interactive which handles some SageNB
+-    specifics.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.interact import sage_interactive
+-        sage: def myfunc(x=10, y="hello", z=None): pass
+-        sage: sage_interactive(myfunc, x=(0,100), z=["one", "two", "three"])
+-        Interactive function <function myfunc ...> with 3 widgets
+-          x: IntSlider(value=10, min=0, max=100, step=1, description=u'x')
+-          y: Text(value=u'hello', description=u'y')
+-          z: Dropdown(value='one', options=['one', 'two', 'three'], description=u'z')
+-    """
+-    def __init__(*args, **kwds):
+-        """
+-        See :class:`ipywidgets.widgets.interaction.interactive`
+-
+-        TESTS::
+-
+-            sage: from sage.repl.ipython_kernel.interact import sage_interactive
+-            sage: def myfunc(): pass
+-            sage: sage_interactive(myfunc, dict(manual=True))
+-            Manual interactive function <function myfunc ...> with 0 widgets
+-
+-        ::
+-
+-            sage: def myfunc(auto_update=False): pass
+-            sage: sage_interactive(myfunc)
+-            Manual interactive function <function myfunc ...> with 0 widgets
+-            sage: def myfunc(auto_update=None): pass
+-            sage: sage_interactive(myfunc)
+-            Interactive function <function myfunc ...> with 0 widgets
+-        """
+-        # Use *args to avoid name clash with keyword arguments
+-        if len(args) < 3:
+-            (self, f) = args
+-            options = {}
+-        else:
+-            (self, f, options) = args
+-            options = options.copy()
+-
+-        # Check for auto_update in signature
+-        sig = signature(f)
+-        params = copy(sig.parameters)
+-        try:
+-            p_auto_update = params.pop("auto_update")
+-        except KeyError:
+-            pass
+-        else:
+-            options["manual"] = (p_auto_update.default is False)
+-
+-        self.__signature = sig.replace(parameters=params.values())
+-        super(sage_interactive, self).__init__(f, options, **kwds)
+-        if self.manual:
+-            # In Sage, manual interacts are always run once
+-            self.on_displayed(self.update)
+-
+-    def __repr__(self):
+-        """
+-        Textual representation of this interactive function.
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_kernel.interact import sage_interactive
+-            sage: def myfunc(): pass
+-            sage: sage_interactive(myfunc)
+-            Interactive function <function myfunc ...> with 0 widgets
+-        """
+-        s = "Manual interactive" if self.manual else "Interactive"
+-        widgets = [w for w in self.children if isinstance(w, ValueWidget)]
+-        n = len(widgets)
+-        s += " function %r with %s widget%s" % (
+-                self.f, n, "s" if n != 1 else "")
+-        for w in widgets:
+-            s += "\n  %s: %s" % (w._kwarg, w)
+-        return s
+-
+-    def signature(self):
+-        """
+-        Return the fixed signature of the interactive function (after
+-        a possible ``auto_update`` parameter was removed).
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_kernel.interact import sage_interactive
+-            sage: def myfunc(x=[1,2,3], auto_update=False): pass
+-            sage: sage_interactive(myfunc).signature().parameters
+-            OrderedDict([('x', <Parameter ... 'x'>)])
+-        """
+-        return self.__signature
+-
+-    @classmethod  # Behaves like a staticmethod, but we need super()
+-    def widget_from_single_value(cls, abbrev, *args, **kwds):
+-        """
+-        Convert a single value (i.e. a non-iterable) to a widget.
+-
+-        This supports the Sage :class:`Color` class. Any unknown type
+-        is changed to a string for evaluating. This is meant to support
+-        symbolic expressions like ``sin(x)``.
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_kernel.interact import sage_interactive
+-            sage: sage_interactive.widget_from_single_value("sin(x)")
+-            Text(value=u'sin(x)')
+-            sage: sage_interactive.widget_from_single_value(sin(x))
+-            EvalText(value=u'sin(x)')
+-            sage: from sage.plot.colors import Color
+-            sage: sage_interactive.widget_from_single_value(Color('cornflowerblue'))
+-            SageColorPicker(value='#6495ed')
+-        """
+-        # Support Sage Colors
+-        if isinstance(abbrev, Color):
+-            return SageColorPicker(value=abbrev.html_color())
+-        # Get widget from IPython if possible
+-        widget = super(sage_interactive, cls).widget_from_single_value(abbrev, *args, **kwds)
+-        if widget is not None or isinstance(abbrev, Iterable):
+-            return widget
+-        # If IPython didn't construct a widget and the abbrev is not an
+-        # iterable, return an EvalText widget
+-        return EvalText(value=str(abbrev))
+-
+-    @classmethod  # Behaves like a staticmethod, but we need super()
+-    def widget_from_tuple(cls, abbrev, *args, **kwds):
+-        """
+-        Convert a tuple to a widget.
+-
+-        This supports two SageNB extensions: ``(description, abbrev)``
+-        if ``description`` is a string and ``(default, abbrev)`` if
+-        ``abbrev`` is not a single value.
+-
+-        Symbolic expressions are changed to a floating-point number.
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_kernel.interact import sage_interactive
+-            sage: sage_interactive.widget_from_tuple( (0, 10) )
+-            IntSlider(value=5, min=0, max=10, step=1)
+-            sage: sage_interactive.widget_from_tuple( (3, (0, 10)) )
+-            IntSlider(value=3, min=0, max=10, step=1)
+-            sage: sage_interactive.widget_from_tuple( (2, dict(one=1, two=2, three=3)) )
+-            Dropdown(value=2, options={'three': 3, 'two': 2, 'one': 1})
+-            sage: sage_interactive.widget_from_tuple( (sqrt(2), pi) )
+-            FloatSlider(value=2.277903107981444, min=1.4142135623730951, max=3.141592653589793, step=0.1)
+-        """
+-        # Support (description, abbrev)
+-        if len(abbrev) == 2 and isinstance(abbrev[0], str):
+-            widget = cls.widget_from_abbrev(abbrev[1])
+-            widget.descriprion = abbrev[0]
+-            return widget
+-        # Support (default, abbrev)
+-        if len(abbrev) == 2 and isinstance(abbrev[1], Iterable):
+-            widget = cls.widget_from_abbrev(abbrev[1])
+-            widget.value = abbrev[0]
+-            return widget
+-        # Numerically evaluate symbolic expressions
+-        def n(x):
+-            if parent(x) is SR:
+-                return x.numerical_approx()
+-            else:
+-                return x
+-        abbrev = tuple(n(x) for x in abbrev)
+-        return super(sage_interactive, cls).widget_from_tuple(abbrev, *args, **kwds)
+-
+-    @classmethod  # Behaves like a staticmethod, but we need super()
+-    def widget_from_iterable(cls, abbrev, *args, **kwds):
+-        """
+-        Convert an unspecified iterable to a widget.
+-
+-        This behaves like in ipywidgets, except that an iterator (like
+-        a generator object) becomes a ``SelectionSlider``.
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_kernel.interact import sage_interactive
+-            sage: sage_interactive.widget_from_iterable([1..5])
+-            Dropdown(value=1, options=[1, 2, 3, 4, 5])
+-            sage: sage_interactive.widget_from_iterable(iter([1..5]))
+-            SelectionSlider(value=1, options=[1, 2, 3, 4, 5])
+-            sage: sage_interactive.widget_from_iterable((1..5))
+-            SelectionSlider(value=1, options=[1, 2, 3, 4, 5])
+-            sage: sage_interactive.widget_from_iterable(x for x in [1..5])
+-            SelectionSlider(value=1, options=[1, 2, 3, 4, 5])
+-            sage: def gen():
+-            ....:     yield 1; yield 2; yield 3; yield 4; yield 5
+-            sage: sage_interactive.widget_from_iterable(gen())
+-            SelectionSlider(value=1, options=[1, 2, 3, 4, 5])
+-        """
+-        if isinstance(abbrev, Iterator):
+-            return SelectionSlider(options=list(abbrev))
+-        return super(sage_interactive, cls).widget_from_iterable(abbrev, *args, **kwds)
+-
+-
+-# @interact decorator
+-interact = sage_interactive.factory()
+--- a/sage/src/sage/repl/ipython_kernel/kernel.py
++++ b/sage/src/sage/repl/ipython_kernel/kernel.py
+@@ -19,9 +19,9 @@
+ from ipykernel.zmqshell import ZMQInteractiveShell
+ from traitlets import Type
+ 
+-from sage.env import SAGE_VERSION
++from sage.env import SAGE_VERSION, SAGE_EXTCODE, SAGE_DOC
+ from sage.repl.interpreter import SageNotebookInteractiveShell
+-from sage.repl.ipython_extension import SageJupyterCustomizations
++from sage.repl.ipython_extension import SageCustomizations
+ 
+ class SageZMQInteractiveShell(SageNotebookInteractiveShell, ZMQInteractiveShell):
+     pass
+@@ -48,7 +48,7 @@
+             <sage.repl.ipython_kernel.kernel.SageKernel object at 0x...>
+         """
+         super(SageKernel, self).__init__(**kwds)
+-        SageJupyterCustomizations(self.shell)
++        SageCustomizations(self.shell)
+ 
+     @property
+     def banner(self):
+@@ -166,21 +166,5 @@
+         ]
+ 
+     def pre_handler_hook(self):
+-        """
+-        Restore the signal handlers to their default values at Sage
+-        startup, saving the old handler at the ``saved_sigint_handler``
+-        attribute. This is needed because Jupyter needs to change the
+-        ``SIGINT`` handler.
+-
+-        See :trac:`19135`.
+-
+-        TESTS::
+-
+-            sage: from sage.repl.ipython_kernel.kernel import SageKernel
+-            sage: k = SageKernel.__new__(SageKernel)
+-            sage: k.pre_handler_hook()
+-            sage: k.saved_sigint_handler
+-            <built-in function python_check_interrupt>
+-        """
+         from cysignals import init_cysignals
+         self.saved_sigint_handler = init_cysignals()
+--- a/sage/src/sage/repl/ipython_kernel/widgets.py
++++ /dev/null
+@@ -1,407 +0,0 @@
+-r"""
+-Widgets to be used for the Sage Jupyter notebook
+-
+-These are all based on widgets from ``ipywidgets``, changing or
+-combining existing widgets.
+-
+-TESTS:
+-
+-We need to setup a proper test environment for widgets::
+-
+-    sage: from ipywidgets.widgets.tests import setup_test_comm
+-    sage: setup_test_comm()
+-"""
+-
+-#*****************************************************************************
+-#       Copyright (C) 2017 Jeroen Demeyer <jdemeyer at cage.ugent.be>
+-#
+-# This program is free software: you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation, either version 2 of the License, or
+-# (at your option) any later version.
+-#                  http://www.gnu.org/licenses/
+-#*****************************************************************************
+-
+-from ipywidgets.widgets import (IntSlider, IntRangeSlider, FloatSlider,
+-        FloatRangeSlider, Text, Textarea, ColorPicker,
+-        Label, HBox, VBox, ValueWidget)
+-from traitlets import List, Unicode, link
+-
+-from sage.misc.sage_eval import sage_eval
+-from sage.repl.user_globals import get_globals
+-from sage.plot.colors import Color
+-
+-
+-class TransformWidget(object):
+-    """
+-    A mixin class for a widget to transform the bare widget value for
+-    use in interactive functions.
+-
+-    INPUT:
+-
+-    - ``transform`` -- a one-argument function which transforms the
+-      value of the widget for use by an interactive function.
+-
+-    - other arguments are passed to the base class
+-
+-    EXAMPLES::
+-
+-        sage: from ipywidgets import ToggleButtons
+-        sage: from sage.repl.ipython_kernel.widgets import TransformWidget
+-        sage: class TransformToggleButtons(TransformWidget, ToggleButtons): pass
+-        sage: w = TransformToggleButtons(options=["pi", "e"], transform=lambda x: x+x)
+-        sage: w
+-        TransformToggleButtons(value='pi', options=['pi', 'e'])
+-        sage: w.get_interact_value()
+-        'pipi'
+-    """
+-    def __init__(self, *args, **kwds):
+-        """
+-        Construct a :class:`TransformWidget`.
+-
+-        TESTS::
+-
+-            sage: from sage.repl.ipython_kernel.widgets import TransformWidget
+-            sage: w = TransformWidget(transform=dict)
+-            sage: w._TransformWidget__transform
+-            <type 'dict'>
+-        """
+-        self.__transform = kwds.pop("transform", None)
+-        return super(TransformWidget, self).__init__(*args, **kwds)
+-
+-    def get_value(self):
+-        """
+-        Return ``self.value``.
+-
+-        This is meant to be overridden by sub-classes to change the
+-        input of the transform function.
+-
+-        EXAMPLES::
+-
+-            sage: from ipywidgets import ColorPicker
+-            sage: from sage.repl.ipython_kernel.widgets import TransformWidget
+-            sage: class TransformColorPicker(TransformWidget, ColorPicker): pass
+-            sage: TransformColorPicker(value="red").get_value()
+-            'red'
+-        """
+-        return self.value
+-
+-    def get_interact_value(self):
+-        """
+-        Return the transformed value of this widget, by calling
+-        the ``transform`` function.
+-
+-        EXAMPLES:
+-
+-            sage: from ipywidgets import Checkbox
+-            sage: from sage.repl.ipython_kernel.widgets import TransformWidget
+-            sage: class TransformCheckbox(TransformWidget, Checkbox): pass
+-            sage: w = TransformCheckbox(value=True, transform=int); w
+-            TransformCheckbox(value=True)
+-            sage: w.get_interact_value()
+-            1
+-        """
+-        v = self.get_value()
+-        f = self.__transform
+-        if f is None:
+-            return v
+-        else:
+-            return f(v)
+-
+-
+-class EvalWidget(TransformWidget):
+-    """
+-    A mixin class for a widget to evaluate (using :func:`sage_eval`) the
+-    widget value and possibly transform it like :class:`TransformWidget`.
+-
+-    EXAMPLES::
+-
+-        sage: from ipywidgets import ToggleButtons
+-        sage: from sage.repl.ipython_kernel.widgets import EvalWidget
+-        sage: class EvalToggleButtons(EvalWidget, ToggleButtons): pass
+-        sage: w = EvalToggleButtons(options=["pi", "e"], transform=lambda x: x+x)
+-        sage: w
+-        EvalToggleButtons(value='pi', options=['pi', 'e'])
+-        sage: w.get_interact_value()
+-        2*pi
+-    """
+-    def get_value(self):
+-        """
+-        Evaluate the bare widget value using :func:`sage_eval`.
+-
+-        EXAMPLES:
+-
+-            sage: from ipywidgets import Dropdown
+-            sage: from sage.repl.ipython_kernel.widgets import EvalWidget
+-            sage: class EvalDropdown(EvalWidget, Dropdown): pass
+-            sage: w = EvalDropdown(options=["the_answer"], transform=RR)
+-            sage: w
+-            EvalDropdown(value='the_answer', options=['the_answer'])
+-            sage: the_answer = 42
+-            sage: w.get_value()
+-            42
+-            sage: w.get_interact_value()
+-            42.0000000000000
+-        """
+-        return sage_eval(self.value, get_globals())
+-
+-
+-class TransformIntSlider(TransformWidget, IntSlider):
+-    """
+-    An :class:`ipywidgets.IntSlider` widget with an optional
+-    transformation.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import TransformIntSlider
+-        sage: w = TransformIntSlider(min=0, max=100, value=7, transform=lambda x: x^2)
+-        sage: w
+-        TransformIntSlider(value=7, min=0, max=100, step=1)
+-        sage: w.get_interact_value()
+-        49
+-    """
+-    pass
+-
+-
+-class TransformFloatSlider(TransformWidget, FloatSlider):
+-    """
+-    A :class:`ipywidgets.FloatSlider` widget with an optional
+-    transformation.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import TransformFloatSlider
+-        sage: w = TransformFloatSlider(min=0, max=100, value=7, transform=lambda x: sqrt(x))
+-        sage: w
+-        TransformFloatSlider(value=7.0, min=0.0, max=100.0, step=0.1)
+-        sage: w.get_interact_value()
+-        2.6457513110645907
+-    """
+-    pass
+-
+-
+-class TransformIntRangeSlider(TransformWidget, IntRangeSlider):
+-    """
+-    An :class:`ipywidgets.IntRangeSlider` widget with an optional
+-    transformation.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import TransformIntRangeSlider
+-        sage: w = TransformIntRangeSlider(min=0, max=100, value=(7,9), transform=lambda x: x[1]-x[0])
+-        sage: w
+-        TransformIntRangeSlider(value=(7, 9), min=0, max=100, step=1)
+-        sage: w.get_interact_value()
+-        2
+-    """
+-    pass
+-
+-
+-class TransformFloatRangeSlider(TransformWidget, FloatRangeSlider):
+-    """
+-    An :class:`ipywidgets.FloatRangeSlider` widget with an optional
+-    transformation.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import TransformFloatRangeSlider
+-        sage: w = TransformFloatRangeSlider(min=0, max=100, value=(7,9), transform=lambda x: x[1]-x[0])
+-        sage: w
+-        TransformFloatRangeSlider(value=(7.0, 9.0), min=0.0, max=100.0, step=1.0)
+-        sage: w.get_interact_value()
+-        2.0
+-    """
+-    pass
+-
+-
+-class TransformText(TransformWidget, Text):
+-    """
+-    A :class:`ipywidgets.Text` widget with an optional
+-    transformation.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import TransformText
+-        sage: w = TransformText(value="hello", transform=lambda x: x+x)
+-        sage: w
+-        TransformText(value=u'hello')
+-        sage: w.get_interact_value()
+-        u'hellohello'
+-    """
+-    pass
+-
+-
+-class TransformTextarea(TransformWidget, Textarea):
+-    """
+-    A :class:`ipywidgets.Textarea` widget with an optional
+-    transformation.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import TransformTextarea
+-        sage: w = TransformTextarea(value="hello", transform=lambda x: x+x)
+-        sage: w
+-        TransformTextarea(value=u'hello')
+-        sage: w.get_interact_value()
+-        u'hellohello'
+-    """
+-    pass
+-
+-
+-class EvalText(EvalWidget, Text):
+-    """
+-    A :class:`ipywidgets.Text` widget which evaluates (using
+-    :func:`sage_eval`) its contents and applies an optional transformation.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import EvalText
+-        sage: w = EvalText(value="pi", transform=lambda x: x^2)
+-        sage: w
+-        EvalText(value=u'pi')
+-        sage: w.get_interact_value()
+-        pi^2
+-    """
+-    pass
+-
+-
+-class EvalTextarea(EvalWidget, Textarea):
+-    """
+-    A :class:`ipywidgets.Textarea` widget which evaluates (using
+-    :func:`sage_eval`) its contents and applies an optional transformation.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import EvalTextarea
+-        sage: w = EvalTextarea(value="pi", transform=lambda x: x^2)
+-        sage: w
+-        EvalTextarea(value=u'pi')
+-        sage: w.get_interact_value()
+-        pi^2
+-    """
+-    pass
+-
+-
+-class SageColorPicker(ColorPicker):
+-    """
+-    A color picker widget return a Sage :class:`Color`.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.widgets import SageColorPicker
+-        sage: SageColorPicker()
+-        SageColorPicker(value='black')
+-    """
+-    def get_interact_value(self):
+-        """
+-        Return a Sage :class:`Color` corresponding to the value of this
+-        widget.
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_kernel.widgets import SageColorPicker
+-            sage: SageColorPicker().get_interact_value()
+-            RGB color (0.0, 0.0, 0.0)
+-        """
+-        return Color(self.value)
+-
+-
+-class Grid(TransformWidget, HBox, ValueWidget):
+-    """
+-    A square grid of widgets whose value is a list of lists of the
+-    values of the individual widgets.
+-
+-    This is usually created using the :func:`input_grid` function.
+-
+-    EXAMPLES::
+-
+-        sage: from ipywidgets import Text
+-        sage: from sage.repl.ipython_kernel.widgets import Grid
+-        sage: w = Grid(2, 2, lambda i,j: Text(value="%s,%s"%(i,j)))
+-        sage: w
+-        Grid(value=[[u'0,0', u'0,1'], [u'1,0', u'1,1']], children=(Label(value=u''), VBox(children=(Text(value=u'0,0'), Text(value=u'1,0'))), VBox(children=(Text(value=u'0,1'), Text(value=u'1,1')))))
+-        sage: w.get_interact_value()
+-        [[u'0,0', u'0,1'], [u'1,0', u'1,1']]
+-    """
+-    value = List()
+-    description = Unicode()
+-
+-    def __init__(self, nrows, ncols, make_widget, description=u"", transform=None):
+-        """
+-        Create a :class:`Grid` widget.
+-
+-        INPUT:
+-
+-        - ``nrows``, ``ncols`` -- number of rows and columns in the grid
+-
+-        - ``make_widget`` -- a function of two arguments ``(i,j)``
+-          returning the widget to be placed at position ``(i,j)``.
+-
+-        - ``description`` -- an optional label.
+-
+-        - ``transform`` -- an optional transformation, see :class:`TransformWidget`.
+-
+-        EXAMPLES::
+-
+-            sage: from sage.repl.ipython_kernel.widgets import Grid, EvalText
+-            sage: w = Grid(2, 2, lambda i,j: EvalText(str(j+4*i)),
+-            ....:         description="2x2 matrix", transform=matrix)
+-            sage: w
+-            Grid(value=[[0, 1], [4, 5]], description=u'2x2 matrix', children=(Label(value=u'2x2 matrix'), VBox(children=(EvalText(value=u'0'), EvalText(value=u'4'))), VBox(children=(EvalText(value=u'1'), EvalText(value=u'5')))))
+-            sage: w.get_interact_value()
+-            [0 1]
+-            [4 5]
+-
+-        TESTS::
+-
+-            sage: w = Grid(0, 1, lambda i,j: EvalText())
+-            Traceback (most recent call last):
+-            ...
+-            ValueError: Grid requires a positive number of rows and columns
+-        """
+-        if nrows < 1 or ncols < 1:
+-            raise ValueError("Grid requires a positive number of rows and columns")
+-        super(Grid, self).__init__(transform=transform)
+-
+-        label = Label(description)
+-        link((label, "value"), (self, "description"))
+-
+-        self.cols = []
+-        for j in range(ncols):
+-            col = VBox()
+-            widgets = []
+-            for i in range(nrows):
+-                w = make_widget(i, j)
+-                w.observe(self._update, names="value")
+-                widgets.append(w)
+-            col.children = widgets
+-            self.cols.append(col)
+-        self.children = [label] + self.cols
+-        self._update()
+-
+-    def _update(self, *args):
+-        """
+-        Compute the ``value`` of the grid.
+-
+-        Thanks to traitlets magic, this is automatically called
+-        whenever one of the child widgets changes.
+-
+-        EXAMPLES::
+-
+-            sage: from ipywidgets import Text
+-            sage: from sage.repl.ipython_kernel.widgets import Grid
+-            sage: w = Grid(2, 2, lambda i,j: Text(value="%s,%s"%(i,j)))
+-            sage: w._update()
+-            sage: w.value
+-            [[u'0,0', u'0,1'], [u'1,0', u'1,1']]
+-            sage: w.cols[0].children[0].value = "abc"
+-            sage: w.value
+-            [[u'abc', u'0,1'], [u'1,0', u'1,1']]
+-        """
+-        v = [[]]
+-        for col in self.cols:
+-            for i in range(len(col.children)):
+-                if i >= len(v):
+-                    v.append([])
+-                v[i].append(col.children[i].get_interact_value())
+-        self.value = v
+--- a/sage/src/sage/repl/ipython_kernel/widgets_sagenb.py
++++ /dev/null
+@@ -1,584 +0,0 @@
+-r"""
+-Functions to construct widgets, based on the old SageNB interface.
+-
+-These should ensure mostly backwards compatibility with SageNB.
+-
+-TESTS:
+-
+-We need to setup a proper test environment for widgets::
+-
+-    sage: from ipywidgets.widgets.tests import setup_test_comm
+-    sage: setup_test_comm()
+-
+-EXAMPLES::
+-
+-    sage: from sage.repl.ipython_kernel.widgets_sagenb import text_control
+-    sage: text_control("Hello World!")
+-    HTML(value=u'Hello World!')
+-"""
+-
+-#*****************************************************************************
+-#       Copyright (C) 2017 Jeroen Demeyer <jdemeyer at cage.ugent.be>
+-#
+-# This program is free software: you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation, either version 2 of the License, or
+-# (at your option) any later version.
+-#                  http://www.gnu.org/licenses/
+-#*****************************************************************************
+-
+-from ipywidgets.widgets import (IntSlider, IntRangeSlider, FloatSlider,
+-        FloatRangeSlider, SelectionSlider,
+-        Checkbox, ToggleButtons, Dropdown, HTML)
+-from .widgets import (TransformText, TransformTextarea,
+-        TransformIntSlider, TransformIntRangeSlider,
+-        TransformFloatSlider, TransformFloatRangeSlider,
+-        EvalText, EvalTextarea, SageColorPicker, Grid)
+-from ipywidgets.widgets.interaction import _get_min_max_value
+-from collections import Iterable, Sequence
+-from numbers import Integral, Rational, Real
+-
+-from sage.structure.all import parent
+-from sage.arith.srange import srange
+-from sage.plot.colors import Color
+-from sage.misc.six import u
+-from sage.symbolic.ring import SR
+-from sage.rings.all import RR
+-
+-
+-# The SageNB text_control widget does exactly the same as the
+-# ipywidgets.HTML widget
+-text_control = HTML
+-
+-
+-def input_box(default=None, label=None, type=None, width=80, height=1):
+-    """
+-    A textbox widget.
+-
+-    INPUT:
+-
+-    - ``default`` -- initial value
+-
+-    - ``label`` -- optional label
+-
+-    - ``type`` -- function of one variable or ``None``. if ``type`` is
+-      ``str``, the value of this widget for interactive functions is
+-      just the text as ``str``. Otherwise, the text is evaluated using
+-      :func:`sage_eval`, ``type`` is called on it and the result is used
+-      as value. Except if ``type`` is ``None``, then the evaluated text
+-      is used as value.
+-
+-    - ``width`` -- width of the box
+-
+-    - ``height`` -- if ``height > 1``, create a textarea instead of a
+-      single-line textbox.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.all_jupyter import input_box
+-
+-    The most basic usage is when ``type=str``::
+-
+-        sage: w = input_box("4+5", type=str, label="enter a string")
+-        sage: w
+-        TransformText(value=u'4+5', description=u'enter a string')
+-        sage: w.get_interact_value()
+-        '4+5'
+-
+-    Without ``type``, the text is evaluated::
+-
+-        sage: w = input_box("4+5")
+-        sage: w
+-        EvalText(value=u'4+5')
+-        sage: w.get_interact_value()
+-        9
+-
+-    With a different ``type``, the text is evaluated and ``type`` is
+-    called on it:
+-
+-        sage: w = input_box("4+5", type=float)
+-        sage: w
+-        EvalText(value=u'4+5')
+-        sage: w.get_interact_value()
+-        9.0
+-
+-    Despite the keyword name, ``type`` does not need to be a type::
+-
+-        sage: w = input_box("4+5", type=sqrt)
+-        sage: w
+-        EvalText(value=u'4+5')
+-        sage: w.get_interact_value()
+-        3
+-
+-    When ``height > 1``, a textarea is returned::
+-
+-        sage: w = input_box("4+5", width=100, height=1)
+-        sage: w
+-        EvalText(value=u'4+5')
+-        sage: w = input_box("4+5", width=100, height=5)
+-        sage: w
+-        EvalTextarea(value=u'4+5')
+-
+-    TESTS::
+-
+-        sage: w = input_box(type=Color)
+-        Traceback (most recent call last):
+-        ...
+-        NotImplementedError: type=Color is not supported
+-    """
+-    kwds = {}
+-    if type is str:
+-        kwds["transform"] = str  # Convert unicode to str
+-        if height > 1:
+-            cls = TransformTextarea
+-        else:
+-            cls = TransformText
+-    elif type is Color:
+-        # This is special-cased by SageNB (with a non-trivial
+-        # implementation!), but it doesn't seem to be used in practice
+-        # because we have a SageColorPicker widget.
+-        raise NotImplementedError("type=Color is not supported")
+-    else:
+-        kwds["transform"] = type
+-        if height > 1:
+-            cls = EvalTextarea
+-        else:
+-            cls = EvalText
+-    if default is not None:
+-        kwds["value"] = str(default)
+-    if label is not None:
+-        kwds["description"] = u(label)
+-    w = cls(**kwds)
+-    w.layout.max_width = str(width+1) + "em"
+-    return w
+-
+-
+-def slider(vmin, vmax=None, step_size=None, default=None, label=None, display_value=True, _range=False):
+-    """
+-    A slider widget.
+-
+-    INPUT:
+-
+-    For a numeric slider (select a value from a range):
+-
+-    - ``vmin``, ``vmax`` -- minimum and maximum value
+-
+-    - ``step_size`` -- the step size
+-
+-    For a selection slider (select a value from a list of values):
+-
+-    - ``vmin`` -- a list of possible values for the slider
+-
+-    For all sliders:
+-
+-    - ``default`` -- initial value
+-
+-    - ``label`` -- optional label
+-
+-    - ``display_value`` -- (boolean) if ``True``, display the current
+-      value.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.all_jupyter import slider
+-        sage: slider(5, label="slide me")
+-        TransformIntSlider(value=5, min=5, max=100, step=1, description=u'slide me')
+-        sage: slider(5, 20)
+-        TransformIntSlider(value=5, min=5, max=20, step=1)
+-        sage: slider(5, 20, 0.5)
+-        TransformFloatSlider(value=5.0, min=5.0, max=20.0, step=0.5)
+-        sage: slider(5, 20, default=12)
+-        TransformIntSlider(value=12, min=5, max=20, step=1)
+-
+-    The parent of the inputs determines the parent of the value::
+-
+-        sage: w = slider(5); w
+-        TransformIntSlider(value=5, min=5, max=100, step=1)
+-        sage: parent(w.get_interact_value())
+-        Integer Ring
+-        sage: w = slider(int(5)); w
+-        IntSlider(value=5, min=5, max=100, step=1)
+-        sage: parent(w.get_interact_value())
+-        <type 'int'>
+-        sage: w = slider(5, 20, step_size=RDF("0.1")); w
+-        TransformFloatSlider(value=5.0, min=5.0, max=20.0, step=0.1)
+-        sage: parent(w.get_interact_value())
+-        Real Double Field
+-        sage: w = slider(5, 20, step_size=10/3); w
+-        SelectionSlider(value=35/3, options=[5, 25/3, 35/3, 15, 55/3])
+-        sage: parent(w.get_interact_value())
+-        Rational Field
+-
+-    Symbolic input is evaluated numerically::
+-
+-        sage: w = slider(e, pi); w
+-        TransformFloatSlider(value=2.718281828459045, min=2.718281828459045, max=3.141592653589793, step=0.1)
+-        sage: parent(w.get_interact_value())
+-        Real Field with 53 bits of precision
+-
+-    For a selection slider, the default is adjusted to one of the
+-    possible values::
+-
+-        sage: slider(range(10), default=17/10)
+-        SelectionSlider(value=2, options=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+-
+-    TESTS::
+-
+-        sage: slider(range(5), range(5))
+-        Traceback (most recent call last):
+-        ...
+-        TypeError: unexpected argument 'vmax' for a selection slider
+-        sage: slider(range(5), step_size=2)
+-        Traceback (most recent call last):
+-        ...
+-        TypeError: unexpected argument 'step_size' for a selection slider
+-        sage: slider(5).readout
+-        True
+-        sage: slider(5, display_value=False).readout
+-        False
+-    """
+-    kwds = {"readout": display_value}
+-    if label:
+-        kwds["description"] = u(label)
+-
+-    # If vmin is iterable, return a SelectionSlider
+-    if isinstance(vmin, Iterable):
+-        if vmax is not None:
+-            raise TypeError("unexpected argument 'vmax' for a selection slider")
+-        if step_size is not None:
+-            raise TypeError("unexpected argument 'step_size' for a selection slider")
+-        if _range:
+-            # https://github.com/ipython/ipywidgets/issues/760
+-            raise NotImplementedError("range_slider does not support a list of values")
+-        options = list(vmin)
+-        # Find default in options
+-        def err(v):
+-            if v is default:
+-                return (-1, 0)
+-            try:
+-                if v == default:
+-                    return (0, 0)
+-                return (0, abs(v - default))
+-            except Exception:
+-                return (1, 0)
+-        kwds["options"] = options
+-        if default is not None:
+-            kwds["value"] = min(options, key=err)
+-        return SelectionSlider(**kwds)
+-
+-    if default is not None:
+-        kwds["value"] = default
+-
+-    # Sum all input numbers to figure out type/parent
+-    p = parent(sum(x for x in (vmin, vmax, step_size) if x is not None))
+-
+-    # Change SR to RR
+-    if p is SR:
+-        p = RR
+-
+-    # Convert all inputs to the common parent
+-    if vmin is not None:
+-        vmin = p(vmin)
+-    if vmax is not None:
+-        vmax = p(vmax)
+-    if step_size is not None:
+-        step_size = p(step_size)
+-
+-    def tuple_elements_p(t):
+-        "Convert all entries of the tuple `t` to `p`"
+-        return tuple(p(x) for x in t)
+-
+-    zero = p()
+-    if isinstance(zero, Integral):
+-        if p is int:
+-            if _range:
+-                cls = IntRangeSlider
+-            else:
+-                cls = IntSlider
+-        else:
+-            if _range:
+-                kwds["transform"] = tuple_elements_p
+-                cls = TransformIntRangeSlider
+-            else:
+-                kwds["transform"] = p
+-                cls = TransformIntSlider
+-    elif isinstance(zero, Rational):
+-        # Rational => implement as SelectionSlider
+-        if _range:
+-            # https://github.com/ipython/ipywidgets/issues/760
+-            raise NotImplementedError("range_slider does not support rational numbers")
+-        vmin, vmax, value = _get_min_max_value(vmin, vmax, default, step_size)
+-        kwds["value"] = value
+-        kwds["options"] = srange(vmin, vmax, step_size, include_endpoint=True)
+-        return SelectionSlider(**kwds)
+-    elif isinstance(zero, Real):
+-        if p is float:
+-            if _range:
+-                cls = FloatRangeSlider
+-            else:
+-                cls = FloatSlider
+-        else:
+-            if _range:
+-                kwds["transform"] = tuple_elements_p
+-                cls = TransformFloatRangeSlider
+-            else:
+-                kwds["transform"] = p
+-                cls = TransformFloatSlider
+-    else:
+-        raise TypeError("unknown parent {!r} for slider".format(p))
+-
+-    kwds["min"] = vmin
+-    if vmax is not None:
+-        kwds["max"] = vmax
+-    if step_size is not None:
+-        kwds["step"] = step_size
+-    return cls(**kwds)
+-
+-
+-def range_slider(*args, **kwds):
+-    """
+-    A slider widget to select a range of values.
+-
+-    INPUT:
+-
+-    - ``vmin``, ``vmax`` -- minimum and maximum value
+-
+-    - ``step_size`` -- the step size
+-
+-    - ``default`` -- initial value, given as a 2-tuple
+-
+-    - ``label`` -- optional label
+-
+-    - ``display_value`` -- (boolean) if ``True``, display the current
+-      value.
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.all_jupyter import range_slider
+-        sage: range_slider(5, label="slide me")
+-        TransformIntRangeSlider(value=(28, 76), min=5, max=100, step=1, description=u'slide me')
+-        sage: range_slider(5, 20)
+-        TransformIntRangeSlider(value=(8, 16), min=5, max=20, step=1)
+-        sage: range_slider(5, 20, 0.5)
+-        TransformFloatRangeSlider(value=(8.75, 16.25), min=5.0, max=20.0, step=0.5)
+-        sage: range_slider(5, 20, default=(12,15))
+-        TransformIntRangeSlider(value=(12, 15), min=5, max=20, step=1)
+-
+-    The parent of the inputs determines the parent of the value::
+-
+-        sage: w = range_slider(5); w
+-        TransformIntRangeSlider(value=(28, 76), min=5, max=100, step=1)
+-        sage: [parent(x) for x in w.get_interact_value()]
+-        [Integer Ring, Integer Ring]
+-        sage: w = range_slider(int(5)); w
+-        IntRangeSlider(value=(28, 76), min=5, max=100, step=1)
+-        sage: [parent(x) for x in w.get_interact_value()]
+-        [<type 'int'>, <type 'int'>]
+-        sage: w = range_slider(5, 20, step_size=RDF("0.1")); w
+-        TransformFloatRangeSlider(value=(8.75, 16.25), min=5.0, max=20.0, step=0.1)
+-        sage: [parent(x) for x in w.get_interact_value()]
+-        [Real Double Field, Real Double Field]
+-
+-    Unfortunately, rational numbers are not supported::
+-
+-        sage: w = range_slider(5, 20, step_size=10/3); w
+-        Traceback (most recent call last):
+-        ...
+-        NotImplementedError: range_slider does not support rational numbers
+-
+-    TESTS::
+-
+-        sage: range_slider(range(5))
+-        Traceback (most recent call last):
+-        ...
+-        NotImplementedError: range_slider does not support a list of values
+-    """
+-    kwds["_range"] = True
+-    return slider(*args, **kwds)
+-
+-
+-def checkbox(default=True, label=None):
+-    """
+-    A checkbox widget.
+-
+-    INPUT:
+-
+-    - ``default`` -- (boolean) initial value
+-
+-    - ``label`` -- optional label
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.all_jupyter import checkbox
+-        sage: checkbox(label="toggle me")
+-        Checkbox(value=True, description=u'toggle me')
+-        sage: checkbox(default=0)
+-        Checkbox(value=False)
+-    """
+-    kwds = {"value": bool(default)}
+-    if label is not None:
+-        kwds["description"] = u(label)
+-    return Checkbox(**kwds)
+-
+-
+-def selector(values, label=None, default=None, nrows=None, ncols=None, width=None, buttons=False):
+-    """
+-    A widget to select a value from a given list of values.
+-
+-    This is rendered as a dropdown box (if ``buttons`` is False) or
+-    as a list of buttons (if ``buttons`` is True).
+-
+-    INPUT:
+-
+-    - ``values`` -- a list of values to choose from (see examples below
+-      for the accepted formats for this)
+-
+-    - ``label`` -- optional label
+-
+-    - ``default`` -- initial value
+-
+-    - ``buttons`` -- (boolean) if True, display buttons instead of a
+-      dropdown box
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.all_jupyter import selector
+-        sage: selector(range(5), label="choose one")
+-        Dropdown(value=0, options=[0, 1, 2, 3, 4], description=u'choose one')
+-        sage: selector(range(5), buttons=True, default=4)
+-        ToggleButtons(value=4, options=[0, 1, 2, 3, 4])
+-
+-    Apart from a simple list, ``values`` can be given as a list of
+-    2-tuples ``(value, label)``::
+-
+-        sage: selector([(1,"one"), (2,"two"), (3,"three")])
+-        Dropdown(value=1, options=[('one', 1), ('two', 2), ('three', 3)])
+-        sage: selector([(1,"one"), (2,"two"), (3,"three")], buttons=True)
+-        ToggleButtons(value=1, options=[('one', 1), ('two', 2), ('three', 3)])
+-
+-    A dict of ``label:value`` pairs is also allowed. Since a ``dict``
+-    is not ordered, it is better to use an :class:`OrderedDict`::
+-
+-        sage: from collections import OrderedDict
+-        sage: selector(OrderedDict(one=1, two=2, three=3))
+-        Dropdown(value=1, options=OrderedDict([('one', 1), ('three', 3), ('two', 2)]))
+-        sage: selector(OrderedDict(one=1, two=2, three=3), buttons=True)
+-        ToggleButtons(value=1, options=OrderedDict([('one', 1), ('three', 3), ('two', 2)]))
+-
+-    The values can be any kind of object:
+-
+-        sage: selector([sin(x^2), GF(29), EllipticCurve('37a1')])
+-        Dropdown(value=sin(x^2), options=[sin(x^2), Finite Field of size 29, Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field])
+-    """
+-    if isinstance(values, Sequence):
+-        values = list(values)
+-        if values:
+-            v0 = values[0]
+-            if isinstance(v0, tuple) and len(v0) == 2:
+-                # Change [(val0, lbl0), ...] to [(lbl0, val0), ...]
+-                values = [(str(lbl), val) for (val, lbl) in values]
+-    kwds = {"options": values}
+-    if buttons:
+-        cls = ToggleButtons
+-    elif nrows is not None or ncols is not None:
+-        # For compatibility with SageNB, these keywords are recognized
+-        # but their value is ignored
+-        cls = ToggleButtons
+-    else:
+-        cls = Dropdown
+-    if default is not None:
+-        kwds["value"] = default
+-    if label is not None:
+-        kwds["description"] = u(label)
+-    return cls(**kwds)
+-
+-
+-def input_grid(nrows, ncols, default=None, label=None, to_value=None, width=4):
+-    """
+-    A widget consisting of a grid (matrix) of textboxes.
+-
+-    The values entered in the textboxes are evaluated (using
+-    :func:`sage_eval`). These are stored as a list of lists on the
+-    ``value`` attribute. The value of this widget for an interactive
+-    function is the result of calling ``to_value`` on this list of
+-    lists.
+-
+-    INPUT:
+-
+-    - ``nrows``, ``ncols`` -- number of rows and columns in the grid
+-
+-    - ``default`` -- initial value (given as a list of lists, a single
+-      constant value or a flat list)
+-
+-    - ``label`` -- optional label
+-
+-    - ``to_value`` -- function to be called to get the value for
+-      interactive functions
+-
+-    - ``width`` -- width of each textbox
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.all_jupyter import input_grid
+-        sage: input_grid(2, 2, default=42, label="answers")
+-        Grid(value=[[42, 42], [42, 42]], description=u'answers', children=(Label(value=u'answers'), VBox(children=(EvalText(value=u'42'), EvalText(value=u'42'))), VBox(children=(EvalText(value=u'42'), EvalText(value=u'42')))))
+-        sage: w = input_grid(2, 2, default=[[cos(x), sin(x)], [-sin(x), cos(x)]], to_value=matrix); w
+-        Grid(value=[[cos(x), sin(x)], [-sin(x), cos(x)]], children=(Label(value=u''), VBox(children=(EvalText(value=u'cos(x)'), EvalText(value=u'-sin(x)'))), VBox(children=(EvalText(value=u'sin(x)'), EvalText(value=u'cos(x)')))))
+-        sage: w.get_interact_value()
+-        [ cos(x)  sin(x)]
+-        [-sin(x)  cos(x)]
+-        sage: w = input_grid(2, 2, default=[1, x, x^2, x^3], to_value=lambda x: x[1][1]); w
+-        Grid(value=[[1, x], [x^2, x^3]], children=(Label(value=u''), VBox(children=(EvalText(value=u'1'), EvalText(value=u'x^2'))), VBox(children=(EvalText(value=u'x'), EvalText(value=u'x^3')))))
+-        sage: w.get_interact_value()
+-        x^3
+-    """
+-    kwds = {"transform": to_value}
+-    if label is not None:
+-        kwds["description"] = u(label)
+-
+-    # Parse default
+-    if not isinstance(default, list):
+-        # Single value
+-        default = [[default] * ncols] * nrows
+-    if all(isinstance(elt, list) for elt in default):
+-        # List of lists
+-        pass
+-    else:
+-        # Flat list
+-        default = [[default[i * ncols + j] for j in range(ncols)] for i in range(nrows)]
+-
+-    def make_widget(i, j):
+-        return input_box(str(default[i][j]), width=width)
+-
+-    grid = Grid(nrows, ncols, make_widget, **kwds)
+-    return grid
+-
+-
+-def color_selector(default=(0, 0, 1), label=None, widget=None, hide_box=False):
+-    """
+-    A widget for choosing a color.
+-
+-    INPUT:
+-
+-    - ``default`` -- initial value
+-
+-    - ``label`` -- optional label
+-
+-    - ``hide_box`` -- (boolean) if True, do not show the textbox
+-
+-    EXAMPLES::
+-
+-        sage: from sage.repl.ipython_kernel.all_jupyter import color_selector
+-        sage: w = color_selector("orange", label="color me"); w
+-        SageColorPicker(value='#ffa500', description=u'color me')
+-        sage: w.get_interact_value()
+-        RGB color (1.0, 0.6470588235294118, 0.0)
+-        sage: color_selector(Color(0.1, 0.2, 0.3))
+-        SageColorPicker(value='#19334c')
+-    """
+-    # widget argument is silently ignored
+-    kwds = {"value": Color(default).html_color(),
+-            "concise": hide_box}
+-    if label is not None:
+-        kwds["description"] = u(label)
+-    return SageColorPicker(**kwds)
diff --git a/debian/patches/series b/debian/patches/series
index 62e1ce5..63672f0 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -70,3 +70,4 @@ dt-version-glpk-4.60-extra-hacky-fixes.patch
 dt-r-no-readline.patch
 dt-more-fix-test-cases.patch
 dt-work-around-doc-common-conf.patch
+dt-undo-trac-21267-sagenb-interacts-for-jupyter.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/sagemath.git



More information about the debian-science-commits mailing list