Skip to content

Jupyterlite integration #977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 69 commits into from
Mar 8, 2023
Merged

Conversation

amueller
Copy link
Contributor

@amueller amueller commented Jul 16, 2022

Fix #927.

To me replite doesn't seem that nice an experience, see discussion in #927.
This PR adds a button to launch a jupyterlite instance in a new page that contains all the example notebooks, so python/jupyter doesn't need to be reloaded to read other examples.

Currently looks like this:
image

And clicking that gets you to something like this:
image

I copy & pasted a bunch of the binder button code, this probably should be refactored and made a bit cleaner, also I feel the footer is too big and we should have the buttons next to each other (launch and download, or maybe one row for launch and one for download?)

@amueller
Copy link
Contributor Author

btw I think we should to the raw html hack to make both of the launch things open in new windows, cause the current behavior is a bit confusing, but that seems orthogonal to adding jupyterlite.

@amueller
Copy link
Contributor Author

btw I think eventually we should use emscripten-forge: https://blog.jupyter.org/mamba-meets-jupyterlite-88ef49ac4dc8

Because pyodite will not have the most recent release when a release is made (and/or might not include less-used packages). We clearly want the docs to actually run the right version of the package, that corresponds to the docs.

@amueller
Copy link
Contributor Author

amueller commented Jul 17, 2022

I'm not sure I understand the exit code 1 error, any help would be appreciated :)

Edit: it's because of jupyterlite/jupyterlite-sphinx#65

@amueller
Copy link
Contributor Author

Seems to mostly work on circle now, but I think you can't execute a kernel because of the way the artifacts are hosted.
check out the build here

Console shows this error when actually trying to execute a kernel:
image

@GaelVaroquaux
Copy link
Contributor

I love this effort. Thank you so much @amueller for pushing in this direction!!

I've been playing a bit with it. I don't seem to get the same errors as you :).

The example "Introductory example - Plotting sin" does fire up a jupyterlab, but trying even a simple "print" in it leads to infinite busy waiting (out of a sanity check, pyiodine does work on my browser, at least the way that it is set up on the front page of numpy).

On the "just_code" example, I am getting the following:
https://output.circle-artifacts.com/output/job/6d1d8c11-9b55-44c9-937e-7481361bda16/artifacts/0/rtd_html/auto_examples/lite/lab/index.html?path=just_code.ipynb
image

@amueller
Copy link
Contributor Author

amueller commented Jul 19, 2022

I think the infinite wait is a consequence of the error. You need to open the console to see it. It's a cross-site scripting protection, I assume. Sorry I wasn't more clear when/where the error occurred.

@lesteve
Copy link
Member

lesteve commented Nov 29, 2022

This would be a great functionality to have!

I tried to resolve the conflicts to get a better idea of the status of this PR.

@lesteve
Copy link
Member

lesteve commented Nov 29, 2022

There are warnings like the ones below when enabling jupyterlite-sphinx. As a temporary work-around I am allowing the doc build to run with warnings.

