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)


Reply via email to