Skip to content
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

fix: trust new notebooks and notebooks with new cells #275

Merged
merged 1 commit into from
May 8, 2024

Conversation

maartenbreddels
Copy link
Contributor

Problem

When a new notebook cell is created from the front end (this includes creating a new notebook), the notebook is not trusted after a page reload. The core issue is that nbclassic creates an invalid notebook on the front end, which does not follow the nbformat 4.5 schema.

This problem only happens when Jupyter notebook 6.x/nbclassic is used in combination with nbformat >=5.1.0 (where nbformat schema 4.5 was introduced) or higher.
Before nbformat 5.1.0, there were no cell-ID's in the notebook format JEP 62.
Starting from nbformat 5.1.0, Cell-ID's are added to notebook data jupyter/nbformat#189.

Following JEP 62, raw_cell, markdown and code_cell should include an id field. When it is not present, nbformat will add the id field to the cell to make it valid according to the schema.

However, this happens after the notebook is 'trusted'. I am not an expert on the notary system, but mutation of the notebook after it is marked trusted will basically turn the notebook into an untrusted notebook.

Therefore, if we want to make use of the notary system as intended, we should send valid notebooks from the front end to the back end.

Steps to reproduce

  • Install and run
$ pip install "nbclassic<7" "nbformat>=5.1.0"
$ jupyter nbclassic
  • Create a new notebook
  • Add this to a cell:
import IPython.display
IPython.display.Javascript("window.javascriptExecuted = true")
  • Execute the cell
  • Save the notebook
  • Reload the notebook

Now, the notebook is seen as not trusted.

One could argue, this is not that bad, since it's a one time thing, but it is not: After trusting the notebook, add a new cell to the notebook, save, reload. The notebook is now again seen as untrusted.

Expected behavior

A new notebook and a notebook after a cell is added should be trusted after a reload.

Related issues / PRs

Solution

We should send valid notebooks from the front end to the back end. This means adding the id field to the raw_cell, markdown, and code_cell when they are created.

This PR is modeled after jupyterlab/jupyterlab#10018. Although the id field should only be set for the raw_cell, markdown and code_cell, the JupyterLab PR sets the id field for all cell types, we only do this for the raw_cell, markdown and code_cell as per the JEP 62.

As explained in the code, we use a uuid trimmed to 8 characters, like nbformat.

Creating a new notebook or adding a new cell to a notebook should
not remove the trust status of the notebook.
@RRosio
Copy link
Collaborator

RRosio commented May 6, 2024

Thank you @maartenbreddels! I have tried running this locally and I am running into a test failure for the end_to_end/test_trust.py and in trying the functionality out, I continue to see an untrusted notebook when I am reloading the page. This led me to look into the CI tests to see what the output there looks like and I see that for the trust_test.py in runs like on macos-12 with python 3.8, out of the 18 statements, 18 are Miss and the coverage is 0% on the coverage report. On many of more of these tests running on CI, there appears to be 0% coverage as opposed to the results of running locally, where I ran the tests with python -m pytest -vv nbclassic/tests/end_to_end --cov=nbclassic as opposed to the command used in the CI python -m pytest -vv --cov=nbclassic --cov-report term-missing:skip-covered || python -m pytest -vv --cov=nbclassic --cov-report term-missing:skip-covered. I may be misinterpreting or misunderstanding this so I would appreciate another set of eyes on this or some additional clarification! Thank you in advance!

Jupyter Packages Installed
(nbclassic_275_py38) ➜ rosioreyes@Rosios-MacBook-Pro  ~/Desktop/code/jupyter/nbclassic git:(pr/275) ✗ jupyter --version
Selected Jupyter core packages...
IPython          : 8.12.3
ipykernel        : 6.29.4
ipywidgets       : not installed
jupyter_client   : 8.6.1
jupyter_core     : 5.7.2
jupyter_server   : 2.14.0
jupyterlab       : not installed
nbclient         : 0.10.0
nbconvert        : 7.16.4
nbformat         : 5.10.4
notebook         : not installed
qtconsole        : not installed
traitlets        : 5.14.3
Pytest Run Results
(nbclassic_275_py38) ➜ rosioreyes@Rosios-MacBook-Pro  ~/Desktop/code/jupyter/nbclassic git:(pr/275) ✗ python -m pytest -vv nbclassic/tests/end_to_end --cov=nbclassic
================================================================================== test session starts ===================================================================================
platform darwin -- Python 3.8.19, pytest-8.2.0, pluggy-1.5.0 -- /Users/rosioreyes/miniconda3/envs/nbclassic_275_py38/bin/python3.8
cachedir: .pytest_cache
rootdir: /Users/rosioreyes/Desktop/code/jupyter/nbclassic
configfile: pyproject.toml
plugins: cov-5.0.0, tornasync-0.6.0.post2, anyio-4.3.0, playwright-0.4.4, base-url-2.1.0, nbval-0.11.0
collected 32 items                                                                                                                                                                       

