Hello community, here is the log from the commit of package python-jupyter_client for openSUSE:Factory checked in at 2018-02-15 13:26:35 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-jupyter_client (Old) and /work/SRC/openSUSE:Factory/.python-jupyter_client.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jupyter_client" Thu Feb 15 13:26:35 2018 rev:6 rq:576585 version:5.2.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-jupyter_client/python-jupyter_client-doc.changes 2017-10-03 23:16:29.277149119 +0200 +++ /work/SRC/openSUSE:Factory/.python-jupyter_client.new/python-jupyter_client-doc.changes 2018-02-15 13:27:05.396524557 +0100 @@ -1,0 +2,75 @@ +Tue Feb 13 04:21:49 UTC 2018 - toddrme2...@gmail.com + +- Update dependencies. +- Add fix_COPY_THRESHOLD.patch + Fixes tests for pyzmq < 17 + See: https://github.com/jupyter/jupyter_client/pull/349 + +------------------------------------------------------------------- +Sat Feb 10 17:57:17 UTC 2018 - a...@gmx.de + +- update to version 5.2.2: + * Fix :meth:`.KernelSpecManager.get_all_specs` method in subclasses + that only override :meth:`.KernelSpecManager.find_kernel_specs` + and :meth:`.KernelSpecManager.get_kernel_spec`. See :ghissue:`338` + and :ghpull:`339`. + * Eliminate occasional error messages during process exit + (:ghpull:`336`). + * Improve error message when attempting to bind on invalid address + (:ghpull:`330`). + * Add missing direct dependency on tornado (:ghpull:`323`). + +------------------------------------------------------------------- +Thu Jan 4 17:16:22 UTC 2018 - a...@gmx.de + +- specfile: + * update copyright year + * require python-spinxcontrib-github-alt + +- update to version 5.2.1: + * Add parenthesis to conditional pytest requirement to work around a + bug in the wheel package, that generate a .whl which otherwise + always depends on pytest see :ghissue:`324` and :ghpull:`325` + +------------------------------------------------------------------- +Thu Dec 21 18:46:10 UTC 2017 - a...@gmx.de + +- update to version 5.2.0: + * Define Jupyter protocol version 5.3: + + Kernels can now opt to be interrupted by a message sent on the + control channel instead of a system signal. See + :ref:`kernelspecs` and :ref:`msging_interrupt` (:ghpull:`294`). + * New jupyter kernel command to launch an installed kernel by name + (:ghpull:`240`). + * Kernelspecs where the command starts with e.g. python3 or + python3.6—matching the version jupyter_client is running on—are + now launched with the same Python executable as the launching + process (:ghpull:`306`). This extends the special handling of + python added in 5.0. + * Command line arguments specified by a kernelspec can now include + {resource_dir}, which will be substituted with the kernelspec + resource directory path when the kernel is launched + (:ghpull:`289`). + * Kernelspecs now have an optional metadata field to hold arbitrary + metadata about kernels—see :ref:`kernelspecs` (:ghpull:`274`). + * Make the KernelRestarter class used by a KernelManager + configurable (:ghpull:`290`). + * When killing a kernel on Unix, kill its process group + (:ghpull:`314`). + * If a kernel dies soon after starting, reassign random ports before + restarting it, in case one of the previously chosen ports has been + bound by another process (:ghpull:`279`). + * Avoid unnecessary filesystem operations when finding a kernelspec + with :meth:`.KernelSpecManager.get_kernel_spec` (:ghpull:`311`). + * :meth:`.KernelSpecManager.get_all_specs` will no longer raise an + exception on encountering an invalid kernel.json file. It will + raise a warning and continue (:ghpull:`310`). + * Check for non-contiguous buffers before trying to send them + through ZMQ (:ghpull:`258`). + * Compatibility with upcoming Tornado version 5.0 (:ghpull:`304`). + * Simplify setup code by always using setuptools (:ghpull:`284`). + * Soften warnings when setting the sticky bit on runtime files fails + (:ghpull:`286`). + * Various corrections and improvements to documentation. + +------------------------------------------------------------------- --- /work/SRC/openSUSE:Factory/python-jupyter_client/python-jupyter_client.changes 2017-10-03 23:16:29.329141801 +0200 +++ /work/SRC/openSUSE:Factory/.python-jupyter_client.new/python-jupyter_client.changes 2018-02-15 13:27:05.656515114 +0100 @@ -1,0 +2,77 @@ +Tue Feb 13 04:21:49 UTC 2018 - toddrme2...@gmail.com + +- Update dependencies. +- Add fix_COPY_THRESHOLD.patch + Fixes tests for pyzmq < 17 + See: https://github.com/jupyter/jupyter_client/pull/349 + +------------------------------------------------------------------- +Sat Feb 10 17:57:17 UTC 2018 - a...@gmx.de + +- update to version 5.2.2: + * Fix :meth:`.KernelSpecManager.get_all_specs` method in subclasses + that only override :meth:`.KernelSpecManager.find_kernel_specs` + and :meth:`.KernelSpecManager.get_kernel_spec`. See :ghissue:`338` + and :ghpull:`339`. + * Eliminate occasional error messages during process exit + (:ghpull:`336`). + * Improve error message when attempting to bind on invalid address + (:ghpull:`330`). + * Add missing direct dependency on tornado (:ghpull:`323`). + +------------------------------------------------------------------- +Thu Jan 4 17:16:22 UTC 2018 - a...@gmx.de + +- specfile: + * update copyright year + +- update to version 5.2.1: + * Add parenthesis to conditional pytest requirement to work around a + bug in the wheel package, that generate a .whl which otherwise + always depends on pytest see :ghissue:`324` and :ghpull:`325` + +------------------------------------------------------------------- +Thu Dec 21 18:46:10 UTC 2017 - a...@gmx.de + +- specfile: + * add binary for python3 jupyter-{kernel, kernelspec, run} + +- update to version 5.2.0: + * Define Jupyter protocol version 5.3: + + Kernels can now opt to be interrupted by a message sent on the + control channel instead of a system signal. See + :ref:`kernelspecs` and :ref:`msging_interrupt` (:ghpull:`294`). + * New jupyter kernel command to launch an installed kernel by name + (:ghpull:`240`). + * Kernelspecs where the command starts with e.g. python3 or + python3.6—matching the version jupyter_client is running on—are + now launched with the same Python executable as the launching + process (:ghpull:`306`). This extends the special handling of + python added in 5.0. + * Command line arguments specified by a kernelspec can now include + {resource_dir}, which will be substituted with the kernelspec + resource directory path when the kernel is launched + (:ghpull:`289`). + * Kernelspecs now have an optional metadata field to hold arbitrary + metadata about kernels—see :ref:`kernelspecs` (:ghpull:`274`). + * Make the KernelRestarter class used by a KernelManager + configurable (:ghpull:`290`). + * When killing a kernel on Unix, kill its process group + (:ghpull:`314`). + * If a kernel dies soon after starting, reassign random ports before + restarting it, in case one of the previously chosen ports has been + bound by another process (:ghpull:`279`). + * Avoid unnecessary filesystem operations when finding a kernelspec + with :meth:`.KernelSpecManager.get_kernel_spec` (:ghpull:`311`). + * :meth:`.KernelSpecManager.get_all_specs` will no longer raise an + exception on encountering an invalid kernel.json file. It will + raise a warning and continue (:ghpull:`310`). + * Check for non-contiguous buffers before trying to send them + through ZMQ (:ghpull:`258`). + * Compatibility with upcoming Tornado version 5.0 (:ghpull:`304`). + * Simplify setup code by always using setuptools (:ghpull:`284`). + * Soften warnings when setting the sticky bit on runtime files fails + (:ghpull:`286`). + * Various corrections and improvements to documentation. + +------------------------------------------------------------------- Old: ---- jupyter_client-5.1.0.tar.gz New: ---- fix_COPY_THRESHOLD.patch jupyter_client-5.2.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-jupyter_client-doc.spec ++++++ --- /var/tmp/diff_new_pack.76lWsR/_old 2018-02-15 13:27:06.392488382 +0100 +++ /var/tmp/diff_new_pack.76lWsR/_new 2018-02-15 13:27:06.396488236 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-jupyter_client-doc # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -25,16 +25,18 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-jupyter_client-doc -Version: 5.1.0 +Version: 5.2.2 Release: 0 Summary: Documentation for python-jupyter_client License: BSD-3-Clause Group: Development/Languages/Python -Url: http://ipython.org +Url: https://github.com/jupyter/jupyter_client Source: https://files.pythonhosted.org/packages/source/j/jupyter_client/jupyter_client-%{version}.tar.gz +# PATCH-FIX-UPSTREAM fix_COPY_THRESHOLD.patch -- fix testing patch for pyzmq < 17 -- https://github.com/jupyter/jupyter_client/pull/349 +Patch0: fix_COPY_THRESHOLD.patch +BuildRequires: %{python_module jupyter_client} BuildRequires: fdupes BuildRequires: python-rpm-macros -BuildRequires: %{python_module jupyter_client} %if %{with tests} # Test Requirements BuildRequires: %{python_module jupyter_ipykernel} @@ -45,12 +47,12 @@ %endif # Documentation requirements %if %{with pdf} || %{with html} +BuildRequires: %{python_module sphinxcontrib-github-alt} BuildRequires: python3-Sphinx %endif %if %{with pdf} BuildRequires: python3-Sphinx-latex %endif -BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildArch: noarch Provides: %{name}-html = %{version} Provides: %{name}-pdf = %{version} @@ -63,6 +65,7 @@ %prep %setup -q -n jupyter_client-%{version} +%patch0 -p1 %build # Build the documentation ++++++ python-jupyter_client.spec ++++++ --- /var/tmp/diff_new_pack.76lWsR/_old 2018-02-15 13:27:06.420487365 +0100 +++ /var/tmp/diff_new_pack.76lWsR/_new 2018-02-15 13:27:06.420487365 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-jupyter_client # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,22 +18,25 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-jupyter_client -Version: 5.1.0 +Version: 5.2.2 Release: 0 Summary: Jupyter protocol implementation and client libraries License: BSD-3-Clause Group: Development/Languages/Python -Url: http://jupyter.org +Url: https://github.com/jupyter/jupyter_client Source: https://files.pythonhosted.org/packages/source/j/jupyter_client/jupyter_client-%{version}.tar.gz -BuildRequires: fdupes -BuildRequires: python-rpm-macros +# PATCH-FIX-UPSTREAM fix_COPY_THRESHOLD.patch -- fix testing patch for pyzmq < 17 -- https://github.com/jupyter/jupyter_client/pull/349 +Patch0: fix_COPY_THRESHOLD.patch BuildRequires: %{python_module devel} BuildRequires: %{python_module setuptools} -Requires: python-python-dateutil >= 2.1 +BuildRequires: fdupes +BuildRequires: python-rpm-macros +Requires: python-entrypoints Requires: python-jupyter_core +Requires: python-python-dateutil >= 2.1 Requires: python-pyzmq >= 13 +Requires: python-tornado >= 4.1 Requires: python-traitlets -BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildArch: noarch %python_subpackages @@ -46,6 +49,7 @@ %prep %setup -q -n jupyter_client-%{version} +%patch0 -p1 %build %python_build @@ -57,7 +61,9 @@ %files %{python_files} %defattr(-,root,root,-) %doc CONTRIBUTING.md COPYING.md README.md -# %%python3_only %%{_bindir}/jupyter-kernelspec +%python3_only %{_bindir}/jupyter-kernel +%python3_only %{_bindir}/jupyter-kernelspec +%python3_only %{_bindir}/jupyter-run %{python_sitelib}/* %changelog ++++++ fix_COPY_THRESHOLD.patch ++++++ >From 2840d26e329b1ce6b752943cd2128469a8a481c6 Mon Sep 17 00:00:00 2001 From: Min RK <benjami...@gmail.com> Date: Wed, 31 Jan 2018 16:51:41 +0100 Subject: [PATCH] fix testing patch for pyzmq < 17 zmq.COPY_THRESHOLD is undefined prior to pyzmq 17, so we need `create=True` to define it in that case --- jupyter_client/tests/test_session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jupyter_client/tests/test_session.py b/jupyter_client/tests/test_session.py index e8027436..55181e91 100644 --- a/jupyter_client/tests/test_session.py +++ b/jupyter_client/tests/test_session.py @@ -41,7 +41,7 @@ def setUp(self): @pytest.fixture def no_copy_threshold(): """Disable zero-copy optimizations in pyzmq >= 17""" - with mock.patch.object(zmq, 'COPY_THRESHOLD', 1): + with mock.patch.object(zmq, 'COPY_THRESHOLD', 1, create=True): yield ++++++ jupyter_client-5.1.0.tar.gz -> jupyter_client-5.2.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/CONTRIBUTING.md new/jupyter_client-5.2.2/CONTRIBUTING.md --- old/jupyter_client-5.1.0/CONTRIBUTING.md 2017-01-06 14:35:54.000000000 +0100 +++ new/jupyter_client-5.2.2/CONTRIBUTING.md 2017-08-08 17:56:49.000000000 +0200 @@ -1,3 +1,5 @@ # Contributing We follow the [IPython Contributing Guide](https://github.com/ipython/ipython/blob/master/CONTRIBUTING.md). + +See the [README](https://github.com/jupyter/jupyter_client/blob/master/README.md) on how to set up a development environment. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/PKG-INFO new/jupyter_client-5.2.2/PKG-INFO --- old/jupyter_client-5.1.0/PKG-INFO 2017-06-22 14:13:50.000000000 +0200 +++ new/jupyter_client-5.2.2/PKG-INFO 2018-01-24 18:35:14.000000000 +0100 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: jupyter_client -Version: 5.1.0 +Version: 5.2.2 Summary: Jupyter protocol implementation and client libraries -Home-page: http://jupyter.org +Home-page: https://jupyter.org Author: Jupyter Development Team Author-email: jupy...@googlegroups.com License: BSD +Description-Content-Type: UNKNOWN Description: UNKNOWN Keywords: Interactive,Interpreter,Shell,Web Platform: Linux diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/README.md new/jupyter_client-5.2.2/README.md --- old/jupyter_client-5.1.0/README.md 2017-02-10 14:29:06.000000000 +0100 +++ new/jupyter_client-5.2.2/README.md 2017-08-08 17:56:49.000000000 +0200 @@ -10,3 +10,37 @@ for installing kernelspecs for use with Jupyter frontends. [Jupyter protocol]: https://jupyter-client.readthedocs.io/en/latest/messaging.html + + +# Development Setup + +The [Jupyter Contributor Guides](http://jupyter.readthedocs.io/en/latest/contributor/content-contributor.html) provide extensive information on contributing code or documentation to Jupyter projects. The limited instructions below for setting up a development environment are for your convenience. + +## Coding + +You'll need Python and `pip` on the search path. Clone the Jupyter Client git repository to your computer, for example in `/my/project/jupyter_client`. +Now create an [editable install](https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs) +and download the dependencies of code and test suite by executing: + + cd /my/projects/jupyter_client/ + pip install -e .[test] + py.test + +The last command runs the test suite to verify the setup. During development, you can pass filenames to `py.test`, and it will execute only those tests. + +## Documentation + +The documentation of Jupyter Client is generated from the files in `docs/` using Sphinx. Instructions for setting up Sphinx with a selection of optional modules are in the [Documentation Guide](http://jupyter.readthedocs.io/en/latest/contrib_docs/index.html). You'll also need the `make` command. +For a minimal Sphinx installation to process the Jupyter Client docs, execute: + + pip install ipykernel sphinx sphinx_rtd_theme + +The following commands build the documentation in HTML format and check for broken links: + + cd /my/projects/jupyter_client/docs/ + make html linkcheck + +Point your browser to the following URL to access the generated documentation: + +_file:///my/projects/jupyter\_client/docs/\_build/html/index.html_ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/docs/api/kernelspec.rst new/jupyter_client-5.2.2/docs/api/kernelspec.rst --- old/jupyter_client-5.1.0/docs/api/kernelspec.rst 2017-01-06 14:35:54.000000000 +0100 +++ new/jupyter_client-5.2.2/docs/api/kernelspec.rst 2017-11-10 11:55:34.000000000 +0100 @@ -25,6 +25,17 @@ The name of the language the kernel implements, to help with picking appropriate kernels when loading notebooks. + .. attribute:: metadata + + Additional kernel-specific metadata; clients can use this as needed, + for instance to aid in kernel selection and filtering. + + Metadata added here should be namespaced for the tool reading and + writing that metadata. Concretely, if you're adding a new field called + :code:`supported_versions` which your tool recognizes, then you should + add it as :code:`"mytool": {"supported_versions": [1, 2]}`, **not** as a + top-level field called :code:`supported_versions`. + .. attribute:: resource_dir The path to the directory with this kernel's resources, such as icons. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/docs/changelog.rst new/jupyter_client-5.2.2/docs/changelog.rst --- old/jupyter_client-5.1.0/docs/changelog.rst 2017-06-22 13:46:04.000000000 +0200 +++ new/jupyter_client-5.2.2/docs/changelog.rst 2018-01-24 18:34:35.000000000 +0100 @@ -4,6 +4,71 @@ Changes in Jupyter Client ========================= +5.2.2 +===== + +`5.2.2 on GitHub <https://github.com/jupyter/jupyter_client/milestones/5.2.2>`__ + +- Fix :meth:`.KernelSpecManager.get_all_specs` method in subclasses + that only override :meth:`.KernelSpecManager.find_kernel_specs` + and :meth:`.KernelSpecManager.get_kernel_spec`. + See :ghissue:`338` and :ghpull:`339`. +- Eliminate occasional error messages during process exit (:ghpull:`336`). +- Improve error message when attempting to bind on invalid address (:ghpull:`330`). +- Add missing direct dependency on tornado (:ghpull:`323`). + + +5.2.1 +===== + +`5.2.1 on GitHub <https://github.com/jupyter/jupyter_client/milestones/5.2.1>`__ + +- Add parenthesis to conditional pytest requirement to work around a bug in the + ``wheel`` package, that generate a ``.whl`` which otherwise always depends on + ``pytest`` see :ghissue:`324` and :ghpull:`325`. + +5.2 +=== + +`5.2 on GitHub <https://github.com/jupyter/jupyter_client/milestones/5.2>`__ + +- Define Jupyter protocol version 5.3: + + - Kernels can now opt to be interrupted by a message sent on the control channel + instead of a system signal. See :ref:`kernelspecs` and :ref:`msging_interrupt` + (:ghpull:`294`). + +- New ``jupyter kernel`` command to launch an installed kernel by name + (:ghpull:`240`). +- Kernelspecs where the command starts with e.g. ``python3`` or + ``python3.6``—matching the version ``jupyter_client`` is running on—are now + launched with the same Python executable as the launching process (:ghpull:`306`). + This extends the special handling of ``python`` added in 5.0. +- Command line arguments specified by a kernelspec can now include + ``{resource_dir}``, which will be substituted with the kernelspec resource + directory path when the kernel is launched (:ghpull:`289`). +- Kernelspecs now have an optional ``metadata`` field to hold arbitrary metadata + about kernels—see :ref:`kernelspecs` (:ghpull:`274`). +- Make the ``KernelRestarter`` class used by a ``KernelManager`` configurable + (:ghpull:`290`). +- When killing a kernel on Unix, kill its process group (:ghpull:`314`). +- If a kernel dies soon after starting, reassign random ports before restarting + it, in case one of the previously chosen ports has been bound by another + process (:ghpull:`279`). +- Avoid unnecessary filesystem operations when finding a kernelspec with + :meth:`.KernelSpecManager.get_kernel_spec` (:ghpull:`311`). +- :meth:`.KernelSpecManager.get_all_specs` will no longer raise an exception on + encountering an invalid ``kernel.json`` file. It will raise a warning and + continue (:ghpull:`310`). +- Check for non-contiguous buffers before trying to send them through ZMQ + (:ghpull:`258`). +- Compatibility with upcoming Tornado version 5.0 (:ghpull:`304`). +- Simplify setup code by always using setuptools (:ghpull:`284`). +- Soften warnings when setting the sticky bit on runtime files fails + (:ghpull:`286`). +- Various corrections and improvements to documentation. + + 5.1 === diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/docs/conf.py new/jupyter_client-5.2.2/docs/conf.py --- old/jupyter_client-5.1.0/docs/conf.py 2017-01-06 14:35:54.000000000 +0100 +++ new/jupyter_client-5.2.2/docs/conf.py 2017-12-19 10:45:53.000000000 +0100 @@ -34,6 +34,7 @@ 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.napoleon', + 'sphinxcontrib_github_alt', ] # Add any paths that contain templates here, relative to this directory. @@ -55,6 +56,8 @@ copyright = '2015, Jupyter Development Team' author = 'Jupyter Development Team' +github_project_url = "https://github.com/jupyter/jupyter_client" + # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. @@ -296,7 +299,7 @@ # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'ipython': ('http://ipython.org/ipython-doc/dev/', None)} +intersphinx_mapping = {'ipython': ('http://ipython.readthedocs.io/en/stable/', None)} # Read The Docs # on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/docs/environment.yml new/jupyter_client-5.2.2/docs/environment.yml --- old/jupyter_client-5.1.0/docs/environment.yml 2017-04-06 09:55:35.000000000 +0200 +++ new/jupyter_client-5.2.2/docs/environment.yml 2017-12-19 10:45:53.000000000 +0100 @@ -8,3 +8,5 @@ - jupyter_core - sphinx>=1.3.6 - sphinx_rtd_theme +- pip: + - sphinxcontrib_github_alt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/docs/kernels.rst new/jupyter_client-5.2.2/docs/kernels.rst --- old/jupyter_client-5.1.0/docs/kernels.rst 2017-02-10 14:29:06.000000000 +0100 +++ new/jupyter_client-5.2.2/docs/kernels.rst 2017-11-22 12:54:35.000000000 +0100 @@ -6,7 +6,7 @@ A 'kernel' is a program that runs and introspects the user's code. IPython includes a kernel for Python code, and people have written kernels for -`several other languages <https://github.com/ipython/ipython/wiki/IPython-kernels-for-other-languages>`_. +`several other languages <https://github.com/jupyter/jupyter/wiki/Jupyter-kernels>`_. When Jupyter starts a kernel, it passes it a connection file. This specifies how to set up communications with the frontend. @@ -132,9 +132,19 @@ is found, a kernel with a matching `language` will be used. This allows a notebook written on any Python or Julia kernel to be properly associated with the user's Python or Julia kernel, even if they aren't listed under the same name as the author's. +- **interrupt_mode** (optional): May be either ``signal`` or ``message`` and + specifies how a client is supposed to interrupt cell execution on this kernel, + either by sending an interrupt ``signal`` via the operating system's + signalling facilities (e.g. `SIGINT` on POSIX systems), or by sending an + ``interrupt_request`` message on the control channel (see + :ref:`msging_interrupt`). If this is not specified + the client will default to ``signal`` mode. - **env** (optional): A dictionary of environment variables to set for the kernel. These will be added to the current environment variables before the kernel is started. +- **metadata** (optional): A dictionary of additional attributes about this + kernel; used by clients to aid clients in kernel selection. Metadata added + here should be namespaced for the tool reading and writing that metadata. For example, the kernel.json file for IPython looks like this:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/docs/messaging.rst new/jupyter_client-5.2.2/docs/messaging.rst --- old/jupyter_client-5.1.0/docs/messaging.rst 2017-06-22 09:57:44.000000000 +0200 +++ new/jupyter_client-5.2.2/docs/messaging.rst 2017-11-22 12:54:35.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.2. +The current version of the specification is 5.3. .. note:: *New in* and *Changed in* messages in this document refer to versions of the @@ -39,7 +39,7 @@ :target: ../_images/frontend-kernel.png A single kernel can be simultaneously connected to one or more frontends. The -kernel has four sockets that serve the following functions: +kernel has dedicated sockets for the following functions: 1. **Shell**: this single ROUTER socket allows multiple incoming connections from frontends, and this is the socket where requests for code execution, object @@ -959,6 +959,27 @@ socket, they simply send a forceful process termination signal, since a dead process is unlikely to respond in any useful way to messages. +.. _msging_interrupt: + +Kernel interrupt +---------------- + +In case a kernel can not catch operating system interrupt signals (e.g. the used +runtime handles signals and does not allow a user program to define a callback), +a kernel can choose to be notified using a message instead. For this to work, +the kernels kernelspec must set `interrupt_mode` to ``message``. An interruption +will then result in the following message on the `control` channel: + +Message type: ``interrupt_request``:: + + content = {} + +Message type: ``interrupt_reply``:: + + content = {} + +.. versionadded:: 5.3 + Messages on the IOPub (PUB/SUB) channel ======================================= @@ -1415,7 +1436,7 @@ - Jupyter Notebook < 5.1 - JupyterLab < 0.24 -- nteract +- nteract < 0.2.0 - CoCalc - Jupyter Console and QtConsole with Python 2 on macOS and Windows @@ -1423,7 +1444,7 @@ - QtConsole, Jupyter Console with Python 3 or Python 2 on Linux -.. see-also:: +.. seealso:: `Discussion on GitHub <https://github.com/jupyter/jupyter_client/issues/259>`_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/_version.py new/jupyter_client-5.2.2/jupyter_client/_version.py --- old/jupyter_client-5.1.0/jupyter_client/_version.py 2017-06-22 14:08:34.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/_version.py 2018-01-24 18:34:48.000000000 +0100 @@ -1,5 +1,5 @@ -version_info = (5, 1, 0) +version_info = (5, 2, 2) __version__ = '.'.join(map(str, version_info)) -protocol_version_info = (5, 2) +protocol_version_info = (5, 3) protocol_version = "%i.%i" % protocol_version_info diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/channels.py new/jupyter_client-5.2.2/jupyter_client/channels.py --- old/jupyter_client-5.1.0/jupyter_client/channels.py 2017-06-22 09:57:44.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/channels.py 2018-01-24 10:08:58.000000000 +0100 @@ -80,7 +80,10 @@ @staticmethod @atexit.register def _notice_exit(): - HBChannel._exiting = True + # Class definitions can be torn down during interpreter shutdown. + # We only need to set _exiting flag if this hasn't happened. + if HBChannel is not None: + HBChannel._exiting = True def _create_socket(self): if self.socket is not None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/connect.py new/jupyter_client-5.2.2/jupyter_client/connect.py --- old/jupyter_client-5.1.0/jupyter_client/connect.py 2017-05-23 18:21:26.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/connect.py 2017-11-10 11:55:34.000000000 +0100 @@ -10,6 +10,7 @@ from __future__ import absolute_import +import errno import glob import json import os @@ -148,14 +149,19 @@ new_permissions = permissions | stat.S_ISVTX if new_permissions != permissions: try: - os.chmod(path, permissions) + os.chmod(path, new_permissions) except OSError as e: - # failed to set sticky bit, - # probably not a big deal - warnings.warn( - "Failed to set sticky bit on %r: %s" % (path, e), - RuntimeWarning, - ) + if e.errno == errno.EPERM and path == runtime_dir: + # suppress permission errors setting sticky bit on runtime_dir, + # which we may not own. + pass + else: + # failed to set sticky bit, probably not a big deal + warnings.warn( + "Failed to set sticky bit on %r: %s" + "\nProbably not a big deal, but runtime files may be cleaned up periodically." % (path, e), + RuntimeWarning, + ) return fname, cfg @@ -299,6 +305,7 @@ _connection_file_written = Bool(False) transport = CaselessStrEnum(['tcp', 'ipc'], default_value='tcp', config=True) + kernel_name = Unicode() ip = Unicode(config=True, help="""Set the kernel\'s IP address [default localhost]. @@ -333,6 +340,9 @@ control_port = Integer(0, config=True, help="set the control (ROUTER) port [default: random]") + # names of the ports with random assignment + _random_port_names = None + @property def ports(self): return [ getattr(self, name) for name in port_names ] @@ -417,6 +427,37 @@ except (IOError, OSError): pass + def _record_random_port_names(self): + """Records which of the ports are randomly assigned. + + Records on first invocation, if the transport is tcp. + Does nothing on later invocations.""" + + if self.transport != 'tcp': + return + if self._random_port_names is not None: + return + + self._random_port_names = [] + for name in port_names: + if getattr(self, name) <= 0: + self._random_port_names.append(name) + + def cleanup_random_ports(self): + """Forgets randomly assigned port numbers and cleans up the connection file. + + Does nothing if no port numbers have been randomly assigned. + In particular, does nothing unless the transport is tcp. + """ + + if not self._random_port_names: + return + + for name in self._random_port_names: + setattr(self, name, 0) + + self.cleanup_connection_file() + def write_connection_file(self): """Write connection info to JSON dict in self.connection_file.""" if self._connection_file_written and os.path.exists(self.connection_file): @@ -431,6 +472,7 @@ kernel_name=self.kernel_name ) # write_connection_file also sets default ports: + self._record_random_port_names() for name in port_names: setattr(self, name, cfg[name]) @@ -467,6 +509,7 @@ self.transport = info.get('transport', self.transport) self.ip = info.get('ip', self._ip_default()) + self._record_random_port_names() for name in port_names: if getattr(self, name) == 0 and name in info: # not overridden by config or cl_args diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/ioloop/manager.py new/jupyter_client-5.2.2/jupyter_client/ioloop/manager.py --- old/jupyter_client-5.1.0/jupyter_client/ioloop/manager.py 2017-02-20 16:32:46.000000000 +0100 +++ new/jupyter_client-5.2.2/jupyter_client/ioloop/manager.py 2017-11-22 12:54:35.000000000 +0100 @@ -1,15 +1,7 @@ """A kernel manager with a tornado IOLoop""" -#----------------------------------------------------------------------------- -# Copyright (c) The Jupyter Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. from __future__ import absolute_import @@ -17,16 +9,13 @@ from zmq.eventloop.zmqstream import ZMQStream from traitlets import ( - Instance + Instance, + Type, ) from jupyter_client.manager import KernelManager from .restarter import IOLoopKernelRestarter -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - def as_zmqstream(f): def wrapped(self, *args, **kwargs): @@ -36,16 +25,26 @@ class IOLoopKernelManager(KernelManager): - loop = Instance('zmq.eventloop.ioloop.IOLoop') + loop = Instance('tornado.ioloop.IOLoop') def _loop_default(self): - return ioloop.IOLoop.instance() + return ioloop.IOLoop.current() + restarter_class = Type( + default_value=IOLoopKernelRestarter, + klass=IOLoopKernelRestarter, + help=( + 'Type of KernelRestarter to use. ' + 'Must be a subclass of IOLoopKernelRestarter.\n' + 'Override this to customize how kernel restarts are managed.' + ), + config=True, + ) _restarter = Instance('jupyter_client.ioloop.IOLoopKernelRestarter', allow_none=True) def start_restarter(self): if self.autorestart and self.has_kernel: if self._restarter is None: - self._restarter = IOLoopKernelRestarter( + self._restarter = self.restarter_class( kernel_manager=self, loop=self.loop, parent=self, log=self.log ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/ioloop/restarter.py new/jupyter_client-5.2.2/jupyter_client/ioloop/restarter.py --- old/jupyter_client-5.1.0/jupyter_client/ioloop/restarter.py 2017-02-20 16:32:46.000000000 +0100 +++ new/jupyter_client-5.2.2/jupyter_client/ioloop/restarter.py 2017-11-22 12:54:35.000000000 +0100 @@ -4,37 +4,28 @@ restarts the kernel if it dies. """ -#----------------------------------------------------------------------------- -# Copyright (c) The Jupyter Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. from __future__ import absolute_import +import warnings from zmq.eventloop import ioloop - from jupyter_client.restarter import KernelRestarter from traitlets import ( Instance, ) -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - class IOLoopKernelRestarter(KernelRestarter): """Monitor and autorestart a kernel.""" - loop = Instance('zmq.eventloop.ioloop.IOLoop') + loop = Instance('tornado.ioloop.IOLoop') def _loop_default(self): - return ioloop.IOLoop.instance() + warnings.warn("IOLoopKernelRestarter.loop is deprecated in jupyter-client 5.2", + DeprecationWarning, stacklevel=4, + ) + return ioloop.IOLoop.current() _pcallback = None @@ -42,7 +33,7 @@ """Start the polling of the kernel.""" if self._pcallback is None: self._pcallback = ioloop.PeriodicCallback( - self.poll, 1000*self.time_to_dead, self.loop + self.poll, 1000*self.time_to_dead, ) self._pcallback.start() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/kernelapp.py new/jupyter_client-5.2.2/jupyter_client/kernelapp.py --- old/jupyter_client-5.1.0/jupyter_client/kernelapp.py 1970-01-01 01:00:00.000000000 +0100 +++ new/jupyter_client-5.2.2/jupyter_client/kernelapp.py 2017-12-15 14:25:47.000000000 +0100 @@ -0,0 +1,81 @@ +import os +import signal +import uuid + +from jupyter_core.application import JupyterApp, base_flags +from tornado.ioloop import IOLoop +from traitlets import Unicode + +from . import __version__ +from .kernelspec import KernelSpecManager, NATIVE_KERNEL_NAME +from .manager import KernelManager + +class KernelApp(JupyterApp): + """Launch a kernel by name in a local subprocess. + """ + version = __version__ + description = "Run a kernel locally in a subprocess" + + classes = [KernelManager, KernelSpecManager] + + aliases = { + 'kernel': 'KernelApp.kernel_name', + 'ip': 'KernelManager.ip', + } + flags = {'debug': base_flags['debug']} + + kernel_name = Unicode(NATIVE_KERNEL_NAME, + help = 'The name of a kernel type to start' + ).tag(config=True) + + def initialize(self, argv=None): + super(KernelApp, self).initialize(argv) + self.km = KernelManager(kernel_name=self.kernel_name, + config=self.config) + cf_basename = 'kernel-%s.json' % uuid.uuid4() + self.km.connection_file = os.path.join(self.runtime_dir, cf_basename) + self.loop = IOLoop.current() + self.loop.add_callback(self._record_started) + + def setup_signals(self): + """Shutdown on SIGTERM or SIGINT (Ctrl-C)""" + if os.name == 'nt': + return + + def shutdown_handler(signo, frame): + self.loop.add_callback_from_signal(self.shutdown, signo) + for sig in [signal.SIGTERM, signal.SIGINT]: + signal.signal(sig, shutdown_handler) + + def shutdown(self, signo): + self.log.info('Shutting down on signal %d' % signo) + self.km.shutdown_kernel() + self.loop.stop() + + def log_connection_info(self): + cf = self.km.connection_file + self.log.info('Connection file: %s', cf) + self.log.info("To connect a client: --existing %s", os.path.basename(cf)) + + def _record_started(self): + """For tests, create a file to indicate that we've started + + Do not rely on this except in our own tests! + """ + fn = os.environ.get('JUPYTER_CLIENT_TEST_RECORD_STARTUP_PRIVATE') + if fn is not None: + with open(fn, 'wb'): + pass + + def start(self): + self.log.info('Starting kernel %r', self.kernel_name) + try: + self.km.start_kernel() + self.log_connection_info() + self.setup_signals() + self.loop.start() + finally: + self.km.cleanup() + + +main = KernelApp.launch_instance diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/kernelspec.py new/jupyter_client-5.2.2/jupyter_client/kernelspec.py --- old/jupyter_client-5.1.0/jupyter_client/kernelspec.py 2017-02-20 16:32:46.000000000 +0100 +++ new/jupyter_client-5.2.2/jupyter_client/kernelspec.py 2018-01-24 10:08:58.000000000 +0100 @@ -3,6 +3,7 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import errno import io import json import os @@ -13,7 +14,9 @@ pjoin = os.path.join from ipython_genutils.py3compat import PY3 -from traitlets import HasTraits, List, Unicode, Dict, Set, Bool, Type +from traitlets import ( + HasTraits, List, Unicode, Dict, Set, Bool, Type, CaselessStrEnum +) from traitlets.config import LoggingConfigurable from jupyter_core.paths import jupyter_data_dir, jupyter_path, SYSTEM_JUPYTER_PATH @@ -28,6 +31,10 @@ language = Unicode() env = Dict() resource_dir = Unicode() + interrupt_mode = CaselessStrEnum( + ['message', 'signal'], default_value='signal' + ) + metadata = Dict() @classmethod def from_resource_dir(cls, resource_dir): @@ -45,6 +52,8 @@ env=self.env, display_name=self.display_name, language=self.language, + interrupt_mode=self.interrupt_mode, + metadata=self.metadata, ) return d @@ -191,15 +200,39 @@ return self.kernel_spec_class.from_resource_dir(resource_dir) + def _find_spec_directory(self, kernel_name): + """Find the resource directory of a named kernel spec""" + for kernel_dir in self.kernel_dirs: + try: + files = os.listdir(kernel_dir) + except OSError as e: + if e.errno in (errno.ENOTDIR, errno.ENOENT): + continue + raise + for f in files: + path = pjoin(kernel_dir, f) + if f.lower() == kernel_name and _is_kernel_dir(path): + return path + + if kernel_name == NATIVE_KERNEL_NAME: + try: + from ipykernel.kernelspec import RESOURCES + except ImportError: + pass + else: + return RESOURCES + def get_kernel_spec(self, kernel_name): """Returns a :class:`KernelSpec` instance for the given kernel_name. Raises :exc:`NoSuchKernel` if the given kernel name is not found. """ - d = self.find_kernel_specs() - try: - resource_dir = d[kernel_name.lower()] - except KeyError: + if not _is_valid_kernel_name(kernel_name): + self.log.warning("Kernelspec name %r is invalid: %s", kernel_name, + _kernel_name_description) + + resource_dir = self._find_spec_directory(kernel_name.lower()) + if resource_dir is None: raise NoSuchKernel(kernel_name) return self._get_kernel_spec_by_name(kernel_name, resource_dir) @@ -218,14 +251,28 @@ } """ d = self.find_kernel_specs() - return {kname: { - "resource_dir": d[kname], - "spec": self._get_kernel_spec_by_name(kname, d[kname]).to_dict() - } for kname in d} + res = {} + for kname, resource_dir in d.items(): + try: + if self.__class__ is KernelSpecManager: + spec = self._get_kernel_spec_by_name(kname, resource_dir) + else: + # avoid calling private methods in subclasses, + # which may have overridden find_kernel_specs + # and get_kernel_spec, but not the newer get_all_specs + spec = self.get_kernel_spec(kname) + + res[kname] = { + "resource_dir": resource_dir, + "spec": spec.to_dict() + } + except Exception: + self.log.warning("Error loading kernelspec %r", kname, exc_info=True) + return res def remove_kernel_spec(self, name): """Remove a kernel spec directory by name. - + Returns the path that was deleted. """ save_native = self.ensure_native_kernel @@ -261,7 +308,7 @@ If ``user`` is False, it will attempt to install into the systemwide kernel registry. If the process does not have appropriate permissions, an :exc:`OSError` will be raised. - + If ``prefix`` is given, the kernelspec will be installed to PREFIX/share/jupyter/kernels/KERNEL_NAME. This can be sys.prefix for installation inside virtual or conda envs. @@ -282,16 +329,16 @@ DeprecationWarning, stacklevel=2, ) - + destination = self._get_destination_dir(kernel_name, user=user, prefix=prefix) self.log.debug('Installing kernelspec in %s', destination) - + kernel_dir = os.path.dirname(destination) if kernel_dir not in self.kernel_dirs: self.log.warning("Installing to %s, which is not in %s. The kernelspec may not be found.", kernel_dir, self.kernel_dirs, ) - + if os.path.isdir(destination): self.log.info('Removing existing kernelspec in %s', destination) shutil.rmtree(destination) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/manager.py new/jupyter_client-5.2.2/jupyter_client/manager.py --- old/jupyter_client-5.1.0/jupyter_client/manager.py 2017-04-28 15:54:56.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/manager.py 2018-01-24 10:30:48.000000000 +0100 @@ -11,11 +11,6 @@ import signal import sys import time -import warnings -try: - from queue import Empty # Py 3 -except ImportError: - from Queue import Empty # Py 2 import zmq @@ -29,7 +24,6 @@ kernelspec, ) from .connect import ConnectionFileMixin -from .session import Session from .managerabc import ( KernelManagerABC ) @@ -174,8 +168,10 @@ else: cmd = self.kernel_spec.argv + extra_arguments - if cmd and cmd[0] == 'python': - # executable is 'python', use sys.executable. + if cmd and cmd[0] in {'python', + 'python%i' % sys.version_info[0], + 'python%i.%i' % sys.version_info[:2]}: + # executable is 'python' or 'python3', use sys.executable. # These will typically be the same, # but if the current process is in an env # and has been launched by abspath without @@ -186,6 +182,10 @@ ns = dict(connection_file=self.connection_file, prefix=sys.prefix, ) + + if self.kernel_spec: + ns["resource_dir"] = self.kernel_spec.resource_dir + ns.update(self._launch_args) pat = re.compile(r'\{([A-Za-z0-9_]+)\}') @@ -229,9 +229,10 @@ """ if self.transport == 'tcp' and not is_local_ip(self.ip): raise RuntimeError("Can only launch a kernel on a local interface. " + "This one is not: %s." "Make sure that the '*_address' attributes are " "configured properly. " - "Currently valid addresses are: %s" % local_ips() + "Currently valid addresses are: %s" % (self.ip, local_ips()) ) # write connection file / get default ports @@ -250,7 +251,7 @@ # If kernel_cmd has been set manually, don't refer to a kernel spec # Environment variables from kernel spec are added to os.environ env.update(self.kernel_spec.env or {}) - + # launch the kernel subprocess self.log.debug("Starting kernel: %s", kernel_cmd) self.kernel = self._launch_kernel(kernel_cmd, env=env, @@ -326,12 +327,9 @@ self.cleanup(connection_file=not restart) - def restart_kernel(self, now=False, **kw): + def restart_kernel(self, now=False, newports=False, **kw): """Restarts a kernel with the arguments that were used to launch it. - If the old kernel was launched with random ports, the same ports will be - used for the new kernel. The same connection file is used again. - Parameters ---------- now : bool, optional @@ -342,6 +340,14 @@ In all cases the kernel is restarted, the only difference is whether it is given a chance to perform a clean shutdown or not. + newports : bool, optional + If the old kernel was launched with random ports, this flag decides + whether the same ports and connection file will be used again. + If False, the same ports and connection file are used. This is + the default. If True, new random port numbers are chosen and a + new connection file is written. It is still possible that the newly + chosen random port numbers happen to be the same as the old ones. + `**kw` : optional Any options specified here will overwrite those used to launch the kernel. @@ -353,6 +359,9 @@ # Stop currently running kernel. self.shutdown_kernel(now=now, restart=True) + if newports: + self.cleanup_random_ports() + # Start new kernel. self._launch_args.update(kw) self.start_kernel(**self._launch_args) @@ -372,7 +381,10 @@ # Signal the kernel to terminate (sends SIGKILL on Unix and calls # TerminateProcess() on Win32). try: - self.kernel.kill() + if hasattr(signal, 'SIGKILL'): + self.signal_kernel(signal.SIGKILL) + else: + self.kernel.kill() except OSError as e: # In Windows, we will get an Access Denied error if the process # has already terminated. Ignore it. @@ -399,11 +411,18 @@ platforms. """ if self.has_kernel: - if sys.platform == 'win32': - from .win_interrupt import send_interrupt - send_interrupt(self.kernel.win32_interrupt_event) - else: - self.signal_kernel(signal.SIGINT) + interrupt_mode = self.kernel_spec.interrupt_mode + if interrupt_mode == 'signal': + if sys.platform == 'win32': + from .win_interrupt import send_interrupt + send_interrupt(self.kernel.win32_interrupt_event) + else: + self.signal_kernel(signal.SIGINT) + + elif interrupt_mode == 'message': + msg = self.session.msg("interrupt_request", content={}) + self._connect_control_socket() + self.session.send(self._control_socket, msg) else: raise RuntimeError("Cannot interrupt kernel. No kernel is running!") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/restarter.py new/jupyter_client-5.2.2/jupyter_client/restarter.py --- old/jupyter_client-5.1.0/jupyter_client/restarter.py 2017-02-20 16:32:46.000000000 +0100 +++ new/jupyter_client-5.2.2/jupyter_client/restarter.py 2017-08-09 14:21:17.000000000 +0200 @@ -34,8 +34,13 @@ restart_limit = Integer(5, config=True, help="""The number of consecutive autorestarts before the kernel is presumed dead.""" ) + + random_ports_until_alive = Bool(True, config=True, + help="""Whether to choose new random ports when restarting before the kernel is alive.""" + ) _restarting = Bool(False) _restart_count = Integer(0) + _initial_startup = Bool(True) callbacks = Dict() def _callbacks_default(self): @@ -98,14 +103,18 @@ self._restart_count = 0 self.stop() else: - self.log.info('KernelRestarter: restarting kernel (%i/%i)', + newports = self.random_ports_until_alive and self._initial_startup + self.log.info('KernelRestarter: restarting kernel (%i/%i), %s random ports', self._restart_count, - self.restart_limit + self.restart_limit, + 'new' if newports else 'keep' ) self._fire_callbacks('restart') - self.kernel_manager.restart_kernel(now=True) + self.kernel_manager.restart_kernel(now=True, newports=newports) self._restarting = True else: + if self._initial_startup: + self._initial_startup = False if self._restarting: self.log.debug("KernelRestarter: restart apparently succeeded") self._restarting = False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/session.py new/jupyter_client-5.2.2/jupyter_client/session.py --- old/jupyter_client-5.1.0/jupyter_client/session.py 2017-06-22 10:22:33.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/session.py 2018-01-16 19:24:11.000000000 +0100 @@ -191,9 +191,9 @@ session = Instance('jupyter_client.session.Session', allow_none=True) - loop = Instance('zmq.eventloop.ioloop.IOLoop') + loop = Instance('tornado.ioloop.IOLoop') def _loop_default(self): - return IOLoop.instance() + return IOLoop.current() def __init__(self, **kwargs): super(SessionFactory, self).__init__(**kwargs) @@ -717,13 +717,20 @@ ) return buffers = [] if buffers is None else buffers - for buf in buffers: - if not isinstance(buf, memoryview): + for idx, buf in enumerate(buffers): + if isinstance(buf, memoryview): + view = buf + else: try: # check to see if buf supports the buffer protocol. - memoryview(buf) + view = memoryview(buf) except TypeError: raise TypeError("Buffer objects must support the buffer protocol.") + # memoryview.contiguous is new in 3.3, + # just skip the check on Python 2 + if hasattr(view, 'contiguous') and not view.contiguous: + # zmq requires memoryviews to be contiguous + raise ValueError("Buffer %i (%r) is not contiguous" % (idx, buf)) if self.adapt_version: msg = adapt(msg, self.adapt_version) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/tests/test_connect.py new/jupyter_client-5.2.2/jupyter_client/tests/test_connect.py --- old/jupyter_client-5.1.0/jupyter_client/tests/test_connect.py 2017-05-23 18:21:26.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/tests/test_connect.py 2017-08-09 14:21:17.000000000 +0200 @@ -21,6 +21,10 @@ JupyterApp.initialize(self, argv=argv) self.init_connection_file() +class DummyConfigurable(connect.ConnectionFileMixin): + def initialize(self): + pass + sample_info = dict(ip='1.2.3.4', transport='ipc', shell_port=1, hb_port=2, iopub_port=3, stdin_port=4, control_port=5, key=b'abc123', signature_scheme='hmac-md5', kernel_name='python' @@ -31,6 +35,7 @@ key=b'abc123', signature_scheme='hmac-md5', kernel_name='test' ) + def test_write_connection_file(): with TemporaryDirectory() as d: cf = os.path.join(d, 'kernel.json') @@ -171,4 +176,26 @@ with open(cf, 'w') as f: f.write('{}') assert connect.find_connection_file(abs_cf, path=jupyter_runtime_dir()) == abs_cf + os.remove(abs_cf) + + +def test_mixin_record_random_ports(): + with TemporaryDirectory() as d: + dc = DummyConfigurable(data_dir=d, kernel_name='via-tcp', transport='tcp') + dc.write_connection_file() + + assert dc._connection_file_written + assert os.path.exists(dc.connection_file) + assert dc._random_port_names == connect.port_names + + +def test_mixin_cleanup_random_ports(): + with TemporaryDirectory() as d: + dc = DummyConfigurable(data_dir=d, kernel_name='via-tcp', transport='tcp') + dc.write_connection_file() + filename = dc.connection_file + dc.cleanup_random_ports() + assert not os.path.exists(filename) + for name in dc._random_port_names: + assert getattr(dc, name) == 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/tests/test_kernelapp.py new/jupyter_client-5.2.2/jupyter_client/tests/test_kernelapp.py --- old/jupyter_client-5.1.0/jupyter_client/tests/test_kernelapp.py 1970-01-01 01:00:00.000000000 +0100 +++ new/jupyter_client-5.2.2/jupyter_client/tests/test_kernelapp.py 2017-12-15 14:25:47.000000000 +0100 @@ -0,0 +1,67 @@ +from __future__ import division + +import os +import shutil +from subprocess import Popen, PIPE +import sys +from tempfile import mkdtemp +import time + +PY3 = sys.version_info[0] >= 3 + +def _launch(extra_env): + env = os.environ.copy() + env.update(extra_env) + return Popen([sys.executable, '-c', + 'from jupyter_client.kernelapp import main; main()'], + env=env, stderr=(PIPE if PY3 else None)) + +WAIT_TIME = 10 +POLL_FREQ = 10 + +def hacky_wait(p): + """Python 2 subprocess doesn't have timeouts :-(""" + for _ in range(WAIT_TIME * POLL_FREQ): + if p.poll() is not None: + return p.returncode + time.sleep(1 / POLL_FREQ) + else: + raise AssertionError("Process didn't exit in {} seconds" + .format(WAIT_TIME)) + +def test_kernelapp_lifecycle(): + # Check that 'jupyter kernel' starts and terminates OK. + runtime_dir = mkdtemp() + startup_dir = mkdtemp() + started = os.path.join(startup_dir, 'started') + try: + p = _launch({'JUPYTER_RUNTIME_DIR': runtime_dir, + 'JUPYTER_CLIENT_TEST_RECORD_STARTUP_PRIVATE': started, + }) + # Wait for start + for _ in range(WAIT_TIME * POLL_FREQ): + if os.path.isfile(started): + break + time.sleep(1 / POLL_FREQ) + else: + raise AssertionError("No started file created in {} seconds" + .format(WAIT_TIME)) + + # Connection file should be there by now + files = os.listdir(runtime_dir) + assert len(files) == 1 + cf = files[0] + assert cf.startswith('kernel') + assert cf.endswith('.json') + + # Send SIGTERM to shut down + p.terminate() + if PY3: + _, stderr = p.communicate(timeout=WAIT_TIME) + assert cf in stderr.decode('utf-8', 'replace') + else: + hacky_wait(p) + finally: + shutil.rmtree(runtime_dir) + shutil.rmtree(startup_dir) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/tests/test_kernelspec.py new/jupyter_client-5.2.2/jupyter_client/tests/test_kernelspec.py --- old/jupyter_client-5.1.0/jupyter_client/tests/test_kernelspec.py 2017-05-18 19:29:10.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/tests/test_kernelspec.py 2018-01-24 10:08:58.000000000 +0100 @@ -4,6 +4,7 @@ # Copyright (c) Jupyter Development Team. # Distributed under the terms of the Modified BSD License. +import copy import io import json from logging import StreamHandler @@ -11,6 +12,7 @@ from os.path import join as pjoin from subprocess import Popen, PIPE, STDOUT import sys +import tempfile import unittest import pytest @@ -67,6 +69,7 @@ self.assertEqual(ks.argv, sample_kernel_json['argv']) self.assertEqual(ks.display_name, sample_kernel_json['display_name']) self.assertEqual(ks.env, {}) + self.assertEqual(ks.metadata, {}) def test_find_all_specs(self): kernels = self.ksm.get_all_specs() @@ -155,7 +158,7 @@ 'Haskell-1-2-3', ]: assert kernelspec._is_valid_kernel_name(good) - + for bad in [ 'has space', u'ünicode', @@ -164,4 +167,33 @@ ]: assert not kernelspec._is_valid_kernel_name(bad) - + def test_subclass(self): + """Test get_all_specs in subclasses that override find_kernel_specs""" + ksm = self.ksm + resource_dir = tempfile.gettempdir() + native_name = kernelspec.NATIVE_KERNEL_NAME + native_kernel = ksm.get_kernel_spec(native_name) + + class MyKSM(kernelspec.KernelSpecManager): + def get_kernel_spec(self, name): + spec = copy.copy(native_kernel) + if name == 'fake': + spec.name = name + spec.resource_dir = resource_dir + elif name == native_name: + pass + else: + raise KeyError(name) + return spec + + def find_kernel_specs(self): + return { + 'fake': resource_dir, + native_name: native_kernel.resource_dir, + } + + # ensure that get_all_specs doesn't raise if only + # find_kernel_specs and get_kernel_spec are defined + myksm = MyKSM() + specs = myksm.get_all_specs() + assert sorted(specs) == ['fake', native_name] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/tests/test_session.py new/jupyter_client-5.2.2/jupyter_client/tests/test_session.py --- old/jupyter_client-5.1.0/jupyter_client/tests/test_session.py 2017-05-18 19:29:10.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/tests/test_session.py 2017-11-22 12:54:35.000000000 +0100 @@ -5,8 +5,13 @@ import hmac import os +import sys import uuid from datetime import datetime +try: + from unittest import mock +except ImportError: + import mock import pytest @@ -33,6 +38,14 @@ self.session = ss.Session() +@pytest.fixture +def no_copy_threshold(): + """Disable zero-copy optimizations in pyzmq >= 17""" + with mock.patch.object(zmq, 'COPY_THRESHOLD', 1): + yield + + +@pytest.mark.usefixtures('no_copy_threshold') class TestSession(SessionTestCase): def test_msg(self): @@ -123,9 +136,15 @@ self.assertEqual(new_msg['buffers'],[b'bar']) # buffers must support the buffer protocol - with self.assertRaises(TypeError) as cm: + with self.assertRaises(TypeError): self.session.send(A, msg, ident=b'foo', buffers=[1]) + # buffers must be contiguous + buf = memoryview(os.urandom(16)) + if sys.version_info >= (3,3): + with self.assertRaises(ValueError): + self.session.send(A, msg, ident=b'foo', buffers=[buf[::2]]) + A.close() B.close() ctx.term() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client/threaded.py new/jupyter_client-5.2.2/jupyter_client/threaded.py --- old/jupyter_client-5.1.0/jupyter_client/threaded.py 2017-06-22 09:57:44.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client/threaded.py 2018-01-24 10:08:58.000000000 +0100 @@ -151,7 +151,10 @@ @staticmethod @atexit.register def _notice_exit(): - IOLoopThread._exiting = True + # Class definitions can be torn down during interpreter shutdown. + # We only need to set _exiting flag if this hasn't happened. + if IOLoopThread is not None: + IOLoopThread._exiting = True def run(self): """Run my loop, ignoring EINTR events in the poller""" @@ -214,7 +217,7 @@ super(ThreadedKernelClient, self).start_channels(shell, iopub, stdin, hb) def _check_kernel_info_reply(self, msg): - """This is run in the ioloop thread when the kernel info reply is recieved + """This is run in the ioloop thread when the kernel info reply is received """ if msg['msg_type'] == 'kernel_info_reply': self._handle_kernel_info_reply(msg) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client.egg-info/PKG-INFO new/jupyter_client-5.2.2/jupyter_client.egg-info/PKG-INFO --- old/jupyter_client-5.1.0/jupyter_client.egg-info/PKG-INFO 2017-06-22 14:13:49.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client.egg-info/PKG-INFO 2018-01-24 18:35:14.000000000 +0100 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: jupyter-client -Version: 5.1.0 +Version: 5.2.2 Summary: Jupyter protocol implementation and client libraries -Home-page: http://jupyter.org +Home-page: https://jupyter.org Author: Jupyter Development Team Author-email: jupy...@googlegroups.com License: BSD +Description-Content-Type: UNKNOWN Description: UNKNOWN Keywords: Interactive,Interpreter,Shell,Web Platform: Linux diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client.egg-info/SOURCES.txt new/jupyter_client-5.2.2/jupyter_client.egg-info/SOURCES.txt --- old/jupyter_client-5.1.0/jupyter_client.egg-info/SOURCES.txt 2017-06-22 14:13:49.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client.egg-info/SOURCES.txt 2018-01-24 18:35:14.000000000 +0100 @@ -29,6 +29,7 @@ jupyter_client/connect.py jupyter_client/consoleapp.py jupyter_client/jsonutil.py +jupyter_client/kernelapp.py jupyter_client/kernelspec.py jupyter_client/kernelspecapp.py jupyter_client/launcher.py @@ -59,6 +60,7 @@ jupyter_client/tests/test_client.py jupyter_client/tests/test_connect.py jupyter_client/tests/test_jsonutil.py +jupyter_client/tests/test_kernelapp.py jupyter_client/tests/test_kernelmanager.py jupyter_client/tests/test_kernelspec.py jupyter_client/tests/test_localinterfaces.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client.egg-info/entry_points.txt new/jupyter_client-5.2.2/jupyter_client.egg-info/entry_points.txt --- old/jupyter_client-5.1.0/jupyter_client.egg-info/entry_points.txt 2017-06-22 14:13:49.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client.egg-info/entry_points.txt 2018-01-24 18:35:14.000000000 +0100 @@ -1,4 +1,5 @@ [console_scripts] +jupyter-kernel = jupyter_client.kernelapp:main jupyter-kernelspec = jupyter_client.kernelspecapp:KernelSpecApp.launch_instance jupyter-run = jupyter_client.runapp:RunApp.launch_instance diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/jupyter_client.egg-info/requires.txt new/jupyter_client-5.2.2/jupyter_client.egg-info/requires.txt --- old/jupyter_client-5.1.0/jupyter_client.egg-info/requires.txt 2017-06-22 14:13:49.000000000 +0200 +++ new/jupyter_client-5.2.2/jupyter_client.egg-info/requires.txt 2018-01-24 18:35:14.000000000 +0100 @@ -2,8 +2,15 @@ jupyter_core pyzmq>=13 python-dateutil>=2.1 +tornado>=4.1 [test] ipykernel ipython +mock + +[test:(python_version >= "3.4" or python_version == "2.7")] pytest + +[test:python_version == "3.3"] +pytest<3.3.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/jupyter_client-5.1.0/setup.py new/jupyter_client-5.2.2/setup.py --- old/jupyter_client-5.1.0/setup.py 2017-05-18 19:29:10.000000000 +0200 +++ new/jupyter_client-5.2.2/setup.py 2018-01-24 10:30:54.000000000 +0100 @@ -28,9 +28,8 @@ #----------------------------------------------------------------------------- import os -from glob import glob -from distutils.core import setup +from setuptools import setup pjoin = os.path.join here = os.path.abspath(os.path.dirname(__file__)) @@ -45,16 +44,26 @@ with open(pjoin(here, name, '_version.py')) as f: exec(f.read(), {}, version_ns) +from setuptools.command.bdist_egg import bdist_egg + +class bdist_egg_disabled(bdist_egg): + """Disabled version of bdist_egg + + Prevents setup.py install from performing setuptools' default easy_install, + which it should never ever do. + """ + def run(self): + sys.exit("Aborting implicit building of eggs. Use `pip install .` to install from source.") + setup_args = dict( name = name, version = version_ns['__version__'], - scripts = glob(pjoin('scripts', '*')), packages = packages, description = "Jupyter protocol implementation and client libraries", author = 'Jupyter Development Team', author_email = 'jupy...@googlegroups.com', - url = 'http://jupyter.org', + url = 'https://jupyter.org', license = 'BSD', platforms = "Linux, Mac OS X, Windows", keywords = ['Interactive', 'Interpreter', 'Shell', 'Web'], @@ -68,32 +77,30 @@ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', ], -) - -if 'develop' in sys.argv or any(a.startswith('bdist') for a in sys.argv): - import setuptools - -setuptools_args = {} -install_requires = setuptools_args['install_requires'] = [ - 'traitlets', - 'jupyter_core', - 'pyzmq>=13', - 'python-dateutil>=2.1', -] - -extras_require = setuptools_args['extras_require'] = { - 'test': ['ipykernel', 'ipython', 'pytest'], -} - -if 'setuptools' in sys.modules: - setup_args.update(setuptools_args) - setup_args['entry_points'] = { + install_requires = [ + 'traitlets', + 'jupyter_core', + 'pyzmq>=13', + 'python-dateutil>=2.1', + 'tornado>=4.1', + ], + extras_require = { + 'test': ['ipykernel', 'ipython', 'mock'], + 'test:python_version == "3.3"': ['pytest<3.3.0'], + 'test:(python_version >= "3.4" or python_version == "2.7")': ['pytest'], + }, + cmdclass = { + 'bdist_egg': bdist_egg if 'bdist_egg' in sys.argv else bdist_egg_disabled, + }, + entry_points = { 'console_scripts': [ 'jupyter-kernelspec = jupyter_client.kernelspecapp:KernelSpecApp.launch_instance', 'jupyter-run = jupyter_client.runapp:RunApp.launch_instance', - ] - } - setup_args.pop('scripts', None) + 'jupyter-kernel = jupyter_client.kernelapp:main', + ], + }, +) + if __name__ == '__main__': setup(**setup_args)