##// END OF EJS Templates
Move displayhook for ZMQ shell to zmq.displayhook, and rename to make the difference clearer.
Thomas Kluyver -
Show More
@@ -1,170 +1,170 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple engine that talks to a controller over 0MQ.
2 """A simple engine that talks to a controller over 0MQ.
3 it handles registration, etc. and launches a kernel
3 it handles registration, etc. and launches a kernel
4 connected to the Controller's Schedulers.
4 connected to the Controller's Schedulers.
5
5
6 Authors:
6 Authors:
7
7
8 * Min RK
8 * Min RK
9 """
9 """
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2010-2011 The IPython Development Team
11 # Copyright (C) 2010-2011 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from __future__ import print_function
17 from __future__ import print_function
18
18
19 import sys
19 import sys
20 import time
20 import time
21
21
22 import zmq
22 import zmq
23 from zmq.eventloop import ioloop, zmqstream
23 from zmq.eventloop import ioloop, zmqstream
24
24
25 # internal
25 # internal
26 from IPython.utils.traitlets import Instance, Dict, Int, Type, CFloat, Unicode
26 from IPython.utils.traitlets import Instance, Dict, Int, Type, CFloat, Unicode
27 # from IPython.utils.localinterfaces import LOCALHOST
27 # from IPython.utils.localinterfaces import LOCALHOST
28
28
29 from IPython.parallel.controller.heartmonitor import Heart
29 from IPython.parallel.controller.heartmonitor import Heart
30 from IPython.parallel.factory import RegistrationFactory
30 from IPython.parallel.factory import RegistrationFactory
31 from IPython.parallel.util import disambiguate_url
31 from IPython.parallel.util import disambiguate_url
32
32
33 from IPython.zmq.session import Message
33 from IPython.zmq.session import Message
34
34
35 from .streamkernel import Kernel
35 from .streamkernel import Kernel
36
36
37 class EngineFactory(RegistrationFactory):
37 class EngineFactory(RegistrationFactory):
38 """IPython engine"""
38 """IPython engine"""
39
39
40 # configurables:
40 # configurables:
41 out_stream_factory=Type('IPython.zmq.iostream.OutStream', config=True,
41 out_stream_factory=Type('IPython.zmq.iostream.OutStream', config=True,
42 help="""The OutStream for handling stdout/err.
42 help="""The OutStream for handling stdout/err.
43 Typically 'IPython.zmq.iostream.OutStream'""")
43 Typically 'IPython.zmq.iostream.OutStream'""")
44 display_hook_factory=Type('IPython.zmq.displayhook.DisplayHook', config=True,
44 display_hook_factory=Type('IPython.zmq.displayhook.ZMQDisplayHook', config=True,
45 help="""The class for handling displayhook.
45 help="""The class for handling displayhook.
46 Typically 'IPython.zmq.displayhook.DisplayHook'""")
46 Typically 'IPython.zmq.displayhook.ZMQDisplayHook'""")
47 location=Unicode(config=True,
47 location=Unicode(config=True,
48 help="""The location (an IP address) of the controller. This is
48 help="""The location (an IP address) of the controller. This is
49 used for disambiguating URLs, to determine whether
49 used for disambiguating URLs, to determine whether
50 loopback should be used to connect or the public address.""")
50 loopback should be used to connect or the public address.""")
51 timeout=CFloat(2,config=True,
51 timeout=CFloat(2,config=True,
52 help="""The time (in seconds) to wait for the Controller to respond
52 help="""The time (in seconds) to wait for the Controller to respond
53 to registration requests before giving up.""")
53 to registration requests before giving up.""")
54
54
55 # not configurable:
55 # not configurable:
56 user_ns=Dict()
56 user_ns=Dict()
57 id=Int(allow_none=True)
57 id=Int(allow_none=True)
58 registrar=Instance('zmq.eventloop.zmqstream.ZMQStream')
58 registrar=Instance('zmq.eventloop.zmqstream.ZMQStream')
59 kernel=Instance(Kernel)
59 kernel=Instance(Kernel)
60
60
61
61
62 def __init__(self, **kwargs):
62 def __init__(self, **kwargs):
63 super(EngineFactory, self).__init__(**kwargs)
63 super(EngineFactory, self).__init__(**kwargs)
64 self.ident = self.session.session
64 self.ident = self.session.session
65 ctx = self.context
65 ctx = self.context
66
66
67 reg = ctx.socket(zmq.XREQ)
67 reg = ctx.socket(zmq.XREQ)
68 reg.setsockopt(zmq.IDENTITY, self.ident)
68 reg.setsockopt(zmq.IDENTITY, self.ident)
69 reg.connect(self.url)
69 reg.connect(self.url)
70 self.registrar = zmqstream.ZMQStream(reg, self.loop)
70 self.registrar = zmqstream.ZMQStream(reg, self.loop)
71
71
72 def register(self):
72 def register(self):
73 """send the registration_request"""
73 """send the registration_request"""
74
74
75 self.log.info("registering")
75 self.log.info("registering")
76 content = dict(queue=self.ident, heartbeat=self.ident, control=self.ident)
76 content = dict(queue=self.ident, heartbeat=self.ident, control=self.ident)
77 self.registrar.on_recv(self.complete_registration)
77 self.registrar.on_recv(self.complete_registration)
78 # print (self.session.key)
78 # print (self.session.key)
79 self.session.send(self.registrar, "registration_request",content=content)
79 self.session.send(self.registrar, "registration_request",content=content)
80
80
81 def complete_registration(self, msg):
81 def complete_registration(self, msg):
82 # print msg
82 # print msg
83 self._abort_dc.stop()
83 self._abort_dc.stop()
84 ctx = self.context
84 ctx = self.context
85 loop = self.loop
85 loop = self.loop
86 identity = self.ident
86 identity = self.ident
87
87
88 idents,msg = self.session.feed_identities(msg)
88 idents,msg = self.session.feed_identities(msg)
89 msg = Message(self.session.unpack_message(msg))
89 msg = Message(self.session.unpack_message(msg))
90
90
91 if msg.content.status == 'ok':
91 if msg.content.status == 'ok':
92 self.id = int(msg.content.id)
92 self.id = int(msg.content.id)
93
93
94 # create Shell Streams (MUX, Task, etc.):
94 # create Shell Streams (MUX, Task, etc.):
95 queue_addr = msg.content.mux
95 queue_addr = msg.content.mux
96 shell_addrs = [ str(queue_addr) ]
96 shell_addrs = [ str(queue_addr) ]
97 task_addr = msg.content.task
97 task_addr = msg.content.task
98 if task_addr:
98 if task_addr:
99 shell_addrs.append(str(task_addr))
99 shell_addrs.append(str(task_addr))
100
100
101 # Uncomment this to go back to two-socket model
101 # Uncomment this to go back to two-socket model
102 # shell_streams = []
102 # shell_streams = []
103 # for addr in shell_addrs:
103 # for addr in shell_addrs:
104 # stream = zmqstream.ZMQStream(ctx.socket(zmq.XREP), loop)
104 # stream = zmqstream.ZMQStream(ctx.socket(zmq.XREP), loop)
105 # stream.setsockopt(zmq.IDENTITY, identity)
105 # stream.setsockopt(zmq.IDENTITY, identity)
106 # stream.connect(disambiguate_url(addr, self.location))
106 # stream.connect(disambiguate_url(addr, self.location))
107 # shell_streams.append(stream)
107 # shell_streams.append(stream)
108
108
109 # Now use only one shell stream for mux and tasks
109 # Now use only one shell stream for mux and tasks
110 stream = zmqstream.ZMQStream(ctx.socket(zmq.XREP), loop)
110 stream = zmqstream.ZMQStream(ctx.socket(zmq.XREP), loop)
111 stream.setsockopt(zmq.IDENTITY, identity)
111 stream.setsockopt(zmq.IDENTITY, identity)
112 shell_streams = [stream]
112 shell_streams = [stream]
113 for addr in shell_addrs:
113 for addr in shell_addrs:
114 stream.connect(disambiguate_url(addr, self.location))
114 stream.connect(disambiguate_url(addr, self.location))
115 # end single stream-socket
115 # end single stream-socket
116
116
117 # control stream:
117 # control stream:
118 control_addr = str(msg.content.control)
118 control_addr = str(msg.content.control)
119 control_stream = zmqstream.ZMQStream(ctx.socket(zmq.XREP), loop)
119 control_stream = zmqstream.ZMQStream(ctx.socket(zmq.XREP), loop)
120 control_stream.setsockopt(zmq.IDENTITY, identity)
120 control_stream.setsockopt(zmq.IDENTITY, identity)
121 control_stream.connect(disambiguate_url(control_addr, self.location))
121 control_stream.connect(disambiguate_url(control_addr, self.location))
122
122
123 # create iopub stream:
123 # create iopub stream:
124 iopub_addr = msg.content.iopub
124 iopub_addr = msg.content.iopub
125 iopub_stream = zmqstream.ZMQStream(ctx.socket(zmq.PUB), loop)
125 iopub_stream = zmqstream.ZMQStream(ctx.socket(zmq.PUB), loop)
126 iopub_stream.setsockopt(zmq.IDENTITY, identity)
126 iopub_stream.setsockopt(zmq.IDENTITY, identity)
127 iopub_stream.connect(disambiguate_url(iopub_addr, self.location))
127 iopub_stream.connect(disambiguate_url(iopub_addr, self.location))
128
128
129 # launch heartbeat
129 # launch heartbeat
130 hb_addrs = msg.content.heartbeat
130 hb_addrs = msg.content.heartbeat
131 # print (hb_addrs)
131 # print (hb_addrs)
132
132
133 # # Redirect input streams and set a display hook.
133 # # Redirect input streams and set a display hook.
134 if self.out_stream_factory:
134 if self.out_stream_factory:
135 sys.stdout = self.out_stream_factory(self.session, iopub_stream, u'stdout')
135 sys.stdout = self.out_stream_factory(self.session, iopub_stream, u'stdout')
136 sys.stdout.topic = 'engine.%i.stdout'%self.id
136 sys.stdout.topic = 'engine.%i.stdout'%self.id
137 sys.stderr = self.out_stream_factory(self.session, iopub_stream, u'stderr')
137 sys.stderr = self.out_stream_factory(self.session, iopub_stream, u'stderr')
138 sys.stderr.topic = 'engine.%i.stderr'%self.id
138 sys.stderr.topic = 'engine.%i.stderr'%self.id
139 if self.display_hook_factory:
139 if self.display_hook_factory:
140 sys.displayhook = self.display_hook_factory(self.session, iopub_stream)
140 sys.displayhook = self.display_hook_factory(self.session, iopub_stream)
141 sys.displayhook.topic = 'engine.%i.pyout'%self.id
141 sys.displayhook.topic = 'engine.%i.pyout'%self.id
142
142
143 self.kernel = Kernel(config=self.config, int_id=self.id, ident=self.ident, session=self.session,
143 self.kernel = Kernel(config=self.config, int_id=self.id, ident=self.ident, session=self.session,
144 control_stream=control_stream, shell_streams=shell_streams, iopub_stream=iopub_stream,
144 control_stream=control_stream, shell_streams=shell_streams, iopub_stream=iopub_stream,
145 loop=loop, user_ns = self.user_ns, log=self.log)
145 loop=loop, user_ns = self.user_ns, log=self.log)
146 self.kernel.start()
146 self.kernel.start()
147 hb_addrs = [ disambiguate_url(addr, self.location) for addr in hb_addrs ]
147 hb_addrs = [ disambiguate_url(addr, self.location) for addr in hb_addrs ]
148 heart = Heart(*map(str, hb_addrs), heart_id=identity)
148 heart = Heart(*map(str, hb_addrs), heart_id=identity)
149 heart.start()
149 heart.start()
150
150
151
151
152 else:
152 else:
153 self.log.fatal("Registration Failed: %s"%msg)
153 self.log.fatal("Registration Failed: %s"%msg)
154 raise Exception("Registration Failed: %s"%msg)
154 raise Exception("Registration Failed: %s"%msg)
155
155
156 self.log.info("Completed registration with id %i"%self.id)
156 self.log.info("Completed registration with id %i"%self.id)
157
157
158
158
159 def abort(self):
159 def abort(self):
160 self.log.fatal("Registration timed out after %.1f seconds"%self.timeout)
160 self.log.fatal("Registration timed out after %.1f seconds"%self.timeout)
161 self.session.send(self.registrar, "unregistration_request", content=dict(id=self.id))
161 self.session.send(self.registrar, "unregistration_request", content=dict(id=self.id))
162 time.sleep(1)
162 time.sleep(1)
163 sys.exit(255)
163 sys.exit(255)
164
164
165 def start(self):
165 def start(self):
166 dc = ioloop.DelayedCallback(self.register, 0, self.loop)
166 dc = ioloop.DelayedCallback(self.register, 0, self.loop)
167 dc.start()
167 dc.start()
168 self._abort_dc = ioloop.DelayedCallback(self.abort, self.timeout*1000, self.loop)
168 self._abort_dc = ioloop.DelayedCallback(self.abort, self.timeout*1000, self.loop)
169 self._abort_dc.start()
169 self._abort_dc.start()
170
170
@@ -1,23 +1,64 b''
1 import __builtin__
1 import __builtin__
2 from base64 import encodestring
2
3
3 from session import extract_header
4 from IPython.core.displayhook import DisplayHook
4
5 from IPython.utils.traitlets import Instance, Dict
5 class DisplayHook(object):
6 from session import extract_header, Session
6
7
8 class ZMQDisplayHook(object):
9 """A simple displayhook that publishes the object's repr over a ZeroMQ
10 socket."""
7 topic=None
11 topic=None
8
12
9 def __init__(self, session, pub_socket):
13 def __init__(self, session, pub_socket):
10 self.session = session
14 self.session = session
11 self.pub_socket = pub_socket
15 self.pub_socket = pub_socket
12 self.parent_header = {}
16 self.parent_header = {}
13
17
14 def __call__(self, obj):
18 def __call__(self, obj):
15 if obj is None:
19 if obj is None:
16 return
20 return
17
21
18 __builtin__._ = obj
22 __builtin__._ = obj
19 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
23 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
20 parent=self.parent_header, ident=self.topic)
24 parent=self.parent_header, ident=self.topic)
21
25
22 def set_parent(self, parent):
26 def set_parent(self, parent):
23 self.parent_header = extract_header(parent) No newline at end of file
27 self.parent_header = extract_header(parent)
28
29
30 def _encode_png(data):
31 pngdata = data.get('image/png')
32 if pngdata is not None:
33 data['image/png'] = encodestring(pngdata)
34
35 class ZMQShellDisplayHook(DisplayHook):
36 """A displayhook subclass that publishes data using ZeroMQ. This is intended
37 to work with an InteractiveShell instance. It sends a dict of different
38 representations of the object."""
39
40 session = Instance(Session)
41 pub_socket = Instance('zmq.Socket')
42 parent_header = Dict({})
43
44 def set_parent(self, parent):
45 """Set the parent for outbound messages."""
46 self.parent_header = extract_header(parent)
47
48 def start_displayhook(self):
49 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
50
51 def write_output_prompt(self):
52 """Write the output prompt."""
53 if self.do_full_cache:
54 self.msg['content']['execution_count'] = self.prompt_count
55
56 def write_format_data(self, format_dict):
57 pngdata = format_dict.get('image/png')
58 _encode_png(format_dict)
59 self.msg['content']['data'] = format_dict
60
61 def finish_displayhook(self):
62 """Finish up all displayhook activities."""
63 self.session.send(self.pub_socket, self.msg)
64 self.msg = None
@@ -1,160 +1,159 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 atexit
6 import atexit
7 import os
7 import os
8 import socket
8 import socket
9 from subprocess import Popen, PIPE
9 from subprocess import Popen, PIPE
10 import sys
10 import sys
11
11
12 # Local imports.
12 # Local imports.
13 from parentpoller import ParentPollerWindows
13 from parentpoller import ParentPollerWindows
14
14
15
15
16
17 def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
16 def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0,
18 ip=None, stdin=None, stdout=None, stderr=None,
17 ip=None, stdin=None, stdout=None, stderr=None,
19 executable=None, independent=False, extra_arguments=[]):
18 executable=None, independent=False, extra_arguments=[]):
20 """ Launches a localhost kernel, binding to the specified ports.
19 """ Launches a localhost kernel, binding to the specified ports.
21
20
22 Parameters
21 Parameters
23 ----------
22 ----------
24 code : str,
23 code : str,
25 A string of Python code that imports and executes a kernel entry point.
24 A string of Python code that imports and executes a kernel entry point.
26
25
27 shell_port : int, optional
26 shell_port : int, optional
28 The port to use for XREP channel.
27 The port to use for XREP channel.
29
28
30 iopub_port : int, optional
29 iopub_port : int, optional
31 The port to use for the SUB channel.
30 The port to use for the SUB channel.
32
31
33 stdin_port : int, optional
32 stdin_port : int, optional
34 The port to use for the REQ (raw input) channel.
33 The port to use for the REQ (raw input) channel.
35
34
36 hb_port : int, optional
35 hb_port : int, optional
37 The port to use for the hearbeat REP channel.
36 The port to use for the hearbeat REP channel.
38
37
39 ip : str, optional
38 ip : str, optional
40 The ip address the kernel will bind to.
39 The ip address the kernel will bind to.
41
40
42 stdin, stdout, stderr : optional (default None)
41 stdin, stdout, stderr : optional (default None)
43 Standards streams, as defined in subprocess.Popen.
42 Standards streams, as defined in subprocess.Popen.
44
43
45 executable : str, optional (default sys.executable)
44 executable : str, optional (default sys.executable)
46 The Python executable to use for the kernel process.
45 The Python executable to use for the kernel process.
47
46
48 independent : bool, optional (default False)
47 independent : bool, optional (default False)
49 If set, the kernel process is guaranteed to survive if this process
48 If set, the kernel process is guaranteed to survive if this process
50 dies. If not set, an effort is made to ensure that the kernel is killed
49 dies. If not set, an effort is made to ensure that the kernel is killed
51 when this process dies. Note that in this case it is still good practice
50 when this process dies. Note that in this case it is still good practice
52 to kill kernels manually before exiting.
51 to kill kernels manually before exiting.
53
52
54 extra_arguments = list, optional
53 extra_arguments = list, optional
55 A list of extra arguments to pass when executing the launch code.
54 A list of extra arguments to pass when executing the launch code.
56
55
57 Returns
56 Returns
58 -------
57 -------
59 A tuple of form:
58 A tuple of form:
60 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
59 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
61 where kernel_process is a Popen object and the ports are integers.
60 where kernel_process is a Popen object and the ports are integers.
62 """
61 """
63 # Find open ports as necessary.
62 # Find open ports as necessary.
64 ports = []
63 ports = []
65 ports_needed = int(shell_port <= 0) + int(iopub_port <= 0) + \
64 ports_needed = int(shell_port <= 0) + int(iopub_port <= 0) + \
66 int(stdin_port <= 0) + int(hb_port <= 0)
65 int(stdin_port <= 0) + int(hb_port <= 0)
67 for i in xrange(ports_needed):
66 for i in xrange(ports_needed):
68 sock = socket.socket()
67 sock = socket.socket()
69 sock.bind(('', 0))
68 sock.bind(('', 0))
70 ports.append(sock)
69 ports.append(sock)
71 for i, sock in enumerate(ports):
70 for i, sock in enumerate(ports):
72 port = sock.getsockname()[1]
71 port = sock.getsockname()[1]
73 sock.close()
72 sock.close()
74 ports[i] = port
73 ports[i] = port
75 if shell_port <= 0:
74 if shell_port <= 0:
76 shell_port = ports.pop(0)
75 shell_port = ports.pop(0)
77 if iopub_port <= 0:
76 if iopub_port <= 0:
78 iopub_port = ports.pop(0)
77 iopub_port = ports.pop(0)
79 if stdin_port <= 0:
78 if stdin_port <= 0:
80 stdin_port = ports.pop(0)
79 stdin_port = ports.pop(0)
81 if hb_port <= 0:
80 if hb_port <= 0:
82 hb_port = ports.pop(0)
81 hb_port = ports.pop(0)
83
82
84 # Build the kernel launch command.
83 # Build the kernel launch command.
85 if executable is None:
84 if executable is None:
86 executable = sys.executable
85 executable = sys.executable
87 arguments = [ executable, '-c', code, 'shell=%i'%shell_port,
86 arguments = [ executable, '-c', code, 'shell=%i'%shell_port,
88 'iopub=%i'%iopub_port, 'stdin=%i'%stdin_port,
87 'iopub=%i'%iopub_port, 'stdin=%i'%stdin_port,
89 'hb=%i'%hb_port
88 'hb=%i'%hb_port
90 ]
89 ]
91 if ip is not None:
90 if ip is not None:
92 arguments.append('ip=%s'%ip)
91 arguments.append('ip=%s'%ip)
93 arguments.extend(extra_arguments)
92 arguments.extend(extra_arguments)
94
93
95 # Spawn a kernel.
94 # Spawn a kernel.
96 if sys.platform == 'win32':
95 if sys.platform == 'win32':
97 # Create a Win32 event for interrupting the kernel.
96 # Create a Win32 event for interrupting the kernel.
98 interrupt_event = ParentPollerWindows.create_interrupt_event()
97 interrupt_event = ParentPollerWindows.create_interrupt_event()
99 arguments += [ 'interrupt=%i'%interrupt_event ]
98 arguments += [ 'interrupt=%i'%interrupt_event ]
100
99
101 # If this process in running on pythonw, stdin, stdout, and stderr are
100 # If this process in running on pythonw, stdin, stdout, and stderr are
102 # invalid. Popen will fail unless they are suitably redirected. We don't
101 # invalid. Popen will fail unless they are suitably redirected. We don't
103 # read from the pipes, but they must exist.
102 # read from the pipes, but they must exist.
104 if sys.executable.endswith('pythonw.exe'):
103 if sys.executable.endswith('pythonw.exe'):
105 redirect = True
104 redirect = True
106 _stdin = PIPE if stdin is None else stdin
105 _stdin = PIPE if stdin is None else stdin
107 _stdout = PIPE if stdout is None else stdout
106 _stdout = PIPE if stdout is None else stdout
108 _stderr = PIPE if stderr is None else stderr
107 _stderr = PIPE if stderr is None else stderr
109 else:
108 else:
110 redirect = False
109 redirect = False
111 _stdin, _stdout, _stderr = stdin, stdout, stderr
110 _stdin, _stdout, _stderr = stdin, stdout, stderr
112
111
113 # If the kernel is running on pythonw and stdout/stderr are not been
112 # If the kernel is running on pythonw and stdout/stderr are not been
114 # re-directed, it will crash when more than 4KB of data is written to
113 # re-directed, it will crash when more than 4KB of data is written to
115 # stdout or stderr. This is a bug that has been with Python for a very
114 # stdout or stderr. This is a bug that has been with Python for a very
116 # long time; see http://bugs.python.org/issue706263.
115 # long time; see http://bugs.python.org/issue706263.
117 # A cleaner solution to this problem would be to pass os.devnull to
116 # A cleaner solution to this problem would be to pass os.devnull to
118 # Popen directly. Unfortunately, that does not work.
117 # Popen directly. Unfortunately, that does not work.
119 if executable.endswith('pythonw.exe'):
118 if executable.endswith('pythonw.exe'):
120 if stdout is None:
119 if stdout is None:
121 arguments.append('--no-stdout')
120 arguments.append('--no-stdout')
122 if stderr is None:
121 if stderr is None:
123 arguments.append('--no-stderr')
122 arguments.append('--no-stderr')
124
123
125 # Launch the kernel process.
124 # Launch the kernel process.
126 if independent:
125 if independent:
127 proc = Popen(arguments,
126 proc = Popen(arguments,
128 creationflags=512, # CREATE_NEW_PROCESS_GROUP
127 creationflags=512, # CREATE_NEW_PROCESS_GROUP
129 stdin=_stdin, stdout=_stdout, stderr=_stderr)
128 stdin=_stdin, stdout=_stdout, stderr=_stderr)
130 else:
129 else:
131 from _subprocess import DuplicateHandle, GetCurrentProcess, \
130 from _subprocess import DuplicateHandle, GetCurrentProcess, \
132 DUPLICATE_SAME_ACCESS
131 DUPLICATE_SAME_ACCESS
133 pid = GetCurrentProcess()
132 pid = GetCurrentProcess()
134 handle = DuplicateHandle(pid, pid, pid, 0,
133 handle = DuplicateHandle(pid, pid, pid, 0,
135 True, # Inheritable by new processes.
134 True, # Inheritable by new processes.
136 DUPLICATE_SAME_ACCESS)
135 DUPLICATE_SAME_ACCESS)
137 proc = Popen(arguments + ['parent=%i'%int(handle)],
136 proc = Popen(arguments + ['parent=%i'%int(handle)],
138 stdin=_stdin, stdout=_stdout, stderr=_stderr)
137 stdin=_stdin, stdout=_stdout, stderr=_stderr)
139
138
140 # Attach the interrupt event to the Popen objet so it can be used later.
139 # Attach the interrupt event to the Popen objet so it can be used later.
141 proc.win32_interrupt_event = interrupt_event
140 proc.win32_interrupt_event = interrupt_event
142
141
143 # Clean up pipes created to work around Popen bug.
142 # Clean up pipes created to work around Popen bug.
144 if redirect:
143 if redirect:
145 if stdin is None:
144 if stdin is None:
146 proc.stdin.close()
145 proc.stdin.close()
147 if stdout is None:
146 if stdout is None:
148 proc.stdout.close()
147 proc.stdout.close()
149 if stderr is None:
148 if stderr is None:
150 proc.stderr.close()
149 proc.stderr.close()
151
150
152 else:
151 else:
153 if independent:
152 if independent:
154 proc = Popen(arguments, preexec_fn=lambda: os.setsid(),
153 proc = Popen(arguments, preexec_fn=lambda: os.setsid(),
155 stdin=stdin, stdout=stdout, stderr=stderr)
154 stdin=stdin, stdout=stdout, stderr=stderr)
156 else:
155 else:
157 proc = Popen(arguments + ['parent=1'],
156 proc = Popen(arguments + ['parent=1'],
158 stdin=stdin, stdout=stdout, stderr=stderr)
157 stdin=stdin, stdout=stdout, stderr=stderr)
159
158
160 return proc, shell_port, iopub_port, stdin_port, hb_port
159 return proc, shell_port, iopub_port, stdin_port, hb_port
@@ -1,483 +1,446 b''
1 """A ZMQ-based subclass of InteractiveShell.
1 """A ZMQ-based subclass of InteractiveShell.
2
2
3 This code is meant to ease the refactoring of the base InteractiveShell into
3 This code is meant to ease the refactoring of the base InteractiveShell into
4 something with a cleaner architecture for 2-process use, without actually
4 something with a cleaner architecture for 2-process use, without actually
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 we subclass and override what we want to fix. Once this is working well, we
6 we subclass and override what we want to fix. Once this is working well, we
7 can go back to the base class and refactor the code for a cleaner inheritance
7 can go back to the base class and refactor the code for a cleaner inheritance
8 implementation that doesn't rely on so much monkeypatching.
8 implementation that doesn't rely on so much monkeypatching.
9
9
10 But this lets us maintain a fully working IPython as we develop the new
10 But this lets us maintain a fully working IPython as we develop the new
11 machinery. This should thus be thought of as scaffolding.
11 machinery. This should thus be thought of as scaffolding.
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 # Stdlib
18 # Stdlib
19 from base64 import encodestring
20 import inspect
19 import inspect
21 import os
20 import os
22
21
23 # Our own
22 # Our own
24 from IPython.core.interactiveshell import (
23 from IPython.core.interactiveshell import (
25 InteractiveShell, InteractiveShellABC
24 InteractiveShell, InteractiveShellABC
26 )
25 )
27 from IPython.core import page
26 from IPython.core import page
28 from IPython.core.autocall import ZMQExitAutocall
27 from IPython.core.autocall import ZMQExitAutocall
29 from IPython.core.displayhook import DisplayHook
30 from IPython.core.displaypub import DisplayPublisher
28 from IPython.core.displaypub import DisplayPublisher
31 from IPython.core.macro import Macro
29 from IPython.core.macro import Macro
32 from IPython.core.magic import MacroToEdit
30 from IPython.core.magic import MacroToEdit
33 from IPython.core.payloadpage import install_payload_page
31 from IPython.core.payloadpage import install_payload_page
34 from IPython.utils import io
32 from IPython.utils import io
35 from IPython.utils.path import get_py_filename
33 from IPython.utils.path import get_py_filename
36 from IPython.utils.traitlets import Instance, Type, Dict
34 from IPython.utils.traitlets import Instance, Type, Dict
37 from IPython.utils.warn import warn
35 from IPython.utils.warn import warn
36 from IPython.zmq.displayhook import ZMQShellDisplayHook
38 from IPython.zmq.session import extract_header
37 from IPython.zmq.session import extract_header
39 from session import Session
38 from session import Session
40
39
41 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
42 # Globals and side-effects
41 # Globals and side-effects
43 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
44
43
45 # Install the payload version of page.
44 # Install the payload version of page.
46 install_payload_page()
45 install_payload_page()
47
46
48 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
49 # Functions and classes
48 # Functions and classes
50 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
51
50
52 def _encode_png(data):
53 pngdata = data.get('image/png')
54 if pngdata is not None:
55 data['image/png'] = encodestring(pngdata)
56
57
58 class ZMQDisplayHook(DisplayHook):
59 """A displayhook subclass that publishes data using ZeroMQ."""
60
61 session = Instance(Session)
62 pub_socket = Instance('zmq.Socket')
63 parent_header = Dict({})
64
65 def set_parent(self, parent):
66 """Set the parent for outbound messages."""
67 self.parent_header = extract_header(parent)
68
69 def start_displayhook(self):
70 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
71
72 def write_output_prompt(self):
73 """Write the output prompt."""
74 if self.do_full_cache:
75 self.msg['content']['execution_count'] = self.prompt_count
76
77 def write_format_data(self, format_dict):
78 pngdata = format_dict.get('image/png')
79 _encode_png(format_dict)
80 self.msg['content']['data'] = format_dict
81
82 def finish_displayhook(self):
83 """Finish up all displayhook activities."""
84 self.session.send(self.pub_socket, self.msg)
85 self.msg = None
86
87
88 class ZMQDisplayPublisher(DisplayPublisher):
51 class ZMQDisplayPublisher(DisplayPublisher):
89 """A display publisher that publishes data using a ZeroMQ PUB socket."""
52 """A display publisher that publishes data using a ZeroMQ PUB socket."""
90
53
91 session = Instance(Session)
54 session = Instance(Session)
92 pub_socket = Instance('zmq.Socket')
55 pub_socket = Instance('zmq.Socket')
93 parent_header = Dict({})
56 parent_header = Dict({})
94
57
95 def set_parent(self, parent):
58 def set_parent(self, parent):
96 """Set the parent for outbound messages."""
59 """Set the parent for outbound messages."""
97 self.parent_header = extract_header(parent)
60 self.parent_header = extract_header(parent)
98
61
99 def publish(self, source, data, metadata=None):
62 def publish(self, source, data, metadata=None):
100 if metadata is None:
63 if metadata is None:
101 metadata = {}
64 metadata = {}
102 self._validate_data(source, data, metadata)
65 self._validate_data(source, data, metadata)
103 content = {}
66 content = {}
104 content['source'] = source
67 content['source'] = source
105 _encode_png(data)
68 _encode_png(data)
106 content['data'] = data
69 content['data'] = data
107 content['metadata'] = metadata
70 content['metadata'] = metadata
108 self.session.send(
71 self.session.send(
109 self.pub_socket, u'display_data', content,
72 self.pub_socket, u'display_data', content,
110 parent=self.parent_header
73 parent=self.parent_header
111 )
74 )
112
75
113
76
114 class ZMQInteractiveShell(InteractiveShell):
77 class ZMQInteractiveShell(InteractiveShell):
115 """A subclass of InteractiveShell for ZMQ."""
78 """A subclass of InteractiveShell for ZMQ."""
116
79
117 displayhook_class = Type(ZMQDisplayHook)
80 displayhook_class = Type(ZMQShellDisplayHook)
118 display_pub_class = Type(ZMQDisplayPublisher)
81 display_pub_class = Type(ZMQDisplayPublisher)
119
82
120 exiter = Instance(ZMQExitAutocall)
83 exiter = Instance(ZMQExitAutocall)
121 def _exiter_default(self):
84 def _exiter_default(self):
122 return ZMQExitAutocall(self)
85 return ZMQExitAutocall(self)
123
86
124 keepkernel_on_exit = None
87 keepkernel_on_exit = None
125
88
126 def init_environment(self):
89 def init_environment(self):
127 """Configure the user's environment.
90 """Configure the user's environment.
128
91
129 """
92 """
130 env = os.environ
93 env = os.environ
131 # These two ensure 'ls' produces nice coloring on BSD-derived systems
94 # These two ensure 'ls' produces nice coloring on BSD-derived systems
132 env['TERM'] = 'xterm-color'
95 env['TERM'] = 'xterm-color'
133 env['CLICOLOR'] = '1'
96 env['CLICOLOR'] = '1'
134 # Since normal pagers don't work at all (over pexpect we don't have
97 # Since normal pagers don't work at all (over pexpect we don't have
135 # single-key control of the subprocess), try to disable paging in
98 # single-key control of the subprocess), try to disable paging in
136 # subprocesses as much as possible.
99 # subprocesses as much as possible.
137 env['PAGER'] = 'cat'
100 env['PAGER'] = 'cat'
138 env['GIT_PAGER'] = 'cat'
101 env['GIT_PAGER'] = 'cat'
139
102
140 def auto_rewrite_input(self, cmd):
103 def auto_rewrite_input(self, cmd):
141 """Called to show the auto-rewritten input for autocall and friends.
104 """Called to show the auto-rewritten input for autocall and friends.
142
105
143 FIXME: this payload is currently not correctly processed by the
106 FIXME: this payload is currently not correctly processed by the
144 frontend.
107 frontend.
145 """
108 """
146 new = self.displayhook.prompt1.auto_rewrite() + cmd
109 new = self.displayhook.prompt1.auto_rewrite() + cmd
147 payload = dict(
110 payload = dict(
148 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
111 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
149 transformed_input=new,
112 transformed_input=new,
150 )
113 )
151 self.payload_manager.write_payload(payload)
114 self.payload_manager.write_payload(payload)
152
115
153 def ask_exit(self):
116 def ask_exit(self):
154 """Engage the exit actions."""
117 """Engage the exit actions."""
155 payload = dict(
118 payload = dict(
156 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
119 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
157 exit=True,
120 exit=True,
158 keepkernel=self.keepkernel_on_exit,
121 keepkernel=self.keepkernel_on_exit,
159 )
122 )
160 self.payload_manager.write_payload(payload)
123 self.payload_manager.write_payload(payload)
161
124
162 def _showtraceback(self, etype, evalue, stb):
125 def _showtraceback(self, etype, evalue, stb):
163
126
164 exc_content = {
127 exc_content = {
165 u'traceback' : stb,
128 u'traceback' : stb,
166 u'ename' : unicode(etype.__name__),
129 u'ename' : unicode(etype.__name__),
167 u'evalue' : unicode(evalue)
130 u'evalue' : unicode(evalue)
168 }
131 }
169
132
170 dh = self.displayhook
133 dh = self.displayhook
171 # Send exception info over pub socket for other clients than the caller
134 # Send exception info over pub socket for other clients than the caller
172 # to pick up
135 # to pick up
173 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', exc_content, dh.parent_header)
136 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', exc_content, dh.parent_header)
174
137
175 # FIXME - Hack: store exception info in shell object. Right now, the
138 # FIXME - Hack: store exception info in shell object. Right now, the
176 # caller is reading this info after the fact, we need to fix this logic
139 # caller is reading this info after the fact, we need to fix this logic
177 # to remove this hack. Even uglier, we need to store the error status
140 # to remove this hack. Even uglier, we need to store the error status
178 # here, because in the main loop, the logic that sets it is being
141 # here, because in the main loop, the logic that sets it is being
179 # skipped because runlines swallows the exceptions.
142 # skipped because runlines swallows the exceptions.
180 exc_content[u'status'] = u'error'
143 exc_content[u'status'] = u'error'
181 self._reply_content = exc_content
144 self._reply_content = exc_content
182 # /FIXME
145 # /FIXME
183
146
184 return exc_content
147 return exc_content
185
148
186 #------------------------------------------------------------------------
149 #------------------------------------------------------------------------
187 # Magic overrides
150 # Magic overrides
188 #------------------------------------------------------------------------
151 #------------------------------------------------------------------------
189 # Once the base class stops inheriting from magic, this code needs to be
152 # Once the base class stops inheriting from magic, this code needs to be
190 # moved into a separate machinery as well. For now, at least isolate here
153 # moved into a separate machinery as well. For now, at least isolate here
191 # the magics which this class needs to implement differently from the base
154 # the magics which this class needs to implement differently from the base
192 # class, or that are unique to it.
155 # class, or that are unique to it.
193
156
194 def magic_doctest_mode(self,parameter_s=''):
157 def magic_doctest_mode(self,parameter_s=''):
195 """Toggle doctest mode on and off.
158 """Toggle doctest mode on and off.
196
159
197 This mode is intended to make IPython behave as much as possible like a
160 This mode is intended to make IPython behave as much as possible like a
198 plain Python shell, from the perspective of how its prompts, exceptions
161 plain Python shell, from the perspective of how its prompts, exceptions
199 and output look. This makes it easy to copy and paste parts of a
162 and output look. This makes it easy to copy and paste parts of a
200 session into doctests. It does so by:
163 session into doctests. It does so by:
201
164
202 - Changing the prompts to the classic ``>>>`` ones.
165 - Changing the prompts to the classic ``>>>`` ones.
203 - Changing the exception reporting mode to 'Plain'.
166 - Changing the exception reporting mode to 'Plain'.
204 - Disabling pretty-printing of output.
167 - Disabling pretty-printing of output.
205
168
206 Note that IPython also supports the pasting of code snippets that have
169 Note that IPython also supports the pasting of code snippets that have
207 leading '>>>' and '...' prompts in them. This means that you can paste
170 leading '>>>' and '...' prompts in them. This means that you can paste
208 doctests from files or docstrings (even if they have leading
171 doctests from files or docstrings (even if they have leading
209 whitespace), and the code will execute correctly. You can then use
172 whitespace), and the code will execute correctly. You can then use
210 '%history -t' to see the translated history; this will give you the
173 '%history -t' to see the translated history; this will give you the
211 input after removal of all the leading prompts and whitespace, which
174 input after removal of all the leading prompts and whitespace, which
212 can be pasted back into an editor.
175 can be pasted back into an editor.
213
176
214 With these features, you can switch into this mode easily whenever you
177 With these features, you can switch into this mode easily whenever you
215 need to do testing and changes to doctests, without having to leave
178 need to do testing and changes to doctests, without having to leave
216 your existing IPython session.
179 your existing IPython session.
217 """
180 """
218
181
219 from IPython.utils.ipstruct import Struct
182 from IPython.utils.ipstruct import Struct
220
183
221 # Shorthands
184 # Shorthands
222 shell = self.shell
185 shell = self.shell
223 disp_formatter = self.shell.display_formatter
186 disp_formatter = self.shell.display_formatter
224 ptformatter = disp_formatter.formatters['text/plain']
187 ptformatter = disp_formatter.formatters['text/plain']
225 # dstore is a data store kept in the instance metadata bag to track any
188 # dstore is a data store kept in the instance metadata bag to track any
226 # changes we make, so we can undo them later.
189 # changes we make, so we can undo them later.
227 dstore = shell.meta.setdefault('doctest_mode', Struct())
190 dstore = shell.meta.setdefault('doctest_mode', Struct())
228 save_dstore = dstore.setdefault
191 save_dstore = dstore.setdefault
229
192
230 # save a few values we'll need to recover later
193 # save a few values we'll need to recover later
231 mode = save_dstore('mode', False)
194 mode = save_dstore('mode', False)
232 save_dstore('rc_pprint', ptformatter.pprint)
195 save_dstore('rc_pprint', ptformatter.pprint)
233 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
196 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
234 save_dstore('xmode', shell.InteractiveTB.mode)
197 save_dstore('xmode', shell.InteractiveTB.mode)
235
198
236 if mode == False:
199 if mode == False:
237 # turn on
200 # turn on
238 ptformatter.pprint = False
201 ptformatter.pprint = False
239 disp_formatter.plain_text_only = True
202 disp_formatter.plain_text_only = True
240 shell.magic_xmode('Plain')
203 shell.magic_xmode('Plain')
241 else:
204 else:
242 # turn off
205 # turn off
243 ptformatter.pprint = dstore.rc_pprint
206 ptformatter.pprint = dstore.rc_pprint
244 disp_formatter.plain_text_only = dstore.rc_plain_text_only
207 disp_formatter.plain_text_only = dstore.rc_plain_text_only
245 shell.magic_xmode(dstore.xmode)
208 shell.magic_xmode(dstore.xmode)
246
209
247 # Store new mode and inform on console
210 # Store new mode and inform on console
248 dstore.mode = bool(1-int(mode))
211 dstore.mode = bool(1-int(mode))
249 mode_label = ['OFF','ON'][dstore.mode]
212 mode_label = ['OFF','ON'][dstore.mode]
250 print('Doctest mode is:', mode_label)
213 print('Doctest mode is:', mode_label)
251
214
252 # Send the payload back so that clients can modify their prompt display
215 # Send the payload back so that clients can modify their prompt display
253 payload = dict(
216 payload = dict(
254 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
217 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
255 mode=dstore.mode)
218 mode=dstore.mode)
256 self.payload_manager.write_payload(payload)
219 self.payload_manager.write_payload(payload)
257
220
258 def magic_edit(self,parameter_s='',last_call=['','']):
221 def magic_edit(self,parameter_s='',last_call=['','']):
259 """Bring up an editor and execute the resulting code.
222 """Bring up an editor and execute the resulting code.
260
223
261 Usage:
224 Usage:
262 %edit [options] [args]
225 %edit [options] [args]
263
226
264 %edit runs IPython's editor hook. The default version of this hook is
227 %edit runs IPython's editor hook. The default version of this hook is
265 set to call the __IPYTHON__.rc.editor command. This is read from your
228 set to call the __IPYTHON__.rc.editor command. This is read from your
266 environment variable $EDITOR. If this isn't found, it will default to
229 environment variable $EDITOR. If this isn't found, it will default to
267 vi under Linux/Unix and to notepad under Windows. See the end of this
230 vi under Linux/Unix and to notepad under Windows. See the end of this
268 docstring for how to change the editor hook.
231 docstring for how to change the editor hook.
269
232
270 You can also set the value of this editor via the command line option
233 You can also set the value of this editor via the command line option
271 '-editor' or in your ipythonrc file. This is useful if you wish to use
234 '-editor' or in your ipythonrc file. This is useful if you wish to use
272 specifically for IPython an editor different from your typical default
235 specifically for IPython an editor different from your typical default
273 (and for Windows users who typically don't set environment variables).
236 (and for Windows users who typically don't set environment variables).
274
237
275 This command allows you to conveniently edit multi-line code right in
238 This command allows you to conveniently edit multi-line code right in
276 your IPython session.
239 your IPython session.
277
240
278 If called without arguments, %edit opens up an empty editor with a
241 If called without arguments, %edit opens up an empty editor with a
279 temporary file and will execute the contents of this file when you
242 temporary file and will execute the contents of this file when you
280 close it (don't forget to save it!).
243 close it (don't forget to save it!).
281
244
282
245
283 Options:
246 Options:
284
247
285 -n <number>: open the editor at a specified line number. By default,
248 -n <number>: open the editor at a specified line number. By default,
286 the IPython editor hook uses the unix syntax 'editor +N filename', but
249 the IPython editor hook uses the unix syntax 'editor +N filename', but
287 you can configure this by providing your own modified hook if your
250 you can configure this by providing your own modified hook if your
288 favorite editor supports line-number specifications with a different
251 favorite editor supports line-number specifications with a different
289 syntax.
252 syntax.
290
253
291 -p: this will call the editor with the same data as the previous time
254 -p: this will call the editor with the same data as the previous time
292 it was used, regardless of how long ago (in your current session) it
255 it was used, regardless of how long ago (in your current session) it
293 was.
256 was.
294
257
295 -r: use 'raw' input. This option only applies to input taken from the
258 -r: use 'raw' input. This option only applies to input taken from the
296 user's history. By default, the 'processed' history is used, so that
259 user's history. By default, the 'processed' history is used, so that
297 magics are loaded in their transformed version to valid Python. If
260 magics are loaded in their transformed version to valid Python. If
298 this option is given, the raw input as typed as the command line is
261 this option is given, the raw input as typed as the command line is
299 used instead. When you exit the editor, it will be executed by
262 used instead. When you exit the editor, it will be executed by
300 IPython's own processor.
263 IPython's own processor.
301
264
302 -x: do not execute the edited code immediately upon exit. This is
265 -x: do not execute the edited code immediately upon exit. This is
303 mainly useful if you are editing programs which need to be called with
266 mainly useful if you are editing programs which need to be called with
304 command line arguments, which you can then do using %run.
267 command line arguments, which you can then do using %run.
305
268
306
269
307 Arguments:
270 Arguments:
308
271
309 If arguments are given, the following possibilites exist:
272 If arguments are given, the following possibilites exist:
310
273
311 - The arguments are numbers or pairs of colon-separated numbers (like
274 - The arguments are numbers or pairs of colon-separated numbers (like
312 1 4:8 9). These are interpreted as lines of previous input to be
275 1 4:8 9). These are interpreted as lines of previous input to be
313 loaded into the editor. The syntax is the same of the %macro command.
276 loaded into the editor. The syntax is the same of the %macro command.
314
277
315 - If the argument doesn't start with a number, it is evaluated as a
278 - If the argument doesn't start with a number, it is evaluated as a
316 variable and its contents loaded into the editor. You can thus edit
279 variable and its contents loaded into the editor. You can thus edit
317 any string which contains python code (including the result of
280 any string which contains python code (including the result of
318 previous edits).
281 previous edits).
319
282
320 - If the argument is the name of an object (other than a string),
283 - If the argument is the name of an object (other than a string),
321 IPython will try to locate the file where it was defined and open the
284 IPython will try to locate the file where it was defined and open the
322 editor at the point where it is defined. You can use `%edit function`
285 editor at the point where it is defined. You can use `%edit function`
323 to load an editor exactly at the point where 'function' is defined,
286 to load an editor exactly at the point where 'function' is defined,
324 edit it and have the file be executed automatically.
287 edit it and have the file be executed automatically.
325
288
326 If the object is a macro (see %macro for details), this opens up your
289 If the object is a macro (see %macro for details), this opens up your
327 specified editor with a temporary file containing the macro's data.
290 specified editor with a temporary file containing the macro's data.
328 Upon exit, the macro is reloaded with the contents of the file.
291 Upon exit, the macro is reloaded with the contents of the file.
329
292
330 Note: opening at an exact line is only supported under Unix, and some
293 Note: opening at an exact line is only supported under Unix, and some
331 editors (like kedit and gedit up to Gnome 2.8) do not understand the
294 editors (like kedit and gedit up to Gnome 2.8) do not understand the
332 '+NUMBER' parameter necessary for this feature. Good editors like
295 '+NUMBER' parameter necessary for this feature. Good editors like
333 (X)Emacs, vi, jed, pico and joe all do.
296 (X)Emacs, vi, jed, pico and joe all do.
334
297
335 - If the argument is not found as a variable, IPython will look for a
298 - If the argument is not found as a variable, IPython will look for a
336 file with that name (adding .py if necessary) and load it into the
299 file with that name (adding .py if necessary) and load it into the
337 editor. It will execute its contents with execfile() when you exit,
300 editor. It will execute its contents with execfile() when you exit,
338 loading any code in the file into your interactive namespace.
301 loading any code in the file into your interactive namespace.
339
302
340 After executing your code, %edit will return as output the code you
303 After executing your code, %edit will return as output the code you
341 typed in the editor (except when it was an existing file). This way
304 typed in the editor (except when it was an existing file). This way
342 you can reload the code in further invocations of %edit as a variable,
305 you can reload the code in further invocations of %edit as a variable,
343 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
306 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
344 the output.
307 the output.
345
308
346 Note that %edit is also available through the alias %ed.
309 Note that %edit is also available through the alias %ed.
347
310
348 This is an example of creating a simple function inside the editor and
311 This is an example of creating a simple function inside the editor and
349 then modifying it. First, start up the editor:
312 then modifying it. First, start up the editor:
350
313
351 In [1]: ed
314 In [1]: ed
352 Editing... done. Executing edited code...
315 Editing... done. Executing edited code...
353 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
316 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
354
317
355 We can then call the function foo():
318 We can then call the function foo():
356
319
357 In [2]: foo()
320 In [2]: foo()
358 foo() was defined in an editing session
321 foo() was defined in an editing session
359
322
360 Now we edit foo. IPython automatically loads the editor with the
323 Now we edit foo. IPython automatically loads the editor with the
361 (temporary) file where foo() was previously defined:
324 (temporary) file where foo() was previously defined:
362
325
363 In [3]: ed foo
326 In [3]: ed foo
364 Editing... done. Executing edited code...
327 Editing... done. Executing edited code...
365
328
366 And if we call foo() again we get the modified version:
329 And if we call foo() again we get the modified version:
367
330
368 In [4]: foo()
331 In [4]: foo()
369 foo() has now been changed!
332 foo() has now been changed!
370
333
371 Here is an example of how to edit a code snippet successive
334 Here is an example of how to edit a code snippet successive
372 times. First we call the editor:
335 times. First we call the editor:
373
336
374 In [5]: ed
337 In [5]: ed
375 Editing... done. Executing edited code...
338 Editing... done. Executing edited code...
376 hello
339 hello
377 Out[5]: "print 'hello'n"
340 Out[5]: "print 'hello'n"
378
341
379 Now we call it again with the previous output (stored in _):
342 Now we call it again with the previous output (stored in _):
380
343
381 In [6]: ed _
344 In [6]: ed _
382 Editing... done. Executing edited code...
345 Editing... done. Executing edited code...
383 hello world
346 hello world
384 Out[6]: "print 'hello world'n"
347 Out[6]: "print 'hello world'n"
385
348
386 Now we call it with the output #8 (stored in _8, also as Out[8]):
349 Now we call it with the output #8 (stored in _8, also as Out[8]):
387
350
388 In [7]: ed _8
351 In [7]: ed _8
389 Editing... done. Executing edited code...
352 Editing... done. Executing edited code...
390 hello again
353 hello again
391 Out[7]: "print 'hello again'n"
354 Out[7]: "print 'hello again'n"
392
355
393
356
394 Changing the default editor hook:
357 Changing the default editor hook:
395
358
396 If you wish to write your own editor hook, you can put it in a
359 If you wish to write your own editor hook, you can put it in a
397 configuration file which you load at startup time. The default hook
360 configuration file which you load at startup time. The default hook
398 is defined in the IPython.core.hooks module, and you can use that as a
361 is defined in the IPython.core.hooks module, and you can use that as a
399 starting example for further modifications. That file also has
362 starting example for further modifications. That file also has
400 general instructions on how to set a new hook for use once you've
363 general instructions on how to set a new hook for use once you've
401 defined it."""
364 defined it."""
402
365
403 opts,args = self.parse_options(parameter_s,'prn:')
366 opts,args = self.parse_options(parameter_s,'prn:')
404
367
405 try:
368 try:
406 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
369 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
407 except MacroToEdit as e:
370 except MacroToEdit as e:
408 # TODO: Implement macro editing over 2 processes.
371 # TODO: Implement macro editing over 2 processes.
409 print("Macro editing not yet implemented in 2-process model.")
372 print("Macro editing not yet implemented in 2-process model.")
410 return
373 return
411
374
412 # Make sure we send to the client an absolute path, in case the working
375 # Make sure we send to the client an absolute path, in case the working
413 # directory of client and kernel don't match
376 # directory of client and kernel don't match
414 filename = os.path.abspath(filename)
377 filename = os.path.abspath(filename)
415
378
416 payload = {
379 payload = {
417 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
380 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
418 'filename' : filename,
381 'filename' : filename,
419 'line_number' : lineno
382 'line_number' : lineno
420 }
383 }
421 self.payload_manager.write_payload(payload)
384 self.payload_manager.write_payload(payload)
422
385
423 def magic_gui(self, *args, **kwargs):
386 def magic_gui(self, *args, **kwargs):
424 raise NotImplementedError(
387 raise NotImplementedError(
425 'GUI support must be enabled in command line options.')
388 'GUI support must be enabled in command line options.')
426
389
427 def magic_pylab(self, *args, **kwargs):
390 def magic_pylab(self, *args, **kwargs):
428 raise NotImplementedError(
391 raise NotImplementedError(
429 'pylab support must be enabled in command line options.')
392 'pylab support must be enabled in command line options.')
430
393
431 # A few magics that are adapted to the specifics of using pexpect and a
394 # A few magics that are adapted to the specifics of using pexpect and a
432 # remote terminal
395 # remote terminal
433
396
434 def magic_clear(self, arg_s):
397 def magic_clear(self, arg_s):
435 """Clear the terminal."""
398 """Clear the terminal."""
436 if os.name == 'posix':
399 if os.name == 'posix':
437 self.shell.system("clear")
400 self.shell.system("clear")
438 else:
401 else:
439 self.shell.system("cls")
402 self.shell.system("cls")
440
403
441 if os.name == 'nt':
404 if os.name == 'nt':
442 # This is the usual name in windows
405 # This is the usual name in windows
443 magic_cls = magic_clear
406 magic_cls = magic_clear
444
407
445 # Terminal pagers won't work over pexpect, but we do have our own pager
408 # Terminal pagers won't work over pexpect, but we do have our own pager
446
409
447 def magic_less(self, arg_s):
410 def magic_less(self, arg_s):
448 """Show a file through the pager.
411 """Show a file through the pager.
449
412
450 Files ending in .py are syntax-highlighted."""
413 Files ending in .py are syntax-highlighted."""
451 cont = open(arg_s).read()
414 cont = open(arg_s).read()
452 if arg_s.endswith('.py'):
415 if arg_s.endswith('.py'):
453 cont = self.shell.pycolorize(cont)
416 cont = self.shell.pycolorize(cont)
454 page.page(cont)
417 page.page(cont)
455
418
456 magic_more = magic_less
419 magic_more = magic_less
457
420
458 # Man calls a pager, so we also need to redefine it
421 # Man calls a pager, so we also need to redefine it
459 if os.name == 'posix':
422 if os.name == 'posix':
460 def magic_man(self, arg_s):
423 def magic_man(self, arg_s):
461 """Find the man page for the given command and display in pager."""
424 """Find the man page for the given command and display in pager."""
462 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
425 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
463 split=False))
426 split=False))
464
427
465 # FIXME: this is specific to the GUI, so we should let the gui app load
428 # FIXME: this is specific to the GUI, so we should let the gui app load
466 # magics at startup that are only for the gui. Once the gui app has proper
429 # magics at startup that are only for the gui. Once the gui app has proper
467 # profile and configuration management, we can have it initialize a kernel
430 # profile and configuration management, we can have it initialize a kernel
468 # with a special config file that provides these.
431 # with a special config file that provides these.
469 def magic_guiref(self, arg_s):
432 def magic_guiref(self, arg_s):
470 """Show a basic reference about the GUI console."""
433 """Show a basic reference about the GUI console."""
471 from IPython.core.usage import gui_reference
434 from IPython.core.usage import gui_reference
472 page.page(gui_reference, auto_html=True)
435 page.page(gui_reference, auto_html=True)
473
436
474 def set_next_input(self, text):
437 def set_next_input(self, text):
475 """Send the specified text to the frontend to be presented at the next
438 """Send the specified text to the frontend to be presented at the next
476 input cell."""
439 input cell."""
477 payload = dict(
440 payload = dict(
478 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
441 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
479 text=text
442 text=text
480 )
443 )
481 self.payload_manager.write_payload(payload)
444 self.payload_manager.write_payload(payload)
482
445
483 InteractiveShellABC.register(ZMQInteractiveShell)
446 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now