Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-jupyter-client for
openSUSE:Factory checked in at 2026-03-11 20:50:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jupyter-client (Old)
and /work/SRC/openSUSE:Factory/.python-jupyter-client.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jupyter-client"
Wed Mar 11 20:50:25 2026 rev:30 rq:1338104 version:8.8.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-jupyter-client/python-jupyter-client.changes
2025-12-19 16:42:50.906350867 +0100
+++
/work/SRC/openSUSE:Factory/.python-jupyter-client.new.8177/python-jupyter-client.changes
2026-03-11 20:51:17.804030773 +0100
@@ -1,0 +2,17 @@
+Tue Mar 10 21:59:08 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 8.8.0:
+ * Added kernel_protocol_version to kernelspec #1097
+ * Faster message serialization
+ * Path resolution by kernel manager and providers #1005
+ * chore: update some parts of the pre-commit #1093 (@henryiii,
+ * Fix flaky client tests by waiting for first request's reply
+ * Re-enable qtconsole in downstream checks #1090 (@rgbkrk)
+ * Fix channel cleanup by closing streams before stopping ioloop
+ thread #1089 (@rgbkrk)
+ * Fix downstream workflow #1087 (@rgbkrk)
+ * Skip mypy on PyPy to avoid librt compilation issues #1086
+ * Upgrade to version 5.5 #1096
+ * Update messaging spec #1095
+
+-------------------------------------------------------------------
Old:
----
jupyter_client-8.7.0.tar.gz
New:
----
jupyter_client-8.8.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-jupyter-client.spec ++++++
--- /var/tmp/diff_new_pack.jmhAaP/_old 2026-03-11 20:51:18.440057100 +0100
+++ /var/tmp/diff_new_pack.jmhAaP/_new 2026-03-11 20:51:18.444057266 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-jupyter-client
#
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -26,7 +26,7 @@
%endif
%{?sle15_python_module_pythons}
Name: python-jupyter-client%{psuffix}
-Version: 8.7.0
+Version: 8.8.0
Release: 0
Summary: Jupyter protocol implementation and client libraries
License: BSD-3-Clause
++++++ jupyter_client-8.7.0.tar.gz -> jupyter_client-8.8.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_client-8.7.0/.github/workflows/downstream.yml
new/jupyter_client-8.8.0/.github/workflows/downstream.yml
--- old/jupyter_client-8.7.0/.github/workflows/downstream.yml 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/.github/workflows/downstream.yml 2020-02-02
01:00:00.000000000 +0100
@@ -30,6 +30,8 @@
with:
package_name: nbclient
env_values: IPYKERNEL_CELL_NAME=\<IPY-INPUT\>
+ # Skip test with execution_count mismatch - nbclient test issue, not
jupyter_client
+ test_command: "pytest -vv -raXxs -W default --durations 10
--color=yes --deselect
tests/test_client.py::test_run_all_notebooks[update-display-id.ipynb-opts14]"
nbconvert:
runs-on: ubuntu-latest
@@ -62,13 +64,13 @@
- name: Base Setup
uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
- - name: Setup conda ${{ matrix.python-version }}
+ - name: Setup conda
uses: conda-incubator/setup-miniconda@v3
with:
auto-update-conda: true
activate-environment: jupyter_kernel_test
- miniforge-variant: Mambaforge
- python-version: ${{ matrix.python-version }}
+ miniforge-version: latest
+ python-version: "3.10"
- name: Test jupyter_kernel_test
shell: bash -l {0}
@@ -89,7 +91,7 @@
- name: Setup Python
uses: actions/setup-python@v5
with:
- python-version: "3.9"
+ python-version: "3.10"
architecture: "x64"
- name: Install System Packages
@@ -121,7 +123,6 @@
needs:
- ipykernel
- nbclient
- - papermill
- nbconvert
- jupyter_server
- jupyter_kernel_test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/.github/workflows/main.yml
new/jupyter_client-8.8.0/.github/workflows/main.yml
--- old/jupyter_client-8.7.0/.github/workflows/main.yml 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/.github/workflows/main.yml 2020-02-02
01:00:00.000000000 +0100
@@ -19,6 +19,8 @@
jobs:
check_release:
runs-on: ubuntu-latest
+ env:
+ HATCH_ENV: ""
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@@ -124,7 +126,7 @@
test_minimum_verisons:
name: Test Minimum Versions
runs-on: ubuntu-latest
- timeout-minutes: 10
+ timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: jupyterlab/maintainer-tools/.github/actions/base-setup@v1
@@ -141,6 +143,11 @@
run: |
hatch -vv run test:nowarn
+ - name: Run the unit tests with orjson installed
+ run: |
+ hatch -e test run pip install orjson
+ hatch -vv run test:nowarn
+
test_prereleases:
name: Test Prereleases
timeout-minutes: 10
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/.jupyter-releaser.toml
new/jupyter_client-8.8.0/.jupyter-releaser.toml
--- old/jupyter_client-8.7.0/.jupyter-releaser.toml 1970-01-01
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/.jupyter-releaser.toml 2020-02-02
01:00:00.000000000 +0100
@@ -0,0 +1,5 @@
+[options]
+python-packages = ["."]
+
+[hooks]
+before-bump-version = ["pip install hatch"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/.pre-commit-config.yaml
new/jupyter_client-8.8.0/.pre-commit-config.yaml
--- old/jupyter_client-8.7.0/.pre-commit-config.yaml 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/.pre-commit-config.yaml 2020-02-02
01:00:00.000000000 +0100
@@ -30,21 +30,30 @@
hooks:
- id: mdformat
- - repo: https://github.com/pre-commit/mirrors-prettier
- rev: "v4.0.0-alpha.8"
+ - repo: https://github.com/rbubley/mirrors-prettier
+ rev: "v3.7.3"
hooks:
- id: prettier
types_or: [yaml, html, json]
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: "v1.18.2"
+ rev: "v1.19.0"
hooks:
- id: mypy
files: jupyter_client
stages: [manual]
- args: ["--install-types", "--non-interactive"]
+ args: []
additional_dependencies:
- ["traitlets>=5.13", "ipykernel>=6.26", "jupyter_core>=5.3.2"]
+ - traitlets>=5.13
+ - ipykernel>=6.26
+ - jupyter_core>=5.3.2
+ - orjson>=3.11.4
+ - msgpack-types
+ - types-pexpect
+ - types-paramiko
+ - types-netifaces
+ - types-psutil
+ - types-python-dateutil
- repo: https://github.com/adamchainz/blacken-docs
rev: "1.20.0"
@@ -69,13 +78,10 @@
rev: v0.14.0
hooks:
- id: ruff-check
- types_or: [python, jupyter]
args: ["--fix", "--show-fixes"]
- id: ruff-format
- types_or: [python, jupyter]
- repo: https://github.com/scientific-python/cookie
rev: "2025.10.01"
hooks:
- id: sp-repo-review
- additional_dependencies: ["repo-review[cli]"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/CHANGELOG.md
new/jupyter_client-8.8.0/CHANGELOG.md
--- old/jupyter_client-8.7.0/CHANGELOG.md 2020-02-02 01:00:00.000000000
+0100
+++ new/jupyter_client-8.8.0/CHANGELOG.md 2020-02-02 01:00:00.000000000
+0100
@@ -2,6 +2,41 @@
<!-- <START NEW CHANGELOG ENTRY> -->
+## 8.8.0
+
+([Full
Changelog](https://github.com/jupyter/jupyter_client/compare/v8.7.0...523294fc6cb9be685fa25129067a06348edaaab6))
+
+### Enhancements made
+
+- Added kernel_protocol_version to kernelspec
[#1097](https://github.com/jupyter/jupyter_client/pull/1097)
([@JohanMabille](https://github.com/JohanMabille),
[@SylvainCorlay](https://github.com/SylvainCorlay))
+- Faster message serialization
[#1064](https://github.com/jupyter/jupyter_client/pull/1064)
([@fleming79](https://github.com/fleming79),
[@Carreau](https://github.com/Carreau),
[@henryiii](https://github.com/henryiii),
[@krassowski](https://github.com/krassowski),
[@minrk](https://github.com/minrk), [@rgbkrk](https://github.com/rgbkrk))
+- Path resolution by kernel manager and providers
[#1005](https://github.com/jupyter/jupyter_client/pull/1005)
([@krassowski](https://github.com/krassowski),
[@rgbkrk](https://github.com/rgbkrk))
+
+### Maintenance and upkeep improvements
+
+- chore: update some parts of the pre-commit
[#1093](https://github.com/jupyter/jupyter_client/pull/1093)
([@henryiii](https://github.com/henryiii), [@minrk](https://github.com/minrk),
[@rgbkrk](https://github.com/rgbkrk))
+- Fix flaky client tests by waiting for first request's reply
[#1091](https://github.com/jupyter/jupyter_client/pull/1091)
([@rgbkrk](https://github.com/rgbkrk))
+- Re-enable qtconsole in downstream checks
[#1090](https://github.com/jupyter/jupyter_client/pull/1090)
([@rgbkrk](https://github.com/rgbkrk))
+- Fix channel cleanup by closing streams before stopping ioloop thread
[#1089](https://github.com/jupyter/jupyter_client/pull/1089)
([@rgbkrk](https://github.com/rgbkrk))
+- Fix downstream workflow
[#1087](https://github.com/jupyter/jupyter_client/pull/1087)
([@rgbkrk](https://github.com/rgbkrk))
+- Skip mypy on PyPy to avoid librt compilation issues
[#1086](https://github.com/jupyter/jupyter_client/pull/1086)
([@rgbkrk](https://github.com/rgbkrk))
+
+### Documentation improvements
+
+- Upgrade to version 5.5
[#1096](https://github.com/jupyter/jupyter_client/pull/1096)
([@JohanMabille](https://github.com/JohanMabille),
[@SylvainCorlay](https://github.com/SylvainCorlay))
+- Update messaging spec
[#1095](https://github.com/jupyter/jupyter_client/pull/1095)
([@JohanMabille](https://github.com/JohanMabille),
[@minrk](https://github.com/minrk), [@rgbkrk](https://github.com/rgbkrk))
+
+### Contributors to this release
+
+The following people contributed discussions, new ideas, code and
documentation contributions, and review.
+See [our definition of
contributors](https://github-activity.readthedocs.io/en/latest/#how-does-this-tool-define-contributions-in-the-reports).
+
+([GitHub contributors page for this
release](https://github.com/jupyter/jupyter_client/graphs/contributors?from=2025-12-09&to=2026-01-08&type=c))
+
+@Carreau
([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3ACarreau+updated%3A2025-12-09..2026-01-08&type=Issues))
| @ccordoba12
([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Accordoba12+updated%3A2025-12-09..2026-01-08&type=Issues))
| @fleming79
([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Afleming79+updated%3A2025-12-09..2026-01-08&type=Issues))
| @henryiii
([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Ahenryiii+updated%3A2025-12-09..2026-01-08&type=Issues))
| @JohanMabille
([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3AJohanMabille+updated%3A2025-12-09..2026-01-08&type=Issues))
| @krassowski
([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Akrassowski+updated%3A2025-12-09..2026-01-08&type=Issues))
| @minrk ([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_cli
ent+involves%3Aminrk+updated%3A2025-12-09..2026-01-08&type=Issues)) | @rgbkrk
([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Argbkrk+updated%3A2025-12-09..2026-01-08&type=Issues))
| @SylvainCorlay
([activity](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3ASylvainCorlay+updated%3A2025-12-09..2026-01-08&type=Issues))
+
+<!-- <END NEW CHANGELOG ENTRY> -->
+
## 8.7.0
([Full
Changelog](https://github.com/jupyter/jupyter_client/compare/v8.6.3...7b4340d29da062cc2386fa218f645c7e80eb800f))
@@ -40,8 +75,6 @@
[@blink1073](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Ablink1073+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@Carreau](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3ACarreau+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@cben](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Acben+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@davidbrochart](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Adavidbrochart+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@ianthomas23](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Aianthomas23+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@JamesWrigley](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3AJamesWrigley+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@kevin-bates](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Akevin-bates+updated%3A2024-09-17..2025-12-09&type=Issue
s) |
[@krassowski](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Akrassowski+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@minrk](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Aminrk+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@rgbkrk](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Argbkrk+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@sebwills](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Asebwills+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@takluyver](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Atakluyver+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@tmaxwell-anthropic](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Atmaxwell-anthropic+updated%3A2024-09-17..2025-12-09&type=Issues)
|
[@wpk-nist-gov](https://github.com/search?q=repo%3Ajupyter%2Fjupyter_client+involves%3Awpk-nist-gov+updated%3A2024-09-17..2025-12-09&typ
e=Issues)
-<!-- <END NEW CHANGELOG ENTRY> -->
-
## 8.6.3
([Full
Changelog](https://github.com/jupyter/jupyter_client/compare/v8.6.2...7d7251f24ed42c34b9b6ebdf09a5d89c46450131))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/PKG-INFO
new/jupyter_client-8.8.0/PKG-INFO
--- old/jupyter_client-8.7.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: jupyter_client
-Version: 8.7.0
+Version: 8.8.0
Summary: Jupyter protocol implementation and client libraries
Project-URL: Homepage, https://jupyter.org
Project-URL: Documentation, https://jupyter-client.readthedocs.io/
@@ -62,11 +62,14 @@
Requires-Dist: sphinx>=4; extra == 'docs'
Requires-Dist: sphinxcontrib-github-alt; extra == 'docs'
Requires-Dist: sphinxcontrib-spelling; extra == 'docs'
+Provides-Extra: orjson
+Requires-Dist: orjson; extra == 'orjson'
Provides-Extra: test
Requires-Dist: anyio; extra == 'test'
Requires-Dist: coverage; extra == 'test'
Requires-Dist: ipykernel>=6.14; extra == 'test'
-Requires-Dist: mypy; extra == 'test'
+Requires-Dist: msgpack; extra == 'test'
+Requires-Dist: mypy; (platform_python_implementation != 'PyPy') and extra ==
'test'
Requires-Dist: paramiko; (sys_platform == 'win32') and extra == 'test'
Requires-Dist: pre-commit; extra == 'test'
Requires-Dist: pytest; extra == 'test'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/docs/messaging.rst
new/jupyter_client-8.8.0/docs/messaging.rst
--- old/jupyter_client-8.7.0/docs/messaging.rst 2020-02-02 01:00:00.000000000
+0100
+++ new/jupyter_client-8.8.0/docs/messaging.rst 2020-02-02 01:00:00.000000000
+0100
@@ -21,7 +21,7 @@
The Jupyter message specification is versioned independently of the packages
that use it.
-The current version of the specification is 5.4.
+The current version of the specification is 5.5.
.. note::
*New in* and *Changed in* messages in this document refer to versions of the
@@ -84,6 +84,11 @@
5. **Heartbeat**: This socket allows for simple bytestring messages to be sent
between the frontend and the kernel to ensure that they are still connected.
+.. versionchanged:: 5.5
+ The **IOPub** PUB socket is replaced with an XPUB socket,
+ to enable the ``iopub_welcome`` message.
+ There is no other difference between kernel PUB and XPUB sockets from the
client perspective.
+
The actual format of the messages allowed on each of these channels is
specified below. Messages are dicts of dicts with string keys and values that
are reasonably representable in JSON.
@@ -1136,12 +1141,21 @@
.. versionadded:: 5.3
+Kernel info
+-----------
+
+This is the same :ref:`kernel info <msging_kernel_info>` message as that
received on the Shell channel.
+
+.. versionadded:: 5.5
+
Debug request
-------------
This message type is used with debugging kernels to request specific actions
to be performed by the debugger such as adding a breakpoint or stepping into
a code.
+Kernels supporting subshells must include ``'debugger'`` in
``'supported_features'``
+in :ref:`kernel info <msging_kernel_info>` reply messages.
Message type: ``debug_request``::
@@ -1158,6 +1172,8 @@
Debug requests and replies are sent over the ``control`` channel to prevent
queuing behind execution requests.
+.. versionadded:: 5.5
+
Additions to the DAP
~~~~~~~~~~~~~~~~~~~~
@@ -1196,6 +1212,8 @@
}
}
+.. versionadded:: 5.5
+
debugInfo
#########
@@ -1231,11 +1249,14 @@
'stoppedThreads' : list(int), # threads in which the debugger
is currently in a stopped state
'richRendering' : bool, # whether the debugger supports rich
rendering of variables
'exceptionPaths' : list(str), # exception names used to match
leaves or nodes in a tree of exception
+ 'copyToGlobals' : bool, # whether the debugger supports supports
the copyToGlobals request
}
}
The ``source_breakpoint`` schema is specified by the Debug Adapter Protocol.
+.. versionadded:: 5.5
+
inspectVariables
################
@@ -1267,6 +1288,8 @@
}
}
+.. versionadded:: 5.5
+
richInspectVariables
####################
@@ -1297,11 +1320,15 @@
}
}
+.. versionadded:: 5.5
+
copyToGlobals
#############
The ``copyToGlobals`` request allows to copy a variable from the local
variable panel
of the debugger to the ``global`` scope to inspect it after debug session.
+The support for this request is optional and should be indicated to the client
via
+the ``copyToGlobals`` boolean field in the debugInfo reply.
Content of the ``copyToGlobals`` request::
@@ -1414,8 +1441,39 @@
.. versionadded:: 5.5
-Messages on the IOPub (PUB/SUB) channel
-=======================================
+Messages on the IOPub (XPUB/SUB) channel
+========================================
+
+Welcome message
+---------------
+
+This message is sent to a client SUB socket the first time it connects to the
+XPUB kernel socket, to notify the client that the connection is established.
+
+message type: ``iopub_welcome``::
+
+ content = {
+ # The topic the SUB has subscribed to. Can be empty string if
+ # the client has subscribed to all topics.
+ 'subscription' : str,
+ }
+
+.. note::
+
+ This message has no parent header.
+
+.. note::
+
+ Welcome messages do not and cannot identify the client whose subscription
is being received.
+ Receiving an iopub_welcome message with your subscription does not mean it
is in response to
+ your own subscription. However, receiving a message does mean that a
matching subscription has
+ been registered for your client, otherwise no message will be received. So
if only one
+ subscription is registered, as is normally the case, receiving any welcome
message is sufficient
+ to indicate that your client's subscription is fully established. The gist
is that receiving a
+ welcome message is a sufficient condition to establish the
subscription-propagation event, and
+ additional welcome messages should be expected and ignored.
+
+.. versionadded:: 5.5
Streams (stdout, stderr, etc)
------------------------------
@@ -1851,15 +1909,17 @@
Changelog
=========
-5.5 (draft)
------------
+5.5
+---
-- Added ``debug_request/reply`` messages
-- Added ``debug_event`` message
+- Added ``debug_request/reply`` and ``debug_event`` messages.
+- Replaced **IOPUB** PUB socket with an XPUB socket.
+- Added support for :ref:`kernel info <msging_kernel_info>` request on the
Control channel.
- Added ``supported_features`` in :ref:`kernel info <msging_kernel_info>`
reply messages.
- Deprecated ``debugger`` in :ref:`kernel info <msging_kernel_info>` reply
messages as
replaced with ``supported_features``.
- Added ``create_subshell``, ``delete_subshell`` and ``list_subshell``
messages.
+- Added ``copyToGlobals`` debug request
5.4
---
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/jupyter_client/_version.py
new/jupyter_client-8.8.0/jupyter_client/_version.py
--- old/jupyter_client-8.7.0/jupyter_client/_version.py 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/jupyter_client/_version.py 2020-02-02
01:00:00.000000000 +0100
@@ -3,7 +3,7 @@
import re
from typing import Union
-__version__ = "8.7.0"
+__version__ = "8.8.0"
# 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_client-8.7.0/jupyter_client/kernelspec.py
new/jupyter_client-8.8.0/jupyter_client/kernelspec.py
--- old/jupyter_client-8.7.0/jupyter_client/kernelspec.py 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/jupyter_client/kernelspec.py 2020-02-02
01:00:00.000000000 +0100
@@ -30,6 +30,7 @@
mimetype = Unicode()
display_name = Unicode()
language = Unicode()
+ kernel_protocol_version = Unicode()
env = Dict()
resource_dir = Unicode()
interrupt_mode = CaselessStrEnum(["message", "signal"],
default_value="signal")
@@ -55,6 +56,7 @@
"language": self.language,
"interrupt_mode": self.interrupt_mode,
"metadata": self.metadata,
+ "kernel_protocol_version": self.kernel_protocol_version,
}
return d
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/jupyter_client/manager.py
new/jupyter_client-8.8.0/jupyter_client/manager.py
--- old/jupyter_client-8.7.0/jupyter_client/manager.py 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/jupyter_client/manager.py 2020-02-02
01:00:00.000000000 +0100
@@ -280,6 +280,11 @@
# Kernel management
#
--------------------------------------------------------------------------
+ def resolve_path(self, path: str) -> str | None:
+ """Resolve path to given file."""
+ assert self.provisioner is not None
+ return self.provisioner.resolve_path(path)
+
def update_env(self, *, env: t.Dict[str, str]) -> None:
"""
Allow to update the environment of a kernel manager.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_client-8.7.0/jupyter_client/provisioning/local_provisioner.py
new/jupyter_client-8.8.0/jupyter_client/provisioning/local_provisioner.py
--- old/jupyter_client-8.7.0/jupyter_client/provisioning/local_provisioner.py
2020-02-02 01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/jupyter_client/provisioning/local_provisioner.py
2020-02-02 01:00:00.000000000 +0100
@@ -4,6 +4,7 @@
# Distributed under the terms of the Modified BSD License.
import asyncio
import os
+import pathlib
import signal
import sys
from typing import TYPE_CHECKING, Any
@@ -32,6 +33,7 @@
pgid = None
ip = None
ports_cached = False
+ cwd = None
@property
def has_process(self) -> bool:
@@ -212,6 +214,7 @@
async def launch_kernel(self, cmd: list[str], **kwargs: Any) ->
KernelConnectionInfo:
"""Launch a kernel with a command."""
+
scrubbed_kwargs = LocalProvisioner._scrub_kwargs(kwargs)
self.process = launch_kernel(cmd, **scrubbed_kwargs)
pgid = None
@@ -223,8 +226,18 @@
self.pid = self.process.pid
self.pgid = pgid
+ self.cwd = kwargs.get("cwd", pathlib.Path.cwd())
return self.connection_info
+ def resolve_path(self, path_str: str) -> str | None:
+ """Resolve path to given file."""
+ path = pathlib.Path(path_str).expanduser()
+ if not path.is_absolute() and self.cwd:
+ path = (pathlib.Path(self.cwd) / path).resolve()
+ if path.exists():
+ return path.as_posix()
+ return None
+
@staticmethod
def _scrub_kwargs(kwargs: dict[str, Any]) -> dict[str, Any]:
"""Remove any keyword arguments that Popen does not tolerate."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/jupyter_client-8.7.0/jupyter_client/provisioning/provisioner_base.py
new/jupyter_client-8.8.0/jupyter_client/provisioning/provisioner_base.py
--- old/jupyter_client-8.7.0/jupyter_client/provisioning/provisioner_base.py
2020-02-02 01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/jupyter_client/provisioning/provisioner_base.py
2020-02-02 01:00:00.000000000 +0100
@@ -218,6 +218,21 @@
"""
return recommended
+ def resolve_path(self, path: str) -> str | None:
+ """
+ Returns the path resolved relative to kernel working directory.
+
+ For example, path `my_code.py` for a kernel started in `/tmp/`
+ should result in `/tmp/my_code.py`, while path `~/test.py` for
+ a kernel started in `/home/my_user/` should resolve to the
+ (fully specified) `/home/my_user/test.py` path.
+
+ The provisioner may choose not to resolve any paths, or restrict
+ the resolution to paths local to the kernel working directory
+ to prevent path traversal and exposure of file system layout.
+ """
+ return None
+
def _finalize_env(self, env: dict[str, str]) -> None:
"""
Ensures env is appropriate prior to launch.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/jupyter_client/session.py
new/jupyter_client-8.8.0/jupyter_client/session.py
--- old/jupyter_client-8.7.0/jupyter_client/session.py 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/jupyter_client/session.py 2020-02-02
01:00:00.000000000 +0100
@@ -13,6 +13,7 @@
# Distributed under the terms of the Modified BSD License.
from __future__ import annotations
+import functools
import hashlib
import hmac
import json
@@ -33,6 +34,7 @@
from traitlets import (
Any,
Bool,
+ Callable,
CBytes,
CUnicode,
Dict,
@@ -125,6 +127,41 @@
return json.loads(s)
+try:
+ import orjson
+except ModuleNotFoundError:
+ has_orjson = False
+ orjson_packer, orjson_unpacker = json_packer, json_unpacker
+else:
+ has_orjson = True
+
+ def orjson_packer(
+ obj: t.Any, *, option: int | None = orjson.OPT_NAIVE_UTC |
orjson.OPT_UTC_Z
+ ) -> bytes:
+ """Convert a json object to a bytes using orjson with fallback to
json_packer."""
+ try:
+ return orjson.dumps(obj, default=json_default, option=option)
+ except Exception:
+ return json_packer(obj)
+
+ def orjson_unpacker(s: str | bytes) -> t.Any:
+ """Convert a json bytes or string to an object using orjson with
fallback to json_unpacker."""
+ try:
+ return orjson.loads(s)
+ except Exception:
+ return json_unpacker(s)
+
+
+try:
+ import msgpack
+except ModuleNotFoundError:
+ has_msgpack = False
+else:
+ has_msgpack = True
+ msgpack_packer = functools.partial(msgpack.packb, default=json_default)
+ msgpack_unpacker = msgpack.unpackb
+
+
def pickle_packer(o: t.Any) -> bytes:
"""Pack an object using the pickle module."""
return pickle.dumps(squash_dates(o), PICKLE_PROTOCOL)
@@ -132,8 +169,6 @@
pickle_unpacker = pickle.loads
-default_packer = json_packer
-default_unpacker = json_unpacker
DELIM = b"<IDS|MSG>"
# singleton dummy tracker, which will always report as done
@@ -316,7 +351,7 @@
debug : bool
whether to trigger extra debugging statements
- packer/unpacker : str : 'json', 'pickle' or import_string
+ packer/unpacker : str : 'orjson', 'json', 'pickle', 'msgpack' or
import_string
importstrings for methods to serialize message parts. If just
'json' or 'pickle', predefined JSON and pickle packers will be used.
Otherwise, the entire importstring must be used.
@@ -351,48 +386,42 @@
""",
)
+ # serialization traits:
packer = DottedObjectName(
- "json",
+ "orjson" if has_orjson else "json",
config=True,
help="""The name of the packer for serializing messages.
Should be one of 'json', 'pickle', or an import name
for a custom callable serializer.""",
)
-
- @observe("packer")
- def _packer_changed(self, change: t.Any) -> None:
- new = change["new"]
- if new.lower() == "json":
- self.pack = json_packer
- self.unpack = json_unpacker
- self.unpacker = new
- elif new.lower() == "pickle":
- self.pack = pickle_packer
- self.unpack = pickle_unpacker
- self.unpacker = new
- else:
- self.pack = import_item(str(new))
-
unpacker = DottedObjectName(
- "json",
+ "orjson" if has_orjson else "json",
config=True,
help="""The name of the unpacker for unserializing messages.
Only used with custom functions for `packer`.""",
)
-
- @observe("unpacker")
- def _unpacker_changed(self, change: t.Any) -> None:
- new = change["new"]
- if new.lower() == "json":
- self.pack = json_packer
- self.unpack = json_unpacker
- self.packer = new
- elif new.lower() == "pickle":
- self.pack = pickle_packer
- self.unpack = pickle_unpacker
- self.packer = new
+ pack = Callable(orjson_packer if has_orjson else json_packer) # the
actual packer function
+ unpack = Callable(
+ orjson_unpacker if has_orjson else json_unpacker
+ ) # the actual unpacker function
+
+ @observe("packer", "unpacker")
+ def _packer_unpacker_changed(self, change: t.Any) -> None:
+ new = change["new"].lower()
+ if new == "orjson" and has_orjson:
+ self.pack, self.unpack = orjson_packer, orjson_unpacker
+ elif new == "json" or new == "orjson":
+ self.pack, self.unpack = json_packer, json_unpacker
+ elif new == "pickle":
+ self.pack, self.unpack = pickle_packer, pickle_unpacker
+ elif new == "msgpack" and has_msgpack:
+ self.pack, self.unpack = msgpack_packer, msgpack_unpacker
else:
- self.unpack = import_item(str(new))
+ obj = import_item(str(change["new"]))
+ name = "pack" if change["name"] == "packer" else "unpack"
+ self.set_trait(name, obj)
+ return
+ self.packer = self.unpacker = change["new"]
session = CUnicode("", config=True, help="""The UUID identifying this
session.""")
@@ -417,8 +446,7 @@
metadata = Dict(
{},
config=True,
- help="Metadata dictionary, which serves as the default top-level
metadata dict for each "
- "message.",
+ help="Metadata dictionary, which serves as the default top-level
metadata dict for each message.",
)
# if 0, no adapting to do.
@@ -487,25 +515,6 @@
# for protecting against sends from forks
pid = Integer()
- # serialization traits:
-
- pack = Any(default_packer) # the actual packer function
-
- @observe("pack")
- def _pack_changed(self, change: t.Any) -> None:
- new = change["new"]
- if not callable(new):
- raise TypeError("packer must be callable, not %s" % type(new))
-
- unpack = Any(default_unpacker) # the actual packer function
-
- @observe("unpack")
- def _unpack_changed(self, change: t.Any) -> None:
- # unpacker is not checked - it is assumed to be
- new = change["new"]
- if not callable(new):
- raise TypeError("unpacker must be callable, not %s" % type(new))
-
# thresholds:
copy_threshold = Integer(
2**16,
@@ -515,8 +524,7 @@
buffer_threshold = Integer(
MAX_BYTES,
config=True,
- help="Threshold (in bytes) beyond which an object's buffer should be
extracted to avoid "
- "pickling.",
+ help="Threshold (in bytes) beyond which an object's buffer should be
extracted to avoid pickling.",
)
item_threshold = Integer(
MAX_ITEMS,
@@ -534,7 +542,7 @@
debug : bool
whether to trigger extra debugging statements
- packer/unpacker : str : 'json', 'pickle' or import_string
+ packer/unpacker : str : 'orjson', 'json', 'pickle', 'msgpack' or
import_string
importstrings for methods to serialize message parts. If just
'json' or 'pickle', predefined JSON and pickle packers will be
used.
Otherwise, the entire importstring must be used.
@@ -626,10 +634,7 @@
unpacked = unpack(packed)
assert unpacked == msg_list
except Exception as e:
- msg = (
- f"unpacker '{self.unpacker}' could not handle output from
packer"
- f" '{self.packer}': {e}"
- )
+ msg = f"unpacker {self.unpacker!r} could not handle output from
packer {self.packer!r}: {e}"
raise ValueError(msg) from e
# check datetime support
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/jupyter_client/threaded.py
new/jupyter_client-8.8.0/jupyter_client/threaded.py
--- old/jupyter_client-8.7.0/jupyter_client/threaded.py 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/jupyter_client/threaded.py 2020-02-02
01:00:00.000000000 +0100
@@ -214,7 +214,13 @@
def _flush(self) -> None:
"""Callback for :method:`self.flush`."""
- assert self.stream is not None
+ # Race condition: flush() checks stream validity then schedules this
+ # callback on the ioloop thread. Between scheduling and execution,
+ # stop_channels() may close the stream (e.g., during teardown).
+ # Handle gracefully rather than asserting, since this is an expected
+ # edge case during shutdown, not a programming error.
+ if self.stream is None or self.stream.closed():
+ return
self.stream.flush()
self._flushed = True
@@ -230,6 +236,13 @@
super().__init__()
self.daemon = True
+ # Instance variable to track exit state for this specific thread.
+ # The class variable _exiting is used by _notice_exit for interpreter
shutdown.
+ # Without this instance variable, stopping one IOLoopThread sets the
class-level
+ # _exiting = True, causing all subsequent IOLoopThread instances to
exit immediately
+ # in _async_run(). This breaks sequential kernel usage (e.g.,
qtconsole tests).
+ self._exiting = False
+
@staticmethod
@atexit.register
def _notice_exit() -> None:
@@ -333,6 +346,19 @@
def stop_channels(self) -> None:
"""Stop the channels on the client."""
+ # Close channel streams while ioloop is still running
+ # This must happen before stopping the ioloop thread, otherwise
+ # the ZMQ streams can't be properly unregistered from the event loop
+ if self.ioloop_thread and self.ioloop_thread.is_alive():
+ if self._shell_channel is not None:
+ self._shell_channel.close()
+ if self._iopub_channel is not None:
+ self._iopub_channel.close()
+ if self._stdin_channel is not None:
+ self._stdin_channel.close()
+ if self._control_channel is not None:
+ self._control_channel.close()
+
super().stop_channels()
if self.ioloop_thread and self.ioloop_thread.is_alive():
self.ioloop_thread.stop()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/pyproject.toml
new/jupyter_client-8.8.0/pyproject.toml
--- old/jupyter_client-8.7.0/pyproject.toml 2020-02-02 01:00:00.000000000
+0100
+++ new/jupyter_client-8.8.0/pyproject.toml 2020-02-02 01:00:00.000000000
+0100
@@ -48,13 +48,14 @@
"anyio",
"coverage",
"ipykernel>=6.14",
- "mypy",
+ "mypy; platform_python_implementation != 'PyPy'",
"paramiko; sys_platform == 'win32'",
"pre-commit",
"pytest",
"pytest-jupyter[client]>=0.6.2",
"pytest-cov",
"pytest-timeout",
+ "msgpack"
]
docs = [
"ipykernel",
@@ -65,6 +66,7 @@
"sphinxcontrib-spelling",
"sphinx-autodoc-typehints",
]
+orjson = ["orjson"] # When orjson is installed it will be used for faster pack
and unpack
[project.scripts]
jupyter-kernelspec =
"jupyter_client.kernelspecapp:KernelSpecApp.launch_instance"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/tests/test_client.py
new/jupyter_client-8.8.0/tests/test_client.py
--- old/jupyter_client-8.7.0/tests/test_client.py 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/tests/test_client.py 2020-02-02
01:00:00.000000000 +0100
@@ -50,6 +50,9 @@
kc = self.kc
msg_id = kc.history(session=0)
self.assertIsInstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ kc._recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = kc.history(session=0, reply=True, timeout=TIMEOUT)
self._check_reply("history", reply)
@@ -57,6 +60,9 @@
kc = self.kc
msg_id = kc.inspect("who cares")
self.assertIsInstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ kc._recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = kc.inspect("code", reply=True, timeout=TIMEOUT)
self._check_reply("inspect", reply)
@@ -64,6 +70,9 @@
kc = self.kc
msg_id = kc.complete("who cares")
self.assertIsInstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ kc._recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = kc.complete("code", reply=True, timeout=TIMEOUT)
self._check_reply("complete", reply)
@@ -71,6 +80,9 @@
kc = self.kc
msg_id = kc.kernel_info()
self.assertIsInstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ kc._recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = kc.kernel_info(reply=True, timeout=TIMEOUT)
self._check_reply("kernel_info", reply)
@@ -78,6 +90,9 @@
kc = self.kc
msg_id = kc.comm_info()
self.assertIsInstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ kc._recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = kc.comm_info(reply=True, timeout=TIMEOUT)
self._check_reply("comm_info", reply)
@@ -150,36 +165,54 @@
async def test_history(self, kc):
msg_id = kc.history(session=0)
assert isinstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ await kc._async_recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = await kc.history(session=0, reply=True, timeout=TIMEOUT)
self._check_reply("history", reply)
async def test_inspect(self, kc):
msg_id = kc.inspect("who cares")
assert isinstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ await kc._async_recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = await kc.inspect("code", reply=True, timeout=TIMEOUT)
self._check_reply("inspect", reply)
async def test_complete(self, kc):
msg_id = kc.complete("who cares")
assert isinstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ await kc._async_recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = await kc.complete("code", reply=True, timeout=TIMEOUT)
self._check_reply("complete", reply)
async def test_is_complete(self, kc):
msg_id = kc.is_complete("who cares")
assert isinstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ await kc._async_recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = await kc.is_complete("code", reply=True, timeout=TIMEOUT)
self._check_reply("is_complete", reply)
async def test_kernel_info(self, kc):
msg_id = kc.kernel_info()
assert isinstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ await kc._async_recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = await kc.kernel_info(reply=True, timeout=TIMEOUT)
self._check_reply("kernel_info", reply)
async def test_comm_info(self, kc):
msg_id = kc.comm_info()
assert isinstance(msg_id, str)
+ # Drain the first reply to avoid race condition
+ await kc._async_recv_reply(msg_id, timeout=TIMEOUT)
+ # Now test the reply=True convenience path
reply = await kc.comm_info(reply=True, timeout=TIMEOUT)
self._check_reply("comm_info", reply)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/jupyter_client-8.7.0/tests/test_session.py
new/jupyter_client-8.8.0/tests/test_session.py
--- old/jupyter_client-8.7.0/tests/test_session.py 2020-02-02
01:00:00.000000000 +0100
+++ new/jupyter_client-8.8.0/tests/test_session.py 2020-02-02
01:00:00.000000000 +0100
@@ -9,12 +9,14 @@
import uuid
import warnings
from datetime import datetime
+from pickle import PicklingError
from unittest import mock
import pytest
import zmq
from dateutil.tz import tzlocal
from tornado import ioloop
+from traitlets import TraitError
from zmq.eventloop.zmqstream import ZMQStream
from jupyter_client import jsonutil
@@ -41,6 +43,16 @@
return ss.Session()
+serializers = [
+ ("json", ss.json_packer, ss.json_unpacker),
+ ("pickle", ss.pickle_packer, ss.pickle_unpacker),
+]
+if ss.has_orjson:
+ serializers.append(("orjson", ss.orjson_packer, ss.orjson_unpacker))
+if ss.has_msgpack:
+ serializers.append(("msgpack", ss.msgpack_packer, ss.msgpack_unpacker))
+
+
@pytest.mark.usefixtures("no_copy_threshold")
class TestSession:
def assertEqual(self, a, b):
@@ -64,7 +76,11 @@
self.assertEqual(msg["header"]["msg_type"], "execute")
self.assertEqual(msg["msg_type"], "execute")
- def test_serialize(self, session):
+ @pytest.mark.parametrize(["packer", "pack", "unpack"], serializers)
+ def test_serialize(self, session, packer, pack, unpack):
+ session.packer = packer
+ assert session.pack is pack
+ assert session.unpack is unpack
msg = session.msg("execute", content=dict(a=10, b=1.1))
msg_list = session.serialize(msg, ident=b"foo")
ident, msg_list = session.feed_identities(msg_list)
@@ -234,16 +250,14 @@
def test_args(self, session):
"""initialization arguments for Session"""
s = session
- self.assertTrue(s.pack is ss.default_packer)
- self.assertTrue(s.unpack is ss.default_unpacker)
self.assertEqual(s.username, os.environ.get("USER", "username"))
s = ss.Session()
self.assertEqual(s.username, os.environ.get("USER", "username"))
- with pytest.raises(TypeError):
+ with pytest.raises(TraitError):
ss.Session(pack="hi")
- with pytest.raises(TypeError):
+ with pytest.raises(TraitError):
ss.Session(unpack="hi")
u = str(uuid.uuid4())
s = ss.Session(username="carrot", session=u)
@@ -491,11 +505,6 @@
B.close()
ctx.term()
- def test_set_packer(self, session):
- s = session
- s.packer = "json"
- s.unpacker = "json"
-
def test_clone(self, session):
s = session
s._add_digest("initial")
@@ -515,14 +524,45 @@
assert ss.squash_unicode("hi") == b"hi"
-def test_json_packer():
- ss.json_packer(dict(a=1))
- with pytest.raises(ValueError):
- ss.json_packer(dict(a=ss.Session()))
- ss.json_packer(dict(a=datetime(2021, 4, 1, 12, tzinfo=tzlocal())))
[email protected](
+ ["description", "data"],
+ [
+ ("dict", [{"a": 1}, [{"a": 1}]]),
+ ("infinite", [math.inf, ["inf", None]]),
+ ("datetime", [datetime(2021, 4, 1, 12, tzinfo=tzlocal()), []]),
+ ],
+)
[email protected](["packer", "pack", "unpack"], serializers)
+def test_serialize_objects(packer, pack, unpack, description, data):
+ data_in, data_out_options = data
with warnings.catch_warnings():
warnings.simplefilter("ignore")
- ss.json_packer(dict(a=math.inf))
+ value = pack(data_in)
+ unpacked = unpack(value)
+ if (description == "infinite") and (packer in ["pickle", "msgpack"]):
+ assert math.isinf(unpacked)
+ elif description == "datetime":
+ assert data_in == jsonutil.parse_date(unpacked)
+ else:
+ assert unpacked in data_out_options
+
+
[email protected](["packer", "pack", "unpack"], serializers)
+def test_cannot_serialize(session, packer, pack, unpack):
+ data = {"a": session}
+ with pytest.raises((TypeError, ValueError, PicklingError)):
+ pack(data)
+
+
[email protected]("mode", ["packer", "unpacker"])
[email protected](["packer", "pack", "unpack"], serializers)
+def test_pack_unpack(session, packer, pack, unpack, mode):
+ s: ss.Session = session
+ s.set_trait(mode, packer)
+ assert s.pack is pack
+ assert s.unpack is unpack
+ mode_reverse = "unpacker" if mode == "packer" else "packer"
+ assert getattr(s, mode_reverse) == packer
def test_message_cls():