nbclassic/tests/end_to_end/test_buffering.py::test_kernels_buffer_without_conn PASSED                                                                                              [  3%]
nbclassic/tests/end_to_end/test_buffering.py::test_buffered_cells_execute_in_order PASSED                                                                                          [  6%]
nbclassic/tests/end_to_end/test_clipboard_multiselect.py::test_clipboard_multiselect PASSED                                                                                        [  9%]
nbclassic/tests/end_to_end/test_dashboard_nav.py::test_navigation PASSED                                                                                                           [ 12%]
nbclassic/tests/end_to_end/test_deletecell.py::test_delete_cells PASSED                                                                                                            [ 15%]
nbclassic/tests/end_to_end/test_display_image.py::test_display_image PASSED                                                                                                        [ 18%]
nbclassic/tests/end_to_end/test_display_isolation.py::test_display_isolation PASSED                                                                                                [ 21%]
nbclassic/tests/end_to_end/test_dualmode_arrows.py::test_dualmode_arrows PASSED                                                                                                    [ 25%]
nbclassic/tests/end_to_end/test_dualmode_cellmode.py::test_dualmode_cellmode PASSED                                                                                                [ 28%]
nbclassic/tests/end_to_end/test_dualmode_clipboard.py::test_dualmode_clipboard PASSED                                                                                              [ 31%]
nbclassic/tests/end_to_end/test_dualmode_execute.py::test_dualmode_execute PASSED                                                                                                  [ 34%]
nbclassic/tests/end_to_end/test_dualmode_insertcell.py::test_insert_cell PASSED                                                                                                    [ 37%]
nbclassic/tests/end_to_end/test_dualmode_markdown.py::test_dualmode_markdown PASSED                                                                                                [ 40%]
nbclassic/tests/end_to_end/test_execute_code.py::test_execute_code PASSED                                                                                                          [ 43%]
nbclassic/tests/end_to_end/test_find_and_replace.py::test_find_and_replace PASSED                                                                                                  [ 46%]
nbclassic/tests/end_to_end/test_interrupt.py::test_interrupt PASSED                                                                                                                [ 50%]
nbclassic/tests/end_to_end/test_kernel_menu.py::test_cancel_restart_or_shutdown PASSED                                                                                             [ 53%]
nbclassic/tests/end_to_end/test_kernel_menu.py::test_menu_items PASSED                                                                                                             [ 56%]
nbclassic/tests/end_to_end/test_markdown.py::test_markdown_cell PASSED                                                                                                             [ 59%]
nbclassic/tests/end_to_end/test_markdown.py::test_markdown_headings PASSED                                                                                                         [ 62%]
nbclassic/tests/end_to_end/test_merge_cells.py::test_merge_cells PASSED                                                                                                            [ 65%]
nbclassic/tests/end_to_end/test_move_multiselection.py::test_move_multiselection PASSED                                                                                            [ 68%]
nbclassic/tests/end_to_end/test_multiselect.py::test_multiselect PASSED                                                                                                            [ 71%]
nbclassic/tests/end_to_end/test_multiselect_toggle.py::test_multiselect_toggle PASSED                                                                                              [ 75%]
nbclassic/tests/end_to_end/test_notifications.py::test_notification PASSED                                                                                                         [ 78%]
nbclassic/tests/end_to_end/test_prompt_numbers.py::test_prompt_numbers PASSED                                                                                                      [ 81%]
nbclassic/tests/end_to_end/test_save.py::test_save PASSED                                                                                                                          [ 84%]
nbclassic/tests/end_to_end/test_save_as_notebook.py::test_save_as_nb PASSED                                                                                                        [ 87%]
nbclassic/tests/end_to_end/test_save_readonly_as.py::test_save_readonly_as SKIPPED (fails randomly on osx)                                                                         [ 90%]
nbclassic/tests/end_to_end/test_shutdown.py::test_shutdown PASSED                                                                                                                  [ 93%]
nbclassic/tests/end_to_end/test_trust.py::test_trust FAILED                                                                                                                        [ 96%]
nbclassic/tests/end_to_end/test_undelete.py::test_undelete_cells PASSED                                                                                                            [100%]

