Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-ipykernel for openSUSE:Factory checked in at 2024-03-06 23:03:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-ipykernel (Old) and /work/SRC/openSUSE:Factory/.python-ipykernel.new.1770 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ipykernel" Wed Mar 6 23:03:02 2024 rev:47 rq:1155310 version:6.29.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-ipykernel/python-ipykernel.changes 2024-02-08 19:01:54.578527791 +0100 +++ /work/SRC/openSUSE:Factory/.python-ipykernel.new.1770/python-ipykernel.changes 2024-03-06 23:03:04.822156256 +0100 @@ -1,0 +2,16 @@ +Tue Mar 5 15:11:37 UTC 2024 - Dominique Leuenberger <dims...@opensuse.org> + +- Skip build for python 3.9: python-ipython is no longer available. + +------------------------------------------------------------------- +Sat Mar 2 11:25:38 UTC 2024 - Ben Greiner <c...@bnavigator.de> + +- Update to 6.29.3 + ## Enhancements made + * Eventloop scheduling improvements for stop_on_error_timeout and + schedule_next #1212 (@jdranczewski) + ## Bugs fixed + * Disable frozen modules by default, add a toggle #1213 + (@krassowski) + +------------------------------------------------------------------- Old: ---- ipykernel-6.29.2.tar.gz New: ---- ipykernel-6.29.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-ipykernel.spec ++++++ --- /var/tmp/diff_new_pack.5d9CLU/_old 2024-03-06 23:03:06.110202954 +0100 +++ /var/tmp/diff_new_pack.5d9CLU/_new 2024-03-06 23:03:06.110202954 +0100 @@ -17,8 +17,9 @@ %{?sle15_python_module_pythons} +%define skip_python39 1 Name: python-ipykernel -Version: 6.29.2 +Version: 6.29.3 Release: 0 Summary: IPython Kernel for Jupyter License: BSD-3-Clause @@ -73,7 +74,7 @@ BuildRequires: %{python_module flaky} BuildRequires: %{python_module matplotlib} BuildRequires: %{python_module pytest >= 7.0} -BuildRequires: %{python_module pytest-asyncio} +BuildRequires: %{python_module pytest-asyncio >= 0.23.5} BuildRequires: %{python_module pytest-timeout} # we don't want ipyparallel and its dependencies in Ring1, see below #BuildRequires: #{python_module ipyparallel} ++++++ ipykernel-6.29.2.tar.gz -> ipykernel-6.29.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/CHANGELOG.md new/ipykernel-6.29.3/CHANGELOG.md --- old/ipykernel-6.29.2/CHANGELOG.md 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/CHANGELOG.md 2020-02-02 01:00:00.000000000 +0100 @@ -2,6 +2,35 @@ <!-- <START NEW CHANGELOG ENTRY> --> +## 6.29.3 + +([Full Changelog](https://github.com/ipython/ipykernel/compare/v6.29.2...de2221ce155668c343084fde37b77fb6b1671dc9)) + +### Enhancements made + +- Eventloop scheduling improvements for stop_on_error_timeout and schedule_next [#1212](https://github.com/ipython/ipykernel/pull/1212) ([@jdranczewski](https://github.com/jdranczewski)) + +### Bugs fixed + +- Disable frozen modules by default, add a toggle [#1213](https://github.com/ipython/ipykernel/pull/1213) ([@krassowski](https://github.com/krassowski)) + +### Maintenance and upkeep improvements + +- Fix typings and update project urls [#1214](https://github.com/ipython/ipykernel/pull/1214) ([@blink1073](https://github.com/blink1073)) +- Unpin pytest-asyncio and update ruff config [#1209](https://github.com/ipython/ipykernel/pull/1209) ([@blink1073](https://github.com/blink1073)) + +### Documentation improvements + +- Correct spelling mistake [#1208](https://github.com/ipython/ipykernel/pull/1208) ([@joouha](https://github.com/joouha)) + +### Contributors to this release + +([GitHub contributors page for this release](https://github.com/ipython/ipykernel/graphs/contributors?from=2024-02-07&to=2024-02-26&type=c)) + +[@blink1073](https://github.com/search?q=repo%3Aipython%2Fipykernel+involves%3Ablink1073+updated%3A2024-02-07..2024-02-26&type=Issues) | [@ccordoba12](https://github.com/search?q=repo%3Aipython%2Fipykernel+involves%3Accordoba12+updated%3A2024-02-07..2024-02-26&type=Issues) | [@jdranczewski](https://github.com/search?q=repo%3Aipython%2Fipykernel+involves%3Ajdranczewski+updated%3A2024-02-07..2024-02-26&type=Issues) | [@joouha](https://github.com/search?q=repo%3Aipython%2Fipykernel+involves%3Ajoouha+updated%3A2024-02-07..2024-02-26&type=Issues) | [@krassowski](https://github.com/search?q=repo%3Aipython%2Fipykernel+involves%3Akrassowski+updated%3A2024-02-07..2024-02-26&type=Issues) + +<!-- <END NEW CHANGELOG ENTRY> --> + ## 6.29.2 ([Full Changelog](https://github.com/ipython/ipykernel/compare/v6.29.1...d45fe71990d26c0bd5b7b3b2a4ccd3d1f6609899)) @@ -20,8 +49,6 @@ [@ianthomas23](https://github.com/search?q=repo%3Aipython%2Fipykernel+involves%3Aianthomas23+updated%3A2024-02-06..2024-02-07&type=Issues) | [@stdll00](https://github.com/search?q=repo%3Aipython%2Fipykernel+involves%3Astdll00+updated%3A2024-02-06..2024-02-07&type=Issues) -<!-- <END NEW CHANGELOG ENTRY> --> - ## 6.29.1 ([Full Changelog](https://github.com/ipython/ipykernel/compare/v6.29.0...09c9b2ad9c15202c5d1896ba24ec978b726c073b)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/PKG-INFO new/ipykernel-6.29.3/PKG-INFO --- old/ipykernel-6.29.2/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 @@ -1,8 +1,12 @@ Metadata-Version: 2.1 Name: ipykernel -Version: 6.29.2 +Version: 6.29.3 Summary: IPython Kernel for Jupyter Project-URL: Homepage, https://ipython.org +Project-URL: Documentation, https://ipykernel.readthedocs.io +Project-URL: Funding, https://numfocus.org/donate +Project-URL: Source, https://github.com/ipython/ipykernel +Project-URL: Tracker, https://github.com/ipython/ipykernel/issues Author-email: IPython Development Team <ipython-...@scipy.org> License: BSD 3-Clause License @@ -78,7 +82,7 @@ Requires-Dist: flaky; extra == 'test' Requires-Dist: ipyparallel; extra == 'test' Requires-Dist: pre-commit; extra == 'test' -Requires-Dist: pytest-asyncio==0.23.4; extra == 'test' +Requires-Dist: pytest-asyncio>=0.23.5; extra == 'test' Requires-Dist: pytest-cov; extra == 'test' Requires-Dist: pytest-timeout; extra == 'test' Requires-Dist: pytest>=7.0; extra == 'test' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/docs/conf.py new/ipykernel-6.29.3/docs/conf.py --- old/ipykernel-6.29.2/docs/conf.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/docs/conf.py 2020-02-02 01:00:00.000000000 +0100 @@ -37,7 +37,7 @@ ] try: - import enchant + import enchant # noqa: F401 extensions += ["sphinxcontrib.spelling"] except ImportError: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/hatch_build.py new/ipykernel-6.29.3/hatch_build.py --- old/ipykernel-6.29.2/hatch_build.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/hatch_build.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,5 +1,4 @@ """A custom hatch build hook for ipykernel.""" -import os import shutil import sys from pathlib import Path diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/__init__.py new/ipykernel-6.29.3/ipykernel/__init__.py --- old/ipykernel-6.29.2/ipykernel/__init__.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/__init__.py 2020-02-02 01:00:00.000000000 +0100 @@ -4,4 +4,4 @@ kernel_protocol_version_info, version_info, ) -from .connect import * +from .connect import * # noqa: F403 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/_version.py new/ipykernel-6.29.3/ipykernel/_version.py --- old/ipykernel-6.29.2/ipykernel/_version.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/_version.py 2020-02-02 01:00:00.000000000 +0100 @@ -5,7 +5,7 @@ from typing import List # Version string must appear intact for hatch versioning -__version__ = "6.29.2" +__version__ = "6.29.3" # 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/ipykernel-6.29.2/ipykernel/compiler.py new/ipykernel-6.29.3/ipykernel/compiler.py --- old/ipykernel-6.29.2/ipykernel/compiler.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/compiler.py 2020-02-02 01:00:00.000000000 +0100 @@ -45,7 +45,7 @@ return h -convert_to_long_pathname = lambda filename: filename +convert_to_long_pathname = lambda filename: filename # noqa: E731 if sys.platform == "win32": try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/datapub.py new/ipykernel-6.29.3/ipykernel/datapub.py --- old/ipykernel-6.29.2/ipykernel/datapub.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/datapub.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,17 +1,11 @@ +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + """Publishing native (typically pickled) objects. """ import warnings -warnings.warn( - "ipykernel.datapub is deprecated. It has moved to ipyparallel.datapub", - DeprecationWarning, - stacklevel=2, -) - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - from traitlets import Any, CBytes, Dict, Instance from traitlets.config import Configurable @@ -26,6 +20,12 @@ from jupyter_client.session import Session, extract_header +warnings.warn( + "ipykernel.datapub is deprecated. It has moved to ipyparallel.datapub", + DeprecationWarning, + stacklevel=2, +) + class ZMQDataPublisher(Configurable): """A zmq data publisher.""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/debugger.py new/ipykernel-6.29.3/ipykernel/debugger.py --- old/ipykernel-6.29.2/ipykernel/debugger.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/debugger.py 2020-02-02 01:00:00.000000000 +0100 @@ -21,7 +21,7 @@ try: # This import is required to have the next ones working... - from debugpy.server import api + from debugpy.server import api # noqa: F401 from _pydevd_bundle import pydevd_frame_utils # isort: skip from _pydevd_bundle.pydevd_suspended_frames import ( # isort: skip @@ -610,7 +610,7 @@ } async def inspectVariables(self, message): - """Handle an insepct variables message.""" + """Handle an inspect variables message.""" self.variable_explorer.untrack_all() # looks like the implementation of untrack_all in ptvsd # destroys objects we nee din track. We have no choice but diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/eventloops.py new/ipykernel-6.29.3/ipykernel/eventloops.py --- old/ipykernel-6.29.2/ipykernel/eventloops.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/eventloops.py 2020-02-02 01:00:00.000000000 +0100 @@ -82,6 +82,11 @@ def enum_helper(name): return operator.attrgetter(name.rpartition(".")[0])(sys.modules[QtCore.__package__]) + def exit_loop(): + """fall back to main loop""" + kernel._qt_notifier.setEnabled(False) + kernel.app.qt_event_loop.quit() + def process_stream_events(): """fall back to main loop when there's a socket event""" # call flush to ensure that the stream doesn't lose events @@ -89,8 +94,7 @@ # flush returns the number of events consumed. # if there were any, wake it up if kernel.shell_stream.flush(limit=1): - kernel._qt_notifier.setEnabled(False) - kernel.app.qt_event_loop.quit() + exit_loop() if not hasattr(kernel, "_qt_notifier"): fd = kernel.shell_stream.getsockopt(zmq.FD) @@ -101,6 +105,23 @@ else: kernel._qt_notifier.setEnabled(True) + # allow for scheduling exits from the loop in case a timeout needs to + # be set from the kernel level + def _schedule_exit(delay): + """schedule fall back to main loop in [delay] seconds""" + # The signatures of QtCore.QTimer.singleShot are inconsistent between PySide and PyQt + # if setting the TimerType, so we create a timer explicitly and store it + # to avoid a memory leak. + # PreciseTimer is needed so we exit after _at least_ the specified delay, not within 5% of it + if not hasattr(kernel, "_qt_timer"): + kernel._qt_timer = QtCore.QTimer(kernel.app) + kernel._qt_timer.setSingleShot(True) + kernel._qt_timer.setTimerType(enum_helper("QtCore.Qt.TimerType").PreciseTimer) + kernel._qt_timer.timeout.connect(exit_loop) + kernel._qt_timer.start(int(1000 * delay)) + + loop_qt._schedule_exit = _schedule_exit + # there may already be unprocessed events waiting. # these events will not wake zmq's edge-triggered FD # since edge-triggered notification only occurs on new i/o activity. @@ -108,11 +129,7 @@ # so we start in a clean state ensuring that any new i/o events will notify. # schedule first call on the eventloop as soon as it's running, # so we don't block here processing events - if not hasattr(kernel, "_qt_timer"): - kernel._qt_timer = QtCore.QTimer(kernel.app) - kernel._qt_timer.setSingleShot(True) - kernel._qt_timer.timeout.connect(process_stream_events) - kernel._qt_timer.start(0) + QtCore.QTimer.singleShot(0, process_stream_events) @register_integration("qt", "qt5", "qt6") @@ -229,23 +246,33 @@ self.app = app self.app.withdraw() - def process_stream_events(stream, *a, **kw): + def exit_loop(): + """fall back to main loop""" + app.tk.deletefilehandler(kernel.shell_stream.getsockopt(zmq.FD)) + app.quit() + app.destroy() + del kernel.app_wrapper + + def process_stream_events(*a, **kw): """fall back to main loop when there's a socket event""" - if stream.flush(limit=1): - app.tk.deletefilehandler(stream.getsockopt(zmq.FD)) - app.quit() - app.destroy() - del kernel.app_wrapper + if kernel.shell_stream.flush(limit=1): + exit_loop() + + # allow for scheduling exits from the loop in case a timeout needs to + # be set from the kernel level + def _schedule_exit(delay): + """schedule fall back to main loop in [delay] seconds""" + app.after(int(1000 * delay), exit_loop) + + loop_tk._schedule_exit = _schedule_exit # For Tkinter, we create a Tk object and call its withdraw method. kernel.app_wrapper = BasicAppWrapper(app) - - notifier = partial(process_stream_events, kernel.shell_stream) - # seems to be needed for tk - notifier.__name__ = "notifier" # type:ignore[attr-defined] - app.tk.createfilehandler(kernel.shell_stream.getsockopt(zmq.FD), READABLE, notifier) + app.tk.createfilehandler( + kernel.shell_stream.getsockopt(zmq.FD), READABLE, process_stream_events + ) # schedule initial call after start - app.after(0, notifier) + app.after(0, process_stream_events) app.mainloop() @@ -484,24 +511,24 @@ else: if gui == "qt5": try: - import PyQt5 + import PyQt5 # noqa: F401 os.environ["QT_API"] = "pyqt5" except ImportError: try: - import PySide2 + import PySide2 # noqa: F401 os.environ["QT_API"] = "pyside2" except ImportError: os.environ["QT_API"] = "pyqt5" elif gui == "qt6": try: - import PyQt6 + import PyQt6 # noqa: F401 os.environ["QT_API"] = "pyqt6" except ImportError: try: - import PySide6 + import PySide6 # noqa: F401 os.environ["QT_API"] = "pyside6" except ImportError: @@ -516,7 +543,7 @@ # Do the actual import now that the environment variable is set to make sure it works. try: - from IPython.external.qt_for_kernel import QtCore, QtGui + pass except Exception as e: # Clear the environment variable for the next attempt. if "QT_API" in os.environ: @@ -560,6 +587,10 @@ # User wants to turn off integration; clear any evidence if Qt was the last one. if hasattr(kernel, "app"): delattr(kernel, "app") + if hasattr(kernel, "_qt_notifier"): + delattr(kernel, "_qt_notifier") + if hasattr(kernel, "_qt_timer"): + delattr(kernel, "_qt_timer") else: if gui.startswith("qt"): # Prepare the kernel here so any exceptions are displayed in the client. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/gui/gtk3embed.py new/ipykernel-6.29.3/ipykernel/gui/gtk3embed.py --- old/ipykernel-6.29.2/ipykernel/gui/gtk3embed.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/gui/gtk3embed.py 2020-02-02 01:00:00.000000000 +0100 @@ -14,16 +14,16 @@ import sys import warnings -warnings.warn( - "The Gtk3 event loop for ipykernel is deprecated", category=DeprecationWarning, stacklevel=2 -) - # Third-party import gi gi.require_version("Gdk", "3.0") gi.require_version("Gtk", "3.0") -from gi.repository import GObject, Gtk +from gi.repository import GObject, Gtk # noqa: E402 + +warnings.warn( + "The Gtk3 event loop for ipykernel is deprecated", category=DeprecationWarning, stacklevel=2 +) # ----------------------------------------------------------------------------- # Classes and functions diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/gui/gtkembed.py new/ipykernel-6.29.3/ipykernel/gui/gtkembed.py --- old/ipykernel-6.29.2/ipykernel/gui/gtkembed.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/gui/gtkembed.py 2020-02-02 01:00:00.000000000 +0100 @@ -14,14 +14,14 @@ import sys import warnings -warnings.warn( - "The Gtk3 event loop for ipykernel is deprecated", category=DeprecationWarning, stacklevel=2 -) - # Third-party import gobject import gtk +warnings.warn( + "The Gtk3 event loop for ipykernel is deprecated", category=DeprecationWarning, stacklevel=2 +) + # ----------------------------------------------------------------------------- # Classes and functions # ----------------------------------------------------------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/ipkernel.py new/ipykernel-6.29.3/ipykernel/ipkernel.py --- old/ipykernel-6.29.2/ipykernel/ipkernel.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/ipkernel.py 2020-02-02 01:00:00.000000000 +0100 @@ -381,7 +381,7 @@ should_run_async = shell.should_run_async accepts_params = _accepts_parameters(run_cell, ["cell_id"]) else: - should_run_async = lambda cell: False # noqa: ARG005 + should_run_async = lambda cell: False # noqa: ARG005, E731 # older IPython, # use blocking run_cell and wrap it in coroutine diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/kernelbase.py new/ipykernel-6.29.3/ipykernel/kernelbase.py --- old/ipykernel-6.29.2/ipykernel/kernelbase.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/kernelbase.py 2020-02-02 01:00:00.000000000 +0100 @@ -472,7 +472,7 @@ self.log.info("Exiting as there is no eventloop") return - def advance_eventloop(): + async def advance_eventloop(): # check if eventloop changed: if self.eventloop is not eventloop: self.log.info("exiting eventloop %s", eventloop) @@ -494,10 +494,13 @@ def schedule_next(): """Schedule the next advance of the eventloop""" - # flush the eventloop every so often, - # giving us a chance to handle messages in the meantime + # call_later allows the io_loop to process other events if needed. + # Going through schedule_dispatch ensures all other dispatches on msg_queue + # are processed before we enter the eventloop, even if the previous dispatch was + # already consumed from the queue by process_one and the queue is + # technically empty. self.log.debug("Scheduling eventloop advance") - self.io_loop.call_later(0.001, advance_eventloop) + self.io_loop.call_later(0.001, partial(self.schedule_dispatch, advance_eventloop)) # begin polling the eventloop schedule_next() @@ -1202,9 +1205,18 @@ # before we reset the flag schedule_stop_aborting = partial(self.schedule_dispatch, stop_aborting) - # if we have a delay, give messages this long to arrive on the queue - # before we stop aborting requests - asyncio.get_event_loop().call_later(self.stop_on_error_timeout, schedule_stop_aborting) + if self.stop_on_error_timeout: + # if we have a delay, give messages this long to arrive on the queue + # before we stop aborting requests + self.io_loop.call_later(self.stop_on_error_timeout, schedule_stop_aborting) + # If we have an eventloop, it may interfere with the call_later above. + # If the loop has a _schedule_exit method, we call that so the loop exits + # after stop_on_error_timeout, returning to the main io_loop and letting + # the call_later fire. + if self.eventloop is not None and hasattr(self.eventloop, "_schedule_exit"): + self.eventloop._schedule_exit(self.stop_on_error_timeout + 0.01) + else: + schedule_stop_aborting() def _send_abort_reply(self, stream, msg, idents): """Send a reply to an aborted request""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/kernelspec.py new/ipykernel-6.29.3/ipykernel/kernelspec.py --- old/ipykernel-6.29.2/ipykernel/kernelspec.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/kernelspec.py 2020-02-02 01:00:00.000000000 +0100 @@ -8,6 +8,7 @@ import errno import json import os +import platform import shutil import stat import sys @@ -17,11 +18,7 @@ from jupyter_client.kernelspec import KernelSpecManager from traitlets import Unicode - -try: - from .debugger import _is_debugpy_available -except ImportError: - _is_debugpy_available = False +from traitlets.config import Application pjoin = os.path.join @@ -35,6 +32,7 @@ mod: str = "ipykernel_launcher", executable: str | None = None, extra_arguments: list[str] | None = None, + python_arguments: list[str] | None = None, ) -> list[str]: """Build Popen command list for launching an IPython kernel. @@ -54,16 +52,18 @@ if executable is None: executable = sys.executable extra_arguments = extra_arguments or [] - arguments = [executable, "-m", mod, "-f", "{connection_file}"] - arguments.extend(extra_arguments) + python_arguments = python_arguments or [] + return [executable, *python_arguments, "-m", mod, "-f", "{connection_file}", *extra_arguments] - return arguments - -def get_kernel_dict(extra_arguments: list[str] | None = None) -> dict[str, Any]: +def get_kernel_dict( + extra_arguments: list[str] | None = None, python_arguments: list[str] | None = None +) -> dict[str, Any]: """Construct dict for kernel.json""" return { - "argv": make_ipkernel_cmd(extra_arguments=extra_arguments), + "argv": make_ipkernel_cmd( + extra_arguments=extra_arguments, python_arguments=python_arguments + ), "display_name": "Python %i (ipykernel)" % sys.version_info[0], "language": "python", "metadata": {"debugger": True}, @@ -74,6 +74,7 @@ path: Path | str | None = None, overrides: dict[str, Any] | None = None, extra_arguments: list[str] | None = None, + python_arguments: list[str] | None = None, ) -> str: """Write a kernel spec directory to `path` @@ -94,7 +95,7 @@ Path(path).chmod(mask | stat.S_IWUSR) # write kernel.json - kernel_dict = get_kernel_dict(extra_arguments) + kernel_dict = get_kernel_dict(extra_arguments, python_arguments) if overrides: kernel_dict.update(overrides) @@ -112,6 +113,7 @@ prefix: str | None = None, profile: str | None = None, env: dict[str, str] | None = None, + frozen_modules: bool = False, ) -> str: """Install the IPython kernelspec for Jupyter @@ -136,6 +138,12 @@ A dictionary of extra environment variables for the kernel. These will be added to the current environment variables before the kernel is started + frozen_modules : bool, optional + Whether to use frozen modules for potentially faster kernel startup. + Using frozen modules prevents debugging inside of some built-in + Python modules, such as io, abc, posixpath, ntpath, or stat. + The frozen modules are used in CPython for faster interpreter startup. + Ignored for cPython <3.11 and for other Python implementations. Returns ------- @@ -144,6 +152,9 @@ if kernel_spec_manager is None: kernel_spec_manager = KernelSpecManager() + if env is None: + env = {} + if (kernel_name != KERNEL_NAME) and (display_name is None): # kernel_name is specified and display_name is not # default display_name to kernel_name @@ -158,9 +169,24 @@ overrides["display_name"] = "Python %i [profile=%s]" % (sys.version_info[0], profile) else: extra_arguments = None + + python_arguments = None + + # addresses the debugger warning from debugpy about frozen modules + if sys.version_info >= (3, 11) and platform.python_implementation() == "CPython": + if not frozen_modules: + # disable frozen modules + python_arguments = ["-Xfrozen_modules=off"] + elif "PYDEVD_DISABLE_FILE_VALIDATION" not in env: + # user opted-in to have frozen modules, and we warned them about + # consequences for the - disable the debugger warning + env["PYDEVD_DISABLE_FILE_VALIDATION"] = "1" + if env: overrides["env"] = env - path = write_kernel_spec(overrides=overrides, extra_arguments=extra_arguments) + path = write_kernel_spec( + overrides=overrides, extra_arguments=extra_arguments, python_arguments=python_arguments + ) dest = kernel_spec_manager.install_kernel_spec( path, kernel_name=kernel_name, user=user, prefix=prefix ) @@ -171,8 +197,6 @@ # Entrypoint -from traitlets.config import Application - class InstallIPythonKernelSpecApp(Application): """Dummy app wrapping argparse""" @@ -237,6 +261,12 @@ metavar=("ENV", "VALUE"), help="Set environment variables for the kernel.", ) + parser.add_argument( + "--frozen_modules", + action="store_true", + help="Enable frozen modules for potentially faster startup." + " This has a downside of preventing the debugger from navigating to certain built-in modules.", + ) opts = parser.parse_args(self.argv) if opts.env: opts.env = dict(opts.env) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/pickleutil.py new/ipykernel-6.29.3/ipykernel/pickleutil.py --- old/ipykernel-6.29.2/ipykernel/pickleutil.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/pickleutil.py 2020-02-02 01:00:00.000000000 +0100 @@ -2,25 +2,23 @@ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. -import typing -import warnings - -warnings.warn( - "ipykernel.pickleutil is deprecated. It has moved to ipyparallel.", - DeprecationWarning, - stacklevel=2, -) - import copy import pickle import sys +import typing +import warnings from types import FunctionType # This registers a hook when it's imported -from ipyparallel.serialize import codeutil from traitlets.log import get_logger from traitlets.utils.importstring import import_item +warnings.warn( + "ipykernel.pickleutil is deprecated. It has moved to ipyparallel.", + DeprecationWarning, + stacklevel=2, +) + buffer = memoryview class_type = type diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/pylab/backend_inline.py new/ipykernel-6.29.3/ipykernel/pylab/backend_inline.py --- old/ipykernel-6.29.2/ipykernel/pylab/backend_inline.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/pylab/backend_inline.py 2020-02-02 01:00:00.000000000 +0100 @@ -5,7 +5,7 @@ import warnings -from matplotlib_inline.backend_inline import * # type:ignore[import-untyped] # analysis: ignore +from matplotlib_inline.backend_inline import * # type:ignore[import-untyped] # noqa: F403 # analysis: ignore warnings.warn( "`ipykernel.pylab.backend_inline` is deprecated, directly " diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/pylab/config.py new/ipykernel-6.29.3/ipykernel/pylab/config.py --- old/ipykernel-6.29.2/ipykernel/pylab/config.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/pylab/config.py 2020-02-02 01:00:00.000000000 +0100 @@ -5,7 +5,7 @@ import warnings -from matplotlib_inline.config import * # type:ignore[import-untyped] # analysis: ignore +from matplotlib_inline.config import * # type:ignore[import-untyped] # noqa: F403 # analysis: ignore warnings.warn( "`ipykernel.pylab.config` is deprecated, directly use `matplotlib_inline.config`", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/serialize.py new/ipykernel-6.29.3/ipykernel/serialize.py --- old/ipykernel-6.29.2/ipykernel/serialize.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/serialize.py 2020-02-02 01:00:00.000000000 +0100 @@ -3,15 +3,8 @@ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. -import warnings - -warnings.warn( - "ipykernel.serialize is deprecated. It has moved to ipyparallel.serialize", - DeprecationWarning, - stacklevel=2, -) - import pickle +import warnings from itertools import chain try: @@ -41,6 +34,12 @@ from jupyter_client.session import MAX_BYTES, MAX_ITEMS +warnings.warn( + "ipykernel.serialize is deprecated. It has moved to ipyparallel.serialize", + DeprecationWarning, + stacklevel=2, +) + # ----------------------------------------------------------------------------- # Serialization Functions # ----------------------------------------------------------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/ipykernel/zmqshell.py new/ipykernel-6.29.3/ipykernel/zmqshell.py --- old/ipykernel-6.29.2/ipykernel/zmqshell.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/ipykernel/zmqshell.py 2020-02-02 01:00:00.000000000 +0100 @@ -612,7 +612,7 @@ """Initialize magics.""" super().init_magics() self.register_magics(KernelMagics) - self.magics_manager.register_alias("ed", "edit") # type:ignore[union-attr] + self.magics_manager.register_alias("ed", "edit") def init_virtualenv(self): """Initialize virtual environment.""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/pyproject.toml new/ipykernel-6.29.3/pyproject.toml --- old/ipykernel-6.29.2/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 @@ -18,7 +18,6 @@ "Programming Language :: Python", "Programming Language :: Python :: 3", ] -urls = {Homepage = "https://ipython.org"} requires-python = ">=3.8" dependencies = [ "debugpy>=1.6.5", @@ -37,6 +36,13 @@ "packaging", ] +[project.urls] +Homepage = "https://ipython.org" +Documentation = "https://ipykernel.readthedocs.io" +Funding = "https://numfocus.org/donate" +Source = "https://github.com/ipython/ipykernel" +Tracker = "https://github.com/ipython/ipykernel/issues" + [project.optional-dependencies] docs = [ "sphinx", @@ -53,7 +59,7 @@ "flaky", "ipyparallel", "pre-commit", - "pytest-asyncio==0.23.4", + "pytest-asyncio>=0.23.5", "pytest-timeout" ] cov = [ @@ -209,29 +215,29 @@ line-length = 100 [tool.ruff.lint] -select = [ - "B", # flake8-bugbear - "I", # isort - "ARG", # flake8-unused-arguments - "C4", # flake8-comprehensions - "EM", # flake8-errmsg - "ICN", # flake8-import-conventions - "G", # flake8-logging-format - "PGH", # pygrep-hooks - "PIE", # flake8-pie - "PL", # pylint - "PT", # flake8-pytest-style - "PTH", # flake8-use-pathlib - "RET", # flake8-return - "RUF", # Ruff-specific - "SIM", # flake8-simplify - "T20", # flake8-print - "UP", # pyupgrade - "YTT", # flake8-2020 - "EXE", # flake8-executable - "NPY", # NumPy specific rules - "PD", # pandas-vet - "PYI", # flake8-pyi +extend-select = [ + "B", # flake8-bugbear + "I", # isort + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "T20", # flake8-print + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable + "NPY", # NumPy specific rules + "PD", # pandas-vet + "PYI", # flake8-pyi ] ignore = [ "PLR", # Design related pylint codes @@ -265,6 +271,9 @@ "T201", # Don't touch noqa lines "RUF100", + # Don't touch imports + "F401", + "F403" ] [tool.ruff.lint.per-file-ignores] @@ -277,6 +286,7 @@ # B018 Found useless expression. Either assign it to a variable or remove it. # S603 `subprocess` call: check for execution of untrusted input "tests/*" = ["B011", "C408", "T201", "B007", "EM", "PTH", "PLW", "PLC1901", "B018", "S603", "ARG", "RET", "PGH"] +"*/__init__.py" = ["F401"] [tool.interrogate] ignore-init-module=true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipykernel-6.29.2/tests/test_kernelspec.py new/ipykernel-6.29.3/tests/test_kernelspec.py --- old/ipykernel-6.29.2/tests/test_kernelspec.py 2020-02-02 01:00:00.000000000 +0100 +++ new/ipykernel-6.29.3/tests/test_kernelspec.py 2020-02-02 01:00:00.000000000 +0100 @@ -3,6 +3,7 @@ import json import os +import platform import shutil import sys import tempfile @@ -22,6 +23,7 @@ ) pjoin = os.path.join +is_cpython = platform.python_implementation() == "CPython" def test_make_ipkernel_cmd(): @@ -144,3 +146,49 @@ assert spec["env"][k] == v else: assert "env" not in spec + + +@pytest.mark.skipif(sys.version_info < (3, 11) or not is_cpython, reason="requires cPython 3.11") +def test_install_frozen_modules_on(): + system_jupyter_dir = tempfile.mkdtemp() + + with mock.patch("jupyter_client.kernelspec.SYSTEM_JUPYTER_PATH", [system_jupyter_dir]): + install(frozen_modules=True) + + spec_file = os.path.join(system_jupyter_dir, "kernels", KERNEL_NAME, "kernel.json") + with open(spec_file) as f: + spec = json.load(f) + assert spec["env"]["PYDEVD_DISABLE_FILE_VALIDATION"] == "1" + assert "-Xfrozen_modules=off" not in spec["argv"] + + +@pytest.mark.skipif(sys.version_info < (3, 11) or not is_cpython, reason="requires cPython 3.11") +def test_install_frozen_modules_off(): + system_jupyter_dir = tempfile.mkdtemp() + + with mock.patch("jupyter_client.kernelspec.SYSTEM_JUPYTER_PATH", [system_jupyter_dir]): + install(frozen_modules=False) + + spec_file = os.path.join(system_jupyter_dir, "kernels", KERNEL_NAME, "kernel.json") + with open(spec_file) as f: + spec = json.load(f) + assert "env" not in spec + assert spec["argv"][1] == "-Xfrozen_modules=off" + + +@pytest.mark.skipif( + sys.version_info >= (3, 11) or is_cpython, + reason="checks versions older than 3.11 and other Python implementations", +) +def test_install_frozen_modules_no_op(): + # ensure we do not add add Xfrozen_modules on older Python versions + # (although cPython does not error out on unknown X options as of 3.8) + system_jupyter_dir = tempfile.mkdtemp() + + with mock.patch("jupyter_client.kernelspec.SYSTEM_JUPYTER_PATH", [system_jupyter_dir]): + install(frozen_modules=False) + + spec_file = os.path.join(system_jupyter_dir, "kernels", KERNEL_NAME, "kernel.json") + with open(spec_file) as f: + spec = json.load(f) + assert "-Xfrozen_modules=off" not in spec["argv"]