[sagemath] 01/01: Use ipywidgets 6, un-revert upstream patch

Ximin Luo infinity0 at debian.org
Wed May 24 12:17:57 UTC 2017


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

infinity0 pushed a commit to branch master
in repository sagemath.

commit 20bc5310514ee6fb3f9906bfd47b19f824692663
Author: Ximin Luo <infinity0 at debian.org>
Date:   Wed May 24 14:16:37 2017 +0200

    Use ipywidgets 6, un-revert upstream patch
---
 debian/TODO                                        |    6 +-
 debian/control.jupyter-depends                     |    2 +-
 ...o-trac-21267-sagenb-interacts-for-jupyter.patch | 1403 --------------------
 debian/patches/series                              |    2 +-
 debian/patches/u1-ipywidgets-repr.patch            |   56 +
 5 files changed, 59 insertions(+), 1410 deletions(-)

diff --git a/debian/TODO b/debian/TODO
index 8161712..46f5399 100644
--- a/debian/TODO
+++ b/debian/TODO
@@ -4,11 +4,7 @@
 
 ## Current
 
-*   Package red stuff in https://people.debian.org/~thansen/debian-sage-status.html
-    *   ecl, ntl, configparser (not strictly needed, tests seem to work OK)
-
-*   Package red stuff in https://people.debian.org/~thansen/debian-sage-dev-status.html
-    *   ipywidgets, maxima, jupyter-notebook, threejs
+*   See https://wiki.debian.org/DebianScience/Sage#Open_tasks
 
 ## Later
 
diff --git a/debian/control.jupyter-depends b/debian/control.jupyter-depends
index aa17a7a..d24873a 100644
--- a/debian/control.jupyter-depends
+++ b/debian/control.jupyter-depends
@@ -2,7 +2,7 @@
  jupyter-core,
  jupyter-nbextension-jupyter-js-widgets,
  python-ipykernel,
- python-ipywidgets,
+ python-ipywidgets (>= 6.0.0-1),
  python-nbconvert,
  python-nbformat,
  python-notebook (>= 4.2.3-3),
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
deleted file mode 100644
index 130947e..0000000
--- a/debian/patches/dt-undo-trac-21267-sagenb-interacts-for-jupyter.patch
+++ /dev/null
@@ -1,1403 +0,0 @@
-Description: Undo trac #21267 because we are lacking ipywidgets 6.0
- This patch is a temporary reversion of this commit:
- .
- 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
-Author: Tobias Hansen <thansen at debian.org>
-
---- 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 342c92b..d62d58b 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -15,6 +15,7 @@ u1-pip-nowarn.patch                        #21835
 u1-fix-atrocious-symlink-logic.patch       #22444
 u1-looser-doctest-basename.patch           #22445
 u1-scripts-dir.patch                       #22731
+u1-ipywidgets-repr.patch                   #https://github.com/jupyter-widgets/ipywidgets/pull/1031
 
 # Patches that should be upstreamed (may need some work first)
 u2-version-cddlib-094h.patch
@@ -71,4 +72,3 @@ 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
diff --git a/debian/patches/u1-ipywidgets-repr.patch b/debian/patches/u1-ipywidgets-repr.patch
new file mode 100644
index 0000000..14405e3
--- /dev/null
+++ b/debian/patches/u1-ipywidgets-repr.patch
@@ -0,0 +1,56 @@
+Description: Money-patch ipywidgets in the way that Sage upstream expects
+ Sage upstream patches ipywidgets, but this is still being discussed
+ upstream (see Bug below). In the meantime, we can have Sage monkey-patch
+ ipywidgets at runtime, to prevent other users of ipywidgets being affected.
+Author: Ximin Luo <infinity0 at debian.org>
+Author: Jeroen Demeyer <jdemeyer at cage.ugent.be>
+Bug: https://github.com/jupyter-widgets/ipywidgets/pull/1031
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/sage/src/sage/repl/ipython_kernel/widgets.py
++++ b/sage/src/sage/repl/ipython_kernel/widgets.py
+@@ -24,13 +24,43 @@
+ 
+ from ipywidgets.widgets import (IntSlider, IntRangeSlider, FloatSlider,
+         FloatRangeSlider, Text, Textarea, ColorPicker,
+-        Label, HBox, VBox, ValueWidget)
++        Label, HBox, VBox, ValueWidget, Widget)
+ 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
+ 
++def __widgets__repr__(self):
++    """
++    Textual representation of this widget, mainly used for testing
++    and debugging.
++    """
++    # List of attributes to show with default values. The attribute
++    # is printed if it exists and its value is not equal to this
++    # default value.
++    attributes = [("value", None),
++                  ("min", None),
++                  ("max", None),
++                  ("step", None),
++                  ("options", None),
++                  ("description", ""),
++                  ("children", [])]
++    r = ""
++    for (attr, default) in attributes:
++        try:
++            v = getattr(self, attr)
++        except AttributeError:
++            continue
++        if default == v:
++            continue
++        if r:
++            r += ", "
++        r += attr + "=" + repr(v)
++    return "%s(%s)" % (type(self).__name__, r)
++Widget.__repr__ = __widgets__repr__
++del __widgets__repr__
++
+ 
+ class TransformWidget(object):
+     """

-- 
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