======================================================================================== FAILURES ========================================================================================
_______________________________________________________________________________________ test_trust _______________________________________________________________________________________

notebook_frontend = <nbclassic.tests.end_to_end.utils.NotebookFrontend object at 0x112dad910>

    def test_trust(notebook_frontend):
        def save_notebook():
            notebook_frontend.evaluate("() => Jupyter.notebook.save_notebook()", page=EDITOR_PAGE)
    
        # Add a cell that executes javascript
        notebook_frontend.add_cell(index=0, content=trust_test_code)
        notebook_frontend.execute_cell(0)
        notebook_frontend.wait_for_cell_output(0)
        # Make sure the JavaScript executed
        assert notebook_frontend.evaluate("() => window.javascriptExecuted", page=EDITOR_PAGE) == True
        # Check that we see the 'Trusted' text on the page
        trusted = notebook_frontend.locate("#notification_trusted", page=EDITOR_PAGE)
        assert trusted.get_inner_text() == "Trusted"
        save_notebook()
    
        # refresh the page, should be trusted
        notebook_frontend.reload(EDITOR_PAGE)
        notebook_frontend.wait_for_kernel_ready()
        trusted = notebook_frontend.locate("#notification_trusted", page=EDITOR_PAGE)
>       assert trusted.get_inner_text() == "Trusted"
E       AssertionError: assert 'Not Trusted' == 'Trusted'
E         
E         - Trusted
E         + Not Trusted
E         ? ++++

nbclassic/tests/end_to_end/test_trust.py:28: AssertionError
--------------------------------------------------------------------------------- Captured stdout setup ----------------------------------------------------------------------------------
command= ['/Users/rosioreyes/miniconda3/envs/nbclassic_275_py38/bin/python3.8', '-m', 'nbclassic', '--no-browser', '--notebook-dir', '/var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/notebooks', '--ServerApp.base_url=/a@b/']
Notebook server info: {'nbdir': '/var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/notebooks', 'extra_env': {'JUPYTER_CONFIG_DIR': '/var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/jupyter_config', 'JUPYTER_RUNTIME_DIR': '/var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/jupyter_runtime', 'IPYTHONDIR': '/var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/ipython'}, 'popen': <subprocess.Popen object at 0x112dadaf0>, 'base_url': '/a@b/', 'hostname': 'localhost', 'password': False, 'pid': 71315, 'port': 8888, 'root_dir': '/var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/notebooks', 'secure': False, 'sock': '', 'token': 'a78dc41167dd7d8804101e24f7cec591fea4f729c770872e', 'url': 'http://localhost:8888/a@b/', 'version': '2.14.0'}
--------------------------------------------------------------------------------- Captured stderr setup ----------------------------------------------------------------------------------
[W 2024-05-06 10:53:17.720 ServerApp] notebook_dir is deprecated, use root_dir
[W 2024-05-06 10:53:17.739 ServerApp] A `_jupyter_server_extension_points` function was not found in nbclassic. Instead, a `_jupyter_server_extension_paths` function was found and will be used for now. This function name will be deprecated in future releases of Jupyter Server.
[I 2024-05-06 10:53:17.748 ServerApp] jupyter_server_terminals | extension was successfully linked.
[I 2024-05-06 10:53:17.751 ServerApp] nbclassic | extension was successfully linked.
[I 2024-05-06 10:53:17.753 ServerApp] Writing Jupyter server cookie secret to /var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/jupyter_runtime/jupyter_cookie_secret
[I 2024-05-06 10:53:17.911 ServerApp] notebook_shim | extension was successfully linked.
[I 2024-05-06 10:53:17.935 ServerApp] notebook_shim | extension was successfully loaded.
[I 2024-05-06 10:53:17.936 ServerApp] jupyter_server_terminals | extension was successfully loaded.
[I 2024-05-06 10:53:17.940 ServerApp] nbclassic | extension was successfully loaded.
[I 2024-05-06 10:53:17.941 ServerApp] Serving notebooks from local directory: /var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/notebooks
[I 2024-05-06 10:53:17.941 ServerApp] Jupyter Server 2.14.0 is running at:
[I 2024-05-06 10:53:17.941 ServerApp] http://localhost:8888/a@b/tree?token=a78dc41167dd7d8804101e24f7cec591fea4f729c770872e
[I 2024-05-06 10:53:17.941 ServerApp]     http://127.0.0.1:8888/a@b/tree?token=a78dc41167dd7d8804101e24f7cec591fea4f729c770872e
[I 2024-05-06 10:53:17.941 ServerApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 2024-05-06 10:53:17.945 ServerApp] 
    
    To access the server, open this file in a browser:
        file:///var/folders/gb/jxvl5f7j7q55tsclds78r_1h0000gp/T/tmpc02td87b/jupyter_runtime/jpserver-71315-open.html
    Or copy and paste one of these URLs:
        http://localhost:8888/a@b/tree?token=a78dc41167dd7d8804101e24f7cec591fea4f729c770872e
        http://127.0.0.1:8888/a@b/tree?token=a78dc41167dd7d8804101e24f7cec591fea4f729c770872e
