From 327a1c7c092afe07b05b792ce67c1845ec0be868 2015-03-30 21:26:38 From: Thomas Kluyver Date: 2015-03-30 21:26:38 Subject: [PATCH] Separate parent functionality from ParentPollerWindows ParentPollerWindows contained a mixture of methods to run in the parent and the child, which was revealed by test failures now that jupyter_client and ipython_kernel are separate packages. This moves the parent methods into a new module jupyter_client.win_interrupt Closes gh-8201 --- diff --git a/ipython_kernel/parentpoller.py b/ipython_kernel/parentpoller.py index d623f9d..227614d 100644 --- a/ipython_kernel/parentpoller.py +++ b/ipython_kernel/parentpoller.py @@ -69,40 +69,6 @@ class ParentPollerWindows(Thread): self.interrupt_handle = interrupt_handle self.parent_handle = parent_handle - @staticmethod - def create_interrupt_event(): - """ Create an interrupt event handle. - - The parent process should use this static method for creating the - interrupt event that is passed to the child process. It should store - this handle and use it with ``send_interrupt`` to interrupt the child - process. - """ - # Create a security attributes struct that permits inheritance of the - # handle by new processes. - # FIXME: We can clean up this mess by requiring pywin32 for IPython. - class SECURITY_ATTRIBUTES(ctypes.Structure): - _fields_ = [ ("nLength", ctypes.c_int), - ("lpSecurityDescriptor", ctypes.c_void_p), - ("bInheritHandle", ctypes.c_int) ] - sa = SECURITY_ATTRIBUTES() - sa_p = ctypes.pointer(sa) - sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES) - sa.lpSecurityDescriptor = 0 - sa.bInheritHandle = 1 - - return ctypes.windll.kernel32.CreateEventA( - sa_p, # lpEventAttributes - False, # bManualReset - False, # bInitialState - '') # lpName - - @staticmethod - def send_interrupt(interrupt_handle): - """ Sends an interrupt event using the specified handle. - """ - ctypes.windll.kernel32.SetEvent(interrupt_handle) - def run(self): """ Run the poll loop. This method never returns. """ diff --git a/jupyter_client/launcher.py b/jupyter_client/launcher.py index 13492d3..66d8442 100644 --- a/jupyter_client/launcher.py +++ b/jupyter_client/launcher.py @@ -175,10 +175,10 @@ def launch_kernel(cmd, stdin=None, stdout=None, stderr=None, env=None, cwd = cast_bytes_py2(cwd, sys.getfilesystemencoding() or 'ascii') kwargs['cwd'] = cwd - from jupyter_client.parentpoller import ParentPollerWindows + from .win_interrupt import create_interrupt_event # Create a Win32 event for interrupting the kernel # and store it in an environment variable. - interrupt_event = ParentPollerWindows.create_interrupt_event() + interrupt_event = create_interrupt_event() env["JPY_INTERRUPT_EVENT"] = str(interrupt_event) # deprecated old env name: env["IPY_INTERRUPT_EVENT"] = env["JPY_INTERRUPT_EVENT"] diff --git a/jupyter_client/manager.py b/jupyter_client/manager.py index 7f74ce6..124b6b8 100644 --- a/jupyter_client/manager.py +++ b/jupyter_client/manager.py @@ -381,8 +381,8 @@ class KernelManager(ConnectionFileMixin): """ if self.has_kernel: if sys.platform == 'win32': - from .parentpoller import ParentPollerWindows as Poller - Poller.send_interrupt(self.kernel.win32_interrupt_event) + from .win_interrupt import send_interrupt + send_interrupt(self.kernel.win32_interrupt_event) else: self.kernel.send_signal(signal.SIGINT) else: diff --git a/jupyter_client/win_interrupt.py b/jupyter_client/win_interrupt.py new file mode 100644 index 0000000..b694295 --- /dev/null +++ b/jupyter_client/win_interrupt.py @@ -0,0 +1,39 @@ +"""Use a Windows event to interrupt a child process like SIGINT. + +The child needs to explicitly listen for this - see +ipython_kernel.parentpoller.ParentPollerWindows for a Python implementation. +""" + +import ctypes + +def create_interrupt_event(): + """Create an interrupt event handle. + + The parent process should call this to create the + interrupt event that is passed to the child process. It should store + this handle and use it with ``send_interrupt`` to interrupt the child + process. + """ + # Create a security attributes struct that permits inheritance of the + # handle by new processes. + # FIXME: We can clean up this mess by requiring pywin32 for IPython. + class SECURITY_ATTRIBUTES(ctypes.Structure): + _fields_ = [ ("nLength", ctypes.c_int), + ("lpSecurityDescriptor", ctypes.c_void_p), + ("bInheritHandle", ctypes.c_int) ] + sa = SECURITY_ATTRIBUTES() + sa_p = ctypes.pointer(sa) + sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES) + sa.lpSecurityDescriptor = 0 + sa.bInheritHandle = 1 + + return ctypes.windll.kernel32.CreateEventA( + sa_p, # lpEventAttributes + False, # bManualReset + False, # bInitialState + '') # lpName + +def send_interrupt(interrupt_handle): + """ Sends an interrupt event using the specified handle. + """ + ctypes.windll.kernel32.SetEvent(interrupt_handle)