Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-ipywidgets for 
openSUSE:Factory checked in at 2022-08-02 22:08:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ipywidgets (Old)
 and      /work/SRC/openSUSE:Factory/.python-ipywidgets.new.1533 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-ipywidgets"

Tue Aug  2 22:08:52 2022 rev:9 rq:992081 version:7.7.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ipywidgets/python-ipywidgets.changes      
2022-01-07 12:47:10.711878675 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-ipywidgets.new.1533/python-ipywidgets.changes
    2022-08-02 22:09:22.817805070 +0200
@@ -1,0 +2,41 @@
+Mon Aug  1 17:41:47 UTC 2022 - Ben Greiner <c...@bnavigator.de>
+
+- Update to version 7.7.1
+  * Fix broken link icon for FontAwesome 4 and 5 #3495
+  * Fix message throttling bug #3494
+  * Fix state message parsing to be more permissive #3486
+  * Fix tests on Python 3.11 #3480
+  * Add better front-page docs #3496
+- Release 7.7
+  * Fix installation on Python 3.10. #3368
+  * Throw an error if we cannot render a widget, enabling the
+    rendering system to fall back to rendering a different data
+    type if available. #3290
+  * Create a new widget control comm channel, enabling more
+    efficient fetching of kernel widget state. #3201
+  * Refactor logic for fetching kernel widget state to the manager
+    base class. This logic first tries to use the new widget
+    control comm channel, falling back to the existing method of
+    requesting each widget's state individually. #3337
+  * Enable HTMLManager output widgets to render state updates.
+    #3372
+  * Do not reset JupyterLab CSS variables if they are already
+    defined. #3344
+  * Fix variable inspector example. #3302
+  * Introduce new widget manager has_model method for synchronously
+    checking if a widget model is registered. #3377
+  * Work around bug in Chrome rendering Combobox arrows. #3375
+  * Optionally echo update messages from frontends to other
+    frontends. This enables widget views in different frontends to
+    maintain consistent state simultaneously, and also makes sure
+    that simultaneous updates from the kernel and frontend resolve
+    to a consistent state. This is off by default in ipywidgets
+    7.7, and it is anticipated this will be on by default in
+    ipywidgets 8.0. To enable echo update messages across
+    ipywidgets, set the environment variable JUPYTER_WIDGETS_ECHO
+    to 1. To opt a specific attribute out of echo updates, tag the
+    attribute with echo_update=False metadata (we do this in core
+    for the FileUpload widget's data attribute). #3400, #3394
+- Drop ipywidgets-pr2655-collectionsabc.patch
+
+-------------------------------------------------------------------

Old:
----
  ipywidgets-7.6.5.tar.gz
  ipywidgets-pr2655-collectionsabc.patch

New:
----
  ipywidgets-7.7.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-ipywidgets.spec ++++++
--- /var/tmp/diff_new_pack.nn57aa/_old  2022-08-02 22:09:23.649807469 +0200
+++ /var/tmp/diff_new_pack.nn57aa/_new  2022-08-02 22:09:23.653807480 +0200
@@ -19,15 +19,13 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define         skip_python2 1
 Name:           python-ipywidgets
-Version:        7.6.5
+Version:        7.7.1
 Release:        0
 Summary:        IPython HTML widgets for Jupyter
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
 URL:            https://github.com/jupyter-widgets/ipywidgets
 Source0:        
https://files.pythonhosted.org/packages/source/i/ipywidgets/ipywidgets-%{version}.tar.gz
-# PATCH-FIX-UPSTREAM ipywidgets-pr2655-collectionsabc.patch -- 
gh#jupyter-widgets/ipywidgets#2655
-Patch0:         
https://github.com/jupyter-widgets/ipywidgets/commit/f9a13dbb3b8f1ffefef483bdb4c14f04f7743ff1.patch#/ipywidgets-pr2655-collectionsabc.patch
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
@@ -36,9 +34,8 @@
 Requires:       python-ipython >= 4
 Requires:       python-ipython_genutils >= 0.2
 Requires:       python-jupyterlab_widgets >= 1
-Requires:       python-nbformat >= 4.2
 Requires:       python-traitlets >= 4.3.1
-Requires:       python-widgetsnbextension >= 3.5.0
+Requires:       python-widgetsnbextension >= 3.6.0
 Provides:       python-jupyter_ipywidgets = %{version}
 Obsoletes:      python-jupyter_ipywidgets < %{version}
 BuildArch:      noarch
@@ -47,10 +44,9 @@
 BuildRequires:  %{python_module ipython >= 4}
 BuildRequires:  %{python_module ipython_genutils >= 0.2}
 BuildRequires:  %{python_module jupyterlab_widgets >= 1}
-BuildRequires:  %{python_module nbformat >= 4.2.0}
 BuildRequires:  %{python_module pytest >= 3.6.0}
 BuildRequires:  %{python_module traitlets >= 4.3.1}
-BuildRequires:  %{python_module widgetsnbextension >= 3.5.0}
+BuildRequires:  %{python_module widgetsnbextension >= 3.6.0}
 # /SECTION
 %if "%{python_flavor}" == "python3" || "%{?python_provides}"  == "python3"
 Provides:       jupyter-ipywidgets = %{version}

++++++ ipywidgets-7.6.5.tar.gz -> ipywidgets-7.7.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/PKG-INFO 
new/ipywidgets-7.7.1/PKG-INFO
--- old/ipywidgets-7.6.5/PKG-INFO       2021-09-14 01:41:09.782837900 +0200
+++ new/ipywidgets-7.7.1/PKG-INFO       2022-06-22 19:40:16.771635000 +0200
@@ -1,33 +1,11 @@
-Metadata-Version: 1.1
+Metadata-Version: 2.1
 Name: ipywidgets
-Version: 7.6.5
+Version: 7.7.1
 Summary: IPython HTML widgets for Jupyter
 Home-page: http://ipython.org
 Author: IPython Development Team
 Author-email: ipython-...@scipy.org
 License: BSD
-Description: 
-        .. image:: https://img.shields.io/pypi/v/ipywidgets.svg
-           :target: https://pypi.python.org/pypi/ipywidgets/
-           :alt: Version Number
-        
-        .. image:: https://img.shields.io/pypi/dm/ipywidgets.svg
-           :target: https://pypi.python.org/pypi/ipywidgets/
-           :alt: Number of PyPI downloads
-        
-        Interactive HTML Widgets
-        ========================
-        
-        Interactive HTML widgets for Jupyter notebooks and the IPython kernel.
-        
-        Usage
-        =====
-        
-        .. code-block:: python
-        
-            from ipywidgets import IntSlider
-            IntSlider()
-        
 Keywords: Interactive,Interpreter,Shell,Web
 Platform: Linux
 Platform: Mac OS X
@@ -43,3 +21,27 @@
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Framework :: Jupyter
+Provides-Extra: test
+License-File: LICENSE
+
+
+.. image:: https://img.shields.io/pypi/v/ipywidgets.svg
+   :target: https://pypi.python.org/pypi/ipywidgets/
+   :alt: Version Number
+
+.. image:: https://img.shields.io/pypi/dm/ipywidgets.svg
+   :target: https://pypi.python.org/pypi/ipywidgets/
+   :alt: Number of PyPI downloads
+
+Interactive HTML Widgets
+========================
+
+Interactive HTML widgets for Jupyter notebooks and the IPython kernel.
+
+Usage
+=====
+
+.. code-block:: python
+
+    from ipywidgets import IntSlider
+    IntSlider()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/docs/requirements.txt 
new/ipywidgets-7.7.1/docs/requirements.txt
--- old/ipywidgets-7.6.5/docs/requirements.txt  2021-09-14 01:30:14.885464400 
+0200
+++ new/ipywidgets-7.7.1/docs/requirements.txt  2022-06-22 19:32:54.793054000 
+0200
@@ -7,4 +7,5 @@
 numpy
 recommonmark
 sphinx>=1.4.6
+jinja2==3.0.0 # pin since newer jinja2 conflicts with sphinx 1.8.6, the 
default on readthedocs
 sphinx_rtd_theme
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/docs/source/changelog.md 
new/ipywidgets-7.7.1/docs/source/changelog.md
--- old/ipywidgets-7.6.5/docs/source/changelog.md       2021-09-14 
01:30:14.885993500 +0200
+++ new/ipywidgets-7.7.1/docs/source/changelog.md       2022-06-22 
19:32:54.793225000 +0200
@@ -3,6 +3,37 @@
 
 A summary of changes in ipywidgets. For more detailed information, see the 
issues and pull requests for the appropriate milestone on 
[GitHub](https://github.com/jupyter-widgets/ipywidgets).
 
+7.7.1
+-----
+
+To see the full list of pull requests, see the [7.7.1 
milestone](https://github.com/jupyter-widgets/ipywidgets/milestone/36?closed=1) 
on GitHub.
+
+Highlights include:
+
+- Fix broken link icon for FontAwesome 4 and 5 
[#3495](https://github.com/jupyter-widgets/ipywidgets/pull/3495)
+- Fix message throttling bug 
[#3494](https://github.com/jupyter-widgets/ipywidgets/pull/3494)
+- Fix state message parsing to be more permissive 
[#3486](https://github.com/jupyter-widgets/ipywidgets/pull/3486)
+- Fix tests on Python 3.11 
[#3480](https://github.com/jupyter-widgets/ipywidgets/pull/3480)
+- Add better front-page docs 
[#3496](https://github.com/jupyter-widgets/ipywidgets/pull/3496)
+
+7.7
+---
+
+To see the full list of pull requests and issues, see the [7.7 
milestone](https://github.com/jupyter-widgets/ipywidgets/milestone/35?closed=1) 
on GitHub.
+
+Highlights include:
+
+- Fix installation on Python 3.10. 
[#3368](https://github.com/jupyter-widgets/ipywidgets/pull/3368)
+- Throw an error if we cannot render a widget, enabling the rendering system 
to fall back to rendering a different data type if available. 
[#3290](https://github.com/jupyter-widgets/ipywidgets/pull/3290)
+- Create a new widget control comm channel, enabling more efficient fetching 
of kernel widget state. 
[#3201](https://github.com/jupyter-widgets/ipywidgets/pull/3021)
+- Refactor logic for fetching kernel widget state to the manager base class. 
This logic first tries to use the new widget control comm channel, falling back 
to the existing method of requesting each widget's state individually. 
[#3337](https://github.com/jupyter-widgets/ipywidgets/pull/3337)
+- Enable HTMLManager output widgets to render state updates. 
[#3372](https://github.com/jupyter-widgets/ipywidgets/pull/3372)
+- Do not reset JupyterLab CSS variables if they are already defined. 
[#3344](https://github.com/jupyter-widgets/ipywidgets/pull/3344)
+- Fix variable inspector example. 
[#3302](https://github.com/jupyter-widgets/ipywidgets/pull/3302)
+- Introduce new widget manager `has_model` method for synchronously checking 
if a widget model is registered. 
[#3377](https://github.com/jupyter-widgets/ipywidgets/pull/3377)
+- Work around bug in Chrome rendering Combobox arrows. 
[#3375](https://github.com/jupyter-widgets/ipywidgets/pull/3375)
+- Optionally echo update messages from frontends to other frontends. This 
enables widget views in different frontends to maintain consistent state 
simultaneously, and also makes sure that simultaneous updates from the kernel 
and frontend resolve to a consistent state. This is off by default in 
ipywidgets 7.7, and it is anticipated this will be on by default in ipywidgets 
8.0. To enable echo update messages across ipwyidgets, set the environment 
variable `JUPYTER_WIDGETS_ECHO` to 1. To opt a specific attribute out of echo 
updates, tag the attribute with `echo_update=False` metadata (we do this in 
core for the FileUpload widget's `data` attribute). 
[#3400](https://github.com/jupyter-widgets/ipywidgets/pull/3400)
+
 7.6
 ---
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/docs/source/conf.py 
new/ipywidgets-7.7.1/docs/source/conf.py
--- old/ipywidgets-7.6.5/docs/source/conf.py    2021-09-14 01:30:14.886560700 
+0200
+++ new/ipywidgets-7.7.1/docs/source/conf.py    2022-06-22 19:32:54.793347800 
+0200
@@ -42,10 +42,10 @@
 
 master_doc = 'index'
 project = 'Jupyter Widgets'
-copyright = '2017 Project Jupyter'
+copyright = '2017-2022 Project Jupyter'
 author = 'Jupyter Team'
 
-language = None
+language = "en"
 exclude_patterns = [
     '**.ipynb_checkpoints',
     'examples.md',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/docs/source/dev_install.md 
new/ipywidgets-7.7.1/docs/source/dev_install.md
--- old/ipywidgets-7.6.5/docs/source/dev_install.md     2021-09-14 
01:30:14.887445000 +0200
+++ new/ipywidgets-7.7.1/docs/source/dev_install.md     2022-06-22 
19:32:54.793535500 +0200
@@ -1,5 +1,9 @@
 # Developer Install
 
+The core Jupyter Widgets packages are developed in the
+[https://github.com/jupyter-widgets/ipywidgets](https://github.com/jupyter-widgets/ipywidgets)
 git repository.
+
+
 ## Prerequisites
 
 To install ipywidgets from git, you will need:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/docs/source/developer_docs.rst 
new/ipywidgets-7.7.1/docs/source/developer_docs.rst
--- old/ipywidgets-7.6.5/docs/source/developer_docs.rst 2021-09-14 
01:30:14.888560500 +0200
+++ new/ipywidgets-7.7.1/docs/source/developer_docs.rst 1970-01-01 
01:00:00.000000000 +0100
@@ -1,27 +0,0 @@
-Developer Docs
-===============
-
-The Jupyter widgets packages are developed in the 
`https://github.com/jupyter-widgets/ipywidgets 
<https://github.com/jupyter-widgets/ipywidgets>`_ git repository. See the issue 
tracker, README, and other Github documents for the most recent information.
-
-
-Scope of ipywidgets
--------------------
-
-``ipywidgets`` is a framework to provide eventful python objects that have a 
representation in the browser (see :doc:`examples/Widget Basics.ipynb` for more 
on the definition of widgets). This requires two components:
-
-1. The framework for widget interactions between the widgets represented in 
the Python kernel and the (javascript) representation of the widgets in the 
browser.
-2. A basic, lightweight set of form controls that *use* this framework, based 
on standard HTML form controls. These included controls include a text area, 
text box, select and multiselect controls, checkbox, etc. A few more advanced 
controls that are very popular are also included, such as a slider and basic 
tab panels.
-
-The framework for building rich interactive objects is the foremost purpose of 
the ipywidgets project, and the set of included reference form controls is 
purposefully kept small and self-contained to serve as something like a 
reference implementation. We encourage and support a robust ecosystem of 
packages built on top of the ipywidgets framework to provide more complicated 
interactive objects, such as maps or 2d and 3d visualizations, or other form 
control systems built on a variety of popular Javascript frameworks such as 
Material or Vue.
-
-
-Additional Developer Docs
--------------------------
-
-.. toctree::
-   :maxdepth: 3
-
-   dev_install.md
-   dev_testing.md
-   dev_docs
-   dev_release.md
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' "old/ipywidgets-7.6.5/docs/source/examples/Layout 
Example.ipynb" "new/ipywidgets-7.7.1/docs/source/examples/Layout Example.ipynb"
--- "old/ipywidgets-7.6.5/docs/source/examples/Layout Example.ipynb"    
2021-09-14 01:30:14.890474800 +0200
+++ "new/ipywidgets-7.7.1/docs/source/examples/Layout Example.ipynb"    
2022-06-22 19:32:54.794555700 +0200
@@ -57,7 +57,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "m = Map(center=(52, 10), zoom=5, basemap=basemaps.Hydda.Full)"
+    "m = Map(center=(52, 10), zoom=5, basemap=basemaps.OpenStreetMap.Mapnik)"
    ]
   },
   {
@@ -66,7 +66,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "maps = {'Hydda' : basemaps.Hydda.Full,\n",
+    "maps = {'Mapnik' : basemaps.OpenStreetMap.Mapnik,\n",
     "        'Esri' : basemaps.Esri.DeLorme}"
    ]
   },
@@ -91,7 +91,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "basemap_selector.value = 'Hydda'\n",
+    "basemap_selector.value = 'Mapnik'\n",
     "m.layout.height='600px'"
    ]
   },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' "old/ipywidgets-7.6.5/docs/source/examples/Variable 
Inspector.ipynb" "new/ipywidgets-7.7.1/docs/source/examples/Variable 
Inspector.ipynb"
--- "old/ipywidgets-7.6.5/docs/source/examples/Variable Inspector.ipynb"        
2021-09-14 01:30:14.895717100 +0200
+++ "new/ipywidgets-7.7.1/docs/source/examples/Variable Inspector.ipynb"        
2022-06-22 19:32:54.796830200 +0200
@@ -73,7 +73,7 @@
     "            self.closed = True\n",
     "            VariableInspectorWindow.instance = None\n",
     "\n",
-    "    def _fill(self):\n",
+    "    def _fill(self, _result):\n",
     "        \"\"\"Fill self with variable information.\"\"\"\n",
     "        values = self.namespace.who_ls()\n",
     "        self._table.value = '<div class=\"rendered_html 
jp-RenderedHTMLCommon\"><table><thead><tr><th>Name</th><th>Type</th><th>Value</th></tr></thead><tr><td>'
 + \\\n",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/docs/source/index.rst 
new/ipywidgets-7.7.1/docs/source/index.rst
--- old/ipywidgets-7.6.5/docs/source/index.rst  2021-09-14 01:30:14.902526600 
+0200
+++ new/ipywidgets-7.7.1/docs/source/index.rst  2022-06-22 19:32:54.801359400 
+0200
@@ -1,11 +1,104 @@
-ipywidgets
-==========
+Jupyter Widgets
+===============
 
-Full Table of Contents
-----------------------
+.. only:: html
+
+    :Release: |release|
+    :Date: |today|
+
+Jupyter Widgets are `interactive browser controls
+<https://github.com/jupyter-widgets/ipywidgets/blob/master/docs/source/examples/Index.ipynb>`_
+for Jupyter notebooks. Examples include:
+
+* Basic form controls like sliders, checkboxes, text inputs
+* Container controls like tabs, accordions, horizontal and vertical layout 
boxes, grid layouts
+* Advanced controls like maps, 2d and 3d visualizations, datagrids, and more
+
+Notebooks come alive when interactive widgets are used. Users can visualize and
+manipulate their data in intuitive and easy ways.  Researchers can easily see
+how changing inputs to a model impact the results. Scientists can share
+interactive results with graphical user interfaces that others can play with
+without seeing code. Exploring, learning, and sharing becomes a fun immersive
+experience.
+
+.. todo: Add screenshot
+
+Core Jupyter Widgets
+--------------------
+
+Jupyter Widgets is primarily a framework to provide interactive controls (see
+:doc:`examples/Widget Basics` for more information). The ``ipywidgets`` package
+also provides a basic, lightweight set of core form controls that *use* this
+framework. These included controls include a text area, text box, select and
+multiselect controls, checkbox, sliders, tab panels, grid layout, etc.
+
+The framework for building rich interactive objects is the foremost purpose of
+the Jupyter Widgets project, and the set of included core form controls is
+purposefully kept small and self-contained. We encourage and support a robust
+ecosystem of packages built on top of the Jupyter Widgets framework to provide
+more complicated interactive objects, such as maps, 2d and 3d visualizations, 
or
+other form control systems built on a variety of popular Javascript frameworks
+such as Material or Vue.
+
+See the `Jupyter Widgets wiki page
+<https://github.com/jupyter/jupyter/wiki/Jupyter-Widgets>`_ for more 
information
+about custom widget packages built on top of the Jupyter Widgets framework.
+
+Jupyter Widgets components
+--------------------------
+
+The Jupyter Widgets framework has several components:
+
+1. A package in the kernel to provide an interface for widgets. The
+   ``ipywidgets`` Python package provides Jupyter Widgets for the IPython
+   kernel. Other kernels may also provide Jupyter Widgets support.
+2. An extension for the browser Jupyter frontend to manage Jupyter Widgets.
+   Installing ``ipywidgets`` automatically installs extensions for JupyterLab
+   and Jupyter Notebook (the ``jupyterlab-widgets`` and ``widgetsnbextension``
+   packages). The Jupyter Widgets project also maintains a plain HTML interface
+   for embedding Jupyter Widgets on a webpage, and many other frontends support
+   Jupyter Widgets.
+
+See the `Jupyter Widgets wiki
+page <https://github.com/jupyter/jupyter/wiki/Jupyter-Widgets>`_ for more
+information from the community about kernels and frontends that support 
Jupyter Widgets, as well as 
+some custom widget packages built on top of the Jupyter Widgets framework.
 
 .. toctree::
     :maxdepth: 2
 
-    user_guide
-    developer_docs
+    user_install.md
+    examples/Widget Basics.ipynb
+    examples/Widget List.ipynb
+    examples/Output Widget.ipynb
+    examples/Widget Events.ipynb
+    examples/Widget Styling.ipynb
+    examples/Layout Templates.ipynb
+    examples/Widget Custom.ipynb
+    examples/Using Interact.ipynb
+    examples/Widget Low Level.ipynb
+    examples/Widget Asynchronous.ipynb
+    embedding.md
+
+.. toctree::
+   :caption: Changelog and Migration
+   :maxdepth: 1
+
+   changelog.md
+   migration_guides.md
+
+.. toctree::
+   :caption: Developer Guide
+   :maxdepth: 1
+
+   dev_install.md
+   dev_testing.md
+   dev_docs.md
+   contributing.md
+   dev_release.md
+
+.. only:: html
+
+  * :ref:`genindex`
+  * :ref:`modindex`
+  * :ref:`search`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/ipywidgets/__init__.py 
new/ipywidgets-7.7.1/ipywidgets/__init__.py
--- old/ipywidgets-7.6.5/ipywidgets/__init__.py 2021-09-14 01:30:14.909575000 
+0200
+++ new/ipywidgets-7.7.1/ipywidgets/__init__.py 2022-06-22 19:32:54.803705200 
+0200
@@ -38,6 +38,7 @@
     if kernel is None:
         kernel = get_ipython().kernel
     kernel.comm_manager.register_target('jupyter.widget', 
Widget.handle_comm_opened)
+    kernel.comm_manager.register_target('jupyter.widget.control', 
Widget.handle_control_comm_opened)
 
 # deprecated alias
 handle_kernel = register_comm_target
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/ipywidgets/_version.py 
new/ipywidgets-7.7.1/ipywidgets/_version.py
--- old/ipywidgets-7.6.5/ipywidgets/_version.py 2021-09-14 01:40:57.517728600 
+0200
+++ new/ipywidgets-7.7.1/ipywidgets/_version.py 2022-06-22 19:40:05.534478700 
+0200
@@ -1,14 +1,15 @@
 # Copyright (c) Jupyter Development Team.
 # Distributed under the terms of the Modified BSD License.
 
-version_info = (7, 6, 5, 'final', 0)
+version_info = (7, 7, 1, 'final', 0)
 
 _specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''}
 
 __version__ = '%s.%s.%s%s'%(version_info[0], version_info[1], version_info[2],
   '' if version_info[3]=='final' else 
_specifier_[version_info[3]]+str(version_info[4]))
 
-__protocol_version__ = '2.0.0'
+__protocol_version__ = '2.1.0'
+__control_protocol_version__ = '1.0.0'
 
 # These are *protocol* versions for each package, *not* npm versions. To 
check, look at each package's src/version.ts file for the protocol version the 
package implements.
 __jupyter_widgets_base_version__ = '1.2.0'
@@ -16,4 +17,4 @@
 __jupyter_widgets_controls_version__ = '1.5.0'
 
 # A compatible @jupyter-widgets/html-manager npm package semver range
-__html_manager_version__ = '^0.20.0'
+__html_manager_version__ = '^0.20.1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ipywidgets-7.6.5/ipywidgets/widgets/tests/test_interaction.py 
new/ipywidgets-7.7.1/ipywidgets/widgets/tests/test_interaction.py
--- old/ipywidgets-7.6.5/ipywidgets/widgets/tests/test_interaction.py   
2021-09-14 01:30:14.912984600 +0200
+++ new/ipywidgets-7.7.1/ipywidgets/widgets/tests/test_interaction.py   
2022-06-22 19:32:54.805021500 +0200
@@ -254,7 +254,12 @@
     check_widgets(c, lis=d)
 
 def test_mapping():
-    from collections import Mapping, OrderedDict
+    try:
+        # Python 3
+        from collections.abc import Mapping
+    except ImportError:
+        # Python 2
+        from collections import Mapping
     class TestMapping(Mapping):
         def __init__(self, values):
             self.values = values
@@ -698,7 +703,7 @@
 
 def test_interact_noinspect():
     a = u'hello'
-    c = interactive(print, a=a)
+    c = interactive(dict, a=a)
     w = c.children[0]
     check_widget(w,
         cls=widgets.Text,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ipywidgets-7.6.5/ipywidgets/widgets/tests/test_send_state.py 
new/ipywidgets-7.7.1/ipywidgets/widgets/tests/test_send_state.py
--- old/ipywidgets-7.6.5/ipywidgets/widgets/tests/test_send_state.py    
2021-09-14 01:29:56.141703100 +0200
+++ new/ipywidgets-7.7.1/ipywidgets/widgets/tests/test_send_state.py    
2022-06-22 19:32:54.805210000 +0200
@@ -3,10 +3,12 @@
 
 from traitlets import Bool, Tuple, List
 
-from .utils import setup, teardown
+from .utils import setup, teardown, DummyComm
 
 from ..widget import Widget
 
+from ..._version import __control_protocol_version__
+
 # A widget with simple traits
 class SimpleWidget(Widget):
     a = Bool().tag(sync=True)
@@ -23,3 +25,16 @@
     with w.hold_sync():
         pass
     assert w.comm.messages == []
+
+
+def test_control():
+    comm = DummyComm()
+    Widget.close_all()
+    w = SimpleWidget()
+    Widget.handle_control_comm_opened(
+        comm, dict(metadata={'version': __control_protocol_version__})
+    )
+    Widget._handle_control_comm_msg(dict(content=dict(
+        data={'method': 'request_states'}
+    )))
+    assert comm.messages
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ipywidgets-7.6.5/ipywidgets/widgets/tests/test_set_state.py 
new/ipywidgets-7.7.1/ipywidgets/widgets/tests/test_set_state.py
--- old/ipywidgets-7.6.5/ipywidgets/widgets/tests/test_set_state.py     
2021-09-14 01:30:14.913266000 +0200
+++ new/ipywidgets-7.7.1/ipywidgets/widgets/tests/test_set_state.py     
2022-06-22 19:32:54.805292000 +0200
@@ -1,20 +1,26 @@
 # Copyright (c) Jupyter Development Team.
 # Distributed under the terms of the Modified BSD License.
 
-from ipython_genutils.py3compat import PY3
-
 import pytest
 try:
     from unittest import mock
 except ImportError:
     import mock
 
-
 from traitlets import Bool, Tuple, List, Instance, CFloat, CInt, Float, Int, 
TraitError, observe
 
 from .utils import setup, teardown
 
-from ..widget import Widget
+import ipywidgets
+from ipywidgets import Widget
+
+
+@pytest.fixture(params=[True, False])
+def echo(request):
+    oldvalue = ipywidgets.widgets.widget.JUPYTER_WIDGETS_ECHO
+    ipywidgets.widgets.widget.JUPYTER_WIDGETS_ECHO = request.param
+    yield request.param
+    ipywidgets.widgets.widget.JUPYTER_WIDGETS_ECHO = oldvalue
 
 #
 # First some widgets to test on:
@@ -78,7 +84,7 @@
 # Actual tests:
 #
 
-def test_set_state_simple():
+def test_set_state_simple(echo):
     w = SimpleWidget()
     w.set_state(dict(
         a=True,
@@ -86,35 +92,47 @@
         c=[False, True, False],
     ))
 
-    assert w.comm.messages == []
+    assert len(w.comm.messages) == (1 if echo else 0)
 
 
-def test_set_state_transformer():
+def test_set_state_transformer(echo):
     w = TransformerWidget()
     w.set_state(dict(
         d=[True, False, True]
     ))
     # Since the deserialize step changes the state, this should send an update
-    assert w.comm.messages == [((), dict(
+    expected = []
+    if echo:
+        expected.append(
+            ((), dict(
+            buffers=[],
+            data=dict(
+                buffer_paths=[],
+                method='echo_update',
+                state=dict(d=[True, False, True]),
+            ))))
+    expected.append(
+        ((), dict(
         buffers=[],
         data=dict(
             buffer_paths=[],
             method='update',
-            state=dict(d=[False, True, False])
-        )))]
+            state=dict(d=[False, True, False]),
+        ))))
+    assert w.comm.messages == expected
 
 
-def test_set_state_data():
+def test_set_state_data(echo):
     w = DataWidget()
     data = memoryview(b'x'*30)
     w.set_state(dict(
         a=True,
         d={'data': data},
     ))
-    assert w.comm.messages == []
+    assert len(w.comm.messages) == (1 if echo else 0)
 
 
-def test_set_state_data_truncate():
+def test_set_state_data_truncate(echo):
     w = TruncateDataWidget()
     data = memoryview(b'x'*30)
     w.set_state(dict(
@@ -122,15 +140,15 @@
         d={'data': data},
     ))
     # Get message for checking
-    assert len(w.comm.messages) == 1   # ensure we didn't get more than 
expected
-    msg = w.comm.messages[0]
+    assert len(w.comm.messages) == 2 if echo else 1   # ensure we didn't get 
more than expected
+    msg = w.comm.messages[-1]
     # Assert that the data update (truncation) sends an update
     buffers = msg[1].pop('buffers')
     assert msg == ((), dict(
         data=dict(
-            buffer_paths=[['d', 'data']],
             method='update',
-            state=dict(d={})
+            state=dict(d={}),
+            buffer_paths=[['d', 'data']]
         )))
 
     # Sanity:
@@ -138,7 +156,7 @@
     assert buffers[0] == data[:20].tobytes()
 
 
-def test_set_state_numbers_int():
+def test_set_state_numbers_int(echo):
     # JS does not differentiate between float/int.
     # Instead, it formats exact floats as ints in JSON (1.0 -> '1').
 
@@ -150,11 +168,11 @@
         i = 3,
         ci = 4,
     ))
-    # Ensure no update message gets produced
-    assert len(w.comm.messages) == 0
+    # Ensure one update message gets produced
+    assert len(w.comm.messages) == (1 if echo else 0)
 
 
-def test_set_state_numbers_float():
+def test_set_state_numbers_float(echo):
     w = NumberWidget()
     # Set floats to int-like floats
     w.set_state(dict(
@@ -162,22 +180,22 @@
         cf = 2.0,
         ci = 4.0
     ))
-    # Ensure no update message gets produced
-    assert len(w.comm.messages) == 0
+    # Ensure one update message gets produced
+    assert len(w.comm.messages) == (1 if echo else 0)
 
 
-def test_set_state_float_to_float():
+def test_set_state_float_to_float(echo):
     w = NumberWidget()
     # Set floats to float
     w.set_state(dict(
         f = 1.2,
         cf = 2.6,
     ))
-    # Ensure no update message gets produced
-    assert len(w.comm.messages) == 0
+    # Ensure one message gets produced
+    assert len(w.comm.messages) == (1 if echo else 0)
 
 
-def test_set_state_cint_to_float():
+def test_set_state_cint_to_float(echo):
     w = NumberWidget()
 
     # Set CInt to float
@@ -185,8 +203,8 @@
         ci = 5.6
     ))
     # Ensure an update message gets produced
-    assert len(w.comm.messages) == 1
-    msg = w.comm.messages[0]
+    assert len(w.comm.messages) == (2 if echo else 1)
+    msg = w.comm.messages[-1]
     data = msg[1]['data']
     assert data['method'] == 'update'
     assert data['state'] == {'ci': 5}
@@ -208,7 +226,7 @@
     assert len(w.comm.messages) == 0
 
 
-def test_set_state_int_to_float():
+def test_set_state_int_to_float(echo):
     w = NumberWidget()
 
     # Set Int to float
@@ -217,7 +235,7 @@
             i = 3.5
         ))
 
-def test_property_lock():
+def test_property_lock(echo):
     # when this widget's value is set to 42, it sets itself to 2, and then 
back to 42 again (and then stops)
     class AnnoyingWidget(Widget):
         value = Float().tag(sync=True)
@@ -241,13 +259,136 @@
     # this mimics a value coming from the front end
     widget.set_state({'value': 42})
     assert widget.value == 42
+    assert widget.stop is True
+
+    # we expect no new state to be sent
+    calls = []
+    widget._send.assert_has_calls(calls)
+
+
+def test_hold_sync(echo):
+    # when this widget's value is set to 42, it sets the value to 2, and also 
sets a different trait value
+    class AnnoyingWidget(Widget):
+        value = Float().tag(sync=True)
+        other = Float().tag(sync=True)
+
+        @observe('value')
+        def _propagate_value(self, change):
+            print('_propagate_value', change.new)
+            if change.new == 42:
+                with self.hold_sync():
+                    self.value = 2
+                    self.other = 11
 
-    # we expect first the {'value': 2.0} state to be send, followed by the 
{'value': 42.0} state
-    msg = {'method': 'update', 'state': {'value': 2.0}, 'buffer_paths': []}
+    widget = AnnoyingWidget(value=1)
+    assert widget.value == 1
+
+    widget._send = mock.MagicMock()
+    # this mimics a value coming from the front end
+    widget.set_state({'value': 42})
+    assert widget.value == 2
+    assert widget.other == 11
+
+    msg = {'method': 'echo_update', 'state': {'value': 42.0}, 'buffer_paths': 
[]}
+    call42 = mock.call(msg, buffers=[])
+
+    msg = {'method': 'update', 'state': {'value': 2.0, 'other': 11.0}, 
'buffer_paths': []}
     call2 = mock.call(msg, buffers=[])
 
-    msg = {'method': 'update', 'state': {'value': 42.0}, 'buffer_paths': []}
+    calls = [call42, call2] if echo else [call2]
+    widget._send.assert_has_calls(calls)
+
+
+def test_echo(echo):
+    # we always echo values back to the frontend if configured
+    class ValueWidget(Widget):
+        value = Float().tag(sync=True)
+
+    widget = ValueWidget(value=1)
+    assert widget.value == 1
+
+    widget._send = mock.MagicMock()
+    # this mimics a state coming from the front end
+    widget.set_state({'value': 42, 'unexpected_field': 43})
+    assert widget.value == 42
+
+    # we expect this to be echoed
+    msg = {'method': 'echo_update', 'state': {'value': 42.0}, 'buffer_paths': 
[]}
     call42 = mock.call(msg, buffers=[])
 
-    calls = [call2, call42]
+    calls = [call42] if echo else []
+    widget._send.assert_has_calls(calls)
+
+
+
+def test_echo_single(echo):
+    # we always echo multiple changes back in 1 update
+    class ValueWidget(Widget):
+        value = Float().tag(sync=True)
+        square = Float().tag(sync=True)
+        @observe('value')
+        def _square(self, change):
+            self.square = self.value**2
+
+    widget = ValueWidget(value=1)
+    assert widget.value == 1
+
+    widget._send = mock.MagicMock()
+    # this mimics a value coming from the front end
+    widget._handle_msg({
+        'content': {
+            'data': {
+                'method': 'update',
+                'state': {
+                    'value': 8,
+                }
+            }
+        }
+    })
+    assert widget.value == 8
+    assert widget.square == 64
+
+    # we expect this to be echoed
+    # note that only value is echoed, not square
+    msg = {'method': 'echo_update', 'state': {'value': 8.0}, 'buffer_paths': 
[]}
+    call = mock.call(msg, buffers=[])
+
+    msg = {'method': 'update', 'state': {'square': 64}, 'buffer_paths': []}
+    call2 = mock.call(msg, buffers=[])
+
+
+    calls = [call, call2] if echo else [call2]
     widget._send.assert_has_calls(calls)
+
+
+def test_no_echo(echo):
+    # in cases where values coming from the frontend are 'heavy', we might 
want to opt out
+    class ValueWidget(Widget):
+        value = Float().tag(sync=True, echo_update=False)
+
+    widget = ValueWidget(value=1)
+    assert widget.value == 1
+
+    widget._send = mock.MagicMock()
+    # this mimics a value coming from the front end
+    widget._handle_msg({
+        'content': {
+            'data': {
+                'method': 'update',
+                'state': {
+                    'value': 42,
+                }
+            }
+        }
+    })
+    assert widget.value == 42
+
+    # widget._send.assert_not_called(calls)
+    widget._send.assert_not_called()
+
+    # a regular set should sync to the frontend
+    widget.value = 43
+    widget._send.assert_has_calls([mock.call({'method': 'update', 'state': 
{'value': 43.0}, 'buffer_paths': []}, buffers=[])])
+
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/ipywidgets/widgets/widget.py 
new/ipywidgets-7.7.1/ipywidgets/widgets/widget.py
--- old/ipywidgets-7.6.5/ipywidgets/widgets/widget.py   2021-09-14 
01:30:14.916297400 +0200
+++ new/ipywidgets-7.7.1/ipywidgets/widgets/widget.py   2022-06-22 
19:32:54.806524500 +0200
@@ -7,6 +7,7 @@
 in the IPython notebook front-end.
 """
 
+import os
 from contextlib import contextmanager
 try:
     from collections.abc import Iterable
@@ -25,8 +26,27 @@
 
 from base64 import standard_b64encode
 
-from .._version import __protocol_version__, __jupyter_widgets_base_version__
+from .._version import __protocol_version__, __control_protocol_version__, 
__jupyter_widgets_base_version__
+
+
+# Based on jupyter_core.paths.envset
+def envset(name, default):
+    """Return True if the given environment variable is turned on, otherwise 
False
+    If the environment variable is set, True will be returned if it is 
assigned to a value
+    other than 'no', 'n', 'false', 'off', '0', or '0.0' (case insensitive).
+    If the environment variable is not set, the default value is returned.
+    """
+    if name in os.environ:
+        return os.environ[name].lower() not in ['no', 'n', 'false', 'off', 
'0', '0.0']
+    else:
+        return bool(default)
+
+
+
+
 PROTOCOL_VERSION_MAJOR = __protocol_version__.split('.')[0]
+CONTROL_PROTOCOL_VERSION_MAJOR = __control_protocol_version__.split('.')[0]
+JUPYTER_WIDGETS_ECHO = envset('JUPYTER_WIDGETS_ECHO', default=False)
 
 def _widget_to_json(x, obj):
     if isinstance(x, dict):
@@ -290,6 +310,7 @@
     # Class attributes
     #-------------------------------------------------------------------------
     _widget_construction_callback = None
+    _control_comm = None
 
     # widgets is a dictionary of all active widget objects
     widgets = {}
@@ -302,7 +323,6 @@
         for widget in list(cls.widgets.values()):
             widget.close()
 
-
     @staticmethod
     def on_widget_constructed(callback):
         """Registers a callback to be called when a widget is constructed.
@@ -317,6 +337,51 @@
         if Widget._widget_construction_callback is not None and 
callable(Widget._widget_construction_callback):
             Widget._widget_construction_callback(widget)
 
+    @classmethod
+    def handle_control_comm_opened(cls, comm, msg):
+        """
+        Class method, called when the comm-open message on the
+        "jupyter.widget.control" comm channel is received
+        """
+        version = msg.get('metadata', {}).get('version', '')
+        if version.split('.')[0] != CONTROL_PROTOCOL_VERSION_MAJOR:
+            raise ValueError("Incompatible widget control protocol versions: 
received version %r, expected version %r"%(version, 
__control_protocol_version__))
+
+        cls._control_comm = comm
+        cls._control_comm.on_msg(cls._handle_control_comm_msg)
+
+    @classmethod
+    def _handle_control_comm_msg(cls, msg):
+        # This shouldn't happen unless someone calls this method manually
+        if cls._control_comm is None:
+            raise RuntimeError('Control comm has not been properly opened')
+
+        data = msg['content']['data']
+        method = data['method']
+
+        if method == 'request_states':
+            # Send back the full widgets state
+            cls.get_manager_state()
+            widgets = cls.widgets.values()
+            full_state = {}
+            drop_defaults = False
+            for widget in widgets:
+                full_state[widget.model_id] = {
+                    'model_name': widget._model_name,
+                    'model_module': widget._model_module,
+                    'model_module_version': widget._model_module_version,
+                    'state': widget.get_state(drop_defaults=drop_defaults),
+                }
+            full_state, buffer_paths, buffers = _remove_buffers(full_state)
+            cls._control_comm.send(dict(
+                method='update_states',
+                states=full_state,
+                buffer_paths=buffer_paths
+            ), buffers=buffers)
+
+        else:
+            raise RuntimeError('Unknown front-end to back-end widget control 
msg with method "%s"' % method)
+
     @staticmethod
     def handle_comm_opened(comm, msg):
         """Static method, called when a widget is constructed."""
@@ -534,6 +599,21 @@
 
     def set_state(self, sync_data):
         """Called when a state is received from the front-end."""
+        # Send an echo update message immediately
+        if JUPYTER_WIDGETS_ECHO:
+            echo_state = {}
+            for attr, value in sync_data.items():
+                if attr in self.keys and self.trait_metadata(attr, 
'echo_update', default=True):
+                    echo_state[attr] = value
+            if echo_state:
+                echo_state, echo_buffer_paths, echo_buffers = 
_remove_buffers(echo_state)
+                msg = {
+                    'method': 'echo_update',
+                    'state': echo_state,
+                    'buffer_paths': echo_buffer_paths,
+                }
+                self._send(msg, buffers=echo_buffers)
+
         # The order of these context managers is important. Properties must
         # be locked when the hold_trait_notification context manager is
         # released and notifications are fired.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/ipywidgets/widgets/widget_upload.py 
new/ipywidgets-7.7.1/ipywidgets/widgets/widget_upload.py
--- old/ipywidgets-7.6.5/ipywidgets/widgets/widget_upload.py    2021-09-14 
01:30:14.920732700 +0200
+++ new/ipywidgets-7.7.1/ipywidgets/widgets/widget_upload.py    2022-06-22 
19:32:54.808712200 +0200
@@ -45,7 +45,7 @@
     style = InstanceDict(ButtonStyle).tag(sync=True, **widget_serialization)
     metadata = List(Dict(), help='List of file metadata').tag(sync=True)
     data = List(Bytes(), help='List of file content (bytes)').tag(
-        sync=True, from_json=content_from_json
+        sync=True, echo_update=False, from_json=content_from_json
     )
     error = Unicode(help='Error message').tag(sync=True)
     value = Dict(read_only=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/package.json 
new/ipywidgets-7.7.1/package.json
--- old/ipywidgets-7.6.5/package.json   2021-09-14 01:30:14.924390300 +0200
+++ new/ipywidgets-7.7.1/package.json   2022-06-22 19:32:54.810718800 +0200
@@ -12,7 +12,7 @@
     "clean": "lerna run clean",
     "integrity": "node scripts/package-integrity.js",
     "lint": "lerna run lint",
-    "publish": "yarn run clean && yarn run build && lerna publish -m \"Publish 
npm packages\"",
+    "publish": "yarn run clean && yarn run build && lerna publish -m \"Publish 
npm packages\" --pre-dist-tag next",
     "update-dependency": "update-dependency --lerna",
     "updated": "lerna updated"
   },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipywidgets-7.6.5/setup.py 
new/ipywidgets-7.7.1/setup.py
--- old/ipywidgets-7.6.5/setup.py       2021-09-14 01:30:14.964580800 +0200
+++ new/ipywidgets-7.7.1/setup.py       2022-06-22 19:32:54.825371000 +0200
@@ -113,14 +113,11 @@
     'ipykernel>=4.5.1',
     'ipython_genutils~=0.2.0',
     'traitlets>=4.3.1',
-    # Requiring nbformat to specify bugfix version which is not required by
-    # notebook.
-    'nbformat>=4.2.0',
     # TODO: Dynamically add this dependency
     # only if notebook 4.x is installed in this
     # interpreter, to allow ipywidgets to be
     # installed on bare kernels.
-    'widgetsnbextension~=3.5.0'
+    'widgetsnbextension~=3.6.0'
 ]
 
 extras_require = setuptools_args['extras_require'] = {

Reply via email to