Migrating custom widget libraries¶
These are migration guides aimed specifically at developers of third-party widgets.
Migrating from 6.0 to 7.0¶
For example migrations, see these PRs:
- ipyleaflet
- jupyter-gmaps
- bqplot: PR #458, PR #497 and PR #501
To avoid tying your development cycle to ipywidgets, we recommend starting the migration on a branch and keeping that branch open until ipywidgets 7.0 is released.
We also recommend testing the migration in a completely new notebook, rather than one that contains widgets that you instantiated with ipywidgets 6.0.
Updating setup.py¶
Start by updating the dependency in your setup.py
to the latest release. To
find the correct version number, go to the releases
page on Github and
cycle through the tags until you see the latest 7.0.0 tag.
Updating package.json¶
Next, we should update the JavaScript dependencies. The most important change
for widget developers is that the JavaScript package for jupyter-widgets has
been split between @jupyter-widgets/base
and @jupyter-widgets/controls
:
@jupyter-widgets/base
contains the base widget classes and the layout classes@jupyter-widgets/controls
contains the widget classes for the user-facing widgets.
In your package.json
, remove jupyter-js-widgets
from your dependencies
and add @jupyter-widgets/base
. To find the correct version, go to the
releases page and
cycle through the tags until you see a tag called
@jupyter-widgets/base@<version>
. Do the same for
@jupyter-widgets/controls
if you think you have a dependency on it (e.g. if
you create widgets that inherit from VBox
or HBox
or another user-facing widget).
Updating Webpack configuration¶
If you use Webpack to build the client-side library, your Webpack
configuration file (probably at js/webpack.config.json
) declares
jupyter-js-widgets
as an external dependency. You will need to change this
in both the bundle for the notebook and the embeddable bundle. If you just
need @jupyter-widgets/base
, your external dependencies would be:
externals: ['@jupyter-widgets/base']
If you need both @jupyter-widgets/base
and @jupyter-widgets/controls
, include
both packages in the array.
The cookiecutter template provides a sample configuration.
Updating the client-side code¶
If you now build the client-side code of your library, you will get many
errors about missing jupyter-js-widgets
dependencies. You need to replace
every import of jupyter-js-widgets
with an import of
@jupyter-widgets/base
(or, possibly, an import of @jupyter-widgets/controls
).
Your imports should now look like one of the following (depending on how you normally import other modules):
widgets = require('@jupyter-widgets/base')
require(['@jupyter-widgets/base'], function(widgets) {
})
import * as widgets from '@jupyter-widgets/base'
All your widget models should also declare the attributes
_view_module_version
and _model_module_version
. A minimal model now looks like:
var HelloModel = widgets.DOMWidgetModel.extend({
defaults: _.extend(widgets.DOMWidgetModel.prototype.defaults(), {
_model_name : 'HelloModel',
_view_name : 'HelloView',
_model_module : 'example_module',
_view_module : 'example_module',
_model_module_version : '~1.0.0',
_view_module_version : '~1.0.0'
})
});
For embedding to work correctly, the module version needs to be a semantic
version range
that matches a release on NPM. The most common pattern is to request a
version compatible with the version currently in your package.json
by using,
~{{ version number }}
for _model_module_version
and _view_module_version
. See the cookiecutter
template
for details.
Since you probably want to avoid repeating the module version in every
widget, a common pattern is to import the version from package.json
and
prepend a ~
. See
ipyvolume
for an example. If you do this, make sure that your webpack configuration
includes a JSON loader. See the Webpack configuration for
ipyvolume
for an example.
Updating the notebook extension¶
Previously, the notebook extension (normally js/src/extension.js
) required
defining jupyter-js-widgets
in the configuration for requirejs
. This is
no longer needed. See the cookiecutter
template
for an example of the correct requirejs
configuration.
Updating the Python code¶
All widgets need to declare the following six traitlets:
class ExampleWidget(widgets.Widget):
_model_name = Unicode('name of model in JS')
_view_name = Unicode('name of view in JS')
_model_module = Unicode('name your JS package')
_view_module = Unicode('name your JS package')
_model_module_version = Unicode('version of your JS bundle')
_view_module_version = Unicode('version of your JS bundle')
It is likely that your widgets already declared a _model_name
,
_view_name
, _model_module
and _view_module
. The _model_module
and
_view_module
should be the name of your package on NPM (the value of the
name
field in your package.json
). The _model_module_version
and
_view_module_version
should be the version of your JavaScript client (the
values of the version
field in your package.json
).
The _model_module_version
and _view_module_version
are used to find your
JavaScript bundle when embedding widgets. The embed manager will look for the
bundle at https://unpkg.com/<module-name>@<module-version>/dist/index.js
when it finds a widget.
Updating embedded widgets¶
There are now two options for embedding widgets in an HTML page outside of the notebook.
Embedding the standard widgets¶
If you are just embedding the standard widgets that come with ipywidgets, then you can simply include the following script tag:
<script src="https://unpkg.com/@jupyter-widgets/html-manager@*/dist/embed.js" crossorigin="anonymous"></script>
If you want to use a specific version of the embedder, you replace the @*
with a semver range, such as @^0.9.0
Embedding custom widgets with RequireJS¶
In order to embed third-party widgets, you can use the RequireJS-based embedding. First, make sure that RequireJS is loaded on the page, for example:
<!-- Load require.js. Delete this if your page already loads require.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.4/require.min.js" integrity="sha256-Ae2Vz/4ePdIu6ZyI/5ZGsYnb+m0JlOmKPjt6XZ9JJkA=" crossorigin="anonymous"></script>
Then include the following script, which defines the embedding libraries and runs the function to render widgets:
<script src="https://unpkg.com/@jupyter-widgets/html-manager@*/dist/embed-amd.js" crossorigin="anonymous"></script>
If you want to use a specific version of the embedder, you replace the @*
with a semver range, such as @^0.9.0
If you need to embed custom widgets without using RequireJS, you’ll need to compile your own embedding javascript that includes the third-party libraries.