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 2022-10-26 14:21:57
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jupyter-server (Old)
and /work/SRC/openSUSE:Factory/.python-jupyter-server.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jupyter-server"
Wed Oct 26 14:21:57 2022 rev:27 rq:1031311 version:1.21.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-jupyter-server/python-jupyter-server.changes
2022-08-06 22:08:15.602674331 +0200
+++
/work/SRC/openSUSE:Factory/.python-jupyter-server.new.2275/python-jupyter-server.changes
2022-10-26 14:21:59.079890085 +0200
@@ -1,0 +2,31 @@
+Wed Oct 26 10:32:16 UTC 2022 - Ben Greiner <[email protected]>
+
+- Update to version 1.21.0
+ * Handle client 8 pending kernels #1014 (@blink1073)
+- Release 1.19.1
+ * Wrap the concurrent futures in an asyncio future #1000
+ (@blink1073)
+- Release 1.19.0
+ * New features added
+ + Backport Inject session identifier into environment variable
+ #920 (@vidartf)
+ * Enhancements made
+ + Backport #981: Make it easier to pass custom env variables to
+ kernel #994 (@divyansshhh)
+ + Retry certain errors between server and gateway #944
+ (@kevin-bates)
+ * Bugs fixed
+ + Backport PR #965: Correct content-type headers #966
+ (@epignot)
+ + avoid creating asyncio.Lock at import time #935 (@minrk)
+ + Fix c.GatewayClient.url snippet syntax #917 (@rickwierenga)
+ + Add back support for kernel launch timeout pad #910
+ (@CiprianAnton)
+ * Maintenance and upkeep improvements
+ + Test with client 8 updates #992 (@blink1073)
+ + Backport PR #922: Improve logging of bare exceptions etc.
+ #926 (@thetorpedodog)
+ + Fix handling of dev version #913 (@blink1073)
+ + Fix owasp link #908 (@blink1073)
+
+-------------------------------------------------------------------
Old:
----
jupyter_server-1.18.1.tar.gz
New:
----
jupyter_server-1.21.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-jupyter-server.spec ++++++
--- /var/tmp/diff_new_pack.NFTbTT/_old 2022-10-26 14:21:59.783891287 +0200
+++ /var/tmp/diff_new_pack.NFTbTT/_new 2022-10-26 14:21:59.787891294 +0200
@@ -31,7 +31,7 @@
%bcond_with libalternatives
%endif
Name: python-jupyter-server%{psuffix}
-Version: 1.18.1
+Version: 1.21.0
Release: 0
Summary: The backend to Jupyter web applications
License: BSD-3-Clause
@@ -94,7 +94,7 @@
Group: Development/Languages/Python
Requires: python-ipykernel
Requires: python-jupyter-server = %{version}
-Requires: python-pytest >= 6
+Requires: python-pytest >= 7
Requires: python-pytest-console-scripts
Requires: python-pytest-mock
Requires: python-pytest-timeout
++++++ jupyter_server-1.18.1.tar.gz -> jupyter_server-1.21.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/CHANGELOG.md
new/jupyter_server-1.21.0/CHANGELOG.md
--- old/jupyter_server-1.18.1/CHANGELOG.md 2022-07-05 22:22:43.000000000
+0200
+++ new/jupyter_server-1.21.0/CHANGELOG.md 2022-10-11 13:35:05.000000000
+0200
@@ -4,6 +4,73 @@
<!-- <START NEW CHANGELOG ENTRY> -->
+## 1.21.0
+
+([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.19.1...2f529bf5d1f8c68a6b7193f474c9ba025111d743))
+
+### Maintenance and upkeep improvements
+
+- Handle client 8 pending kernels
[#1014](https://github.com/jupyter-server/jupyter_server/pull/1014)
([@blink1073](https://github.com/blink1073))
+
+### Documentation improvements
+
+- Pin docutils to fix docs build
[#1004](https://github.com/jupyter-server/jupyter_server/pull/1004)
([@blink1073](https://github.com/blink1073))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyter-server/jupyter_server/graphs/contributors?from=2022-09-27&to=2022-10-11&type=c))
+
+[@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acodecov-commenter+updated%3A2022-09-27..2022-10-11&type=Issues)
|
[@meeseeksmachine](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ameeseeksmachine+updated%3A2022-09-27..2022-10-11&type=Issues)
|
[@welcome](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Awelcome+updated%3A2022-09-27..2022-10-11&type=Issues)
+
+<!-- <END NEW CHANGELOG ENTRY> -->
+
+## 1.19.1
+
+([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.19.0...690d2f4131b2d65476d05b302a4b3e9a2f052650))
+
+### Bugs fixed
+
+- Wrap the concurrent futures in an asyncio future
[#1000](https://github.com/jupyter-server/jupyter_server/pull/1000)
([@blink1073](https://github.com/blink1073))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyter-server/jupyter_server/graphs/contributors?from=2022-09-26&to=2022-09-27&type=c))
+
+[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ablink1073+updated%3A2022-09-26..2022-09-27&type=Issues)
|
[@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acodecov-commenter+updated%3A2022-09-26..2022-09-27&type=Issues)
+
+## 1.19.0
+
+([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.18.1...27bc44c23fba38a4d02b3d9d9eeef45e53eb76ba))
+
+### New features added
+
+- Backport Inject session identifier into environment variable
[#920](https://github.com/jupyter-server/jupyter_server/pull/920)
([@vidartf](https://github.com/vidartf))
+
+### Enhancements made
+
+- Backport #981: Make it easier to pass custom env variables to kernel
[#994](https://github.com/jupyter-server/jupyter_server/pull/994)
([@divyansshhh](https://github.com/divyansshhh))
+- Retry certain errors between server and gateway
[#944](https://github.com/jupyter-server/jupyter_server/pull/944)
([@kevin-bates](https://github.com/kevin-bates))
+
+### Bugs fixed
+
+- Backport PR #965: Correct content-type headers
[#966](https://github.com/jupyter-server/jupyter_server/pull/966)
([@epignot](https://github.com/epignot))
+- avoid creating asyncio.Lock at import time
[#935](https://github.com/jupyter-server/jupyter_server/pull/935)
([@minrk](https://github.com/minrk))
+- Fix c.GatewayClient.url snippet syntax
[#917](https://github.com/jupyter-server/jupyter_server/pull/917)
([@rickwierenga](https://github.com/rickwierenga))
+- Add back support for kernel launch timeout pad
[#910](https://github.com/jupyter-server/jupyter_server/pull/910)
([@CiprianAnton](https://github.com/CiprianAnton))
+
+### Maintenance and upkeep improvements
+
+- Test with client 8 updates
[#992](https://github.com/jupyter-server/jupyter_server/pull/992)
([@blink1073](https://github.com/blink1073))
+- Backport PR #922: Improve logging of bare exceptions etc.
[#926](https://github.com/jupyter-server/jupyter_server/pull/926)
([@thetorpedodog](https://github.com/thetorpedodog))
+- Fix handling of dev version
[#913](https://github.com/jupyter-server/jupyter_server/pull/913)
([@blink1073](https://github.com/blink1073))
+- Fix owasp link
[#908](https://github.com/jupyter-server/jupyter_server/pull/908)
([@blink1073](https://github.com/blink1073))
+
+### Contributors to this release
+
+([GitHub contributors page for this
release](https://github.com/jupyter-server/jupyter_server/graphs/contributors?from=2022-07-05&to=2022-09-26&type=c))
+
+[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ablink1073+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acodecov-commenter+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Adavidbrochart+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@divyansshhh](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Adivyansshhh+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@dlqqq](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Adlqqq+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@echarles](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aecharles+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@epignot](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involve
s%3Aepignot+updated%3A2022-07-05..2022-09-26&type=Issues) |
[@kevin-bates](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Akevin-bates+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@meeseeksdev](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ameeseeksdev+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@meeseeksmachine](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ameeseeksmachine+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@minrk](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aminrk+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@thetorpedodog](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Athetorpedodog+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@vidartf](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Avidartf+updated%3A2022-07-05..2022-09-26&type=Issues)
| [@welcome](https://github.c
om/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Awelcome+updated%3A2022-07-05..2022-09-26&type=Issues)
|
[@Zsailer](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3AZsailer+updated%3A2022-07-05..2022-09-26&type=Issues)
+
## 1.18.1
([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.18.0...65d779a12b6e4123de0767de6547e6cdf2d5e7e9))
@@ -19,8 +86,6 @@
[@blink1073](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Ablink1073+updated%3A2022-06-23..2022-07-05&type=Issues)
|
[@Carreau](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3ACarreau+updated%3A2022-06-23..2022-07-05&type=Issues)
|
[@codecov-commenter](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Acodecov-commenter+updated%3A2022-06-23..2022-07-05&type=Issues)
|
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Adavidbrochart+updated%3A2022-06-23..2022-07-05&type=Issues)
|
[@echarles](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Aecharles+updated%3A2022-06-23..2022-07-05&type=Issues)
|
[@kevin-bates](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_server+involves%3Akevin-bates+updated%3A2022-06-23..2022-07-05&type=Issues)
|
[@meeseeksmachine](https://github.com/search?q=repo%3Ajupyter-server%2Fjupyter_se
rver+involves%3Ameeseeksmachine+updated%3A2022-06-23..2022-07-05&type=Issues)
-<!-- <END NEW CHANGELOG ENTRY> -->
-
## 1.18.0
([Full
Changelog](https://github.com/jupyter-server/jupyter_server/compare/v1.17.1...a625db91efc4927c4b6fed4bf67ab995e479c36d))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/PKG-INFO
new/jupyter_server-1.21.0/PKG-INFO
--- old/jupyter_server-1.18.1/PKG-INFO 2022-07-05 22:23:12.652353500 +0200
+++ new/jupyter_server-1.21.0/PKG-INFO 2022-10-11 13:35:20.650097600 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: jupyter_server
-Version: 1.18.1
+Version: 1.21.0
Summary: The backend???i.e. core services, APIs, and REST endpoints???to
Jupyter web applications.
Home-page: https://jupyter-server.readthedocs.io
Author: Jupyter Development Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/RELEASE.md
new/jupyter_server-1.21.0/RELEASE.md
--- old/jupyter_server-1.18.1/RELEASE.md 2022-07-05 22:22:43.000000000
+0200
+++ new/jupyter_server-1.21.0/RELEASE.md 2022-10-11 13:34:37.000000000
+0200
@@ -4,6 +4,9 @@
The recommended way to make a release is to use
[`jupyter_releaser`](https://github.com/jupyter-server/jupyter_releaser#checklist-for-adoption).
+Note that we must use manual versions since Jupyter Releaser does not
+yet support "next" or "patch" when dev versions are used.
+
## Manual Release
To create a manual release, perform the following steps:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/docs/doc-requirements.txt
new/jupyter_server-1.21.0/docs/doc-requirements.txt
--- old/jupyter_server-1.18.1/docs/doc-requirements.txt 2022-07-05
22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/docs/doc-requirements.txt 2022-10-11
13:34:37.000000000 +0200
@@ -1,6 +1,11 @@
+# needed because m2r uses deprecated APIs
+# m2r is depended on by sphinxcontrib-openapi
+docutils<0.19
ipykernel
jinja2
jupyter_client
+jupyter_server
+mistune<1.0.0
myst-parser
nbformat
prometheus_client
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/docs/source/conf.py
new/jupyter_server-1.21.0/docs/source/conf.py
--- old/jupyter_server-1.18.1/docs/source/conf.py 2022-07-05
22:22:58.000000000 +0200
+++ new/jupyter_server-1.21.0/docs/source/conf.py 2022-10-11
13:35:02.000000000 +0200
@@ -107,7 +107,7 @@
# |version| and |release|, also used in various other places throughout the
# built documents.
#
-__version__ = "1.18.1"
+__version__ = "1.21.0"
# The short X.Y version.
version_parsed = parse_version(__version__)
version = f"{version_parsed.major}.{version_parsed.minor}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/docs/source/operators/public-server.rst
new/jupyter_server-1.21.0/docs/source/operators/public-server.rst
--- old/jupyter_server-1.18.1/docs/source/operators/public-server.rst
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/docs/source/operators/public-server.rst
2022-10-11 13:34:37.000000000 +0200
@@ -180,7 +180,7 @@
certificate and follow the steps in :ref:`using-lets-encrypt` to set up a
public server.
-.. _OWASP: https://www.owasp.org/index.php/Main_Page
+.. _OWASP: https://owasp.org/sitemap/
.. _tutorial:
https://arstechnica.com/information-technology/2009/12/how-to-get-set-with-a-secure-sertificate-for-free/
.. _jupyter_public_server:
@@ -364,7 +364,7 @@
.. code-block:: python
- c.GatewayClient.url = http://my-gateway-server:8888
+ c.GatewayClient.url = 'http://my-gateway-server:8888'
When provided, all kernel specifications will be retrieved from the specified
Gateway server and all
kernels will be managed by that server. This option enables the ability to
target kernel processes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/jupyter_server/_version.py
new/jupyter_server-1.21.0/jupyter_server/_version.py
--- old/jupyter_server-1.18.1/jupyter_server/_version.py 2022-07-05
22:22:58.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server/_version.py 2022-10-11
13:35:02.000000000 +0200
@@ -2,5 +2,5 @@
store the current version info of the server.
"""
-version_info = (1, 18, 1, "", "")
+version_info = (1, 21, 0, "", "")
__version__ = ".".join(map(str, version_info[:3])) + "".join(version_info[3:])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server/base/handlers.py
new/jupyter_server-1.21.0/jupyter_server/base/handlers.py
--- old/jupyter_server-1.18.1/jupyter_server/base/handlers.py 2022-07-05
22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server/base/handlers.py 2022-10-11
13:34:37.000000000 +0200
@@ -95,7 +95,7 @@
# tornado raise Exception (not a subclass)
# if method is unsupported (websocket and
Access-Control-Allow-Origin
# for example, so just ignore)
- self.log.debug(e)
+ self.log.exception("Could not set default headers: %s", e)
def force_clear_cookie(self, name, path="/", domain=None):
"""Deletes the cookie with the given name.
@@ -646,7 +646,7 @@
reply["message"] = "Unhandled error"
reply["reason"] = None
reply["traceback"] =
"".join(traceback.format_exception(*exc_info))
- self.log.warning(reply["message"])
+ self.log.warning("wrote error: %r", reply["message"])
self.finish(json.dumps(reply))
def get_current_user(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server/extension/manager.py
new/jupyter_server-1.21.0/jupyter_server/extension/manager.py
--- old/jupyter_server-1.18.1/jupyter_server/extension/manager.py
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server/extension/manager.py
2022-10-11 13:34:37.000000000 +0200
@@ -1,6 +1,4 @@
import importlib
-import sys
-import traceback
from tornado.gen import multi
from traitlets import Any, Bool, Dict, HasTraits, Instance, Unicode, default,
observe
@@ -326,7 +324,13 @@
except Exception as e:
if self.serverapp.reraise_server_extension_failures:
raise
- self.log.warning(e)
+ self.log.warning(
+ "%s | error adding extension (enabled: %s): %s",
+ extension_name,
+ enabled,
+ e,
+ exc_info=True,
+ )
return False
def link_extension(self, name):
@@ -337,11 +341,11 @@
# Link extension and store links
extension.link_all_points(self.serverapp)
self.linked_extensions[name] = True
- self.log.info(f"{name} | extension was successfully linked.")
+ self.log.info("%s | extension was successfully linked.", name)
except Exception as e:
if self.serverapp.reraise_server_extension_failures:
raise
- self.log.warning(e)
+ self.log.warning("%s | error linking extension: %s", name, e,
exc_info=True)
def load_extension(self, name):
extension = self.extensions.get(name)
@@ -352,21 +356,17 @@
except Exception as e:
if self.serverapp.reraise_server_extension_failures:
raise
-
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)
- )
- )
+ self.log.warning("%s | extension failed loading with message:
%s", name, e)
+ self.log.exception("%s | stack trace", name)
else:
- self.log.info(f"{name} | extension was successfully loaded.")
+ self.log.info("%s | extension was successfully loaded.", name)
async def stop_extension(self, name, apps):
"""Call the shutdown hooks in the specified apps."""
for app in apps:
- self.log.debug(f'{name} | extension app "{app.name}" stopping')
+ self.log.debug("%s | extension app %r stopping", name, app.name)
await app.stop_extension()
- self.log.debug(f'{name} | extension app "{app.name}" stopped')
+ self.log.debug("%s | extension app %r stopped", name, app.name)
def link_all_extensions(self):
"""Link all enabled extensions
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server/gateway/gateway_client.py
new/jupyter_server-1.21.0/jupyter_server/gateway/gateway_client.py
--- old/jupyter_server-1.18.1/jupyter_server/gateway/gateway_client.py
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server/gateway/gateway_client.py
2022-10-11 13:34:37.000000000 +0200
@@ -1,11 +1,14 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
+import asyncio
import json
+import logging
import os
+import typing as ty
from socket import gaierror
from tornado import web
-from tornado.httpclient import AsyncHTTPClient, HTTPError
+from tornado.httpclient import AsyncHTTPClient, HTTPClientError, HTTPResponse
from traitlets import Bool, Float, Int, TraitError, Unicode, default, validate
from traitlets.config import SingletonConfigurable
@@ -128,7 +131,7 @@
os.environ.get("JUPYTER_GATEWAY_CONNECT_TIMEOUT",
self.connect_timeout_default_value)
)
- request_timeout_default_value = 40.0
+ request_timeout_default_value = 42.0
request_timeout_env = "JUPYTER_GATEWAY_REQUEST_TIMEOUT"
request_timeout = Float(
default_value=request_timeout_default_value,
@@ -341,6 +344,25 @@
os.environ.get("JUPYTER_GATEWAY_RETRY_MAX",
self.gateway_retry_max_default_value)
)
+ launch_timeout_pad_default_value = 2.0
+ launch_timeout_pad_env = "JUPYTER_GATEWAY_LAUNCH_TIMEOUT_PAD"
+ launch_timeout_pad = Float(
+ default_value=launch_timeout_pad_default_value,
+ config=True,
+ help="""Timeout pad to be ensured between KERNEL_LAUNCH_TIMEOUT and
request_timeout
+ such that request_timeout >= KERNEL_LAUNCH_TIMEOUT +
launch_timeout_pad.
+ (JUPYTER_GATEWAY_LAUNCH_TIMEOUT_PAD env var)""",
+ )
+
+ @default("launch_timeout_pad")
+ def launch_timeout_pad_default(self):
+ return float(
+ os.environ.get(
+ "JUPYTER_GATEWAY_LAUNCH_TIMEOUT_PAD",
+ self.launch_timeout_pad_default_value,
+ )
+ )
+
@property
def gateway_enabled(self):
return bool(self.url is not None and len(self.url) > 0)
@@ -353,12 +375,18 @@
perform this operation once.
"""
- # Ensure that request timeout and KERNEL_LAUNCH_TIMEOUT are the same,
taking the
- # greater value of the two.
- if self.request_timeout < float(GatewayClient.KERNEL_LAUNCH_TIMEOUT):
- self.request_timeout = float(GatewayClient.KERNEL_LAUNCH_TIMEOUT)
- elif self.request_timeout > float(GatewayClient.KERNEL_LAUNCH_TIMEOUT):
- GatewayClient.KERNEL_LAUNCH_TIMEOUT = int(self.request_timeout)
+ # Ensure that request timeout and KERNEL_LAUNCH_TIMEOUT are in sync,
taking the
+ # greater value of the two and taking into account the following
relation:
+ # request_timeout = KERNEL_LAUNCH_TIME + padding
+ minimum_request_timeout = (
+ float(GatewayClient.KERNEL_LAUNCH_TIMEOUT) +
self.launch_timeout_pad
+ )
+ if self.request_timeout < minimum_request_timeout:
+ self.request_timeout = minimum_request_timeout
+ elif self.request_timeout > minimum_request_timeout:
+ GatewayClient.KERNEL_LAUNCH_TIMEOUT = int(
+ self.request_timeout - self.launch_timeout_pad
+ )
# Ensure any adjustments are reflected in env.
os.environ["KERNEL_LAUNCH_TIMEOUT"] =
str(GatewayClient.KERNEL_LAUNCH_TIMEOUT)
@@ -388,44 +416,112 @@
if len(self._static_args) == 0:
self.init_static_args()
- kwargs.update(self._static_args)
+ for arg, static_value in self._static_args.items():
+ if arg == "headers":
+ given_value = kwargs.setdefault(arg, {})
+ if isinstance(given_value, dict):
+ given_value.update(static_value)
+ else:
+ kwargs[arg] = static_value
+
return kwargs
-async def gateway_request(endpoint, **kwargs):
+class RetryableHTTPClient:
+ """
+ Inspired by urllib.util.Retry
(https://urllib3.readthedocs.io/en/stable/reference/urllib3.util.html),
+ this class is initialized with desired retry characteristics, uses a
recursive method `fetch()` against an instance
+ of `AsyncHTTPClient` which tracks the current retry count across
applicable request retries.
+ """
+
+ MAX_RETRIES_DEFAULT = 2
+ MAX_RETRIES_CAP = 10 # The upper limit to max_retries value.
+ max_retries: int = int(os.getenv("JUPYTER_GATEWAY_MAX_REQUEST_RETRIES",
MAX_RETRIES_DEFAULT))
+ max_retries = max(0, min(max_retries, MAX_RETRIES_CAP)) # Enforce
boundaries
+ retried_methods: ty.Set[str] = {"GET", "DELETE"}
+ retried_errors: ty.Set[int] = {502, 503, 504, 599}
+ retried_exceptions: ty.Set[type] = {ConnectionError}
+ backoff_factor: float = 0.1
+
+ def __init__(self):
+ self.retry_count: int = 0
+ self.client: AsyncHTTPClient = AsyncHTTPClient()
+
+ async def fetch(self, endpoint: str, **kwargs: ty.Any) -> HTTPResponse:
+ """
+ Retryable AsyncHTTPClient.fetch() method. When the request fails,
this method will
+ recurse up to max_retries times if the condition deserves a retry.
+ """
+ self.retry_count = 0
+ return await self._fetch(endpoint, **kwargs)
+
+ async def _fetch(self, endpoint: str, **kwargs: ty.Any) -> HTTPResponse:
+ """
+ Performs the fetch against the contained AsyncHTTPClient instance and
determines
+ if retry is necessary on any exceptions. If so, retry is performed
recursively.
+ """
+ try:
+ response: HTTPResponse = await self.client.fetch(endpoint,
**kwargs)
+ except Exception as e:
+ is_retryable: bool = await self._is_retryable(kwargs["method"], e)
+ if not is_retryable:
+ raise e
+ logging.getLogger("ServerApp").info(
+ f"Attempting retry ({self.retry_count}) against "
+ f"endpoint '{endpoint}'. Retried error: '{repr(e)}'"
+ )
+ response = await self._fetch(endpoint, **kwargs)
+ return response
+
+ async def _is_retryable(self, method: str, exception: Exception) -> bool:
+ """Determines if the given exception is retryable based on object's
configuration."""
+
+ if method not in self.retried_methods:
+ return False
+ if self.retry_count == self.max_retries:
+ return False
+
+ # Determine if error is retryable...
+ if isinstance(exception, HTTPClientError):
+ hce: HTTPClientError = exception
+ if hce.code not in self.retried_errors:
+ return False
+ elif not any(isinstance(exception, error) for error in
self.retried_exceptions):
+ return False
+
+ # Is retryable, wait for backoff, then increment count
+ await asyncio.sleep(self.backoff_factor * (2**self.retry_count))
+ self.retry_count += 1
+ return True
+
+
+async def gateway_request(endpoint: str, **kwargs: ty.Any) -> HTTPResponse:
"""Make an async request to kernel gateway endpoint, returns a response"""
- client = AsyncHTTPClient()
kwargs = GatewayClient.instance().load_connection_args(**kwargs)
+ rhc = RetryableHTTPClient()
try:
- response = await client.fetch(endpoint, **kwargs)
+ response = await rhc.fetch(endpoint, **kwargs)
# Trap a set of common exceptions so that we can inform the user that
their Gateway url is incorrect
# or the server is not running.
- # NOTE: We do this here since this handler is called during the Notebook's
startup and subsequent refreshes
+ # NOTE: We do this here since this handler is called during the server's
startup and subsequent refreshes
# of the tree view.
- except ConnectionRefusedError as e:
+ except HTTPClientError as e:
raise web.HTTPError(
- 503,
- "Connection refused from Gateway server url '{}'. "
- "Check to be sure the Gateway instance is running.".format(
- GatewayClient.instance().url
- ),
+ e.code,
+ f"Error attempting to connect to Gateway server url
'{GatewayClient.instance().url}'. "
+ "Ensure gateway url is valid and the Gateway instance is running.",
) from e
- except HTTPError as e:
- # This can occur if the host is valid (e.g., foo.com) but there's
nothing there.
+ except ConnectionError as e:
raise web.HTTPError(
- e.code,
- "Error attempting to connect to Gateway server url '{}'. "
- "Ensure gateway url is valid and the Gateway instance is
running.".format(
- GatewayClient.instance().url
- ),
+ 503,
+ f"ConnectionError was received from Gateway server url
'{GatewayClient.instance().url}'. "
+ "Check to be sure the Gateway instance is running.",
) from e
except gaierror as e:
raise web.HTTPError(
404,
- "The Gateway server specified in the gateway_url '{}' doesn't
appear to be valid. "
- "Ensure gateway url is valid and the Gateway instance is
running.".format(
- GatewayClient.instance().url
- ),
+ f"The Gateway server specified in the gateway_url
'{GatewayClient.instance().url}' doesn't "
+ f"appear to be valid. Ensure gateway url is valid and the Gateway
instance is running.",
) from e
return response
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server/gateway/managers.py
new/jupyter_server-1.21.0/jupyter_server/gateway/managers.py
--- old/jupyter_server-1.18.1/jupyter_server/gateway/managers.py
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server/gateway/managers.py
2022-10-11 13:34:37.000000000 +0200
@@ -326,7 +326,8 @@
self.kernels_url = url_path_join(
GatewayClient.instance().url,
GatewayClient.instance().kernels_endpoint
)
- self.kernel_url = self.kernel = self.kernel_id = None
+ self.kernel_url: str
+ self.kernel = self.kernel_id = None
# simulate busy/activity markers:
self.execution_state = self.last_activity = None
@@ -435,7 +436,12 @@
json_body = json_encode({"name": kernel_name, "env": kernel_env})
- response = await gateway_request(self.kernels_url, method="POST",
body=json_body)
+ response = await gateway_request(
+ self.kernels_url,
+ method="POST",
+ headers={"Content-Type": "application/json"},
+ body=json_body,
+ )
self.kernel = json_decode(response.body)
self.kernel_id = self.kernel["id"]
self.kernel_url = url_path_join(self.kernels_url,
url_escape(str(self.kernel_id)))
@@ -466,7 +472,12 @@
assert self.kernel_url is not None
kernel_url = self.kernel_url + "/restart"
self.log.debug("Request restart kernel at: %s", kernel_url)
- response = await gateway_request(kernel_url, method="POST",
body=json_encode({}))
+ response = await gateway_request(
+ kernel_url,
+ method="POST",
+ headers={"Content-Type": "application/json"},
+ body=json_encode({}),
+ )
self.log.debug("Restart kernel response: %d %s", response.code,
response.reason)
async def interrupt_kernel(self):
@@ -475,7 +486,12 @@
assert self.kernel_url is not None
kernel_url = self.kernel_url + "/interrupt"
self.log.debug("Request interrupt kernel at: %s", kernel_url)
- response = await gateway_request(kernel_url, method="POST",
body=json_encode({}))
+ response = await gateway_request(
+ kernel_url,
+ method="POST",
+ headers={"Content-Type": "application/json"},
+ body=json_encode({}),
+ )
self.log.debug("Interrupt kernel response: %d %s", response.code,
response.reason)
async def is_alive(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server/services/kernels/handlers.py
new/jupyter_server-1.21.0/jupyter_server/services/kernels/handlers.py
--- old/jupyter_server-1.18.1/jupyter_server/services/kernels/handlers.py
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server/services/kernels/handlers.py
2022-10-11 13:34:37.000000000 +0200
@@ -4,6 +4,7 @@
"""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
+import asyncio
import json
from textwrap import dedent
from traceback import format_tb
@@ -15,8 +16,9 @@
except ImportError:
from jupyter_client.jsonutil import date_default as json_default
+from concurrent.futures import Future
+
from tornado import gen, web
-from tornado.concurrent import Future
from tornado.ioloop import IOLoop
from jupyter_server.auth import authorized
@@ -55,7 +57,9 @@
else:
model.setdefault("name", km.default_kernel_name)
- kernel_id = await km.start_kernel(kernel_name=model["name"],
path=model.get("path"))
+ kernel_id = await ensure_async(
+ km.start_kernel(kernel_name=model["name"], path=model.get("path"))
+ )
model = await ensure_async(km.kernel_model(kernel_id))
location = url_path_join(self.base_url, "api", "kernels",
url_escape(kernel_id))
self.set_header("Location", location)
@@ -104,6 +108,15 @@
self.finish()
+def _ensure_future(f):
+ """Wrap a concurrent future as an asyncio future if there is a running
loop."""
+ try:
+ asyncio.get_running_loop()
+ return asyncio.wrap_future(f)
+ except RuntimeError:
+ return f
+
+
class ZMQChannelsHandler(AuthenticatedZMQStreamHandler):
"""There is one ZMQChannelsHandler per running kernel and it oversees all
the sessions.
@@ -182,7 +195,7 @@
self.log.debug("Nudge: not nudging busy kernel %s", self.kernel_id)
f: Future = Future()
f.set_result(None)
- return f
+ return _ensure_future(f)
# Use a transient shell channel to prevent leaking
# shell responses to the front-end.
shell_channel = kernel.connect_shell()
@@ -283,7 +296,7 @@
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
+ return _ensure_future(future)
def request_kernel_info(self):
"""send a request for kernel_info"""
@@ -307,7 +320,7 @@
if not future.done():
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
+ return _ensure_future(self._kernel_info_future)
def _handle_kernel_info_reply(self, msg):
"""process the kernel_info_reply
@@ -384,8 +397,11 @@
kernel = self.kernel_manager.get_kernel(self.kernel_id)
if hasattr(kernel, "ready"):
+ ready = kernel.ready
+ if not isinstance(ready, asyncio.Future):
+ ready = asyncio.wrap_future(ready)
try:
- await kernel.ready
+ await ready
except Exception as e:
kernel.execution_state = "dead"
kernel.reason = str(e)
@@ -404,7 +420,7 @@
loop = IOLoop.current()
loop.add_timeout(loop.time() + self.kernel_info_timeout, give_up)
# actually wait for it
- await future
+ await asyncio.wrap_future(future)
async def get(self, kernel_id):
self.kernel_id = kernel_id
@@ -700,7 +716,7 @@
def close(self):
super().close()
- return self._close_future
+ return _ensure_future(self._close_future)
def on_close(self):
self.log.debug("Websocket closed %s", self.session_key)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server/services/kernels/kernelmanager.py
new/jupyter_server-1.21.0/jupyter_server/services/kernels/kernelmanager.py
--- old/jupyter_server-1.18.1/jupyter_server/services/kernels/kernelmanager.py
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server/services/kernels/kernelmanager.py
2022-10-11 13:34:37.000000000 +0200
@@ -227,15 +227,15 @@
kernel.execution_state = "starting"
kernel.reason = ""
kernel.last_activity = utcnow()
- self.log.info("Kernel started: %s" % kernel_id)
- self.log.debug("Kernel args: %r" % kwargs)
+ self.log.info("Kernel started: %s", kernel_id)
+ self.log.debug("Kernel args: %r", kwargs)
# Increase the metric of number of kernels running
# for the relevant kernel type by 1
KERNEL_CURRENTLY_RUNNING_TOTAL.labels(type=self._kernels[kernel_id].kernel_name).inc()
else:
- self.log.info("Using existing kernel: %s" % kernel_id)
+ self.log.info("Using existing kernel: %s", kernel_id)
# Initialize culling if not already
if not self._initialized_culler:
@@ -246,10 +246,13 @@
async def _finish_kernel_start(self, kernel_id):
km = self.get_kernel(kernel_id)
if hasattr(km, "ready"):
+ ready = km.ready
+ if not isinstance(ready, asyncio.Future):
+ ready = asyncio.wrap_future(ready)
try:
- await km.ready
- except Exception as e:
- self.log.exception(e)
+ await ready
+ except Exception:
+ self.log.exception("Error waiting for kernel manager ready")
return
self._kernel_ports[kernel_id] = km.ports
@@ -276,7 +279,7 @@
changed_ports = self._get_changed_ports(kernel_id)
if changed_ports:
# If changed, update captured ports and return True, else return
False.
- self.log.debug(f"Port change detected for kernel: {kernel_id}")
+ self.log.debug("Port change detected for kernel: %s", kernel_id)
self._kernel_ports[kernel_id] = changed_ports
return True
return False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server/services/nbconvert/handlers.py
new/jupyter_server-1.21.0/jupyter_server/services/nbconvert/handlers.py
--- old/jupyter_server-1.18.1/jupyter_server/services/nbconvert/handlers.py
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server/services/nbconvert/handlers.py
2022-10-11 13:34:37.000000000 +0200
@@ -11,11 +11,16 @@
AUTH_RESOURCE = "nbconvert"
-LOCK = asyncio.Lock()
-
-
class NbconvertRootHandler(APIHandler):
auth_resource = AUTH_RESOURCE
+ _exporter_lock: asyncio.Lock
+
+ def initialize(self, **kwargs):
+ super().initialize(**kwargs)
+ # share lock across instances of this handler class
+ if not hasattr(self.__class__, "_exporter_lock"):
+ self.__class__._exporter_lock = asyncio.Lock()
+ self._exporter_lock = self.__class__._exporter_lock
@web.authenticated
@authorized
@@ -28,22 +33,22 @@
# Some exporters use the filesystem when instantiating, delegate that
# to a thread so we don't block the event loop for it.
exporters = await run_sync(base.get_export_names)
- for exporter_name in exporters:
- try:
- async with LOCK:
+ async with self._exporter_lock:
+ for exporter_name in exporters:
+ try:
exporter_class = await run_sync(base.get_exporter,
exporter_name)
- except ValueError:
- # I think the only way this will happen is if the entrypoint
- # is uninstalled while this method is running
- continue
- # XXX: According to the docs, it looks like this should be set to
None
- # if the exporter shouldn't be exposed to the front-end and a
friendly
- # name if it should. However, none of the built-in exports have it
defined.
- # if not exporter_class.export_from_notebook:
- # continue
- res[exporter_name] = {
- "output_mimetype": exporter_class.output_mimetype,
- }
+ except ValueError:
+ # I think the only way this will happen is if the
entrypoint
+ # is uninstalled while this method is running
+ continue
+ # XXX: According to the docs, it looks like this should be set
to None
+ # if the exporter shouldn't be exposed to the front-end and a
friendly
+ # name if it should. However, none of the built-in exports
have it defined.
+ # if not exporter_class.export_from_notebook:
+ # continue
+ res[exporter_name] = {
+ "output_mimetype": exporter_class.output_mimetype,
+ }
self.finish(json.dumps(res))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server/services/sessions/sessionmanager.py
new/jupyter_server-1.21.0/jupyter_server/services/sessions/sessionmanager.py
---
old/jupyter_server-1.18.1/jupyter_server/services/sessions/sessionmanager.py
2022-07-05 22:22:43.000000000 +0200
+++
new/jupyter_server-1.21.0/jupyter_server/services/sessions/sessionmanager.py
2022-10-11 13:34:37.000000000 +0200
@@ -1,6 +1,7 @@
"""A base class session manager."""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
+import os
import pathlib
import uuid
@@ -267,12 +268,19 @@
self._pending_sessions.remove(record)
return result
+ def get_kernel_env(self, path):
+ """Return the environment variables that need to be set in the
kernel"""
+ return {**os.environ, "JPY_SESSION_NAME": path}
+
async def start_kernel_for_session(self, session_id, path, name, type,
kernel_name):
"""Start a new kernel for a given session."""
# allow contents manager to specify kernels cwd
- kernel_path = self.contents_manager.get_kernel_path(path=path)
+ kernel_path = await
ensure_async(self.contents_manager.get_kernel_path(path=path))
+ kernel_env = self.get_kernel_env(path)
kernel_id = await self.kernel_manager.start_kernel(
- path=kernel_path, kernel_name=kernel_name
+ path=kernel_path,
+ kernel_name=kernel_name,
+ env=kernel_env,
)
return kernel_id
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server.egg-info/PKG-INFO
new/jupyter_server-1.21.0/jupyter_server.egg-info/PKG-INFO
--- old/jupyter_server-1.18.1/jupyter_server.egg-info/PKG-INFO 2022-07-05
22:23:12.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server.egg-info/PKG-INFO 2022-10-11
13:35:20.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: jupyter-server
-Version: 1.18.1
+Version: 1.21.0
Summary: The backend???i.e. core services, APIs, and REST endpoints???to
Jupyter web applications.
Home-page: https://jupyter-server.readthedocs.io
Author: Jupyter Development Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/jupyter_server.egg-info/requires.txt
new/jupyter_server-1.21.0/jupyter_server.egg-info/requires.txt
--- old/jupyter_server-1.18.1/jupyter_server.egg-info/requires.txt
2022-07-05 22:23:12.000000000 +0200
+++ new/jupyter_server-1.21.0/jupyter_server.egg-info/requires.txt
2022-10-11 13:35:20.000000000 +0200
@@ -26,5 +26,5 @@
pytest-mock
pytest-timeout
pytest-tornasync
-pytest>=6.0
+pytest>=7.0
requests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/pyproject.toml
new/jupyter_server-1.21.0/pyproject.toml
--- old/jupyter_server-1.18.1/pyproject.toml 2022-07-05 22:22:58.000000000
+0200
+++ new/jupyter_server-1.21.0/pyproject.toml 2022-10-11 13:35:02.000000000
+0200
@@ -34,7 +34,7 @@
post-version-spec = "dev"
[tool.tbump.version]
-current = "1.18.1"
+current = "1.21.0"
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.18.1/setup.cfg
new/jupyter_server-1.21.0/setup.cfg
--- old/jupyter_server-1.18.1/setup.cfg 2022-07-05 22:23:12.652353500 +0200
+++ new/jupyter_server-1.21.0/setup.cfg 2022-10-11 13:35:20.650097600 +0200
@@ -65,7 +65,7 @@
pytest-mock
pytest-timeout
pytest-tornasync
- pytest>=6.0
+ pytest>=7.0
requests
requests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/tests/extension/test_app.py
new/jupyter_server-1.21.0/tests/extension/test_app.py
--- old/jupyter_server-1.18.1/tests/extension/test_app.py 2022-07-05
22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/tests/extension/test_app.py 2022-10-11
13:34:37.000000000 +0200
@@ -161,8 +161,8 @@
run_sync(jp_serverapp.cleanup_extensions())
assert [msg for *_, msg in caplog.record_tuples] == [
"Shutting down 1 extension",
- f'{extension_name} | extension app "mockextension" stopping',
- f'{extension_name} | extension app "mockextension" stopped',
+ f"{extension_name} | extension app 'mockextension' stopping",
+ f"{extension_name} | extension app 'mockextension' stopped",
]
# check the shutdown method was called once
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/tests/services/kernels/test_api.py
new/jupyter_server-1.21.0/tests/services/kernels/test_api.py
--- old/jupyter_server-1.18.1/tests/services/kernels/test_api.py
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/tests/services/kernels/test_api.py
2022-10-11 13:34:37.000000000 +0200
@@ -1,3 +1,4 @@
+import asyncio
import json
import os
import time
@@ -22,7 +23,10 @@
if getattr(km, "use_pending_kernels", False):
kernel = km.get_kernel(kernel_id)
if getattr(kernel, "ready", None):
- await kernel.ready
+ ready = kernel.ready
+ if not isinstance(ready, asyncio.Future):
+ ready = asyncio.wrap_future(ready)
+ await ready
return _
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_server-1.18.1/tests/services/sessions/test_api.py
new/jupyter_server-1.21.0/tests/services/sessions/test_api.py
--- old/jupyter_server-1.18.1/tests/services/sessions/test_api.py
2022-07-05 22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/tests/services/sessions/test_api.py
2022-10-11 13:34:37.000000000 +0200
@@ -1,3 +1,4 @@
+import asyncio
import json
import os
import shutil
@@ -163,7 +164,10 @@
kernel_id = session["kernel"]["id"]
kernel = mkm.get_kernel(kernel_id)
if getattr(kernel, "ready", None):
- await kernel.ready
+ ready = kernel.ready
+ if not isinstance(ready, asyncio.Future):
+ ready = asyncio.wrap_future(ready)
+ await ready
return _
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_server-1.18.1/tests/test_gateway.py
new/jupyter_server-1.21.0/tests/test_gateway.py
--- old/jupyter_server-1.18.1/tests/test_gateway.py 2022-07-05
22:22:43.000000000 +0200
+++ new/jupyter_server-1.21.0/tests/test_gateway.py 2022-10-11
13:34:37.000000000 +0200
@@ -186,6 +186,7 @@
monkeypatch.setenv("JUPYTER_GATEWAY_HTTP_USER", mock_http_user)
monkeypatch.setenv("JUPYTER_GATEWAY_REQUEST_TIMEOUT", "44.4")
monkeypatch.setenv("JUPYTER_GATEWAY_CONNECT_TIMEOUT", "44.4")
+ monkeypatch.setenv("JUPYTER_GATEWAY_LAUNCH_TIMEOUT_PAD", "1.1")
yield
GatewayClient.clear_instance()
@@ -198,11 +199,10 @@
jp_serverapp.gateway_config.connect_timeout ==
jp_serverapp.gateway_config.request_timeout
)
assert jp_serverapp.gateway_config.connect_timeout == 44.4
+ assert jp_serverapp.gateway_config.launch_timeout_pad == 1.1
GatewayClient.instance().init_static_args()
- assert GatewayClient.instance().KERNEL_LAUNCH_TIMEOUT == int(
- jp_serverapp.gateway_config.request_timeout
- )
+ assert GatewayClient.instance().KERNEL_LAUNCH_TIMEOUT == 43
async def test_gateway_cli_options(jp_configurable_serverapp):
@@ -211,6 +211,7 @@
"--GatewayClient.http_user=" + mock_http_user,
"--GatewayClient.connect_timeout=44.4",
"--GatewayClient.request_timeout=96.0",
+ "--GatewayClient.launch_timeout_pad=5.1",
]
GatewayClient.clear_instance()
@@ -221,10 +222,40 @@
assert app.gateway_config.http_user == mock_http_user
assert app.gateway_config.connect_timeout == 44.4
assert app.gateway_config.request_timeout == 96.0
+ assert app.gateway_config.launch_timeout_pad == 5.1
GatewayClient.instance().init_static_args()
assert (
- GatewayClient.instance().KERNEL_LAUNCH_TIMEOUT == 96
- ) # Ensure KLT gets set from request-timeout
+ GatewayClient.instance().KERNEL_LAUNCH_TIMEOUT == 90
+ ) # Ensure KLT gets set from request-timeout - launch_timeout_pad
+ GatewayClient.clear_instance()
+
+
[email protected](
+
"request_timeout,kernel_launch_timeout,expected_request_timeout,expected_kernel_launch_timeout",
+ [(50, 10, 50, 45), (10, 50, 55, 50)],
+)
+async def test_gateway_request_timeout_pad_option(
+ jp_configurable_serverapp,
+ monkeypatch,
+ request_timeout,
+ kernel_launch_timeout,
+ expected_request_timeout,
+ expected_kernel_launch_timeout,
+):
+ argv = [
+ f"--GatewayClient.request_timeout={request_timeout}",
+ "--GatewayClient.launch_timeout_pad=5",
+ ]
+
+ GatewayClient.clear_instance()
+ app = jp_configurable_serverapp(argv=argv)
+
+ monkeypatch.setattr(GatewayClient, "KERNEL_LAUNCH_TIMEOUT",
kernel_launch_timeout)
+ GatewayClient.instance().init_static_args()
+
+ assert app.gateway_config.request_timeout == expected_request_timeout
+ assert GatewayClient.instance().KERNEL_LAUNCH_TIMEOUT ==
expected_kernel_launch_timeout
+
GatewayClient.clear_instance()