##// END OF EJS Templates
explicit allow_none
Sylvain Corlay -
Show More
@@ -1,437 +1,437
1 1 # encoding: utf-8
2 2 """
3 3 A mixin for :class:`~IPython.core.application.Application` classes that
4 4 launch InteractiveShell instances, load extensions, etc.
5 5
6 6 Authors
7 7 -------
8 8
9 9 * Min Ragan-Kelley
10 10 """
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2008-2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 from __future__ import absolute_import
24 24 from __future__ import print_function
25 25
26 26 import glob
27 27 import os
28 28 import sys
29 29
30 30 from IPython.config.application import boolean_flag
31 31 from IPython.config.configurable import Configurable
32 32 from IPython.config.loader import Config
33 33 from IPython.core import pylabtools
34 34 from IPython.utils import py3compat
35 35 from IPython.utils.contexts import preserve_keys
36 36 from IPython.utils.path import filefind
37 37 from IPython.utils.traitlets import (
38 38 Unicode, Instance, List, Bool, CaselessStrEnum
39 39 )
40 40 from IPython.lib.inputhook import guis
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Aliases and Flags
44 44 #-----------------------------------------------------------------------------
45 45
46 46 gui_keys = tuple(sorted([ key for key in guis if key is not None ]))
47 47
48 48 backend_keys = sorted(pylabtools.backends.keys())
49 49 backend_keys.insert(0, 'auto')
50 50
51 51 shell_flags = {}
52 52
53 53 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
54 54 addflag('autoindent', 'InteractiveShell.autoindent',
55 55 'Turn on autoindenting.', 'Turn off autoindenting.'
56 56 )
57 57 addflag('automagic', 'InteractiveShell.automagic',
58 58 """Turn on the auto calling of magic commands. Type %%magic at the
59 59 IPython prompt for more information.""",
60 60 'Turn off the auto calling of magic commands.'
61 61 )
62 62 addflag('pdb', 'InteractiveShell.pdb',
63 63 "Enable auto calling the pdb debugger after every exception.",
64 64 "Disable auto calling the pdb debugger after every exception."
65 65 )
66 66 # pydb flag doesn't do any config, as core.debugger switches on import,
67 67 # which is before parsing. This just allows the flag to be passed.
68 68 shell_flags.update(dict(
69 69 pydb = ({},
70 70 """Use the third party 'pydb' package as debugger, instead of pdb.
71 71 Requires that pydb is installed."""
72 72 )
73 73 ))
74 74 addflag('pprint', 'PlainTextFormatter.pprint',
75 75 "Enable auto pretty printing of results.",
76 76 "Disable auto pretty printing of results."
77 77 )
78 78 addflag('color-info', 'InteractiveShell.color_info',
79 79 """IPython can display information about objects via a set of functions,
80 80 and optionally can use colors for this, syntax highlighting
81 81 source code and various other elements. This is on by default, but can cause
82 82 problems with some pagers. If you see such problems, you can disable the
83 83 colours.""",
84 84 "Disable using colors for info related things."
85 85 )
86 86 addflag('deep-reload', 'InteractiveShell.deep_reload',
87 87 """Enable deep (recursive) reloading by default. IPython can use the
88 88 deep_reload module which reloads changes in modules recursively (it
89 89 replaces the reload() function, so you don't need to change anything to
90 90 use it). deep_reload() forces a full reload of modules whose code may
91 91 have changed, which the default reload() function does not. When
92 92 deep_reload is off, IPython will use the normal reload(), but
93 93 deep_reload will still be available as dreload(). This feature is off
94 94 by default [which means that you have both normal reload() and
95 95 dreload()].""",
96 96 "Disable deep (recursive) reloading by default."
97 97 )
98 98 nosep_config = Config()
99 99 nosep_config.InteractiveShell.separate_in = ''
100 100 nosep_config.InteractiveShell.separate_out = ''
101 101 nosep_config.InteractiveShell.separate_out2 = ''
102 102
103 103 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
104 104 shell_flags['pylab'] = (
105 105 {'InteractiveShellApp' : {'pylab' : 'auto'}},
106 106 """Pre-load matplotlib and numpy for interactive use with
107 107 the default matplotlib backend."""
108 108 )
109 109 shell_flags['matplotlib'] = (
110 110 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
111 111 """Configure matplotlib for interactive use with
112 112 the default matplotlib backend."""
113 113 )
114 114
115 115 # it's possible we don't want short aliases for *all* of these:
116 116 shell_aliases = dict(
117 117 autocall='InteractiveShell.autocall',
118 118 colors='InteractiveShell.colors',
119 119 logfile='InteractiveShell.logfile',
120 120 logappend='InteractiveShell.logappend',
121 121 c='InteractiveShellApp.code_to_run',
122 122 m='InteractiveShellApp.module_to_run',
123 123 ext='InteractiveShellApp.extra_extension',
124 124 gui='InteractiveShellApp.gui',
125 125 pylab='InteractiveShellApp.pylab',
126 126 matplotlib='InteractiveShellApp.matplotlib',
127 127 )
128 128 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
129 129
130 130 #-----------------------------------------------------------------------------
131 131 # Main classes and functions
132 132 #-----------------------------------------------------------------------------
133 133
134 134 class InteractiveShellApp(Configurable):
135 135 """A Mixin for applications that start InteractiveShell instances.
136 136
137 137 Provides configurables for loading extensions and executing files
138 138 as part of configuring a Shell environment.
139 139
140 140 The following methods should be called by the :meth:`initialize` method
141 141 of the subclass:
142 142
143 143 - :meth:`init_path`
144 144 - :meth:`init_shell` (to be implemented by the subclass)
145 145 - :meth:`init_gui_pylab`
146 146 - :meth:`init_extensions`
147 147 - :meth:`init_code`
148 148 """
149 149 extensions = List(Unicode, config=True,
150 150 help="A list of dotted module names of IPython extensions to load."
151 151 )
152 152 extra_extension = Unicode('', config=True,
153 153 help="dotted module name of an IPython extension to load."
154 154 )
155 155 def _extra_extension_changed(self, name, old, new):
156 156 if new:
157 157 # add to self.extensions
158 158 self.extensions.append(new)
159 159
160 160 # Extensions that are always loaded (not configurable)
161 161 default_extensions = List(Unicode, [u'storemagic'], config=False)
162 162
163 163 hide_initial_ns = Bool(True, config=True,
164 164 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
165 165 be hidden from tools like %who?"""
166 166 )
167 167
168 168 exec_files = List(Unicode, config=True,
169 169 help="""List of files to run at IPython startup."""
170 170 )
171 171 exec_PYTHONSTARTUP = Bool(True, config=True,
172 172 help="""Run the file referenced by the PYTHONSTARTUP environment
173 173 variable at IPython startup."""
174 174 )
175 175 file_to_run = Unicode('', config=True,
176 176 help="""A file to be run""")
177 177
178 178 exec_lines = List(Unicode, config=True,
179 179 help="""lines of code to run at IPython startup."""
180 180 )
181 181 code_to_run = Unicode('', config=True,
182 182 help="Execute the given command string."
183 183 )
184 184 module_to_run = Unicode('', config=True,
185 185 help="Run the module as a script."
186 186 )
187 gui = CaselessStrEnum(gui_keys, config=True,
187 gui = CaselessStrEnum(gui_keys, config=True, allow_none=True,
188 188 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
189 189 )
190 matplotlib = CaselessStrEnum(backend_keys,
190 matplotlib = CaselessStrEnum(backend_keys, allow_none=True,
191 191 config=True,
192 192 help="""Configure matplotlib for interactive use with
193 193 the default matplotlib backend."""
194 194 )
195 pylab = CaselessStrEnum(backend_keys,
195 pylab = CaselessStrEnum(backend_keys, allow_none=True,
196 196 config=True,
197 197 help="""Pre-load matplotlib and numpy for interactive use,
198 198 selecting a particular matplotlib backend and loop integration.
199 199 """
200 200 )
201 201 pylab_import_all = Bool(True, config=True,
202 202 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
203 203 and an ``import *`` is done from numpy and pylab, when using pylab mode.
204 204
205 205 When False, pylab mode should not import any names into the user namespace.
206 206 """
207 207 )
208 208 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
209 209
210 210 user_ns = Instance(dict, args=None, allow_none=True)
211 211 def _user_ns_changed(self, name, old, new):
212 212 if self.shell is not None:
213 213 self.shell.user_ns = new
214 214 self.shell.init_user_ns()
215 215
216 216 def init_path(self):
217 217 """Add current working directory, '', to sys.path"""
218 218 if sys.path[0] != '':
219 219 sys.path.insert(0, '')
220 220
221 221 def init_shell(self):
222 222 raise NotImplementedError("Override in subclasses")
223 223
224 224 def init_gui_pylab(self):
225 225 """Enable GUI event loop integration, taking pylab into account."""
226 226 enable = False
227 227 shell = self.shell
228 228 if self.pylab:
229 229 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
230 230 key = self.pylab
231 231 elif self.matplotlib:
232 232 enable = shell.enable_matplotlib
233 233 key = self.matplotlib
234 234 elif self.gui:
235 235 enable = shell.enable_gui
236 236 key = self.gui
237 237
238 238 if not enable:
239 239 return
240 240
241 241 try:
242 242 r = enable(key)
243 243 except ImportError:
244 244 self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?")
245 245 self.shell.showtraceback()
246 246 return
247 247 except Exception:
248 248 self.log.warn("GUI event loop or pylab initialization failed")
249 249 self.shell.showtraceback()
250 250 return
251 251
252 252 if isinstance(r, tuple):
253 253 gui, backend = r[:2]
254 254 self.log.info("Enabling GUI event loop integration, "
255 255 "eventloop=%s, matplotlib=%s", gui, backend)
256 256 if key == "auto":
257 257 print("Using matplotlib backend: %s" % backend)
258 258 else:
259 259 gui = r
260 260 self.log.info("Enabling GUI event loop integration, "
261 261 "eventloop=%s", gui)
262 262
263 263 def init_extensions(self):
264 264 """Load all IPython extensions in IPythonApp.extensions.
265 265
266 266 This uses the :meth:`ExtensionManager.load_extensions` to load all
267 267 the extensions listed in ``self.extensions``.
268 268 """
269 269 try:
270 270 self.log.debug("Loading IPython extensions...")
271 271 extensions = self.default_extensions + self.extensions
272 272 for ext in extensions:
273 273 try:
274 274 self.log.info("Loading IPython extension: %s" % ext)
275 275 self.shell.extension_manager.load_extension(ext)
276 276 except:
277 277 msg = ("Error in loading extension: {ext}\n"
278 278 "Check your config files in {location}".format(
279 279 ext=ext,
280 280 location=self.profile_dir.location
281 281 ))
282 282 self.log.warn(msg, exc_info=True)
283 283 except:
284 284 self.log.warn("Unknown error in loading extensions:", exc_info=True)
285 285
286 286 def init_code(self):
287 287 """run the pre-flight code, specified via exec_lines"""
288 288 self._run_startup_files()
289 289 self._run_exec_lines()
290 290 self._run_exec_files()
291 291
292 292 # Hide variables defined here from %who etc.
293 293 if self.hide_initial_ns:
294 294 self.shell.user_ns_hidden.update(self.shell.user_ns)
295 295
296 296 # command-line execution (ipython -i script.py, ipython -m module)
297 297 # should *not* be excluded from %whos
298 298 self._run_cmd_line_code()
299 299 self._run_module()
300 300
301 301 # flush output, so itwon't be attached to the first cell
302 302 sys.stdout.flush()
303 303 sys.stderr.flush()
304 304
305 305 def _run_exec_lines(self):
306 306 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
307 307 if not self.exec_lines:
308 308 return
309 309 try:
310 310 self.log.debug("Running code from IPythonApp.exec_lines...")
311 311 for line in self.exec_lines:
312 312 try:
313 313 self.log.info("Running code in user namespace: %s" %
314 314 line)
315 315 self.shell.run_cell(line, store_history=False)
316 316 except:
317 317 self.log.warn("Error in executing line in user "
318 318 "namespace: %s" % line)
319 319 self.shell.showtraceback()
320 320 except:
321 321 self.log.warn("Unknown error in handling IPythonApp.exec_lines:")
322 322 self.shell.showtraceback()
323 323
324 324 def _exec_file(self, fname, shell_futures=False):
325 325 try:
326 326 full_filename = filefind(fname, [u'.', self.ipython_dir])
327 327 except IOError as e:
328 328 self.log.warn("File not found: %r"%fname)
329 329 return
330 330 # Make sure that the running script gets a proper sys.argv as if it
331 331 # were run from a system shell.
332 332 save_argv = sys.argv
333 333 sys.argv = [full_filename] + self.extra_args[1:]
334 334 # protect sys.argv from potential unicode strings on Python 2:
335 335 if not py3compat.PY3:
336 336 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
337 337 try:
338 338 if os.path.isfile(full_filename):
339 339 self.log.info("Running file in user namespace: %s" %
340 340 full_filename)
341 341 # Ensure that __file__ is always defined to match Python
342 342 # behavior.
343 343 with preserve_keys(self.shell.user_ns, '__file__'):
344 344 self.shell.user_ns['__file__'] = fname
345 345 if full_filename.endswith('.ipy'):
346 346 self.shell.safe_execfile_ipy(full_filename,
347 347 shell_futures=shell_futures)
348 348 else:
349 349 # default to python, even without extension
350 350 self.shell.safe_execfile(full_filename,
351 351 self.shell.user_ns,
352 352 shell_futures=shell_futures)
353 353 finally:
354 354 sys.argv = save_argv
355 355
356 356 def _run_startup_files(self):
357 357 """Run files from profile startup directory"""
358 358 startup_dir = self.profile_dir.startup_dir
359 359 startup_files = []
360 360
361 361 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
362 362 not (self.file_to_run or self.code_to_run or self.module_to_run):
363 363 python_startup = os.environ['PYTHONSTARTUP']
364 364 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
365 365 try:
366 366 self._exec_file(python_startup)
367 367 except:
368 368 self.log.warn("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
369 369 self.shell.showtraceback()
370 370 finally:
371 371 # Many PYTHONSTARTUP files set up the readline completions,
372 372 # but this is often at odds with IPython's own completions.
373 373 # Do not allow PYTHONSTARTUP to set up readline.
374 374 if self.shell.has_readline:
375 375 self.shell.set_readline_completer()
376 376
377 377 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
378 378 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
379 379 if not startup_files:
380 380 return
381 381
382 382 self.log.debug("Running startup files from %s...", startup_dir)
383 383 try:
384 384 for fname in sorted(startup_files):
385 385 self._exec_file(fname)
386 386 except:
387 387 self.log.warn("Unknown error in handling startup files:")
388 388 self.shell.showtraceback()
389 389
390 390 def _run_exec_files(self):
391 391 """Run files from IPythonApp.exec_files"""
392 392 if not self.exec_files:
393 393 return
394 394
395 395 self.log.debug("Running files in IPythonApp.exec_files...")
396 396 try:
397 397 for fname in self.exec_files:
398 398 self._exec_file(fname)
399 399 except:
400 400 self.log.warn("Unknown error in handling IPythonApp.exec_files:")
401 401 self.shell.showtraceback()
402 402
403 403 def _run_cmd_line_code(self):
404 404 """Run code or file specified at the command-line"""
405 405 if self.code_to_run:
406 406 line = self.code_to_run
407 407 try:
408 408 self.log.info("Running code given at command line (c=): %s" %
409 409 line)
410 410 self.shell.run_cell(line, store_history=False)
411 411 except:
412 412 self.log.warn("Error in executing line in user namespace: %s" %
413 413 line)
414 414 self.shell.showtraceback()
415 415
416 416 # Like Python itself, ignore the second if the first of these is present
417 417 elif self.file_to_run:
418 418 fname = self.file_to_run
419 419 try:
420 420 self._exec_file(fname, shell_futures=True)
421 421 except:
422 422 self.log.warn("Error in executing file in user namespace: %s" %
423 423 fname)
424 424 self.shell.showtraceback()
425 425
426 426 def _run_module(self):
427 427 """Run module specified at the command-line."""
428 428 if self.module_to_run:
429 429 # Make sure that the module gets a proper sys.argv as if it were
430 430 # run using `python -m`.
431 431 save_argv = sys.argv
432 432 sys.argv = [sys.executable] + self.extra_args
433 433 try:
434 434 self.shell.safe_run_module(self.module_to_run,
435 435 self.shell.user_ns)
436 436 finally:
437 437 sys.argv = save_argv
@@ -1,496 +1,496
1 1 """Test suite for our zeromq-based message specification."""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import re
7 7 import sys
8 8 from distutils.version import LooseVersion as V
9 9 try:
10 10 from queue import Empty # Py 3
11 11 except ImportError:
12 12 from Queue import Empty # Py 2
13 13
14 14 import nose.tools as nt
15 15
16 16 from IPython.utils.traitlets import (
17 17 HasTraits, TraitError, Bool, Unicode, Dict, Integer, List, Enum,
18 18 )
19 19 from IPython.utils.py3compat import string_types, iteritems
20 20
21 21 from .utils import TIMEOUT, start_global_kernel, flush_channels, execute
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Globals
25 25 #-----------------------------------------------------------------------------
26 26 KC = None
27 27
28 28 def setup():
29 29 global KC
30 30 KC = start_global_kernel()
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # Message Spec References
34 34 #-----------------------------------------------------------------------------
35 35
36 36 class Reference(HasTraits):
37 37
38 38 """
39 39 Base class for message spec specification testing.
40 40
41 41 This class is the core of the message specification test. The
42 42 idea is that child classes implement trait attributes for each
43 43 message keys, so that message keys can be tested against these
44 44 traits using :meth:`check` method.
45 45
46 46 """
47 47
48 48 def check(self, d):
49 49 """validate a dict against our traits"""
50 50 for key in self.trait_names():
51 51 nt.assert_in(key, d)
52 52 # FIXME: always allow None, probably not a good idea
53 53 if d[key] is None:
54 54 continue
55 55 try:
56 56 setattr(self, key, d[key])
57 57 except TraitError as e:
58 58 assert False, str(e)
59 59
60 60
61 61 class Version(Unicode):
62 62 def __init__(self, *args, **kwargs):
63 63 self.min = kwargs.pop('min', None)
64 64 self.max = kwargs.pop('max', None)
65 65 kwargs['default_value'] = self.min
66 66 super(Version, self).__init__(*args, **kwargs)
67 67
68 68 def validate(self, obj, value):
69 69 if self.min and V(value) < V(self.min):
70 70 raise TraitError("bad version: %s < %s" % (value, self.min))
71 71 if self.max and (V(value) > V(self.max)):
72 72 raise TraitError("bad version: %s > %s" % (value, self.max))
73 73
74 74
75 75 class RMessage(Reference):
76 76 msg_id = Unicode()
77 77 msg_type = Unicode()
78 78 header = Dict()
79 79 parent_header = Dict()
80 80 content = Dict()
81 81
82 82 def check(self, d):
83 83 super(RMessage, self).check(d)
84 84 RHeader().check(self.header)
85 85 if self.parent_header:
86 86 RHeader().check(self.parent_header)
87 87
88 88 class RHeader(Reference):
89 89 msg_id = Unicode()
90 90 msg_type = Unicode()
91 91 session = Unicode()
92 92 username = Unicode()
93 93 version = Version(min='5.0')
94 94
95 95 mime_pat = re.compile(r'^[\w\-\+\.]+/[\w\-\+\.]+$')
96 96
97 97 class MimeBundle(Reference):
98 98 metadata = Dict()
99 99 data = Dict()
100 100 def _data_changed(self, name, old, new):
101 101 for k,v in iteritems(new):
102 102 assert mime_pat.match(k)
103 103 nt.assert_is_instance(v, string_types)
104 104
105 105 # shell replies
106 106
107 107 class ExecuteReply(Reference):
108 108 execution_count = Integer()
109 status = Enum((u'ok', u'error'))
109 status = Enum((u'ok', u'error'), allow_none=True)
110 110
111 111 def check(self, d):
112 112 Reference.check(self, d)
113 113 if d['status'] == 'ok':
114 114 ExecuteReplyOkay().check(d)
115 115 elif d['status'] == 'error':
116 116 ExecuteReplyError().check(d)
117 117
118 118
119 119 class ExecuteReplyOkay(Reference):
120 120 payload = List(Dict)
121 121 user_expressions = Dict()
122 122
123 123
124 124 class ExecuteReplyError(Reference):
125 125 ename = Unicode()
126 126 evalue = Unicode()
127 127 traceback = List(Unicode)
128 128
129 129
130 130 class InspectReply(MimeBundle):
131 131 found = Bool()
132 132
133 133
134 134 class ArgSpec(Reference):
135 135 args = List(Unicode)
136 136 varargs = Unicode()
137 137 varkw = Unicode()
138 138 defaults = List()
139 139
140 140
141 141 class Status(Reference):
142 execution_state = Enum((u'busy', u'idle', u'starting'))
142 execution_state = Enum((u'busy', u'idle', u'starting'), allow_none=True)
143 143
144 144
145 145 class CompleteReply(Reference):
146 146 matches = List(Unicode)
147 147 cursor_start = Integer()
148 148 cursor_end = Integer()
149 149 status = Unicode()
150 150
151 151 class LanguageInfo(Reference):
152 152 name = Unicode('python')
153 153 version = Unicode(sys.version.split()[0])
154 154
155 155 class KernelInfoReply(Reference):
156 156 protocol_version = Version(min='5.0')
157 157 implementation = Unicode('ipython')
158 158 implementation_version = Version(min='2.1')
159 159 language_info = Dict()
160 160 banner = Unicode()
161 161
162 162 def check(self, d):
163 163 Reference.check(self, d)
164 164 LanguageInfo().check(d['language_info'])
165 165
166 166
167 167 class IsCompleteReply(Reference):
168 status = Enum((u'complete', u'incomplete', u'invalid', u'unknown'))
168 status = Enum((u'complete', u'incomplete', u'invalid', u'unknown'), allow_none=True)
169 169
170 170 def check(self, d):
171 171 Reference.check(self, d)
172 172 if d['status'] == 'incomplete':
173 173 IsCompleteReplyIncomplete().check(d)
174 174
175 175 class IsCompleteReplyIncomplete(Reference):
176 176 indent = Unicode()
177 177
178 178
179 179 # IOPub messages
180 180
181 181 class ExecuteInput(Reference):
182 182 code = Unicode()
183 183 execution_count = Integer()
184 184
185 185
186 186 Error = ExecuteReplyError
187 187
188 188
189 189 class Stream(Reference):
190 name = Enum((u'stdout', u'stderr'))
190 name = Enum((u'stdout', u'stderr'), allow_none=True)
191 191 text = Unicode()
192 192
193 193
194 194 class DisplayData(MimeBundle):
195 195 pass
196 196
197 197
198 198 class ExecuteResult(MimeBundle):
199 199 execution_count = Integer()
200 200
201 201 class HistoryReply(Reference):
202 202 history = List(List())
203 203
204 204
205 205 references = {
206 206 'execute_reply' : ExecuteReply(),
207 207 'inspect_reply' : InspectReply(),
208 208 'status' : Status(),
209 209 'complete_reply' : CompleteReply(),
210 210 'kernel_info_reply': KernelInfoReply(),
211 211 'is_complete_reply': IsCompleteReply(),
212 212 'execute_input' : ExecuteInput(),
213 213 'execute_result' : ExecuteResult(),
214 214 'history_reply' : HistoryReply(),
215 215 'error' : Error(),
216 216 'stream' : Stream(),
217 217 'display_data' : DisplayData(),
218 218 'header' : RHeader(),
219 219 }
220 220 """
221 221 Specifications of `content` part of the reply messages.
222 222 """
223 223
224 224
225 225 def validate_message(msg, msg_type=None, parent=None):
226 226 """validate a message
227 227
228 228 This is a generator, and must be iterated through to actually
229 229 trigger each test.
230 230
231 231 If msg_type and/or parent are given, the msg_type and/or parent msg_id
232 232 are compared with the given values.
233 233 """
234 234 RMessage().check(msg)
235 235 if msg_type:
236 236 nt.assert_equal(msg['msg_type'], msg_type)
237 237 if parent:
238 238 nt.assert_equal(msg['parent_header']['msg_id'], parent)
239 239 content = msg['content']
240 240 ref = references[msg['msg_type']]
241 241 ref.check(content)
242 242
243 243
244 244 #-----------------------------------------------------------------------------
245 245 # Tests
246 246 #-----------------------------------------------------------------------------
247 247
248 248 # Shell channel
249 249
250 250 def test_execute():
251 251 flush_channels()
252 252
253 253 msg_id = KC.execute(code='x=1')
254 254 reply = KC.get_shell_msg(timeout=TIMEOUT)
255 255 validate_message(reply, 'execute_reply', msg_id)
256 256
257 257
258 258 def test_execute_silent():
259 259 flush_channels()
260 260 msg_id, reply = execute(code='x=1', silent=True)
261 261
262 262 # flush status=idle
263 263 status = KC.iopub_channel.get_msg(timeout=TIMEOUT)
264 264 validate_message(status, 'status', msg_id)
265 265 nt.assert_equal(status['content']['execution_state'], 'idle')
266 266
267 267 nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
268 268 count = reply['execution_count']
269 269
270 270 msg_id, reply = execute(code='x=2', silent=True)
271 271
272 272 # flush status=idle
273 273 status = KC.iopub_channel.get_msg(timeout=TIMEOUT)
274 274 validate_message(status, 'status', msg_id)
275 275 nt.assert_equal(status['content']['execution_state'], 'idle')
276 276
277 277 nt.assert_raises(Empty, KC.iopub_channel.get_msg, timeout=0.1)
278 278 count_2 = reply['execution_count']
279 279 nt.assert_equal(count_2, count)
280 280
281 281
282 282 def test_execute_error():
283 283 flush_channels()
284 284
285 285 msg_id, reply = execute(code='1/0')
286 286 nt.assert_equal(reply['status'], 'error')
287 287 nt.assert_equal(reply['ename'], 'ZeroDivisionError')
288 288
289 289 error = KC.iopub_channel.get_msg(timeout=TIMEOUT)
290 290 validate_message(error, 'error', msg_id)
291 291
292 292
293 293 def test_execute_inc():
294 294 """execute request should increment execution_count"""
295 295 flush_channels()
296 296
297 297 msg_id, reply = execute(code='x=1')
298 298 count = reply['execution_count']
299 299
300 300 flush_channels()
301 301
302 302 msg_id, reply = execute(code='x=2')
303 303 count_2 = reply['execution_count']
304 304 nt.assert_equal(count_2, count+1)
305 305
306 306 def test_execute_stop_on_error():
307 307 """execute request should not abort execution queue with stop_on_error False"""
308 308 flush_channels()
309 309
310 310 fail = '\n'.join([
311 311 # sleep to ensure subsequent message is waiting in the queue to be aborted
312 312 'import time',
313 313 'time.sleep(0.5)',
314 314 'raise ValueError',
315 315 ])
316 316 KC.execute(code=fail)
317 317 msg_id = KC.execute(code='print("Hello")')
318 318 KC.get_shell_msg(timeout=TIMEOUT)
319 319 reply = KC.get_shell_msg(timeout=TIMEOUT)
320 320 nt.assert_equal(reply['content']['status'], 'aborted')
321 321
322 322 flush_channels()
323 323
324 324 KC.execute(code=fail, stop_on_error=False)
325 325 msg_id = KC.execute(code='print("Hello")')
326 326 KC.get_shell_msg(timeout=TIMEOUT)
327 327 reply = KC.get_shell_msg(timeout=TIMEOUT)
328 328 nt.assert_equal(reply['content']['status'], 'ok')
329 329
330 330
331 331 def test_user_expressions():
332 332 flush_channels()
333 333
334 334 msg_id, reply = execute(code='x=1', user_expressions=dict(foo='x+1'))
335 335 user_expressions = reply['user_expressions']
336 336 nt.assert_equal(user_expressions, {u'foo': {
337 337 u'status': u'ok',
338 338 u'data': {u'text/plain': u'2'},
339 339 u'metadata': {},
340 340 }})
341 341
342 342
343 343 def test_user_expressions_fail():
344 344 flush_channels()
345 345
346 346 msg_id, reply = execute(code='x=0', user_expressions=dict(foo='nosuchname'))
347 347 user_expressions = reply['user_expressions']
348 348 foo = user_expressions['foo']
349 349 nt.assert_equal(foo['status'], 'error')
350 350 nt.assert_equal(foo['ename'], 'NameError')
351 351
352 352
353 353 def test_oinfo():
354 354 flush_channels()
355 355
356 356 msg_id = KC.inspect('a')
357 357 reply = KC.get_shell_msg(timeout=TIMEOUT)
358 358 validate_message(reply, 'inspect_reply', msg_id)
359 359
360 360
361 361 def test_oinfo_found():
362 362 flush_channels()
363 363
364 364 msg_id, reply = execute(code='a=5')
365 365
366 366 msg_id = KC.inspect('a')
367 367 reply = KC.get_shell_msg(timeout=TIMEOUT)
368 368 validate_message(reply, 'inspect_reply', msg_id)
369 369 content = reply['content']
370 370 assert content['found']
371 371 text = content['data']['text/plain']
372 372 nt.assert_in('Type:', text)
373 373 nt.assert_in('Docstring:', text)
374 374
375 375
376 376 def test_oinfo_detail():
377 377 flush_channels()
378 378
379 379 msg_id, reply = execute(code='ip=get_ipython()')
380 380
381 381 msg_id = KC.inspect('ip.object_inspect', cursor_pos=10, detail_level=1)
382 382 reply = KC.get_shell_msg(timeout=TIMEOUT)
383 383 validate_message(reply, 'inspect_reply', msg_id)
384 384 content = reply['content']
385 385 assert content['found']
386 386 text = content['data']['text/plain']
387 387 nt.assert_in('Definition:', text)
388 388 nt.assert_in('Source:', text)
389 389
390 390
391 391 def test_oinfo_not_found():
392 392 flush_channels()
393 393
394 394 msg_id = KC.inspect('dne')
395 395 reply = KC.get_shell_msg(timeout=TIMEOUT)
396 396 validate_message(reply, 'inspect_reply', msg_id)
397 397 content = reply['content']
398 398 nt.assert_false(content['found'])
399 399
400 400
401 401 def test_complete():
402 402 flush_channels()
403 403
404 404 msg_id, reply = execute(code="alpha = albert = 5")
405 405
406 406 msg_id = KC.complete('al', 2)
407 407 reply = KC.get_shell_msg(timeout=TIMEOUT)
408 408 validate_message(reply, 'complete_reply', msg_id)
409 409 matches = reply['content']['matches']
410 410 for name in ('alpha', 'albert'):
411 411 nt.assert_in(name, matches)
412 412
413 413
414 414 def test_kernel_info_request():
415 415 flush_channels()
416 416
417 417 msg_id = KC.kernel_info()
418 418 reply = KC.get_shell_msg(timeout=TIMEOUT)
419 419 validate_message(reply, 'kernel_info_reply', msg_id)
420 420
421 421
422 422 def test_single_payload():
423 423 flush_channels()
424 424 msg_id, reply = execute(code="for i in range(3):\n"+
425 425 " x=range?\n")
426 426 payload = reply['payload']
427 427 next_input_pls = [pl for pl in payload if pl["source"] == "set_next_input"]
428 428 nt.assert_equal(len(next_input_pls), 1)
429 429
430 430 def test_is_complete():
431 431 flush_channels()
432 432
433 433 msg_id = KC.is_complete("a = 1")
434 434 reply = KC.get_shell_msg(timeout=TIMEOUT)
435 435 validate_message(reply, 'is_complete_reply', msg_id)
436 436
437 437 def test_history_range():
438 438 flush_channels()
439 439
440 440 msg_id_exec = KC.execute(code='x=1', store_history = True)
441 441 reply_exec = KC.get_shell_msg(timeout=TIMEOUT)
442 442
443 443 msg_id = KC.history(hist_access_type = 'range', raw = True, output = True, start = 1, stop = 2, session = 0)
444 444 reply = KC.get_shell_msg(timeout=TIMEOUT)
445 445 validate_message(reply, 'history_reply', msg_id)
446 446 content = reply['content']
447 447 nt.assert_equal(len(content['history']), 1)
448 448
449 449 def test_history_tail():
450 450 flush_channels()
451 451
452 452 msg_id_exec = KC.execute(code='x=1', store_history = True)
453 453 reply_exec = KC.get_shell_msg(timeout=TIMEOUT)
454 454
455 455 msg_id = KC.history(hist_access_type = 'tail', raw = True, output = True, n = 1, session = 0)
456 456 reply = KC.get_shell_msg(timeout=TIMEOUT)
457 457 validate_message(reply, 'history_reply', msg_id)
458 458 content = reply['content']
459 459 nt.assert_equal(len(content['history']), 1)
460 460
461 461 def test_history_search():
462 462 flush_channels()
463 463
464 464 msg_id_exec = KC.execute(code='x=1', store_history = True)
465 465 reply_exec = KC.get_shell_msg(timeout=TIMEOUT)
466 466
467 467 msg_id = KC.history(hist_access_type = 'search', raw = True, output = True, n = 1, pattern = '*', session = 0)
468 468 reply = KC.get_shell_msg(timeout=TIMEOUT)
469 469 validate_message(reply, 'history_reply', msg_id)
470 470 content = reply['content']
471 471 nt.assert_equal(len(content['history']), 1)
472 472
473 473 # IOPub channel
474 474
475 475
476 476 def test_stream():
477 477 flush_channels()
478 478
479 479 msg_id, reply = execute("print('hi')")
480 480
481 481 stdout = KC.iopub_channel.get_msg(timeout=TIMEOUT)
482 482 validate_message(stdout, 'stream', msg_id)
483 483 content = stdout['content']
484 484 nt.assert_equal(content['text'], u'hi\n')
485 485
486 486
487 487 def test_display_data():
488 488 flush_channels()
489 489
490 490 msg_id, reply = execute("from IPython.core.display import display; display(1)")
491 491
492 492 display = KC.iopub_channel.get_msg(timeout=TIMEOUT)
493 493 validate_message(display, 'display_data', parent=msg_id)
494 494 data = display['content']['data']
495 495 nt.assert_equal(data['text/plain'], u'1')
496 496
@@ -1,578 +1,578
1 1 # -*- coding: utf-8 -*-
2 2 """terminal client to the IPython kernel"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from __future__ import print_function
8 8
9 9 import base64
10 10 import bdb
11 11 import signal
12 12 import os
13 13 import sys
14 14 import time
15 15 import subprocess
16 16 from getpass import getpass
17 17 from io import BytesIO
18 18
19 19 try:
20 20 from queue import Empty # Py 3
21 21 except ImportError:
22 22 from Queue import Empty # Py 2
23 23
24 24 from IPython.core import page
25 25 from IPython.core import release
26 26 from IPython.terminal.console.zmqhistory import ZMQHistoryManager
27 27 from IPython.utils.warn import warn, error
28 28 from IPython.utils import io
29 29 from IPython.utils.py3compat import string_types, input
30 30 from IPython.utils.traitlets import List, Enum, Any, Instance, Unicode, Float, Bool
31 31 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
32 32
33 33 from IPython.terminal.interactiveshell import TerminalInteractiveShell
34 34 from IPython.terminal.console.completer import ZMQCompleter
35 35
36 36 class ZMQTerminalInteractiveShell(TerminalInteractiveShell):
37 37 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
38 38 _executing = False
39 39 _execution_state = Unicode('')
40 40 _pending_clearoutput = False
41 41 kernel_banner = Unicode('')
42 42 kernel_timeout = Float(60, config=True,
43 43 help="""Timeout for giving up on a kernel (in seconds).
44 44
45 45 On first connect and restart, the console tests whether the
46 46 kernel is running and responsive by sending kernel_info_requests.
47 47 This sets the timeout in seconds for how long the kernel can take
48 48 before being presumed dead.
49 49 """
50 50 )
51 51
52 52 image_handler = Enum(('PIL', 'stream', 'tempfile', 'callable'),
53 config=True, help=
53 config=True, allow_none=True, help=
54 54 """
55 55 Handler for image type output. This is useful, for example,
56 56 when connecting to the kernel in which pylab inline backend is
57 57 activated. There are four handlers defined. 'PIL': Use
58 58 Python Imaging Library to popup image; 'stream': Use an
59 59 external program to show the image. Image will be fed into
60 60 the STDIN of the program. You will need to configure
61 61 `stream_image_handler`; 'tempfile': Use an external program to
62 62 show the image. Image will be saved in a temporally file and
63 63 the program is called with the temporally file. You will need
64 64 to configure `tempfile_image_handler`; 'callable': You can set
65 65 any Python callable which is called with the image data. You
66 66 will need to configure `callable_image_handler`.
67 67 """
68 68 )
69 69
70 70 stream_image_handler = List(config=True, help=
71 71 """
72 72 Command to invoke an image viewer program when you are using
73 73 'stream' image handler. This option is a list of string where
74 74 the first element is the command itself and reminders are the
75 75 options for the command. Raw image data is given as STDIN to
76 76 the program.
77 77 """
78 78 )
79 79
80 80 tempfile_image_handler = List(config=True, help=
81 81 """
82 82 Command to invoke an image viewer program when you are using
83 83 'tempfile' image handler. This option is a list of string
84 84 where the first element is the command itself and reminders
85 85 are the options for the command. You can use {file} and
86 86 {format} in the string to represent the location of the
87 87 generated image file and image format.
88 88 """
89 89 )
90 90
91 91 callable_image_handler = Any(config=True, help=
92 92 """
93 93 Callable object called via 'callable' image handler with one
94 94 argument, `data`, which is `msg["content"]["data"]` where
95 95 `msg` is the message from iopub channel. For exmaple, you can
96 96 find base64 encoded PNG data as `data['image/png']`.
97 97 """
98 98 )
99 99
100 100 mime_preference = List(
101 101 default_value=['image/png', 'image/jpeg', 'image/svg+xml'],
102 102 config=True, allow_none=False, help=
103 103 """
104 104 Preferred object representation MIME type in order. First
105 105 matched MIME type will be used.
106 106 """
107 107 )
108 108
109 109 manager = Instance('IPython.kernel.KernelManager')
110 110 client = Instance('IPython.kernel.KernelClient')
111 111 def _client_changed(self, name, old, new):
112 112 self.session_id = new.session.session
113 113 session_id = Unicode()
114 114
115 115 def init_completer(self):
116 116 """Initialize the completion machinery.
117 117
118 118 This creates completion machinery that can be used by client code,
119 119 either interactively in-process (typically triggered by the readline
120 120 library), programmatically (such as in test suites) or out-of-process
121 121 (typically over the network by remote frontends).
122 122 """
123 123 from IPython.core.completerlib import (module_completer,
124 124 magic_run_completer, cd_completer)
125 125
126 126 self.Completer = ZMQCompleter(self, self.client, config=self.config)
127 127
128 128
129 129 self.set_hook('complete_command', module_completer, str_key = 'import')
130 130 self.set_hook('complete_command', module_completer, str_key = 'from')
131 131 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
132 132 self.set_hook('complete_command', cd_completer, str_key = '%cd')
133 133
134 134 # Only configure readline if we truly are using readline. IPython can
135 135 # do tab-completion over the network, in GUIs, etc, where readline
136 136 # itself may be absent
137 137 if self.has_readline:
138 138 self.set_readline_completer()
139 139
140 140 def run_cell(self, cell, store_history=True):
141 141 """Run a complete IPython cell.
142 142
143 143 Parameters
144 144 ----------
145 145 cell : str
146 146 The code (including IPython code such as %magic functions) to run.
147 147 store_history : bool
148 148 If True, the raw and translated cell will be stored in IPython's
149 149 history. For user code calling back into IPython's machinery, this
150 150 should be set to False.
151 151 """
152 152 if (not cell) or cell.isspace():
153 153 # pressing enter flushes any pending display
154 154 self.handle_iopub()
155 155 return
156 156
157 157 # flush stale replies, which could have been ignored, due to missed heartbeats
158 158 while self.client.shell_channel.msg_ready():
159 159 self.client.shell_channel.get_msg()
160 160 # execute takes 'hidden', which is the inverse of store_hist
161 161 msg_id = self.client.execute(cell, not store_history)
162 162
163 163 # first thing is wait for any side effects (output, stdin, etc.)
164 164 self._executing = True
165 165 self._execution_state = "busy"
166 166 while self._execution_state != 'idle' and self.client.is_alive():
167 167 try:
168 168 self.handle_input_request(msg_id, timeout=0.05)
169 169 except Empty:
170 170 # display intermediate print statements, etc.
171 171 self.handle_iopub(msg_id)
172 172
173 173 # after all of that is done, wait for the execute reply
174 174 while self.client.is_alive():
175 175 try:
176 176 self.handle_execute_reply(msg_id, timeout=0.05)
177 177 except Empty:
178 178 pass
179 179 else:
180 180 break
181 181 self._executing = False
182 182
183 183 #-----------------
184 184 # message handlers
185 185 #-----------------
186 186
187 187 def handle_execute_reply(self, msg_id, timeout=None):
188 188 msg = self.client.shell_channel.get_msg(block=False, timeout=timeout)
189 189 if msg["parent_header"].get("msg_id", None) == msg_id:
190 190
191 191 self.handle_iopub(msg_id)
192 192
193 193 content = msg["content"]
194 194 status = content['status']
195 195
196 196 if status == 'aborted':
197 197 self.write('Aborted\n')
198 198 return
199 199 elif status == 'ok':
200 200 # handle payloads
201 201 for item in content["payload"]:
202 202 source = item['source']
203 203 if source == 'page':
204 204 page.page(item['data']['text/plain'])
205 205 elif source == 'set_next_input':
206 206 self.set_next_input(item['text'])
207 207 elif source == 'ask_exit':
208 208 self.ask_exit()
209 209
210 210 elif status == 'error':
211 211 for frame in content["traceback"]:
212 212 print(frame, file=io.stderr)
213 213
214 214 self.execution_count = int(content["execution_count"] + 1)
215 215
216 216 include_other_output = Bool(False, config=True,
217 217 help="""Whether to include output from clients
218 218 other than this one sharing the same kernel.
219 219
220 220 Outputs are not displayed until enter is pressed.
221 221 """
222 222 )
223 223 other_output_prefix = Unicode("[remote] ", config=True,
224 224 help="""Prefix to add to outputs coming from clients other than this one.
225 225
226 226 Only relevant if include_other_output is True.
227 227 """
228 228 )
229 229
230 230 def from_here(self, msg):
231 231 """Return whether a message is from this session"""
232 232 return msg['parent_header'].get("session", self.session_id) == self.session_id
233 233
234 234 def include_output(self, msg):
235 235 """Return whether we should include a given output message"""
236 236 from_here = self.from_here(msg)
237 237 if msg['msg_type'] == 'execute_input':
238 238 # only echo inputs not from here
239 239 return self.include_other_output and not from_here
240 240
241 241 if self.include_other_output:
242 242 return True
243 243 else:
244 244 return from_here
245 245
246 246 def handle_iopub(self, msg_id=''):
247 247 """Process messages on the IOPub channel
248 248
249 249 This method consumes and processes messages on the IOPub channel,
250 250 such as stdout, stderr, execute_result and status.
251 251
252 252 It only displays output that is caused by this session.
253 253 """
254 254 while self.client.iopub_channel.msg_ready():
255 255 sub_msg = self.client.iopub_channel.get_msg()
256 256 msg_type = sub_msg['header']['msg_type']
257 257 parent = sub_msg["parent_header"]
258 258
259 259 if self.include_output(sub_msg):
260 260 if msg_type == 'status':
261 261 self._execution_state = sub_msg["content"]["execution_state"]
262 262 elif msg_type == 'stream':
263 263 if sub_msg["content"]["name"] == "stdout":
264 264 if self._pending_clearoutput:
265 265 print("\r", file=io.stdout, end="")
266 266 self._pending_clearoutput = False
267 267 print(sub_msg["content"]["text"], file=io.stdout, end="")
268 268 io.stdout.flush()
269 269 elif sub_msg["content"]["name"] == "stderr":
270 270 if self._pending_clearoutput:
271 271 print("\r", file=io.stderr, end="")
272 272 self._pending_clearoutput = False
273 273 print(sub_msg["content"]["text"], file=io.stderr, end="")
274 274 io.stderr.flush()
275 275
276 276 elif msg_type == 'execute_result':
277 277 if self._pending_clearoutput:
278 278 print("\r", file=io.stdout, end="")
279 279 self._pending_clearoutput = False
280 280 self.execution_count = int(sub_msg["content"]["execution_count"])
281 281 if not self.from_here(sub_msg):
282 282 sys.stdout.write(self.other_output_prefix)
283 283 format_dict = sub_msg["content"]["data"]
284 284 self.handle_rich_data(format_dict)
285 285
286 286 # taken from DisplayHook.__call__:
287 287 hook = self.displayhook
288 288 hook.start_displayhook()
289 289 hook.write_output_prompt()
290 290 hook.write_format_data(format_dict)
291 291 hook.log_output(format_dict)
292 292 hook.finish_displayhook()
293 293
294 294 elif msg_type == 'display_data':
295 295 data = sub_msg["content"]["data"]
296 296 handled = self.handle_rich_data(data)
297 297 if not handled:
298 298 if not self.from_here(sub_msg):
299 299 sys.stdout.write(self.other_output_prefix)
300 300 # if it was an image, we handled it by now
301 301 if 'text/plain' in data:
302 302 print(data['text/plain'])
303 303
304 304 elif msg_type == 'execute_input':
305 305 content = sub_msg['content']
306 306 self.execution_count = content['execution_count']
307 307 if not self.from_here(sub_msg):
308 308 sys.stdout.write(self.other_output_prefix)
309 309 sys.stdout.write(self.prompt_manager.render('in'))
310 310 sys.stdout.write(content['code'])
311 311
312 312 elif msg_type == 'clear_output':
313 313 if sub_msg["content"]["wait"]:
314 314 self._pending_clearoutput = True
315 315 else:
316 316 print("\r", file=io.stdout, end="")
317 317
318 318 _imagemime = {
319 319 'image/png': 'png',
320 320 'image/jpeg': 'jpeg',
321 321 'image/svg+xml': 'svg',
322 322 }
323 323
324 324 def handle_rich_data(self, data):
325 325 for mime in self.mime_preference:
326 326 if mime in data and mime in self._imagemime:
327 327 self.handle_image(data, mime)
328 328 return True
329 329
330 330 def handle_image(self, data, mime):
331 331 handler = getattr(
332 332 self, 'handle_image_{0}'.format(self.image_handler), None)
333 333 if handler:
334 334 handler(data, mime)
335 335
336 336 def handle_image_PIL(self, data, mime):
337 337 if mime not in ('image/png', 'image/jpeg'):
338 338 return
339 339 import PIL.Image
340 340 raw = base64.decodestring(data[mime].encode('ascii'))
341 341 img = PIL.Image.open(BytesIO(raw))
342 342 img.show()
343 343
344 344 def handle_image_stream(self, data, mime):
345 345 raw = base64.decodestring(data[mime].encode('ascii'))
346 346 imageformat = self._imagemime[mime]
347 347 fmt = dict(format=imageformat)
348 348 args = [s.format(**fmt) for s in self.stream_image_handler]
349 349 with open(os.devnull, 'w') as devnull:
350 350 proc = subprocess.Popen(
351 351 args, stdin=subprocess.PIPE,
352 352 stdout=devnull, stderr=devnull)
353 353 proc.communicate(raw)
354 354
355 355 def handle_image_tempfile(self, data, mime):
356 356 raw = base64.decodestring(data[mime].encode('ascii'))
357 357 imageformat = self._imagemime[mime]
358 358 filename = 'tmp.{0}'.format(imageformat)
359 359 with NamedFileInTemporaryDirectory(filename) as f, \
360 360 open(os.devnull, 'w') as devnull:
361 361 f.write(raw)
362 362 f.flush()
363 363 fmt = dict(file=f.name, format=imageformat)
364 364 args = [s.format(**fmt) for s in self.tempfile_image_handler]
365 365 subprocess.call(args, stdout=devnull, stderr=devnull)
366 366
367 367 def handle_image_callable(self, data, mime):
368 368 self.callable_image_handler(data)
369 369
370 370 def handle_input_request(self, msg_id, timeout=0.1):
371 371 """ Method to capture raw_input
372 372 """
373 373 req = self.client.stdin_channel.get_msg(timeout=timeout)
374 374 # in case any iopub came while we were waiting:
375 375 self.handle_iopub(msg_id)
376 376 if msg_id == req["parent_header"].get("msg_id"):
377 377 # wrap SIGINT handler
378 378 real_handler = signal.getsignal(signal.SIGINT)
379 379 def double_int(sig,frame):
380 380 # call real handler (forwards sigint to kernel),
381 381 # then raise local interrupt, stopping local raw_input
382 382 real_handler(sig,frame)
383 383 raise KeyboardInterrupt
384 384 signal.signal(signal.SIGINT, double_int)
385 385 content = req['content']
386 386 read = getpass if content.get('password', False) else input
387 387 try:
388 388 raw_data = read(content["prompt"])
389 389 except EOFError:
390 390 # turn EOFError into EOF character
391 391 raw_data = '\x04'
392 392 except KeyboardInterrupt:
393 393 sys.stdout.write('\n')
394 394 return
395 395 finally:
396 396 # restore SIGINT handler
397 397 signal.signal(signal.SIGINT, real_handler)
398 398
399 399 # only send stdin reply if there *was not* another request
400 400 # or execution finished while we were reading.
401 401 if not (self.client.stdin_channel.msg_ready() or self.client.shell_channel.msg_ready()):
402 402 self.client.input(raw_data)
403 403
404 404 def mainloop(self, display_banner=False):
405 405 while True:
406 406 try:
407 407 self.interact(display_banner=display_banner)
408 408 #self.interact_with_readline()
409 409 # XXX for testing of a readline-decoupled repl loop, call
410 410 # interact_with_readline above
411 411 break
412 412 except KeyboardInterrupt:
413 413 # this should not be necessary, but KeyboardInterrupt
414 414 # handling seems rather unpredictable...
415 415 self.write("\nKeyboardInterrupt in interact()\n")
416 416
417 417 self.client.shutdown()
418 418
419 419 def _banner1_default(self):
420 420 return "IPython Console {version}\n".format(version=release.version)
421 421
422 422 def compute_banner(self):
423 423 super(ZMQTerminalInteractiveShell, self).compute_banner()
424 424 if self.client and not self.kernel_banner:
425 425 msg_id = self.client.kernel_info()
426 426 while True:
427 427 try:
428 428 reply = self.client.get_shell_msg(timeout=1)
429 429 except Empty:
430 430 break
431 431 else:
432 432 if reply['parent_header'].get('msg_id') == msg_id:
433 433 self.kernel_banner = reply['content'].get('banner', '')
434 434 break
435 435 self.banner += self.kernel_banner
436 436
437 437 def wait_for_kernel(self, timeout=None):
438 438 """method to wait for a kernel to be ready"""
439 439 tic = time.time()
440 440 self.client.hb_channel.unpause()
441 441 while True:
442 442 msg_id = self.client.kernel_info()
443 443 reply = None
444 444 while True:
445 445 try:
446 446 reply = self.client.get_shell_msg(timeout=1)
447 447 except Empty:
448 448 break
449 449 else:
450 450 if reply['parent_header'].get('msg_id') == msg_id:
451 451 return True
452 452 if timeout is not None \
453 453 and (time.time() - tic) > timeout \
454 454 and not self.client.hb_channel.is_beating():
455 455 # heart failed
456 456 return False
457 457 return True
458 458
459 459 def interact(self, display_banner=None):
460 460 """Closely emulate the interactive Python console."""
461 461
462 462 # batch run -> do not interact
463 463 if self.exit_now:
464 464 return
465 465
466 466 if display_banner is None:
467 467 display_banner = self.display_banner
468 468
469 469 if isinstance(display_banner, string_types):
470 470 self.show_banner(display_banner)
471 471 elif display_banner:
472 472 self.show_banner()
473 473
474 474 more = False
475 475
476 476 # run a non-empty no-op, so that we don't get a prompt until
477 477 # we know the kernel is ready. This keeps the connection
478 478 # message above the first prompt.
479 479 if not self.wait_for_kernel(self.kernel_timeout):
480 480 error("Kernel did not respond\n")
481 481 return
482 482
483 483 if self.has_readline:
484 484 self.readline_startup_hook(self.pre_readline)
485 485 hlen_b4_cell = self.readline.get_current_history_length()
486 486 else:
487 487 hlen_b4_cell = 0
488 488 # exit_now is set by a call to %Exit or %Quit, through the
489 489 # ask_exit callback.
490 490
491 491 while not self.exit_now:
492 492 if not self.client.is_alive():
493 493 # kernel died, prompt for action or exit
494 494
495 495 action = "restart" if self.manager else "wait for restart"
496 496 ans = self.ask_yes_no("kernel died, %s ([y]/n)?" % action, default='y')
497 497 if ans:
498 498 if self.manager:
499 499 self.manager.restart_kernel(True)
500 500 self.wait_for_kernel(self.kernel_timeout)
501 501 else:
502 502 self.exit_now = True
503 503 continue
504 504 try:
505 505 # protect prompt block from KeyboardInterrupt
506 506 # when sitting on ctrl-C
507 507 self.hooks.pre_prompt_hook()
508 508 if more:
509 509 try:
510 510 prompt = self.prompt_manager.render('in2')
511 511 except Exception:
512 512 self.showtraceback()
513 513 if self.autoindent:
514 514 self.rl_do_indent = True
515 515
516 516 else:
517 517 try:
518 518 prompt = self.separate_in + self.prompt_manager.render('in')
519 519 except Exception:
520 520 self.showtraceback()
521 521
522 522 line = self.raw_input(prompt)
523 523 if self.exit_now:
524 524 # quick exit on sys.std[in|out] close
525 525 break
526 526 if self.autoindent:
527 527 self.rl_do_indent = False
528 528
529 529 except KeyboardInterrupt:
530 530 #double-guard against keyboardinterrupts during kbdint handling
531 531 try:
532 532 self.write('\n' + self.get_exception_only())
533 533 source_raw = self.input_splitter.raw_reset()
534 534 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
535 535 more = False
536 536 except KeyboardInterrupt:
537 537 pass
538 538 except EOFError:
539 539 if self.autoindent:
540 540 self.rl_do_indent = False
541 541 if self.has_readline:
542 542 self.readline_startup_hook(None)
543 543 self.write('\n')
544 544 self.exit()
545 545 except bdb.BdbQuit:
546 546 warn('The Python debugger has exited with a BdbQuit exception.\n'
547 547 'Because of how pdb handles the stack, it is impossible\n'
548 548 'for IPython to properly format this particular exception.\n'
549 549 'IPython will resume normal operation.')
550 550 except:
551 551 # exceptions here are VERY RARE, but they can be triggered
552 552 # asynchronously by signal handlers, for example.
553 553 self.showtraceback()
554 554 else:
555 555 try:
556 556 self.input_splitter.push(line)
557 557 more = self.input_splitter.push_accepts_more()
558 558 except SyntaxError:
559 559 # Run the code directly - run_cell takes care of displaying
560 560 # the exception.
561 561 more = False
562 562 if (self.SyntaxTB.last_syntax_error and
563 563 self.autoedit_syntax):
564 564 self.edit_syntax_error()
565 565 if not more:
566 566 source_raw = self.input_splitter.raw_reset()
567 567 hlen_b4_cell = self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
568 568 self.run_cell(source_raw)
569 569
570 570
571 571 # Turn off the exit flag, so the mainloop can be restarted if desired
572 572 self.exit_now = False
573 573
574 574 def init_history(self):
575 575 """Sets up the command history. """
576 576 self.history_manager = ZMQHistoryManager(client=self.client)
577 577 self.configurables.append(self.history_manager)
578 578
General Comments 0
You need to be logged in to leave comments. Login now