WARNING: multiple files found for the document "auto_examples/local_module": ['auto_examples/local_module.py', 'auto_examples/local_module.rst', 'auto_examples/local_module.ipynb']
Use '/home/circleci/project/doc/auto_examples/local_module.rst' for the build.
WARNING: multiple files found for the document "auto_examples/plot_0_sin": ['auto_examples/plot_0_sin.py', 'auto_examples/plot_0_sin.py.md5', 'auto_examples/plot_0_sin.rst', 'auto_examples/plot_0_sin.ipynb']
Use '/home/circleci/project/doc/auto_examples/plot_0_sin.rst' for the build.
WARNING: multiple files found for the document "auto_examples/plot_1_exp": ['auto_examples/plot_1_exp.py', 'auto_examples/plot_1_exp.py.md5', 'auto_examples/plot_1_exp.rst', 'auto_examples/plot_1_exp.ipynb']
Use '/home/circleci/project/doc/auto_examples/plot_1_exp.rst' for the build.
WARNING: multiple files found for the document "auto_examples/plot_2_seaborn": ['auto_examples/plot_2_seaborn.py', 'auto_examples/plot_2_seaborn.py.md5', 'auto_examples/plot_2_seaborn.rst', 'auto_examples/plot_2_seaborn.ipynb']
Use '/home/circleci/project/doc/auto_examples/plot_2_seaborn.rst' for the build.
WARNING: multiple files found for the document "auto_examples/plot_3_capture_repr": ['auto_examples/plot_3_capture_repr.py', 'auto_examples/plot_3_capture_repr.py.md5', 'auto_examples/plot_3_capture_repr.rst', 'auto_examples/plot_3_capture_repr.ipynb']
Use '/home/circleci/project/doc/auto_examples/plot_3_capture_repr.rst' for the build.
WARNING: multiple files found for the document "auto_examples/plot_4_choose_thumbnail": ['auto_examples/plot_4_choose_thumbnail.py', 'auto_examples/plot_4_choose_thumbnail.py.md5', 'auto_examples/plot_4_choose_thumbnail.rst', 'auto_examples/plot_4_choose_thumbnail.ipynb']
Use '/home/circleci/project/doc/auto_examples/plot_4_choose_thumbnail.rst' for the build.
WARNING: multiple files found for the document "auto_examples/plot_4b_provide_thumbnail": ['auto_examples/plot_4b_provide_thumbnail.py', 'auto_examples/plot_4b_provide_thumbnail.py.md5', 'auto_examples/plot_4b_provide_thumbnail.rst', 'auto_examples/plot_4b_provide_thumbnail.ipynb']
Use '/home/circleci/project/doc/auto_examples/plot_4b_provide_thumbnail.rst' for the build.
WARNING: multiple files found for the document "auto_examples/plot_5_unicode_everywhere": ['auto_examples/plot_5_unicode_everywhere.py', 'auto_examples/plot_5_unicode_everywhere.py.md5', 'auto_examples/plot_5_unicode_everywhere.rst', 'auto_examples/plot_5_unicode_everywhere.ipynb']
Use '/home/circleci/project/doc/auto_examples/plot_5_unicode_everywhere.rst' for the build.
WARNING: multiple files found for the document "auto_examples/plot_6_function_identifier": ['auto_examples/plot_6_function_identifier.py', 'auto_examples/plot_6_function_identifier.py.md5', 'auto_examples/plot_6_function_identifier.rst', 'auto_examples/plot_6_function_identifier.ipynb']
Use '/home/circleci/project/doc/auto_examples/plot_6_function_identifier.rst' for the build.

Edit: I figured this is fixed by setting jupyterlite_bind_ipynb_suffix = False

@lesteve
Copy link
Member

lesteve commented Nov 29, 2022

Not sure why the CircleCI status still seems to be pending, the build has actually finished.

example HTML

JupyterLite link for this example

I get a similar error as in #977 (comment). Basically the kernel is unresponsive. More details about the errors below.

Edit: a little bit of googling seems to indicate that this is a CircleCI-specific issue, see microsoft/playwright#18108 (comment).

Chromium:

ServiceWorker registration failed: SecurityError: Failed to register a ServiceWorker for scope ('https://output.circle-artifacts.com/output/job/ec051f51-e6c5-4416-a009-de2b73c4563c/artifacts/0/rtd_html/lite/') with script ('https://output.circle-artifacts.com/output/job/ec051f51-e6c5-4416-a009-de2b73c4563c/artifacts/0/rtd_html/lite/services.js'): The script resource is behind a redirect, which is disallowed.
(anonymous) @ serviceworker.js:37
Unsafe attempt to load URL https://circleci-tasks-prod.s3.us-east-1.amazonaws.com/forks/storage/artifacts/2629550a-a4b7-499e-98e6-87b759009294/139059363/ec051f51-e6c5-4416-a009-de2b73c4563c/0/rtd_html/lite/build/835.42921e6.js?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQVFQINEOON7A6VRW%2F20221129%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221129T104450Z&X-Amz-Expires=60&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEMaCXVzLWVhc3QtMSJHMEUCIASCwhgzdCnneUK4l2I1y4zoZuSNicXl3dFIRU%2FBj%2FT0AiEAuZS4KxmfqyCqCO%2F2JugwhcAxxNGbcR%2FTMDh...cSxDroQAW6URTHv6tv0IEcc24eKK9zK98Aiou9y5PP34noFC2kAO6VnWoo9%2BqXfFNuv%2FuN5DVk0n9%2BDsNBCwXKCQ2lMwN1Ik5RZG0NBDshRpKWvzs%2B8nQyEP49aA5rm9vbJRmGDVDNDF9zarCpjeTClw5ecBjqdAcSweYbkk%2FSpSnvrlwplK2gNdUOytPKu9vupodJl07wY4daB6UC%2BXCRLAajn%2FMAYPaL5IG4LifUJ41HgRWRNrZJmO3R8WyJi1JHD8iyOCUB0YeeWwENaImP26xfUlPtuYJxvoW2vBedJx799MESRmkoAYkkJ3ecq9AYRZ2KqRTLTn%2FKq8h9dJZDlYcmRXVOBfeRgpRCt2qhbvHZs8EM%3D&X-Amz-SignedHeaders=host&x-id=GetObject&X-Amz-Signature=03e9a941cd93f50bbe3c323ce4a15f9f8a590b809a6c7ab30803826e70097bbf from frame with URL https://output.circle-artifacts.com/output/job/ec051f51-e6c5-4416-a009-de2b73c4563c/artifacts/0/rtd_html/lite/lab/index.html. Domains, protocols and ports must match.