[I 2024-05-06 10:53:18.252 ServerApp] 302 GET /a@b/?token=[secret] (@127.0.0.1) 0.45ms
[I 2024-05-06 10:53:18.565 ServerApp] Creating new notebook in 
[W 2024-05-06 10:53:19.237 ServerApp] 404 GET /a@b/nbextensions/widgets/notebook/js/extension.js?v=20240506175317 (0a8313789709403aad9563262d8d9153@127.0.0.1) 10.53ms referer=http://localhost:8888/a@b/notebooks/Untitled.ipynb?kernel_name=python3
[I 2024-05-06 10:53:19.246 ServerApp] Kernel started: f0103368-8c69-4090-a2b0-3377af689190
[I 2024-05-06 10:53:19.707 ServerApp] Connecting to kernel f0103368-8c69-4090-a2b0-3377af689190.
---------------------------------------------------------------------------------- Captured stderr call ----------------------------------------------------------------------------------
[I 2024-05-06 10:53:20.161 ServerApp] Saving file at /Untitled.ipynb
/Users/rosioreyes/miniconda3/envs/nbclassic_275_py38/lib/python3.8/site-packages/nbformat/__init__.py:132: MissingIDFieldWarning: Cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.
  validate(nb)
[I 2024-05-06 10:53:20.202 ServerApp] Starting buffering for f0103368-8c69-4090-a2b0-3377af689190:ae20fabca09644c4a9d00b0d30eb2b83
[W 2024-05-06 10:53:20.622 ServerApp] Notebook Untitled.ipynb is not trusted
[W 2024-05-06 10:53:20.647 ServerApp] 404 GET /a@b/nbextensions/widgets/notebook/js/extension.js?v=20240506175317 (0a8313789709403aad9563262d8d9153@127.0.0.1) 0.98ms referer=http://localhost:8888/a@b/notebooks/Untitled.ipynb?kernel_name=python3
[I 2024-05-06 10:53:20.649 ServerApp] Connecting to kernel f0103368-8c69-4090-a2b0-3377af689190.
-------------------------------------------------------------------------------- Captured stdout teardown --------------------------------------------------------------------------------

  _   _          _      _
 | | | |_ __  __| |__ _| |_ ___
 | |_| | '_ \/ _` / _` |  _/ -_)
  \___/| .__/\__,_\__,_|\__\___|
       |_|
                                                                           
Read the migration plan to Notebook 7 to learn about the new features and the actions to take if you are using extensions.

https://jupyter-notebook.readthedocs.io/en/latest/migrate_to_notebook7.html

Please note that updating to Notebook 7 might break some of your extensions.

-------------------------------------------------------------------------------- Captured stderr teardown --------------------------------------------------------------------------------
[I 2024-05-06 10:53:20.712 ServerApp] Shutting down on /api/shutdown request.
[I 2024-05-06 10:53:20.712 ServerApp] Shutting down 3 extensions
[I 2024-05-06 10:53:20.713 ServerApp] Shutting down 1 kernel
[I 2024-05-06 10:53:20.713 ServerApp] Kernel shutdown: f0103368-8c69-4090-a2b0-3377af689190
[I 2024-05-06 10:53:20.725 ServerApp] Starting buffering for f0103368-8c69-4090-a2b0-3377af689190:87253ff7730f4e50a1aa3cb2f204bafe
[I 2024-05-06 10:53:20.726 ServerApp] Kernel shutdown: f0103368-8c69-4090-a2b0-3377af689190

