Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-jupyter-server for
openSUSE:Factory checked in at 2021-08-23 10:07:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jupyter-server (Old)
and /work/SRC/openSUSE:Factory/.python-jupyter-server.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jupyter-server"
Mon Aug 23 10:07:55 2021 rev:15 rq:912675 version:1.10.2
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-jupyter-server/python-jupyter-server.changes
2021-07-18 23:45:14.118913973 +0200
+++
/work/SRC/openSUSE:Factory/.python-jupyter-server.new.1899/python-jupyter-server.changes
2021-08-23 10:08:34.540218004 +0200
@@ -1,0 +2,21 @@
+Mon Aug 16 12:39:42 UTC 2021 - Ben Greiner <[email protected]>
+
+- Update to 1.10.2
+ * fix: make command line aliases work again #564
+ * decode bytes from secure cookie #562
+ * Maintenance and upkeep improvements
+ * Add the needed space in the welcome message #561
+ * Update check-release workflow #558
+ * Fix typo in allow_password_change help #559
+- Release notes for v1.10.1
+ * Protect against unset spec #556
+- Release notes for v1.10.0
+ * PR: Add a new preferred-dir traitlet #549
+ * stop hook for extensions #526
+ * extensions: allow extensions in namespace packages #523
+ * Fix examples/simple test execution #552
+ * Rebuild package-lock, fixing local setup #548
+ * small test changes #541
+- Add conftest.py missing from release tarball
+
+-------------------------------------------------------------------
Old:
----
jupyter_server-1.9.0.tar.gz
New:
----
conftest.py
jupyter_server-1.10.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-jupyter-server.spec ++++++
--- /var/tmp/diff_new_pack.Yv75CQ/_old 2021-08-23 10:08:35.080217375 +0200
+++ /var/tmp/diff_new_pack.Yv75CQ/_new 2021-08-23 10:08:35.080217375 +0200
@@ -19,13 +19,16 @@
%{?!python_module:%define python_module() python3-%{**}}
%define skip_python2 1
Name: python-jupyter-server
-Version: 1.9.0
+Version: 1.10.2
Release: 0
Summary: The backend to Jupyter web applications
License: BSD-3-Clause
Group: Development/Languages/Python
URL: https://github.com/jupyter-server/jupyter_server
+# need the release tarball for the static stylesheets
Source:
https://github.com/jupyter-server/jupyter_server/releases/download/v%{version}/jupyter_server-%{version}.tar.gz
+# conftest.py is not in release tarball but required for tests
+Source1:
https://github.com/jupyter-server/jupyter_server/raw/v%{version}/conftest.py
BuildRequires: %{python_module Jinja2}
BuildRequires: %{python_module Send2Trash}
BuildRequires: %{python_module anyio >= 3.1.0}
@@ -70,10 +73,10 @@
Obsoletes: python-jupyter_server < %{version}-%{release}
# SECTION extras_require test
BuildRequires: %{python_module ipykernel}
+BuildRequires: %{python_module pytest >= 6}
BuildRequires: %{python_module pytest-console-scripts}
BuildRequires: %{python_module pytest-mock}
BuildRequires: %{python_module pytest-tornasync}
-BuildRequires: %{python_module pytest}
BuildRequires: %{python_module requests}
# /SECTION
%if "%{python_flavor}" == "python3" || "%{python_provides}" == "python3"
@@ -91,6 +94,7 @@
%prep
%setup -q -n jupyter_server-%{version}
+cp %{SOURCE1} ./
%build
%python_build
++++++ conftest.py ++++++
import pytest
pytest_plugins = [
"jupyter_server.pytest_plugin"
]
def pytest_addoption(parser):
parser.addoption(
"--integration_tests",
default=False,
type=bool,
help="only run tests with the 'integration_test' pytest mark.",
)
def pytest_configure(config):
# register an additional marker
config.addinivalue_line(
"markers", "integration_test"
)
def pytest_runtest_setup(item):
is_integration_test = any(mark for mark in
item.iter_markers(name="integration_test"))
if item.config.getoption("--integration_tests") is True:
if not is_integration_test:
pytest.skip("Only running tests marked as 'integration_test'.")
else:
if is_integration_test:
pytest.skip("Skipping this test because it's marked
'integration_test'. Run integration tests using the `--integration_tests`
flag.")
++++++ jupyter_server-1.9.0.tar.gz -> jupyter_server-1.10.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/CHANGELOG.md
new/jupyter_server-1.10.2/CHANGELOG.md
--- old/jupyter_server-1.9.0/CHANGELOG.md 2021-06-24 17:42:30.000000000
+0200
+++ new/jupyter_server-1.10.2/CHANGELOG.md 2021-08-02 23:35:30.000000000
+0200
@@ -4,6 +4,71 @@
<!-- <START NEW CHANGELOG ENTRY> -->
+## 1.10.2
+
+([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.10.1...7956dc51d8239b7b9e8de3b22ceb4473bbf1d4e5))
+
+### Bugs fixed
+
+- fix: make command line aliases work again
[#564](https://github.com/jupyter-server/jupyter_server/pull/564)
([@mariobuikhuizen](https://github.com/mariobuikhuizen))
+- decode bytes from secure cookie
[#562](https://github.com/jupyter-server/jupyter_server/pull/562)
([@oliver-sanders](https://github.com/oliver-sanders))
+
+### Maintenance and upkeep improvements
+
+- Add the needed space in the welcome message
[#561](https://github.com/jupyter-server/jupyter_server/pull/561)
([@echarles](https://github.com/echarles))
+- Update check-release workflow
[#558](https://github.com/jupyter-server/jupyter_server/pull/558)
([@afshin](https://github.com/afshin))
+
+### Documentation improvements
+
+- Fix typo in allow_password_change help
[#559](https://github.com/jupyter-server/jupyter_server/pull/559)
([@manics](https://github.com/manics))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyter-server/jupyter_server/graphs/contributors?from=2021-07-23&to=2021-08-02&type=c))
+
+[@afshin](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aafshin+updated%3A2021-07-23..2021-08-02&type=Issues)
|
[@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acodecov-commenter+updated%3A2021-07-23..2021-08-02&type=Issues)
|
[@echarles](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aecharles+updated%3A2021-07-23..2021-08-02&type=Issues)
|
[@manics](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Amanics+updated%3A2021-07-23..2021-08-02&type=Issues)
|
[@mariobuikhuizen](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Amariobuikhuizen+updated%3A2021-07-23..2021-08-02&type=Issues)
|
[@oliver-sanders](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aoliver-sanders+updated%3A2021-07-23..2021-08-02&type=Issues)
|
[@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+i
nvolves%3Awelcome+updated%3A2021-07-23..2021-08-02&type=Issues) |
[@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3AZsailer+updated%3A2021-07-23..2021-08-02&type=Issues)
+
+<!-- <END NEW CHANGELOG ENTRY> -->
+
+## 1.10.1
+
+([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.10.0...42a195665aa8ae218fce4ec8165f19e734a9edaf))
+
+### Bugs fixed
+
+- Protect against unset spec
[#556](https://github.com/jupyter-server/jupyter_server/pull/556)
([@fcollonval](https://github.com/fcollonval))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyter-server/jupyter_server/graphs/contributors?from=2021-07-22&to=2021-07-23&type=c))
+
+[@fcollonval](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Afcollonval+updated%3A2021-07-22..2021-07-23&type=Issues)
+
+## 1.10.0
+
+([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.9.0...c9ee2a45e9a8f04215c2f3901f90cdc7b8fdc9c6))
+
+### Enhancements made
+
+- PR: Add a new preferred-dir traitlet
[#549](https://github.com/jupyter-server/jupyter_server/pull/549)
([@goanpeca](https://github.com/goanpeca))
+- stop hook for extensions
[#526](https://github.com/jupyter-server/jupyter_server/pull/526)
([@oliver-sanders](https://github.com/oliver-sanders))
+- extensions: allow extensions in namespace packages
[#523](https://github.com/jupyter-server/jupyter_server/pull/523)
([@oliver-sanders](https://github.com/oliver-sanders))
+
+### Bugs fixed
+
+- Fix examples/simple test execution
[#552](https://github.com/jupyter-server/jupyter_server/pull/552)
([@davidbrochart](https://github.com/davidbrochart))
+- Rebuild package-lock, fixing local setup
[#548](https://github.com/jupyter-server/jupyter_server/pull/548)
([@martinRenou](https://github.com/martinRenou))
+
+### Maintenance and upkeep improvements
+
+- small test changes
[#541](https://github.com/jupyter-server/jupyter_server/pull/541)
([@oliver-sanders](https://github.com/oliver-sanders))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyter-server/jupyter_server/graphs/contributors?from=2021-06-24&to=2021-07-21&type=c))
+
+[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ablink1073+updated%3A2021-06-24..2021-07-21&type=Issues)
|
[@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acodecov-commenter+updated%3A2021-06-24..2021-07-21&type=Issues)
|
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Adavidbrochart+updated%3A2021-06-24..2021-07-21&type=Issues)
|
[@goanpeca](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Agoanpeca+updated%3A2021-06-24..2021-07-21&type=Issues)
|
[@kevin-bates](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Akevin-bates+updated%3A2021-06-24..2021-07-21&type=Issues)
|
[@martinRenou](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3AmartinRenou+updated%3A2021-06-24..2021-07-21&type=Issues)
| [@oliver-sanders](https://github.com/search?q=repo%3Ajupyter-server%2Fjup
yter_server+involves%3Aoliver-sanders+updated%3A2021-06-24..2021-07-21&type=Issues)
|
[@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Awelcome+updated%3A2021-06-24..2021-07-21&type=Issues)
|
[@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3AZsailer+updated%3A2021-06-24..2021-07-21&type=Issues)
+
## 1.9.0
([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.8.0...f712734c4f7005f6a844abec9f57b993e7b004b0))
@@ -35,8 +100,6 @@
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ablink1073+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acodecov-commenter+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Adavidbrochart+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@eastonsuo](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aeastonsuo+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@icankeep](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aicankeep+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@jtpio](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ajtpio+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@kevin-bates](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involve
s%3Akevin-bates+updated%3A2021-05-20..2021-06-24&type=Issues) |
[@krassowski](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Akrassowski+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@telamonian](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Atelamonian+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@vidartf](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Avidartf+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Awelcome+updated%3A2021-05-20..2021-06-24&type=Issues)
|
[@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3AZsailer+updated%3A2021-05-20..2021-06-24&type=Issues)
-<!-- <END NEW CHANGELOG ENTRY> -->
-
## 1.8.0
([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.7.0...b063117a3a48ea67371c62e492f4637e44157586))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/CONTRIBUTING.rst
new/jupyter_server-1.10.2/CONTRIBUTING.rst
--- old/jupyter_server-1.9.0/CONTRIBUTING.rst 2021-06-24 17:42:30.000000000
+0200
+++ new/jupyter_server-1.10.2/CONTRIBUTING.rst 2021-08-02 23:35:30.000000000
+0200
@@ -58,10 +58,12 @@
Install dependencies::
pip install -e .[test]
+ pip install -e examples/simple
To run the Python tests, use::
pytest
+ pytest examples/simple --confcutdir=$PWD
Building the Docs
=================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/PKG-INFO
new/jupyter_server-1.10.2/PKG-INFO
--- old/jupyter_server-1.9.0/PKG-INFO 2021-06-24 17:45:56.836275000 +0200
+++ new/jupyter_server-1.10.2/PKG-INFO 2021-08-02 23:35:56.407143000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: jupyter_server
-Version: 1.9.0
+Version: 1.10.2
Summary: The backend???i.e. core services, APIs, and REST endpoints???to
Jupyter web applications.
Home-page: https://jupyter.org
Author: Jupyter Development Team
@@ -61,10 +61,7 @@
### Testing
-To test an installed `jupyter_server`, run the following:
-
- pip install jupyter_server[test]
- pytest jupyter_server
+See
[CONTRIBUTING](https://github.com/jupyter-server/jupyter_server/blob/master/CONTRIBUTING.rst#running-tests).
## Contributing
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/README.md
new/jupyter_server-1.10.2/README.md
--- old/jupyter_server-1.9.0/README.md 2021-06-24 17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/README.md 2021-08-02 23:35:30.000000000 +0200
@@ -35,10 +35,7 @@
### Testing
-To test an installed `jupyter_server`, run the following:
-
- pip install jupyter_server[test]
- pytest jupyter_server
+See
[CONTRIBUTING](https://github.com/jupyter-server/jupyter_server/blob/master/CONTRIBUTING.rst#running-tests).
## Contributing
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/docs/source/developers/extensions.rst
new/jupyter_server-1.10.2/docs/source/developers/extensions.rst
--- old/jupyter_server-1.9.0/docs/source/developers/extensions.rst
2021-06-24 17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/docs/source/developers/extensions.rst
2021-08-02 23:35:30.000000000 +0200
@@ -156,14 +156,19 @@
...
# Change the jinja templating environment
+ async def stop_extension(self):
+ ...
+ # Perform any required shut down steps
+
The ``ExtensionApp`` uses the following methods and properties to connect your
extension to the Jupyter server. You do not need to define a
``_load_jupyter_server_extension`` function for these apps. Instead, overwrite
the pieces below to add your custom settings, handlers and templates:
Methods
-* ``initialize_setting()``: adds custom settings to the Tornado Web
Application.
+* ``initialize_settings()``: adds custom settings to the Tornado Web
Application.
* ``initialize_handlers()``: appends handlers to the Tornado Web Application.
* ``initialize_templates()``: initialize the templating engine (e.g. jinja2)
for your frontend.
+* ``stop_extension()``: called on server shut down.
Properties
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/docs/source/other/full-config.rst
new/jupyter_server-1.10.2/docs/source/other/full-config.rst
--- old/jupyter_server-1.9.0/docs/source/other/full-config.rst 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/docs/source/other/full-config.rst 2021-08-02
23:35:30.000000000 +0200
@@ -135,7 +135,7 @@
Allow password to be changed at login for the Jupyter server.
- While loggin in with a token, the Jupyter server UI will give the
opportunity to
+ While logging in with a token, the Jupyter server UI will give the
opportunity to
the user to enter a new password at the same time that will replace
the token login mechanism.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/examples/simple/tests/conftest.py
new/jupyter_server-1.10.2/examples/simple/tests/conftest.py
--- old/jupyter_server-1.9.0/examples/simple/tests/conftest.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/examples/simple/tests/conftest.py 1970-01-01
01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-pytest_plugins = [
- 'jupyter_server.pytest_plugin'
-]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/jupyter_server/_version.py
new/jupyter_server-1.10.2/jupyter_server/_version.py
--- old/jupyter_server-1.9.0/jupyter_server/_version.py 2021-06-24
17:42:45.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/_version.py 2021-08-02
23:35:45.000000000 +0200
@@ -5,7 +5,7 @@
import re
# Version string must appear intact for tbump versioning
-__version__ = '1.9.0'
+__version__ = '1.10.2'
# Build up version_info tuple for backwards compatibility
pattern = r'(?P<major>\d+).(?P<minor>\d+).(?P<patch>\d+)(?P<rest>.*)'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/jupyter_server/auth/login.py
new/jupyter_server-1.10.2/jupyter_server/auth/login.py
--- old/jupyter_server-1.9.0/jupyter_server/auth/login.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/auth/login.py 2021-08-02
23:35:30.000000000 +0200
@@ -172,6 +172,8 @@
if user_id is None:
get_secure_cookie_kwargs =
handler.settings.get('get_secure_cookie_kwargs', {})
user_id = handler.get_secure_cookie(handler.cookie_name,
**get_secure_cookie_kwargs )
+ if user_id:
+ user_id = user_id.decode()
else:
cls.set_login_cookie(handler, user_id)
# Record that the current request has been authenticated with a
token.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/jupyter_server/auth/security.py
new/jupyter_server-1.10.2/jupyter_server/auth/security.py
--- old/jupyter_server-1.9.0/jupyter_server/auth/security.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/auth/security.py 2021-08-02
23:35:30.000000000 +0200
@@ -43,8 +43,8 @@
Examples
--------
- >>> passwd('mypassword')
- 'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12'
+ >>> passwd('mypassword') # doctest: +ELLIPSIS
+ 'argon2:...'
"""
if passphrase is None:
@@ -94,11 +94,11 @@
Examples
--------
- >>> from jupyter_server.auth.security import passwd_check
- >>> passwd_check('argon2:...', 'mypassword')
+ >>> myhash = passwd('mypassword')
+ >>> passwd_check(myhash, 'mypassword')
True
- >>> passwd_check('argon2:...', 'otherpassword')
+ >>> passwd_check(myhash, 'otherpassword')
False
>>>
passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server/extension/application.py
new/jupyter_server-1.10.2/jupyter_server/extension/application.py
--- old/jupyter_server-1.9.0/jupyter_server/extension/application.py
2021-06-24 17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/extension/application.py
2021-08-02 23:35:30.000000000 +0200
@@ -20,7 +20,7 @@
from jupyter_server.serverapp import ServerApp
from jupyter_server.transutils import _i18n
-from jupyter_server.utils import url_path_join
+from jupyter_server.utils import url_path_join, is_namespace_package
from .handler import ExtensionHandlerMixin
# -----------------------------------------------------------------------------
@@ -174,7 +174,11 @@
@classmethod
def get_extension_package(cls):
- return cls.__module__.split('.')[0]
+ parts = cls.__module__.split('.')
+ if is_namespace_package(parts[0]):
+ # in this case the package name is `<namespace>.<package>`.
+ return '.'.join(parts[0:2])
+ return parts[0]
@classmethod
def get_extension_point(cls):
@@ -416,6 +420,9 @@
# Start the server.
self.serverapp.start()
+ async def stop_extension(self):
+ """Cleanup any resources managed by this extension."""
+
def stop(self):
"""Stop the underlying Jupyter server.
"""
@@ -485,6 +492,7 @@
find_extensions = False
serverapp = ServerApp.instance(
jpserver_extensions=jpserver_extensions, **kwargs)
+ serverapp.aliases.update(cls.aliases)
serverapp.initialize(
argv=argv,
starter_extension=cls.name,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server/extension/manager.py
new/jupyter_server-1.10.2/jupyter_server/extension/manager.py
--- old/jupyter_server-1.9.0/jupyter_server/extension/manager.py
2021-06-24 17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/extension/manager.py
2021-08-02 23:35:30.000000000 +0200
@@ -2,6 +2,8 @@
import sys
import traceback
+from tornado.gen import multi
+
from traitlets.config import LoggingConfigurable
from traitlets import (
@@ -230,15 +232,17 @@
def load_point(self, point_name, serverapp):
point = self.extension_points[point_name]
- point.load(serverapp)
+ return point.load(serverapp)
def link_all_points(self, serverapp):
for point_name in self.extension_points:
self.link_point(point_name, serverapp)
def load_all_points(self, serverapp):
- for point_name in self.extension_points:
+ return [
self.load_point(point_name, serverapp)
+ for point_name in self.extension_points
+ ]
class ExtensionManager(LoggingConfigurable):
@@ -291,11 +295,25 @@
)
@property
+ def extension_apps(self):
+ """Return mapping of extension names and sets of ExtensionApp objects.
+ """
+ return {
+ name: {
+ point.app
+ for point in extension.extension_points.values()
+ if point.app
+ }
+ for name, extension in self.extensions.items()
+ }
+
+ @property
def extension_points(self):
- extensions = self.extensions
+ """Return mapping of extension point names and ExtensionPoint objects.
+ """
return {
name: point
- for value in extensions.values()
+ for value in self.extensions.values()
for name, point in value.extension_points.items()
}
@@ -341,13 +359,22 @@
def load_extension(self, name, serverapp):
extension = self.extensions.get(name)
+
if extension.enabled:
try:
- extension.load_all_points(serverapp)
- self.log.info("{name} | extension was successfully
loaded.".format(name=name))
+ points = extension.load_all_points(serverapp)
except Exception as e:
self.log.debug("".join(traceback.format_exception(*sys.exc_info())))
self.log.warning("{name} | extension failed loading with
message: {error}".format(name=name,error=str(e)))
+ else:
+ self.log.info("{name} | extension was successfully
loaded.".format(name=name))
+
+ async def stop_extension(self, name, apps):
+ """Call the shutdown hooks in the specified apps."""
+ for app in apps:
+ self.log.debug('{} | extension app "{}" stopping'.format(name,
app.name))
+ await app.stop_extension()
+ self.log.debug('{} | extension app "{}" stopped'.format(name,
app.name))
def link_all_extensions(self, serverapp):
"""Link all enabled extensions
@@ -366,3 +393,10 @@
# order.
for name in self.sorted_extensions.keys():
self.load_extension(name, serverapp)
+
+ async def stop_all_extensions(self, serverapp):
+ """Call the shutdown hooks in all extensions."""
+ await multi([
+ self.stop_extension(name, apps)
+ for name, apps in sorted(dict(self.extension_apps).items())
+ ])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/jupyter_server/pytest_plugin.py
new/jupyter_server-1.10.2/jupyter_server/pytest_plugin.py
--- old/jupyter_server-1.9.0/jupyter_server/pytest_plugin.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/pytest_plugin.py 2021-08-02
23:35:30.000000000 +0200
@@ -18,7 +18,7 @@
from jupyter_server.extension import serverextension
from jupyter_server.serverapp import ServerApp
-from jupyter_server.utils import url_path_join
+from jupyter_server.utils import url_path_join, run_sync
from jupyter_server.services.contents.filemanager import FileContentsManager
from jupyter_server.services.contents.largefilemanager import LargeFileManager
@@ -284,7 +284,7 @@
"""Starts a Jupyter Server instance based on the established configuration
values."""
app = jp_configurable_serverapp(config=jp_server_config, argv=jp_argv)
yield app
- app._cleanup()
+ run_sync(app._cleanup())
@pytest.fixture
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/jupyter_server/serverapp.py
new/jupyter_server-1.10.2/jupyter_server/serverapp.py
--- old/jupyter_server-1.9.0/jupyter_server/serverapp.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/serverapp.py 2021-08-02
23:35:30.000000000 +0200
@@ -43,7 +43,7 @@
from jupyter_core.paths import secure_write
from jupyter_server.transutils import trans, _i18n
-from jupyter_server.utils import run_sync
+from jupyter_server.utils import run_sync_in_loop
# the minimum viable tornado version: needs to be kept in sync with setup.py
MIN_TORNADO = (6, 1, 0)
@@ -610,6 +610,7 @@
'certfile': 'ServerApp.certfile',
'client-ca': 'ServerApp.client_ca',
'notebook-dir': 'ServerApp.root_dir',
+ 'preferred-dir': 'ServerApp.preferred_dir',
'browser': 'ServerApp.browser',
'pylab': 'ServerApp.pylab',
'gateway-url': 'GatewayClient.url',
@@ -972,7 +973,7 @@
allow_password_change = Bool(True, config=True,
help="""Allow password to be changed at login for the
Jupyter server.
- While loggin in with a token, the Jupyter server UI will
give the opportunity to
+ While logging in with a token, the Jupyter server UI will
give the opportunity to
the user to enter a new password at the same time that
will replace
the token login mechanism.
@@ -1355,9 +1356,7 @@
else:
return os.getcwd()
- @validate('root_dir')
- def _root_dir_validate(self, proposal):
- value = proposal['value']
+ def _normalize_dir(self, value):
# Strip any trailing slashes
# *except* if it's root
_, path = os.path.splitdrive(value)
@@ -1367,13 +1366,41 @@
if not os.path.isabs(value):
# If we receive a non-absolute path, make it absolute.
value = os.path.abspath(value)
+ return value
+
+ @validate('root_dir')
+ def _root_dir_validate(self, proposal):
+ value = self._normalize_dir(proposal['value'])
if not os.path.isdir(value):
raise TraitError(trans.gettext("No such directory: '%r'") % value)
return value
+ preferred_dir = Unicode(config=True,
+ help=trans.gettext("Preferred starting directory to use for notebooks
and kernels.")
+ )
+
+ @default('preferred_dir')
+ def _default_prefered_dir(self):
+ return self.root_dir
+
+ @validate('preferred_dir')
+ def _preferred_dir_validate(self, proposal):
+ value = self._normalize_dir(proposal['value'])
+ if not os.path.isdir(value):
+ raise TraitError(trans.gettext("No such preferred dir: '%r'") %
value)
+
+ # preferred_dir must be equal or a subdir of root_dir
+ if not value.startswith(self.root_dir):
+ raise TraitError(trans.gettext("preferred_dir must be equal or a
subdir of root_dir: '%r'") % value)
+
+ return value
+
@observe('root_dir')
def _root_dir_changed(self, change):
self._root_dir_set = True
+ if not self.preferred_dir.startswith(change['new']):
+ self.log.warning(trans.gettext("Value of preferred_dir updated to
use value of root_dir"))
+ self.preferred_dir = change['new']
@observe('server_extensions')
def _update_server_extensions(self, change):
@@ -1750,7 +1777,7 @@
self.log.critical(_i18n("Shutting down..."))
# schedule stop on the main thread,
# since this might be called from a signal handler
- self.io_loop.add_callback_from_signal(self.io_loop.stop)
+ self.stop(from_signal=True)
return
print(self.running_server_info())
yes = _i18n('y')
@@ -1764,7 +1791,7 @@
self.log.critical(_i18n("Shutdown confirmed"))
# schedule stop on the main thread,
# since this might be called from a signal handler
- self.io_loop.add_callback_from_signal(self.io_loop.stop)
+ self.stop(from_signal=True)
return
else:
print(_i18n("No answer for 5s:"), end=' ')
@@ -1777,7 +1804,7 @@
def _signal_stop(self, sig, frame):
self.log.critical(_i18n("received signal %s, stopping"), sig)
- self.io_loop.add_callback_from_signal(self.io_loop.stop)
+ self.stop(from_signal=True)
def _signal_info(self, sig, frame):
print(self.running_server_info())
@@ -2059,7 +2086,7 @@
if new_httpserver:
self.init_httpserver()
- def cleanup_kernels(self):
+ async def cleanup_kernels(self):
"""Shutdown all kernels.
The kernels will shutdown themselves when this process no longer
exists,
@@ -2068,9 +2095,9 @@
n_kernels = len(self.kernel_manager.list_kernel_ids())
kernel_msg = trans.ngettext('Shutting down %d kernel', 'Shutting down
%d kernels', n_kernels)
self.log.info(kernel_msg % n_kernels)
- run_sync(self.kernel_manager.shutdown_all())
+ await run_sync_in_loop(self.kernel_manager.shutdown_all())
- def cleanup_terminals(self):
+ async def cleanup_terminals(self):
"""Shutdown all terminals.
The terminals will shutdown themselves when this process no longer
exists,
@@ -2083,7 +2110,20 @@
n_terminals = len(terminal_manager.list())
terminal_msg = trans.ngettext('Shutting down %d terminal', 'Shutting
down %d terminals', n_terminals)
self.log.info(terminal_msg % n_terminals)
- run_sync(terminal_manager.terminate_all())
+ await run_sync_in_loop(terminal_manager.terminate_all())
+
+ async def cleanup_extensions(self):
+ """Call shutdown hooks in all extensions."""
+ n_extensions = len(self.extension_manager.extension_apps)
+ extension_msg = trans.ngettext(
+ 'Shutting down %d extension',
+ 'Shutting down %d extensions',
+ n_extensions
+ )
+ self.log.info(extension_msg % n_extensions)
+ await run_sync_in_loop(
+ self.extension_manager.stop_all_extensions(self)
+ )
def running_server_info(self, kernel_count=True):
"Return the current working directory and the server url information"
@@ -2289,7 +2329,7 @@
info(_i18n("Welcome to Project Jupyter! Explore the various tools
available"
" and their corresponding documentation. If you are
interested"
" in contributing to the platform, please visit the community"
- "resources section at https://jupyter.org/community.html."))
+ " resources section at https://jupyter.org/community.html."))
self.write_server_info_file()
self.write_browser_open_files()
@@ -2321,14 +2361,15 @@
' %s' % self.display_url,
]))
- def _cleanup(self):
- """General cleanup of files and kernels created
+ async def _cleanup(self):
+ """General cleanup of files, extensions and kernels created
by this instance ServerApp.
"""
self.remove_server_info_file()
self.remove_browser_open_files()
- self.cleanup_kernels()
- self.cleanup_terminals()
+ await self.cleanup_extensions()
+ await self.cleanup_kernels()
+ await self.cleanup_terminals()
def start_ioloop(self):
"""Start the IO Loop."""
@@ -2341,8 +2382,6 @@
self.io_loop.start()
except KeyboardInterrupt:
self.log.info(_i18n("Interrupted..."))
- finally:
- self._cleanup()
def init_ioloop(self):
"""init self.io_loop so that an extension can use it by
io_loop.call_later() to create background tasks"""
@@ -2356,13 +2395,23 @@
self.start_app()
self.start_ioloop()
- def stop(self):
- def _stop():
+ async def _stop(self):
+ """Cleanup resources and stop the IO Loop."""
+ await self._cleanup()
+ self.io_loop.stop()
+
+ def stop(self, from_signal=False):
+ """Cleanup resources and stop the server."""
+ if hasattr(self, '_http_server'):
# Stop a server if its set.
- if hasattr(self, '_http_server'):
- self.http_server.stop()
- self.io_loop.stop()
- self.io_loop.add_callback(_stop)
+ self.http_server.stop()
+ if getattr(self, 'io_loop', None):
+ # use IOLoop.add_callback because signal.signal must be called
+ # from main thread
+ if from_signal:
+ self.io_loop.add_callback_from_signal(self._stop)
+ else:
+ self.io_loop.add_callback(self._stop)
def list_running_servers(runtime_dir=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server/tests/conftest.py
new/jupyter_server-1.10.2/jupyter_server/tests/conftest.py
--- old/jupyter_server-1.9.0/jupyter_server/tests/conftest.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/tests/conftest.py 1970-01-01
01:00:00.000000000 +0100
@@ -1,36 +0,0 @@
-import pytest
-
-
-pytest_plugins = [
- "jupyter_server.pytest_plugin"
-]
-
-
-import pytest
-
-
-def pytest_addoption(parser):
- parser.addoption(
- "--integration_tests",
- default=False,
- type=bool,
- help="only run tests with the 'integration_test' pytest mark.",
- )
-
-
-def pytest_configure(config):
- # register an additional marker
- config.addinivalue_line(
- "markers", "integration_test"
- )
-
-
-def pytest_runtest_setup(item):
- is_integration_test = any([mark for mark in
item.iter_markers(name="integration_test")])
-
- if item.config.getoption("--integration_tests") is True:
- if not is_integration_test:
- pytest.skip("Only running tests marked as 'integration_test'.")
- else:
- if is_integration_test:
- pytest.skip("Skipping this test because it's marked
'integration_test'. Run integration tests using the `--integration_tests`
flag.")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server/tests/extension/test_app.py
new/jupyter_server-1.10.2/jupyter_server/tests/extension/test_app.py
--- old/jupyter_server-1.9.0/jupyter_server/tests/extension/test_app.py
2021-06-24 17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/tests/extension/test_app.py
2021-08-02 23:35:30.000000000 +0200
@@ -1,6 +1,7 @@
import pytest
from traitlets.config import Config
from jupyter_server.serverapp import ServerApp
+from jupyter_server.utils import run_sync
from .mockextensions.app import MockExtensionApp
@@ -101,3 +102,42 @@
exts = serverapp.jpserver_extensions
assert exts['jupyter_server.tests.extension.mockextensions.mock1']
assert exts['jupyter_server.tests.extension.mockextensions']
+
+
+def test_stop_extension(jp_serverapp, caplog):
+ """Test the stop_extension method.
+
+ This should be fired by ServerApp.cleanup_extensions.
+ """
+ calls = 0
+
+ # load extensions (make sure we only have the one extension loaded
+ jp_serverapp.extension_manager.load_all_extensions(jp_serverapp)
+ extension_name = 'jupyter_server.tests.extension.mockextensions'
+ assert list(jp_serverapp.extension_manager.extension_apps) == [
+ extension_name
+ ]
+
+ # add a stop_extension method for the extension app
+ async def _stop(*args):
+ nonlocal calls
+ calls += 1
+ for apps in jp_serverapp.extension_manager.extension_apps.values():
+ for app in apps:
+ if app:
+ app.stop_extension = _stop
+
+ # call cleanup_extensions, check the logging is correct
+ caplog.clear()
+ run_sync(jp_serverapp.cleanup_extensions())
+ assert [
+ msg
+ for *_, msg in caplog.record_tuples
+ ] == [
+ 'Shutting down 1 extension',
+ '{} | extension app "mockextension" stopping'.format(extension_name),
+ '{} | extension app "mockextension" stopped'.format(extension_name),
+ ]
+
+ # check the shutdown method was called once
+ assert calls == 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server/tests/namespace-package-test/README.md
new/jupyter_server-1.10.2/jupyter_server/tests/namespace-package-test/README.md
---
old/jupyter_server-1.9.0/jupyter_server/tests/namespace-package-test/README.md
1970-01-01 01:00:00.000000000 +0100
+++
new/jupyter_server-1.10.2/jupyter_server/tests/namespace-package-test/README.md
2021-08-02 23:35:30.000000000 +0200
@@ -0,0 +1,3 @@
+Blank namespace package for use in testing.
+
+https://www.python.org/dev/peps/pep-0420/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server/tests/namespace-package-test/setup.cfg
new/jupyter_server-1.10.2/jupyter_server/tests/namespace-package-test/setup.cfg
---
old/jupyter_server-1.9.0/jupyter_server/tests/namespace-package-test/setup.cfg
1970-01-01 01:00:00.000000000 +0100
+++
new/jupyter_server-1.10.2/jupyter_server/tests/namespace-package-test/setup.cfg
2021-08-02 23:35:30.000000000 +0200
@@ -0,0 +1,5 @@
+[metadata]
+name = namespace-package-test
+
+[options]
+packages = find_namespace:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server/tests/test_serverapp.py
new/jupyter_server-1.10.2/jupyter_server/tests/test_serverapp.py
--- old/jupyter_server-1.9.0/jupyter_server/tests/test_serverapp.py
2021-06-24 17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/tests/test_serverapp.py
2021-08-02 23:35:30.000000000 +0200
@@ -286,3 +286,93 @@
assert serverapp.connection_url == connection_url
# Cleanup singleton after test.
ServerApp.clear_instance()
+
+
+# Preferred dir tests
+# ----------------------------------------------------------------------------
+def test_valid_preferred_dir(tmp_path, jp_configurable_serverapp):
+ path = str(tmp_path)
+ app = jp_configurable_serverapp(root_dir=path, preferred_dir=path)
+ assert app.root_dir == path
+ assert app.preferred_dir == path
+ assert app.root_dir == app.preferred_dir
+
+
+def test_valid_preferred_dir_is_root_subdir(tmp_path,
jp_configurable_serverapp):
+ path = str(tmp_path)
+ path_subdir = str(tmp_path / 'subdir')
+ os.makedirs(path_subdir, exist_ok=True)
+ app = jp_configurable_serverapp(root_dir=path, preferred_dir=path_subdir)
+ assert app.root_dir == path
+ assert app.preferred_dir == path_subdir
+ assert app.preferred_dir.startswith(app.root_dir)
+
+
+def test_valid_preferred_dir_does_not_exist(tmp_path,
jp_configurable_serverapp):
+ path = str(tmp_path)
+ path_subdir = str(tmp_path / 'subdir')
+ with pytest.raises(TraitError) as error:
+ app = jp_configurable_serverapp(root_dir=path,
preferred_dir=path_subdir)
+
+ assert "No such preferred dir:" in str(error)
+
+
+def test_invalid_preferred_dir_does_not_exist(tmp_path,
jp_configurable_serverapp):
+ path = str(tmp_path)
+ path_subdir = str(tmp_path / 'subdir')
+ with pytest.raises(TraitError) as error:
+ app = jp_configurable_serverapp(root_dir=path,
preferred_dir=path_subdir)
+
+ assert "No such preferred dir:" in str(error)
+
+
+def test_invalid_preferred_dir_does_not_exist_set(tmp_path,
jp_configurable_serverapp):
+ path = str(tmp_path)
+ path_subdir = str(tmp_path / 'subdir')
+
+ app = jp_configurable_serverapp(root_dir=path)
+ with pytest.raises(TraitError) as error:
+ app.preferred_dir = path_subdir
+
+ assert "No such preferred dir:" in str(error)
+
+
+def test_invalid_preferred_dir_not_root_subdir(tmp_path,
jp_configurable_serverapp):
+ path = str(tmp_path / 'subdir')
+ os.makedirs(path, exist_ok=True)
+ not_subdir_path = str(tmp_path)
+
+ with pytest.raises(TraitError) as error:
+ app = jp_configurable_serverapp(root_dir=path,
preferred_dir=not_subdir_path)
+
+ assert "preferred_dir must be equal or a subdir of root_dir:" in str(error)
+
+
+def test_invalid_preferred_dir_not_root_subdir_set(tmp_path,
jp_configurable_serverapp):
+ path = str(tmp_path / 'subdir')
+ os.makedirs(path, exist_ok=True)
+ not_subdir_path = str(tmp_path)
+
+ app = jp_configurable_serverapp(root_dir=path)
+ with pytest.raises(TraitError) as error:
+ app.preferred_dir = not_subdir_path
+
+ assert "preferred_dir must be equal or a subdir of root_dir:" in str(error)
+
+
+def test_observed_root_dir_updates_preferred_dir(tmp_path,
jp_configurable_serverapp):
+ path = str(tmp_path)
+ new_path = str(tmp_path / 'subdir')
+ os.makedirs(new_path, exist_ok=True)
+
+ app = jp_configurable_serverapp(root_dir=path, preferred_dir=path)
+ app.root_dir = new_path
+ assert app.preferred_dir == new_path
+
+
+def test_observed_root_dir_does_not_update_preferred_dir(tmp_path,
jp_configurable_serverapp):
+ path = str(tmp_path)
+ new_path = str(tmp_path.parent)
+ app = jp_configurable_serverapp(root_dir=path, preferred_dir=path)
+ app.root_dir = new_path
+ assert app.preferred_dir == path
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server/tests/test_utils.py
new/jupyter_server-1.10.2/jupyter_server/tests/test_utils.py
--- old/jupyter_server-1.9.0/jupyter_server/tests/test_utils.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/tests/test_utils.py
2021-08-02 23:35:30.000000000 +0200
@@ -1,19 +1,25 @@
+from pathlib import Path
+from unittest.mock import patch
+
import pytest
from traitlets.tests.utils import check_help_all_output
-from jupyter_server.utils import url_escape, url_unescape
+from jupyter_server.utils import (
+ url_escape,
+ url_unescape,
+ is_namespace_package
+)
def test_help_output():
check_help_all_output('jupyter_server')
-
@pytest.mark.parametrize(
'unescaped,escaped',
[
(
- '/this is a test/for spaces/',
+ '/this is a test/for spaces/',
'/this%20is%20a%20test/for%20spaces/'
),
(
@@ -37,3 +43,29 @@
# Test unescaping.
path = url_unescape(escaped)
assert path == unescaped
+
+
[email protected](
+ 'name, expected',
+ [
+ # returns True if it is a namespace package
+ ('test_namespace', True),
+ # returns False if it isn't a namespace package
+ ('sys', False),
+ ('jupyter_server', False),
+ # returns None if it isn't importable
+ ('not_a_python_namespace', None)
+ ]
+)
+def test_is_namespace_package(monkeypatch, name, expected):
+ monkeypatch.syspath_prepend(Path(__file__).parent /
'namespace-package-test')
+
+ assert is_namespace_package(name) is expected
+
+
+def test_is_namespace_package_no_spec():
+ with patch("importlib.util.find_spec") as mocked_spec:
+ mocked_spec.side_effect = ValueError()
+
+ assert is_namespace_package('dummy') is None
+ mocked_spec.assert_called_once_with('dummy')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/jupyter_server/traittypes.py
new/jupyter_server-1.10.2/jupyter_server/traittypes.py
--- old/jupyter_server-1.9.0/jupyter_server/traittypes.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/traittypes.py 2021-08-02
23:35:30.000000000 +0200
@@ -50,13 +50,15 @@
'an object'
>>> describe("a", type(object))
'a type'
+
Definite description:
- >>> describe("the", object())
- "the object at '0x10741f1b0'"
+ >>> describe("the", object()) # doctest: +ELLIPSIS
+ "the object at '0x...'"
>>> describe("the", object)
- "the type 'object'"
+ 'the object object'
>>> describe("the", type(object))
- "the type 'type'"
+ 'the type type'
+
Definitely named description:
>>> describe("the", object(), "I made")
'the object I made'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/jupyter_server/utils.py
new/jupyter_server-1.10.2/jupyter_server/utils.py
--- old/jupyter_server-1.9.0/jupyter_server/utils.py 2021-06-24
17:42:30.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server/utils.py 2021-08-02
23:35:30.000000000 +0200
@@ -3,8 +3,10 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
+from _frozen_importlib_external import _NamespacePath
import asyncio
import errno
+import importlib.util
import inspect
import os
import socket
@@ -230,6 +232,29 @@
return wrapped()
+async def run_sync_in_loop(maybe_async):
+ """Runs a function synchronously whether it is an async function or not.
+
+ If async, runs maybe_async and blocks until it has executed.
+
+ If not async, just returns maybe_async as it is the result of something
+ that has already executed.
+
+ Parameters
+ ----------
+ maybe_async : async or non-async object
+ The object to be executed, if it is async.
+
+ Returns
+ -------
+ result
+ Whatever the async object returns, or the object itself.
+ """
+ if not inspect.isawaitable(maybe_async):
+ return maybe_async
+ return await maybe_async
+
+
def urlencode_unix_socket_path(socket_path):
"""Encodes a UNIX socket path string from a socket path for the
`http+unix` URI form."""
return socket_path.replace('/', '%2F')
@@ -352,3 +377,23 @@
with _request_for_tornado_client(urlstring) as request:
response = await AsyncHTTPClient(io_loop).fetch(request)
return response
+
+
+def is_namespace_package(namespace):
+ """Is the provided namespace a Python Namespace Package (PEP420).
+
+ https://www.python.org/dev/peps/pep-0420/#specification
+
+ Returns `None` if module is not importable.
+
+ """
+ # NOTE: using submodule_search_locations because the loader can be None
+ try:
+ spec = importlib.util.find_spec(namespace)
+ except ValueError: # spec is not set - see
https://docs.python.org/3/library/importlib.html#importlib.util.find_spec
+ return None
+
+ if not spec:
+ # e.g. module not installed
+ return None
+ return isinstance(spec.submodule_search_locations, _NamespacePath)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server.egg-info/PKG-INFO
new/jupyter_server-1.10.2/jupyter_server.egg-info/PKG-INFO
--- old/jupyter_server-1.9.0/jupyter_server.egg-info/PKG-INFO 2021-06-24
17:45:56.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server.egg-info/PKG-INFO 2021-08-02
23:35:56.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: jupyter-server
-Version: 1.9.0
+Version: 1.10.2
Summary: The backend???i.e. core services, APIs, and REST endpoints???to
Jupyter web applications.
Home-page: https://jupyter.org
Author: Jupyter Development Team
@@ -61,10 +61,7 @@
### Testing
-To test an installed `jupyter_server`, run the following:
-
- pip install jupyter_server[test]
- pytest jupyter_server
+See
[CONTRIBUTING](https://github.com/jupyter-server/jupyter_server/blob/master/CONTRIBUTING.rst#running-tests).
## Contributing
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server.egg-info/SOURCES.txt
new/jupyter_server-1.10.2/jupyter_server.egg-info/SOURCES.txt
--- old/jupyter_server-1.9.0/jupyter_server.egg-info/SOURCES.txt
2021-06-24 17:45:56.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server.egg-info/SOURCES.txt
2021-08-02 23:35:56.000000000 +0200
@@ -86,7 +86,6 @@
examples/simple/simple_ext2/templates/simple_ext2.html
examples/simple/src/index.ts
examples/simple/src/tsconfig.json
-examples/simple/tests/conftest.py
examples/simple/tests/test_handlers.py
jupyter_server/__init__.py
jupyter_server/__main__.py
@@ -199,7 +198,6 @@
jupyter_server/terminal/handlers.py
jupyter_server/terminal/terminalmanager.py
jupyter_server/tests/__init__.py
-jupyter_server/tests/conftest.py
jupyter_server/tests/test_config_manager.py
jupyter_server/tests/test_files.py
jupyter_server/tests/test_gateway.py
@@ -235,6 +233,9 @@
jupyter_server/tests/extension/mockextensions/mockext_sys.py
jupyter_server/tests/extension/mockextensions/mockext_user.py
jupyter_server/tests/extension/mockextensions/static/mock.txt
+jupyter_server/tests/namespace-package-test/README.md
+jupyter_server/tests/namespace-package-test/setup.cfg
+jupyter_server/tests/namespace-package-test/test_namespace/test_package/__init__.py
jupyter_server/tests/nbconvert/__init__.py
jupyter_server/tests/nbconvert/test_handlers.py
jupyter_server/tests/services/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.9.0/jupyter_server.egg-info/requires.txt
new/jupyter_server-1.10.2/jupyter_server.egg-info/requires.txt
--- old/jupyter_server-1.9.0/jupyter_server.egg-info/requires.txt
2021-06-24 17:45:56.000000000 +0200
+++ new/jupyter_server-1.10.2/jupyter_server.egg-info/requires.txt
2021-08-02 23:35:56.000000000 +0200
@@ -17,7 +17,7 @@
[test]
coverage
-pytest
+pytest>=6.0
pytest-cov
pytest-mock
requests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/pyproject.toml
new/jupyter_server-1.10.2/pyproject.toml
--- old/jupyter_server-1.9.0/pyproject.toml 2021-06-24 17:42:45.000000000
+0200
+++ new/jupyter_server-1.10.2/pyproject.toml 2021-08-02 23:35:45.000000000
+0200
@@ -6,14 +6,16 @@
factory = "jupyter_packaging.npm_builder"
[tool.check-manifest]
-ignore = ["tbump.toml", ".*", "*.yml", "package-lock.json", "bootstrap*"]
+ignore = ["tbump.toml", ".*", "*.yml", "package-lock.json", "bootstrap*",
"conftest.py"]
[tool.pytest.ini_options]
-# Exclude the example tests.
-norecursedirs = "examples/*"
+addopts = "--doctest-modules"
+testpaths = [
+ "jupyter_server"
+]
[tool.tbump.version]
-current = "1.9.0"
+current = "1.10.2"
regex = '''
(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
((?P<channel>a|b|rc|.dev)(?P<release>\d+))?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.9.0/setup.cfg
new/jupyter_server-1.10.2/setup.cfg
--- old/jupyter_server-1.9.0/setup.cfg 2021-06-24 17:45:56.836275000 +0200
+++ new/jupyter_server-1.10.2/setup.cfg 2021-08-02 23:35:56.407143000 +0200
@@ -45,7 +45,15 @@
requests-unixsocket
[options.extras_require]
-test = coverage; pytest; pytest-cov; pytest-mock; requests; pytest-tornasync;
pytest-console-scripts; ipykernel
+test =
+ coverage
+ pytest>=6.0
+ pytest-cov
+ pytest-mock
+ requests
+ pytest-tornasync
+ pytest-console-scripts
+ ipykernel
[options.entry_points]
console_scripts =