1818__version__ = '0.0.3'
1919
2020import ctypes
21- from contextlib import contextmanager
22- from fcntl import fcntl , F_GETFL , F_SETFL
2321import os
2422import shutil
2523import select
2624import struct
2725import sys
2826import threading
27+ import time
2928
3029from traitlets import Unicode , Float , Dict , List , CaselessStrEnum
3130from ipykernel .kernelbase import Kernel
3938class my_void_p (ctypes .c_void_p ):
4039 pass
4140
42- libc = ctypes .CDLL (None )
43- try :
44- c_stdout_p = ctypes .c_void_p .in_dll (libc , 'stdout' )
45- c_stderr_p = ctypes .c_void_p .in_dll (libc , 'stderr' )
46- except ValueError :
47- # libc.stdout is has a funny name on OS X
48- c_stdout_p = ctypes .c_void_p .in_dll (libc , '__stdoutp' )
49- c_stderr_p = ctypes .c_void_p .in_dll (libc , '__stderrp' )
41+ if sys .platform == 'win32' :
42+ import msvcrt
43+ libc = ctypes .cdll .msvcrt
44+
45+ class FILE (ctypes .Structure ):
46+ pass
47+
48+ FILE_p = ctypes .POINTER (FILE )
49+
50+ libc ._fdopen .argtypes = [ctypes .c_int , ctypes .c_char_p ]
51+ libc ._fdopen .restype = FILE_p
52+
53+ c_stdout_p = libc ._fdopen (sys .stdout .fileno (), b"w" )
54+ c_stderr_p = libc ._fdopen (sys .stderr .fileno (), b"w" )
55+
56+ peek_named_pipe = ctypes .windll .kernel32 .PeekNamedPipe
57+ peek_named_pipe .argtypes = [
58+ ctypes .wintypes .HANDLE ,
59+ ctypes .c_void_p ,
60+ ctypes .wintypes .DWORD ,
61+ ctypes .POINTER (ctypes .wintypes .DWORD ),
62+ ctypes .POINTER (ctypes .wintypes .DWORD ),
63+ ctypes .POINTER (ctypes .wintypes .DWORD ),
64+ ]
65+ peek_named_pipe .restype = ctypes .c_bool
66+
67+ libc .fflush .argtypes = [FILE_p ]
68+ libc .fflush .restype = ctypes .c_int
69+ else :
70+ libc = ctypes .CDLL (None )
71+
72+ try :
73+ c_stdout_p = ctypes .c_void_p .in_dll (libc , 'stdout' )
74+ c_stderr_p = ctypes .c_void_p .in_dll (libc , 'stderr' )
75+ except ValueError :
76+ # libc.stdout is has a funny name on OS X
77+ c_stdout_p = ctypes .c_void_p .in_dll (libc , '__stdoutp' )
78+ c_stderr_p = ctypes .c_void_p .in_dll (libc , '__stderrp' )
5079
5180
5281class FdReplacer :
@@ -59,8 +88,9 @@ def __init__(self, name):
5988 os .dup2 (pipe_in , self .real_fd )
6089 os .close (pipe_in )
6190 # make pipe_out non-blocking
62- flags = fcntl (self .pipe_out , F_GETFL )
63- fcntl (self .pipe_out , F_SETFL , flags | os .O_NONBLOCK )
91+ # flags = fcntl(self.pipe_out, F_GETFL)
92+ # fcntl(self.pipe_out, F_SETFL, flags|os.O_NONBLOCK)
93+ os .set_blocking (self .pipe_out , False )
6494
6595 def restore (self ):
6696 os .close (self .real_fd )
@@ -120,7 +150,7 @@ def __init__(self, **kwargs):
120150 else :
121151 raise RuntimeError ('cling at ' + clingInPath + ' is unusable. No cling, no fun.' )
122152
123- for libFolder in ["/lib/libclingJupyter." , "/libexec/lib/libclingJupyter." ]:
153+ for libFolder in ["/bin/libclingJupyter." , "/ lib/libclingJupyter." , "/libexec/lib/libclingJupyter." ]:
124154
125155 for ext in ['so' , 'dylib' , 'dll' ]:
126156 libFilename = clingInstDir + libFolder + ext
@@ -225,6 +255,44 @@ def forward_streams(self):
225255
226256 def handle_input (self ):
227257 """Capture stdout, stderr and sideband. Forward them as stream messages."""
258+ if sys .platform == 'win32' :
259+ pipes = {"sideband" : self .sideband_pipe }
260+ for rs in self .replaced_streams :
261+ if rs :
262+ pipes [rs .name ] = rs .pipe_out
263+
264+ # wait for the flush interval before peeking at the pipe
265+ time .sleep (self .flush_interval )
266+
267+ pipe_bytes = {}
268+ total_bytes = 0
269+ for name , pipe in pipes .items ():
270+ bytes_available = ctypes .wintypes .DWORD (0 )
271+ peek_named_pipe (
272+ ctypes .wintypes .HANDLE (msvcrt .get_osfhandle (pipe )),
273+ None ,
274+ 0 ,
275+ None ,
276+ ctypes .byref (bytes_available ),
277+ None ,
278+ )
279+ pipe_bytes [name ] = bytes_available .value
280+ total_bytes += bytes_available .value
281+
282+ if total_bytes == 0 :
283+ libc .fflush (c_stdout_p )
284+ libc .fflush (c_stderr_p )
285+ return False
286+
287+ for name , n_bytes in pipe_bytes .items ():
288+ if n_bytes == 0 :
289+ continue
290+
291+ if name == "sideband" :
292+ self ._process_sideband_data ()
293+ else :
294+ self ._process_stdio_data (pipes [name ], name )
295+ return True
228296 # create pipe for stdout, stderr
229297 select_on = [self .sideband_pipe ]
230298 for rs in self .replaced_streams :
@@ -287,7 +355,8 @@ def do_execute(self, code, silent, store_history=True,
287355 run_cell_thread .join ()
288356
289357 # Any leftovers?
290- while self .handle_input (): True
358+ while self .handle_input ():
359+ pass
291360
292361 self .close_forwards ()
293362 status = 'ok'
0 commit comments