[Python-modules-commits] [ipykernel] 01/08: Import ipykernel_4.8.0.orig.tar.gz
Gordon Ball
chronitis-guest at moszumanska.debian.org
Tue Feb 6 15:11:09 UTC 2018
This is an automated email from the git hooks/post-receive script.
chronitis-guest pushed a commit to branch master
in repository ipykernel.
commit 669a5bd37c9d020646d02a2d3eb0a88c74758f2d
Author: Gordon Ball <gordon at chronitis.net>
Date: Tue Feb 6 11:02:13 2018 +0000
Import ipykernel_4.8.0.orig.tar.gz
---
MANIFEST.in | 2 +-
docs/changelog.rst | 17 +++++
docs/conf.py | 3 +
docs/requirements.txt | 1 +
ipykernel/_eventloop_macos.py | 153 ++++++++++++++++++++++++++++++++++++++++++
ipykernel/_version.py | 2 +-
ipykernel/eventloops.py | 117 +++++++++++++++++++-------------
ipykernel/kernelbase.py | 6 +-
ipykernel/zmqshell.py | 4 ++
readthedocs.yml | 1 +
10 files changed, 256 insertions(+), 50 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
index ce535d5..90bc61e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -10,7 +10,7 @@ exclude docs/\#*
graft examples
# docs subdirs we want to skip
-prune docs/build
+prune docs/_build
prune docs/gh-pages
prune docs/dist
diff --git a/docs/changelog.rst b/docs/changelog.rst
index a5d950d..40f675c 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,6 +1,21 @@
Changes in IPython kernel
=========================
+4.8
+---
+
+4.8.0
+*****
+
+`4.8.0 on GitHub <https://github.com/ipython/ipykernel/milestones/4.8>`__
+
+- Cleanly shutdown integrated event loops when shutting down the kernel.
+ (:ghpull:`290`)
+- ``%gui qt`` now uses Qt 5 by default rather than Qt 4, following a similar
+ change in terminal IPython. (:ghpull:`293`)
+- Fix event loop integration for :mod:`asyncio` when run with Tornado 5,
+ which uses asyncio where available. (:ghpull:`296`)
+
4.7
---
@@ -38,8 +53,10 @@ Changes in IPython kernel
- Add to API `DisplayPublisher.publish` two new fully backward-compatible
keyword-args:
+
- `update: bool`
- `transient: dict`
+
- Support new `transient` key in `display_data` messages spec for `publish`.
For a display data message, `transient` contains data that shouldn't be
persisted to files or documents. Add a `display_id` to this `transient`
diff --git a/docs/conf.py b/docs/conf.py
index 4c03611..d7a215b 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -33,8 +33,11 @@ import shlex
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
+ 'sphinxcontrib_github_alt',
]
+github_project_url = "https://github.com/ipython/ipykernel"
+
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..623e487
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1 @@
+sphinxcontrib_github_alt
diff --git a/ipykernel/_eventloop_macos.py b/ipykernel/_eventloop_macos.py
new file mode 100644
index 0000000..fbae6ac
--- /dev/null
+++ b/ipykernel/_eventloop_macos.py
@@ -0,0 +1,153 @@
+"""Eventloop hook for OS X
+
+Calls NSApp / CoreFoundation APIs via ctypes.
+"""
+
+# cribbed heavily from IPython.terminal.pt_inputhooks.osx
+# obj-c boilerplate from appnope, used under BSD 2-clause
+
+import ctypes
+import ctypes.util
+from threading import Event
+
+objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc'))
+
+void_p = ctypes.c_void_p
+
+objc.objc_getClass.restype = void_p
+objc.sel_registerName.restype = void_p
+objc.objc_msgSend.restype = void_p
+objc.objc_msgSend.argtypes = [void_p, void_p]
+
+msg = objc.objc_msgSend
+
+
+def _utf8(s):
+ """ensure utf8 bytes"""
+ if not isinstance(s, bytes):
+ s = s.encode('utf8')
+ return s
+
+
+def n(name):
+ """create a selector name (for ObjC methods)"""
+ return objc.sel_registerName(_utf8(name))
+
+
+def C(classname):
+ """get an ObjC Class by name"""
+ return objc.objc_getClass(_utf8(classname))
+
+
+# end obj-c boilerplate from appnope
+
+# CoreFoundation C-API calls we will use:
+CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
+
+CFAbsoluteTimeGetCurrent = CoreFoundation.CFAbsoluteTimeGetCurrent
+CFAbsoluteTimeGetCurrent.restype = ctypes.c_double
+
+CFRunLoopGetCurrent = CoreFoundation.CFRunLoopGetCurrent
+CFRunLoopGetCurrent.restype = void_p
+
+CFRunLoopGetMain = CoreFoundation.CFRunLoopGetMain
+CFRunLoopGetMain.restype = void_p
+
+CFRunLoopStop = CoreFoundation.CFRunLoopStop
+CFRunLoopStop.restype = None
+CFRunLoopStop.argtypes = [void_p]
+
+CFRunLoopTimerCreate = CoreFoundation.CFRunLoopTimerCreate
+CFRunLoopTimerCreate.restype = void_p
+CFRunLoopTimerCreate.argtypes = [
+ void_p, # allocator (NULL)
+ ctypes.c_double, # fireDate
+ ctypes.c_double, # interval
+ ctypes.c_int, # flags (0)
+ ctypes.c_int, # order (0)
+ void_p, # callout
+ void_p, # context
+]
+
+CFRunLoopAddTimer = CoreFoundation.CFRunLoopAddTimer
+CFRunLoopAddTimer.restype = None
+CFRunLoopAddTimer.argtypes = [ void_p, void_p, void_p ]
+
+kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')
+
+
+def _NSApp():
+ """Return the global NSApplication instance (NSApp)"""
+ return msg(C('NSApplication'), n('sharedApplication'))
+
+
+def _wake(NSApp):
+ """Wake the Application"""
+ event = msg(C('NSEvent'),
+ n('otherEventWithType:location:modifierFlags:'
+ 'timestamp:windowNumber:context:subtype:data1:data2:'),
+ 15, # Type
+ 0, # location
+ 0, # flags
+ 0, # timestamp
+ 0, # window
+ None, # context
+ 0, # subtype
+ 0, # data1
+ 0, # data2
+ )
+ msg(NSApp, n('postEvent:atStart:'), void_p(event), True)
+
+
+_triggered = Event()
+
+
+def stop(timer=None, loop=None):
+ """Callback to fire when there's input to be read"""
+ _triggered.set()
+ NSApp = _NSApp()
+ # if NSApp is not running, stop CFRunLoop directly,
+ # otherwise stop and wake NSApp
+ if msg(NSApp, n('isRunning')):
+ msg(NSApp, n('stop:'), NSApp)
+ _wake(NSApp)
+ else:
+ CFRunLoopStop(CFRunLoopGetCurrent())
+
+
+_c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p)
+_c_stop_callback = _c_callback_func_type(stop)
+
+
+def _stop_after(delay):
+ """Register callback to stop eventloop after a delay"""
+ timer = CFRunLoopTimerCreate(
+ None, # allocator
+ CFAbsoluteTimeGetCurrent() + delay, # fireDate
+ 0, # interval
+ 0, # flags
+ 0, # order
+ _c_stop_callback,
+ None,
+ )
+ CFRunLoopAddTimer(
+ CFRunLoopGetMain(),
+ timer,
+ kCFRunLoopCommonModes,
+ )
+
+
+def mainloop(duration=1):
+ """run the Cocoa eventloop for the specified duration (seconds)"""
+
+ _triggered.clear()
+ NSApp = _NSApp()
+ _stop_after(duration)
+ msg(NSApp, n('run'))
+ if not _triggered.is_set():
+ # app closed without firing callback,
+ # probably due to last window being closed.
+ # Run the loop manually in this case,
+ # since there may be events still to process (ipython/ipython#9734)
+ CoreFoundation.CFRunLoopRun()
+
diff --git a/ipykernel/_version.py b/ipykernel/_version.py
index 645a51e..df91ce1 100644
--- a/ipykernel/_version.py
+++ b/ipykernel/_version.py
@@ -1,4 +1,4 @@
-version_info = (4, 7, 0)
+version_info = (4, 8, 0)
__version__ = '.'.join(map(str, version_info))
kernel_protocol_version_info = (5, 1)
diff --git a/ipykernel/eventloops.py b/ipykernel/eventloops.py
index 86f21cd..47b6d72 100644
--- a/ipykernel/eventloops.py
+++ b/ipykernel/eventloops.py
@@ -49,7 +49,7 @@ loop_map = {
'notebook': None,
'ipympl': None,
'widget': None,
- None : None,
+ None: None,
}
def register_integration(*toolkitnames):
@@ -68,6 +68,17 @@ def register_integration(*toolkitnames):
def decorator(func):
for name in toolkitnames:
loop_map[name] = func
+
+ func.exit_hook = lambda kernel: None
+
+ def exit_decorator(exit_func):
+ """@func.exit is now a decorator
+
+ to register a function to be called on exit
+ """
+ func.exit_hook = exit_func
+
+ func.exit = exit_decorator
return func
return decorator
@@ -85,7 +96,7 @@ def _loop_qt(app):
app._in_event_loop = False
- at register_integration('qt', 'qt4')
+ at register_integration('qt4')
def loop_qt4(kernel):
"""Start a kernel with PyQt4 event loop integration."""
@@ -100,13 +111,23 @@ def loop_qt4(kernel):
_loop_qt(kernel.app)
- at register_integration('qt5')
+ at loop_qt4.exit
+def loop_qt4_exit(kernel):
+ kernel.app.exit()
+
+
+ at register_integration('qt', 'qt5')
def loop_qt5(kernel):
"""Start a kernel with PyQt5 event loop integration."""
os.environ['QT_API'] = 'pyqt5'
return loop_qt4(kernel)
+ at loop_qt5.exit
+def loop_qt5_exit(kernel):
+ kernel.app.exit()
+
+
def _loop_wx(app):
"""Inner-loop for running the Wx eventloop
@@ -171,6 +192,12 @@ def loop_wx(kernel):
_loop_wx(kernel.app)
+ at loop_wx.exit
+def loop_wx_exit(kernel):
+ import wx
+ wx.Exit()
+
+
@register_integration('tk')
def loop_tk(kernel):
"""Start a kernel with the Tk event loop."""
@@ -201,6 +228,11 @@ def loop_tk(kernel):
kernel.timer.start()
+ at loop_tk.exit
+def loop_tk_exit(kernel):
+ kernel.timer.app.destroy()
+
+
@register_integration('gtk')
def loop_gtk(kernel):
"""Start the kernel, coordinating with the GTK event loop"""
@@ -208,6 +240,12 @@ def loop_gtk(kernel):
gtk_kernel = GTKEmbed(kernel)
gtk_kernel.start()
+ kernel._gtk = gtk_kernel
+
+
+ at loop_gtk.exit
+def loop_gtk_exit(kernel):
+ kernel._gtk.stop()
@register_integration('gtk3')
@@ -217,6 +255,12 @@ def loop_gtk3(kernel):
gtk_kernel = GTKEmbed(kernel)
gtk_kernel.start()
+ kernel._gtk = gtk_kernel
+
+
+ at loop_gtk3.exit
+def loop_gtk3_exit(kernel):
+ kernel._gtk.stop()
@register_integration('osx')
@@ -224,62 +268,27 @@ def loop_cocoa(kernel):
"""Start the kernel, coordinating with the Cocoa CFRunLoop event loop
via the matplotlib MacOSX backend.
"""
- import matplotlib
- if matplotlib.__version__ < '1.1.0':
- kernel.log.warn(
- "MacOSX backend in matplotlib %s doesn't have a Timer, "
- "falling back on Tk for CFRunLoop integration. Note that "
- "even this won't work if Tk is linked against X11 instead of "
- "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, "
- "you must use matplotlib >= 1.1.0, or a native libtk."
- )
- return loop_tk(kernel)
-
- from matplotlib.backends.backend_macosx import TimerMac, show
-
- # scale interval for sec->ms
- poll_interval = int(1000*kernel._poll_interval)
+ from ._eventloop_macos import mainloop, stop
real_excepthook = sys.excepthook
def handle_int(etype, value, tb):
"""don't let KeyboardInterrupts look like crashes"""
+ # wake the eventloop when we get a signal
+ stop()
if etype is KeyboardInterrupt:
io.raw_print("KeyboardInterrupt caught in CFRunLoop")
else:
real_excepthook(etype, value, tb)
- # add doi() as a Timer to the CFRunLoop
- def doi():
- # restore excepthook during IPython code
- sys.excepthook = real_excepthook
- kernel.do_one_iteration()
- # and back:
- sys.excepthook = handle_int
-
- t = TimerMac(poll_interval)
- t.add_callback(doi)
- t.start()
-
- # but still need a Poller for when there are no active windows,
- # during which time mainloop() returns immediately
- poller = zmq.Poller()
- if kernel.control_stream:
- poller.register(kernel.control_stream.socket, zmq.POLLIN)
- for stream in kernel.shell_streams:
- poller.register(stream.socket, zmq.POLLIN)
-
- while True:
+ while not kernel.shell.exit_now:
try:
# double nested try/except, to properly catch KeyboardInterrupt
# due to pyzmq Issue #130
try:
# don't let interrupts during mainloop invoke crash_handler:
sys.excepthook = handle_int
- show.mainloop()
+ mainloop(kernel._poll_interval)
sys.excepthook = real_excepthook
- # use poller if mainloop returned (no windows)
- # scale by extra factor of 10, since it's a real poll
- poller.poll(10*poll_interval)
kernel.do_one_iteration()
except:
raise
@@ -291,20 +300,26 @@ def loop_cocoa(kernel):
sys.excepthook = real_excepthook
+ at loop_cocoa.exit
+def loop_cocoa_exit(kernel):
+ from ._eventloop_macos import stop
+ stop()
+
+
@register_integration('asyncio')
def loop_asyncio(kernel):
'''Start a kernel with asyncio event loop support.'''
import asyncio
loop = asyncio.get_event_loop()
+ # loop is already running (e.g. tornado 5), nothing left to do
+ if loop.is_running():
+ return
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:
@@ -320,6 +335,16 @@ def loop_asyncio(kernel):
raise error
break
+
+ at loop_asyncio.exit
+def loop_asyncio_exit(kernel):
+ """Exit hook for asyncio"""
+ import asyncio
+ loop = asyncio.get_event_loop()
+ if loop.is_running():
+ loop.call_soon(loop.stop)
+
+
def enable_gui(gui, kernel=None):
"""Enable integration with a given GUI"""
if gui not in loop_map:
diff --git a/ipykernel/kernelbase.py b/ipykernel/kernelbase.py
index 199af5c..cf75e10 100644
--- a/ipykernel/kernelbase.py
+++ b/ipykernel/kernelbase.py
@@ -50,7 +50,8 @@ class Kernel(SingletonConfigurable):
def _update_eventloop(self, change):
"""schedule call to eventloop from IOLoop"""
loop = ioloop.IOLoop.current()
- loop.add_callback(self.enter_eventloop)
+ if change.new is not None:
+ loop.add_callback(self.enter_eventloop)
session = Instance(Session, allow_none=True)
profile_dir = Instance('IPython.core.profiledir.ProfileDir', allow_none=True)
@@ -256,7 +257,7 @@ class Kernel(SingletonConfigurable):
# which may be skipped by entering the eventloop
stream.flush(zmq.POLLOUT)
# restore default_int_handler
- signal(SIGINT, default_int_handler)
+ self.pre_handler_hook()
while self.eventloop is not None:
try:
self.eventloop(self)
@@ -268,6 +269,7 @@ class Kernel(SingletonConfigurable):
# eventloop exited cleanly, this means we should stop (right?)
self.eventloop = None
break
+ self.post_handler_hook()
self.log.info("exiting eventloop")
def start(self):
diff --git a/ipykernel/zmqshell.py b/ipykernel/zmqshell.py
index 7d25d4d..3cdf6e6 100644
--- a/ipykernel/zmqshell.py
+++ b/ipykernel/zmqshell.py
@@ -471,6 +471,10 @@ class ZMQInteractiveShell(InteractiveShell):
if change['new']:
loop = self.kernel.io_loop
loop.call_later(0.1, loop.stop)
+ if self.kernel.eventloop:
+ exit_hook = getattr(self.kernel.eventloop, 'exit_hook', None)
+ if exit_hook:
+ exit_hook(self.kernel)
keepkernel_on_exit = None
diff --git a/readthedocs.yml b/readthedocs.yml
index f8b3b41..a2bc264 100644
--- a/readthedocs.yml
+++ b/readthedocs.yml
@@ -1,3 +1,4 @@
python:
version: 3.5
pip_install: true
+requirements_file: docs/requirements.txt
--
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