diff -Nru jupyter-notebook-6.1.4/appveyor.yml jupyter-notebook-6.2.0/appveyor.yml
--- jupyter-notebook-6.1.4/appveyor.yml 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/appveyor.yml 2021-01-13 16:30:49.000000000 +0000
@@ -21,7 +21,7 @@
- cmd: conda config --set show_channel_urls true
- cmd: conda config --add channels conda-forge
#- cmd: conda update --yes --quiet conda
- - cmd: conda install -y python=%CONDA_PY_SPEC% pyzmq tornado jupyter_client nbformat ipykernel pip nodejs nose
+ - cmd: conda install -y python=%CONDA_PY_SPEC% pyzmq tornado jupyter_client nbformat ipykernel pip nodejs pytest nose
# not using `conda install -y` on nbconvent package because there is
# currently a bug with the version that the anaconda installs, so we will just install it with pip
- cmd: pip install nbconvert
@@ -29,4 +29,4 @@
- cmd: pip install .[test]
test_script:
- - nosetests -v notebook --exclude-dir notebook\tests\selenium
+ - py.test -v notebook --ignore notebook\tests\selenium
diff -Nru jupyter-notebook-6.1.4/CONTRIBUTING.rst jupyter-notebook-6.2.0/CONTRIBUTING.rst
--- jupyter-notebook-6.1.4/CONTRIBUTING.rst 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/CONTRIBUTING.rst 2021-01-13 16:30:49.000000000 +0000
@@ -171,19 +171,17 @@
To build the documentation you'll need `Sphinx `_,
`pandoc `_ and a few other packages.
-To install (and activate) a `conda environment`_ named ``notebook_docs``
+To install (and activate) a conda environment named ``notebook_docs``
containing all the necessary packages (except pandoc), use::
- conda env create -f docs/environment.yml
+ conda create -n notebook_docs pip
conda activate notebook_docs # Linux and OS X
- activate notebook_docs # Windows
-
-.. _conda environment:
- https://conda.io/docs/user-guide/tasks/manage-environments.html#creating-an-environment-from-an-environment-yml-file
+ activate notebook_docs # Windows
+ pip install .[docs]
If you want to install the necessary packages with ``pip``, use the following instead::
- pip install -r docs/doc-requirements.txt
+ pip install .[docs]
Once you have installed the required packages, you can build the docs with::
diff -Nru jupyter-notebook-6.1.4/debian/changelog jupyter-notebook-6.2.0/debian/changelog
--- jupyter-notebook-6.1.4/debian/changelog 2020-09-18 14:20:36.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/changelog 2021-01-17 19:52:42.000000000 +0000
@@ -1,9 +1,45 @@
-jupyter-notebook (6.1.4-1~ppa20.10~1) groovy; urgency=medium
+jupyter-notebook (6.2.0-1~ppa20.10~1) groovy; urgency=medium
- * New upstream version 6.1.4
+ * New upstream version 6.2.0
+ * Version dependencies on tornado, send2trash
+ * Disable all tests of notebook trashing; these are too sensitive to
+ different mount and container layouts to be useful.
* PPA snapshot for 20.10
- -- Gordon Ball Fri, 18 Sep 2020 16:20:36 +0200
+ -- Gordon Ball Sun, 17 Jan 2021 20:52:42 +0100
+
+jupyter-notebook (6.1.6-2) unstable; urgency=medium
+
+ * Use uglifyjs instead of node-uglify (Closes: #979898)
+
+ -- Gordon Ball Tue, 12 Jan 2021 18:52:17 +0000
+
+jupyter-notebook (6.1.6-1) unstable; urgency=medium
+
+ * New upstream version 6.1.6
+ * Run tests using pytest instead of nose, as upstream
+
+ -- Gordon Ball Sat, 26 Dec 2020 20:18:26 +0000
+
+jupyter-notebook (6.1.5-1) unstable; urgency=medium
+
+ * New upstream version 6.1.5
+
+ -- Gordon Ball Sat, 07 Nov 2020 21:07:30 +0000
+
+jupyter-notebook (6.1.4-1) unstable; urgency=medium
+
+ [ Gordon Ball ]
+ * New upstream version 6.1.4
+ * Mark the symlink autopkgtest as superficial
+
+ [ Ondřej Nový ]
+ * d/control: Update Maintainer field with new Debian Python Team
+ contact address.
+ * d/control: Update Vcs-* fields with new Debian Python Team Salsa
+ layout.
+
+ -- Gordon Ball Thu, 24 Sep 2020 19:06:44 +0000
jupyter-notebook (6.1.3-1) unstable; urgency=medium
diff -Nru jupyter-notebook-6.1.4/debian/control jupyter-notebook-6.2.0/debian/control
--- jupyter-notebook-6.1.4/debian/control 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/control 2021-01-15 15:03:16.000000000 +0000
@@ -1,32 +1,32 @@
Source: jupyter-notebook
-Maintainer: Debian Python Modules Team
+Maintainer: Debian Python Team
Uploaders: Gordon Ball , Jerome Benoit
Section: python
Priority: optional
Standards-Version: 4.5.0
Homepage: https://github.com/jupyter/notebook
-Vcs-Git: https://salsa.debian.org/python-team/modules/jupyter-notebook.git
-Vcs-Browser: https://salsa.debian.org/python-team/modules/jupyter-notebook
+Vcs-Git: https://salsa.debian.org/python-team/packages/jupyter-notebook.git
+Vcs-Browser: https://salsa.debian.org/python-team/packages/jupyter-notebook
Build-Depends: debhelper-compat (= 13),
dh-python,
python3-all,
python3-setuptools,
python3-argon2,
python3-nose ,
- python3-nose-exclude ,
python3-requests ,
python3-requests-unixsocket ,
python3-ipython ,
python3-jupyter-core (>= 4.6.1) ,
python3-jupyter-client (>= 5.3.4) ,
- python3-tornado ,
+ python3-tornado (>= 6.1) ,
python3-nbformat (>= 4.4) ,
python3-nbconvert (>= 5) ,
python3-ipykernel ,
python3-prometheus-client ,
+ python3-pytest ,
python3-terminado (>= 0.8.3) ,
python3-entrypoints ,
- python3-send2trash ,
+ python3-send2trash (>= 1.5) ,
python3-zmq ,
python3-sphinx ,
python3-sphinx-rtd-theme ,
@@ -54,11 +54,11 @@
node-source-map,
node-requirejs (>= 2.3),
node-react (>= 16.13),
- node-uglify,
node-po2json,
node-fbjs,
node-loose-envify,
node-object-assign,
+ uglifyjs,
webpack,
pandoc
Testsuite: autopkgtest-pkg-python
diff -Nru jupyter-notebook-6.1.4/debian/patches/0002-Use-local-MathJax-in-documentation.patch jupyter-notebook-6.2.0/debian/patches/0002-Use-local-MathJax-in-documentation.patch
--- jupyter-notebook-6.1.4/debian/patches/0002-Use-local-MathJax-in-documentation.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0002-Use-local-MathJax-in-documentation.patch 2021-01-15 15:03:16.000000000 +0000
@@ -7,10 +7,10 @@
1 file changed, 2 insertions(+)
diff --git a/docs/source/conf.py b/docs/source/conf.py
-index 7e924f0..ed9e491 100644
+index 6987abb..a649138 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
-@@ -348,6 +348,8 @@ intersphinx_mapping = {
+@@ -347,6 +347,8 @@ intersphinx_mapping = {
'jupyter': ('https://jupyter.readthedocs.io/en/latest/', None),
}
diff -Nru jupyter-notebook-6.1.4/debian/patches/0004-Call-lessc-with-source-map-basepath-option-for-repro.patch jupyter-notebook-6.2.0/debian/patches/0004-Call-lessc-with-source-map-basepath-option-for-repro.patch
--- jupyter-notebook-6.1.4/debian/patches/0004-Call-lessc-with-source-map-basepath-option-for-repro.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0004-Call-lessc-with-source-map-basepath-option-for-repro.patch 2021-01-15 15:03:16.000000000 +0000
@@ -7,10 +7,10 @@
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setupbase.py b/setupbase.py
-index c9454ee..7eeb243 100644
+index 40c3f35..0a85d82 100644
--- a/setupbase.py
+++ b/setupbase.py
-@@ -477,7 +477,7 @@ class CompileCSS(Command):
+@@ -474,7 +474,7 @@ class CompileCSS(Command):
for src, dst in zip(self.sources, self.targets):
try:
run(['lessc',
diff -Nru jupyter-notebook-6.1.4/debian/patches/0005-Work-around-https-github.com-less-less.js-pull-3002.patch jupyter-notebook-6.2.0/debian/patches/0005-Work-around-https-github.com-less-less.js-pull-3002.patch
--- jupyter-notebook-6.1.4/debian/patches/0005-Work-around-https-github.com-less-less.js-pull-3002.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0005-Work-around-https-github.com-less-less.js-pull-3002.patch 2021-01-15 15:03:16.000000000 +0000
@@ -7,10 +7,10 @@
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setupbase.py b/setupbase.py
-index 7eeb243..28dec37 100644
+index 0a85d82..3a72f78 100644
--- a/setupbase.py
+++ b/setupbase.py
-@@ -480,7 +480,7 @@ class CompileCSS(Command):
+@@ -477,7 +477,7 @@ class CompileCSS(Command):
'--source-map', '--source-map-basepath='+os.path.dirname(__file__),
'--include-path=%s' % pipes.quote(static),
src,
diff -Nru jupyter-notebook-6.1.4/debian/patches/0006-Debian-specific-hack-to-fix-upstream-s-non-increment.patch jupyter-notebook-6.2.0/debian/patches/0006-Debian-specific-hack-to-fix-upstream-s-non-increment.patch
--- jupyter-notebook-6.1.4/debian/patches/0006-Debian-specific-hack-to-fix-upstream-s-non-increment.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0006-Debian-specific-hack-to-fix-upstream-s-non-increment.patch 2021-01-15 15:03:16.000000000 +0000
@@ -7,7 +7,7 @@
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/setup.py b/setup.py
-index de6ab7a..95626b2 100755
+index 676c576..c30235d 100755
--- a/setup.py
+++ b/setup.py
@@ -147,18 +147,21 @@ class bdist_egg_disabled(bdist_egg):
diff -Nru jupyter-notebook-6.1.4/debian/patches/0007-Ignore-errors-in-documentation-notebooks-during-buil.patch jupyter-notebook-6.2.0/debian/patches/0007-Ignore-errors-in-documentation-notebooks-during-buil.patch
--- jupyter-notebook-6.1.4/debian/patches/0007-Ignore-errors-in-documentation-notebooks-during-buil.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0007-Ignore-errors-in-documentation-notebooks-during-buil.patch 2021-01-15 15:03:16.000000000 +0000
@@ -7,10 +7,10 @@
1 file changed, 1 insertion(+)
diff --git a/docs/source/conf.py b/docs/source/conf.py
-index ed9e491..ee2671d 100644
+index a649138..f08e073 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
-@@ -355,3 +355,4 @@ spelling_word_list_filename='spelling_wordlist.txt'
+@@ -354,3 +354,4 @@ spelling_word_list_filename='spelling_wordlist.txt'
# import before any doc is built, so _ is guaranteed to be injected
import notebook.transutils
diff -Nru jupyter-notebook-6.1.4/debian/patches/0009-Don-t-try-and-patch-bootstrap-less.patch jupyter-notebook-6.2.0/debian/patches/0009-Don-t-try-and-patch-bootstrap-less.patch
--- jupyter-notebook-6.1.4/debian/patches/0009-Don-t-try-and-patch-bootstrap-less.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0009-Don-t-try-and-patch-bootstrap-less.patch 2021-01-15 15:03:16.000000000 +0000
@@ -12,10 +12,10 @@
1 file changed, 2 deletions(-)
diff --git a/setupbase.py b/setupbase.py
-index 28dec37..d81c1d1 100644
+index 3a72f78..436991c 100644
--- a/setupbase.py
+++ b/setupbase.py
-@@ -472,8 +472,6 @@ class CompileCSS(Command):
+@@ -469,8 +469,6 @@ class CompileCSS(Command):
env = os.environ.copy()
env['PATH'] = npm_path
diff -Nru jupyter-notebook-6.1.4/debian/patches/0011-use-system-po2json.patch jupyter-notebook-6.2.0/debian/patches/0011-use-system-po2json.patch
--- jupyter-notebook-6.1.4/debian/patches/0011-use-system-po2json.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0011-use-system-po2json.patch 2021-01-15 15:03:16.000000000 +0000
@@ -7,10 +7,10 @@
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setupbase.py b/setupbase.py
-index 5a21cb5..c9454ee 100644
+index fb3327d..40c3f35 100644
--- a/setupbase.py
+++ b/setupbase.py
-@@ -553,7 +553,7 @@ class CompileJS(Command):
+@@ -550,7 +550,7 @@ class CompileJS(Command):
def build_jstranslation(self, trd):
lang = trd[-5:]
run([
diff -Nru jupyter-notebook-6.1.4/debian/patches/0012-Skip-all-send2trash-tests.patch jupyter-notebook-6.2.0/debian/patches/0012-Skip-all-send2trash-tests.patch
--- jupyter-notebook-6.1.4/debian/patches/0012-Skip-all-send2trash-tests.patch 1970-01-01 00:00:00.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0012-Skip-all-send2trash-tests.patch 2021-01-15 15:03:16.000000000 +0000
@@ -0,0 +1,92 @@
+From: Gordon Ball
+Date: Thu, 14 Jan 2021 15:56:57 +0000
+Subject: Skip all send2trash tests
+
+send2trash fails in various unpredictable ways in container
+environments, overlays and bind mounts. This leads to lots of issues
+with different build and CI environments.
+---
+ notebook/services/contents/tests/test_contents_api.py | 5 +++++
+ notebook/services/contents/tests/test_manager.py | 4 ++++
+ 2 files changed, 9 insertions(+)
+
+diff --git a/notebook/services/contents/tests/test_contents_api.py b/notebook/services/contents/tests/test_contents_api.py
+index 6e4ad49..7f0e01f 100644
+--- a/notebook/services/contents/tests/test_contents_api.py
++++ b/notebook/services/contents/tests/test_contents_api.py
+@@ -11,6 +11,7 @@ from unicodedata import normalize
+
+ pjoin = os.path.join
+
++import pytest
+ import requests
+ from send2trash import send2trash
+ from send2trash.exceptions import TrashPermissionError
+@@ -510,6 +511,7 @@ class APITest(NotebookTestBase):
+ with assert_http_error(400):
+ resp = self.api.copy(u'å b', u'foo')
+
++ @pytest.mark.skip("skip send2trash tests")
+ def test_delete(self):
+ for d, name in self.dirs_nbs:
+ print('%r, %r' % (d, name))
+@@ -523,6 +525,7 @@ class APITest(NotebookTestBase):
+ print(nbs)
+ self.assertEqual(nbs, [])
+
++ @pytest.mark.skip("skip send2trash tests")
+ def test_delete_dirs(self):
+ # depth-first delete everything, so we don't try to delete empty directories
+ for name in sorted(self.dirs + ['/'], key=len, reverse=True):
+@@ -532,6 +535,7 @@ class APITest(NotebookTestBase):
+ listing = self.api.list('/').json()['content']
+ self.assertEqual(listing, [])
+
++ @pytest.mark.skip("skip send2trash tests")
+ def test_delete_non_empty_dir(self):
+ if sys.platform == 'win32':
+ self.skipTest("Disabled deleting non-empty dirs on Windows")
+@@ -559,6 +563,7 @@ class APITest(NotebookTestBase):
+ self.assertIn('z.ipynb', nbnames)
+ self.assertNotIn('a.ipynb', nbnames)
+
++ @pytest.mark.skip("skip send2trash tests")
+ def test_checkpoints_follow_file(self):
+
+ # Read initial file state
+diff --git a/notebook/services/contents/tests/test_manager.py b/notebook/services/contents/tests/test_manager.py
+index dfe5d27..bb854eb 100644
+--- a/notebook/services/contents/tests/test_manager.py
++++ b/notebook/services/contents/tests/test_manager.py
+@@ -6,6 +6,7 @@ import time
+ from contextlib import contextmanager
+ from itertools import combinations
+
++import pytest
+ from tornado.web import HTTPError
+ from unittest import TestCase, skipIf
+ from tempfile import NamedTemporaryFile
+@@ -181,6 +182,7 @@ class TestFileContentsManager(TestCase):
+ else:
+ self.fail("Should have raised HTTPError(403)")
+
++ @pytest.mark.skip("skip send2trash tests")
+ def test_escape_root(self):
+ with TemporaryDirectory() as td:
+ cm = FileContentsManager(root_dir=td)
+@@ -506,6 +508,7 @@ class TestContentsManager(TestCase):
+ self.assertEqual(model['name'], 'Untitled.ipynb')
+ self.assertEqual(model['path'], 'foo/Untitled.ipynb')
+
++ @pytest.mark.skip("skip send2trash tests")
+ def test_delete(self):
+ cm = self.contents_manager
+ # Create a notebook
+@@ -574,6 +577,7 @@ class TestContentsManager(TestCase):
+ # Created a notebook in the renamed directory should work
+ cm.new_untitled("foo/bar_diff", ext=".ipynb")
+
++ @pytest.mark.skip("skip send2trash tests")
+ def test_delete_root(self):
+ cm = self.contents_manager
+ with self.assertRaises(HTTPError) as err:
diff -Nru jupyter-notebook-6.1.4/debian/patches/0013-Avoid-manipulating-PYTHONPATH-in-tests.patch jupyter-notebook-6.2.0/debian/patches/0013-Avoid-manipulating-PYTHONPATH-in-tests.patch
--- jupyter-notebook-6.1.4/debian/patches/0013-Avoid-manipulating-PYTHONPATH-in-tests.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0013-Avoid-manipulating-PYTHONPATH-in-tests.patch 2021-01-15 15:03:16.000000000 +0000
@@ -13,10 +13,10 @@
1 file changed, 2 deletions(-)
diff --git a/notebook/tests/launchnotebook.py b/notebook/tests/launchnotebook.py
-index 25ce8c8..b704c66 100644
+index bb5f8b7..cf43665 100644
--- a/notebook/tests/launchnotebook.py
+++ b/notebook/tests/launchnotebook.py
-@@ -97,9 +97,7 @@ class NotebookTestBase(TestCase):
+@@ -98,9 +98,7 @@ class NotebookTestBase(TestCase):
def get_patch_env(cls):
return {
'HOME': cls.home_dir,
diff -Nru jupyter-notebook-6.1.4/debian/patches/0013-documentation-fixes.patch jupyter-notebook-6.2.0/debian/patches/0013-documentation-fixes.patch
--- jupyter-notebook-6.1.4/debian/patches/0013-documentation-fixes.patch 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/0013-documentation-fixes.patch 2021-01-15 15:03:16.000000000 +0000
@@ -7,10 +7,10 @@
1 file changed, 2 deletions(-)
diff --git a/docs/source/conf.py b/docs/source/conf.py
-index ee2671d..6e8ae93 100644
+index f08e073..5a681ee 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
-@@ -68,9 +68,7 @@ extensions = [
+@@ -67,9 +67,7 @@ extensions = [
'sphinx.ext.intersphinx',
'sphinx.ext.autosummary',
'sphinx.ext.mathjax',
diff -Nru jupyter-notebook-6.1.4/debian/patches/series jupyter-notebook-6.2.0/debian/patches/series
--- jupyter-notebook-6.1.4/debian/patches/series 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/patches/series 2021-01-15 15:03:16.000000000 +0000
@@ -9,3 +9,4 @@
0013-documentation-fixes.patch
0013-Avoid-manipulating-PYTHONPATH-in-tests.patch
0011-Requirejs-shim-config-for-xterm-xterm-addon-fit.patch
+0012-Skip-all-send2trash-tests.patch
diff -Nru jupyter-notebook-6.1.4/debian/rules jupyter-notebook-6.2.0/debian/rules
--- jupyter-notebook-6.1.4/debian/rules 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/rules 2021-01-15 15:03:16.000000000 +0000
@@ -9,7 +9,7 @@
export LC_ALL=C.UTF-8
# selenium tests require extra dependencies
# test_notebookapp_integration tries to invoke jupyter-notebook which isn't in the PATH when this runs
-export PYBUILD_TEST_ARGS=--exclude-dir notebook/tests/selenium --exclude test_notebookapp_integration
+export PYBUILD_TEST_ARGS=--ignore=notebook/tests/selenium -k 'not notebookapp_integration'
%:
@@ -140,12 +140,6 @@
echo "js:Built-Using=$(BUILTUSING)" >> debian/python3-notebook.substvars
dh_gencontrol
-override_dh_auto_test:
- mkdir -p debian/runtime/home debian/runtime/tmpdir debian/runtime/xdg
- # send2trash deletion tests fail if the temporary notebook files
- # are on a different block device to the implicit trash directory in HOME
- TMPDIR=$(CURDIR)/debian/runtime/tmpdir XDG_RUNTIME_DIR=$(CURDIR)/debian/runtime/xdg HOME=$(CURDIR)/debian/runtime/home dh_auto_test
-
override_dh_installchangelogs:
dh_installchangelogs -k docs/source/changelog.rst
diff -Nru jupyter-notebook-6.1.4/debian/tests/control jupyter-notebook-6.2.0/debian/tests/control
--- jupyter-notebook-6.1.4/debian/tests/control 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/tests/control 2021-01-15 15:03:16.000000000 +0000
@@ -1,6 +1,7 @@
-Tests: nose
-Depends: @, python3-pytest, python3-nose, python3-nose-exclude, python3-requests, python3-requests-unixsocket
+Tests: pytest
+Depends: @, python3-pytest, python3-nose, python3-requests, python3-requests-unixsocket
Restrictions: allow-stderr
Test-Command: find /usr/lib/python3/dist-packages/notebook -xtype l >&2
Depends: @
+Restrictions: superficial
diff -Nru jupyter-notebook-6.1.4/debian/tests/nose jupyter-notebook-6.2.0/debian/tests/nose
--- jupyter-notebook-6.1.4/debian/tests/nose 2020-09-15 11:09:02.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/tests/nose 1970-01-01 00:00:00.000000000 +0000
@@ -1,19 +0,0 @@
-#!/bin/sh -e
-
-for d in tmp home/runtime home/data/trash; do
- mkdir -p $AUTOPKGTEST_TMP/$d
-done
-
-# try and ensure files are on the same device, since otherwise
-# deletion-related tests fail attempting a cross-device rename
-# by default, debci seems to place /tmp and $AUTOPKGTEST_TMP on
-# different devices
-export HOME=$AUTOPKGTEST_TMP/home
-export XDG_RUNTIME_DIR=$AUTOPKGTEST_TMP/home/runtime
-export XDG_DATA_HOME=$AUTOPKGTEST_TMP/home/data
-export TMPDIR=$AUTOPKGTEST_TMP/tmp
-export NOSE_IGNORE_CONFIG_FILES=1
-
-chmod 0700 $XDG_RUNTIME_DIR
-
-nosetests3 --exclude-dir notebook/tests/selenium
diff -Nru jupyter-notebook-6.1.4/debian/tests/pytest jupyter-notebook-6.2.0/debian/tests/pytest
--- jupyter-notebook-6.1.4/debian/tests/pytest 1970-01-01 00:00:00.000000000 +0000
+++ jupyter-notebook-6.2.0/debian/tests/pytest 2021-01-15 15:03:16.000000000 +0000
@@ -0,0 +1,7 @@
+#!/bin/sh -e
+
+export XDG_RUNTIME_DIR=$AUTOPKGTEST_TMP/runtime
+mkdir -p $XDG_RUNTIME_DIR
+chmod 0700 $XDG_RUNTIME_DIR
+
+python3 -m pytest --ignore=notebook/tests/selenium
diff -Nru jupyter-notebook-6.1.4/docs/source/changelog.rst jupyter-notebook-6.2.0/docs/source/changelog.rst
--- jupyter-notebook-6.1.4/docs/source/changelog.rst 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/docs/source/changelog.rst 2021-01-13 16:30:49.000000000 +0000
@@ -22,6 +22,59 @@
``pip --version``.
+
+.. _release-6.2.0:
+
+6.2.0
+-----
+
+Merged PRs
+~~~~~~~~~~
+
+- Increase minimum tornado version (:ghpull:`5933`)
+- Adjust skip decorators to avoid remaining dependency on nose (:ghpull:`5932`)
+- Ensure that cell ids persist after save (:ghpull:`5928`)
+- Add reconnection to Gateway (form nb2kg) (:ghpull:`5924`)
+- Fix some typos (:ghpull:`5917`)
+- Handle TrashPermissionError, now that it exists (:ghpull:`5894`)
+
+Thank you to all the contributors:
+
+- @kevin-bates
+- @mishaschwartz
+- @oyvsyo
+- @user202729
+- @stefanor
+
+.. _release-6.1.6:
+
+6.1.6
+-----
+
+Merged PRs
+~~~~~~~~~~
+
+* do not require nose for testing (:ghpull:`5826`)
+* [docs] Update Chinese and Hindi readme.md (:ghpull:`5823`)
+* Add support for creating terminals via GET (:ghpull:`5813`)
+* Made doc translations in Hindi and Chinese (:ghpull:`5787`)
+
+Thank you to all the contributors:
+
+- @pgajdos
+- @rjn01
+- @kevin-bates
+- @virejdasani
+
+.. _release-6.1.5:
+
+6.1.5
+-----
+
+6.1.5 is a security release, fixing one vulnerability:
+
+- Fix open redirect vulnerability GHSA-c7vm-f5p4-8fqh (CVE to be assigned)
+
.. _release-6.1.4:
6.1.4
diff -Nru jupyter-notebook-6.1.4/docs/source/config_overview.rst jupyter-notebook-6.2.0/docs/source/config_overview.rst
--- jupyter-notebook-6.1.4/docs/source/config_overview.rst 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/docs/source/config_overview.rst 2021-01-13 16:30:49.000000000 +0000
@@ -54,12 +54,11 @@
Notebook front-end client
-------------------------
-- :ref:`How front-end configuration works `
- * :ref:`Example: Changing the notebook's default indentation setting
- `
- * :ref:`Example: Restoring the notebook's default indentation setting
- `
-- :ref:`Persisting configuration settings `
+
+.. toctree::
+ :maxdepth: 2
+
+ frontend_config
.. _configure_nbextensions:
diff -Nru jupyter-notebook-6.1.4/docs/source/conf.py jupyter-notebook-6.2.0/docs/source/conf.py
--- jupyter-notebook-6.1.4/docs/source/conf.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/docs/source/conf.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
#
# Jupyter Notebook documentation build configuration file, created by
# sphinx-quickstart on Mon Apr 13 09:51:11 2015.
diff -Nru "/tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs/source/examples/Notebook/What is the Jupyter Notebook.ipynb" "/tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs/source/examples/Notebook/What is the Jupyter Notebook.ipynb"
--- "/tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs/source/examples/Notebook/What is the Jupyter Notebook.ipynb" 2020-09-08 17:47:36.000000000 +0000
+++ "/tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs/source/examples/Notebook/What is the Jupyter Notebook.ipynb" 2021-01-13 16:30:49.000000000 +0000
@@ -135,7 +135,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "When you run the notebook web application on your computer, notebook documents are just **files on your local filesystem with a `.ipynb` extension**. This allows you to use familiar workflows for organizing your notebooks into folders and sharing them with others."
+ "When you run the notebook web application on your computer, notebook documents are just **files on your local filesystem with a** `.ipynb` **extension**. This allows you to use familiar workflows for organizing your notebooks into folders and sharing them with others."
]
},
{
@@ -148,7 +148,7 @@
"* **Markdown cells:** Narrative text with embedded LaTeX equations\n",
"* **Raw cells:** Unformatted text that is included, without modification, when notebooks are converted to different formats using nbconvert\n",
"\n",
- "Internally, notebook documents are **[JSON](https://en.wikipedia.org/wiki/JSON) data** with **binary values [base64](https://en.wikipedia.org/wiki/Base64)** encoded. This allows them to be **read and manipulated programmatically** by any programming language. Because JSON is a text format, notebook documents are version control friendly.\n",
+ "Internally, notebook documents are [JSON](https://en.wikipedia.org/wiki/JSON) **data** with **binary values** [base64](https://en.wikipedia.org/wiki/Base64) encoded. This allows them to be **read and manipulated programmatically** by any programming language. Because JSON is a text format, notebook documents are version control friendly.\n",
"\n",
"**Notebooks can be exported** to different static formats including HTML, reStructeredText, LaTeX, PDF, and slide shows ([reveal.js](https://revealjs.com)) using Jupyter's `nbconvert` utility.\n",
"\n",
diff -Nru "/tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs/source/examples/Notebook/Working With Markdown Cells.ipynb" "/tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs/source/examples/Notebook/Working With Markdown Cells.ipynb"
--- "/tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs/source/examples/Notebook/Working With Markdown Cells.ipynb" 2020-09-08 17:47:36.000000000 +0000
+++ "/tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs/source/examples/Notebook/Working With Markdown Cells.ipynb" 2021-01-13 16:30:49.000000000 +0000
@@ -175,7 +175,9 @@
"Courtesy of MathJax, you can include mathematical expressions both inline: \n",
"$e^{i\\pi} + 1 = 0$ and displayed:\n",
"\n",
- "$$e^x=\\sum_{i=0}^\\infty \\frac{1}{i!}x^i$$\n",
+ "\\begin{equation}\n",
+ "e^x=\\sum_{i=0}^\\infty \\frac{1}{i!}x^i\n",
+ "\\end{equation}\n",
"\n",
"Inline expressions can be added by surrounding the latex code with `$`:\n",
"\n",
@@ -183,10 +185,12 @@
"$e^{i\\pi} + 1 = 0$\n",
"```\n",
"\n",
- "Expressions on their own line are surrounded by `$$`:\n",
+ "Expressions on their own line are surrounded by `\\begin{equation}` and `\\end{equation}`:\n",
"\n",
"```latex\n",
- "$$e^x=\\sum_{i=0}^\\infty \\frac{1}{i!}x^i$$\n",
+ "\\begin{equation}\n",
+ "e^x=\\sum_{i=0}^\\infty \\frac{1}{i!}x^i\n",
+ "\\end{equation}\n",
"```"
]
},
diff -Nru jupyter-notebook-6.1.4/docs/source/frontend_config.rst jupyter-notebook-6.2.0/docs/source/frontend_config.rst
--- jupyter-notebook-6.1.4/docs/source/frontend_config.rst 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/docs/source/frontend_config.rst 2021-01-13 16:30:49.000000000 +0000
@@ -48,6 +48,18 @@
`_ which are available
for configuration.
+You can similarly change the options of the file editor by entering the following
+snippet in the browser's Javascript console once (from a file editing page).::
+
+ var config = Jupyter.editor.config
+ var patch = {
+ Editor: {
+ codemirror_options: {
+ indentUnit: 2
+ }
+ }
+ }
+ config.update(patch)
Example - Restoring the notebook's default indentation
------------------------------------------------------
diff -Nru jupyter-notebook-6.1.4/docs-translations/hi-IN/README.md jupyter-notebook-6.2.0/docs-translations/hi-IN/README.md
--- jupyter-notebook-6.1.4/docs-translations/hi-IN/README.md 1970-01-01 00:00:00.000000000 +0000
+++ jupyter-notebook-6.2.0/docs-translations/hi-IN/README.md 2021-01-13 16:30:49.000000000 +0000
@@ -0,0 +1,77 @@
+# Jupyter Notebook
+
+[![Google Group](https://img.shields.io/badge/-Google%20Group-lightgrey.svg)](https://groups.google.com/forum/#!forum/jupyter)
+[![Build Status](https://travis-ci.org/jupyter/notebook.svg?branch=master)](https://travis-ci.org/jupyter/notebook)
+[![Documentation Status](https://readthedocs.org/projects/jupyter-notebook/badge/?version=latest)](https://jupyter-notebook.readthedocs.io/en/latest/?badge=latest)
+
+
+
+Jupyter नोटबुक इंटरैक्टिव के लिए एक वेब-आधारित नोटबुक वातावरण है
+कंप्यूटिंग।
+
+![Jupyter notebook example](docs/resources/running_code_med.png "Jupyter notebook example")
+
+### नोटिस
+कृपया ध्यान दें कि इस भंडार का रखरखाव वर्तमान में जुपिटर समुदाय के एक कंकाल के दल द्वारा किया जाता है। हम उपयोगकर्ताओं को जुपिटरलैब में संक्रमण के लिए प्रोत्साहित करते हैं, जहां अधिक तत्काल समर्थन हो सकता है। हमारा दृष्टिकोण आगे बढ़ेगा:
+
+1. जुपिटर नोटबुक की सुरक्षा बनाए रखने के लिए। इसका मतलब है कि सुरक्षा से संबंधित मुद्दे और पुल अनुरोध हमारी सर्वोच्च प्राथमिकता है।
+2. JupyterLab को संबोधित करने के लिए [समता मुद्दों की सुविधा](https://github.com/jupyterlab/jupyterlab/issues?q=is%3Aopen+is%3Aissue+label%3A%22tag%3AFeature+Parity%22)| इस प्रयास के हिस्से के रूप में, हम एक बेहतर [नोटबुक-ओनली एक्सपीरियंस](https://github.com/jupyterlab/jupyterlab/issues/8450)JupyterLab में उन उपयोगकर्ताओं के लिए जो क्लासिक Jupyter नोटबुक के UI को पसंद करते हैं।
+3. समुदाय के सदस्यों की कड़ी मेहनत के प्रति उत्तरदायी होना जिन्होंने पुल अनुरोधों को खोला है। हम इन पीआर को ट्राई कर रहे हैं। हम इस समय नई सुविधाओं का समर्थन या रखरखाव नहीं कर सकते हैं, लेकिन हम सुरक्षा और अन्य स्थिरता सुधारों का स्वागत करते हैं।
+
+यदि आपके पास एक नई सुविधा के साथ एक खुला पुल अनुरोध है या यदि आप एक खोलने की योजना बना रहे हैं, तो कृपया इसे [नोटबुक एक्सटेंशन](https://jupyter-notebook.readthedocs.io/en/stable/extending/) के रूप में शिपिंग करने पर विचार करें। बजाय।
+
+##### `नोटबुक` में योगदान करने के लिए विकल्प
+इसके अतिरिक्त, कृपया विचार करें कि क्या आपका योगदान Jupyter फ्रंट-एंड के लिए अंतर्निहित सर्वर के लिए उपयुक्त होगा, [jupyter server](https://github.com/jupyter/jupyter_server) या में [JupyterLab फ़्रंट एंड](https://github.com/jupyterlab/jupyterlab).
+
+### जुपिटर नोटबुक, आइपीथॉन नोटबुक की भाषा-अज्ञेय विकास
+Jupyter नोटबुक एक भाषा-अज्ञेय HTML नोटबुक अनुप्रयोग है
+प्रोजेक्ट जुपिटर। 2015 में, जुपिटर नोटबुक के एक भाग के रूप में जारी किया गया था
+IPython कोडबेस का बिग स्प्लिट ™। IPython 3 अंतिम प्रमुख अखंड था
+दोनों भाषा-अज्ञेयवादी कोड, जैसे *IPython नोटबुक*,
+और भाषा विशिष्ट कोड, जैसे कि *अजगर के लिए आईपीथॉन कर्नेल*। जैसा
+कई भाषाओं में कंप्यूटिंग स्पैन, प्रोजेक्ट जुपिटर विकसित करना जारी रखेगा
+भाषा-अज्ञेय **जुपिटर नोटबुक** इस रेपो में और की मदद से
+समुदाय भाषा विशिष्ट गुठली विकसित करते हैं जो अपने आप में पाए जाते हैं
+असतत रेपो।
+[[Big Split™ घोषणा](https://blog.jupyter.org/the-big-split-9d7b88a031a7)]
+[[Jupyter आरोही ब्लॉग पोस्ट](https://blog.jupyter.org/jupyter-ascending-1bf5b362d97e)]
+
+## स्थापना
+आप के लिए स्थापना प्रलेखन पा सकते हैं
+[बृहस्पति मंच, ReadTheDocs पर](https://jupyter.readthedocs.io/en/latest/install.html).
+जुपिटर नोटबुक के उन्नत उपयोग के लिए दस्तावेज पाया जा सकता है
+[यहाँ](https://jupyter-notebook.readthedocs.io/en/latest/).
+
+स्थानीय स्थापना के लिए, सुनिश्चित करें कि आपके पास है
+[pip स्थापित](https://pip.readthedocs.io/en/stable/installing/) और भाग खड़ा हुआ:
+
+ $ pip install notebook
+
+## उपयोग - जुपिटर नोटबुक चल रहा है
+
+### स्थानीय स्थापना में चल रहा है
+
+इसके साथ लॉन्च करें:
+
+ $ jupyter notebook
+
+### एक दूरस्थ स्थापना में चल रहा है
+
+आपको बृहस्पति नोटबुक को दूरस्थ रूप से शुरू करने से पहले कुछ कॉन्फ़िगरेशन की आवश्यकता है। देखें [नोटबुक सर्वर चला रहा है](https://jupyter-notebook.readthedocs.io/en/stable/public_server.html).
+
+## विकास स्थापना
+
+स्थानीय विकास की स्थापना कैसे करें, इसके लिए [`CONTRIBUTING.rst`](CONTRIBUTING.rst) देखें।
+
+## योगदान
+
+यदि आप इस परियोजना में योगदान देने में रुचि रखते हैं, तो [`CONTRIBUTING.rst`](CONTRIBUTING.rst) देखें।
+
+## साधन
+- [Project Jupyter website](https://jupyter.org)
+- [Online Demo at jupyter.org/try](https://jupyter.org/try)
+- [Documentation for Jupyter notebook](https://jupyter-notebook.readthedocs.io/en/latest/) [[PDF](https://media.readthedocs.org/pdf/jupyter-notebook/latest/jupyter-notebook.pdf)]
+- [Korean Version of Installation](https://github.com/ChungJooHo/Jupyter_Kor_doc/)
+- [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html) [[PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)]
+- [Issues](https://github.com/jupyter/notebook/issues)
+- [Technical support - Jupyter Google Group](https://groups.google.com/forum/#!forum/jupyter)
\ No newline at end of file
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/hi-IN/resources/dashboard.GIF and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/hi-IN/resources/dashboard.GIF differ
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/hi-IN/resources/edit_mode.GIF and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/hi-IN/resources/edit_mode.GIF differ
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/hi-IN/resources/file_editor.GIF and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/hi-IN/resources/file_editor.GIF differ
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/hi-IN/resources/Notebook_Editor.GIF and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/hi-IN/resources/Notebook_Editor.GIF differ
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/hi-IN/resources/running_code_med.png and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/hi-IN/resources/running_code_med.png differ
diff -Nru jupyter-notebook-6.1.4/docs-translations/zh-CN/README.md jupyter-notebook-6.2.0/docs-translations/zh-CN/README.md
--- jupyter-notebook-6.1.4/docs-translations/zh-CN/README.md 1970-01-01 00:00:00.000000000 +0000
+++ jupyter-notebook-6.2.0/docs-translations/zh-CN/README.md 2021-01-13 16:30:49.000000000 +0000
@@ -0,0 +1,77 @@
+# Jupyter Notebook
+
+[![Google Group](https://img.shields.io/badge/-Google%20Group-lightgrey.svg)](https://groups.google.com/forum/#!forum/jupyter)
+[![Build Status](https://travis-ci.org/jupyter/notebook.svg?branch=master)](https://travis-ci.org/jupyter/notebook)
+[![Documentation Status](https://readthedocs.org/projects/jupyter-notebook/badge/?version=latest)](https://jupyter-notebook.readthedocs.io/en/latest/?badge=latest)
+
+
+
+Jupyter Notebook是用于交互的基于Web的笔记本环境
+计算。
+
+![Jupyter notebook example](docs/resources/running_code_med.png "Jupyter notebook example")
+
+### 注意
+请注意,这家商店目前由木星社区的骨干团队维护。我们鼓励用户过渡到 JupyterLab,那里可能会立即提供更多支持。我们的方法将向前发展:
+
+1.维护Jupiter笔记本电脑的安全性。这意味着与安全相关的问题和请求是我们的首要任务。
+2.解决JupyterLab [促进平等问题](https://github.com/jupyterlab/jupyterlab/issues?q=is%3Aopen+is%3Aissue+label%3A%22tag%3AFeature+Parity%22)|作为这项工作的一部分,我们有更好的[仅限笔记本电脑的体验](https://github.com/jupyterlab/jupyterlab/issues/8450)在JupyterLab中,适合喜欢经典Jupyter笔记本UI的用户。
+3.负责提出请求请求的社区成员的辛勤工作。我们正在尝试这些PR。我们目前无法支持或维护新设施,但是我们欢迎安全性和其他稳定性方面的改进。
+
+如果您有一个具有新功能的打开请求请求,或者您打算打开一个请求,请将该请求命名为[notebook extension](https://jupyter-notebook.readthedocs.io/en/stable/extending/) 考虑运送为。代替。
+
+##### 选择贡献“笔记本”
+此外,请考虑您的贡献是否适合Jupyter前端的基础服务器, [jupyter server](https://github.com/jupyter/jupyter_server) 或在 [JupyterLab 前端](https://github.com/jupyterlab/jupyterlab).
+
+### Jupyter笔记本,与IPython笔记本无关的语言开发
+Jupyter Notebook是与语言无关的HTML Notebook应用程序
+木星计划。 2015年,木星作为笔记本的一部分发布
+IPython代码库的Big Split™。 IPython 3是最后一个主要的整体
+两种与语言无关的代码,例如 *IPython notebook*,
+以及特定语言的代码,例如 *用于Python的IPython内核* 。如
+通过多种语言计算SPAN,Jupyter项目将继续发展
+与语言无关 **Jupyter Notebook** 在此仓库中更多帮助下
+社区开发自己发现的特定于语言的内核
+离散回购。
+[[Big Split™ 宣言](https://blog.jupyter.org/the-big-split-9d7b88a031a7)]
+[[Jupyter 升序博客文章](https://blog.jupyter.org/jupyter-ascending-1bf5b362d97e)]
+
+## 成立
+您可以找到以下安装文件
+[Jupiter论坛,在ReadTheDocs上](https://jupyter.readthedocs.io/en/latest/install.html).
+可以找到有关Jupiter笔记本的高级使用的文档
+[这里](https://jupyter-notebook.readthedocs.io/en/latest/).
+
+对于本地安装,请确保您已经
+[pip 成立时间](https://pip.readthedocs.io/en/stable/installing/) 并运行:
+
+ $ pip install notebook
+
+## 用法-运行木星笔记本
+
+### 在本地安装中运行
+
+与启动
+
+ $ jupyter笔记本
+
+### 在远程安装中运行
+
+在远程启动Jupiter笔记本电脑之前,需要进行一些配置。请参阅 [运行笔记本服务器](https://jupyter-notebook.readthedocs.io/en/stable/public_server.html).
+
+## 开发设置
+
+有关如何建立本地发展 [`CONTRIBUTING.rst`](CONTRIBUTING.rst) 看到。
+
+## 贡献
+
+如果您有兴趣为这个项目做贡献,请参阅 [`CONTRIBUTING.rst`](CONTRIBUTING.rst).
+
+## 资源
+- [Project Jupyter website](https://jupyter.org)
+- [Online Demo at jupyter.org/try](https://jupyter.org/try)
+- [Documentation for Jupyter notebook](https://jupyter-notebook.readthedocs.io/en/latest/) [[PDF](https://media.readthedocs.org/pdf/jupyter-notebook/latest/jupyter-notebook.pdf)]
+- [Korean Version of Installation](https://github.com/ChungJooHo/Jupyter_Kor_doc/)
+- [Documentation for Project Jupyter](https://jupyter.readthedocs.io/en/latest/index.html) [[PDF](https://media.readthedocs.org/pdf/jupyter/latest/jupyter.pdf)]
+- [Issues](https://github.com/jupyter/notebook/issues)
+- [Technical support - Jupyter Google Group](https://groups.google.com/forum/#!forum/jupyter)
\ No newline at end of file
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/zh-CN/resources/dashboard.GIF and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/zh-CN/resources/dashboard.GIF differ
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/zh-CN/resources/edit_mode.GIF and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/zh-CN/resources/edit_mode.GIF differ
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/zh-CN/resources/file_editor.GIF and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/zh-CN/resources/file_editor.GIF differ
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/zh-CN/resources/Notebook_Editor.GIF and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/zh-CN/resources/Notebook_Editor.GIF differ
Binary files /tmp/tmpVPGDnS/E0y011L9x5/jupyter-notebook-6.1.4/docs-translations/zh-CN/resources/running_code_med.png and /tmp/tmpVPGDnS/H33b62u1IS/jupyter-notebook-6.2.0/docs-translations/zh-CN/resources/running_code_med.png differ
diff -Nru jupyter-notebook-6.1.4/.github/ISSUE_TEMPLATE/bug_report.md jupyter-notebook-6.2.0/.github/ISSUE_TEMPLATE/bug_report.md
--- jupyter-notebook-6.1.4/.github/ISSUE_TEMPLATE/bug_report.md 1970-01-01 00:00:00.000000000 +0000
+++ jupyter-notebook-6.2.0/.github/ISSUE_TEMPLATE/bug_report.md 2021-01-13 16:30:49.000000000 +0000
@@ -0,0 +1,50 @@
+---
+name: Is this a bug in Notebook? Open an issue.
+about: If you're not sure, feel free to post your question on Jupyter's Discourse channel.
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff -Nru jupyter-notebook-6.1.4/.github/ISSUE_TEMPLATE/config.yml jupyter-notebook-6.2.0/.github/ISSUE_TEMPLATE/config.yml
--- jupyter-notebook-6.1.4/.github/ISSUE_TEMPLATE/config.yml 1970-01-01 00:00:00.000000000 +0000
+++ jupyter-notebook-6.2.0/.github/ISSUE_TEMPLATE/config.yml 2021-01-13 16:30:49.000000000 +0000
@@ -0,0 +1,11 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Is this a common issue? See our Docs.
+ url: https://jupyter-notebook.readthedocs.io/en/stable/troubleshooting.html#what-to-do-when-things-go-wrong
+ about: Before posting an issue here, make sure your issue hasn't already been addressed here.
+ - name: Do you need support or a question answered? See Jupyter Discourse.
+ url: https://discourse.jupyter.org/c/notebook/31
+ about: If you have a question or you're having issues installing Jupyter Notebook, try posting on Discourse. There are lots of friendly Joyvans there to help!
+ - name: Do you have a feature request? See JupyterLab.
+ url: https://github.com/jupyterlab/jupyterlab
+ about: Jupyter Notebook is in a maintenance-only phase. We won't likely accept new features; instead, we recommend you check out JupyterLab for new features and support.
diff -Nru jupyter-notebook-6.1.4/notebook/auth/tests/test_security.py jupyter-notebook-6.2.0/notebook/auth/tests/test_security.py
--- jupyter-notebook-6.1.4/notebook/auth/tests/test_security.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/auth/tests/test_security.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,22 +1,20 @@
-# coding: utf-8
from ..security import passwd, passwd_check
-import nose.tools as nt
def test_passwd_structure():
p = passwd('passphrase')
algorithm, hashed = p.split(':')
- nt.assert_equal(algorithm, 'argon2')
- nt.assert_true(hashed.startswith('$argon2id$'))
+ assert algorithm == 'argon2'
+ assert hashed.startswith('$argon2id$')
def test_roundtrip():
p = passwd('passphrase')
- nt.assert_equal(passwd_check(p, 'passphrase'), True)
+ assert passwd_check(p, 'passphrase') == True
def test_bad():
p = passwd('passphrase')
- nt.assert_equal(passwd_check(p, p), False)
- nt.assert_equal(passwd_check(p, 'a:b:c:d'), False)
- nt.assert_equal(passwd_check(p, 'a:b'), False)
+ assert passwd_check(p, p) == False
+ assert passwd_check(p, 'a:b:c:d') == False
+ assert passwd_check(p, 'a:b') == False
def test_passwd_check_unicode():
# GH issue #4524
diff -Nru jupyter-notebook-6.1.4/notebook/base/handlers.py jupyter-notebook-6.2.0/notebook/base/handlers.py
--- jupyter-notebook-6.1.4/notebook/base/handlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/base/handlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -301,7 +301,7 @@
def set_default_headers(self):
"""Add CORS headers, if defined"""
- super(IPythonHandler, self).set_default_headers()
+ super().set_default_headers()
if self.allow_origin:
self.set_header("Access-Control-Allow-Origin", self.allow_origin)
elif self.allow_origin_pat:
@@ -404,6 +404,10 @@
Used on GET for api endpoints and /files/
to block cross-site inclusion (XSSI).
"""
+
+ if self.allow_origin == "*" or self.skip_check_origin():
+ return True
+
host = self.request.headers.get("Host")
referer = self.request.headers.get("Referer")
@@ -442,7 +446,7 @@
# Servers without authentication are vulnerable to XSRF
return
try:
- return super(IPythonHandler, self).check_xsrf_cookie()
+ return super().check_xsrf_cookie()
except web.HTTPError as e:
if self.request.method in {'GET', 'HEAD'}:
# Consider Referer a sufficient cross-origin check for GET requests
@@ -496,7 +500,7 @@
def prepare(self):
if not self.check_host():
raise web.HTTPError(403)
- return super(IPythonHandler, self).prepare()
+ return super().prepare()
#---------------------------------------------------------------
# template rendering
@@ -591,7 +595,7 @@
def prepare(self):
if not self.check_origin():
raise web.HTTPError(404)
- return super(APIHandler, self).prepare()
+ return super().prepare()
def write_error(self, status_code, **kwargs):
"""APIHandler errors are JSON, not human pages"""
@@ -618,7 +622,7 @@
# preserve _user_cache so we don't raise more than once
if hasattr(self, '_user_cache'):
return self._user_cache
- self._user_cache = user = super(APIHandler, self).get_current_user()
+ self._user_cache = user = super().get_current_user()
return user
def get_login_url(self):
@@ -627,12 +631,12 @@
# instead of redirecting, raise 403 instead.
if not self.current_user:
raise web.HTTPError(403)
- return super(APIHandler, self).get_login_url()
+ return super().get_login_url()
@property
def content_security_policy(self):
csp = '; '.join([
- super(APIHandler, self).content_security_policy,
+ super().content_security_policy,
"default-src 'none'",
])
return csp
@@ -653,7 +657,7 @@
def finish(self, *args, **kwargs):
self.update_api_activity()
self.set_header('Content-Type', 'application/json')
- return super(APIHandler, self).finish(*args, **kwargs)
+ return super().finish(*args, **kwargs)
def options(self, *args, **kwargs):
if 'Access-Control-Allow-Headers' in self.settings.get('headers', {}):
@@ -700,13 +704,12 @@
def content_security_policy(self):
# In case we're serving HTML/SVG, confine any Javascript to a unique
# origin so it can't interact with the notebook server.
- return super(AuthenticatedFileHandler, self).content_security_policy + \
- "; sandbox allow-scripts"
+ return super().content_security_policy + "; sandbox allow-scripts"
@web.authenticated
def head(self, path):
self.check_xsrf_cookie()
- return super(AuthenticatedFileHandler, self).head(path)
+ return super().head(path)
@web.authenticated
def get(self, path):
@@ -731,10 +734,10 @@
if cur_mime == 'text/plain':
return 'text/plain; charset=UTF-8'
else:
- return super(AuthenticatedFileHandler, self).get_content_type()
+ return super().get_content_type()
def set_headers(self):
- super(AuthenticatedFileHandler, self).set_headers()
+ super().set_headers()
# disable browser caching, rely on 304 replies for savings
if "v" not in self.request.arguments:
self.add_header("Cache-Control", "no-cache")
@@ -749,7 +752,7 @@
Adding to tornado's own handling, forbids the serving of hidden files.
"""
- abs_path = super(AuthenticatedFileHandler, self).validate_absolute_path(root, absolute_path)
+ abs_path = super().validate_absolute_path(root, absolute_path)
abs_root = os.path.abspath(root)
if is_hidden(abs_path, abs_root) and not self.contents_manager.allow_hidden:
self.log.info("Refusing to serve hidden file, via 404 Error, use flag 'ContentsManager.allow_hidden' to enable")
@@ -795,7 +798,7 @@
_static_paths = {}
def set_headers(self):
- super(FileFindHandler, self).set_headers()
+ super().set_headers()
# disable browser caching, rely on 304 replies for savings
if "v" not in self.request.arguments or \
any(self.request.path.startswith(path) for path in self.no_cache_paths):
@@ -842,7 +845,7 @@
if (absolute_path + os.sep).startswith(root):
break
- return super(FileFindHandler, self).validate_absolute_path(root, absolute_path)
+ return super().validate_absolute_path(root, absolute_path)
class APIVersionHandler(APIHandler):
@@ -854,13 +857,18 @@
class TrailingSlashHandler(web.RequestHandler):
"""Simple redirect handler that strips trailing slashes
-
+
This should be the first, highest priority handler.
"""
-
+
def get(self):
- self.redirect(self.request.uri.rstrip('/'))
-
+ path, *rest = self.request.uri.partition("?")
+ # trim trailing *and* leading /
+ # to avoid misinterpreting repeated '//'
+ path = "/" + path.strip("/")
+ new_uri = "".join([path, *rest])
+ self.redirect(new_uri)
+
post = put = get
@@ -911,12 +919,15 @@
url = sep.join([self._url, self.request.query])
self.redirect(url, permanent=self._permanent)
+
class PrometheusMetricsHandler(IPythonHandler):
"""
Return prometheus metrics for this notebook server
"""
- @web.authenticated
def get(self):
+ if self.settings['authenticate_prometheus'] and not self.logged_in:
+ raise web.HTTPError(403)
+
self.set_header('Content-Type', prometheus_client.CONTENT_TYPE_LATEST)
self.write(prometheus_client.generate_latest(prometheus_client.REGISTRY))
diff -Nru jupyter-notebook-6.1.4/notebook/base/zmqhandlers.py jupyter-notebook-6.2.0/notebook/base/zmqhandlers.py
--- jupyter-notebook-6.1.4/notebook/base/zmqhandlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/base/zmqhandlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Tornado handlers for WebSocket <-> ZMQ sockets."""
# Copyright (c) Jupyter Development Team.
@@ -41,8 +40,6 @@
# don't modify msg or buffer list in-place
msg = msg.copy()
buffers = list(msg.pop('buffers'))
- if sys.version_info < (3, 4):
- buffers = [x.tobytes() for x in buffers]
bmsg = json.dumps(msg, default=date_default).encode('utf8')
buffers.insert(0, bmsg)
nbufs = len(buffers)
@@ -289,7 +286,7 @@
# assign and yield in two step to avoid tornado 3 issues
res = self.pre_get()
yield maybe_future(res)
- res = super(AuthenticatedZMQStreamHandler, self).get(*args, **kwargs)
+ res = super().get(*args, **kwargs)
yield maybe_future(res)
def initialize(self):
diff -Nru jupyter-notebook-6.1.4/notebook/bundler/bundlerextensions.py jupyter-notebook-6.2.0/notebook/bundler/bundlerextensions.py
--- jupyter-notebook-6.1.4/notebook/bundler/bundlerextensions.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/bundler/bundlerextensions.py 2021-01-13 16:30:49.000000000 +0000
@@ -294,7 +294,7 @@
def start(self):
"""Perform the App's functions as configured"""
- super(BundlerExtensionApp, self).start()
+ super().start()
# The above should have called a subcommand and raised NoStart; if we
# get here, it didn't, so we should self.log.info a message.
diff -Nru jupyter-notebook-6.1.4/notebook/bundler/tests/test_bundler_api.py jupyter-notebook-6.2.0/notebook/bundler/tests/test_bundler_api.py
--- jupyter-notebook-6.1.4/notebook/bundler/tests/test_bundler_api.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/bundler/tests/test_bundler_api.py 2021-01-13 16:30:49.000000000 +0000
@@ -46,7 +46,7 @@
self.assertIn('Missing argument bundler', resp.text)
def test_notebook_not_found(self):
- """Shoudl respond with 404 error about missing notebook"""
+ """Should respond with 404 error about missing notebook"""
resp = self.request('GET', 'bundle/fake.ipynb',
params={'bundler': 'fake_bundler'})
self.assertEqual(resp.status_code, 404)
diff -Nru jupyter-notebook-6.1.4/notebook/config_manager.py jupyter-notebook-6.2.0/notebook/config_manager.py
--- jupyter-notebook-6.1.4/notebook/config_manager.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/config_manager.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Manager to read and modify config data in JSON files."""
# Copyright (c) Jupyter Development Team.
diff -Nru jupyter-notebook-6.1.4/notebook/edit/handlers.py jupyter-notebook-6.2.0/notebook/edit/handlers.py
--- jupyter-notebook-6.1.4/notebook/edit/handlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/edit/handlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-#encoding: utf-8
"""Tornado handlers for the terminal emulator."""
# Copyright (c) Jupyter Development Team.
diff -Nru jupyter-notebook-6.1.4/notebook/extensions.py jupyter-notebook-6.2.0/notebook/extensions.py
--- jupyter-notebook-6.1.4/notebook/extensions.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/extensions.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Utilities for installing extensions"""
# Copyright (c) Jupyter Development Team.
diff -Nru jupyter-notebook-6.1.4/notebook/files/handlers.py jupyter-notebook-6.2.0/notebook/files/handlers.py
--- jupyter-notebook-6.1.4/notebook/files/handlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/files/handlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -26,8 +26,7 @@
def content_security_policy(self):
# In case we're serving HTML/SVG, confine any Javascript to a unique
# origin so it can't interact with the notebook server.
- return super(FilesHandler, self).content_security_policy + \
- "; sandbox allow-scripts"
+ return super().content_security_policy + "; sandbox allow-scripts"
@web.authenticated
def head(self, path):
diff -Nru jupyter-notebook-6.1.4/notebook/gateway/handlers.py jupyter-notebook-6.2.0/notebook/gateway/handlers.py
--- jupyter-notebook-6.1.4/notebook/gateway/handlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/gateway/handlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -4,6 +4,7 @@
import os
import logging
import mimetypes
+import random
from ..base.handlers import APIHandler, IPythonHandler
from ..utils import url_path_join
@@ -68,7 +69,7 @@
def get(self, kernel_id, *args, **kwargs):
self.authenticate()
self.kernel_id = cast_unicode(kernel_id, 'ascii')
- yield super(WebSocketChannelsHandler, self).get(kernel_id=kernel_id, *args, **kwargs)
+ yield super().get(kernel_id=kernel_id, *args, **kwargs)
def send_ping(self):
if self.ws_connection is None and self.ping_callback is not None:
@@ -97,7 +98,7 @@
if self.ws_connection: # prevent WebSocketClosedError
if isinstance(message, bytes):
binary = True
- super(WebSocketChannelsHandler, self).write_message(message, binary=binary)
+ super().write_message(message, binary=binary)
elif self.log.isEnabledFor(logging.DEBUG):
msg_summary = WebSocketChannelsHandler._get_message_summary(json_decode(utf8(message)))
self.log.debug("Notebook client closed websocket connection - message dropped: {}".format(msg_summary))
@@ -105,7 +106,7 @@
def on_close(self):
self.log.debug("Closing websocket connection %s", self.request.path)
self.gateway.on_close()
- super(WebSocketChannelsHandler, self).on_close()
+ super().on_close()
@staticmethod
def _get_message_summary(message):
@@ -129,11 +130,12 @@
"""Proxy web socket connection to a kernel/enterprise gateway."""
def __init__(self, **kwargs):
- super(GatewayWebSocketClient, self).__init__(**kwargs)
+ super().__init__(**kwargs)
self.kernel_id = None
self.ws = None
self.ws_future = Future()
self.disconnected = False
+ self.retry = 0
@gen.coroutine
def _connect(self, kernel_id):
@@ -155,6 +157,7 @@
def _connection_done(self, fut):
if not self.disconnected and fut.exception() is None: # prevent concurrent.futures._base.CancelledError
self.ws = fut.result()
+ self.retry = 0
self.log.debug("Connection is ready: ws: {}".format(self.ws))
else:
self.log.warning("Websocket connection has been closed via client disconnect or due to error. "
@@ -189,8 +192,15 @@
else: # ws cancelled - stop reading
break
- if not self.disconnected: # if websocket is not disconnected by client, attept to reconnect to Gateway
- self.log.info("Attempting to re-establish the connection to Gateway: {}".format(self.kernel_id))
+ # NOTE(esevan): if websocket is not disconnected by client, try to reconnect.
+ if not self.disconnected and self.retry < GatewayClient.instance().gateway_retry_max:
+ jitter = random.randint(10, 100) * 0.01
+ retry_interval = min(GatewayClient.instance().gateway_retry_interval * (2 ** self.retry),
+ GatewayClient.instance().gateway_retry_interval_max) + jitter
+ self.retry += 1
+ self.log.info("Attempting to re-establish the connection to Gateway in %s secs (%s/%s): %s",
+ retry_interval, self.retry, GatewayClient.instance().gateway_retry_max, self.kernel_id)
+ yield gen.sleep(retry_interval)
self._connect(self.kernel_id)
loop = IOLoop.current()
loop.add_future(self.ws_future, lambda future: self._read_messages(callback))
diff -Nru jupyter-notebook-6.1.4/notebook/gateway/managers.py jupyter-notebook-6.2.0/notebook/gateway/managers.py
--- jupyter-notebook-6.1.4/notebook/gateway/managers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/gateway/managers.py 2021-01-13 16:30:49.000000000 +0000
@@ -15,14 +15,14 @@
from jupyter_client.kernelspec import KernelSpecManager
from ..utils import url_path_join
-from traitlets import Instance, Unicode, Float, Bool, default, validate, TraitError
+from traitlets import Instance, Unicode, Int, Float, Bool, default, validate, TraitError
from traitlets.config import SingletonConfigurable
class GatewayClient(SingletonConfigurable):
"""This class manages the configuration. It's its own singleton class so that we
can share these values across all objects. It also contains some helper methods
- to build request arguments out of the various config options.
+ to build request arguments out of the various config options.
"""
@@ -205,7 +205,7 @@
return bool(os.environ.get(self.validate_cert_env, str(self.validate_cert_default_value)) not in ['no', 'false'])
def __init__(self, **kwargs):
- super(GatewayClient, self).__init__(**kwargs)
+ super().__init__(**kwargs)
self._static_args = {} # initialized on first use
env_whitelist_default_value = ''
@@ -220,6 +220,38 @@
def _env_whitelist_default(self):
return os.environ.get(self.env_whitelist_env, self.env_whitelist_default_value)
+ gateway_retry_interval_default_value = 1.0
+ gateway_retry_interval_env = 'JUPYTER_GATEWAY_RETRY_INTERVAL'
+ gateway_retry_interval = Float(default_value=gateway_retry_interval_default_value, config=True,
+ help="""The time allowed for HTTP reconnection with the Gateway server for the first time.
+ Next will be JUPYTER_GATEWAY_RETRY_INTERVAL multiplied by two in factor of numbers of retries
+ but less than JUPYTER_GATEWAY_RETRY_INTERVAL_MAX.
+ (JUPYTER_GATEWAY_RETRY_INTERVAL env var)""")
+
+ @default('gateway_retry_interval')
+ def gateway_retry_interval_default(self):
+ return float(os.environ.get('JUPYTER_GATEWAY_RETRY_INTERVAL', self.gateway_retry_interval_default_value))
+
+ gateway_retry_interval_max_default_value = 30.0
+ gateway_retry_interval_max_env = 'JUPYTER_GATEWAY_RETRY_INTERVAL_MAX'
+ gateway_retry_interval_max = Float(default_value=gateway_retry_interval_max_default_value, config=True,
+ help="""The maximum time allowed for HTTP reconnection retry with the Gateway server.
+ (JUPYTER_GATEWAY_RETRY_INTERVAL_MAX env var)""")
+
+ @default('gateway_retry_interval_max')
+ def gateway_retry_interval_max_default(self):
+ return float(os.environ.get('JUPYTER_GATEWAY_RETRY_INTERVAL_MAX', self.gateway_retry_interval_max_default_value))
+
+ gateway_retry_max_default_value = 5
+ gateway_retry_max_env = 'JUPYTER_GATEWAY_RETRY_MAX'
+ gateway_retry_max = Int(default_value=gateway_retry_max_default_value, config=True,
+ help="""The maximum retries allowed for HTTP reconnection with the Gateway server.
+ (JUPYTER_GATEWAY_RETRY_MAX env var)""")
+
+ @default('gateway_retry_max')
+ def gateway_retry_max_default(self):
+ return int(os.environ.get('JUPYTER_GATEWAY_RETRY_MAX', self.gateway_retry_max_default_value))
+
@property
def gateway_enabled(self):
return bool(self.url is not None and len(self.url) > 0)
@@ -310,7 +342,7 @@
_kernels = {}
def __init__(self, **kwargs):
- super(GatewayKernelManager, self).__init__(**kwargs)
+ super().__init__(**kwargs)
self.base_endpoint = url_path_join(GatewayClient.instance().url, GatewayClient.instance().kernels_endpoint)
def __contains__(self, kernel_id):
@@ -503,11 +535,10 @@
self.remove_kernel(kernel_id)
-
class GatewayKernelSpecManager(KernelSpecManager):
def __init__(self, **kwargs):
- super(GatewayKernelSpecManager, self).__init__(**kwargs)
+ super().__init__(**kwargs)
base_endpoint = url_path_join(GatewayClient.instance().url,
GatewayClient.instance().kernelspecs_endpoint)
diff -Nru jupyter-notebook-6.1.4/notebook/i18n/zh_CN/LC_MESSAGES/nbjs.po jupyter-notebook-6.2.0/notebook/i18n/zh_CN/LC_MESSAGES/nbjs.po
--- jupyter-notebook-6.1.4/notebook/i18n/zh_CN/LC_MESSAGES/nbjs.po 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/i18n/zh_CN/LC_MESSAGES/nbjs.po 2021-01-13 16:30:49.000000000 +0000
@@ -19,15 +19,15 @@
#: notebook/static/base/js/dialog.js:161
msgid "Manually edit the JSON below to manipulate the metadata for this cell."
-msgstr "手动编辑下面的JSON代码来修改块元数据."
+msgstr "手动编辑下面的 JSON 代码来修改块元数据。"
#: notebook/static/base/js/dialog.js:163
msgid "Manually edit the JSON below to manipulate the metadata for this notebook."
-msgstr "手动编辑下面的JSON代码来修改界面元数据."
+msgstr "手动编辑下面的 JSON 代码来修改笔记本元数据。"
#: notebook/static/base/js/dialog.js:165
msgid " We recommend putting custom metadata attributes in an appropriately named substructure, so they don't conflict with those of others."
-msgstr "我们建议将自定义的元数据属性放入适当的子结构中,这样就不会与其他的子结构发生冲突."
+msgstr "我们建议将自定义的元数据属性放入适当的子结构中,这样就不会与其他的子结构发生冲突。"
#: notebook/static/base/js/dialog.js:180
msgid "Edit the metadata"
@@ -35,7 +35,7 @@
#: notebook/static/base/js/dialog.js:202
msgid "Edit Notebook Metadata"
-msgstr "编辑界面元数据"
+msgstr "编辑笔记本元数据"
#: notebook/static/base/js/dialog.js:204
msgid "Edit Cell Metadata"
@@ -70,11 +70,11 @@
#: notebook/static/base/js/dialog.js:225
msgid "WARNING: Could not save invalid JSON."
-msgstr "警告: 不能保存无效的JSON."
+msgstr "警告: 不能保存无效的JSON。"
#: notebook/static/base/js/dialog.js:247
msgid "There are no attachments for this cell."
-msgstr "这个块没有附件."
+msgstr "这个块没有附件。"
#: notebook/static/base/js/dialog.js:250
msgid "Current cell attachments"
@@ -100,7 +100,7 @@
#: notebook/static/base/js/dialog.js:348
msgid "Edit Notebook Attachments"
-msgstr "编辑代码附件"
+msgstr "编辑笔记本附件"
#: notebook/static/base/js/dialog.js:350
msgid "Edit Cell Attachments"
@@ -116,19 +116,19 @@
#: notebook/static/notebook/js/about.js:14
msgid "You are using Jupyter notebook."
-msgstr "你正在运行notebook."
+msgstr "您正在使用 Jupyter Notebook。"
#: notebook/static/notebook/js/about.js:16
msgid "The version of the notebook server is: "
-msgstr "该notebook 服务的版本是:"
+msgstr "该 notebook 服务的版本是:"
#: notebook/static/notebook/js/about.js:22
msgid "The server is running on this version of Python:"
-msgstr "该服务运行中使用的python版本为:"
+msgstr "该服务运行中使用的 Python 版本为:"
#: notebook/static/notebook/js/about.js:25
msgid "Waiting for kernel to be available..."
-msgstr "等待服务可用..."
+msgstr "等待内核可用..."
#: notebook/static/notebook/js/about.js:27
msgid "Server Information:"
@@ -136,15 +136,15 @@
#: notebook/static/notebook/js/about.js:29
msgid "Current Kernel Information:"
-msgstr "当前服务信息:"
+msgstr "当前内核信息:"
#: notebook/static/notebook/js/about.js:32
msgid "Could not access sys_info variable for version information."
-msgstr "无法为版本信息访问sysinfo变量."
+msgstr "无法访问 sys_info 变量来获取版本信息。"
#: notebook/static/notebook/js/about.js:34
msgid "Cannot find sys_info!"
-msgstr "找不到sys_info!"
+msgstr "找不到 sys_info!"
#: notebook/static/notebook/js/about.js:38
msgid "About Jupyter Notebook"
@@ -152,19 +152,19 @@
#: notebook/static/notebook/js/about.js:47
msgid "unable to contact kernel"
-msgstr "不能连接到服务"
+msgstr "不能连接到内核"
#: notebook/static/notebook/js/actions.js:69
msgid "toggle rtl layout"
-msgstr "切换trl布局"
+msgstr "切换 RTL 布局"
#: notebook/static/notebook/js/actions.js:70
msgid "Toggle the screen directionality between left-to-right and right-to-left"
-msgstr "切换左右至右至左之间的屏幕方向"
+msgstr "切换左至右或右至左的屏幕方向"
#: notebook/static/notebook/js/actions.js:76
msgid "edit command mode keyboard shortcuts"
-msgstr "编辑命令模式快捷键"
+msgstr "编辑命令模式键盘快捷键"
#: notebook/static/notebook/js/actions.js:77
msgid "Open a dialog to edit the command mode keyboard shortcuts"
@@ -172,56 +172,56 @@
#: notebook/static/notebook/js/actions.js:97
msgid "restart kernel"
-msgstr "重启服务"
+msgstr "重启内核"
#: notebook/static/notebook/js/actions.js:98
msgid "restart the kernel (no confirmation dialog)"
-msgstr "重启服务(没有确认窗口)"
+msgstr "重启内核(无确认对话框)"
#: notebook/static/notebook/js/actions.js:106
msgid "confirm restart kernel"
-msgstr "确定重启服务"
+msgstr "确定重启内核"
#: notebook/static/notebook/js/actions.js:107
msgid "restart the kernel (with dialog)"
-msgstr "重启服务(带窗口)"
+msgstr "重启内核(带确认对话框)"
#: notebook/static/notebook/js/actions.js:113
msgid "restart kernel and run all cells"
-msgstr "重启服务并且运行所有代码块"
+msgstr "重启内核并且运行所有代码块"
#: notebook/static/notebook/js/actions.js:114
msgid "restart the kernel, then re-run the whole notebook (no confirmation dialog)"
-msgstr "重启服务, 然后重新运行整个代码(不含确认窗口)"
+msgstr "重启服务,然后重新运行整个笔记本(无确认对话框)"
#: notebook/static/notebook/js/actions.js:120
msgid "confirm restart kernel and run all cells"
-msgstr "确认重启服务并且运行所有代码块"
+msgstr "确认重启内核并且运行所有代码块"
#: notebook/static/notebook/js/actions.js:121
msgid "restart the kernel, then re-run the whole notebook (with dialog)"
-msgstr "重启服务, 然后重新运行整个代码(含窗口)"
+msgstr "重启内核, 然后重新运行整个代码(带确认对话框)"
#: notebook/static/notebook/js/actions.js:127
msgid "restart kernel and clear output"
-msgstr "重启服务并且清空输入"
+msgstr "重启内核并且清空输出"
#: notebook/static/notebook/js/actions.js:128
msgid "restart the kernel and clear all output (no confirmation dialog)"
-msgstr "重启服务并且清空所有输出(不含确认窗口)"
+msgstr "重启内核并且清空所有输出(无确认对话框)"
#: notebook/static/notebook/js/actions.js:134
msgid "confirm restart kernel and clear output"
-msgstr "确认重启服务并且清空输出"
+msgstr "确认重启内核并且清空输出"
#: notebook/static/notebook/js/actions.js:135
msgid "restart the kernel and clear all output (with dialog)"
-msgstr "重启服务并且清空所有输出(含窗口)"
+msgstr "重启内核并且清空所有输出(带确认对话框)"
#: notebook/static/notebook/js/actions.js:142
#: notebook/static/notebook/js/actions.js:143
msgid "interrupt the kernel"
-msgstr "中断服务"
+msgstr "中断内核"
#: notebook/static/notebook/js/actions.js:150
msgid "run cell and select next"
@@ -239,7 +239,7 @@
#: notebook/static/notebook/js/actions.js:167
#: notebook/static/notebook/js/actions.js:168
msgid "run cell and insert below"
-msgstr "运行代码块并且插入下面"
+msgstr "运行代码块并且在下面插入代码块"
#: notebook/static/notebook/js/actions.js:175
#: notebook/static/notebook/js/actions.js:176
@@ -269,22 +269,22 @@
#: notebook/static/notebook/js/actions.js:213
#: notebook/static/notebook/js/actions.js:214
msgid "cut cell attachments"
-msgstr "剪切代码块"
+msgstr "剪切代码块的附件"
#: notebook/static/notebook/js/actions.js:221
#: notebook/static/notebook/js/actions.js:222
msgid "copy cell attachments"
-msgstr "复制代码块"
+msgstr "复制代码块的附件"
#: notebook/static/notebook/js/actions.js:229
#: notebook/static/notebook/js/actions.js:230
msgid "paste cell attachments"
-msgstr "粘贴代码块"
+msgstr "粘贴代码块的附件"
#: notebook/static/notebook/js/actions.js:237
#: notebook/static/notebook/js/actions.js:238
msgid "split cell at cursor"
-msgstr "在鼠标处分割代码块"
+msgstr "在光标处分割代码块"
#: notebook/static/notebook/js/actions.js:245
#: notebook/static/notebook/js/actions.js:246
@@ -361,7 +361,7 @@
#: notebook/static/notebook/js/actions.js:373
#: notebook/static/notebook/js/actions.js:374
msgid "change cell to markdown"
-msgstr "把代码块变成标签"
+msgstr "把代码块变成 Markdown"
#: notebook/static/notebook/js/actions.js:381
#: notebook/static/notebook/js/actions.js:382
@@ -371,48 +371,48 @@
#: notebook/static/notebook/js/actions.js:389
#: notebook/static/notebook/js/actions.js:390
msgid "change cell to heading 1"
-msgstr "把代码块变成heading 1"
+msgstr "把代码块变成标题 1"
#: notebook/static/notebook/js/actions.js:397
#: notebook/static/notebook/js/actions.js:398
msgid "change cell to heading 2"
-msgstr "把代码块变成heading 2"
+msgstr "把代码块变成标题 2"
#: notebook/static/notebook/js/actions.js:405
#: notebook/static/notebook/js/actions.js:406
msgid "change cell to heading 3"
-msgstr "把代码块变成heading 3"
+msgstr "把代码块变成标题 3"
#: notebook/static/notebook/js/actions.js:413
#: notebook/static/notebook/js/actions.js:414
msgid "change cell to heading 4"
-msgstr "把代码块变成heading 4"
+msgstr "把代码块变成标题 4"
#: notebook/static/notebook/js/actions.js:421
#: notebook/static/notebook/js/actions.js:422
msgid "change cell to heading 5"
-msgstr "把代码块变成heading 5"
+msgstr "把代码块变成标题 5"
#: notebook/static/notebook/js/actions.js:429
#: notebook/static/notebook/js/actions.js:430
msgid "change cell to heading 6"
-msgstr "把代码块变成heading 6"
+msgstr "把代码块变成标题 6"
#: notebook/static/notebook/js/actions.js:437
msgid "toggle cell output"
-msgstr "切换单元输出"
+msgstr "切换代码块输出"
#: notebook/static/notebook/js/actions.js:438
msgid "toggle output of selected cells"
-msgstr "选择单元格的输出"
+msgstr "切换选定单元格的输出"
#: notebook/static/notebook/js/actions.js:445
msgid "toggle cell scrolling"
-msgstr "切换单元滚动"
+msgstr "切换单元格滚动"
#: notebook/static/notebook/js/actions.js:446
msgid "toggle output scrolling of selected cells"
-msgstr "切换选定单元的输出滚动"
+msgstr "切换选中单元格的输出滚动"
#: notebook/static/notebook/js/actions.js:453
msgid "clear cell output"
@@ -446,7 +446,7 @@
#: notebook/static/notebook/js/actions.js:486
#: notebook/static/notebook/js/actions.js:487
msgid "show keyboard shortcuts"
-msgstr "显示快捷键"
+msgstr "显示键盘快捷键"
#: notebook/static/notebook/js/actions.js:494
msgid "delete cells"
@@ -528,7 +528,7 @@
#: notebook/static/notebook/js/actions.js:590
msgid "switch between showing and hiding the header"
-msgstr "显示和隐藏标题之间的切换"
+msgstr "切换显示和隐藏标题"
#: notebook/static/notebook/js/actions.js:605
#: notebook/static/notebook/js/actions.js:606
@@ -546,7 +546,7 @@
#: notebook/static/notebook/js/actions.js:647
msgid "switch between showing and hiding the toolbar"
-msgstr "选择显示/隐藏工具栏"
+msgstr "切换显示/隐藏工具栏"
#: notebook/static/notebook/js/actions.js:660
#: notebook/static/notebook/js/actions.js:661
@@ -561,7 +561,7 @@
#: notebook/static/notebook/js/actions.js:678
#: notebook/static/notebook/js/actions.js:679
msgid "close the pager"
-msgstr "关闭页面"
+msgstr "关闭分页器"
#: notebook/static/notebook/js/actions.js:704
msgid "ignore"
@@ -589,7 +589,7 @@
#: notebook/static/notebook/js/actions.js:770
msgid "scroll cell center"
-msgstr "滚动到单元格中间"
+msgstr "滚动单元格到中间"
#: notebook/static/notebook/js/actions.js:771
msgid "Scroll the current cell to the center"
@@ -597,7 +597,7 @@
#: notebook/static/notebook/js/actions.js:781
msgid "scroll cell top"
-msgstr "滚动到单元格开始处"
+msgstr "滚动单元格到顶"
#: notebook/static/notebook/js/actions.js:782
msgid "Scroll the current cell to the top"
@@ -605,31 +605,31 @@
#: notebook/static/notebook/js/actions.js:792
msgid "duplicate notebook"
-msgstr "复制代码"
+msgstr "制作笔记本副本"
#: notebook/static/notebook/js/actions.js:793
msgid "Create and open a copy of the current notebook"
-msgstr "创建并打开当前代码的一个副本"
+msgstr "创建并打开当前笔记本的一个副本"
#: notebook/static/notebook/js/actions.js:799
msgid "trust notebook"
-msgstr "信任代码"
+msgstr "信任笔记本"
#: notebook/static/notebook/js/actions.js:800
msgid "Trust the current notebook"
-msgstr "信任当前代码"
+msgstr "信任当前笔记本"
#: notebook/static/notebook/js/actions.js:806
msgid "rename notebook"
-msgstr "重命名"
+msgstr "重命名笔记本"
#: notebook/static/notebook/js/actions.js:807
msgid "Rename the current notebook"
-msgstr "重命名"
+msgstr "重命名当前笔记本"
#: notebook/static/notebook/js/actions.js:813
msgid "toggle all cells output collapsed"
-msgstr "切换所有单元格的输出"
+msgstr "切换折叠所有单元格的输出"
#: notebook/static/notebook/js/actions.js:814
msgid "Toggle the hidden state of all output areas"
@@ -637,7 +637,7 @@
#: notebook/static/notebook/js/actions.js:820
msgid "toggle all cells output scrolled"
-msgstr "切换所有单元格的输出"
+msgstr "切换所有单元格输出的滚动状态"
#: notebook/static/notebook/js/actions.js:821
msgid "Toggle the scrolling state of all output areas"
@@ -653,15 +653,15 @@
#: notebook/static/notebook/js/actions.js:835
msgid "save notebook"
-msgstr "保存代码"
+msgstr "保存笔记本"
#: notebook/static/notebook/js/actions.js:836
msgid "Save and Checkpoint"
-msgstr "保存并检查"
+msgstr "保存并建立检查点"
#: notebook/static/notebook/js/cell.js:79
msgid "Warning: accessing Cell.cm_config directly is deprecated."
-msgstr "警告: 访问Cell.cm_config已经被弃用了."
+msgstr "警告: 直接访问 Cell.cm_config 已经被弃用了。"
#: notebook/static/notebook/js/cell.js:763
#, python-format
@@ -697,11 +697,11 @@
#: notebook/static/notebook/js/clipboard.js:113
#, python-format
msgid "Press %s again to paste"
-msgstr "再按一次 %s 粘贴"
+msgstr "再按一次 %s 来粘贴"
#: notebook/static/notebook/js/clipboard.js:116
msgid "Why is this needed? "
-msgstr "这个为啥需要?"
+msgstr "为什么需要它?"
#: notebook/static/notebook/js/clipboard.js:118
msgid "We can't get paste events in this browser without a text box. "
@@ -718,7 +718,7 @@
#: notebook/static/notebook/js/codecell.js:310
msgid "Can't execute cell since kernel is not set."
-msgstr "只要服务没有设置就不能执行单元格代码."
+msgstr "当前不能执行单元格代码,因为内核还没有准备好。"
#: notebook/static/notebook/js/codecell.js:481
msgid "In"
@@ -727,30 +727,30 @@
#: notebook/static/notebook/js/kernelselector.js:269
#, python-format
msgid "Could not find a kernel matching %s. Please select a kernel:"
-msgstr "找不到服务匹配 %s. 请选择一个服务:"
+msgstr "找不到匹配 %s 的内核。请选择一个内核:"
#: notebook/static/notebook/js/kernelselector.js:278
msgid "Continue Without Kernel"
-msgstr "继续运行没有服务"
+msgstr "无内核继续运行"
#: notebook/static/notebook/js/kernelselector.js:278
msgid "Set Kernel"
-msgstr "设置服务"
+msgstr "设置内核"
#: notebook/static/notebook/js/kernelselector.js:281
msgid "Kernel not found"
-msgstr "服务没找到"
+msgstr "找不到内核"
#: notebook/static/notebook/js/kernelselector.js:319
#: notebook/static/tree/js/newnotebook.js:99
msgid "Creating Notebook Failed"
-msgstr "创建代码失败"
+msgstr "创建笔记本失败"
#: notebook/static/notebook/js/kernelselector.js:320
#: notebook/static/tree/js/notebooklist.js:1362
#, python-format
msgid "The error was: %s"
-msgstr "错误; %s"
+msgstr "错误: %s"
#: notebook/static/notebook/js/maintoolbar.js:54
msgid "Run"
@@ -774,29 +774,29 @@
#: notebook/static/notebook/js/maintoolbar.js:115
msgid "unrecognized cell type:"
-msgstr "未识别的单元格类型:"
+msgstr "未识别的单元格类型:"
#: notebook/static/notebook/js/mathjaxutils.js:45
#, python-format
msgid "Failed to retrieve MathJax from '%s'"
-msgstr "从 '%s' 中未能检索 MathJax"
+msgstr "未能从 '%s' 中检索 MathJax"
#: notebook/static/notebook/js/mathjaxutils.js:47
msgid "Math/LaTeX rendering will be disabled."
-msgstr "Math/LaTeX 渲染 将会失效."
+msgstr "Math/LaTeX 渲染将被禁用。"
#: notebook/static/notebook/js/menubar.js:220
msgid "Trusted Notebook"
-msgstr "可信的笔记"
+msgstr "可信的笔记本"
#: notebook/static/notebook/js/menubar.js:226
msgid "Trust Notebook"
-msgstr "信任笔记"
+msgstr "信任笔记本"
#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:16
#: notebook/static/notebook/js/menubar.js:383
msgid "None"
-msgstr ""
+msgstr "无"
#: notebook/static/notebook/js/menubar.js:406
msgid "No checkpoints"
@@ -808,23 +808,23 @@
#: notebook/static/notebook/js/notebook.js:441
msgid "Autosave in progress, latest changes may be lost."
-msgstr "自动保存, 最新的改变有可能被丢弃."
+msgstr "自动保存进行中,最新的改变可能会丢失。"
#: notebook/static/notebook/js/notebook.js:443
msgid "Unsaved changes will be lost."
-msgstr "未保存的修改将会丢失."
+msgstr "未保存的修改将会丢失。"
#: notebook/static/notebook/js/notebook.js:448
msgid "The Kernel is busy, outputs may be lost."
-msgstr "服务正忙, 输出也许会丢失."
+msgstr "内核正忙,输出也许会丢失。"
#: notebook/static/notebook/js/notebook.js:471
msgid "This notebook is version %1$s, but we only fully support up to %2$s."
-msgstr "本程序版本 %1$s, 但是我们只是支持到 %2$s."
+msgstr "该笔记本使用了版本 %1$s,但是我们只支持到 %2$s."
#: notebook/static/notebook/js/notebook.js:473
msgid "You can still work with this notebook, but cell and output types introduced in later notebook versions will not be available."
-msgstr "您仍然可以使用本程序, 但是在以后的版本中引入的单元和输出类型将不可用."
+msgstr "您仍然可以使用该笔记本,但是在新版本中引入的单元和输出类型将不可用。"
#: notebook/static/notebook/js/notebook.js:480
msgid "Restart and Run All Cells"
@@ -860,72 +860,72 @@
#: notebook/static/notebook/js/notebook.js:493
msgid "Newer Notebook"
-msgstr "新笔记"
+msgstr "新笔记本"
#: notebook/static/notebook/js/notebook.js:1558
msgid "Use markdown headings"
-msgstr "使用标签 headings"
+msgstr "使用 Markdown 标题"
#: notebook/static/notebook/js/notebook.js:1560
msgid "Jupyter no longer uses special heading cells. Instead, write your headings in Markdown cells using # characters:"
-msgstr "Jupyter不再使用特殊的标题单元格. 相反, 在Markdown单元中使用字符来写标题:"
+msgstr "Jupyter 不再使用特殊的标题单元格。请在 Markdown 单元格中使用 # 字符来写标题:"
#: notebook/static/notebook/js/notebook.js:1563
msgid "## This is a level 2 heading"
-msgstr "## 这是一个 2 heading"
+msgstr "## 这是一个二级标题"
#: notebook/static/notebook/js/notebook.js:2261
msgid "Restart kernel and re-run the whole notebook?"
-msgstr "重新启动内核并重新运行整个笔记本?"
+msgstr "重新启动内核并重新运行整个笔记本?"
#: notebook/static/notebook/js/notebook.js:2263
msgid "Are you sure you want to restart the current kernel and re-execute the whole notebook? All variables and outputs will be lost."
-msgstr "您确定要重新启动当前的内核并重新执行整个笔记本吗? 所有的变量和输出都将丢失."
+msgstr "您确定要重新启动当前的内核并重新执行整个笔记本吗?所有的变量和输出都将丢失。"
#: notebook/static/notebook/js/notebook.js:2288
msgid "Restart kernel and clear all output?"
-msgstr "重启服务并且清空输出?"
+msgstr "重启内核并且清空输出?"
#: notebook/static/notebook/js/notebook.js:2290
msgid "Do you want to restart the current kernel and clear all output? All variables and outputs will be lost."
-msgstr "您是否希望重新启动当前的内核并清除所有输出? 所有的变量和输出都将丢失."
+msgstr "您是否希望重新启动当前的内核并清除所有输出?所有的变量和输出都将丢失。"
#: notebook/static/notebook/js/notebook.js:2335
msgid "Restart kernel?"
-msgstr "重启服务?"
+msgstr "重启内核?"
#: notebook/static/notebook/js/notebook.js:2337
msgid "Do you want to restart the current kernel? All variables will be lost."
-msgstr "如果重启服务, 所有变量都会丢弃."
+msgstr "如果重启内核,所有变量都会丢失。是否重启?"
#: notebook/static/notebook/js/notebook.js:2320
msgid "Shutdown kernel?"
-msgstr "关闭服务"
+msgstr "关闭内核?"
#: notebook/static/notebook/js/notebook.js:2322
msgid "Do you want to shutdown the current kernel? All variables will be lost."
-msgstr "如果关闭服务,所有变量都会丢失"
+msgstr "如果关闭内核,所有变量都会丢失。是否关闭?"
#: notebook/static/notebook/js/notebook.js:2750
msgid "Notebook changed"
-msgstr "笔记改变了"
+msgstr "笔记本改变了"
#: notebook/static/notebook/js/notebook.js:2751
msgid "The notebook file has changed on disk since the last time we opened or saved it. Do you want to overwrite the file on disk with the version open here, or load the version on disk (reload the page)?"
-msgstr "自从上次我们打开或保存它以来, 笔记本文件已经在磁盘上发生了变化. 您是否希望在磁盘上使用打开的版本, 或在磁盘上的版本(重新加载页面)上覆盖该文件?"
+msgstr "自从上次我们打开或保存它以来,笔记本文件已经在磁盘上发生了变化。您希望用这里打开的版本覆盖磁盘上的版本,还是加载磁盘上的版本(刷新页面)?"
#: notebook/static/notebook/js/notebook.js:2798
#: notebook/static/notebook/js/notebook.js:3020
msgid "Notebook validation failed"
-msgstr "Notebook 失效"
+msgstr "Notebook 校验失败"
#: notebook/static/notebook/js/notebook.js:2801
msgid "The save operation succeeded, but the notebook does not appear to be valid. The validation error was:"
-msgstr "保存操作成功了, 但是这个笔记本看起来并不有效. 验证错误:"
+msgstr "保存操作成功了,但是这个笔记本看起来并不有效。校验错误:"
#: notebook/static/notebook/js/notebook.js:2852
msgid "A trusted Jupyter notebook may execute hidden malicious code when you open it. Selecting trust will immediately reload this notebook in a trusted state. For more information, see the Jupyter security documentation: "
-msgstr "当你打开它时, 一个可信任的Jupyter笔记本可能会执行隐藏的恶意代码. 选择信任将立即在一个可信的状态中重新加载这个笔记本. 要了解更多信息, 请参阅Jupyter安全文档:"
+msgstr "当你打开一个可信任的 Jupyter 笔记本时,它可能会执行隐藏的恶意代码。选择信任将立即在一个可信的状态中重新加载这个笔记本。要了解更多信息,请参阅 Jupyter 安全文档:"
#: notebook/static/notebook/js/notebook.js:2856
msgid "here"
@@ -933,11 +933,11 @@
#: notebook/static/notebook/js/notebook.js:2864
msgid "Trust this notebook?"
-msgstr "信任这个代码?"
+msgstr "信任这个笔记本?"
#: notebook/static/notebook/js/notebook.js:3011
msgid "Notebook failed to load"
-msgstr "代码加载失败"
+msgstr "笔记本加载失败"
#: notebook/static/notebook/js/notebook.js:3013
msgid "The error was: "
@@ -945,74 +945,74 @@
#: notebook/static/notebook/js/notebook.js:3017
msgid "See the error console for details."
-msgstr "有关详细信息, 请参阅错误控制台."
+msgstr "有关详细信息,请参阅错误控制台。"
#: notebook/static/notebook/js/notebook.js:3025
msgid "The notebook also failed validation:"
-msgstr "代码失败了:"
+msgstr "这个笔记本校验也失败了:"
#: notebook/static/notebook/js/notebook.js:3027
msgid "An invalid notebook may not function properly. The validation error was:"
-msgstr "无效的笔记本可能不能正常工作. 验证错误:"
+msgstr "无效的笔记本可能无法正常运行。校验错误:"
#: notebook/static/notebook/js/notebook.js:3066
#, python-format
msgid "This notebook has been converted from an older notebook format to the current notebook format v(%s)."
-msgstr "本笔记本已从较旧的笔记本格式转换为当前的笔记本格式 v(%s)."
+msgstr "本笔记本已从较旧的笔记本格式转换为当前的笔记本格式 v(%s)。"
#: notebook/static/notebook/js/notebook.js:3068
#, python-format
msgid "This notebook has been converted from a newer notebook format to the current notebook format v(%s)."
-msgstr "这个笔记本已经从一种新的笔记本格式转换为当前的笔记本格式 v(%s)."
+msgstr "这个笔记本已经从一种新的笔记本格式转换为当前的笔记本格式 v(%s)。"
#: notebook/static/notebook/js/notebook.js:3076
msgid "The next time you save this notebook, the current notebook format will be used."
-msgstr "下次你保存这个笔记本时, 当前的笔记本格式将会被使用."
+msgstr "下次你保存这个笔记本时,当前的笔记本格式将会被使用。"
#: notebook/static/notebook/js/notebook.js:3081
msgid "Older versions of Jupyter may not be able to read the new format."
-msgstr "旧版本的Jupyter可能无法读取新格式."
+msgstr "旧版本的 Jupyter 可能无法读取新格式。"
#: notebook/static/notebook/js/notebook.js:3083
msgid "Some features of the original notebook may not be available."
-msgstr "原始笔记本的一些特性可能无法使用."
+msgstr "原笔记本的一些特性可能无法使用。"
#: notebook/static/notebook/js/notebook.js:3086
msgid "To preserve the original version, close the notebook without saving it."
-msgstr "为了保存原始版本, 关闭笔记本而不保存它."
+msgstr "为了保存原始版本,关闭笔记本而不保存它。"
#: notebook/static/notebook/js/notebook.js:3091
msgid "Notebook converted"
-msgstr "代码被修改了"
+msgstr "已转换笔记本"
#: notebook/static/notebook/js/notebook.js:3113
msgid "(No name)"
-msgstr "(没有名字)"
+msgstr "(没有名字)"
#: notebook/static/notebook/js/notebook.js:3161
#, python-format
msgid "An unknown error occurred while loading this notebook. This version can load notebook formats %s or earlier. See the server log for details."
-msgstr "加载本笔记本时出现了一个未知的错误. 这个版本可以加载%s或更早的笔记本. 有关详细信息, 请参阅服务器日志."
+msgstr "加载本笔记本时出现了一个未知的错误。这个版本可以加载 %s 或更早的笔记本。有关详细信息,请参阅服务器日志。"
#: notebook/static/notebook/js/notebook.js:3172
msgid "Error loading notebook"
-msgstr "加载代码出错"
+msgstr "加载笔记本出错"
#: notebook/static/notebook/js/notebook.js:3273
msgid "Are you sure you want to revert the notebook to the latest checkpoint?"
-msgstr "确定撤销操作?"
+msgstr "确定将笔记本恢复至最近的检查点?"
#: notebook/static/notebook/js/notebook.js:3276
msgid "This cannot be undone."
-msgstr "该操作不能被执行."
+msgstr "该操作不能被还原。"
#: notebook/static/notebook/js/notebook.js:3279
msgid "The checkpoint was last updated at:"
-msgstr "这个代码最后更新时间:"
+msgstr "笔记本的最新检查点更新于:"
#: notebook/static/notebook/js/notebook.js:3290
msgid "Revert notebook to checkpoint"
-msgstr "恢复代码"
+msgstr "恢复笔记本至检查点"
#: notebook/static/notebook/js/notificationarea.js:76
#: notebook/static/notebook/js/tour.js:61
@@ -1024,19 +1024,19 @@
#: notebook/static/notebook/js/notificationarea.js:87
#: notebook/static/notebook/js/tour.js:54
msgid "Command Mode"
-msgstr "命令 模式"
+msgstr "命令模式"
#: notebook/static/notebook/js/notificationarea.js:94
msgid "Kernel Created"
-msgstr "服务创建"
+msgstr "内核已创建"
#: notebook/static/notebook/js/notificationarea.js:98
msgid "Connecting to kernel"
-msgstr "正在连接服务"
+msgstr "正在连接内核"
#: notebook/static/notebook/js/notificationarea.js:102
msgid "Not Connected"
-msgstr "未连接成功"
+msgstr "未连接"
#: notebook/static/notebook/js/notificationarea.js:105
msgid "click to reconnect"
@@ -1044,39 +1044,39 @@
#: notebook/static/notebook/js/notificationarea.js:114
msgid "Restarting kernel"
-msgstr "重启服务"
+msgstr "重启内核"
#: notebook/static/notebook/js/notificationarea.js:128
msgid "Kernel Restarting"
-msgstr "服务正重启"
+msgstr "内核正在重启"
#: notebook/static/notebook/js/notificationarea.js:129
msgid "The kernel appears to have died. It will restart automatically."
-msgstr "服务似乎挂掉了,但是会立刻重启的."
+msgstr "内核似乎挂掉了,它很快将自动重启。"
#: notebook/static/notebook/js/notificationarea.js:139
#: notebook/static/notebook/js/notificationarea.js:197
#: notebook/static/notebook/js/notificationarea.js:217
msgid "Dead kernel"
-msgstr "挂掉的服务"
+msgstr "挂掉的内核"
#: notebook/static/notebook/js/notificationarea.js:140
#: notebook/static/notebook/js/notificationarea.js:218
#: notebook/static/notebook/js/notificationarea.js:265
msgid "Kernel Dead"
-msgstr "服务挂掉"
+msgstr "内核挂掉"
#: notebook/static/notebook/js/notificationarea.js:144
msgid "Interrupting kernel"
-msgstr "正在中断服务"
+msgstr "正在中断内核"
#: notebook/static/notebook/js/notificationarea.js:150
msgid "No Connection to Kernel"
-msgstr "没有到服务的连接"
+msgstr "没有连接到内核"
#: notebook/static/notebook/js/notificationarea.js:160
msgid "A connection to the notebook server could not be established. The notebook will continue trying to reconnect. Check your network connection or notebook server configuration."
-msgstr "到后台服务的连接没能建立, 我们会继续尝试重连, 请检查网络连接还有服务配置."
+msgstr "无法建立到笔记本服务器的连接。 我们会继续尝试重连。请检查网络连接还有服务配置。"
#: notebook/static/notebook/js/notificationarea.js:165
msgid "Connection failed"
@@ -1084,11 +1084,11 @@
#: notebook/static/notebook/js/notificationarea.js:178
msgid "No kernel"
-msgstr "没有服务"
+msgstr "没有内核"
#: notebook/static/notebook/js/notificationarea.js:179
msgid "Kernel is not running"
-msgstr "服务没有运行"
+msgstr "内核没有运行"
#: notebook/static/notebook/js/notificationarea.js:186
msgid "Don't Restart"
@@ -1100,90 +1100,90 @@
#: notebook/static/notebook/js/notificationarea.js:190
msgid "The kernel has died, and the automatic restart has failed. It is possible the kernel cannot be restarted. If you are not able to restart the kernel, you will still be able to save the notebook, but running code will no longer work until the notebook is reopened."
-msgstr "内核已经死亡,自动重启也失败了。有可能内核不能重新启动。如果您不能重新启动内核,您仍然能够保存笔记本,但是运行代码将不再工作,直到笔记本重新打开. "
+msgstr "内核已经死亡,自动重启也失败了。可能是内核不能重新启动。如果您不能重新启动内核,您仍然能够保存笔记本,但笔记本要重新打开才能运行代码。"
#: notebook/static/notebook/js/notificationarea.js:224
msgid "No Kernel"
-msgstr "没有服务"
+msgstr "没有内核"
#: notebook/static/notebook/js/notificationarea.js:251
msgid "Failed to start the kernel"
-msgstr "启动服务失败"
+msgstr "启动内核失败"
#: notebook/static/notebook/js/notificationarea.js:271
#: notebook/static/notebook/js/notificationarea.js:291
#: notebook/static/notebook/js/notificationarea.js:305
msgid "Kernel Busy"
-msgstr "服务正忙"
+msgstr "内核正忙"
#: notebook/static/notebook/js/notificationarea.js:272
msgid "Kernel starting, please wait..."
-msgstr "服务正在启动,请等待..."
+msgstr "内核正在启动,请等待..."
#: notebook/static/notebook/js/notificationarea.js:278
#: notebook/static/notebook/js/notificationarea.js:285
msgid "Kernel Idle"
-msgstr "服务空闲"
+msgstr "内核空闲"
#: notebook/static/notebook/js/notificationarea.js:279
msgid "Kernel ready"
-msgstr "服务准备好了"
+msgstr "内核就绪"
#: notebook/static/notebook/js/notificationarea.js:296
msgid "Using kernel: "
-msgstr "使用服务:"
+msgstr "使用内核:"
#: notebook/static/notebook/js/notificationarea.js:297
msgid "Only candidate for language: %1$s was %2$s."
-msgstr "只支持语言: %1$s - %2$s."
+msgstr "只支持语言: %1$s - %2$s."
#: notebook/static/notebook/js/notificationarea.js:318
msgid "Loading notebook"
-msgstr "加载服务"
+msgstr "加载笔记本"
#: notebook/static/notebook/js/notificationarea.js:321
msgid "Notebook loaded"
-msgstr "程序已加载"
+msgstr "笔记本已加载"
#: notebook/static/notebook/js/notificationarea.js:324
msgid "Saving notebook"
-msgstr "保存代码"
+msgstr "保存笔记本"
#: notebook/static/notebook/js/notificationarea.js:327
msgid "Notebook saved"
-msgstr "代码已保存"
+msgstr "笔记本已保存"
#: notebook/static/notebook/js/notificationarea.js:330
msgid "Notebook save failed"
-msgstr "代码保存失败"
+msgstr "笔记本保存失败"
#: notebook/static/notebook/js/notificationarea.js:333
msgid "Notebook copy failed"
-msgstr "代码复制失败"
+msgstr "笔记本复制失败"
#: notebook/static/notebook/js/notificationarea.js:338
msgid "Checkpoint created"
-msgstr "checkpoint已创建"
+msgstr "检查点已创建"
#: notebook/static/notebook/js/notificationarea.js:346
msgid "Checkpoint failed"
-msgstr "Checkpoint 失败"
+msgstr "检查点创建失败"
#: notebook/static/notebook/js/notificationarea.js:349
msgid "Checkpoint deleted"
-msgstr "checkpoint已删除"
+msgstr "检查点已删除"
#: notebook/static/notebook/js/notificationarea.js:352
msgid "Checkpoint delete failed"
-msgstr "checkpoint删除失败"
+msgstr "检查点删除失败"
#: notebook/static/notebook/js/notificationarea.js:355
msgid "Restoring to checkpoint..."
-msgstr "重新保存checkpoint..."
+msgstr "正在恢复至检查点..."
#: notebook/static/notebook/js/notificationarea.js:358
msgid "Checkpoint restore failed"
-msgstr "checkpoint 重新保存失败"
+msgstr "检查点恢复失败"
#: notebook/static/notebook/js/notificationarea.js:363
msgid "Autosave disabled"
@@ -1192,11 +1192,11 @@
#: notebook/static/notebook/js/notificationarea.js:366
#, python-format
msgid "Saving every %d sec."
-msgstr "每隔 %s 秒保存一次."
+msgstr "每隔 %s 秒保存一次。"
#: notebook/static/notebook/js/notificationarea.js:382
msgid "Trusted"
-msgstr "可信的"
+msgstr "可信"
#: notebook/static/notebook/js/notificationarea.js:384
msgid "Not Trusted"
@@ -1204,49 +1204,49 @@
#: notebook/static/notebook/js/outputarea.js:85
msgid "click to expand output"
-msgstr "点击展开内容"
+msgstr "点击展开输出"
#: notebook/static/notebook/js/outputarea.js:89
msgid "click to expand output; double click to hide output"
-msgstr "点击展开输出; 双击隐藏"
+msgstr "点击展开输出;双击隐藏输出"
#: notebook/static/notebook/js/outputarea.js:177
msgid "click to unscroll output; double click to hide"
-msgstr "单击显示输出; 双击隐藏"
+msgstr "单击取消滚动输出;双击隐藏"
#: notebook/static/notebook/js/outputarea.js:184
msgid "click to scroll output; double click to hide"
-msgstr "点击滚动输出;双击隐藏"
+msgstr "点击滚动输出;双击隐藏"
#: notebook/static/notebook/js/outputarea.js:434
msgid "Javascript error adding output!"
-msgstr "Javascript添加输出错误!"
+msgstr "添加输出时 Javascript 出错了!"
#: notebook/static/notebook/js/outputarea.js:439
msgid "See your browser Javascript console for more details."
-msgstr "更多细节请参见您的浏览器Javascript控制台。"
+msgstr "更多细节请参见您的浏览器 Javascript 控制台。"
#: notebook/static/notebook/js/outputarea.js:480
#, python-format
msgid "Out[%d]:"
-msgstr "输出[%d]:"
+msgstr ""
#: notebook/static/notebook/js/outputarea.js:589
#, python-format
msgid "Unrecognized output: %s"
-msgstr "未识别的输出: %s"
+msgstr "未识别的输出: %s"
#: notebook/static/notebook/js/pager.js:36
msgid "Open the pager in an external window"
-msgstr "在内部窗口打开页面"
+msgstr "在外部窗口打开分页器"
#: notebook/static/notebook/js/pager.js:45
msgid "Close the pager"
-msgstr "关闭页面"
+msgstr "关闭分页器"
#: notebook/static/notebook/js/pager.js:148
msgid "Jupyter Pager"
-msgstr "Jupyter 页面"
+msgstr "Jupyter 分页器"
#: notebook/static/notebook/js/quickhelp.js:39
#: notebook/static/notebook/js/quickhelp.js:54
@@ -1263,12 +1263,12 @@
#: notebook/static/notebook/js/quickhelp.js:41
#: notebook/static/notebook/js/quickhelp.js:58
msgid "go one word left"
-msgstr "跳到单词左边"
+msgstr "往左跳一个单词"
#: notebook/static/notebook/js/quickhelp.js:42
#: notebook/static/notebook/js/quickhelp.js:59
msgid "go one word right"
-msgstr "跳到单词右边"
+msgstr "往右跳一个单词"
#: notebook/static/notebook/js/quickhelp.js:43
#: notebook/static/notebook/js/quickhelp.js:60
@@ -1292,19 +1292,19 @@
#: notebook/static/notebook/js/quickhelp.js:47
msgid "emacs-style line kill"
-msgstr ""
+msgstr "Emacs 风格的 Line Kill"
#: notebook/static/notebook/js/quickhelp.js:48
msgid "delete line left of cursor"
-msgstr "删除光标左边线"
+msgstr "删除光标左边一行"
#: notebook/static/notebook/js/quickhelp.js:49
msgid "delete line right of cursor"
-msgstr ""
+msgstr "删除光标右边一行"
#: notebook/static/notebook/js/quickhelp.js:68
msgid "code completion or indent"
-msgstr "代码完成或缩进"
+msgstr "代码补全或缩进"
#: notebook/static/notebook/js/quickhelp.js:69
msgid "tooltip"
@@ -1328,7 +1328,7 @@
#: notebook/static/notebook/js/quickhelp.js:74
msgid "comment"
-msgstr "评论"
+msgstr "注释"
#: notebook/static/notebook/js/quickhelp.js:75
msgid "delete whole line"
@@ -1340,7 +1340,7 @@
#: notebook/static/notebook/js/quickhelp.js:77
msgid "toggle overwrite flag"
-msgstr "切换 重写标志"
+msgstr "切换重写标志"
#: notebook/static/notebook/js/quickhelp.js:111
#: notebook/static/notebook/js/quickhelp.js:252
@@ -1374,7 +1374,7 @@
#: notebook/static/notebook/js/quickhelp.js:118
msgid "Caps Lock"
-msgstr "Caps Lock"
+msgstr "大写锁定"
#: notebook/static/notebook/js/quickhelp.js:119
#: notebook/static/notebook/js/quickhelp.js:278
@@ -1414,7 +1414,7 @@
#: notebook/static/notebook/js/quickhelp.js:127
msgid "Backspace"
-msgstr "删除"
+msgstr "退格"
#: notebook/static/notebook/js/quickhelp.js:128
msgid "Minus"
@@ -1426,15 +1426,15 @@
#: notebook/static/notebook/js/quickhelp.js:206
msgid "The Jupyter Notebook has two different keyboard input modes."
-msgstr "Jupyter笔记本有两种不同的键盘输入模式."
+msgstr "Jupyter 笔记本有两种不同的键盘输入模式。"
#: notebook/static/notebook/js/quickhelp.js:208
msgid "Edit mode allows you to type code or text into a cell and is indicated by a green cell border."
-msgstr "编辑模式允许您将代码或文本输入到一个单元格中,并通过一个绿色的单元格来表示"
+msgstr "编辑模式允许您将代码或文本输入到一个单元格中,并通过一个绿色边框的单元格来表示"
#: notebook/static/notebook/js/quickhelp.js:210
msgid "Command mode binds the keyboard to notebook level commands and is indicated by a grey cell border with a blue left margin."
-msgstr "命令模式将键盘与笔记本级命令绑定在一起,并通过一个灰色的单元格边界显示,该边框为蓝色的左边框。"
+msgstr "命令模式将键盘与笔记本级命令绑定在一起,并通过一个灰框、左边距蓝色的单元格显示。"
#: notebook/static/notebook/js/quickhelp.js:231
#: notebook/static/notebook/js/tooltip.js:58
@@ -1444,7 +1444,7 @@
#: notebook/static/notebook/js/quickhelp.js:234
msgid "Keyboard shortcuts"
-msgstr "快捷键"
+msgstr "键盘快捷键"
#: notebook/static/notebook/js/quickhelp.js:249
msgid "Command"
@@ -1465,7 +1465,7 @@
#: notebook/static/notebook/js/quickhelp.js:279
#, python-format
msgid "Command Mode (press %s to enable)"
-msgstr "命令行模式(按 %s 生效)"
+msgstr "命令行模式(按 %s 生效)"
#: notebook/static/notebook/js/quickhelp.js:281
msgid "Edit Shortcuts"
@@ -1473,16 +1473,16 @@
#: notebook/static/notebook/js/quickhelp.js:284
msgid "edit command-mode keyboard shortcuts"
-msgstr "编辑命令行快捷键"
+msgstr "编辑命令模式键盘快捷键"
#: notebook/static/notebook/js/quickhelp.js:301
#, python-format
msgid "Edit Mode (press %s to enable)"
-msgstr "编辑模式(按 %s 生效)"
+msgstr "编辑模式(按 %s 生效)"
#: notebook/static/notebook/js/savewidget.js:49
msgid "Autosave Failed!"
-msgstr "自动保存失败!"
+msgstr "自动保存失败!"
#: notebook/static/notebook/js/savewidget.js:71
#: notebook/static/tree/js/notebooklist.js:850
@@ -1493,19 +1493,19 @@
#: notebook/static/notebook/js/savewidget.js:78
#: notebook/static/tree/js/notebooklist.js:841
msgid "Enter a new notebook name:"
-msgstr "请输入代码名称:"
+msgstr "请输入新的笔记本名称:"
#: notebook/static/notebook/js/savewidget.js:86
msgid "Rename Notebook"
-msgstr "重命名"
+msgstr "重命名笔记本"
#: notebook/static/notebook/js/savewidget.js:98
msgid "Invalid notebook name. Notebook names must have 1 or more characters and can contain any characters except :/\\. Please enter a new notebook name:"
-msgstr "无效的文件名. 代码名不能为空 并且不能包含\".\" 请输入一个新的文件名:"
+msgstr "无效的笔记本名称。笔记本名称不能为空,并且不能包含\":/.\"。请输入一个新的笔记本名称:"
#: notebook/static/notebook/js/savewidget.js:103
msgid "Renaming..."
-msgstr "正在重命名..."
+msgstr "正在重命名…"
#: notebook/static/notebook/js/savewidget.js:109
msgid "Unknown error"
@@ -1518,20 +1518,20 @@
#: notebook/static/notebook/js/savewidget.js:193
#, python-format
msgid "Last Checkpoint: %s"
-msgstr "最后检查: %s "
+msgstr "最新检查点: %s "
#: notebook/static/notebook/js/savewidget.js:217
msgid "(unsaved changes)"
-msgstr "(未保存改变)"
+msgstr "(更改未保存)"
#: notebook/static/notebook/js/savewidget.js:219
msgid "(autosaved)"
-msgstr "(自动保存)"
+msgstr "(已自动保存)"
#: notebook/static/notebook/js/searchandreplace.js:71
#, python-format
msgid "Warning: too many matches (%d). Some changes might not be shown or applied."
-msgstr "警告:太多的匹配(%d). 有些更改可能不会被显示或应用."
+msgstr "警告:太多的匹配(%d)。有些更改可能不会被显示或应用."
#: notebook/static/notebook/js/searchandreplace.js:74
#, python-format
@@ -1542,11 +1542,11 @@
#: notebook/static/notebook/js/searchandreplace.js:141
msgid "More than 100 matches, aborting"
-msgstr "超过100个匹配, 中止"
+msgstr "超过 100 个匹配, 中止"
#: notebook/static/notebook/js/searchandreplace.js:161
msgid "Use regex (JavaScript regex syntax)"
-msgstr ""
+msgstr "使用正则表达式(JavaScript 正则表达式语法)"
#: notebook/static/notebook/js/searchandreplace.js:169
msgid "Replace in selected cells"
@@ -1554,7 +1554,7 @@
#: notebook/static/notebook/js/searchandreplace.js:176
msgid "Match case"
-msgstr "匹配"
+msgstr "匹配大小写"
#: notebook/static/notebook/js/searchandreplace.js:182
msgid "Find"
@@ -1566,11 +1566,11 @@
#: notebook/static/notebook/js/searchandreplace.js:244
msgid "No matches, invalid or empty regular expression"
-msgstr "没匹配到, 无效或空的正则表达式"
+msgstr "无匹配,表达式无效或表达式为空"
#: notebook/static/notebook/js/searchandreplace.js:348
msgid "Replace All"
-msgstr "替换所有"
+msgstr "全部替换"
#: notebook/static/notebook/js/searchandreplace.js:352
msgid "Find and Replace"
@@ -1583,27 +1583,27 @@
#: notebook/static/notebook/js/textcell.js:559
msgid "Write raw LaTeX or other formats here, for use with nbconvert. It will not be rendered in the notebook. When passing through nbconvert, a Raw Cell's content is added to the output unmodified."
-msgstr ""
+msgstr "在这里直接写 LaTeX 或者其它格式的文本来配合 nbconvert。笔记本不会渲染它。传给 nbconvert 时,原始单元格的内容会被完好地加进输出。"
#: notebook/static/notebook/js/tooltip.js:41
msgid "Grow the tooltip vertically (press shift-tab twice)"
-msgstr ""
+msgstr "纵向展开工具提示(按两次 Shift+Tab)"
#: notebook/static/notebook/js/tooltip.js:48
msgid "show the current docstring in pager (press shift-tab 4 times)"
-msgstr ""
+msgstr "在分页器中显示当前的文档字符串(按四次 Shift+Tab)"
#: notebook/static/notebook/js/tooltip.js:49
msgid "Open in Pager"
-msgstr ""
+msgstr "在分页器中打开"
#: notebook/static/notebook/js/tooltip.js:68
msgid "Tooltip will linger for 10 seconds while you type"
-msgstr ""
+msgstr "当您键入时,工具提示会停留十秒"
#: notebook/static/notebook/js/tour.js:27
msgid "Welcome to the Notebook Tour"
-msgstr "欢迎使用Notebook"
+msgstr "欢迎来到 Notebook 导览"
#: notebook/static/notebook/js/tour.js:30
msgid "You can use the left and right arrow keys to go backwards and forwards."
@@ -1615,19 +1615,19 @@
#: notebook/static/notebook/js/tour.js:35
msgid "Click here to change the filename for this notebook."
-msgstr "点击改变代码文件名"
+msgstr "点击这里修改笔记本的文件名"
#: notebook/static/notebook/js/tour.js:39
msgid "Notebook Menubar"
-msgstr "菜单栏"
+msgstr "笔记本菜单栏"
#: notebook/static/notebook/js/tour.js:40
msgid "The menubar has menus for actions on the notebook, its cells, and the kernel it communicates with."
-msgstr "菜单栏操作界面, 它的单元格和它与之通信的内核上进行操作. "
+msgstr "菜单栏上的菜单可以用来操作笔记本、单元格和与笔记本通信的内核。"
#: notebook/static/notebook/js/tour.js:44
msgid "Notebook Toolbar"
-msgstr "代码工具栏"
+msgstr "笔记本工具栏"
#: notebook/static/notebook/js/tour.js:45
msgid "The toolbar has buttons for the most common actions. Hover your mouse over each button for more information."
@@ -1639,35 +1639,35 @@
#: notebook/static/notebook/js/tour.js:50
msgid "The Notebook has two modes: Edit Mode and Command Mode. In this area, an indicator can appear to tell you which mode you are in."
-msgstr "该笔记本有两种模式:编辑模式和命令模式. 在这个区域, 一个指示器可以显示你在哪个模式. "
+msgstr "笔记本有两种模式:编辑模式和命令模式。在这个区域,一个指示器可以显示你在哪个模式。"
#: notebook/static/notebook/js/tour.js:58
msgid "Right now you are in Command Mode, and many keyboard shortcuts are available. In this mode, no icon is displayed in the indicator area."
-msgstr "现在你处于命令模式, 许多快捷键都可以使用. 在该模式下, 指示区域中没有显示图标."
+msgstr "现在你处于命令模式,许多快捷键都可以使用。在该模式下,指示区域中没有显示图标。"
#: notebook/static/notebook/js/tour.js:64
msgid "Pressing Enter
or clicking in the input text area of the cell switches to Edit Mode."
-msgstr "按下Enter
, 或者点击输入文本区域, 将你返回到命令模式. "
+msgstr "按下Enter
或者点击输入文本区域来切换到编辑模式. "
#: notebook/static/notebook/js/tour.js:70
msgid "Notice that the border around the currently active cell changed color. Typing will insert text into the currently active cell."
-msgstr "请注意, 当前活动单元周围的边框改变了颜色. 键入将在当前活动单元中插入文本."
+msgstr "您会发现当前活动单元格周围的边框改变了颜色。键入将在当前活动单元格中插入文本."
#: notebook/static/notebook/js/tour.js:73
msgid "Back to Command Mode"
-msgstr "转到命令模式"
+msgstr "回到命令模式"
#: notebook/static/notebook/js/tour.js:76
msgid "Pressing Esc
or clicking outside of the input text area takes you back to Command Mode."
-msgstr "按下Esc
, 或者点击输入文本区域, 将你返回到命令模式. "
+msgstr "按下Esc
或者点击输入框外面来返回到命令模式。"
#: notebook/static/notebook/js/tour.js:79
msgid "Keyboard Shortcuts"
-msgstr "快捷键"
+msgstr "键盘快捷键"
#: notebook/static/notebook/js/tour.js:91
msgid "You can click here to get a list of all of the keyboard shortcuts."
-msgstr "点击获得所有快捷键"
+msgstr "点击这里获得所有键盘快捷键"
#: notebook/static/notebook/js/tour.js:94
#: notebook/static/notebook/js/tour.js:100
@@ -1688,7 +1688,7 @@
#: notebook/static/notebook/js/tour.js:109
msgid "To cancel a computation in progress, you can click here."
-msgstr "要取消正在进行的计算,您可以点击这里。"
+msgstr "要取消正在进行的计算任务,您可以点击这里。"
#: notebook/static/notebook/js/tour.js:114
msgid "Notification Area"
@@ -1696,15 +1696,15 @@
#: notebook/static/notebook/js/tour.js:115
msgid "Messages in response to user actions (Save, Interrupt, etc.) appear here."
-msgstr "响应用户操作(保存, 中断等)的消息出现在这里."
+msgstr "响应用户操作(保存,中断等)的消息出现在这里。"
#: notebook/static/notebook/js/tour.js:117
msgid "End of Tour"
-msgstr "结束"
+msgstr "结束导览"
#: notebook/static/notebook/js/tour.js:120
msgid "This concludes the Jupyter Notebook User Interface Tour."
-msgstr "这就结束了Jupyter笔记本用户界面之旅。"
+msgstr "Jupyter 笔记本用户界面之旅到此为止。"
#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:32
msgid "Edit Attachments"
@@ -1721,23 +1721,23 @@
#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:22
msgid "Custom"
-msgstr ""
+msgstr "自定义"
#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:32
msgid "Set the MIME type of the raw cell:"
-msgstr ""
+msgstr "设置原始单元格的 MIME 类型:"
#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:40
msgid "Raw Cell MIME Type"
-msgstr ""
+msgstr "原始单元格的 MIME 类型"
#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:74
msgid "Raw NBConvert Format"
-msgstr ""
+msgstr "原始 NBConvert 类型"
#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:81
msgid "Raw Cell Format"
-msgstr ""
+msgstr "原始单元格格式"
#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:15
msgid "Slide"
@@ -1761,7 +1761,7 @@
#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:35
msgid "Slide Type"
-msgstr "类型"
+msgstr "幻灯片类型"
#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:41
msgid "Slideshow"
@@ -1773,15 +1773,15 @@
#: notebook/static/notebook/js/celltoolbarpresets/tags.js:163
msgid "Edit the list of tags below. All whitespace is treated as tag separators."
-msgstr "编辑下面的标签列表. 所有空格都被当作标记分隔符."
+msgstr "编辑下面的标签列表。所有空格都被当作标记分隔符。"
#: notebook/static/notebook/js/celltoolbarpresets/tags.js:172
msgid "Edit the tags"
-msgstr "编辑tags"
+msgstr "编辑标签"
#: notebook/static/notebook/js/celltoolbarpresets/tags.js:186
msgid "Edit Tags"
-msgstr "编辑tags"
+msgstr "编辑标签"
#: notebook/static/tree/js/kernellist.js:86
#: notebook/static/tree/js/terminallist.js:105
@@ -1791,11 +1791,11 @@
#: notebook/static/tree/js/newnotebook.js:70
#, python-format
msgid "Create a new notebook with %s"
-msgstr "创建新的代码 %s"
+msgstr "创建新的笔记本 %s"
#: notebook/static/tree/js/newnotebook.js:101
msgid "An error occurred while creating a new notebook."
-msgstr "当创建新的notebook的时候出现一个错误."
+msgstr "创建新笔记本时出错。"
#: notebook/static/tree/js/notebooklist.js:154
msgid "Creating File Failed"
@@ -1803,7 +1803,7 @@
#: notebook/static/tree/js/notebooklist.js:156
msgid "An error occurred while creating a new file."
-msgstr "创建新文件的时候出现了一个错误"
+msgstr "创建新文件时出错。"
#: notebook/static/tree/js/notebooklist.js:174
msgid "Creating Folder Failed"
@@ -1811,7 +1811,7 @@
#: notebook/static/tree/js/notebooklist.js:176
msgid "An error occurred while creating a new folder."
-msgstr "创建新文件夹的时候出现了一个错误."
+msgstr "创建新文件夹时出错。"
#: notebook/static/tree/js/notebooklist.js:271
msgid "Failed to read file"
@@ -1820,13 +1820,13 @@
#: notebook/static/tree/js/notebooklist.js:272
#, python-format
msgid "Failed to read file %s"
-msgstr "读取代码文件 %s 失败了."
+msgstr "读取文件 %s 失败了"
#: notebook/static/tree/js/notebooklist.js:283
#, python-format
msgid "The file size is %d MB. Do you still want to upload it?"
-msgstr "文件大小为 %d MB, 还想上传么?"
+msgstr "文件大小为 %d MB,依然上传?"
#: notebook/static/tree/js/notebooklist.js:286
@@ -1836,16 +1836,16 @@
#: notebook/static/tree/js/notebooklist.js:355
msgid "Server error: "
-msgstr "服务出现错误:"
+msgstr "服务出现错误:"
#: notebook/static/tree/js/notebooklist.js:380
msgid "The notebook list is empty."
-msgstr "代码列表为空, 请添加代码."
+msgstr "笔记本列表为空。"
#: notebook/static/tree/js/notebooklist.js:453
msgid "Click here to rename, delete, etc."
-msgstr "点击进行操作."
+msgstr "点击这里进行重命名或删除等操作"
#: notebook/static/tree/js/notebooklist.js:493
@@ -1854,17 +1854,17 @@
#: notebook/static/tree/js/notebooklist.js:839
msgid "Enter a new file name:"
-msgstr "请输入一个新的文件名:"
+msgstr "请输入一个新的文件名:"
#: notebook/static/tree/js/notebooklist.js:840
msgid "Enter a new directory name:"
-msgstr "请输入一个新的路径:"
+msgstr "请输入一个新的路径:"
#: notebook/static/tree/js/notebooklist.js:842
msgid "Enter a new name:"
-msgstr "请输入新名字:"
+msgstr "请输入新名字:"
#: notebook/static/tree/js/notebooklist.js:847
@@ -1878,7 +1878,7 @@
#: notebook/static/tree/js/notebooklist.js:849
msgid "Rename notebook"
-msgstr "重命名"
+msgstr "重命名笔记本"
#: notebook/static/tree/js/notebooklist.js:863
msgid "Move"
@@ -1896,15 +1896,15 @@
#, python-format
msgid "Enter a new destination directory path for this item:"
msgid_plural "Enter a new destination directory path for these %d items:"
-msgstr[0] "为代码选择一个新的路径:"
-msgstr[1] "为选中的 %d 代码选择一个新的路径:"
+msgstr[0] "为笔记本选择一个新的路径:"
+msgstr[1] "为选中的 %d 笔记本选择一个新的路径:"
#: notebook/static/tree/js/notebooklist.js:944
#, python-format
msgid "Move an Item"
msgid_plural "Move %d Items"
-msgstr[0] "移动一个代码文件"
-msgstr[1] "移动 %d 个代码文件"
+msgstr[0] "移动一个文件"
+msgstr[1] "移动 %d 个文件"
#: notebook/static/tree/js/notebooklist.js:963
msgid "An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\"."
@@ -1918,13 +1918,13 @@
#, python-format
msgid "Are you sure you want to permanently delete: \"%s\"?"
msgid_plural "Are you sure you want to permanently delete the %d files or folders selected?"
-msgstr[0] "删除不可恢复: \"%s\", 确定删除?"
-msgstr[1] "删除不可恢复: 选择 %d 文件, 确定删除?"
+msgstr[0] "确定永久删除 \"%s\"?"
+msgstr[1] "确定永久删除选中的 %d 个文件或文件夹?"
#: notebook/static/tree/js/notebooklist.js:1039
#, python-format
msgid "An error occurred while deleting \"%s\"."
-msgstr "当删除 \"%s\" 时, 出现错误."
+msgstr "当删除 \"%s\" 时, 出现错误。"
#: notebook/static/tree/js/notebooklist.js:1041
msgid "Delete Failed"
@@ -1934,21 +1934,21 @@
#, python-format
msgid "Are you sure you want to duplicate: \"%s\"?"
msgid_plural "Are you sure you want to duplicate the %d files selected?"
-msgstr[0] "确定复制: \"%s\"?"
-msgstr[1] "确定复制: 已选择 %d 文件?"
+msgstr[0] "确定制作 \"%s\" 的副本?"
+msgstr[1] "确定制作选中的 %d 个文件的副本?"
#: notebook/static/tree/js/notebooklist.js:1089
msgid "Duplicate"
-msgstr "复制"
+msgstr "制作副本"
#: notebook/static/tree/js/notebooklist.js:1103
#, python-format
msgid "An error occurred while duplicating \"%s\"."
-msgstr "当复制\"%s\" 时出现错误."
+msgstr "制作 \"%s\" 的副本时出现错误。"
#: notebook/static/tree/js/notebooklist.js:1105
msgid "Duplicate Failed"
-msgstr "复制失败"
+msgstr "制作副本失败"
#: notebook/static/tree/js/notebooklist.js:1325
msgid "Upload"
@@ -1964,12 +1964,12 @@
#: notebook/static/tree/js/notebooklist.js:1364
msgid "Cannot upload invalid Notebook"
-msgstr "无法上传无效的Notebook"
+msgstr "无法上传无效的笔记本"
#: notebook/static/tree/js/notebooklist.js:1397
#, python-format
msgid "There is already a file named \"%s\". Do you want to replace it?"
-msgstr "文件名已经存在 \"%s\", 需要替换现有文件?"
+msgstr "已经存在一个名为 \"%s\" 的文件,替换现有文件?"
#: notebook/static/tree/js/notebooklist.js:1399
msgid "Replace file"
diff -Nru jupyter-notebook-6.1.4/notebook/jstest.py jupyter-notebook-6.2.0/notebook/jstest.py
--- jupyter-notebook-6.1.4/notebook/jstest.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/jstest.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
"""Notebook Javascript Test Controller
This module runs one or more subprocesses which will actually run the Javascript
@@ -8,8 +7,6 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
-from __future__ import absolute_import, print_function
-
import argparse
import json
import multiprocessing.pool
@@ -45,7 +42,7 @@
daemon = True # Don't hang if main thread crashes
started = False
def __init__(self, echo=False):
- super(StreamCapturer, self).__init__()
+ super().__init__()
self.echo = echo
self.streams = []
self.buffer = BytesIO()
@@ -264,14 +261,14 @@
# If the engine is SlimerJS, we need to buffer the output because
# SlimerJS does not support exit codes, so CasperJS always returns 0.
if self.engine == 'slimerjs' and not buffer_output:
- return super(JSController, self).launch(capture_output=True)
+ return super().launch(capture_output=True)
else:
- return super(JSController, self).launch(buffer_output=buffer_output)
+ return super().launch(buffer_output=buffer_output)
def wait(self, *pargs, **kwargs):
"""Wait for the JSController to finish"""
- ret = super(JSController, self).wait(*pargs, **kwargs)
+ ret = super().wait(*pargs, **kwargs)
# If this is a SlimerJS controller, check the captured stdout for
# errors. Otherwise, just return the return code.
if self.engine == 'slimerjs':
diff -Nru jupyter-notebook-6.1.4/notebook/log.py jupyter-notebook-6.2.0/notebook/log.py
--- jupyter-notebook-6.1.4/notebook/log.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/log.py 2021-01-13 16:30:49.000000000 +0000
@@ -10,7 +10,7 @@
from .prometheus.log_functions import prometheus_log_method
-def log_request(handler):
+def log_request(handler, log=access_log, log_json=False):
"""log a bit more information about each request than tornado's default
- move static file get success to debug-level (reduces noise)
@@ -22,29 +22,35 @@
request = handler.request
if status < 300 or status == 304:
# Successes (or 304 FOUND) are debug-level
- log_method = access_log.debug
+ log_method = log.debug
elif status < 400:
- log_method = access_log.info
+ log_method = log.info
elif status < 500:
- log_method = access_log.warning
+ log_method = log.warning
else:
- log_method = access_log.error
+ log_method = log.error
- request_time = 1000.0 * handler.request.request_time()
+ request_time = 1000.0 * request.request_time()
ns = dict(
status=status,
method=request.method,
ip=request.remote_ip,
uri=request.uri,
- request_time=request_time,
+ request_time=float('%.2f' % request_time),
)
- msg = "{status} {method} {uri} ({ip}) {request_time:.2f}ms"
+ msg = "{status} {method} {uri} ({ip}) {request_time:f}ms"
if status >= 400:
# log bad referers
ns['referer'] = request.headers.get('Referer', 'None')
msg = msg + ' referer={referer}'
if status >= 500 and status != 502:
# log all headers if it caused an error
- log_method(json.dumps(dict(request.headers), indent=2))
- log_method(msg.format(**ns))
+ if log_json:
+ log_method("", extra=dict(props=dict(request.headers)))
+ else:
+ log_method(json.dumps(dict(request.headers), indent=2))
+ if log_json:
+ log_method("", extra=dict(props=ns))
+ else:
+ log_method(msg.format(**ns))
prometheus_log_method(handler)
diff -Nru jupyter-notebook-6.1.4/notebook/__main__.py jupyter-notebook-6.2.0/notebook/__main__.py
--- jupyter-notebook-6.1.4/notebook/__main__.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/__main__.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
if __name__ == '__main__':
from notebook import notebookapp as app
diff -Nru jupyter-notebook-6.1.4/notebook/nbconvert/handlers.py jupyter-notebook-6.2.0/notebook/nbconvert/handlers.py
--- jupyter-notebook-6.1.4/notebook/nbconvert/handlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/nbconvert/handlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -83,8 +83,7 @@
def content_security_policy(self):
# In case we're serving HTML/SVG, confine any Javascript to a unique
# origin so it can't interact with the notebook server.
- return super(NbconvertFileHandler, self).content_security_policy + \
- "; sandbox allow-scripts"
+ return super().content_security_policy + "; sandbox allow-scripts"
@web.authenticated
@gen.coroutine
@@ -158,8 +157,7 @@
def content_security_policy(self):
# In case we're serving HTML/SVG, confine any Javascript to a unique
# origin so it can't interact with the notebook server.
- return super(NbconvertPostHandler, self).content_security_policy + \
- "; sandbox allow-scripts"
+ return super().content_security_policy + "; sandbox allow-scripts"
@web.authenticated
def post(self, format):
diff -Nru jupyter-notebook-6.1.4/notebook/nbconvert/tests/test_nbconvert_handlers.py jupyter-notebook-6.2.0/notebook/nbconvert/tests/test_nbconvert_handlers.py
--- jupyter-notebook-6.1.4/notebook/nbconvert/tests/test_nbconvert_handlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/nbconvert/tests/test_nbconvert_handlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# coding: utf-8
import io
import json
import os
diff -Nru jupyter-notebook-6.1.4/notebook/nbextensions.py jupyter-notebook-6.2.0/notebook/nbextensions.py
--- jupyter-notebook-6.1.4/notebook/nbextensions.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/nbextensions.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,11 +1,8 @@
-# coding: utf-8
"""Utilities for installing Javascript extensions for the notebook"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
-from __future__ import print_function
-
import os
import shutil
import sys
@@ -980,7 +977,7 @@
def start(self):
"""Perform the App's functions as configured"""
- super(NBExtensionApp, self).start()
+ super().start()
# The above should have called a subcommand and raised NoStart; if we
# get here, it didn't, so we should self.log.info a message.
diff -Nru jupyter-notebook-6.1.4/notebook/notebookapp.py jupyter-notebook-6.2.0/notebook/notebookapp.py
--- jupyter-notebook-6.1.4/notebook/notebookapp.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/notebookapp.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,16 +1,14 @@
-# coding: utf-8
"""A tornado based Jupyter notebook server."""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
-from __future__ import absolute_import, print_function
-
import notebook
import asyncio
import binascii
import datetime
import errno
+import functools
import gettext
import hashlib
import hmac
@@ -190,7 +188,7 @@
if settings['autoreload']:
log.info('Autoreload enabled: the webapp will restart when any Python src file changes.')
- super(NotebookWebApplication, self).__init__(handlers, **settings)
+ super().__init__(handlers, **settings)
def init_settings(self, jupyter_app, kernel_manager, contents_manager,
session_manager, kernel_spec_manager,
@@ -250,9 +248,12 @@
# collapse $HOME to ~
root_dir = '~' + root_dir[len(home):]
+ # Use the NotebookApp logger and its formatting for tornado request logging.
+ log_function = functools.partial(
+ log_request, log=log, log_json=jupyter_app.log_json)
settings = dict(
# basics
- log_function=log_request,
+ log_function=log_function,
base_url=base_url,
default_url=default_url,
template_path=template_path,
@@ -282,6 +283,7 @@
disable_check_xsrf=jupyter_app.disable_check_xsrf,
allow_remote_access=jupyter_app.allow_remote_access,
local_hostnames=jupyter_app.local_hostnames,
+ authenticate_prometheus=jupyter_app.authenticate_prometheus,
# managers
kernel_manager=kernel_manager,
@@ -511,7 +513,7 @@
help="UNIX socket of the server to be killed.")
def parse_command_line(self, argv=None):
- super(NbserverStopApp, self).parse_command_line(argv)
+ super().parse_command_line(argv)
if self.extra_args:
try:
self.port = int(self.extra_args[0])
@@ -704,6 +706,43 @@
_log_formatter_cls = LogFormatter
+ _json_logging_import_error_logged = False
+
+ log_json = Bool(False, config=True,
+ help=_('Set to True to enable JSON formatted logs. '
+ 'Run "pip install notebook[json-logging]" to install the '
+ 'required dependent packages. Can also be set using the '
+ 'environment variable JUPYTER_ENABLE_JSON_LOGGING=true.')
+ )
+
+ @default('log_json')
+ def _default_log_json(self):
+ """Get the log_json value from the environment."""
+ return os.getenv('JUPYTER_ENABLE_JSON_LOGGING', 'false').lower() == 'true'
+
+ @validate('log_json')
+ def _validate_log_json(self, proposal):
+ # If log_json=True, see if the json_logging package can be imported and
+ # override _log_formatter_cls if so.
+ value = proposal['value']
+ if value:
+ try:
+ import json_logging
+ self.log.debug('initializing json logging')
+ json_logging.init_non_web(enable_json=True)
+ self._log_formatter_cls = json_logging.JSONLogFormatter
+ except ImportError:
+ # If configured for json logs and we can't do it, log a hint.
+ # Only log the error once though.
+ if not self._json_logging_import_error_logged:
+ self.log.warning(
+ 'Unable to use json logging due to missing packages. '
+ 'Run "pip install notebook[json-logging]" to fix.'
+ )
+ self._json_logging_import_error_logged = True
+ value = False
+ return value
+
@default('log_level')
def _default_log_level(self):
return logging.INFO
@@ -1513,6 +1552,13 @@
is not available.
"""))
+ authenticate_prometheus = Bool(
+ True,
+ help=""""
+ Require authentication to access prometheus metrics.
+ """
+ ).tag(config=True)
+
# Since use of terminals is also a function of whether the terminado package is
# available, this variable holds the "final indication" of whether terminal functionality
# should be considered (particularly during shutdown/cleanup). It is enabled only
@@ -1523,7 +1569,7 @@
terminals_available = False
def parse_command_line(self, argv=None):
- super(NotebookApp, self).parse_command_line(argv)
+ super().parse_command_line(argv)
if self.extra_args:
arg0 = self.extra_args[0]
@@ -1962,6 +2008,8 @@
# ensure css, js are correct, which are required for pages to function
mimetypes.add_type('text/css', '.css')
mimetypes.add_type('application/javascript', '.js')
+ # for python <3.8
+ mimetypes.add_type('application/wasm', '.wasm')
def shutdown_no_activity(self):
"""Shutdown server on timeout when there are no kernels or terminals."""
@@ -1993,7 +2041,7 @@
def _init_asyncio_patch(self):
"""set default asyncio policy to be compatible with tornado
- Tornado 6 (at least) is not compatible with the default
+ Tornado <6.1 is not compatible with the default
asyncio implementation on Windows
Pick the older SelectorEventLoopPolicy on Windows
@@ -2006,7 +2054,7 @@
FIXME: if/when tornado supports the defaults in asyncio,
remove and bump tornado requirement for py38
"""
- if sys.platform.startswith("win") and sys.version_info >= (3, 8):
+ if sys.platform.startswith("win") and sys.version_info >= (3, 8) and tornado.version_info < (6, 1):
import asyncio
try:
from asyncio import (
@@ -2026,7 +2074,7 @@
def initialize(self, argv=None):
self._init_asyncio_patch()
- super(NotebookApp, self).initialize(argv)
+ super().initialize(argv)
self.init_logging()
if self._dispatching:
return
@@ -2192,7 +2240,7 @@
This method takes no arguments so all configuration and initialization
must be done prior to calling this method."""
- super(NotebookApp, self).start()
+ super().start()
if not self.allow_root:
# check if we are running as root, and abort if it's not allowed
diff -Nru jupyter-notebook-6.1.4/notebook/serverextensions.py jupyter-notebook-6.2.0/notebook/serverextensions.py
--- jupyter-notebook-6.1.4/notebook/serverextensions.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/serverextensions.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,11 +1,8 @@
-# coding: utf-8
"""Utilities for installing server extensions for the notebook"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
-from __future__ import print_function
-
import importlib
import sys
@@ -291,7 +288,7 @@
def start(self):
"""Perform the App's actions as configured"""
- super(ServerExtensionApp, self).start()
+ super().start()
# The above should have called a subcommand and raised NoStart; if we
# get here, it didn't, so we should self.log.info a message.
diff -Nru jupyter-notebook-6.1.4/notebook/services/config/tests/test_config_api.py jupyter-notebook-6.2.0/notebook/services/config/tests/test_config_api.py
--- jupyter-notebook-6.1.4/notebook/services/config/tests/test_config_api.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/config/tests/test_config_api.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Test the config webservice API."""
import json
diff -Nru jupyter-notebook-6.1.4/notebook/services/contents/fileio.py jupyter-notebook-6.2.0/notebook/services/contents/fileio.py
--- jupyter-notebook-6.1.4/notebook/services/contents/fileio.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/contents/fileio.py 2021-01-13 16:30:49.000000000 +0000
@@ -183,7 +183,7 @@
Classes using this mixin must provide the following attributes:
root_dir : unicode
- A directory against against which API-style paths are to be resolved.
+ A directory against which API-style paths are to be resolved.
log : logging.Logger
"""
diff -Nru jupyter-notebook-6.1.4/notebook/services/contents/filemanager.py jupyter-notebook-6.2.0/notebook/services/contents/filemanager.py
--- jupyter-notebook-6.1.4/notebook/services/contents/filemanager.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/contents/filemanager.py 2021-01-13 16:30:49.000000000 +0000
@@ -15,6 +15,7 @@
import nbformat
from send2trash import send2trash
+from send2trash.exceptions import TrashPermissionError
from tornado import web
from .filecheckpoints import FileCheckpoints
@@ -512,17 +513,6 @@
if not os.path.exists(os_path):
raise web.HTTPError(404, u'File or directory does not exist: %s' % os_path)
- def _check_trash(os_path):
- if sys.platform in {'win32', 'darwin'}:
- return True
-
- # It's a bit more nuanced than this, but until we can better
- # distinguish errors from send2trash, assume that we can only trash
- # files on the same partition as the home directory.
- file_dev = os.stat(os_path).st_dev
- home_dev = os.stat(os.path.expanduser('~')).st_dev
- return file_dev == home_dev
-
def is_non_empty_dir(os_path):
if os.path.isdir(os_path):
# A directory containing only leftover checkpoints is
@@ -538,16 +528,12 @@
# send2trash can really delete files on Windows, so disallow
# deleting non-empty files. See Github issue 3631.
raise web.HTTPError(400, u'Directory %s not empty' % os_path)
- if _check_trash(os_path):
+ try:
self.log.debug("Sending %s to trash", os_path)
- # Looking at the code in send2trash, I don't think the errors it
- # raises let us distinguish permission errors from other errors in
- # code. So for now, just let them all get logged as server errors.
send2trash(os_path)
return
- else:
- self.log.warning("Skipping trash for %s, on different device "
- "to home directory", os_path)
+ except TrashPermissionError as e:
+ self.log.warning("Skipping trash for %s, %s", os_path, e)
if os.path.isdir(os_path):
# Don't permanently delete non-empty directories.
diff -Nru jupyter-notebook-6.1.4/notebook/services/contents/largefilemanager.py jupyter-notebook-6.2.0/notebook/services/contents/largefilemanager.py
--- jupyter-notebook-6.1.4/notebook/services/contents/largefilemanager.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/contents/largefilemanager.py 2021-01-13 16:30:49.000000000 +0000
@@ -27,7 +27,7 @@
if chunk == 1:
self.log.debug("Saving %s", os_path)
self.run_pre_save_hook(model=model, path=path)
- super(LargeFileManager, self)._save_file(os_path, model['content'], model.get('format'))
+ super()._save_file(os_path, model['content'], model.get('format'))
else:
self._save_large_file(os_path, model['content'], model.get('format'))
except web.HTTPError:
@@ -43,7 +43,7 @@
self.run_post_save_hook(model=model, os_path=os_path)
return model
else:
- return super(LargeFileManager, self).save(model, path)
+ return super().save(model, path)
def _save_large_file(self, os_path, content, format):
"""Save content of a generic file."""
diff -Nru jupyter-notebook-6.1.4/notebook/services/contents/tests/test_contents_api.py jupyter-notebook-6.2.0/notebook/services/contents/tests/test_contents_api.py
--- jupyter-notebook-6.1.4/notebook/services/contents/tests/test_contents_api.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/contents/tests/test_contents_api.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Test the contents webservice API."""
from contextlib import contextmanager
@@ -13,6 +12,8 @@
pjoin = os.path.join
import requests
+from send2trash import send2trash
+from send2trash.exceptions import TrashPermissionError
from ..filecheckpoints import GenericFileCheckpoints
@@ -198,6 +199,14 @@
def isdir(self, api_path):
return os.path.isdir(self.to_os_path(api_path))
+ def can_send2trash(self, api_path):
+ """Send a path to trash, if possible. Return success."""
+ try:
+ send2trash(self.to_os_path(api_path))
+ return True
+ except TrashPermissionError as e:
+ return False
+
def setUp(self):
for d in (self.dirs + self.hidden_dirs):
self.make_dir(d)
@@ -527,7 +536,13 @@
if sys.platform == 'win32':
self.skipTest("Disabled deleting non-empty dirs on Windows")
# Test that non empty directory can be deleted
- self.api.delete(u'å b')
+ try:
+ self.api.delete(u'å b')
+ except requests.HTTPError as e:
+ if e.response.status_code == 400:
+ if not self.can_send2trash(u'å b'):
+ self.skipTest("Dir can't be sent to trash")
+ raise
# Check if directory has actually been deleted
with assert_http_error(404):
self.api.list(u'å b')
diff -Nru jupyter-notebook-6.1.4/notebook/services/contents/tests/test_fileio.py jupyter-notebook-6.2.0/notebook/services/contents/tests/test_fileio.py
--- jupyter-notebook-6.1.4/notebook/services/contents/tests/test_fileio.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/contents/tests/test_fileio.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# encoding: utf-8
"""Tests for file IO"""
# Copyright (c) Jupyter Development Team.
@@ -6,11 +5,11 @@
import io as stdlib_io
import os.path
+import unittest
+import pytest
import stat
+import sys
-import nose.tools as nt
-
-from ipython_genutils.testing.decorators import skip_win32
from ..fileio import atomic_writing
from ipython_genutils.tempdir import TemporaryDirectory
@@ -39,24 +38,24 @@
# OSError: The user lacks the privilege (Windows)
have_symlink = False
- with nt.assert_raises(CustomExc):
+ with pytest.raises(CustomExc):
with atomic_writing(f1) as f:
f.write(u'Failing write')
raise CustomExc
# Because of the exception, the file should not have been modified
with stdlib_io.open(f1, 'r') as f:
- nt.assert_equal(f.read(), u'Before')
+ assert f.read() == u'Before'
with atomic_writing(f1) as f:
f.write(u'Overwritten')
with stdlib_io.open(f1, 'r') as f:
- nt.assert_equal(f.read(), u'Overwritten')
+ assert f.read() == u'Overwritten'
if os.name != 'nt':
mode = stat.S_IMODE(os.stat(f1).st_mode)
- nt.assert_equal(mode, orig_mode)
+ assert mode == orig_mode
if have_symlink:
# Check that writing over a file preserves a symlink
@@ -64,33 +63,35 @@
f.write(u'written from symlink')
with stdlib_io.open(f1, 'r') as f:
- nt.assert_equal(f.read(), u'written from symlink')
+ assert f.read() == u'written from symlink'
-def _save_umask():
- global umask
- umask = os.umask(0)
- os.umask(umask)
-
-def _restore_umask():
- os.umask(umask)
-
-@skip_win32
-@nt.with_setup(_save_umask, _restore_umask)
-def test_atomic_writing_umask():
- with TemporaryDirectory() as td:
- os.umask(0o022)
- f1 = os.path.join(td, '1')
- with atomic_writing(f1) as f:
- f.write(u'1')
- mode = stat.S_IMODE(os.stat(f1).st_mode)
- nt.assert_equal(mode, 0o644, '{:o} != 644'.format(mode))
-
- os.umask(0o057)
- f2 = os.path.join(td, '2')
- with atomic_writing(f2) as f:
- f.write(u'2')
- mode = stat.S_IMODE(os.stat(f2).st_mode)
- nt.assert_equal(mode, 0o620, '{:o} != 620'.format(mode))
+class TestWithSetUmask(unittest.TestCase):
+ def setUp(self):
+ # save umask
+ global umask
+ umask = os.umask(0)
+ os.umask(umask)
+
+ def tearDown(self):
+ # restore umask
+ os.umask(umask)
+
+ @pytest.mark.skipif(sys.platform == "win32", reason="do not run on windows")
+ def test_atomic_writing_umask(self):
+ with TemporaryDirectory() as td:
+ os.umask(0o022)
+ f1 = os.path.join(td, '1')
+ with atomic_writing(f1) as f:
+ f.write(u'1')
+ mode = stat.S_IMODE(os.stat(f1).st_mode)
+ assert mode == 0o644
+
+ os.umask(0o057)
+ f2 = os.path.join(td, '2')
+ with atomic_writing(f2) as f:
+ f.write(u'2')
+ mode = stat.S_IMODE(os.stat(f2).st_mode)
+ assert mode == 0o620
def test_atomic_writing_newlines():
@@ -106,21 +107,21 @@
f.write(lf)
with stdlib_io.open(path, 'r', newline='') as f:
read = f.read()
- nt.assert_equal(read, plat)
+ assert read == plat
# test newline=LF
with stdlib_io.open(path, 'w', newline='\n') as f:
f.write(lf)
with stdlib_io.open(path, 'r', newline='') as f:
read = f.read()
- nt.assert_equal(read, lf)
+ assert read == lf
# test newline=CRLF
with atomic_writing(path, newline='\r\n') as f:
f.write(lf)
with stdlib_io.open(path, 'r', newline='') as f:
read = f.read()
- nt.assert_equal(read, crlf)
+ assert read == crlf
# test newline=no convert
text = u'crlf\r\ncr\rlf\n'
@@ -128,4 +129,4 @@
f.write(text)
with stdlib_io.open(path, 'r', newline='') as f:
read = f.read()
- nt.assert_equal(read, text)
+ assert read == text
diff -Nru jupyter-notebook-6.1.4/notebook/services/contents/tests/test_manager.py jupyter-notebook-6.2.0/notebook/services/contents/tests/test_manager.py
--- jupyter-notebook-6.1.4/notebook/services/contents/tests/test_manager.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/contents/tests/test_manager.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,6 +1,4 @@
-# coding: utf-8
"""Tests for the notebook manager."""
-from __future__ import print_function
import os
import sys
@@ -8,16 +6,14 @@
from contextlib import contextmanager
from itertools import combinations
-from nose import SkipTest
from tornado.web import HTTPError
-from unittest import TestCase
+from unittest import TestCase, skipIf
from tempfile import NamedTemporaryFile
from nbformat import v4 as nbformat
from ipython_genutils.tempdir import TemporaryDirectory
from traitlets import TraitError
-from ipython_genutils.testing import decorators as dec
from ..filemanager import FileContentsManager
@@ -108,7 +104,6 @@
self.assertEqual(cp_dir, os.path.join(root, cpm.checkpoint_dir, cp_name))
self.assertEqual(cp_subdir, os.path.join(root, subd, cpm.checkpoint_dir, cp_name))
- @dec.skipif(sys.platform == 'win32' and sys.version_info[0] < 3)
def test_bad_symlink(self):
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
@@ -129,7 +124,7 @@
# broken symlinks should still be shown in the contents manager
self.assertTrue('bad symlink' in contents)
- @dec.skipif(sys.platform == 'win32')
+ @skipIf(sys.platform == 'win32', "will not run on windows")
def test_recursive_symlink(self):
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
@@ -149,7 +144,6 @@
# recursive symlinks should not be shown in the contents manager
self.assertNotIn('recursive', contents)
- @dec.skipif(sys.platform == 'win32' and sys.version_info[0] < 3)
def test_good_symlink(self):
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
@@ -169,13 +163,10 @@
[symlink_model, file_model],
)
- def test_403(self):
- if hasattr(os, 'getuid'):
- if os.getuid() == 0:
- raise SkipTest("Can't test permissions as root")
- if sys.platform.startswith('win'):
- raise SkipTest("Can't test permissions on Windows")
+ @skipIf(hasattr(os, 'getuid') and os.getuid() == 0, "Can't test permissions as root")
+ @skipIf(sys.platform.startswith('win'), "Can't test permissions on Windows")
+ def test_403(self):
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
model = cm.new_untitled(type='file')
diff -Nru jupyter-notebook-6.1.4/notebook/services/kernels/handlers.py jupyter-notebook-6.2.0/notebook/services/kernels/handlers.py
--- jupyter-notebook-6.1.4/notebook/services/kernels/handlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/kernels/handlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -123,11 +123,125 @@
def create_stream(self):
km = self.kernel_manager
identity = self.session.bsession
- for channel in ('shell', 'control', 'iopub', 'stdin'):
- meth = getattr(km, 'connect_' + channel)
+ for channel in ("iopub", "shell", "control", "stdin"):
+ meth = getattr(km, "connect_" + channel)
self.channels[channel] = stream = meth(self.kernel_id, identity=identity)
stream.channel = channel
+ def nudge(self):
+ """Nudge the zmq connections with kernel_info_requests
+
+ Returns a Future that will resolve when we have received
+ a shell reply and at least one iopub message,
+ ensuring that zmq subscriptions are established,
+ sockets are fully connected, and kernel is responsive.
+
+ Keeps retrying kernel_info_request until these are both received.
+ """
+ kernel = self.kernel_manager.get_kernel(self.kernel_id)
+
+ # Do not nudge busy kernels as kernel info requests sent to shell are
+ # queued behind execution requests.
+ # nudging in this case would cause a potentially very long wait
+ # before connections are opened,
+ # plus it is *very* unlikely that a busy kernel will not finish
+ # establishing its zmq subscriptions before processing the next request.
+ if getattr(kernel, "execution_state") == "busy":
+ self.log.debug("Nudge: not nudging busy kernel %s", self.kernel_id)
+ f = Future()
+ f.set_result(None)
+ return f
+
+ # Use a transient shell channel to prevent leaking
+ # shell responses to the front-end.
+ shell_channel = kernel.connect_shell()
+ # The IOPub used by the client, whose subscriptions we are verifying.
+ iopub_channel = self.channels["iopub"]
+
+ info_future = Future()
+ iopub_future = Future()
+ both_done = gen.multi([info_future, iopub_future])
+
+ def finish(f=None):
+ """Ensure all futures are resolved
+
+ which in turn triggers cleanup
+ """
+ for f in (info_future, iopub_future):
+ if not f.done():
+ f.set_result(None)
+
+ def cleanup(f=None):
+ """Common cleanup"""
+ loop.remove_timeout(nudge_handle)
+ iopub_channel.stop_on_recv()
+ if not shell_channel.closed():
+ shell_channel.close()
+
+ # trigger cleanup when both message futures are resolved
+ both_done.add_done_callback(cleanup)
+
+ def on_shell_reply(msg):
+ self.log.debug("Nudge: shell info reply received: %s", self.kernel_id)
+ if not info_future.done():
+ self.log.debug("Nudge: resolving shell future: %s", self.kernel_id)
+ info_future.set_result(None)
+
+ def on_iopub(msg):
+ self.log.debug("Nudge: IOPub received: %s", self.kernel_id)
+ if not iopub_future.done():
+ iopub_channel.stop_on_recv()
+ self.log.debug("Nudge: resolving iopub future: %s", self.kernel_id)
+ iopub_future.set_result(None)
+
+ iopub_channel.on_recv(on_iopub)
+ shell_channel.on_recv(on_shell_reply)
+ loop = IOLoop.current()
+
+ # Nudge the kernel with kernel info requests until we get an IOPub message
+ def nudge(count):
+ count += 1
+
+ # NOTE: this close check appears to never be True during on_open,
+ # even when the peer has closed the connection
+ if self.ws_connection is None or self.ws_connection.is_closing():
+ self.log.debug(
+ "Nudge: cancelling on closed websocket: %s", self.kernel_id
+ )
+ finish()
+ return
+
+ # check for stopped kernel
+ if self.kernel_id not in self.kernel_manager:
+ self.log.debug(
+ "Nudge: cancelling on stopped kernel: %s", self.kernel_id
+ )
+ finish()
+ return
+
+ # check for closed zmq socket
+ if shell_channel.closed():
+ self.log.debug(
+ "Nudge: cancelling on closed zmq socket: %s", self.kernel_id
+ )
+ finish()
+ return
+
+ if not both_done.done():
+ log = self.log.warning if count % 10 == 0 else self.log.debug
+ log("Nudge: attempt %s on kernel %s" % (count, self.kernel_id))
+ self.session.send(shell_channel, "kernel_info_request")
+ nonlocal nudge_handle
+ nudge_handle = loop.call_later(0.5, nudge, count)
+
+ nudge_handle = loop.call_later(0, nudge, count=0)
+
+ # resolve with a timeout if we get no response
+ future = gen.with_timeout(loop.time() + self.kernel_info_timeout, both_done)
+ # ensure we have no dangling resources or unresolved Futures in case of timeout
+ future.add_done_callback(finish)
+ return future
+
def request_kernel_info(self):
"""send a request for kernel_info"""
km = self.kernel_manager
@@ -150,7 +264,7 @@
self.log.debug("Waiting for pending kernel_info request")
future.add_done_callback(lambda f: self._finish_kernel_info(f.result()))
return self._kernel_info_future
-
+
def _handle_kernel_info_reply(self, msg):
"""process the kernel_info_reply
@@ -190,7 +304,7 @@
self._kernel_info_future.set_result(info)
def initialize(self):
- super(ZMQChannelsHandler, self).initialize()
+ super().initialize()
self.zmq_stream = None
self.channels = {}
self.kernel_id = None
@@ -212,7 +326,7 @@
@gen.coroutine
def pre_get(self):
# authenticate first
- super(ZMQChannelsHandler, self).pre_get()
+ super().pre_get()
# check session collision:
yield self._register_session()
# then request kernel info, waiting up to a certain time before giving up.
@@ -236,7 +350,7 @@
@gen.coroutine
def get(self, kernel_id):
self.kernel_id = cast_unicode(kernel_id, 'ascii')
- yield super(ZMQChannelsHandler, self).get(kernel_id=kernel_id)
+ yield super().get(kernel_id=kernel_id)
@gen.coroutine
def _register_session(self):
@@ -254,7 +368,7 @@
self._open_sessions[self.session_key] = self
def open(self, kernel_id):
- super(ZMQChannelsHandler, self).open()
+ super().open()
km = self.kernel_manager
km.notify_connect(kernel_id)
@@ -263,15 +377,21 @@
if buffer_info and buffer_info['session_key'] == self.session_key:
self.log.info("Restoring connection for %s", self.session_key)
self.channels = buffer_info['channels']
- replay_buffer = buffer_info['buffer']
- if replay_buffer:
- self.log.info("Replaying %s buffered messages", len(replay_buffer))
- for channel, msg_list in replay_buffer:
- stream = self.channels[channel]
- self._on_zmq_reply(stream, msg_list)
+ connected = self.nudge()
+
+ def replay(value):
+ replay_buffer = buffer_info['buffer']
+ if replay_buffer:
+ self.log.info("Replaying %s buffered messages", len(replay_buffer))
+ for channel, msg_list in replay_buffer:
+ stream = self.channels[channel]
+ self._on_zmq_reply(stream, msg_list)
+
+ connected.add_done_callback(replay)
else:
try:
self.create_stream()
+ connected = self.nudge()
except web.HTTPError as e:
self.log.error("Error opening stream: %s", e)
# WebSockets don't response to traditional error codes so we
@@ -285,8 +405,13 @@
km.add_restart_callback(self.kernel_id, self.on_kernel_restarted)
km.add_restart_callback(self.kernel_id, self.on_restart_failed, 'dead')
- for channel, stream in self.channels.items():
- stream.on_recv_stream(self._on_zmq_reply)
+ def subscribe(value):
+ for channel, stream in self.channels.items():
+ stream.on_recv_stream(self._on_zmq_reply)
+
+ connected.add_done_callback(subscribe)
+
+ return connected
def on_message(self, msg):
if not self.channels:
@@ -419,10 +544,10 @@
self._iopub_window_byte_count -= byte_count
self._iopub_window_byte_queue.pop(-1)
return
- super(ZMQChannelsHandler, self)._on_zmq_reply(stream, msg)
+ super()._on_zmq_reply(stream, msg)
def close(self):
- super(ZMQChannelsHandler, self).close()
+ super().close()
return self._close_future
def on_close(self):
diff -Nru jupyter-notebook-6.1.4/notebook/services/kernels/kernelmanager.py jupyter-notebook-6.2.0/notebook/services/kernels/kernelmanager.py
--- jupyter-notebook-6.1.4/notebook/services/kernels/kernelmanager.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/kernels/kernelmanager.py 2021-01-13 16:30:49.000000000 +0000
@@ -294,7 +294,6 @@
kernel._activity_stream.close()
kernel._activity_stream = None
self.stop_buffering(kernel_id)
- self._kernel_connections.pop(kernel_id, None)
# Decrease the metric of number of kernels
# running for the relevant kernel type by 1
@@ -302,7 +301,12 @@
type=self._kernels[kernel_id].kernel_name
).dec()
- return self.pinned_superclass.shutdown_kernel(self, kernel_id, now=now, restart=restart)
+ self.pinned_superclass.shutdown_kernel(self, kernel_id, now=now, restart=restart)
+ # Unlike its async sibling method in AsyncMappingKernelManager, removing the kernel_id
+ # from the connections dictionary isn't as problematic before the shutdown since the
+ # method is synchronous. However, we'll keep the relative call orders the same from
+ # a maintenance perspective.
+ self._kernel_connections.pop(kernel_id, None)
async def restart_kernel(self, kernel_id, now=False):
"""Restart a kernel by kernel_id"""
@@ -376,8 +380,11 @@
kernels = []
kernel_ids = self.pinned_superclass.list_kernel_ids(self)
for kernel_id in kernel_ids:
- model = self.kernel_model(kernel_id)
- kernels.append(model)
+ try:
+ model = self.kernel_model(kernel_id)
+ kernels.append(model)
+ except (web.HTTPError, KeyError):
+ pass # Probably due to a (now) non-existent kernel, continue building the list
return kernels
# override _check_kernel_id to raise 404 instead of KeyError
@@ -498,7 +505,6 @@
kernel._activity_stream.close()
kernel._activity_stream = None
self.stop_buffering(kernel_id)
- self._kernel_connections.pop(kernel_id, None)
# Decrease the metric of number of kernels
# running for the relevant kernel type by 1
@@ -506,4 +512,9 @@
type=self._kernels[kernel_id].kernel_name
).dec()
- return await self.pinned_superclass.shutdown_kernel(self, kernel_id, now=now, restart=restart)
+ await self.pinned_superclass.shutdown_kernel(self, kernel_id, now=now, restart=restart)
+ # Remove kernel_id from the connections dictionary only after kernel has been shutdown,
+ # otherwise a race condition can occur since the shutdown may take a while - allowing
+ # list/fetch kernel operations to access _kernel_connections for a non-existent key
+ # (kernel_id) while "awaiting" the result of the shutdown.
+ self._kernel_connections.pop(kernel_id, None)
diff -Nru jupyter-notebook-6.1.4/notebook/services/kernelspecs/handlers.py jupyter-notebook-6.2.0/notebook/services/kernelspecs/handlers.py
--- jupyter-notebook-6.1.4/notebook/services/kernelspecs/handlers.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/kernelspecs/handlers.py 2021-01-13 16:30:49.000000000 +0000
@@ -27,7 +27,6 @@
}
# Add resource files if they exist
- resource_dir = resource_dir
for resource in ['kernel.js', 'kernel.css']:
if os.path.exists(pjoin(resource_dir, resource)):
d['resources'][resource] = url_path_join(
diff -Nru jupyter-notebook-6.1.4/notebook/services/kernelspecs/tests/test_kernelspecs_api.py jupyter-notebook-6.2.0/notebook/services/kernelspecs/tests/test_kernelspecs_api.py
--- jupyter-notebook-6.1.4/notebook/services/kernelspecs/tests/test_kernelspecs_api.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/kernelspecs/tests/test_kernelspecs_api.py 2021-01-13 16:30:49.000000000 +0000
@@ -1,4 +1,3 @@
-# coding: utf-8
"""Test the kernel specs webservice API."""
import errno
diff -Nru jupyter-notebook-6.1.4/notebook/services/sessions/tests/test_sessionmanager.py jupyter-notebook-6.2.0/notebook/services/sessions/tests/test_sessionmanager.py
--- jupyter-notebook-6.1.4/notebook/services/sessions/tests/test_sessionmanager.py 2020-09-08 17:47:36.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/services/sessions/tests/test_sessionmanager.py 2021-01-13 16:30:49.000000000 +0000
@@ -21,7 +21,7 @@
class DummyMKM(MappingKernelManager):
"""MappingKernelManager interface that doesn't start kernels, for testing"""
def __init__(self, *args, **kwargs):
- super(DummyMKM, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self.id_letters = iter(u'ABCDEFGHIJK')
def _new_id(self):
diff -Nru jupyter-notebook-6.1.4/notebook/static/base/js/markdown.js jupyter-notebook-6.2.0/notebook/static/base/js/markdown.js
--- jupyter-notebook-6.1.4/notebook/static/base/js/markdown.js 1970-01-01 00:00:00.000000000 +0000
+++ jupyter-notebook-6.2.0/notebook/static/base/js/markdown.js 2021-01-13 16:30:49.000000000 +0000
@@ -0,0 +1,117 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+define([
+ 'jquery',
+ 'base/js/utils',
+ 'base/js/mathjaxutils',
+ 'base/js/security',
+ 'components/marked/lib/marked',
+ 'codemirror/lib/codemirror',
+], function($, utils, mathjaxutils, security, marked, CodeMirror){
+ "use strict";
+
+ marked.setOptions({
+ gfm : true,
+ tables: true,
+ langPrefix: "cm-s-ipython language-",
+ highlight: function(code, lang, callback) {
+ if (!lang) {
+ // no language, no highlight
+ if (callback) {
+ callback(null, code);
+ return;
+ } else {
+ return code;
+ }
+ }
+ utils.requireCodeMirrorMode(lang, function (spec) {
+ var el = document.createElement("div");
+ var mode = CodeMirror.getMode({}, spec);
+ if (!mode) {
+ console.log("No CodeMirror mode: " + lang);
+ callback(null, code);
+ return;
+ }
+ try {
+ CodeMirror.runMode(code, spec, el);
+ callback(null, el.innerHTML);
+ } catch (err) {
+ console.log("Failed to highlight " + lang + " code", err);
+ callback(err, code);
+ }
+ }, function (err) {
+ console.log("No CodeMirror mode: " + lang);
+ console.log("Require CodeMirror mode error: " + err);
+ callback(null, code);
+ });
+ }
+ });
+
+ var mathjax_init_done = false;
+ function ensure_mathjax_init() {
+ if(!mathjax_init_done) {
+ mathjax_init_done = true;
+ mathjaxutils.init();
+ }
+ }
+
+ function render(markdown, options, callback) {
+ /**
+ * Find a readme in the current directory. Look for files with
+ * a name like 'readme.md' (case insensitive) or similar and
+ * mimetype 'text/markdown'.
+ *
+ * @param markdown: the markdown text to parse
+ * @param options
+ * Object with parameters:
+ * with_math: the markdown can contain mathematics
+ * clean_tables: prevent default inline styles for table cells
+ * sanitize: remove dangerous html (like