[Python-modules-commits] [ipykernel] 01/09: Import ipykernel_4.7.0.orig.tar.gz
Gordon Ball
chronitis-guest at moszumanska.debian.org
Wed Dec 13 08:50:55 UTC 2017
This is an automated email from the git hooks/post-receive script.
chronitis-guest pushed a commit to branch master
in repository ipykernel.
commit 017d6a026d10428f285efa959cfdd02d07c6d4ac
Author: Gordon Ball <gordon at chronitis.net>
Date: Wed Dec 13 08:29:13 2017 +0000
Import ipykernel_4.7.0.orig.tar.gz
---
.travis.yml | 5 +-
appveyor.yml | 6 +-
docs/changelog.rst | 18 ++++++
docs/conf.py | 2 +-
ipykernel/_version.py | 2 +-
ipykernel/connect.py | 9 ++-
ipykernel/displayhook.py | 4 +-
ipykernel/eventloops.py | 29 +++++++++
ipykernel/inprocess/tests/test_kernel.py | 6 +-
ipykernel/inprocess/tests/test_kernelmanager.py | 28 ++++-----
ipykernel/iostream.py | 70 ++++++++++++++-------
ipykernel/ipkernel.py | 83 ++++++++++++++++++++-----
ipykernel/jsonutil.py | 46 ++++++++++----
ipykernel/kernelapp.py | 3 +-
ipykernel/kernelbase.py | 11 ++--
ipykernel/pylab/backend_inline.py | 6 +-
ipykernel/tests/_asyncio.py | 17 +++++
ipykernel/tests/test_connect.py | 18 +++---
ipykernel/tests/test_embed_kernel.py | 27 ++++----
ipykernel/tests/test_eventloop.py | 44 +++++++++++++
ipykernel/tests/test_jsonutil.py | 43 ++++++-------
ipykernel/tests/test_kernel.py | 63 ++++++++++---------
ipykernel/tests/test_kernelspec.py | 18 +++---
ipykernel/tests/test_message_spec.py | 52 ++++++++--------
ipykernel/tests/test_pickleutil.py | 13 ++--
ipykernel/tests/test_serialize.py | 83 +++++++++++--------------
ipykernel/tests/test_start_kernel.py | 12 ++--
ipykernel/tests/test_zmq_shell.py | 43 +++++++------
ipykernel/tests/utils.py | 21 ++++---
ipykernel/zmqshell.py | 4 +-
setup.cfg | 9 +--
setup.py | 8 ++-
32 files changed, 501 insertions(+), 302 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 32869e4..c68a67e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
language: python
python:
- "nightly"
- - 3.6
+ - 3.6
- 3.5
- 3.4
- 3.3
@@ -16,9 +16,10 @@ install:
if [[ "$TRAVIS_PYTHON_VERSION" == "3.6" || "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
pip install matplotlib
fi
+ - pip freeze
script:
- jupyter kernelspec list
- - nosetests --with-coverage --with-timer --cover-package ipykernel ipykernel
+ - pytest --cov ipykernel --durations 10 -v ipykernel
after_success:
- codecov
matrix:
diff --git a/appveyor.yml b/appveyor.yml
index 939ea8f..fe9d253 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -21,14 +21,14 @@ install:
pip install --upgrade pip wheel
pip --version
- cmd: |
- pip install --pre -e . coverage nose_warnings_filters
- pip install ipykernel[test] nose-timer
+ pip install --pre -e .
+ pip install ipykernel[test]
- cmd: |
pip install matplotlib numpy
pip freeze
- cmd: python -c "import ipykernel.kernelspec; ipykernel.kernelspec.install(user=True)"
test_script:
- - cmd: nosetests --with-coverage --with-timer --cover-package=ipykernel ipykernel
+ - cmd: pytest -v --cov ipykernel ipykernel
on_success:
- cmd: pip install codecov
diff --git a/docs/changelog.rst b/docs/changelog.rst
index b49d4dc..a5d950d 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,6 +1,24 @@
Changes in IPython kernel
=========================
+4.7
+---
+
+4.7.0
+*****
+
+`4.7.0 on GitHub <https://github.com/ipython/ipykernel/milestones/4.7>`__
+
+- Add event loop integration for :mod:`asyncio`.
+- Use the new IPython completer API.
+- Add support for displaying GIF images (mimetype ``image/gif``).
+- Allow the kernel to be interrupted without killing the Qt console.
+- Fix ``is_complete`` response with cell magics.
+- Clean up encoding of bytes objects.
+- Clean up help links to use ``https`` and improve display titles.
+- Clean up ioloop handling in preparation for tornado 5.
+
+
4.6
---
diff --git a/docs/conf.py b/docs/conf.py
index d44ecd4..4c03611 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -297,7 +297,7 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
- 'https://docs.python.org/': None,
+ 'python': ('https://docs.python.org/3/', None),
'ipython': ('https://ipython.readthedocs.io/en/latest', None),
'jupyter': ('https://jupyter.readthedocs.io/en/latest', None),
}
diff --git a/ipykernel/_version.py b/ipykernel/_version.py
index fbcadc4..645a51e 100644
--- a/ipykernel/_version.py
+++ b/ipykernel/_version.py
@@ -1,4 +1,4 @@
-version_info = (4, 6, 1)
+version_info = (4, 7, 0)
__version__ = '.'.join(map(str, version_info))
kernel_protocol_version_info = (5, 1)
diff --git a/ipykernel/connect.py b/ipykernel/connect.py
index e49ad10..faaa402 100644
--- a/ipykernel/connect.py
+++ b/ipykernel/connect.py
@@ -13,7 +13,7 @@ import warnings
from IPython.core.profiledir import ProfileDir
from IPython.paths import get_ipython_dir
from ipython_genutils.path import filefind
-from ipython_genutils.py3compat import str_to_bytes
+from ipython_genutils.py3compat import str_to_bytes, PY3
import jupyter_client
from jupyter_client import write_connection_file
@@ -169,8 +169,15 @@ def connect_qtconsole(connection_file=None, argv=None, profile=None):
"qtconsoleapp.main()"
])
+ kwargs = {}
+ if PY3:
+ # Launch the Qt console in a separate session & process group, so
+ # interrupting the kernel doesn't kill it. This kwarg is not on Py2.
+ kwargs['start_new_session'] = True
+
return Popen([sys.executable, '-c', cmd, '--existing', cf] + argv,
stdout=PIPE, stderr=PIPE, close_fds=(sys.platform != 'win32'),
+ **kwargs
)
diff --git a/ipykernel/displayhook.py b/ipykernel/displayhook.py
index 6e263ab..7e90ef1 100644
--- a/ipykernel/displayhook.py
+++ b/ipykernel/displayhook.py
@@ -6,7 +6,7 @@
import sys
from IPython.core.displayhook import DisplayHook
-from ipykernel.jsonutil import encode_images
+from ipykernel.jsonutil import encode_images, json_clean
from ipython_genutils.py3compat import builtin_mod
from traitlets import Instance, Dict, Any
from jupyter_client.session import extract_header, Session
@@ -68,7 +68,7 @@ class ZMQShellDisplayHook(DisplayHook):
self.msg['content']['execution_count'] = self.prompt_count
def write_format_data(self, format_dict, md_dict=None):
- self.msg['content']['data'] = encode_images(format_dict)
+ self.msg['content']['data'] = json_clean(encode_images(format_dict))
self.msg['content']['metadata'] = md_dict
def finish_displayhook(self):
diff --git a/ipykernel/eventloops.py b/ipykernel/eventloops.py
index d5cc740..86f21cd 100644
--- a/ipykernel/eventloops.py
+++ b/ipykernel/eventloops.py
@@ -48,6 +48,7 @@ loop_map = {
'nbagg': None,
'notebook': None,
'ipympl': None,
+ 'widget': None,
None : None,
}
@@ -290,6 +291,34 @@ def loop_cocoa(kernel):
sys.excepthook = real_excepthook
+ at register_integration('asyncio')
+def loop_asyncio(kernel):
+ '''Start a kernel with asyncio event loop support.'''
+ import asyncio
+ loop = asyncio.get_event_loop()
+
+ def kernel_handler():
+ loop.call_soon(kernel.do_one_iteration)
+ loop.call_later(kernel._poll_interval, kernel_handler)
+
+ loop.call_soon(kernel_handler)
+ # loop is already running (e.g. tornado 5), nothing left to do
+ if loop.is_running():
+ return
+ while True:
+ error = None
+ try:
+ loop.run_forever()
+ except KeyboardInterrupt:
+ continue
+ except Exception as e:
+ error = e
+ if hasattr(loop, 'shutdown_asyncgens'):
+ loop.run_until_complete(loop.shutdown_asyncgens())
+ loop.close()
+ if error is not None:
+ raise error
+ break
def enable_gui(gui, kernel=None):
"""Enable integration with a given GUI"""
diff --git a/ipykernel/inprocess/tests/test_kernel.py b/ipykernel/inprocess/tests/test_kernel.py
index 0231c86..aa7cf67 100644
--- a/ipykernel/inprocess/tests/test_kernel.py
+++ b/ipykernel/inprocess/tests/test_kernel.py
@@ -50,7 +50,7 @@ class InProcessKernelTestCase(unittest.TestCase):
self.kc.execute('x = raw_input()')
finally:
sys.stdin = sys_stdin
- self.assertEqual(self.km.kernel.shell.user_ns.get('x'), 'foobar')
+ assert self.km.kernel.shell.user_ns.get('x') == 'foobar'
def test_stdout(self):
""" Does the in-process kernel correctly capture IO?
@@ -59,13 +59,13 @@ class InProcessKernelTestCase(unittest.TestCase):
with capture_output() as io:
kernel.shell.run_cell('print("foo")')
- self.assertEqual(io.stdout, 'foo\n')
+ assert io.stdout == 'foo\n'
kc = BlockingInProcessKernelClient(kernel=kernel, session=kernel.session)
kernel.frontends.append(kc)
kc.execute('print("bar")')
out, err = assemble_output(kc.iopub_channel)
- self.assertEqual(out, 'bar\n')
+ assert out == 'bar\n'
def test_getpass_stream(self):
"Tests that kernel getpass accept the stream parameter"
diff --git a/ipykernel/inprocess/tests/test_kernelmanager.py b/ipykernel/inprocess/tests/test_kernelmanager.py
index f3e4436..9de5994 100644
--- a/ipykernel/inprocess/tests/test_kernelmanager.py
+++ b/ipykernel/inprocess/tests/test_kernelmanager.py
@@ -25,31 +25,31 @@ class InProcessKernelManagerTestCase(unittest.TestCase):
""" Does the in-process kernel manager implement the basic KM interface?
"""
km = self.km
- self.assert_(not km.has_kernel)
+ assert not km.has_kernel
km.start_kernel()
- self.assert_(km.has_kernel)
- self.assert_(km.kernel is not None)
+ assert km.has_kernel
+ assert km.kernel is not None
kc = km.client()
- self.assert_(not kc.channels_running)
+ assert not kc.channels_running
kc.start_channels()
- self.assert_(kc.channels_running)
+ assert kc.channels_running
old_kernel = km.kernel
km.restart_kernel()
self.assertIsNotNone(km.kernel)
- self.assertNotEquals(km.kernel, old_kernel)
+ assert km.kernel != old_kernel
km.shutdown_kernel()
- self.assert_(not km.has_kernel)
+ assert not km.has_kernel
self.assertRaises(NotImplementedError, km.interrupt_kernel)
self.assertRaises(NotImplementedError, km.signal_kernel, 9)
kc.stop_channels()
- self.assert_(not kc.channels_running)
+ assert not kc.channels_running
def test_execute(self):
""" Does executing code in an in-process kernel work?
@@ -60,7 +60,7 @@ class InProcessKernelManagerTestCase(unittest.TestCase):
kc.start_channels()
kc.wait_for_ready()
kc.execute('foo = 1')
- self.assertEquals(km.kernel.shell.user_ns['foo'], 1)
+ assert km.kernel.shell.user_ns['foo'] == 1
def test_complete(self):
""" Does requesting completion from an in-process kernel work?
@@ -73,7 +73,7 @@ class InProcessKernelManagerTestCase(unittest.TestCase):
km.kernel.shell.push({'my_bar': 0, 'my_baz': 1})
kc.complete('my_ba', 5)
msg = kc.get_shell_msg()
- self.assertEqual(msg['header']['msg_type'], 'complete_reply')
+ assert msg['header']['msg_type'] == 'complete_reply'
self.assertEqual(sorted(msg['content']['matches']),
['my_bar', 'my_baz'])
@@ -88,7 +88,7 @@ class InProcessKernelManagerTestCase(unittest.TestCase):
km.kernel.shell.user_ns['foo'] = 1
kc.inspect('foo')
msg = kc.get_shell_msg()
- self.assertEqual(msg['header']['msg_type'], 'inspect_reply')
+ assert msg['header']['msg_type'] == 'inspect_reply'
content = msg['content']
assert content['found']
text = content['data']['text/plain']
@@ -105,10 +105,10 @@ class InProcessKernelManagerTestCase(unittest.TestCase):
kc.execute('1')
kc.history(hist_access_type='tail', n=1)
msg = kc.shell_channel.get_msgs()[-1]
- self.assertEquals(msg['header']['msg_type'], 'history_reply')
+ assert msg['header']['msg_type'] == 'history_reply'
history = msg['content']['history']
- self.assertEquals(len(history), 1)
- self.assertEquals(history[0][2], '1')
+ assert len(history) == 1
+ assert history[0][2] == '1'
if __name__ == '__main__':
diff --git a/ipykernel/iostream.py b/ipykernel/iostream.py
index 4e99e96..0d11d9e 100644
--- a/ipykernel/iostream.py
+++ b/ipykernel/iostream.py
@@ -7,11 +7,16 @@
from __future__ import print_function
import atexit
from binascii import b2a_hex
+from collections import deque
+try:
+ from importlib import lock_held as import_lock_held
+except ImportError:
+ from imp import lock_held as import_lock_held
import os
import sys
import threading
import warnings
-from io import StringIO, UnsupportedOperation, TextIOBase
+from io import StringIO, TextIOBase
import zmq
from zmq.eventloop.ioloop import IOLoop
@@ -58,17 +63,18 @@ class IOPubThread(object):
self.background_socket = BackgroundSocket(self)
self._master_pid = os.getpid()
self._pipe_flag = pipe
- self.io_loop = IOLoop()
+ self.io_loop = IOLoop(make_current=False)
if pipe:
self._setup_pipe_in()
self._local = threading.local()
- self._events = {}
+ self._events = deque()
self._setup_event_pipe()
self.thread = threading.Thread(target=self._thread_main)
self.thread.daemon = True
def _thread_main(self):
"""The inner loop that's actually run in a thread"""
+ self.io_loop.make_current()
self.io_loop.start()
self.io_loop.close(all_fds=True)
@@ -83,7 +89,7 @@ class IOPubThread(object):
pipe_in.bind(iface)
self._event_puller = ZMQStream(pipe_in, self.io_loop)
self._event_puller.on_recv(self._handle_event)
-
+
@property
def _event_pipe(self):
"""thread-local event pipe for signaling events that should be processed in the thread"""
@@ -99,11 +105,20 @@ class IOPubThread(object):
return event_pipe
def _handle_event(self, msg):
- """Handle an event on the event pipe"""
- event_id = msg[0]
- event_f = self._events.pop(event_id)
- event_f()
-
+ """Handle an event on the event pipe
+
+ Content of the message is ignored.
+
+ Whenever *an* event arrives on the event stream,
+ *all* waiting events are processed in order.
+ """
+ # freeze event count so new writes don't extend the queue
+ # while we are processing
+ n_events = len(self._events)
+ for i in range(n_events):
+ event_f = self._events.popleft()
+ event_f()
+
def _setup_pipe_in(self):
"""setup listening pipe for IOPub from forked subprocesses"""
ctx = self.socket.context
@@ -125,7 +140,7 @@ class IOPubThread(object):
return
self._pipe_in = ZMQStream(pipe_in, self.io_loop)
self._pipe_in.on_recv(self._handle_pipe_msg)
-
+
def _handle_pipe_msg(self, msg):
"""handle a pipe message from a subprocess"""
if not self._pipe_flag or not self._is_master_process():
@@ -183,11 +198,9 @@ class IOPubThread(object):
If the thread is not running, call immediately.
"""
if self.thread.is_alive():
- event_id = os.urandom(16)
- while event_id in self._events:
- event_id = os.urandom(16)
- self._events[event_id] = f
- self._event_pipe.send(event_id)
+ self._events.append(f)
+ # wake event thread (message content is ignored)
+ self._event_pipe.send(b'')
else:
f()
@@ -255,6 +268,9 @@ class OutStream(TextIOBase):
Output is handed off to an IO Thread
"""
+ # timeout for flush to avoid infinite hang
+ # in case of misbehavior
+ flush_timeout = 10
# The time interval between automatic flushes, in seconds.
flush_interval = 0.2
topic = None
@@ -296,7 +312,7 @@ class OutStream(TextIOBase):
def _schedule_flush(self):
"""schedule a flush in the IO thread
-
+
call this on write, to indicate that flush should be called soon.
"""
if self._flush_pending:
@@ -310,21 +326,29 @@ class OutStream(TextIOBase):
def flush(self):
"""trigger actual zmq send
-
+
send will happen in the background thread
"""
if self.pub_thread.thread.is_alive():
- # wait for flush to actually get through:
+ # request flush on the background thread
self.pub_thread.schedule(self._flush)
- evt = threading.Event()
- self.pub_thread.schedule(evt.set)
- evt.wait()
+ # wait for flush to actually get through, if we can.
+ # waiting across threads during import can cause deadlocks
+ # so only wait if import lock is not held
+ if not import_lock_held():
+ evt = threading.Event()
+ self.pub_thread.schedule(evt.set)
+ # and give a timeout to avoid
+ if not evt.wait(self.flush_timeout):
+ # write directly to __stderr__ instead of warning because
+ # if this is happening sys.stderr may be the problem.
+ print("IOStream.flush timed out", file=sys.__stderr__)
else:
self._flush()
-
+
def _flush(self):
"""This is where the actual send happens.
-
+
_flush should generally be called in the IO thread,
unless the thread has been destroyed (e.g. forked subprocess).
"""
diff --git a/ipykernel/ipkernel.py b/ipykernel/ipkernel.py
index c9627ad..6304131 100644
--- a/ipykernel/ipkernel.py
+++ b/ipykernel/ipkernel.py
@@ -2,23 +2,35 @@
import getpass
import sys
-import traceback
from IPython.core import release
from ipython_genutils.py3compat import builtin_mod, PY3, unicode_type, safe_unicode
from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
-from traitlets import Instance, Type, Any, List
+from traitlets import Instance, Type, Any, List, Bool
from .comm import CommManager
from .kernelbase import Kernel as KernelBase
from .zmqshell import ZMQInteractiveShell
+try:
+ from IPython.core.completer import rectify_completions as _rectify_completions, provisionalcompleter as _provisionalcompleter
+ _use_experimental_60_completion = True
+except ImportError:
+ _use_experimental_60_completion = False
+
+_EXPERIMENTAL_KEY_NAME = '_jupyter_types_experimental'
+
+
class IPythonKernel(KernelBase):
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
allow_none=True)
shell_class = Type(ZMQInteractiveShell)
+ use_experimental_completions = Bool(True,
+ help="Set this flag to False to deactivate the use of experimental IPython completion APIs.",
+ ).tag(config=True)
+
user_module = Any()
def _user_module_changed(self, name, old, new):
if self.shell is not None:
@@ -60,32 +72,32 @@ class IPythonKernel(KernelBase):
help_links = List([
{
- 'text': "Python",
- 'url': "http://docs.python.org/%i.%i" % sys.version_info[:2],
+ 'text': "Python Reference",
+ 'url': "https://docs.python.org/%i.%i" % sys.version_info[:2],
},
{
- 'text': "IPython",
- 'url': "http://ipython.org/documentation.html",
+ 'text': "IPython Reference",
+ 'url': "https://ipython.org/documentation.html",
},
{
- 'text': "NumPy",
- 'url': "http://docs.scipy.org/doc/numpy/reference/",
+ 'text': "NumPy Reference",
+ 'url': "https://docs.scipy.org/doc/numpy/reference/",
},
{
- 'text': "SciPy",
- 'url': "http://docs.scipy.org/doc/scipy/reference/",
+ 'text': "SciPy Reference",
+ 'url': "https://docs.scipy.org/doc/scipy/reference/",
},
{
- 'text': "Matplotlib",
- 'url': "http://matplotlib.org/contents.html",
+ 'text': "Matplotlib Reference",
+ 'url': "https://matplotlib.org/contents.html",
},
{
- 'text': "SymPy",
+ 'text': "SymPy Reference",
'url': "http://docs.sympy.org/latest/index.html",
},
{
- 'text': "pandas",
- 'url': "http://pandas.pydata.org/pandas-docs/stable/",
+ 'text': "pandas Reference",
+ 'url': "https://pandas.pydata.org/pandas-docs/stable/",
},
]).tag(config=True)
@@ -246,6 +258,9 @@ class IPythonKernel(KernelBase):
return reply_content
def do_complete(self, code, cursor_pos):
+ if _use_experimental_60_completion and self.use_experimental_completions:
+ return self._experimental_do_complete(code, cursor_pos)
+
# FIXME: IPython completers currently assume single line,
# but completion messages give multi-line context
# For now, extract line from cell, based on cursor_pos:
@@ -261,6 +276,42 @@ class IPythonKernel(KernelBase):
'metadata' : {},
'status' : 'ok'}
+ def _experimental_do_complete(self, code, cursor_pos):
+ """
+ Experimental completions from IPython, using Jedi.
+ """
+ if cursor_pos is None:
+ cursor_pos = len(code)
+ with _provisionalcompleter():
+ raw_completions = self.shell.Completer.completions(code, cursor_pos)
+ completions = list(_rectify_completions(code, raw_completions))
+
+ comps = []
+ for comp in completions:
+ comps.append(dict(
+ start=comp.start,
+ end=comp.end,
+ text=comp.text,
+ type=comp.type,
+ ))
+
+ if completions:
+ s = completions[0].start
+ e = completions[0].end
+ matches = [c.text for c in completions]
+ else:
+ s = cursor_pos
+ e = cursor_pos
+ matches = []
+
+ return {'matches': matches,
+ 'cursor_end': e,
+ 'cursor_start': s,
+ 'metadata': {_EXPERIMENTAL_KEY_NAME: comps},
+ 'status': 'ok'}
+
+
+
def do_inspect(self, code, cursor_pos, detail_level=0):
name = token_at_cursor(code, cursor_pos)
info = self.shell.object_inspect(name)
@@ -304,7 +355,7 @@ class IPythonKernel(KernelBase):
return dict(status='ok', restart=restart)
def do_is_complete(self, code):
- status, indent_spaces = self.shell.input_transformer_manager.check_complete(code)
+ status, indent_spaces = self.shell.input_splitter.check_complete(code)
r = {'status': status}
if status == 'incomplete':
r['indent'] = ' ' * indent_spaces
diff --git a/ipykernel/jsonutil.py b/ipykernel/jsonutil.py
index 3121e53..df669f7 100644
--- a/ipykernel/jsonutil.py
+++ b/ipykernel/jsonutil.py
@@ -3,18 +3,13 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
+from binascii import b2a_base64
import math
import re
import types
from datetime import datetime
import numbers
-try:
- # base64.encodestring is deprecated in Python 3.x
- from base64 import encodebytes
-except ImportError:
- # Python 2.x
- from base64 import encodestring as encodebytes
from ipython_genutils import py3compat
from ipython_genutils.py3compat import unicode_type, iteritems
@@ -45,6 +40,9 @@ PNG64 = b'iVBORw0KG'
JPEG = b'\xff\xd8'
# front of JPEG base64-encoded
JPEG64 = b'/9'
+# constants for identifying gif data
+GIF_64 = b'R0lGODdh'
+GIF89_64 = b'R0lGODlh'
# front of PDF base64-encoded
PDF64 = b'JVBER'
@@ -68,27 +66,41 @@ def encode_images(format_dict):
is base64-encoded.
"""
+
+ # no need for handling of ambiguous bytestrings on Python 3,
+ # where bytes objects always represent binary data and thus
+ # base64-encoded.
+ if py3compat.PY3:
+ return format_dict
+
encoded = format_dict.copy()
pngdata = format_dict.get('image/png')
if isinstance(pngdata, bytes):
# make sure we don't double-encode
if not pngdata.startswith(PNG64):
- pngdata = encodebytes(pngdata)
+ pngdata = b2a_base64(pngdata)
encoded['image/png'] = pngdata.decode('ascii')
jpegdata = format_dict.get('image/jpeg')
if isinstance(jpegdata, bytes):
# make sure we don't double-encode
if not jpegdata.startswith(JPEG64):
- jpegdata = encodebytes(jpegdata)
+ jpegdata = b2a_base64(jpegdata)
encoded['image/jpeg'] = jpegdata.decode('ascii')
+
+ gifdata = format_dict.get('image/gif')
+ if isinstance(gifdata, bytes):
+ # make sure we don't double-encode
+ if not gifdata.startswith((GIF_64, GIF89_64)):
+ gifdata = b2a_base64(gifdata)
+ encoded['image/gif'] = gifdata.decode('ascii')
pdfdata = format_dict.get('application/pdf')
if isinstance(pdfdata, bytes):
# make sure we don't double-encode
if not pdfdata.startswith(PDF64):
- pdfdata = encodebytes(pdfdata)
+ pdfdata = b2a_base64(pdfdata)
encoded['application/pdf'] = pdfdata.decode('ascii')
return encoded
@@ -141,9 +153,21 @@ def json_clean(obj):
if isinstance(obj, atomic_ok):
return obj
-
+
if isinstance(obj, bytes):
- return obj.decode(DEFAULT_ENCODING, 'replace')
+ if py3compat.PY3:
+ # unanmbiguous binary data is base64-encoded
+ # (this probably should have happened upstream)
+ return b2a_base64(obj).decode('ascii')
+ else:
+ # Python 2 bytestr is ambiguous,
+ # needs special handling for possible binary bytestrings.
+ # imperfect workaround: if ascii, assume text.
+ # otherwise assume binary, base64-encode (py3 behavior).
+ try:
+ return obj.decode('ascii')
+ except UnicodeDecodeError:
+ return b2a_base64(obj).decode('ascii')
if isinstance(obj, container_to_list) or (
hasattr(obj, '__iter__') and hasattr(obj, next_attr_name)):
diff --git a/ipykernel/kernelapp.py b/ipykernel/kernelapp.py
index 59190c0..b67d150 100644
--- a/ipykernel/kernelapp.py
+++ b/ipykernel/kernelapp.py
@@ -473,8 +473,9 @@ class IPKernelApp(BaseIPythonApplication, InteractiveShellApp,
if self.poller is not None:
self.poller.start()
self.kernel.start()
+ self.io_loop = ioloop.IOLoop.current()
try:
- ioloop.IOLoop.instance().start()
+ self.io_loop.start()
except KeyboardInterrupt:
pass
diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py
index 90f33cf..199af5c 100644
--- a/ipykernel/kernelbase.py
+++ b/ipykernel/kernelbase.py
@@ -49,7 +49,7 @@ class Kernel(SingletonConfigurable):
@observe('eventloop')
def _update_eventloop(self, change):
"""schedule call to eventloop from IOLoop"""
- loop = ioloop.IOLoop.instance()
+ loop = ioloop.IOLoop.current()
loop.add_callback(self.enter_eventloop)
session = Instance(Session, allow_none=True)
@@ -135,7 +135,6 @@ class Kernel(SingletonConfigurable):
def __init__(self, **kwargs):
super(Kernel, self).__init__(**kwargs)
-
# Build dict of handlers for message types
self.shell_handlers = {}
for msg_type in self.msg_types:
@@ -212,8 +211,6 @@ class Kernel(SingletonConfigurable):
self.set_parent(idents, msg)
self._publish_status(u'busy')
- header = msg['header']
- msg_id = header['msg_id']
msg_type = msg['header']['msg_type']
# Print some info about this message and leave a '--->' marker, so it's
@@ -275,6 +272,7 @@ class Kernel(SingletonConfigurable):
def start(self):
"""register dispatchers for streams"""
+ self.io_loop = ioloop.IOLoop.current()
if self.control_stream:
self.control_stream.on_recv(self.dispatch_control, copy=False)
@@ -430,12 +428,11 @@ class Kernel(SingletonConfigurable):
content = parent['content']
code = content['code']
cursor_pos = content['cursor_pos']
-
+
matches = self.do_complete(code, cursor_pos)
matches = json_clean(matches)
completion_msg = self.session.send(stream, 'complete_reply',
matches, parent, ident)
- self.log.debug("%s", completion_msg)
def do_complete(self, code, cursor_pos):
"""Override in subclasses to find completions.
@@ -534,7 +531,7 @@ class Kernel(SingletonConfigurable):
self._at_shutdown()
# call sys.exit after a short delay
- loop = ioloop.IOLoop.instance()
+ loop = ioloop.IOLoop.current()
loop.add_timeout(time.time()+0.1, loop.stop)
def do_shutdown(self, restart):
diff --git a/ipykernel/pylab/backend_inline.py b/ipykernel/pylab/backend_inline.py
index 63b9693..739165e 100644
--- a/ipykernel/pylab/backend_inline.py
+++ b/ipykernel/pylab/backend_inline.py
@@ -150,12 +150,14 @@ def _enable_matplotlib_integration():
ip = get_ipython()
backend = get_backend()
if ip and backend == 'module://%s' % __name__:
- from IPython.core.pylabtools import configure_inline_support
+ from IPython.core.pylabtools import configure_inline_support, activate_matplotlib
try:
+ activate_matplotlib(backend)
configure_inline_support(ip, backend)
- except ImportError:
+ except (ImportError, AttributeError):
# bugs may cause a circular import on Python 2
def configure_once(*args):
+ activate_matplotlib(backend)
configure_inline_support(ip, backend)
ip.events.unregister('post_run_cell', configure_once)
ip.events.register('post_run_cell', configure_once)
diff --git a/ipykernel/tests/_asyncio.py b/ipykernel/tests/_asyncio.py
new file mode 100644
index 0000000..43e3229
--- /dev/null
+++ b/ipykernel/tests/_asyncio.py
@@ -0,0 +1,17 @@
+"""test utilities that use async/await syntax
+
+a separate file to avoid syntax errors on Python 2
+"""
+
+import asyncio
+
+
+def async_func():
+ """Simple async function to schedule a task on the current eventloop"""
+ loop = asyncio.get_event_loop()
+ assert loop.is_running()
+
+ async def task():
+ await asyncio.sleep(1)
+
+ loop.create_task(task())
diff --git a/ipykernel/tests/test_connect.py b/ipykernel/tests/test_connect.py
index e0b812c..739eb12 100644
--- a/ipykernel/tests/test_connect.py
+++ b/ipykernel/tests/test_connect.py
@@ -6,8 +6,6 @@
import json
import os
-import nose.tools as nt
-
from traitlets.config import Config
from ipython_genutils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
from ipython_genutils.py3compat import str_to_bytes
@@ -36,14 +34,14 @@ def test_get_connection_file():
app.initialize()
profile_cf = os.path.join(app.connection_dir, cf)
- nt.assert_equal(profile_cf, app.abs_connection_file)
+ assert profile_cf == app.abs_connection_file
with open(profile_cf, 'w') as f:
f.write("{}")
- nt.assert_true(os.path.exists(profile_cf))
- nt.assert_equal(connect.get_connection_file(app), profile_cf)
+ assert os.path.exists(profile_cf)
+ assert connect.get_connection_file(app) == profile_cf
app.connection_file = cf
- nt.assert_equal(connect.get_connection_file(app), profile_cf)
+ assert connect.get_connection_file(app) == profile_cf
def test_get_connection_info():
@@ -52,12 +50,12 @@ def test_get_connection_info():
connect.write_connection_file(cf, **sample_info)
json_info = connect.get_connection_info(cf)
info = connect.get_connection_info(cf, unpack=True)
-
- nt.assert_equal(type(json_info), type(""))
+ assert isinstance(json_info, str)
+
sub_info = {k:v for k,v in info.items() if k in sample_info}
- nt.assert_equal(sub_info, sample_info)
+ assert sub_info == sample_info
info2 = json.loads(json_info)
info2['key'] = str_to_bytes(info2['key'])
sub_info2 = {k:v for k,v in info.items() if k in sample_info}
- nt.assert_equal(sub_info2, sample_info)
+ assert sub_info2 == sample_info
diff --git a/ipykernel/tests/test_embed_kernel.py b/ipykernel/tests/test_embed_kernel.py
index 03de53d..5e60245 100644
--- a/ipykernel/tests/test_embed_kernel.py
+++ b/ipykernel/tests/test_embed_kernel.py
@@ -4,19 +4,14 @@
# Distributed under the terms of the Modified BSD License.
import os
-import shutil
import sys
-import tempfile
import time
from contextlib import contextmanager
from subprocess import Popen, PIPE
-import nose.tools as nt
-
from jupyter_client import BlockingKernelClient
from jupyter_core import paths
-from IPython.paths import get_ipython_dir
from ipython_genutils import py3compat
from ipython_genutils.py3compat import unicode_type
@@ -83,20 +78,20 @@ def test_embed_kernel_basic():
msg_id = client.inspect('a')
msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
content = msg['content']
- nt.assert_true(content['found'])
+ assert content['found']
msg_id = client.execute("c=a*2")
msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
content = msg['content']
- nt.assert_equal(content['status'], u'ok')
+ assert content['status'] == u'ok'
# oinfo c (should be 10)
msg_id = client.inspect('c')
msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
content = msg['content']
- nt.assert_true(content['found'])
+ assert content['found']
text = content['data']['text/plain']
- nt.assert_in('10', text)
+ assert '10' in text
def test_embed_kernel_namespace():
"""IPython.embed_kernel() inherits calling namespace"""
@@ -115,23 +110,23 @@ def test_embed_kernel_namespace():
msg_id = client.inspect('a')
msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
content = msg['content']
- nt.assert_true(content['found'])
+ assert content['found']
text = content['data']['text/plain']
- nt.assert_in(u'5', text)
+ assert u'5' in text
# oinfo b (str)
msg_id = client.inspect('b')
msg = client.get_shell_msg(block=True, timeout=TIMEOUT)
content = msg['content']
- nt.assert_true(content['found'])
+ assert content['found']
text = content['data']['text/plain']
- nt.assert_in(u'hi there', text)
+ assert u'hi there' in text
... 1156 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/ipykernel.git
More information about the Python-modules-commits
mailing list