6
6
7
7
import logging
8
8
import signal
9
+ import time
10
+ import sys
9
11
10
- from traitlets .config .application import Application
11
12
from traitlets .config import catch_config_error
12
13
from traitlets import (
13
- Instance , Dict , Unicode , Bool , List , CUnicode , Any
14
+ Instance , Dict , Unicode , Bool , List , CUnicode , Any , Float
14
15
)
15
16
from jupyter_core .application import (
16
17
JupyterApp , base_flags , base_aliases
19
20
from . import __version__
20
21
from .consoleapp import JupyterConsoleApp , app_aliases , app_flags
21
22
22
- from jupyter_console .ptshell import ZMQTerminalInteractiveShell
23
+ try :
24
+ import queue
25
+ except ImportError :
26
+ import Queue as queue
27
+
28
+ OUTPUT_TIMEOUT = 10
23
29
24
30
# copy flags from mixin:
25
31
flags = dict (base_flags )
@@ -48,6 +54,24 @@ class RunApp(JupyterApp, JupyterConsoleApp):
48
54
aliases = Dict (aliases )
49
55
frontend_aliases = Any (frontend_aliases )
50
56
frontend_flags = Any (frontend_flags )
57
+ session_id = Unicode ()
58
+ include_other_output = Bool (False , config = True ,
59
+ help = """Whether to include output from clients
60
+ other than this one sharing the same kernel.
61
+
62
+ Outputs are not displayed until enter is pressed.
63
+ """
64
+ )
65
+ kernel_info = {}
66
+ kernel_timeout = Float (60 , config = True ,
67
+ help = """Timeout for giving up on a kernel (in seconds).
68
+
69
+ On first connect and restart, the console tests whether the
70
+ kernel is running and responsive by sending kernel_info_requests.
71
+ This sets the timeout in seconds for how long the kernel can take
72
+ before being presumed dead.
73
+ """
74
+ )
51
75
52
76
def parse_command_line (self , argv = None ):
53
77
super (RunApp , self ).parse_command_line (argv )
@@ -56,32 +80,74 @@ def parse_command_line(self, argv=None):
56
80
57
81
@catch_config_error
58
82
def initialize (self , argv = None ):
83
+ self .log .debug ("jupyter run initialize..." )
59
84
super (RunApp , self ).initialize (argv )
60
85
JupyterConsoleApp .initialize (self )
61
86
signal .signal (signal .SIGINT , self .handle_sigint )
62
- self .shell = ZMQTerminalInteractiveShell .instance (parent = self ,
63
- manager = self .kernel_manager ,
64
- client = self .kernel_client ,
65
- )
66
- self .shell .own_kernel = not self .existing
87
+ self .init_kernel_info ()
67
88
68
89
def handle_sigint (self , * args ):
69
- if self .shell ._executing :
70
- if self .kernel_manager :
71
- self .kernel_manager .interrupt_kernel ()
72
- else :
73
- print ("" , file = sys .stderr )
74
- error ("Cannot interrupt kernels we didn't start.\n " )
90
+ if self .kernel_manager :
91
+ self .kernel_manager .interrupt_kernel ()
75
92
else :
76
- # raise the KeyboardInterrupt if we aren't waiting for execution,
77
- # so that the interact loop advances, and prompt is redrawn, etc.
78
- raise KeyboardInterrupt
93
+ print ("" , file = sys .stderr )
94
+ error ("Cannot interrupt kernels we didn't start.\n " )
95
+
96
+ def init_kernel_info (self ):
97
+ """Wait for a kernel to be ready, and store kernel info"""
98
+ timeout = self .kernel_timeout
99
+ tic = time .time ()
100
+ self .kernel_client .hb_channel .unpause ()
101
+ msg_id = self .kernel_client .kernel_info ()
102
+ while True :
103
+ try :
104
+ reply = self .kernel_client .get_shell_msg (timeout = 1 )
105
+ except queue .Empty :
106
+ if (time .time () - tic ) > timeout :
107
+ raise RuntimeError ("Kernel didn't respond to kernel_info_request" )
108
+ else :
109
+ if reply ['parent_header' ].get ('msg_id' ) == msg_id :
110
+ self .kernel_info = reply ['content' ]
111
+ return
79
112
80
113
def start (self ):
114
+ self .log .debug ("jupyter run start..." )
81
115
super (RunApp , self ).start ()
82
116
for filename in self .filenames_to_run :
117
+ self .log .debug ("jupyter run: running `%s`" % filename )
83
118
cell = open (filename ).read ()
84
- self .shell .run_cell (cell , False )
119
+ self .run_cell (cell )
120
+
121
+ def run_cell (self , cell ):
122
+ """
123
+ Run a cell on a KernelClient
124
+ Any output from the cell will be displayed.
125
+ """
126
+ msg_id = self .kernel_client .execute (cell )
127
+ while True :
128
+ try :
129
+ msg = self .kernel_client .get_iopub_msg (timeout = OUTPUT_TIMEOUT )
130
+ except queue .Empty :
131
+ raise TimeoutError ("Timeout waiting for kernel output" )
132
+
133
+ if msg ['parent_header' ].get ('msg_id' ) != msg_id :
134
+ continue
135
+ msg_type = msg ['header' ]['msg_type' ]
136
+ content = msg ['content' ]
137
+ if msg_type == 'status' :
138
+ if content ['execution_state' ] == 'idle' :
139
+ # idle means output is done
140
+ break
141
+ elif msg_type == 'stream' :
142
+ stream = getattr (sys , content ['name' ])
143
+ stream .write (content ['text' ])
144
+ elif msg_type in ('display_data' , 'execute_result' , 'error' ):
145
+ if msg_type == 'error' :
146
+ print ('\n ' .join (content ['traceback' ]), file = sys .stderr )
147
+ else :
148
+ sys .stdout .write (content ['data' ].get ('text/plain' , '' ))
149
+ else :
150
+ pass
85
151
86
152
main = launch_new_instance = RunApp .launch_instance
87
153
0 commit comments