Firefox:

ServiceWorker registration failed: SecurityError: The operation is insecure. [serviceworker.js:37:20](webpack://_JUPYTERLAB.CORE_OUTPUT/packages/server/lib/serviceworker.js)
    initialize serviceworker.js:37
Security Error: Content at https://output.circle-artifacts.com/output/job/ec051f51-e6c5-4416-a009-de2b73c4563c/artifacts/0/rtd_html/lite/lab/index.html?path=plot_0_sin.ipynb may not load data from https://circleci-tasks-prod.s3.us-east-1.amazonaws.com/forks/storage/artifacts/2629550a-a4b7-499e-98e6-87b759009294/139059363/ec051f51-e6c5-4416-a009-de2b73c4563c/0/rtd_html/lite/build/835.42921e6.js?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAQVFQINEONPAW62VN%2F20221129%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20221129T104631Z&X-Amz-Expires=60&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEMaCXVzLWVhc3QtMSJHMEUCIAVDikXgmeYLoTU0i3IXw1y2pP66AynC%2FBfR4ls%2Bxj5eAiEA%2FZUfzRcuASeGwxOon1Dn6gU9mlmRoIzMGqsHHQFpL%2BoqqwIIXBADGgwwNDU0NjY4MDY1NTYiDCZEssD1BrBiFAqRpSqIAuBHDfVtUsLcLnYPHcvnIM6PhecLpLfSjZeEP%2FCIpwaN6w%2FT21K4s%2FNIs%2FXxGCC%2FcY2y3d9owttd33Zrhlg8%2BVj0I0RBotiiSN4yiTcwgZuX34Kj51qePpoPQCVNNL%2BUf2m02rdGBIdIJFSLEgIBksQUZACdL5PMGJgGwMqimdLP0ytSr%2BUrOUVra0V21%2F%2B6xNQXX9LAHxOZ0KUsfxB8ormz5a3DbUzUAeihTR90GqtgfwPhbWa%2B6VTiqLD7AlWzlRAOCF9WZfm8anIPWvaKNr5ytA5yFvAgm8m6vW%2BFMUQiy1kCQpbsIkKYiSOFkcQiOCnpfccVsNbqiINxRD%2BkIOTEw6suev5rsDD3wpecBjqdAbqDjYbihto0wmqUh5gU7scKIRhyoVxmmMDtg%2FVBuTvMcx6OXLQtMkc4vmqlP1It9DLj2u3YBYwuFLJ%2FYIykNuHY8AlOvn6LUIzl4OAqKI0%2B9n7GpsqkjICOHecC5lpJZ8bAO6Eft4RqI0Rf6mMIXoCvlL8eFaG6ioMEc3V5y7SW%2FSjOqTuKe7k3UtOwVxRg3iOGdWKUVhXxIi4mgi8%3D&X-Amz-SignedHeaders=host&x-id=GetObject&X-Amz-Signature=08a3efb9809361ff0bed9ef005d3006353ae6599cf101d7178c845139310cad8.
Loading Worker from “https://output.circle-artifacts.com/output/job/ec051f51-e6c5-4416-a009-de2b73c4563c/artifacts/0/rtd_html/lite/build/835.42921e6.js” was blocked because of a disallowed MIME type (“”).

@lesteve
Copy link
Member

lesteve commented Nov 29, 2022

The CircleCI issue is annoying but not a blocker, it works fine locally when opening a server with python -m http.server in the _build/html folder. I expect it to work fine in most deployments setup e.g. readthedocs.io or github pages.

I triggered another CI run to make sure the other CI failures are not spurious.

Copy link
Contributor

@ogrisel ogrisel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking forward to testing this on the scikit-learn example gallery.

I expect that we might want to disable jupyterlite for specific examples where we know for sure that they will not run with Pyodide in the foreseeable future (e.g. because of an extra dependencies not available for WASM).

Would it be possible to have a configuration point to set a list of examples for each to disable the launch jupyterlite button and to avoid generating the matching notebook in the jupyterlite_contents folder?

<https://pyodide.org/en/stable/index.html>`__ environment. That means that
some non pure-Python packages may not be available, see list of `available
packages in Pyodide
<https://pyodide.org/en/stable/usage/packages-in-pyodide.html>`__.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could expand this point a bit and explain that this it's possible to install extra, pure-python packages from pypi.org using the following construct:

try:
    # Manually install extra dependencies when running this example with
    # Pyodide:
    import micropip
    await micropip.install("package_name")
except ImportError:
    # Assume all the dependencies are already installed when running on other
    # types of hosts, such as binder.
    pass

Not protecting this snippet against ImportError would render the example pyodide-dependent as a result.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the %pip magic is also supported in the latest JupyterLite releases: https://jupyterlite.readthedocs.io/en/latest/howto/python/packages.html#installing-packages-at-runtime

%pip install package_name

Which could help make remove this try/ except block which could be awkward to some users.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice I didn't know this!

@lesteve
Copy link
Member

lesteve commented Feb 8, 2023

CI is green, I have added some documentation, I think this is ready for review.

===============================================================

Sphinx-Gallery automatically generates Jupyter notebooks for any examples built
with the gallery. `JupyterLite <https://jupyterlite.readthedocs.io>`_ makes it
with the gallery. `JupyterLite <https://jupyterlite.readthedocs.io>`__ makes it
possible to run an example in your browser. TODO mention difference with Binder?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
possible to run an example in your browser. TODO mention difference with Binder?
possible to run an example in your browser. This is different from Binder links where
the notebook is run on a server. By running in the reader's browser the startup time
can be much lower compared to Binder. However some libraries or parts of some
libraries do not yet work in the browser.

How about something like this? Just an idea I had as I was reading the diff (didn't take long to write and maybe you find it useful)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice thanks a lot! (I thought I tackled all the TODOs left but apparently not 😉)

@lesteve
Copy link
Member

lesteve commented Mar 6, 2023

Ping @larsoner or @GaelVaroquaux in case you have some time to review this one!

Feedback from anyone else would be welcome too of course!

@rth
Copy link

rth commented Mar 6, 2023

FWIW from someone not much involved in sphinx-gallery development, I find the current implementation looks pretty good, and that it would be better to release it as experimental and get user feedback rather than try to get things into a perfect state and wait X more month.

Anyway, there are still a few open questions about packaging. If you say want to document a package with C extensions it would need to be built for emscripten/wasm32 target. Probably in CI alongside the docs, but not as part of the doc builds. So what should be best practices there would likely need to be discussed at some point (not in this PR), and the outcome of that discussion might also have an impact on how the related configuration should look like. But anyway that is the next step after getting a minimal working solution out there IMO.

@larsoner
Copy link
Contributor

larsoner commented Mar 6, 2023

@lucyleeow do you have time this week to look and merge if you're happy? If not then I can look

<https://pyodide.org/en/latest/usage/wasm-constraints.html>`__ for some
Pyodide limitations.
- with JupyterLite environments are not as flexible as Binder, for example you
can not use a docker image but only the default `Pyodide
Copy link

@jtpio jtpio Mar 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only the default Pyodide

Maybe there could be a quick mention that it's also be possible to use other kernels, for example Xeus Python: https://github.com/jupyterlite/xeus-python-kernel.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point. I tried to focus this PR on the simplest case i.e. the Pyolite kernel, but this is certainly something which could be mentioned in a follow-up PR.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem it could definitely be mentioned later (just noticed while looking at the diff).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Especially with deeper instructions on how to package a kernel with built-in dependencies required to run the examples of a given project.

@larsoner
Copy link
Contributor

larsoner commented Mar 8, 2023

I took a look and this is all reasonable. I want to cut 0.12, so I'll merge this then make a release so that people can start using it!

@larsoner larsoner merged commit 28f744d into sphinx-gallery:master Mar 8, 2023
@lesteve
Copy link
Member

lesteve commented Mar 9, 2023

Great to see this PR merged, thanks to everyone involved!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add option to generate interactive gallery with replite
9 participants