[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