---------- coverage: platform darwin, python 3.8.19-final-0 ----------
Name                                                       Stmts   Miss  Cover
------------------------------------------------------------------------------
nbclassic/__init__.py                                         32      9    72%
nbclassic/__main__.py                                          3      0   100%
nbclassic/_sysinfo.py                                         32     32     0%
nbclassic/_version.py                                          8      0   100%
nbclassic/bundler/__init__.py                                  0      0   100%
nbclassic/bundler/__main__.py                                  3      3     0%
nbclassic/bundler/bundlerextensions.py                        98     98     0%
nbclassic/bundler/handlers.py                                 44     44     0%
nbclassic/bundler/tarball_bundler.py                          19     19     0%
nbclassic/bundler/tests/__init__.py                            0      0   100%
nbclassic/bundler/tests/test_bundler_api.py                   46     46     0%
nbclassic/bundler/tests/test_bundler_tools.py                 63     63     0%
nbclassic/bundler/tests/test_bundlerextension.py              44     44     0%
nbclassic/bundler/tools.py                                   101    101     0%
nbclassic/bundler/zip_bundler.py                              23     23     0%
nbclassic/config_manager.py                                   68     68     0%
nbclassic/edit/__init__.py                                     0      0   100%
nbclassic/edit/handlers.py                                    17      6    65%
nbclassic/extensions.py                                       44     44     0%
nbclassic/i18n/__init__.py                                    57     57     0%
nbclassic/jstest.py                                          366    366     0%
nbclassic/nbextensions.py                                    411    411     0%
nbclassic/notebook/__init__.py                                 0      0   100%
nbclassic/notebook/handlers.py                                50      8    84%
nbclassic/notebookapp.py                                     103      6    94%
nbclassic/serverextensions.py                                120    120     0%
nbclassic/shim.py                                              2      2     0%
nbclassic/shim_notebook.py                                    29     29     0%
nbclassic/terminal/__init__.py                                 0      0   100%
nbclassic/terminal/handlers.py                                10      3    70%
nbclassic/tests/__init__.py                                    0      0   100%
nbclassic/tests/end_to_end/__init__.py                         0      0   100%
nbclassic/tests/end_to_end/conftest.py                        88     20    77%
nbclassic/tests/end_to_end/manual_test_prototyper.py           1      0   100%
nbclassic/tests/end_to_end/test_buffering.py                  23      0   100%
nbclassic/tests/end_to_end/test_clipboard_multiselect.py      18      0   100%
nbclassic/tests/end_to_end/test_dashboard_nav.py              63      0   100%
nbclassic/tests/end_to_end/test_deletecell.py                 38      2    95%
nbclassic/tests/end_to_end/test_display_image.py              33      0   100%
nbclassic/tests/end_to_end/test_display_isolation.py          45      0   100%
nbclassic/tests/end_to_end/test_dualmode_arrows.py            71      0   100%
nbclassic/tests/end_to_end/test_dualmode_cellmode.py          41      0   100%
nbclassic/tests/end_to_end/test_dualmode_clipboard.py         42      0   100%
nbclassic/tests/end_to_end/test_dualmode_execute.py           45      0   100%
nbclassic/tests/end_to_end/test_dualmode_insertcell.py        37      0   100%
nbclassic/tests/end_to_end/test_dualmode_markdown.py          36      0   100%
nbclassic/tests/end_to_end/test_execute_code.py               44      0   100%
nbclassic/tests/end_to_end/test_find_and_replace.py            8      0   100%
nbclassic/tests/end_to_end/test_interrupt.py                  18      0   100%
nbclassic/tests/end_to_end/test_kernel_menu.py                28      1    96%
nbclassic/tests/end_to_end/test_markdown.py                   15      0   100%
nbclassic/tests/end_to_end/test_merge_cells.py                18      0   100%
nbclassic/tests/end_to_end/test_move_multiselection.py        20      0   100%
nbclassic/tests/end_to_end/test_multiselect.py                37      0   100%
nbclassic/tests/end_to_end/test_multiselect_toggle.py         28      0   100%
nbclassic/tests/end_to_end/test_notifications.py              37      0   100%
nbclassic/tests/end_to_end/test_prompt_numbers.py             17      0   100%
nbclassic/tests/end_to_end/test_save.py                       45      1    98%
nbclassic/tests/end_to_end/test_save_as_notebook.py           68      8    88%
nbclassic/tests/end_to_end/test_save_readonly_as.py           89     77    13%
nbclassic/tests/end_to_end/test_shutdown.py                    9      0   100%
nbclassic/tests/end_to_end/test_trust.py                      18      2    89%
nbclassic/tests/end_to_end/test_undelete.py                   62      0   100%
nbclassic/tests/end_to_end/utils.py                          556    169    70%
nbclassic/tests/launchnotebook.py                            161    161     0%
nbclassic/traits.py                                            1      1     0%
nbclassic/transutils.py                                        5      5     0%
nbclassic/tree/__init__.py                                     0      0   100%
nbclassic/tree/handlers.py                                    50     15    70%
------------------------------------------------------------------------------
TOTAL                                                       3708   2064    44%

