##// END OF EJS Templates
displaypub b64 encoding is non-destructive...
MinRK -
Show More
@@ -1,73 +1,75 b''
1 import __builtin__
1 import __builtin__
2 import sys
2 import sys
3 from base64 import encodestring
3 from base64 import encodestring
4
4
5 from IPython.core.displayhook import DisplayHook
5 from IPython.core.displayhook import DisplayHook
6 from IPython.utils.traitlets import Instance, Dict
6 from IPython.utils.traitlets import Instance, Dict
7 from session import extract_header, Session
7 from session import extract_header, Session
8
8
9 class ZMQDisplayHook(object):
9 class ZMQDisplayHook(object):
10 """A simple displayhook that publishes the object's repr over a ZeroMQ
10 """A simple displayhook that publishes the object's repr over a ZeroMQ
11 socket."""
11 socket."""
12 topic=None
12 topic=None
13
13
14 def __init__(self, session, pub_socket):
14 def __init__(self, session, pub_socket):
15 self.session = session
15 self.session = session
16 self.pub_socket = pub_socket
16 self.pub_socket = pub_socket
17 self.parent_header = {}
17 self.parent_header = {}
18
18
19 def __call__(self, obj):
19 def __call__(self, obj):
20 if obj is None:
20 if obj is None:
21 return
21 return
22
22
23 __builtin__._ = obj
23 __builtin__._ = obj
24 sys.stdout.flush()
24 sys.stdout.flush()
25 sys.stderr.flush()
25 sys.stderr.flush()
26 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
26 msg = self.session.send(self.pub_socket, u'pyout', {u'data':repr(obj)},
27 parent=self.parent_header, ident=self.topic)
27 parent=self.parent_header, ident=self.topic)
28
28
29 def set_parent(self, parent):
29 def set_parent(self, parent):
30 self.parent_header = extract_header(parent)
30 self.parent_header = extract_header(parent)
31
31
32
32
33 def _encode_binary(format_dict):
33 def _encode_binary(format_dict):
34 encoded = format_dict.copy()
34 pngdata = format_dict.get('image/png')
35 pngdata = format_dict.get('image/png')
35 if pngdata is not None:
36 if isinstance(pngdata, bytes):
36 format_dict['image/png'] = encodestring(pngdata).decode('ascii')
37 encoded['image/png'] = encodestring(pngdata).decode('ascii')
37 jpegdata = format_dict.get('image/jpeg')
38 jpegdata = format_dict.get('image/jpeg')
38 if jpegdata is not None:
39 if isinstance(jpegdata, bytes):
39 format_dict['image/jpeg'] = encodestring(jpegdata).decode('ascii')
40 encoded['image/jpeg'] = encodestring(jpegdata).decode('ascii')
41
42 return encoded
40
43
41
44
42 class ZMQShellDisplayHook(DisplayHook):
45 class ZMQShellDisplayHook(DisplayHook):
43 """A displayhook subclass that publishes data using ZeroMQ. This is intended
46 """A displayhook subclass that publishes data using ZeroMQ. This is intended
44 to work with an InteractiveShell instance. It sends a dict of different
47 to work with an InteractiveShell instance. It sends a dict of different
45 representations of the object."""
48 representations of the object."""
46 topic=None
49 topic=None
47
50
48 session = Instance(Session)
51 session = Instance(Session)
49 pub_socket = Instance('zmq.Socket')
52 pub_socket = Instance('zmq.Socket')
50 parent_header = Dict({})
53 parent_header = Dict({})
51
54
52 def set_parent(self, parent):
55 def set_parent(self, parent):
53 """Set the parent for outbound messages."""
56 """Set the parent for outbound messages."""
54 self.parent_header = extract_header(parent)
57 self.parent_header = extract_header(parent)
55
58
56 def start_displayhook(self):
59 def start_displayhook(self):
57 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
60 self.msg = self.session.msg(u'pyout', {}, parent=self.parent_header)
58
61
59 def write_output_prompt(self):
62 def write_output_prompt(self):
60 """Write the output prompt."""
63 """Write the output prompt."""
61 self.msg['content']['execution_count'] = self.prompt_count
64 self.msg['content']['execution_count'] = self.prompt_count
62
65
63 def write_format_data(self, format_dict):
66 def write_format_data(self, format_dict):
64 _encode_binary(format_dict)
67 self.msg['content']['data'] = _encode_binary(format_dict)
65 self.msg['content']['data'] = format_dict
66
68
67 def finish_displayhook(self):
69 def finish_displayhook(self):
68 """Finish up all displayhook activities."""
70 """Finish up all displayhook activities."""
69 sys.stdout.flush()
71 sys.stdout.flush()
70 sys.stderr.flush()
72 sys.stderr.flush()
71 self.session.send(self.pub_socket, self.msg, ident=self.topic)
73 self.session.send(self.pub_socket, self.msg, ident=self.topic)
72 self.msg = None
74 self.msg = None
73
75
@@ -1,540 +1,539 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 import inspect
19 import inspect
20 import os
20 import os
21 import sys
21 import sys
22 import time
22 import time
23 from subprocess import Popen, PIPE
23 from subprocess import Popen, PIPE
24
24
25 # System library imports
25 # System library imports
26 from zmq.eventloop import ioloop
26 from zmq.eventloop import ioloop
27
27
28 # Our own
28 # Our own
29 from IPython.core.interactiveshell import (
29 from IPython.core.interactiveshell import (
30 InteractiveShell, InteractiveShellABC
30 InteractiveShell, InteractiveShellABC
31 )
31 )
32 from IPython.core import page, pylabtools
32 from IPython.core import page, pylabtools
33 from IPython.core.autocall import ZMQExitAutocall
33 from IPython.core.autocall import ZMQExitAutocall
34 from IPython.core.displaypub import DisplayPublisher
34 from IPython.core.displaypub import DisplayPublisher
35 from IPython.core.macro import Macro
35 from IPython.core.macro import Macro
36 from IPython.core.magics import MacroToEdit
36 from IPython.core.magics import MacroToEdit
37 from IPython.core.payloadpage import install_payload_page
37 from IPython.core.payloadpage import install_payload_page
38 from IPython.lib.kernel import (
38 from IPython.lib.kernel import (
39 get_connection_file, get_connection_info, connect_qtconsole
39 get_connection_file, get_connection_info, connect_qtconsole
40 )
40 )
41 from IPython.testing.skipdoctest import skip_doctest
41 from IPython.testing.skipdoctest import skip_doctest
42 from IPython.utils import io
42 from IPython.utils import io
43 from IPython.utils.jsonutil import json_clean
43 from IPython.utils.jsonutil import json_clean
44 from IPython.utils.path import get_py_filename
44 from IPython.utils.path import get_py_filename
45 from IPython.utils.process import arg_split
45 from IPython.utils.process import arg_split
46 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
46 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
47 from IPython.utils.warn import warn, error
47 from IPython.utils.warn import warn, error
48 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
48 from IPython.zmq.displayhook import ZMQShellDisplayHook, _encode_binary
49 from IPython.zmq.session import extract_header
49 from IPython.zmq.session import extract_header
50 from session import Session
50 from session import Session
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Functions and classes
53 # Functions and classes
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 class ZMQDisplayPublisher(DisplayPublisher):
56 class ZMQDisplayPublisher(DisplayPublisher):
57 """A display publisher that publishes data using a ZeroMQ PUB socket."""
57 """A display publisher that publishes data using a ZeroMQ PUB socket."""
58
58
59 session = Instance(Session)
59 session = Instance(Session)
60 pub_socket = Instance('zmq.Socket')
60 pub_socket = Instance('zmq.Socket')
61 parent_header = Dict({})
61 parent_header = Dict({})
62 topic = CBytes(b'displaypub')
62 topic = CBytes(b'displaypub')
63
63
64 def set_parent(self, parent):
64 def set_parent(self, parent):
65 """Set the parent for outbound messages."""
65 """Set the parent for outbound messages."""
66 self.parent_header = extract_header(parent)
66 self.parent_header = extract_header(parent)
67
67
68 def _flush_streams(self):
68 def _flush_streams(self):
69 """flush IO Streams prior to display"""
69 """flush IO Streams prior to display"""
70 sys.stdout.flush()
70 sys.stdout.flush()
71 sys.stderr.flush()
71 sys.stderr.flush()
72
72
73 def publish(self, source, data, metadata=None):
73 def publish(self, source, data, metadata=None):
74 self._flush_streams()
74 self._flush_streams()
75 if metadata is None:
75 if metadata is None:
76 metadata = {}
76 metadata = {}
77 self._validate_data(source, data, metadata)
77 self._validate_data(source, data, metadata)
78 content = {}
78 content = {}
79 content['source'] = source
79 content['source'] = source
80 _encode_binary(data)
80 content['data'] = _encode_binary(data)
81 content['data'] = data
82 content['metadata'] = metadata
81 content['metadata'] = metadata
83 self.session.send(
82 self.session.send(
84 self.pub_socket, u'display_data', json_clean(content),
83 self.pub_socket, u'display_data', json_clean(content),
85 parent=self.parent_header, ident=self.topic,
84 parent=self.parent_header, ident=self.topic,
86 )
85 )
87
86
88 def clear_output(self, stdout=True, stderr=True, other=True):
87 def clear_output(self, stdout=True, stderr=True, other=True):
89 content = dict(stdout=stdout, stderr=stderr, other=other)
88 content = dict(stdout=stdout, stderr=stderr, other=other)
90
89
91 if stdout:
90 if stdout:
92 print('\r', file=sys.stdout, end='')
91 print('\r', file=sys.stdout, end='')
93 if stderr:
92 if stderr:
94 print('\r', file=sys.stderr, end='')
93 print('\r', file=sys.stderr, end='')
95
94
96 self._flush_streams()
95 self._flush_streams()
97
96
98 self.session.send(
97 self.session.send(
99 self.pub_socket, u'clear_output', content,
98 self.pub_socket, u'clear_output', content,
100 parent=self.parent_header, ident=self.topic,
99 parent=self.parent_header, ident=self.topic,
101 )
100 )
102
101
103 class ZMQInteractiveShell(InteractiveShell):
102 class ZMQInteractiveShell(InteractiveShell):
104 """A subclass of InteractiveShell for ZMQ."""
103 """A subclass of InteractiveShell for ZMQ."""
105
104
106 displayhook_class = Type(ZMQShellDisplayHook)
105 displayhook_class = Type(ZMQShellDisplayHook)
107 display_pub_class = Type(ZMQDisplayPublisher)
106 display_pub_class = Type(ZMQDisplayPublisher)
108
107
109 # Override the traitlet in the parent class, because there's no point using
108 # Override the traitlet in the parent class, because there's no point using
110 # readline for the kernel. Can be removed when the readline code is moved
109 # readline for the kernel. Can be removed when the readline code is moved
111 # to the terminal frontend.
110 # to the terminal frontend.
112 colors_force = CBool(True)
111 colors_force = CBool(True)
113 readline_use = CBool(False)
112 readline_use = CBool(False)
114 # autoindent has no meaning in a zmqshell, and attempting to enable it
113 # autoindent has no meaning in a zmqshell, and attempting to enable it
115 # will print a warning in the absence of readline.
114 # will print a warning in the absence of readline.
116 autoindent = CBool(False)
115 autoindent = CBool(False)
117
116
118 exiter = Instance(ZMQExitAutocall)
117 exiter = Instance(ZMQExitAutocall)
119 def _exiter_default(self):
118 def _exiter_default(self):
120 return ZMQExitAutocall(self)
119 return ZMQExitAutocall(self)
121
120
122 def _exit_now_changed(self, name, old, new):
121 def _exit_now_changed(self, name, old, new):
123 """stop eventloop when exit_now fires"""
122 """stop eventloop when exit_now fires"""
124 if new:
123 if new:
125 loop = ioloop.IOLoop.instance()
124 loop = ioloop.IOLoop.instance()
126 loop.add_timeout(time.time()+0.1, loop.stop)
125 loop.add_timeout(time.time()+0.1, loop.stop)
127
126
128 keepkernel_on_exit = None
127 keepkernel_on_exit = None
129
128
130 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
129 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
131 # interactive input being read; we provide event loop support in ipkernel
130 # interactive input being read; we provide event loop support in ipkernel
132 from .eventloops import enable_gui
131 from .eventloops import enable_gui
133 enable_gui = staticmethod(enable_gui)
132 enable_gui = staticmethod(enable_gui)
134
133
135 def init_environment(self):
134 def init_environment(self):
136 """Configure the user's environment.
135 """Configure the user's environment.
137
136
138 """
137 """
139 env = os.environ
138 env = os.environ
140 # These two ensure 'ls' produces nice coloring on BSD-derived systems
139 # These two ensure 'ls' produces nice coloring on BSD-derived systems
141 env['TERM'] = 'xterm-color'
140 env['TERM'] = 'xterm-color'
142 env['CLICOLOR'] = '1'
141 env['CLICOLOR'] = '1'
143 # Since normal pagers don't work at all (over pexpect we don't have
142 # Since normal pagers don't work at all (over pexpect we don't have
144 # single-key control of the subprocess), try to disable paging in
143 # single-key control of the subprocess), try to disable paging in
145 # subprocesses as much as possible.
144 # subprocesses as much as possible.
146 env['PAGER'] = 'cat'
145 env['PAGER'] = 'cat'
147 env['GIT_PAGER'] = 'cat'
146 env['GIT_PAGER'] = 'cat'
148
147
149 # And install the payload version of page.
148 # And install the payload version of page.
150 install_payload_page()
149 install_payload_page()
151
150
152 def auto_rewrite_input(self, cmd):
151 def auto_rewrite_input(self, cmd):
153 """Called to show the auto-rewritten input for autocall and friends.
152 """Called to show the auto-rewritten input for autocall and friends.
154
153
155 FIXME: this payload is currently not correctly processed by the
154 FIXME: this payload is currently not correctly processed by the
156 frontend.
155 frontend.
157 """
156 """
158 new = self.prompt_manager.render('rewrite') + cmd
157 new = self.prompt_manager.render('rewrite') + cmd
159 payload = dict(
158 payload = dict(
160 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
159 source='IPython.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
161 transformed_input=new,
160 transformed_input=new,
162 )
161 )
163 self.payload_manager.write_payload(payload)
162 self.payload_manager.write_payload(payload)
164
163
165 def ask_exit(self):
164 def ask_exit(self):
166 """Engage the exit actions."""
165 """Engage the exit actions."""
167 self.exit_now = True
166 self.exit_now = True
168 payload = dict(
167 payload = dict(
169 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
168 source='IPython.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
170 exit=True,
169 exit=True,
171 keepkernel=self.keepkernel_on_exit,
170 keepkernel=self.keepkernel_on_exit,
172 )
171 )
173 self.payload_manager.write_payload(payload)
172 self.payload_manager.write_payload(payload)
174
173
175 def _showtraceback(self, etype, evalue, stb):
174 def _showtraceback(self, etype, evalue, stb):
176
175
177 exc_content = {
176 exc_content = {
178 u'traceback' : stb,
177 u'traceback' : stb,
179 u'ename' : unicode(etype.__name__),
178 u'ename' : unicode(etype.__name__),
180 u'evalue' : unicode(evalue)
179 u'evalue' : unicode(evalue)
181 }
180 }
182
181
183 dh = self.displayhook
182 dh = self.displayhook
184 # Send exception info over pub socket for other clients than the caller
183 # Send exception info over pub socket for other clients than the caller
185 # to pick up
184 # to pick up
186 topic = None
185 topic = None
187 if dh.topic:
186 if dh.topic:
188 topic = dh.topic.replace(b'pyout', b'pyerr')
187 topic = dh.topic.replace(b'pyout', b'pyerr')
189
188
190 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
189 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
191
190
192 # FIXME - Hack: store exception info in shell object. Right now, the
191 # FIXME - Hack: store exception info in shell object. Right now, the
193 # caller is reading this info after the fact, we need to fix this logic
192 # caller is reading this info after the fact, we need to fix this logic
194 # to remove this hack. Even uglier, we need to store the error status
193 # to remove this hack. Even uglier, we need to store the error status
195 # here, because in the main loop, the logic that sets it is being
194 # here, because in the main loop, the logic that sets it is being
196 # skipped because runlines swallows the exceptions.
195 # skipped because runlines swallows the exceptions.
197 exc_content[u'status'] = u'error'
196 exc_content[u'status'] = u'error'
198 self._reply_content = exc_content
197 self._reply_content = exc_content
199 # /FIXME
198 # /FIXME
200
199
201 return exc_content
200 return exc_content
202
201
203 #------------------------------------------------------------------------
202 #------------------------------------------------------------------------
204 # Magic overrides
203 # Magic overrides
205 #------------------------------------------------------------------------
204 #------------------------------------------------------------------------
206 # Once the base class stops inheriting from magic, this code needs to be
205 # Once the base class stops inheriting from magic, this code needs to be
207 # moved into a separate machinery as well. For now, at least isolate here
206 # moved into a separate machinery as well. For now, at least isolate here
208 # the magics which this class needs to implement differently from the base
207 # the magics which this class needs to implement differently from the base
209 # class, or that are unique to it.
208 # class, or that are unique to it.
210
209
211 def magic_doctest_mode(self,parameter_s=''):
210 def magic_doctest_mode(self,parameter_s=''):
212 """Toggle doctest mode on and off.
211 """Toggle doctest mode on and off.
213
212
214 This mode is intended to make IPython behave as much as possible like a
213 This mode is intended to make IPython behave as much as possible like a
215 plain Python shell, from the perspective of how its prompts, exceptions
214 plain Python shell, from the perspective of how its prompts, exceptions
216 and output look. This makes it easy to copy and paste parts of a
215 and output look. This makes it easy to copy and paste parts of a
217 session into doctests. It does so by:
216 session into doctests. It does so by:
218
217
219 - Changing the prompts to the classic ``>>>`` ones.
218 - Changing the prompts to the classic ``>>>`` ones.
220 - Changing the exception reporting mode to 'Plain'.
219 - Changing the exception reporting mode to 'Plain'.
221 - Disabling pretty-printing of output.
220 - Disabling pretty-printing of output.
222
221
223 Note that IPython also supports the pasting of code snippets that have
222 Note that IPython also supports the pasting of code snippets that have
224 leading '>>>' and '...' prompts in them. This means that you can paste
223 leading '>>>' and '...' prompts in them. This means that you can paste
225 doctests from files or docstrings (even if they have leading
224 doctests from files or docstrings (even if they have leading
226 whitespace), and the code will execute correctly. You can then use
225 whitespace), and the code will execute correctly. You can then use
227 '%history -t' to see the translated history; this will give you the
226 '%history -t' to see the translated history; this will give you the
228 input after removal of all the leading prompts and whitespace, which
227 input after removal of all the leading prompts and whitespace, which
229 can be pasted back into an editor.
228 can be pasted back into an editor.
230
229
231 With these features, you can switch into this mode easily whenever you
230 With these features, you can switch into this mode easily whenever you
232 need to do testing and changes to doctests, without having to leave
231 need to do testing and changes to doctests, without having to leave
233 your existing IPython session.
232 your existing IPython session.
234 """
233 """
235
234
236 from IPython.utils.ipstruct import Struct
235 from IPython.utils.ipstruct import Struct
237
236
238 # Shorthands
237 # Shorthands
239 shell = self.shell
238 shell = self.shell
240 disp_formatter = self.shell.display_formatter
239 disp_formatter = self.shell.display_formatter
241 ptformatter = disp_formatter.formatters['text/plain']
240 ptformatter = disp_formatter.formatters['text/plain']
242 # dstore is a data store kept in the instance metadata bag to track any
241 # dstore is a data store kept in the instance metadata bag to track any
243 # changes we make, so we can undo them later.
242 # changes we make, so we can undo them later.
244 dstore = shell.meta.setdefault('doctest_mode', Struct())
243 dstore = shell.meta.setdefault('doctest_mode', Struct())
245 save_dstore = dstore.setdefault
244 save_dstore = dstore.setdefault
246
245
247 # save a few values we'll need to recover later
246 # save a few values we'll need to recover later
248 mode = save_dstore('mode', False)
247 mode = save_dstore('mode', False)
249 save_dstore('rc_pprint', ptformatter.pprint)
248 save_dstore('rc_pprint', ptformatter.pprint)
250 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
249 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
251 save_dstore('xmode', shell.InteractiveTB.mode)
250 save_dstore('xmode', shell.InteractiveTB.mode)
252
251
253 if mode == False:
252 if mode == False:
254 # turn on
253 # turn on
255 ptformatter.pprint = False
254 ptformatter.pprint = False
256 disp_formatter.plain_text_only = True
255 disp_formatter.plain_text_only = True
257 shell.magic_xmode('Plain')
256 shell.magic_xmode('Plain')
258 else:
257 else:
259 # turn off
258 # turn off
260 ptformatter.pprint = dstore.rc_pprint
259 ptformatter.pprint = dstore.rc_pprint
261 disp_formatter.plain_text_only = dstore.rc_plain_text_only
260 disp_formatter.plain_text_only = dstore.rc_plain_text_only
262 shell.magic_xmode(dstore.xmode)
261 shell.magic_xmode(dstore.xmode)
263
262
264 # Store new mode and inform on console
263 # Store new mode and inform on console
265 dstore.mode = bool(1-int(mode))
264 dstore.mode = bool(1-int(mode))
266 mode_label = ['OFF','ON'][dstore.mode]
265 mode_label = ['OFF','ON'][dstore.mode]
267 print('Doctest mode is:', mode_label)
266 print('Doctest mode is:', mode_label)
268
267
269 # Send the payload back so that clients can modify their prompt display
268 # Send the payload back so that clients can modify their prompt display
270 payload = dict(
269 payload = dict(
271 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
270 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
272 mode=dstore.mode)
271 mode=dstore.mode)
273 self.payload_manager.write_payload(payload)
272 self.payload_manager.write_payload(payload)
274
273
275 @skip_doctest
274 @skip_doctest
276 def magic_edit(self,parameter_s='',last_call=['','']):
275 def magic_edit(self,parameter_s='',last_call=['','']):
277 """Bring up an editor and execute the resulting code.
276 """Bring up an editor and execute the resulting code.
278
277
279 Usage:
278 Usage:
280 %edit [options] [args]
279 %edit [options] [args]
281
280
282 %edit runs an external text editor. You will need to set the command for
281 %edit runs an external text editor. You will need to set the command for
283 this editor via the ``TerminalInteractiveShell.editor`` option in your
282 this editor via the ``TerminalInteractiveShell.editor`` option in your
284 configuration file before it will work.
283 configuration file before it will work.
285
284
286 This command allows you to conveniently edit multi-line code right in
285 This command allows you to conveniently edit multi-line code right in
287 your IPython session.
286 your IPython session.
288
287
289 If called without arguments, %edit opens up an empty editor with a
288 If called without arguments, %edit opens up an empty editor with a
290 temporary file and will execute the contents of this file when you
289 temporary file and will execute the contents of this file when you
291 close it (don't forget to save it!).
290 close it (don't forget to save it!).
292
291
293
292
294 Options:
293 Options:
295
294
296 -n <number>: open the editor at a specified line number. By default,
295 -n <number>: open the editor at a specified line number. By default,
297 the IPython editor hook uses the unix syntax 'editor +N filename', but
296 the IPython editor hook uses the unix syntax 'editor +N filename', but
298 you can configure this by providing your own modified hook if your
297 you can configure this by providing your own modified hook if your
299 favorite editor supports line-number specifications with a different
298 favorite editor supports line-number specifications with a different
300 syntax.
299 syntax.
301
300
302 -p: this will call the editor with the same data as the previous time
301 -p: this will call the editor with the same data as the previous time
303 it was used, regardless of how long ago (in your current session) it
302 it was used, regardless of how long ago (in your current session) it
304 was.
303 was.
305
304
306 -r: use 'raw' input. This option only applies to input taken from the
305 -r: use 'raw' input. This option only applies to input taken from the
307 user's history. By default, the 'processed' history is used, so that
306 user's history. By default, the 'processed' history is used, so that
308 magics are loaded in their transformed version to valid Python. If
307 magics are loaded in their transformed version to valid Python. If
309 this option is given, the raw input as typed as the command line is
308 this option is given, the raw input as typed as the command line is
310 used instead. When you exit the editor, it will be executed by
309 used instead. When you exit the editor, it will be executed by
311 IPython's own processor.
310 IPython's own processor.
312
311
313 -x: do not execute the edited code immediately upon exit. This is
312 -x: do not execute the edited code immediately upon exit. This is
314 mainly useful if you are editing programs which need to be called with
313 mainly useful if you are editing programs which need to be called with
315 command line arguments, which you can then do using %run.
314 command line arguments, which you can then do using %run.
316
315
317
316
318 Arguments:
317 Arguments:
319
318
320 If arguments are given, the following possibilites exist:
319 If arguments are given, the following possibilites exist:
321
320
322 - The arguments are numbers or pairs of colon-separated numbers (like
321 - The arguments are numbers or pairs of colon-separated numbers (like
323 1 4:8 9). These are interpreted as lines of previous input to be
322 1 4:8 9). These are interpreted as lines of previous input to be
324 loaded into the editor. The syntax is the same of the %macro command.
323 loaded into the editor. The syntax is the same of the %macro command.
325
324
326 - If the argument doesn't start with a number, it is evaluated as a
325 - If the argument doesn't start with a number, it is evaluated as a
327 variable and its contents loaded into the editor. You can thus edit
326 variable and its contents loaded into the editor. You can thus edit
328 any string which contains python code (including the result of
327 any string which contains python code (including the result of
329 previous edits).
328 previous edits).
330
329
331 - If the argument is the name of an object (other than a string),
330 - If the argument is the name of an object (other than a string),
332 IPython will try to locate the file where it was defined and open the
331 IPython will try to locate the file where it was defined and open the
333 editor at the point where it is defined. You can use `%edit function`
332 editor at the point where it is defined. You can use `%edit function`
334 to load an editor exactly at the point where 'function' is defined,
333 to load an editor exactly at the point where 'function' is defined,
335 edit it and have the file be executed automatically.
334 edit it and have the file be executed automatically.
336
335
337 If the object is a macro (see %macro for details), this opens up your
336 If the object is a macro (see %macro for details), this opens up your
338 specified editor with a temporary file containing the macro's data.
337 specified editor with a temporary file containing the macro's data.
339 Upon exit, the macro is reloaded with the contents of the file.
338 Upon exit, the macro is reloaded with the contents of the file.
340
339
341 Note: opening at an exact line is only supported under Unix, and some
340 Note: opening at an exact line is only supported under Unix, and some
342 editors (like kedit and gedit up to Gnome 2.8) do not understand the
341 editors (like kedit and gedit up to Gnome 2.8) do not understand the
343 '+NUMBER' parameter necessary for this feature. Good editors like
342 '+NUMBER' parameter necessary for this feature. Good editors like
344 (X)Emacs, vi, jed, pico and joe all do.
343 (X)Emacs, vi, jed, pico and joe all do.
345
344
346 - If the argument is not found as a variable, IPython will look for a
345 - If the argument is not found as a variable, IPython will look for a
347 file with that name (adding .py if necessary) and load it into the
346 file with that name (adding .py if necessary) and load it into the
348 editor. It will execute its contents with execfile() when you exit,
347 editor. It will execute its contents with execfile() when you exit,
349 loading any code in the file into your interactive namespace.
348 loading any code in the file into your interactive namespace.
350
349
351 After executing your code, %edit will return as output the code you
350 After executing your code, %edit will return as output the code you
352 typed in the editor (except when it was an existing file). This way
351 typed in the editor (except when it was an existing file). This way
353 you can reload the code in further invocations of %edit as a variable,
352 you can reload the code in further invocations of %edit as a variable,
354 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
353 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
355 the output.
354 the output.
356
355
357 Note that %edit is also available through the alias %ed.
356 Note that %edit is also available through the alias %ed.
358
357
359 This is an example of creating a simple function inside the editor and
358 This is an example of creating a simple function inside the editor and
360 then modifying it. First, start up the editor:
359 then modifying it. First, start up the editor:
361
360
362 In [1]: ed
361 In [1]: ed
363 Editing... done. Executing edited code...
362 Editing... done. Executing edited code...
364 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
363 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
365
364
366 We can then call the function foo():
365 We can then call the function foo():
367
366
368 In [2]: foo()
367 In [2]: foo()
369 foo() was defined in an editing session
368 foo() was defined in an editing session
370
369
371 Now we edit foo. IPython automatically loads the editor with the
370 Now we edit foo. IPython automatically loads the editor with the
372 (temporary) file where foo() was previously defined:
371 (temporary) file where foo() was previously defined:
373
372
374 In [3]: ed foo
373 In [3]: ed foo
375 Editing... done. Executing edited code...
374 Editing... done. Executing edited code...
376
375
377 And if we call foo() again we get the modified version:
376 And if we call foo() again we get the modified version:
378
377
379 In [4]: foo()
378 In [4]: foo()
380 foo() has now been changed!
379 foo() has now been changed!
381
380
382 Here is an example of how to edit a code snippet successive
381 Here is an example of how to edit a code snippet successive
383 times. First we call the editor:
382 times. First we call the editor:
384
383
385 In [5]: ed
384 In [5]: ed
386 Editing... done. Executing edited code...
385 Editing... done. Executing edited code...
387 hello
386 hello
388 Out[5]: "print 'hello'n"
387 Out[5]: "print 'hello'n"
389
388
390 Now we call it again with the previous output (stored in _):
389 Now we call it again with the previous output (stored in _):
391
390
392 In [6]: ed _
391 In [6]: ed _
393 Editing... done. Executing edited code...
392 Editing... done. Executing edited code...
394 hello world
393 hello world
395 Out[6]: "print 'hello world'n"
394 Out[6]: "print 'hello world'n"
396
395
397 Now we call it with the output #8 (stored in _8, also as Out[8]):
396 Now we call it with the output #8 (stored in _8, also as Out[8]):
398
397
399 In [7]: ed _8
398 In [7]: ed _8
400 Editing... done. Executing edited code...
399 Editing... done. Executing edited code...
401 hello again
400 hello again
402 Out[7]: "print 'hello again'n"
401 Out[7]: "print 'hello again'n"
403 """
402 """
404
403
405 opts,args = self.parse_options(parameter_s,'prn:')
404 opts,args = self.parse_options(parameter_s,'prn:')
406
405
407 try:
406 try:
408 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
407 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
409 except MacroToEdit as e:
408 except MacroToEdit as e:
410 # TODO: Implement macro editing over 2 processes.
409 # TODO: Implement macro editing over 2 processes.
411 print("Macro editing not yet implemented in 2-process model.")
410 print("Macro editing not yet implemented in 2-process model.")
412 return
411 return
413
412
414 # Make sure we send to the client an absolute path, in case the working
413 # Make sure we send to the client an absolute path, in case the working
415 # directory of client and kernel don't match
414 # directory of client and kernel don't match
416 filename = os.path.abspath(filename)
415 filename = os.path.abspath(filename)
417
416
418 payload = {
417 payload = {
419 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
418 'source' : 'IPython.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
420 'filename' : filename,
419 'filename' : filename,
421 'line_number' : lineno
420 'line_number' : lineno
422 }
421 }
423 self.payload_manager.write_payload(payload)
422 self.payload_manager.write_payload(payload)
424
423
425 # A few magics that are adapted to the specifics of using pexpect and a
424 # A few magics that are adapted to the specifics of using pexpect and a
426 # remote terminal
425 # remote terminal
427
426
428 def magic_clear(self, arg_s):
427 def magic_clear(self, arg_s):
429 """Clear the terminal."""
428 """Clear the terminal."""
430 if os.name == 'posix':
429 if os.name == 'posix':
431 self.shell.system("clear")
430 self.shell.system("clear")
432 else:
431 else:
433 self.shell.system("cls")
432 self.shell.system("cls")
434
433
435 if os.name == 'nt':
434 if os.name == 'nt':
436 # This is the usual name in windows
435 # This is the usual name in windows
437 magic_cls = magic_clear
436 magic_cls = magic_clear
438
437
439 # Terminal pagers won't work over pexpect, but we do have our own pager
438 # Terminal pagers won't work over pexpect, but we do have our own pager
440
439
441 def magic_less(self, arg_s):
440 def magic_less(self, arg_s):
442 """Show a file through the pager.
441 """Show a file through the pager.
443
442
444 Files ending in .py are syntax-highlighted."""
443 Files ending in .py are syntax-highlighted."""
445 cont = open(arg_s).read()
444 cont = open(arg_s).read()
446 if arg_s.endswith('.py'):
445 if arg_s.endswith('.py'):
447 cont = self.shell.pycolorize(cont)
446 cont = self.shell.pycolorize(cont)
448 page.page(cont)
447 page.page(cont)
449
448
450 magic_more = magic_less
449 magic_more = magic_less
451
450
452 # Man calls a pager, so we also need to redefine it
451 # Man calls a pager, so we also need to redefine it
453 if os.name == 'posix':
452 if os.name == 'posix':
454 def magic_man(self, arg_s):
453 def magic_man(self, arg_s):
455 """Find the man page for the given command and display in pager."""
454 """Find the man page for the given command and display in pager."""
456 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
455 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
457 split=False))
456 split=False))
458
457
459 # FIXME: this is specific to the GUI, so we should let the gui app load
458 # FIXME: this is specific to the GUI, so we should let the gui app load
460 # magics at startup that are only for the gui. Once the gui app has proper
459 # magics at startup that are only for the gui. Once the gui app has proper
461 # profile and configuration management, we can have it initialize a kernel
460 # profile and configuration management, we can have it initialize a kernel
462 # with a special config file that provides these.
461 # with a special config file that provides these.
463 def magic_guiref(self, arg_s):
462 def magic_guiref(self, arg_s):
464 """Show a basic reference about the GUI console."""
463 """Show a basic reference about the GUI console."""
465 from IPython.core.usage import gui_reference
464 from IPython.core.usage import gui_reference
466 page.page(gui_reference, auto_html=True)
465 page.page(gui_reference, auto_html=True)
467
466
468 def magic_connect_info(self, arg_s):
467 def magic_connect_info(self, arg_s):
469 """Print information for connecting other clients to this kernel
468 """Print information for connecting other clients to this kernel
470
469
471 It will print the contents of this session's connection file, as well as
470 It will print the contents of this session's connection file, as well as
472 shortcuts for local clients.
471 shortcuts for local clients.
473
472
474 In the simplest case, when called from the most recently launched kernel,
473 In the simplest case, when called from the most recently launched kernel,
475 secondary clients can be connected, simply with:
474 secondary clients can be connected, simply with:
476
475
477 $> ipython <app> --existing
476 $> ipython <app> --existing
478
477
479 """
478 """
480
479
481 from IPython.core.application import BaseIPythonApplication as BaseIPApp
480 from IPython.core.application import BaseIPythonApplication as BaseIPApp
482
481
483 if BaseIPApp.initialized():
482 if BaseIPApp.initialized():
484 app = BaseIPApp.instance()
483 app = BaseIPApp.instance()
485 security_dir = app.profile_dir.security_dir
484 security_dir = app.profile_dir.security_dir
486 profile = app.profile
485 profile = app.profile
487 else:
486 else:
488 profile = 'default'
487 profile = 'default'
489 security_dir = ''
488 security_dir = ''
490
489
491 try:
490 try:
492 connection_file = get_connection_file()
491 connection_file = get_connection_file()
493 info = get_connection_info(unpack=False)
492 info = get_connection_info(unpack=False)
494 except Exception as e:
493 except Exception as e:
495 error("Could not get connection info: %r" % e)
494 error("Could not get connection info: %r" % e)
496 return
495 return
497
496
498 # add profile flag for non-default profile
497 # add profile flag for non-default profile
499 profile_flag = "--profile %s" % profile if profile != 'default' else ""
498 profile_flag = "--profile %s" % profile if profile != 'default' else ""
500
499
501 # if it's in the security dir, truncate to basename
500 # if it's in the security dir, truncate to basename
502 if security_dir == os.path.dirname(connection_file):
501 if security_dir == os.path.dirname(connection_file):
503 connection_file = os.path.basename(connection_file)
502 connection_file = os.path.basename(connection_file)
504
503
505
504
506 print (info + '\n')
505 print (info + '\n')
507 print ("Paste the above JSON into a file, and connect with:\n"
506 print ("Paste the above JSON into a file, and connect with:\n"
508 " $> ipython <app> --existing <file>\n"
507 " $> ipython <app> --existing <file>\n"
509 "or, if you are local, you can connect with just:\n"
508 "or, if you are local, you can connect with just:\n"
510 " $> ipython <app> --existing {0} {1}\n"
509 " $> ipython <app> --existing {0} {1}\n"
511 "or even just:\n"
510 "or even just:\n"
512 " $> ipython <app> --existing {1}\n"
511 " $> ipython <app> --existing {1}\n"
513 "if this is the most recent IPython session you have started.".format(
512 "if this is the most recent IPython session you have started.".format(
514 connection_file, profile_flag
513 connection_file, profile_flag
515 )
514 )
516 )
515 )
517
516
518 def magic_qtconsole(self, arg_s):
517 def magic_qtconsole(self, arg_s):
519 """Open a qtconsole connected to this kernel.
518 """Open a qtconsole connected to this kernel.
520
519
521 Useful for connecting a qtconsole to running notebooks, for better
520 Useful for connecting a qtconsole to running notebooks, for better
522 debugging.
521 debugging.
523 """
522 """
524 try:
523 try:
525 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
524 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
526 except Exception as e:
525 except Exception as e:
527 error("Could not start qtconsole: %r" % e)
526 error("Could not start qtconsole: %r" % e)
528 return
527 return
529
528
530 def set_next_input(self, text):
529 def set_next_input(self, text):
531 """Send the specified text to the frontend to be presented at the next
530 """Send the specified text to the frontend to be presented at the next
532 input cell."""
531 input cell."""
533 payload = dict(
532 payload = dict(
534 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
533 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
535 text=text
534 text=text
536 )
535 )
537 self.payload_manager.write_payload(payload)
536 self.payload_manager.write_payload(payload)
538
537
539
538
540 InteractiveShellABC.register(ZMQInteractiveShell)
539 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now