##// END OF EJS Templates
Update production code to public names of raw_print functions.
Fernando Perez -
Show More
@@ -1,201 +1,201 b''
1 """ Defines helper functions for creating kernel entry points and process
1 """ Defines helper functions for creating kernel entry points and process
2 launchers.
2 launchers.
3 """
3 """
4
4
5 # Standard library imports.
5 # Standard library imports.
6 import os
6 import os
7 import socket
7 import socket
8 from subprocess import Popen
8 from subprocess import Popen
9 import sys
9 import sys
10
10
11 # System library imports.
11 # System library imports.
12 import zmq
12 import zmq
13
13
14 # Local imports.
14 # Local imports.
15 from IPython.core.ultratb import FormattedTB
15 from IPython.core.ultratb import FormattedTB
16 from IPython.external.argparse import ArgumentParser
16 from IPython.external.argparse import ArgumentParser
17 from IPython.utils import io
17 from IPython.utils import io
18 from exitpoller import ExitPollerUnix, ExitPollerWindows
18 from exitpoller import ExitPollerUnix, ExitPollerWindows
19 from displayhook import DisplayHook
19 from displayhook import DisplayHook
20 from iostream import OutStream
20 from iostream import OutStream
21 from session import Session
21 from session import Session
22
22
23
23
24 def bind_port(socket, ip, port):
24 def bind_port(socket, ip, port):
25 """ Binds the specified ZMQ socket. If the port is zero, a random port is
25 """ Binds the specified ZMQ socket. If the port is zero, a random port is
26 chosen. Returns the port that was bound.
26 chosen. Returns the port that was bound.
27 """
27 """
28 connection = 'tcp://%s' % ip
28 connection = 'tcp://%s' % ip
29 if port <= 0:
29 if port <= 0:
30 port = socket.bind_to_random_port(connection)
30 port = socket.bind_to_random_port(connection)
31 else:
31 else:
32 connection += ':%i' % port
32 connection += ':%i' % port
33 socket.bind(connection)
33 socket.bind(connection)
34 return port
34 return port
35
35
36
36
37 def make_argument_parser():
37 def make_argument_parser():
38 """ Creates an ArgumentParser for the generic arguments supported by all
38 """ Creates an ArgumentParser for the generic arguments supported by all
39 kernel entry points.
39 kernel entry points.
40 """
40 """
41 parser = ArgumentParser()
41 parser = ArgumentParser()
42 parser.add_argument('--ip', type=str, default='127.0.0.1',
42 parser.add_argument('--ip', type=str, default='127.0.0.1',
43 help='set the kernel\'s IP address [default: local]')
43 help='set the kernel\'s IP address [default: local]')
44 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
44 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
45 help='set the XREP channel port [default: random]')
45 help='set the XREP channel port [default: random]')
46 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
46 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
47 help='set the PUB channel port [default: random]')
47 help='set the PUB channel port [default: random]')
48 parser.add_argument('--req', type=int, metavar='PORT', default=0,
48 parser.add_argument('--req', type=int, metavar='PORT', default=0,
49 help='set the REQ channel port [default: random]')
49 help='set the REQ channel port [default: random]')
50
50
51 if sys.platform == 'win32':
51 if sys.platform == 'win32':
52 parser.add_argument('--parent', type=int, metavar='HANDLE',
52 parser.add_argument('--parent', type=int, metavar='HANDLE',
53 default=0, help='kill this process if the process '
53 default=0, help='kill this process if the process '
54 'with HANDLE dies')
54 'with HANDLE dies')
55 else:
55 else:
56 parser.add_argument('--parent', action='store_true',
56 parser.add_argument('--parent', action='store_true',
57 help='kill this process if its parent dies')
57 help='kill this process if its parent dies')
58
58
59 return parser
59 return parser
60
60
61
61
62 def make_kernel(namespace, kernel_factory,
62 def make_kernel(namespace, kernel_factory,
63 out_stream_factory=None, display_hook_factory=None):
63 out_stream_factory=None, display_hook_factory=None):
64 """ Creates a kernel.
64 """ Creates a kernel.
65 """
65 """
66 # Install minimal exception handling
66 # Install minimal exception handling
67 color_scheme = 'LightBG' if sys.platform == 'darwin' else 'Linux'
67 color_scheme = 'LightBG' if sys.platform == 'darwin' else 'Linux'
68 sys.excepthook = FormattedTB(
68 sys.excepthook = FormattedTB(
69 mode='Verbose', color_scheme=color_scheme, ostream=sys.__stdout__
69 mode='Verbose', color_scheme=color_scheme, ostream=sys.__stdout__
70 )
70 )
71
71
72 # Create a context, a session, and the kernel sockets.
72 # Create a context, a session, and the kernel sockets.
73 io.rprint("Starting the kernel...")
73 io.raw_print("Starting the kernel...")
74 context = zmq.Context()
74 context = zmq.Context()
75 session = Session(username=u'kernel')
75 session = Session(username=u'kernel')
76
76
77 reply_socket = context.socket(zmq.XREP)
77 reply_socket = context.socket(zmq.XREP)
78 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
78 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
79 io.rprint("XREP Channel on port", xrep_port)
79 io.raw_print("XREP Channel on port", xrep_port)
80
80
81 pub_socket = context.socket(zmq.PUB)
81 pub_socket = context.socket(zmq.PUB)
82 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
82 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
83 io.rprint("PUB Channel on port", pub_port)
83 io.raw_print("PUB Channel on port", pub_port)
84
84
85 req_socket = context.socket(zmq.XREQ)
85 req_socket = context.socket(zmq.XREQ)
86 req_port = bind_port(req_socket, namespace.ip, namespace.req)
86 req_port = bind_port(req_socket, namespace.ip, namespace.req)
87 io.rprint("REQ Channel on port", req_port)
87 io.raw_print("REQ Channel on port", req_port)
88
88
89 # Redirect input streams and set a display hook.
89 # Redirect input streams and set a display hook.
90 if out_stream_factory:
90 if out_stream_factory:
91 pass
91 pass
92 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
92 sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
93 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
93 sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
94 if display_hook_factory:
94 if display_hook_factory:
95 sys.displayhook = display_hook_factory(session, pub_socket)
95 sys.displayhook = display_hook_factory(session, pub_socket)
96
96
97 # Create the kernel.
97 # Create the kernel.
98 return kernel_factory(session=session, reply_socket=reply_socket,
98 return kernel_factory(session=session, reply_socket=reply_socket,
99 pub_socket=pub_socket, req_socket=req_socket)
99 pub_socket=pub_socket, req_socket=req_socket)
100
100
101
101
102 def start_kernel(namespace, kernel):
102 def start_kernel(namespace, kernel):
103 """ Starts a kernel.
103 """ Starts a kernel.
104 """
104 """
105 # Configure this kernel/process to die on parent termination, if necessary.
105 # Configure this kernel/process to die on parent termination, if necessary.
106 if namespace.parent:
106 if namespace.parent:
107 if sys.platform == 'win32':
107 if sys.platform == 'win32':
108 poller = ExitPollerWindows(namespace.parent)
108 poller = ExitPollerWindows(namespace.parent)
109 else:
109 else:
110 poller = ExitPollerUnix()
110 poller = ExitPollerUnix()
111 poller.start()
111 poller.start()
112
112
113 # Start the kernel mainloop.
113 # Start the kernel mainloop.
114 kernel.start()
114 kernel.start()
115
115
116
116
117 def make_default_main(kernel_factory):
117 def make_default_main(kernel_factory):
118 """ Creates the simplest possible kernel entry point.
118 """ Creates the simplest possible kernel entry point.
119 """
119 """
120 def main():
120 def main():
121 namespace = make_argument_parser().parse_args()
121 namespace = make_argument_parser().parse_args()
122 kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook)
122 kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook)
123 start_kernel(namespace, kernel)
123 start_kernel(namespace, kernel)
124 return main
124 return main
125
125
126
126
127 def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0,
127 def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0,
128 independent=False, extra_arguments=[]):
128 independent=False, extra_arguments=[]):
129 """ Launches a localhost kernel, binding to the specified ports.
129 """ Launches a localhost kernel, binding to the specified ports.
130
130
131 Parameters
131 Parameters
132 ----------
132 ----------
133 code : str,
133 code : str,
134 A string of Python code that imports and executes a kernel entry point.
134 A string of Python code that imports and executes a kernel entry point.
135
135
136 xrep_port : int, optional
136 xrep_port : int, optional
137 The port to use for XREP channel.
137 The port to use for XREP channel.
138
138
139 pub_port : int, optional
139 pub_port : int, optional
140 The port to use for the SUB channel.
140 The port to use for the SUB channel.
141
141
142 req_port : int, optional
142 req_port : int, optional
143 The port to use for the REQ (raw input) channel.
143 The port to use for the REQ (raw input) channel.
144
144
145 independent : bool, optional (default False)
145 independent : bool, optional (default False)
146 If set, the kernel process is guaranteed to survive if this process
146 If set, the kernel process is guaranteed to survive if this process
147 dies. If not set, an effort is made to ensure that the kernel is killed
147 dies. If not set, an effort is made to ensure that the kernel is killed
148 when this process dies. Note that in this case it is still good practice
148 when this process dies. Note that in this case it is still good practice
149 to kill kernels manually before exiting.
149 to kill kernels manually before exiting.
150
150
151 extra_arguments = list, optional
151 extra_arguments = list, optional
152 A list of extra arguments to pass when executing the launch code.
152 A list of extra arguments to pass when executing the launch code.
153
153
154 Returns
154 Returns
155 -------
155 -------
156 A tuple of form:
156 A tuple of form:
157 (kernel_process, xrep_port, pub_port, req_port)
157 (kernel_process, xrep_port, pub_port, req_port)
158 where kernel_process is a Popen object and the ports are integers.
158 where kernel_process is a Popen object and the ports are integers.
159 """
159 """
160 # Find open ports as necessary.
160 # Find open ports as necessary.
161 ports = []
161 ports = []
162 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
162 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
163 for i in xrange(ports_needed):
163 for i in xrange(ports_needed):
164 sock = socket.socket()
164 sock = socket.socket()
165 sock.bind(('', 0))
165 sock.bind(('', 0))
166 ports.append(sock)
166 ports.append(sock)
167 for i, sock in enumerate(ports):
167 for i, sock in enumerate(ports):
168 port = sock.getsockname()[1]
168 port = sock.getsockname()[1]
169 sock.close()
169 sock.close()
170 ports[i] = port
170 ports[i] = port
171 if xrep_port <= 0:
171 if xrep_port <= 0:
172 xrep_port = ports.pop(0)
172 xrep_port = ports.pop(0)
173 if pub_port <= 0:
173 if pub_port <= 0:
174 pub_port = ports.pop(0)
174 pub_port = ports.pop(0)
175 if req_port <= 0:
175 if req_port <= 0:
176 req_port = ports.pop(0)
176 req_port = ports.pop(0)
177
177
178 # Build the kernel launch command.
178 # Build the kernel launch command.
179 arguments = [ sys.executable, '-c', code, '--xrep', str(xrep_port),
179 arguments = [ sys.executable, '-c', code, '--xrep', str(xrep_port),
180 '--pub', str(pub_port), '--req', str(req_port) ]
180 '--pub', str(pub_port), '--req', str(req_port) ]
181 arguments.extend(extra_arguments)
181 arguments.extend(extra_arguments)
182
182
183 # Spawn a kernel.
183 # Spawn a kernel.
184 if independent:
184 if independent:
185 if sys.platform == 'win32':
185 if sys.platform == 'win32':
186 proc = Popen(['start', '/b'] + arguments, shell=True)
186 proc = Popen(['start', '/b'] + arguments, shell=True)
187 else:
187 else:
188 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
188 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
189 else:
189 else:
190 if sys.platform == 'win32':
190 if sys.platform == 'win32':
191 from _subprocess import DuplicateHandle, GetCurrentProcess, \
191 from _subprocess import DuplicateHandle, GetCurrentProcess, \
192 DUPLICATE_SAME_ACCESS
192 DUPLICATE_SAME_ACCESS
193 pid = GetCurrentProcess()
193 pid = GetCurrentProcess()
194 handle = DuplicateHandle(pid, pid, pid, 0,
194 handle = DuplicateHandle(pid, pid, pid, 0,
195 True, # Inheritable by new processes.
195 True, # Inheritable by new processes.
196 DUPLICATE_SAME_ACCESS)
196 DUPLICATE_SAME_ACCESS)
197 proc = Popen(arguments + ['--parent', str(int(handle))])
197 proc = Popen(arguments + ['--parent', str(int(handle))])
198 else:
198 else:
199 proc = Popen(arguments + ['--parent'])
199 proc = Popen(arguments + ['--parent'])
200
200
201 return proc, xrep_port, pub_port, req_port
201 return proc, xrep_port, pub_port, req_port
@@ -1,456 +1,456 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Standard library imports.
18 # Standard library imports.
19 import __builtin__
19 import __builtin__
20 import sys
20 import sys
21 import time
21 import time
22 import traceback
22 import traceback
23
23
24 # System library imports.
24 # System library imports.
25 import zmq
25 import zmq
26
26
27 # Local imports.
27 # Local imports.
28 from IPython.config.configurable import Configurable
28 from IPython.config.configurable import Configurable
29 from IPython.utils import io
29 from IPython.utils import io
30 from IPython.lib import pylabtools
30 from IPython.lib import pylabtools
31 from IPython.utils.traitlets import Instance
31 from IPython.utils.traitlets import Instance
32 from entry_point import base_launch_kernel, make_argument_parser, make_kernel, \
32 from entry_point import base_launch_kernel, make_argument_parser, make_kernel, \
33 start_kernel
33 start_kernel
34 from iostream import OutStream
34 from iostream import OutStream
35 from session import Session, Message
35 from session import Session, Message
36 from zmqshell import ZMQInteractiveShell
36 from zmqshell import ZMQInteractiveShell
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Main kernel class
39 # Main kernel class
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 class Kernel(Configurable):
42 class Kernel(Configurable):
43
43
44 #---------------------------------------------------------------------------
44 #---------------------------------------------------------------------------
45 # Kernel interface
45 # Kernel interface
46 #---------------------------------------------------------------------------
46 #---------------------------------------------------------------------------
47
47
48 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
48 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
49 session = Instance(Session)
49 session = Instance(Session)
50 reply_socket = Instance('zmq.Socket')
50 reply_socket = Instance('zmq.Socket')
51 pub_socket = Instance('zmq.Socket')
51 pub_socket = Instance('zmq.Socket')
52 req_socket = Instance('zmq.Socket')
52 req_socket = Instance('zmq.Socket')
53
53
54 def __init__(self, **kwargs):
54 def __init__(self, **kwargs):
55 super(Kernel, self).__init__(**kwargs)
55 super(Kernel, self).__init__(**kwargs)
56
56
57 # Initialize the InteractiveShell subclass
57 # Initialize the InteractiveShell subclass
58 self.shell = ZMQInteractiveShell.instance()
58 self.shell = ZMQInteractiveShell.instance()
59 self.shell.displayhook.session = self.session
59 self.shell.displayhook.session = self.session
60 self.shell.displayhook.pub_socket = self.pub_socket
60 self.shell.displayhook.pub_socket = self.pub_socket
61
61
62 # TMP - hack while developing
62 # TMP - hack while developing
63 self.shell._reply_content = None
63 self.shell._reply_content = None
64
64
65 # Build dict of handlers for message types
65 # Build dict of handlers for message types
66 msg_types = [ 'execute_request', 'complete_request',
66 msg_types = [ 'execute_request', 'complete_request',
67 'object_info_request', 'prompt_request',
67 'object_info_request', 'prompt_request',
68 'history_request' ]
68 'history_request' ]
69 self.handlers = {}
69 self.handlers = {}
70 for msg_type in msg_types:
70 for msg_type in msg_types:
71 self.handlers[msg_type] = getattr(self, msg_type)
71 self.handlers[msg_type] = getattr(self, msg_type)
72
72
73 def do_one_iteration(self):
73 def do_one_iteration(self):
74 try:
74 try:
75 ident = self.reply_socket.recv(zmq.NOBLOCK)
75 ident = self.reply_socket.recv(zmq.NOBLOCK)
76 except zmq.ZMQError, e:
76 except zmq.ZMQError, e:
77 if e.errno == zmq.EAGAIN:
77 if e.errno == zmq.EAGAIN:
78 return
78 return
79 else:
79 else:
80 raise
80 raise
81 # FIXME: Bug in pyzmq/zmq?
81 # FIXME: Bug in pyzmq/zmq?
82 # assert self.reply_socket.rcvmore(), "Missing message part."
82 # assert self.reply_socket.rcvmore(), "Missing message part."
83 msg = self.reply_socket.recv_json()
83 msg = self.reply_socket.recv_json()
84 omsg = Message(msg)
84 omsg = Message(msg)
85 io.rprint('\n')
85 io.raw_print('\n')
86 io.rprint(omsg)
86 io.raw_print(omsg)
87 handler = self.handlers.get(omsg.msg_type, None)
87 handler = self.handlers.get(omsg.msg_type, None)
88 if handler is None:
88 if handler is None:
89 io.rprinte("UNKNOWN MESSAGE TYPE:", omsg)
89 io.raw_print_err("UNKNOWN MESSAGE TYPE:", omsg)
90 else:
90 else:
91 handler(ident, omsg)
91 handler(ident, omsg)
92
92
93 def start(self):
93 def start(self):
94 """ Start the kernel main loop.
94 """ Start the kernel main loop.
95 """
95 """
96 while True:
96 while True:
97 time.sleep(0.05)
97 time.sleep(0.05)
98 self.do_one_iteration()
98 self.do_one_iteration()
99
99
100
100
101 #---------------------------------------------------------------------------
101 #---------------------------------------------------------------------------
102 # Kernel request handlers
102 # Kernel request handlers
103 #---------------------------------------------------------------------------
103 #---------------------------------------------------------------------------
104
104
105 def execute_request(self, ident, parent):
105 def execute_request(self, ident, parent):
106 try:
106 try:
107 code = parent[u'content'][u'code']
107 code = parent[u'content'][u'code']
108 except:
108 except:
109 io.rprinte("Got bad msg: ")
109 io.raw_print_err("Got bad msg: ")
110 io.rprinte(Message(parent))
110 io.raw_print_err(Message(parent))
111 return
111 return
112 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
112 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
113 self.pub_socket.send_json(pyin_msg)
113 self.pub_socket.send_json(pyin_msg)
114
114
115 try:
115 try:
116 # Replace raw_input. Note that is not sufficient to replace
116 # Replace raw_input. Note that is not sufficient to replace
117 # raw_input in the user namespace.
117 # raw_input in the user namespace.
118 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
118 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
119 __builtin__.raw_input = raw_input
119 __builtin__.raw_input = raw_input
120
120
121 # Set the parent message of the display hook and out streams.
121 # Set the parent message of the display hook and out streams.
122 self.shell.displayhook.set_parent(parent)
122 self.shell.displayhook.set_parent(parent)
123 sys.stdout.set_parent(parent)
123 sys.stdout.set_parent(parent)
124 sys.stderr.set_parent(parent)
124 sys.stderr.set_parent(parent)
125
125
126 # FIXME: runlines calls the exception handler itself. We should
126 # FIXME: runlines calls the exception handler itself. We should
127 # clean this up.
127 # clean this up.
128 self.shell._reply_content = None
128 self.shell._reply_content = None
129 self.shell.runlines(code)
129 self.shell.runlines(code)
130 except:
130 except:
131 # FIXME: this code right now isn't being used yet by default,
131 # FIXME: this code right now isn't being used yet by default,
132 # because the runlines() call above directly fires off exception
132 # because the runlines() call above directly fires off exception
133 # reporting. This code, therefore, is only active in the scenario
133 # reporting. This code, therefore, is only active in the scenario
134 # where runlines itself has an unhandled exception. We need to
134 # where runlines itself has an unhandled exception. We need to
135 # uniformize this, for all exception construction to come from a
135 # uniformize this, for all exception construction to come from a
136 # single location in the codbase.
136 # single location in the codbase.
137 etype, evalue, tb = sys.exc_info()
137 etype, evalue, tb = sys.exc_info()
138 tb_list = traceback.format_exception(etype, evalue, tb)
138 tb_list = traceback.format_exception(etype, evalue, tb)
139 reply_content = self.shell._showtraceback(etype, evalue, tb_list)
139 reply_content = self.shell._showtraceback(etype, evalue, tb_list)
140 else:
140 else:
141 payload = self.shell.payload_manager.read_payload()
141 payload = self.shell.payload_manager.read_payload()
142 # Be agressive about clearing the payload because we don't want
142 # Be agressive about clearing the payload because we don't want
143 # it to sit in memory until the next execute_request comes in.
143 # it to sit in memory until the next execute_request comes in.
144 self.shell.payload_manager.clear_payload()
144 self.shell.payload_manager.clear_payload()
145 reply_content = { 'status' : 'ok', 'payload' : payload }
145 reply_content = { 'status' : 'ok', 'payload' : payload }
146
146
147 # Compute the prompt information
147 # Compute the prompt information
148 prompt_number = self.shell.displayhook.prompt_count
148 prompt_number = self.shell.displayhook.prompt_count
149 reply_content['prompt_number'] = prompt_number
149 reply_content['prompt_number'] = prompt_number
150 prompt_string = self.shell.displayhook.prompt1.peek_next_prompt()
150 prompt_string = self.shell.displayhook.prompt1.peek_next_prompt()
151 next_prompt = {'prompt_string' : prompt_string,
151 next_prompt = {'prompt_string' : prompt_string,
152 'prompt_number' : prompt_number+1,
152 'prompt_number' : prompt_number+1,
153 'input_sep' : self.shell.displayhook.input_sep}
153 'input_sep' : self.shell.displayhook.input_sep}
154 reply_content['next_prompt'] = next_prompt
154 reply_content['next_prompt'] = next_prompt
155
155
156 # TMP - fish exception info out of shell, possibly left there by
156 # TMP - fish exception info out of shell, possibly left there by
157 # runlines
157 # runlines
158 if self.shell._reply_content is not None:
158 if self.shell._reply_content is not None:
159 reply_content.update(self.shell._reply_content)
159 reply_content.update(self.shell._reply_content)
160
160
161 # Flush output before sending the reply.
161 # Flush output before sending the reply.
162 sys.stderr.flush()
162 sys.stderr.flush()
163 sys.stdout.flush()
163 sys.stdout.flush()
164
164
165 # Send the reply.
165 # Send the reply.
166 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
166 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
167 io.rprint(Message(reply_msg))
167 io.raw_print(Message(reply_msg))
168 self.reply_socket.send(ident, zmq.SNDMORE)
168 self.reply_socket.send(ident, zmq.SNDMORE)
169 self.reply_socket.send_json(reply_msg)
169 self.reply_socket.send_json(reply_msg)
170 if reply_msg['content']['status'] == u'error':
170 if reply_msg['content']['status'] == u'error':
171 self._abort_queue()
171 self._abort_queue()
172
172
173 def complete_request(self, ident, parent):
173 def complete_request(self, ident, parent):
174 txt, matches = self._complete(parent)
174 txt, matches = self._complete(parent)
175 matches = {'matches' : matches,
175 matches = {'matches' : matches,
176 'matched_text' : txt,
176 'matched_text' : txt,
177 'status' : 'ok'}
177 'status' : 'ok'}
178 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
178 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
179 matches, parent, ident)
179 matches, parent, ident)
180 io.rprint(completion_msg)
180 io.raw_print(completion_msg)
181
181
182 def object_info_request(self, ident, parent):
182 def object_info_request(self, ident, parent):
183 context = parent['content']['oname'].split('.')
183 context = parent['content']['oname'].split('.')
184 object_info = self._object_info(context)
184 object_info = self._object_info(context)
185 msg = self.session.send(self.reply_socket, 'object_info_reply',
185 msg = self.session.send(self.reply_socket, 'object_info_reply',
186 object_info, parent, ident)
186 object_info, parent, ident)
187 io.rprint(msg)
187 io.raw_print(msg)
188
188
189 def prompt_request(self, ident, parent):
189 def prompt_request(self, ident, parent):
190 prompt_number = self.shell.displayhook.prompt_count
190 prompt_number = self.shell.displayhook.prompt_count
191 prompt_string = self.shell.displayhook.prompt1.peek_next_prompt()
191 prompt_string = self.shell.displayhook.prompt1.peek_next_prompt()
192 content = {'prompt_string' : prompt_string,
192 content = {'prompt_string' : prompt_string,
193 'prompt_number' : prompt_number+1,
193 'prompt_number' : prompt_number+1,
194 'input_sep' : self.shell.displayhook.input_sep}
194 'input_sep' : self.shell.displayhook.input_sep}
195 msg = self.session.send(self.reply_socket, 'prompt_reply',
195 msg = self.session.send(self.reply_socket, 'prompt_reply',
196 content, parent, ident)
196 content, parent, ident)
197 io.rprint(msg)
197 io.raw_print(msg)
198
198
199 def history_request(self, ident, parent):
199 def history_request(self, ident, parent):
200 output = parent['content']['output']
200 output = parent['content']['output']
201 index = parent['content']['index']
201 index = parent['content']['index']
202 raw = parent['content']['raw']
202 raw = parent['content']['raw']
203 hist = self.shell.get_history(index=index, raw=raw, output=output)
203 hist = self.shell.get_history(index=index, raw=raw, output=output)
204 content = {'history' : hist}
204 content = {'history' : hist}
205 msg = self.session.send(self.reply_socket, 'history_reply',
205 msg = self.session.send(self.reply_socket, 'history_reply',
206 content, parent, ident)
206 content, parent, ident)
207 io.rprint(msg)
207 io.raw_print(msg)
208
208
209 #---------------------------------------------------------------------------
209 #---------------------------------------------------------------------------
210 # Protected interface
210 # Protected interface
211 #---------------------------------------------------------------------------
211 #---------------------------------------------------------------------------
212
212
213 def _abort_queue(self):
213 def _abort_queue(self):
214 while True:
214 while True:
215 try:
215 try:
216 ident = self.reply_socket.recv(zmq.NOBLOCK)
216 ident = self.reply_socket.recv(zmq.NOBLOCK)
217 except zmq.ZMQError, e:
217 except zmq.ZMQError, e:
218 if e.errno == zmq.EAGAIN:
218 if e.errno == zmq.EAGAIN:
219 break
219 break
220 else:
220 else:
221 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
221 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
222 msg = self.reply_socket.recv_json()
222 msg = self.reply_socket.recv_json()
223 io.rprint("Aborting:\n", Message(msg))
223 io.raw_print("Aborting:\n", Message(msg))
224 msg_type = msg['msg_type']
224 msg_type = msg['msg_type']
225 reply_type = msg_type.split('_')[0] + '_reply'
225 reply_type = msg_type.split('_')[0] + '_reply'
226 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
226 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
227 io.rprint(Message(reply_msg))
227 io.raw_print(Message(reply_msg))
228 self.reply_socket.send(ident,zmq.SNDMORE)
228 self.reply_socket.send(ident,zmq.SNDMORE)
229 self.reply_socket.send_json(reply_msg)
229 self.reply_socket.send_json(reply_msg)
230 # We need to wait a bit for requests to come in. This can probably
230 # We need to wait a bit for requests to come in. This can probably
231 # be set shorter for true asynchronous clients.
231 # be set shorter for true asynchronous clients.
232 time.sleep(0.1)
232 time.sleep(0.1)
233
233
234 def _raw_input(self, prompt, ident, parent):
234 def _raw_input(self, prompt, ident, parent):
235 # Flush output before making the request.
235 # Flush output before making the request.
236 sys.stderr.flush()
236 sys.stderr.flush()
237 sys.stdout.flush()
237 sys.stdout.flush()
238
238
239 # Send the input request.
239 # Send the input request.
240 content = dict(prompt=prompt)
240 content = dict(prompt=prompt)
241 msg = self.session.msg(u'input_request', content, parent)
241 msg = self.session.msg(u'input_request', content, parent)
242 self.req_socket.send_json(msg)
242 self.req_socket.send_json(msg)
243
243
244 # Await a response.
244 # Await a response.
245 reply = self.req_socket.recv_json()
245 reply = self.req_socket.recv_json()
246 try:
246 try:
247 value = reply['content']['value']
247 value = reply['content']['value']
248 except:
248 except:
249 io.rprinte("Got bad raw_input reply: ")
249 io.raw_print_err("Got bad raw_input reply: ")
250 io.rprinte(Message(parent))
250 io.raw_print_err(Message(parent))
251 value = ''
251 value = ''
252 return value
252 return value
253
253
254 def _complete(self, msg):
254 def _complete(self, msg):
255 c = msg['content']
255 c = msg['content']
256 try:
256 try:
257 cpos = int(c['cursor_pos'])
257 cpos = int(c['cursor_pos'])
258 except:
258 except:
259 # If we don't get something that we can convert to an integer, at
259 # If we don't get something that we can convert to an integer, at
260 # least attempt the completion guessing the cursor is at the end of
260 # least attempt the completion guessing the cursor is at the end of
261 # the text, if there's any, and otherwise of the line
261 # the text, if there's any, and otherwise of the line
262 cpos = len(c['text'])
262 cpos = len(c['text'])
263 if cpos==0:
263 if cpos==0:
264 cpos = len(c['line'])
264 cpos = len(c['line'])
265 return self.shell.complete(c['text'], c['line'], cpos)
265 return self.shell.complete(c['text'], c['line'], cpos)
266
266
267 def _object_info(self, context):
267 def _object_info(self, context):
268 symbol, leftover = self._symbol_from_context(context)
268 symbol, leftover = self._symbol_from_context(context)
269 if symbol is not None and not leftover:
269 if symbol is not None and not leftover:
270 doc = getattr(symbol, '__doc__', '')
270 doc = getattr(symbol, '__doc__', '')
271 else:
271 else:
272 doc = ''
272 doc = ''
273 object_info = dict(docstring = doc)
273 object_info = dict(docstring = doc)
274 return object_info
274 return object_info
275
275
276 def _symbol_from_context(self, context):
276 def _symbol_from_context(self, context):
277 if not context:
277 if not context:
278 return None, context
278 return None, context
279
279
280 base_symbol_string = context[0]
280 base_symbol_string = context[0]
281 symbol = self.shell.user_ns.get(base_symbol_string, None)
281 symbol = self.shell.user_ns.get(base_symbol_string, None)
282 if symbol is None:
282 if symbol is None:
283 symbol = __builtin__.__dict__.get(base_symbol_string, None)
283 symbol = __builtin__.__dict__.get(base_symbol_string, None)
284 if symbol is None:
284 if symbol is None:
285 return None, context
285 return None, context
286
286
287 context = context[1:]
287 context = context[1:]
288 for i, name in enumerate(context):
288 for i, name in enumerate(context):
289 new_symbol = getattr(symbol, name, None)
289 new_symbol = getattr(symbol, name, None)
290 if new_symbol is None:
290 if new_symbol is None:
291 return symbol, context[i:]
291 return symbol, context[i:]
292 else:
292 else:
293 symbol = new_symbol
293 symbol = new_symbol
294
294
295 return symbol, []
295 return symbol, []
296
296
297
297
298 class QtKernel(Kernel):
298 class QtKernel(Kernel):
299 """A Kernel subclass with Qt support."""
299 """A Kernel subclass with Qt support."""
300
300
301 def start(self):
301 def start(self):
302 """Start a kernel with QtPy4 event loop integration."""
302 """Start a kernel with QtPy4 event loop integration."""
303
303
304 from PyQt4 import QtGui, QtCore
304 from PyQt4 import QtGui, QtCore
305 self.app = QtGui.QApplication([])
305 self.app = QtGui.QApplication([])
306 self.app.setQuitOnLastWindowClosed (False)
306 self.app.setQuitOnLastWindowClosed (False)
307 self.timer = QtCore.QTimer()
307 self.timer = QtCore.QTimer()
308 self.timer.timeout.connect(self.do_one_iteration)
308 self.timer.timeout.connect(self.do_one_iteration)
309 self.timer.start(50)
309 self.timer.start(50)
310 self.app.exec_()
310 self.app.exec_()
311
311
312
312
313 class WxKernel(Kernel):
313 class WxKernel(Kernel):
314 """A Kernel subclass with Wx support."""
314 """A Kernel subclass with Wx support."""
315
315
316 def start(self):
316 def start(self):
317 """Start a kernel with wx event loop support."""
317 """Start a kernel with wx event loop support."""
318
318
319 import wx
319 import wx
320 doi = self.do_one_iteration
320 doi = self.do_one_iteration
321
321
322 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
322 # We have to put the wx.Timer in a wx.Frame for it to fire properly.
323 # We make the Frame hidden when we create it in the main app below.
323 # We make the Frame hidden when we create it in the main app below.
324 class TimerFrame(wx.Frame):
324 class TimerFrame(wx.Frame):
325 def __init__(self, func):
325 def __init__(self, func):
326 wx.Frame.__init__(self, None, -1)
326 wx.Frame.__init__(self, None, -1)
327 self.timer = wx.Timer(self)
327 self.timer = wx.Timer(self)
328 self.timer.Start(50)
328 self.timer.Start(50)
329 self.Bind(wx.EVT_TIMER, self.on_timer)
329 self.Bind(wx.EVT_TIMER, self.on_timer)
330 self.func = func
330 self.func = func
331 def on_timer(self, event):
331 def on_timer(self, event):
332 self.func()
332 self.func()
333
333
334 # We need a custom wx.App to create our Frame subclass that has the
334 # We need a custom wx.App to create our Frame subclass that has the
335 # wx.Timer to drive the ZMQ event loop.
335 # wx.Timer to drive the ZMQ event loop.
336 class IPWxApp(wx.App):
336 class IPWxApp(wx.App):
337 def OnInit(self):
337 def OnInit(self):
338 self.frame = TimerFrame(doi)
338 self.frame = TimerFrame(doi)
339 self.frame.Show(False)
339 self.frame.Show(False)
340 return True
340 return True
341
341
342 # The redirect=False here makes sure that wx doesn't replace
342 # The redirect=False here makes sure that wx doesn't replace
343 # sys.stdout/stderr with its own classes.
343 # sys.stdout/stderr with its own classes.
344 self.app = IPWxApp(redirect=False)
344 self.app = IPWxApp(redirect=False)
345 self.app.MainLoop()
345 self.app.MainLoop()
346
346
347
347
348 class TkKernel(Kernel):
348 class TkKernel(Kernel):
349 """A Kernel subclass with Tk support."""
349 """A Kernel subclass with Tk support."""
350
350
351 def start(self):
351 def start(self):
352 """Start a Tk enabled event loop."""
352 """Start a Tk enabled event loop."""
353
353
354 import Tkinter
354 import Tkinter
355 doi = self.do_one_iteration
355 doi = self.do_one_iteration
356
356
357 # For Tkinter, we create a Tk object and call its withdraw method.
357 # For Tkinter, we create a Tk object and call its withdraw method.
358 class Timer(object):
358 class Timer(object):
359 def __init__(self, func):
359 def __init__(self, func):
360 self.app = Tkinter.Tk()
360 self.app = Tkinter.Tk()
361 self.app.withdraw()
361 self.app.withdraw()
362 self.func = func
362 self.func = func
363 def on_timer(self):
363 def on_timer(self):
364 self.func()
364 self.func()
365 self.app.after(50, self.on_timer)
365 self.app.after(50, self.on_timer)
366 def start(self):
366 def start(self):
367 self.on_timer() # Call it once to get things going.
367 self.on_timer() # Call it once to get things going.
368 self.app.mainloop()
368 self.app.mainloop()
369
369
370 self.timer = Timer(doi)
370 self.timer = Timer(doi)
371 self.timer.start()
371 self.timer.start()
372
372
373 #-----------------------------------------------------------------------------
373 #-----------------------------------------------------------------------------
374 # Kernel main and launch functions
374 # Kernel main and launch functions
375 #-----------------------------------------------------------------------------
375 #-----------------------------------------------------------------------------
376
376
377 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False,
377 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False,
378 pylab=False):
378 pylab=False):
379 """ Launches a localhost kernel, binding to the specified ports.
379 """ Launches a localhost kernel, binding to the specified ports.
380
380
381 Parameters
381 Parameters
382 ----------
382 ----------
383 xrep_port : int, optional
383 xrep_port : int, optional
384 The port to use for XREP channel.
384 The port to use for XREP channel.
385
385
386 pub_port : int, optional
386 pub_port : int, optional
387 The port to use for the SUB channel.
387 The port to use for the SUB channel.
388
388
389 req_port : int, optional
389 req_port : int, optional
390 The port to use for the REQ (raw input) channel.
390 The port to use for the REQ (raw input) channel.
391
391
392 independent : bool, optional (default False)
392 independent : bool, optional (default False)
393 If set, the kernel process is guaranteed to survive if this process
393 If set, the kernel process is guaranteed to survive if this process
394 dies. If not set, an effort is made to ensure that the kernel is killed
394 dies. If not set, an effort is made to ensure that the kernel is killed
395 when this process dies. Note that in this case it is still good practice
395 when this process dies. Note that in this case it is still good practice
396 to kill kernels manually before exiting.
396 to kill kernels manually before exiting.
397
397
398 pylab : bool or string, optional (default False)
398 pylab : bool or string, optional (default False)
399 If not False, the kernel will be launched with pylab enabled. If a
399 If not False, the kernel will be launched with pylab enabled. If a
400 string is passed, matplotlib will use the specified backend. Otherwise,
400 string is passed, matplotlib will use the specified backend. Otherwise,
401 matplotlib's default backend will be used.
401 matplotlib's default backend will be used.
402
402
403 Returns
403 Returns
404 -------
404 -------
405 A tuple of form:
405 A tuple of form:
406 (kernel_process, xrep_port, pub_port, req_port)
406 (kernel_process, xrep_port, pub_port, req_port)
407 where kernel_process is a Popen object and the ports are integers.
407 where kernel_process is a Popen object and the ports are integers.
408 """
408 """
409 extra_arguments = []
409 extra_arguments = []
410 if pylab:
410 if pylab:
411 extra_arguments.append('--pylab')
411 extra_arguments.append('--pylab')
412 if isinstance(pylab, basestring):
412 if isinstance(pylab, basestring):
413 extra_arguments.append(pylab)
413 extra_arguments.append(pylab)
414 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
414 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
415 xrep_port, pub_port, req_port, independent,
415 xrep_port, pub_port, req_port, independent,
416 extra_arguments)
416 extra_arguments)
417
417
418 def main():
418 def main():
419 """ The IPython kernel main entry point.
419 """ The IPython kernel main entry point.
420 """
420 """
421 parser = make_argument_parser()
421 parser = make_argument_parser()
422 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
422 parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
423 const='auto', help = \
423 const='auto', help = \
424 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
424 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
425 given, the GUI backend is matplotlib's, otherwise use one of: \
425 given, the GUI backend is matplotlib's, otherwise use one of: \
426 ['tk', 'gtk', 'qt', 'wx', 'payload-svg'].")
426 ['tk', 'gtk', 'qt', 'wx', 'payload-svg'].")
427 namespace = parser.parse_args()
427 namespace = parser.parse_args()
428
428
429 kernel_class = Kernel
429 kernel_class = Kernel
430
430
431 _kernel_classes = {
431 _kernel_classes = {
432 'qt' : QtKernel,
432 'qt' : QtKernel,
433 'qt4' : QtKernel,
433 'qt4' : QtKernel,
434 'payload-svg':Kernel,
434 'payload-svg':Kernel,
435 'wx' : WxKernel,
435 'wx' : WxKernel,
436 'tk' : TkKernel
436 'tk' : TkKernel
437 }
437 }
438 if namespace.pylab:
438 if namespace.pylab:
439 if namespace.pylab == 'auto':
439 if namespace.pylab == 'auto':
440 gui, backend = pylabtools.find_gui_and_backend()
440 gui, backend = pylabtools.find_gui_and_backend()
441 else:
441 else:
442 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
442 gui, backend = pylabtools.find_gui_and_backend(namespace.pylab)
443 kernel_class = _kernel_classes.get(gui)
443 kernel_class = _kernel_classes.get(gui)
444 if kernel_class is None:
444 if kernel_class is None:
445 raise ValueError('GUI is not supported: %r' % gui)
445 raise ValueError('GUI is not supported: %r' % gui)
446 pylabtools.activate_matplotlib(backend)
446 pylabtools.activate_matplotlib(backend)
447
447
448 kernel = make_kernel(namespace, kernel_class, OutStream)
448 kernel = make_kernel(namespace, kernel_class, OutStream)
449
449
450 if namespace.pylab:
450 if namespace.pylab:
451 pylabtools.import_pylab(kernel.shell.user_ns)
451 pylabtools.import_pylab(kernel.shell.user_ns)
452
452
453 start_kernel(namespace, kernel)
453 start_kernel(namespace, kernel)
454
454
455 if __name__ == '__main__':
455 if __name__ == '__main__':
456 main()
456 main()
@@ -1,389 +1,388 b''
1 import inspect
1 import inspect
2 import re
2 import re
3 import sys
3 import sys
4 from subprocess import Popen, PIPE
4 from subprocess import Popen, PIPE
5
5
6 from IPython.core.interactiveshell import (
6 from IPython.core.interactiveshell import (
7 InteractiveShell, InteractiveShellABC
7 InteractiveShell, InteractiveShellABC
8 )
8 )
9 from IPython.core.displayhook import DisplayHook
9 from IPython.core.displayhook import DisplayHook
10 from IPython.core.macro import Macro
10 from IPython.core.macro import Macro
11 from IPython.utils.io import rprint
12 from IPython.utils.path import get_py_filename
11 from IPython.utils.path import get_py_filename
13 from IPython.utils.text import StringTypes
12 from IPython.utils.text import StringTypes
14 from IPython.utils.traitlets import Instance, Type, Dict
13 from IPython.utils.traitlets import Instance, Type, Dict
15 from IPython.utils.warn import warn
14 from IPython.utils.warn import warn
16 from IPython.zmq.session import extract_header
15 from IPython.zmq.session import extract_header
17 from IPython.core.payloadpage import install_payload_page
16 from IPython.core.payloadpage import install_payload_page
18 from session import Session
17 from session import Session
19
18
20 # Install the payload version of page.
19 # Install the payload version of page.
21 install_payload_page()
20 install_payload_page()
22
21
23
22
24 class ZMQDisplayHook(DisplayHook):
23 class ZMQDisplayHook(DisplayHook):
25
24
26 session = Instance(Session)
25 session = Instance(Session)
27 pub_socket = Instance('zmq.Socket')
26 pub_socket = Instance('zmq.Socket')
28 parent_header = Dict({})
27 parent_header = Dict({})
29
28
30 def set_parent(self, parent):
29 def set_parent(self, parent):
31 """Set the parent for outbound messages."""
30 """Set the parent for outbound messages."""
32 self.parent_header = extract_header(parent)
31 self.parent_header = extract_header(parent)
33
32
34 def start_displayhook(self):
33 def start_displayhook(self):
35 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
34 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
36
35
37 def write_output_prompt(self):
36 def write_output_prompt(self):
38 """Write the output prompt."""
37 """Write the output prompt."""
39 if self.do_full_cache:
38 if self.do_full_cache:
40 self.msg['content']['output_sep'] = self.output_sep
39 self.msg['content']['output_sep'] = self.output_sep
41 self.msg['content']['prompt_string'] = str(self.prompt_out)
40 self.msg['content']['prompt_string'] = str(self.prompt_out)
42 self.msg['content']['prompt_number'] = self.prompt_count
41 self.msg['content']['prompt_number'] = self.prompt_count
43 self.msg['content']['output_sep2'] = self.output_sep2
42 self.msg['content']['output_sep2'] = self.output_sep2
44
43
45 def write_result_repr(self, result_repr):
44 def write_result_repr(self, result_repr):
46 self.msg['content']['data'] = result_repr
45 self.msg['content']['data'] = result_repr
47
46
48 def finish_displayhook(self):
47 def finish_displayhook(self):
49 """Finish up all displayhook activities."""
48 """Finish up all displayhook activities."""
50 self.pub_socket.send_json(self.msg)
49 self.pub_socket.send_json(self.msg)
51 self.msg = None
50 self.msg = None
52
51
53
52
54 class ZMQInteractiveShell(InteractiveShell):
53 class ZMQInteractiveShell(InteractiveShell):
55 """A subclass of InteractiveShell for ZMQ."""
54 """A subclass of InteractiveShell for ZMQ."""
56
55
57 displayhook_class = Type(ZMQDisplayHook)
56 displayhook_class = Type(ZMQDisplayHook)
58
57
59 def system(self, cmd):
58 def system(self, cmd):
60 cmd = self.var_expand(cmd, depth=2)
59 cmd = self.var_expand(cmd, depth=2)
61 sys.stdout.flush()
60 sys.stdout.flush()
62 sys.stderr.flush()
61 sys.stderr.flush()
63 p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
62 p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
64 for line in p.stdout.read().split('\n'):
63 for line in p.stdout.read().split('\n'):
65 if len(line) > 0:
64 if len(line) > 0:
66 print line
65 print line
67 for line in p.stderr.read().split('\n'):
66 for line in p.stderr.read().split('\n'):
68 if len(line) > 0:
67 if len(line) > 0:
69 print line
68 print line
70 p.wait()
69 p.wait()
71
70
72 def init_io(self):
71 def init_io(self):
73 # This will just use sys.stdout and sys.stderr. If you want to
72 # This will just use sys.stdout and sys.stderr. If you want to
74 # override sys.stdout and sys.stderr themselves, you need to do that
73 # override sys.stdout and sys.stderr themselves, you need to do that
75 # *before* instantiating this class, because Term holds onto
74 # *before* instantiating this class, because Term holds onto
76 # references to the underlying streams.
75 # references to the underlying streams.
77 import IPython.utils.io
76 import IPython.utils.io
78 Term = IPython.utils.io.IOTerm()
77 Term = IPython.utils.io.IOTerm()
79 IPython.utils.io.Term = Term
78 IPython.utils.io.Term = Term
80
79
81 def magic_edit(self,parameter_s='',last_call=['','']):
80 def magic_edit(self,parameter_s='',last_call=['','']):
82 """Bring up an editor and execute the resulting code.
81 """Bring up an editor and execute the resulting code.
83
82
84 Usage:
83 Usage:
85 %edit [options] [args]
84 %edit [options] [args]
86
85
87 %edit runs IPython's editor hook. The default version of this hook is
86 %edit runs IPython's editor hook. The default version of this hook is
88 set to call the __IPYTHON__.rc.editor command. This is read from your
87 set to call the __IPYTHON__.rc.editor command. This is read from your
89 environment variable $EDITOR. If this isn't found, it will default to
88 environment variable $EDITOR. If this isn't found, it will default to
90 vi under Linux/Unix and to notepad under Windows. See the end of this
89 vi under Linux/Unix and to notepad under Windows. See the end of this
91 docstring for how to change the editor hook.
90 docstring for how to change the editor hook.
92
91
93 You can also set the value of this editor via the command line option
92 You can also set the value of this editor via the command line option
94 '-editor' or in your ipythonrc file. This is useful if you wish to use
93 '-editor' or in your ipythonrc file. This is useful if you wish to use
95 specifically for IPython an editor different from your typical default
94 specifically for IPython an editor different from your typical default
96 (and for Windows users who typically don't set environment variables).
95 (and for Windows users who typically don't set environment variables).
97
96
98 This command allows you to conveniently edit multi-line code right in
97 This command allows you to conveniently edit multi-line code right in
99 your IPython session.
98 your IPython session.
100
99
101 If called without arguments, %edit opens up an empty editor with a
100 If called without arguments, %edit opens up an empty editor with a
102 temporary file and will execute the contents of this file when you
101 temporary file and will execute the contents of this file when you
103 close it (don't forget to save it!).
102 close it (don't forget to save it!).
104
103
105
104
106 Options:
105 Options:
107
106
108 -n <number>: open the editor at a specified line number. By default,
107 -n <number>: open the editor at a specified line number. By default,
109 the IPython editor hook uses the unix syntax 'editor +N filename', but
108 the IPython editor hook uses the unix syntax 'editor +N filename', but
110 you can configure this by providing your own modified hook if your
109 you can configure this by providing your own modified hook if your
111 favorite editor supports line-number specifications with a different
110 favorite editor supports line-number specifications with a different
112 syntax.
111 syntax.
113
112
114 -p: this will call the editor with the same data as the previous time
113 -p: this will call the editor with the same data as the previous time
115 it was used, regardless of how long ago (in your current session) it
114 it was used, regardless of how long ago (in your current session) it
116 was.
115 was.
117
116
118 -r: use 'raw' input. This option only applies to input taken from the
117 -r: use 'raw' input. This option only applies to input taken from the
119 user's history. By default, the 'processed' history is used, so that
118 user's history. By default, the 'processed' history is used, so that
120 magics are loaded in their transformed version to valid Python. If
119 magics are loaded in their transformed version to valid Python. If
121 this option is given, the raw input as typed as the command line is
120 this option is given, the raw input as typed as the command line is
122 used instead. When you exit the editor, it will be executed by
121 used instead. When you exit the editor, it will be executed by
123 IPython's own processor.
122 IPython's own processor.
124
123
125 -x: do not execute the edited code immediately upon exit. This is
124 -x: do not execute the edited code immediately upon exit. This is
126 mainly useful if you are editing programs which need to be called with
125 mainly useful if you are editing programs which need to be called with
127 command line arguments, which you can then do using %run.
126 command line arguments, which you can then do using %run.
128
127
129
128
130 Arguments:
129 Arguments:
131
130
132 If arguments are given, the following possibilites exist:
131 If arguments are given, the following possibilites exist:
133
132
134 - The arguments are numbers or pairs of colon-separated numbers (like
133 - The arguments are numbers or pairs of colon-separated numbers (like
135 1 4:8 9). These are interpreted as lines of previous input to be
134 1 4:8 9). These are interpreted as lines of previous input to be
136 loaded into the editor. The syntax is the same of the %macro command.
135 loaded into the editor. The syntax is the same of the %macro command.
137
136
138 - If the argument doesn't start with a number, it is evaluated as a
137 - If the argument doesn't start with a number, it is evaluated as a
139 variable and its contents loaded into the editor. You can thus edit
138 variable and its contents loaded into the editor. You can thus edit
140 any string which contains python code (including the result of
139 any string which contains python code (including the result of
141 previous edits).
140 previous edits).
142
141
143 - If the argument is the name of an object (other than a string),
142 - If the argument is the name of an object (other than a string),
144 IPython will try to locate the file where it was defined and open the
143 IPython will try to locate the file where it was defined and open the
145 editor at the point where it is defined. You can use `%edit function`
144 editor at the point where it is defined. You can use `%edit function`
146 to load an editor exactly at the point where 'function' is defined,
145 to load an editor exactly at the point where 'function' is defined,
147 edit it and have the file be executed automatically.
146 edit it and have the file be executed automatically.
148
147
149 If the object is a macro (see %macro for details), this opens up your
148 If the object is a macro (see %macro for details), this opens up your
150 specified editor with a temporary file containing the macro's data.
149 specified editor with a temporary file containing the macro's data.
151 Upon exit, the macro is reloaded with the contents of the file.
150 Upon exit, the macro is reloaded with the contents of the file.
152
151
153 Note: opening at an exact line is only supported under Unix, and some
152 Note: opening at an exact line is only supported under Unix, and some
154 editors (like kedit and gedit up to Gnome 2.8) do not understand the
153 editors (like kedit and gedit up to Gnome 2.8) do not understand the
155 '+NUMBER' parameter necessary for this feature. Good editors like
154 '+NUMBER' parameter necessary for this feature. Good editors like
156 (X)Emacs, vi, jed, pico and joe all do.
155 (X)Emacs, vi, jed, pico and joe all do.
157
156
158 - If the argument is not found as a variable, IPython will look for a
157 - If the argument is not found as a variable, IPython will look for a
159 file with that name (adding .py if necessary) and load it into the
158 file with that name (adding .py if necessary) and load it into the
160 editor. It will execute its contents with execfile() when you exit,
159 editor. It will execute its contents with execfile() when you exit,
161 loading any code in the file into your interactive namespace.
160 loading any code in the file into your interactive namespace.
162
161
163 After executing your code, %edit will return as output the code you
162 After executing your code, %edit will return as output the code you
164 typed in the editor (except when it was an existing file). This way
163 typed in the editor (except when it was an existing file). This way
165 you can reload the code in further invocations of %edit as a variable,
164 you can reload the code in further invocations of %edit as a variable,
166 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
165 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
167 the output.
166 the output.
168
167
169 Note that %edit is also available through the alias %ed.
168 Note that %edit is also available through the alias %ed.
170
169
171 This is an example of creating a simple function inside the editor and
170 This is an example of creating a simple function inside the editor and
172 then modifying it. First, start up the editor:
171 then modifying it. First, start up the editor:
173
172
174 In [1]: ed
173 In [1]: ed
175 Editing... done. Executing edited code...
174 Editing... done. Executing edited code...
176 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
175 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
177
176
178 We can then call the function foo():
177 We can then call the function foo():
179
178
180 In [2]: foo()
179 In [2]: foo()
181 foo() was defined in an editing session
180 foo() was defined in an editing session
182
181
183 Now we edit foo. IPython automatically loads the editor with the
182 Now we edit foo. IPython automatically loads the editor with the
184 (temporary) file where foo() was previously defined:
183 (temporary) file where foo() was previously defined:
185
184
186 In [3]: ed foo
185 In [3]: ed foo
187 Editing... done. Executing edited code...
186 Editing... done. Executing edited code...
188
187
189 And if we call foo() again we get the modified version:
188 And if we call foo() again we get the modified version:
190
189
191 In [4]: foo()
190 In [4]: foo()
192 foo() has now been changed!
191 foo() has now been changed!
193
192
194 Here is an example of how to edit a code snippet successive
193 Here is an example of how to edit a code snippet successive
195 times. First we call the editor:
194 times. First we call the editor:
196
195
197 In [5]: ed
196 In [5]: ed
198 Editing... done. Executing edited code...
197 Editing... done. Executing edited code...
199 hello
198 hello
200 Out[5]: "print 'hello'n"
199 Out[5]: "print 'hello'n"
201
200
202 Now we call it again with the previous output (stored in _):
201 Now we call it again with the previous output (stored in _):
203
202
204 In [6]: ed _
203 In [6]: ed _
205 Editing... done. Executing edited code...
204 Editing... done. Executing edited code...
206 hello world
205 hello world
207 Out[6]: "print 'hello world'n"
206 Out[6]: "print 'hello world'n"
208
207
209 Now we call it with the output #8 (stored in _8, also as Out[8]):
208 Now we call it with the output #8 (stored in _8, also as Out[8]):
210
209
211 In [7]: ed _8
210 In [7]: ed _8
212 Editing... done. Executing edited code...
211 Editing... done. Executing edited code...
213 hello again
212 hello again
214 Out[7]: "print 'hello again'n"
213 Out[7]: "print 'hello again'n"
215
214
216
215
217 Changing the default editor hook:
216 Changing the default editor hook:
218
217
219 If you wish to write your own editor hook, you can put it in a
218 If you wish to write your own editor hook, you can put it in a
220 configuration file which you load at startup time. The default hook
219 configuration file which you load at startup time. The default hook
221 is defined in the IPython.core.hooks module, and you can use that as a
220 is defined in the IPython.core.hooks module, and you can use that as a
222 starting example for further modifications. That file also has
221 starting example for further modifications. That file also has
223 general instructions on how to set a new hook for use once you've
222 general instructions on how to set a new hook for use once you've
224 defined it."""
223 defined it."""
225
224
226 # FIXME: This function has become a convoluted mess. It needs a
225 # FIXME: This function has become a convoluted mess. It needs a
227 # ground-up rewrite with clean, simple logic.
226 # ground-up rewrite with clean, simple logic.
228
227
229 def make_filename(arg):
228 def make_filename(arg):
230 "Make a filename from the given args"
229 "Make a filename from the given args"
231 try:
230 try:
232 filename = get_py_filename(arg)
231 filename = get_py_filename(arg)
233 except IOError:
232 except IOError:
234 if args.endswith('.py'):
233 if args.endswith('.py'):
235 filename = arg
234 filename = arg
236 else:
235 else:
237 filename = None
236 filename = None
238 return filename
237 return filename
239
238
240 # custom exceptions
239 # custom exceptions
241 class DataIsObject(Exception): pass
240 class DataIsObject(Exception): pass
242
241
243 opts,args = self.parse_options(parameter_s,'prn:')
242 opts,args = self.parse_options(parameter_s,'prn:')
244 # Set a few locals from the options for convenience:
243 # Set a few locals from the options for convenience:
245 opts_p = opts.has_key('p')
244 opts_p = opts.has_key('p')
246 opts_r = opts.has_key('r')
245 opts_r = opts.has_key('r')
247
246
248 # Default line number value
247 # Default line number value
249 lineno = opts.get('n',None)
248 lineno = opts.get('n',None)
250 if lineno is not None:
249 if lineno is not None:
251 try:
250 try:
252 lineno = int(lineno)
251 lineno = int(lineno)
253 except:
252 except:
254 warn("The -n argument must be an integer.")
253 warn("The -n argument must be an integer.")
255 return
254 return
256
255
257 if opts_p:
256 if opts_p:
258 args = '_%s' % last_call[0]
257 args = '_%s' % last_call[0]
259 if not self.shell.user_ns.has_key(args):
258 if not self.shell.user_ns.has_key(args):
260 args = last_call[1]
259 args = last_call[1]
261
260
262 # use last_call to remember the state of the previous call, but don't
261 # use last_call to remember the state of the previous call, but don't
263 # let it be clobbered by successive '-p' calls.
262 # let it be clobbered by successive '-p' calls.
264 try:
263 try:
265 last_call[0] = self.shell.displayhook.prompt_count
264 last_call[0] = self.shell.displayhook.prompt_count
266 if not opts_p:
265 if not opts_p:
267 last_call[1] = parameter_s
266 last_call[1] = parameter_s
268 except:
267 except:
269 pass
268 pass
270
269
271 # by default this is done with temp files, except when the given
270 # by default this is done with temp files, except when the given
272 # arg is a filename
271 # arg is a filename
273 use_temp = 1
272 use_temp = 1
274
273
275 if re.match(r'\d',args):
274 if re.match(r'\d',args):
276 # Mode where user specifies ranges of lines, like in %macro.
275 # Mode where user specifies ranges of lines, like in %macro.
277 # This means that you can't edit files whose names begin with
276 # This means that you can't edit files whose names begin with
278 # numbers this way. Tough.
277 # numbers this way. Tough.
279 ranges = args.split()
278 ranges = args.split()
280 data = ''.join(self.extract_input_slices(ranges,opts_r))
279 data = ''.join(self.extract_input_slices(ranges,opts_r))
281 elif args.endswith('.py'):
280 elif args.endswith('.py'):
282 filename = make_filename(args)
281 filename = make_filename(args)
283 data = ''
282 data = ''
284 use_temp = 0
283 use_temp = 0
285 elif args:
284 elif args:
286 try:
285 try:
287 # Load the parameter given as a variable. If not a string,
286 # Load the parameter given as a variable. If not a string,
288 # process it as an object instead (below)
287 # process it as an object instead (below)
289
288
290 #print '*** args',args,'type',type(args) # dbg
289 #print '*** args',args,'type',type(args) # dbg
291 data = eval(args,self.shell.user_ns)
290 data = eval(args,self.shell.user_ns)
292 if not type(data) in StringTypes:
291 if not type(data) in StringTypes:
293 raise DataIsObject
292 raise DataIsObject
294
293
295 except (NameError,SyntaxError):
294 except (NameError,SyntaxError):
296 # given argument is not a variable, try as a filename
295 # given argument is not a variable, try as a filename
297 filename = make_filename(args)
296 filename = make_filename(args)
298 if filename is None:
297 if filename is None:
299 warn("Argument given (%s) can't be found as a variable "
298 warn("Argument given (%s) can't be found as a variable "
300 "or as a filename." % args)
299 "or as a filename." % args)
301 return
300 return
302
301
303 data = ''
302 data = ''
304 use_temp = 0
303 use_temp = 0
305 except DataIsObject:
304 except DataIsObject:
306
305
307 # macros have a special edit function
306 # macros have a special edit function
308 if isinstance(data,Macro):
307 if isinstance(data,Macro):
309 self._edit_macro(args,data)
308 self._edit_macro(args,data)
310 return
309 return
311
310
312 # For objects, try to edit the file where they are defined
311 # For objects, try to edit the file where they are defined
313 try:
312 try:
314 filename = inspect.getabsfile(data)
313 filename = inspect.getabsfile(data)
315 if 'fakemodule' in filename.lower() and inspect.isclass(data):
314 if 'fakemodule' in filename.lower() and inspect.isclass(data):
316 # class created by %edit? Try to find source
315 # class created by %edit? Try to find source
317 # by looking for method definitions instead, the
316 # by looking for method definitions instead, the
318 # __module__ in those classes is FakeModule.
317 # __module__ in those classes is FakeModule.
319 attrs = [getattr(data, aname) for aname in dir(data)]
318 attrs = [getattr(data, aname) for aname in dir(data)]
320 for attr in attrs:
319 for attr in attrs:
321 if not inspect.ismethod(attr):
320 if not inspect.ismethod(attr):
322 continue
321 continue
323 filename = inspect.getabsfile(attr)
322 filename = inspect.getabsfile(attr)
324 if filename and 'fakemodule' not in filename.lower():
323 if filename and 'fakemodule' not in filename.lower():
325 # change the attribute to be the edit target instead
324 # change the attribute to be the edit target instead
326 data = attr
325 data = attr
327 break
326 break
328
327
329 datafile = 1
328 datafile = 1
330 except TypeError:
329 except TypeError:
331 filename = make_filename(args)
330 filename = make_filename(args)
332 datafile = 1
331 datafile = 1
333 warn('Could not find file where `%s` is defined.\n'
332 warn('Could not find file where `%s` is defined.\n'
334 'Opening a file named `%s`' % (args,filename))
333 'Opening a file named `%s`' % (args,filename))
335 # Now, make sure we can actually read the source (if it was in
334 # Now, make sure we can actually read the source (if it was in
336 # a temp file it's gone by now).
335 # a temp file it's gone by now).
337 if datafile:
336 if datafile:
338 try:
337 try:
339 if lineno is None:
338 if lineno is None:
340 lineno = inspect.getsourcelines(data)[1]
339 lineno = inspect.getsourcelines(data)[1]
341 except IOError:
340 except IOError:
342 filename = make_filename(args)
341 filename = make_filename(args)
343 if filename is None:
342 if filename is None:
344 warn('The file `%s` where `%s` was defined cannot '
343 warn('The file `%s` where `%s` was defined cannot '
345 'be read.' % (filename,data))
344 'be read.' % (filename,data))
346 return
345 return
347 use_temp = 0
346 use_temp = 0
348 else:
347 else:
349 data = ''
348 data = ''
350
349
351 if use_temp:
350 if use_temp:
352 filename = self.shell.mktempfile(data)
351 filename = self.shell.mktempfile(data)
353 print 'IPython will make a temporary file named:',filename
352 print 'IPython will make a temporary file named:',filename
354
353
355 payload = {
354 payload = {
356 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
355 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
357 'filename' : filename,
356 'filename' : filename,
358 'line_number' : lineno
357 'line_number' : lineno
359 }
358 }
360 self.payload_manager.write_payload(payload)
359 self.payload_manager.write_payload(payload)
361
360
362
361
363 def _showtraceback(self, etype, evalue, stb):
362 def _showtraceback(self, etype, evalue, stb):
364
363
365 exc_content = {
364 exc_content = {
366 u'status' : u'error',
365 u'status' : u'error',
367 u'traceback' : stb,
366 u'traceback' : stb,
368 u'ename' : unicode(etype.__name__),
367 u'ename' : unicode(etype.__name__),
369 u'evalue' : unicode(evalue)
368 u'evalue' : unicode(evalue)
370 }
369 }
371
370
372 dh = self.displayhook
371 dh = self.displayhook
373 exc_msg = dh.session.msg(u'pyerr', exc_content, dh.parent_header)
372 exc_msg = dh.session.msg(u'pyerr', exc_content, dh.parent_header)
374 # Send exception info over pub socket for other clients than the caller
373 # Send exception info over pub socket for other clients than the caller
375 # to pick up
374 # to pick up
376 dh.pub_socket.send_json(exc_msg)
375 dh.pub_socket.send_json(exc_msg)
377
376
378 # FIXME - Hack: store exception info in shell object. Right now, the
377 # FIXME - Hack: store exception info in shell object. Right now, the
379 # caller is reading this info after the fact, we need to fix this logic
378 # caller is reading this info after the fact, we need to fix this logic
380 # to remove this hack.
379 # to remove this hack.
381 self._reply_content = exc_content
380 self._reply_content = exc_content
382 # /FIXME
381 # /FIXME
383
382
384 return exc_content
383 return exc_content
385
384
386 def runlines(self, lines, clean=False):
385 def runlines(self, lines, clean=False):
387 return InteractiveShell.runlines(self, lines, clean)
386 return InteractiveShell.runlines(self, lines, clean)
388
387
389 InteractiveShellABC.register(ZMQInteractiveShell)
388 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now