================================================================================ short test summary info =================================================================================
FAILED nbclassic/tests/end_to_end/test_trust.py::test_trust - AssertionError: assert 'Not Trusted' == 'Trusted'
  
  - Trusted
  + Not Trusted
  ? ++++
================================================================== 1 failed, 30 passed, 1 skipped in 159.04s (0:02:39) ===================================================================

@maartenbreddels
Copy link
Contributor Author

Hi @RRosio

thank you for taking a look at this PR so thoroughly. Did you rebuild the JavaScript? A npm run build should be enough I think.

The test results you are looking at only runs the tests from the tests directory, it does not run the playwright/browser tests. If you look at for instance:
https://github.com/jupyter/nbclassic/actions/runs/8853167617/job/24313402768?pr=275
You will see

PASSED nbclassic/tests/end_to_end/test_trust.py::test_trust

Showing the test ran and passed.

I hope this clarifies things. If not, I'm happy to assist further.

Regards,

Maarten

@RRosio
Copy link
Collaborator

RRosio commented May 8, 2024

Hi @maartenbreddels thank you for your reply and clarification! I completely forgot to rebuild the JS assets after checking out the branch! I did notice the Playwright Tests were actually running afterward but I was stuck on the local test failing.

I've tried it out and it works great thank you!!

@RRosio RRosio merged commit 9913614 into jupyter:main May 8, 2024
32 of 33 checks passed
@jph00
Copy link

jph00 commented May 11, 2024

@RRosio thank you so much for merging this PR -- it fixes a bug that's been driving us crazy for over a year, so it's really marvellous to have it available. :D

@JasonWeill
Copy link

@RRosio Thank you so much for merging this! Are you able to cut a new release containing this fix? Looks like there hasn't been an official nbclassic release since 1.0.0, which was released just over a year ago.

@maartenbreddels
Copy link
Contributor Author

Hi @RRosio, if I can help with anything related to making a release, please let me know. I'd love to see this high-friction fix released.

@RRosio
Copy link
Collaborator

RRosio commented May 24, 2024

Thank you for the feedback @jph00!
There was one other PR I was hoping to get in for the next release but I am not entirely confident that the CI test failures are not related to the changes introduced by the PR.
I will work on a release for this! (cc @maartenbreddels @JasonWeill)

@jph00
Copy link

jph00 commented May 24, 2024

Thank you for the feedback @jph00! There was one other PR I was hoping to get in for the next release but I am not entirely confident that the CI test failures are not related to the changes introduced by the PR. I will work on a release for this! (cc @maartenbreddels @JasonWeill)

Let me know if we can help at all with testing of the other PR and/or looking into CI failures.

@RRosio
Copy link
Collaborator

RRosio commented May 24, 2024

Let me know if we can help at all with testing of the other PR and/or looking into CI failures.

Thank you! I am taking a look at the test_save_as_notebook.py in #277 and I am seeing more frequent failures in test_display_isolation.pytoo!

@RRosio
Copy link
Collaborator

RRosio commented May 24, 2024

The release is available now https://github.com/jupyter/nbclassic/releases/tag/v1.1.0! Please let me know if there is anything I missed or any issues!

I will continue looking at the CI as well!

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.

4 participants