##// END OF EJS Templates
Machinery to replace the current cell instead of adding a new one
Thomas Kluyver -
Show More
@@ -1,3336 +1,3336 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Main IPython class."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 from __future__ import absolute_import, print_function
14 14
15 15 import __future__
16 16 import abc
17 17 import ast
18 18 import atexit
19 19 import functools
20 20 import os
21 21 import re
22 22 import runpy
23 23 import sys
24 24 import tempfile
25 25 import traceback
26 26 import types
27 27 import subprocess
28 28 from io import open as io_open
29 29
30 30 from IPython.config.configurable import SingletonConfigurable
31 31 from IPython.core import debugger, oinspect
32 32 from IPython.core import magic
33 33 from IPython.core import page
34 34 from IPython.core import prefilter
35 35 from IPython.core import shadowns
36 36 from IPython.core import ultratb
37 37 from IPython.core.alias import AliasManager, AliasError
38 38 from IPython.core.autocall import ExitAutocall
39 39 from IPython.core.builtin_trap import BuiltinTrap
40 40 from IPython.core.events import EventManager, available_events
41 41 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
42 42 from IPython.core.display_trap import DisplayTrap
43 43 from IPython.core.displayhook import DisplayHook
44 44 from IPython.core.displaypub import DisplayPublisher
45 45 from IPython.core.error import InputRejected, UsageError
46 46 from IPython.core.extensions import ExtensionManager
47 47 from IPython.core.formatters import DisplayFormatter
48 48 from IPython.core.history import HistoryManager
49 49 from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2
50 50 from IPython.core.logger import Logger
51 51 from IPython.core.macro import Macro
52 52 from IPython.core.payload import PayloadManager
53 53 from IPython.core.prefilter import PrefilterManager
54 54 from IPython.core.profiledir import ProfileDir
55 55 from IPython.core.prompts import PromptManager
56 56 from IPython.core.usage import default_banner
57 57 from IPython.lib.latextools import LaTeXTool
58 58 from IPython.testing.skipdoctest import skip_doctest
59 59 from IPython.utils import PyColorize
60 60 from IPython.utils import io
61 61 from IPython.utils import py3compat
62 62 from IPython.utils import openpy
63 63 from IPython.utils.decorators import undoc
64 64 from IPython.utils.io import ask_yes_no
65 65 from IPython.utils.ipstruct import Struct
66 66 from IPython.utils.path import get_home_dir, get_ipython_dir, get_py_filename, unquote_filename, ensure_dir_exists
67 67 from IPython.utils.pickleshare import PickleShareDB
68 68 from IPython.utils.process import system, getoutput
69 69 from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types,
70 70 with_metaclass, iteritems)
71 71 from IPython.utils.strdispatch import StrDispatch
72 72 from IPython.utils.syspathcontext import prepended_to_syspath
73 73 from IPython.utils.text import (format_screen, LSString, SList,
74 74 DollarFormatter)
75 75 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
76 76 List, Unicode, Instance, Type)
77 77 from IPython.utils.warn import warn, error
78 78 import IPython.core.hooks
79 79
80 80 #-----------------------------------------------------------------------------
81 81 # Globals
82 82 #-----------------------------------------------------------------------------
83 83
84 84 # compiled regexps for autoindent management
85 85 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
86 86
87 87 #-----------------------------------------------------------------------------
88 88 # Utilities
89 89 #-----------------------------------------------------------------------------
90 90
91 91 @undoc
92 92 def softspace(file, newvalue):
93 93 """Copied from code.py, to remove the dependency"""
94 94
95 95 oldvalue = 0
96 96 try:
97 97 oldvalue = file.softspace
98 98 except AttributeError:
99 99 pass
100 100 try:
101 101 file.softspace = newvalue
102 102 except (AttributeError, TypeError):
103 103 # "attribute-less object" or "read-only attributes"
104 104 pass
105 105 return oldvalue
106 106
107 107 @undoc
108 108 def no_op(*a, **kw): pass
109 109
110 110 @undoc
111 111 class NoOpContext(object):
112 112 def __enter__(self): pass
113 113 def __exit__(self, type, value, traceback): pass
114 114 no_op_context = NoOpContext()
115 115
116 116 class SpaceInInput(Exception): pass
117 117
118 118 @undoc
119 119 class Bunch: pass
120 120
121 121
122 122 def get_default_colors():
123 123 if sys.platform=='darwin':
124 124 return "LightBG"
125 125 elif os.name=='nt':
126 126 return 'Linux'
127 127 else:
128 128 return 'Linux'
129 129
130 130
131 131 class SeparateUnicode(Unicode):
132 132 r"""A Unicode subclass to validate separate_in, separate_out, etc.
133 133
134 134 This is a Unicode based trait that converts '0'->'' and ``'\\n'->'\n'``.
135 135 """
136 136
137 137 def validate(self, obj, value):
138 138 if value == '0': value = ''
139 139 value = value.replace('\\n','\n')
140 140 return super(SeparateUnicode, self).validate(obj, value)
141 141
142 142
143 143 class ReadlineNoRecord(object):
144 144 """Context manager to execute some code, then reload readline history
145 145 so that interactive input to the code doesn't appear when pressing up."""
146 146 def __init__(self, shell):
147 147 self.shell = shell
148 148 self._nested_level = 0
149 149
150 150 def __enter__(self):
151 151 if self._nested_level == 0:
152 152 try:
153 153 self.orig_length = self.current_length()
154 154 self.readline_tail = self.get_readline_tail()
155 155 except (AttributeError, IndexError): # Can fail with pyreadline
156 156 self.orig_length, self.readline_tail = 999999, []
157 157 self._nested_level += 1
158 158
159 159 def __exit__(self, type, value, traceback):
160 160 self._nested_level -= 1
161 161 if self._nested_level == 0:
162 162 # Try clipping the end if it's got longer
163 163 try:
164 164 e = self.current_length() - self.orig_length
165 165 if e > 0:
166 166 for _ in range(e):
167 167 self.shell.readline.remove_history_item(self.orig_length)
168 168
169 169 # If it still doesn't match, just reload readline history.
170 170 if self.current_length() != self.orig_length \
171 171 or self.get_readline_tail() != self.readline_tail:
172 172 self.shell.refill_readline_hist()
173 173 except (AttributeError, IndexError):
174 174 pass
175 175 # Returning False will cause exceptions to propagate
176 176 return False
177 177
178 178 def current_length(self):
179 179 return self.shell.readline.get_current_history_length()
180 180
181 181 def get_readline_tail(self, n=10):
182 182 """Get the last n items in readline history."""
183 183 end = self.shell.readline.get_current_history_length() + 1
184 184 start = max(end-n, 1)
185 185 ghi = self.shell.readline.get_history_item
186 186 return [ghi(x) for x in range(start, end)]
187 187
188 188
189 189 @undoc
190 190 class DummyMod(object):
191 191 """A dummy module used for IPython's interactive module when
192 192 a namespace must be assigned to the module's __dict__."""
193 193 pass
194 194
195 195 #-----------------------------------------------------------------------------
196 196 # Main IPython class
197 197 #-----------------------------------------------------------------------------
198 198
199 199 class InteractiveShell(SingletonConfigurable):
200 200 """An enhanced, interactive shell for Python."""
201 201
202 202 _instance = None
203 203
204 204 ast_transformers = List([], config=True, help=
205 205 """
206 206 A list of ast.NodeTransformer subclass instances, which will be applied
207 207 to user input before code is run.
208 208 """
209 209 )
210 210
211 211 autocall = Enum((0,1,2), default_value=0, config=True, help=
212 212 """
213 213 Make IPython automatically call any callable object even if you didn't
214 214 type explicit parentheses. For example, 'str 43' becomes 'str(43)'
215 215 automatically. The value can be '0' to disable the feature, '1' for
216 216 'smart' autocall, where it is not applied if there are no more
217 217 arguments on the line, and '2' for 'full' autocall, where all callable
218 218 objects are automatically called (even if no arguments are present).
219 219 """
220 220 )
221 221 # TODO: remove all autoindent logic and put into frontends.
222 222 # We can't do this yet because even runlines uses the autoindent.
223 223 autoindent = CBool(True, config=True, help=
224 224 """
225 225 Autoindent IPython code entered interactively.
226 226 """
227 227 )
228 228 automagic = CBool(True, config=True, help=
229 229 """
230 230 Enable magic commands to be called without the leading %.
231 231 """
232 232 )
233 233
234 234 banner = Unicode('')
235 235
236 236 banner1 = Unicode(default_banner, config=True,
237 237 help="""The part of the banner to be printed before the profile"""
238 238 )
239 239 banner2 = Unicode('', config=True,
240 240 help="""The part of the banner to be printed after the profile"""
241 241 )
242 242
243 243 cache_size = Integer(1000, config=True, help=
244 244 """
245 245 Set the size of the output cache. The default is 1000, you can
246 246 change it permanently in your config file. Setting it to 0 completely
247 247 disables the caching system, and the minimum value accepted is 20 (if
248 248 you provide a value less than 20, it is reset to 0 and a warning is
249 249 issued). This limit is defined because otherwise you'll spend more
250 250 time re-flushing a too small cache than working
251 251 """
252 252 )
253 253 color_info = CBool(True, config=True, help=
254 254 """
255 255 Use colors for displaying information about objects. Because this
256 256 information is passed through a pager (like 'less'), and some pagers
257 257 get confused with color codes, this capability can be turned off.
258 258 """
259 259 )
260 260 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
261 261 default_value=get_default_colors(), config=True,
262 262 help="Set the color scheme (NoColor, Linux, or LightBG)."
263 263 )
264 264 colors_force = CBool(False, help=
265 265 """
266 266 Force use of ANSI color codes, regardless of OS and readline
267 267 availability.
268 268 """
269 269 # FIXME: This is essentially a hack to allow ZMQShell to show colors
270 270 # without readline on Win32. When the ZMQ formatting system is
271 271 # refactored, this should be removed.
272 272 )
273 273 debug = CBool(False, config=True)
274 274 deep_reload = CBool(False, config=True, help=
275 275 """
276 276 Enable deep (recursive) reloading by default. IPython can use the
277 277 deep_reload module which reloads changes in modules recursively (it
278 278 replaces the reload() function, so you don't need to change anything to
279 279 use it). deep_reload() forces a full reload of modules whose code may
280 280 have changed, which the default reload() function does not. When
281 281 deep_reload is off, IPython will use the normal reload(), but
282 282 deep_reload will still be available as dreload().
283 283 """
284 284 )
285 285 disable_failing_post_execute = CBool(False, config=True,
286 286 help="Don't call post-execute functions that have failed in the past."
287 287 )
288 288 display_formatter = Instance(DisplayFormatter)
289 289 displayhook_class = Type(DisplayHook)
290 290 display_pub_class = Type(DisplayPublisher)
291 291 data_pub_class = None
292 292
293 293 exit_now = CBool(False)
294 294 exiter = Instance(ExitAutocall)
295 295 def _exiter_default(self):
296 296 return ExitAutocall(self)
297 297 # Monotonically increasing execution counter
298 298 execution_count = Integer(1)
299 299 filename = Unicode("<ipython console>")
300 300 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
301 301
302 302 # Input splitter, to transform input line by line and detect when a block
303 303 # is ready to be executed.
304 304 input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
305 305 (), {'line_input_checker': True})
306 306
307 307 # This InputSplitter instance is used to transform completed cells before
308 308 # running them. It allows cell magics to contain blank lines.
309 309 input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter',
310 310 (), {'line_input_checker': False})
311 311
312 312 logstart = CBool(False, config=True, help=
313 313 """
314 314 Start logging to the default log file.
315 315 """
316 316 )
317 317 logfile = Unicode('', config=True, help=
318 318 """
319 319 The name of the logfile to use.
320 320 """
321 321 )
322 322 logappend = Unicode('', config=True, help=
323 323 """
324 324 Start logging to the given file in append mode.
325 325 """
326 326 )
327 327 object_info_string_level = Enum((0,1,2), default_value=0,
328 328 config=True)
329 329 pdb = CBool(False, config=True, help=
330 330 """
331 331 Automatically call the pdb debugger after every exception.
332 332 """
333 333 )
334 334 multiline_history = CBool(sys.platform != 'win32', config=True,
335 335 help="Save multi-line entries as one entry in readline history"
336 336 )
337 337
338 338 # deprecated prompt traits:
339 339
340 340 prompt_in1 = Unicode('In [\\#]: ', config=True,
341 341 help="Deprecated, use PromptManager.in_template")
342 342 prompt_in2 = Unicode(' .\\D.: ', config=True,
343 343 help="Deprecated, use PromptManager.in2_template")
344 344 prompt_out = Unicode('Out[\\#]: ', config=True,
345 345 help="Deprecated, use PromptManager.out_template")
346 346 prompts_pad_left = CBool(True, config=True,
347 347 help="Deprecated, use PromptManager.justify")
348 348
349 349 def _prompt_trait_changed(self, name, old, new):
350 350 table = {
351 351 'prompt_in1' : 'in_template',
352 352 'prompt_in2' : 'in2_template',
353 353 'prompt_out' : 'out_template',
354 354 'prompts_pad_left' : 'justify',
355 355 }
356 356 warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format(
357 357 name=name, newname=table[name])
358 358 )
359 359 # protect against weird cases where self.config may not exist:
360 360 if self.config is not None:
361 361 # propagate to corresponding PromptManager trait
362 362 setattr(self.config.PromptManager, table[name], new)
363 363
364 364 _prompt_in1_changed = _prompt_trait_changed
365 365 _prompt_in2_changed = _prompt_trait_changed
366 366 _prompt_out_changed = _prompt_trait_changed
367 367 _prompt_pad_left_changed = _prompt_trait_changed
368 368
369 369 show_rewritten_input = CBool(True, config=True,
370 370 help="Show rewritten input, e.g. for autocall."
371 371 )
372 372
373 373 quiet = CBool(False, config=True)
374 374
375 375 history_length = Integer(10000, config=True)
376 376
377 377 # The readline stuff will eventually be moved to the terminal subclass
378 378 # but for now, we can't do that as readline is welded in everywhere.
379 379 readline_use = CBool(True, config=True)
380 380 readline_remove_delims = Unicode('-/~', config=True)
381 381 readline_delims = Unicode() # set by init_readline()
382 382 # don't use \M- bindings by default, because they
383 383 # conflict with 8-bit encodings. See gh-58,gh-88
384 384 readline_parse_and_bind = List([
385 385 'tab: complete',
386 386 '"\C-l": clear-screen',
387 387 'set show-all-if-ambiguous on',
388 388 '"\C-o": tab-insert',
389 389 '"\C-r": reverse-search-history',
390 390 '"\C-s": forward-search-history',
391 391 '"\C-p": history-search-backward',
392 392 '"\C-n": history-search-forward',
393 393 '"\e[A": history-search-backward',
394 394 '"\e[B": history-search-forward',
395 395 '"\C-k": kill-line',
396 396 '"\C-u": unix-line-discard',
397 397 ], config=True)
398 398
399 399 _custom_readline_config = False
400 400
401 401 def _readline_parse_and_bind_changed(self, name, old, new):
402 402 # notice that readline config is customized
403 403 # indicates that it should have higher priority than inputrc
404 404 self._custom_readline_config = True
405 405
406 406 ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'],
407 407 default_value='last_expr', config=True,
408 408 help="""
409 409 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
410 410 run interactively (displaying output from expressions).""")
411 411
412 412 # TODO: this part of prompt management should be moved to the frontends.
413 413 # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n'
414 414 separate_in = SeparateUnicode('\n', config=True)
415 415 separate_out = SeparateUnicode('', config=True)
416 416 separate_out2 = SeparateUnicode('', config=True)
417 417 wildcards_case_sensitive = CBool(True, config=True)
418 418 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
419 419 default_value='Context', config=True)
420 420
421 421 # Subcomponents of InteractiveShell
422 422 alias_manager = Instance('IPython.core.alias.AliasManager')
423 423 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
424 424 builtin_trap = Instance('IPython.core.builtin_trap.BuiltinTrap')
425 425 display_trap = Instance('IPython.core.display_trap.DisplayTrap')
426 426 extension_manager = Instance('IPython.core.extensions.ExtensionManager')
427 427 payload_manager = Instance('IPython.core.payload.PayloadManager')
428 428 history_manager = Instance('IPython.core.history.HistoryAccessorBase')
429 429 magics_manager = Instance('IPython.core.magic.MagicsManager')
430 430
431 431 profile_dir = Instance('IPython.core.application.ProfileDir')
432 432 @property
433 433 def profile(self):
434 434 if self.profile_dir is not None:
435 435 name = os.path.basename(self.profile_dir.location)
436 436 return name.replace('profile_','')
437 437
438 438
439 439 # Private interface
440 440 _post_execute = Instance(dict)
441 441
442 442 # Tracks any GUI loop loaded for pylab
443 443 pylab_gui_select = None
444 444
445 445 def __init__(self, ipython_dir=None, profile_dir=None,
446 446 user_module=None, user_ns=None,
447 447 custom_exceptions=((), None), **kwargs):
448 448
449 449 # This is where traits with a config_key argument are updated
450 450 # from the values on config.
451 451 super(InteractiveShell, self).__init__(**kwargs)
452 452 self.configurables = [self]
453 453
454 454 # These are relatively independent and stateless
455 455 self.init_ipython_dir(ipython_dir)
456 456 self.init_profile_dir(profile_dir)
457 457 self.init_instance_attrs()
458 458 self.init_environment()
459 459
460 460 # Check if we're in a virtualenv, and set up sys.path.
461 461 self.init_virtualenv()
462 462
463 463 # Create namespaces (user_ns, user_global_ns, etc.)
464 464 self.init_create_namespaces(user_module, user_ns)
465 465 # This has to be done after init_create_namespaces because it uses
466 466 # something in self.user_ns, but before init_sys_modules, which
467 467 # is the first thing to modify sys.
468 468 # TODO: When we override sys.stdout and sys.stderr before this class
469 469 # is created, we are saving the overridden ones here. Not sure if this
470 470 # is what we want to do.
471 471 self.save_sys_module_state()
472 472 self.init_sys_modules()
473 473
474 474 # While we're trying to have each part of the code directly access what
475 475 # it needs without keeping redundant references to objects, we have too
476 476 # much legacy code that expects ip.db to exist.
477 477 self.db = PickleShareDB(os.path.join(self.profile_dir.location, 'db'))
478 478
479 479 self.init_history()
480 480 self.init_encoding()
481 481 self.init_prefilter()
482 482
483 483 self.init_syntax_highlighting()
484 484 self.init_hooks()
485 485 self.init_events()
486 486 self.init_pushd_popd_magic()
487 487 # self.init_traceback_handlers use to be here, but we moved it below
488 488 # because it and init_io have to come after init_readline.
489 489 self.init_user_ns()
490 490 self.init_logger()
491 491 self.init_builtins()
492 492
493 493 # The following was in post_config_initialization
494 494 self.init_inspector()
495 495 # init_readline() must come before init_io(), because init_io uses
496 496 # readline related things.
497 497 self.init_readline()
498 498 # We save this here in case user code replaces raw_input, but it needs
499 499 # to be after init_readline(), because PyPy's readline works by replacing
500 500 # raw_input.
501 501 if py3compat.PY3:
502 502 self.raw_input_original = input
503 503 else:
504 504 self.raw_input_original = raw_input
505 505 # init_completer must come after init_readline, because it needs to
506 506 # know whether readline is present or not system-wide to configure the
507 507 # completers, since the completion machinery can now operate
508 508 # independently of readline (e.g. over the network)
509 509 self.init_completer()
510 510 # TODO: init_io() needs to happen before init_traceback handlers
511 511 # because the traceback handlers hardcode the stdout/stderr streams.
512 512 # This logic in in debugger.Pdb and should eventually be changed.
513 513 self.init_io()
514 514 self.init_traceback_handlers(custom_exceptions)
515 515 self.init_prompts()
516 516 self.init_display_formatter()
517 517 self.init_display_pub()
518 518 self.init_data_pub()
519 519 self.init_displayhook()
520 520 self.init_latextool()
521 521 self.init_magics()
522 522 self.init_alias()
523 523 self.init_logstart()
524 524 self.init_pdb()
525 525 self.init_extension_manager()
526 526 self.init_payload()
527 527 self.hooks.late_startup_hook()
528 528 self.events.trigger('shell_initialized', self)
529 529 atexit.register(self.atexit_operations)
530 530
531 531 def get_ipython(self):
532 532 """Return the currently running IPython instance."""
533 533 return self
534 534
535 535 #-------------------------------------------------------------------------
536 536 # Trait changed handlers
537 537 #-------------------------------------------------------------------------
538 538
539 539 def _ipython_dir_changed(self, name, new):
540 540 ensure_dir_exists(new)
541 541
542 542 def set_autoindent(self,value=None):
543 543 """Set the autoindent flag, checking for readline support.
544 544
545 545 If called with no arguments, it acts as a toggle."""
546 546
547 547 if value != 0 and not self.has_readline:
548 548 if os.name == 'posix':
549 549 warn("The auto-indent feature requires the readline library")
550 550 self.autoindent = 0
551 551 return
552 552 if value is None:
553 553 self.autoindent = not self.autoindent
554 554 else:
555 555 self.autoindent = value
556 556
557 557 #-------------------------------------------------------------------------
558 558 # init_* methods called by __init__
559 559 #-------------------------------------------------------------------------
560 560
561 561 def init_ipython_dir(self, ipython_dir):
562 562 if ipython_dir is not None:
563 563 self.ipython_dir = ipython_dir
564 564 return
565 565
566 566 self.ipython_dir = get_ipython_dir()
567 567
568 568 def init_profile_dir(self, profile_dir):
569 569 if profile_dir is not None:
570 570 self.profile_dir = profile_dir
571 571 return
572 572 self.profile_dir =\
573 573 ProfileDir.create_profile_dir_by_name(self.ipython_dir, 'default')
574 574
575 575 def init_instance_attrs(self):
576 576 self.more = False
577 577
578 578 # command compiler
579 579 self.compile = CachingCompiler()
580 580
581 581 # Make an empty namespace, which extension writers can rely on both
582 582 # existing and NEVER being used by ipython itself. This gives them a
583 583 # convenient location for storing additional information and state
584 584 # their extensions may require, without fear of collisions with other
585 585 # ipython names that may develop later.
586 586 self.meta = Struct()
587 587
588 588 # Temporary files used for various purposes. Deleted at exit.
589 589 self.tempfiles = []
590 590 self.tempdirs = []
591 591
592 592 # Keep track of readline usage (later set by init_readline)
593 593 self.has_readline = False
594 594
595 595 # keep track of where we started running (mainly for crash post-mortem)
596 596 # This is not being used anywhere currently.
597 597 self.starting_dir = py3compat.getcwd()
598 598
599 599 # Indentation management
600 600 self.indent_current_nsp = 0
601 601
602 602 # Dict to track post-execution functions that have been registered
603 603 self._post_execute = {}
604 604
605 605 def init_environment(self):
606 606 """Any changes we need to make to the user's environment."""
607 607 pass
608 608
609 609 def init_encoding(self):
610 610 # Get system encoding at startup time. Certain terminals (like Emacs
611 611 # under Win32 have it set to None, and we need to have a known valid
612 612 # encoding to use in the raw_input() method
613 613 try:
614 614 self.stdin_encoding = sys.stdin.encoding or 'ascii'
615 615 except AttributeError:
616 616 self.stdin_encoding = 'ascii'
617 617
618 618 def init_syntax_highlighting(self):
619 619 # Python source parser/formatter for syntax highlighting
620 620 pyformat = PyColorize.Parser().format
621 621 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
622 622
623 623 def init_pushd_popd_magic(self):
624 624 # for pushd/popd management
625 625 self.home_dir = get_home_dir()
626 626
627 627 self.dir_stack = []
628 628
629 629 def init_logger(self):
630 630 self.logger = Logger(self.home_dir, logfname='ipython_log.py',
631 631 logmode='rotate')
632 632
633 633 def init_logstart(self):
634 634 """Initialize logging in case it was requested at the command line.
635 635 """
636 636 if self.logappend:
637 637 self.magic('logstart %s append' % self.logappend)
638 638 elif self.logfile:
639 639 self.magic('logstart %s' % self.logfile)
640 640 elif self.logstart:
641 641 self.magic('logstart')
642 642
643 643 def init_builtins(self):
644 644 # A single, static flag that we set to True. Its presence indicates
645 645 # that an IPython shell has been created, and we make no attempts at
646 646 # removing on exit or representing the existence of more than one
647 647 # IPython at a time.
648 648 builtin_mod.__dict__['__IPYTHON__'] = True
649 649
650 650 # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to
651 651 # manage on enter/exit, but with all our shells it's virtually
652 652 # impossible to get all the cases right. We're leaving the name in for
653 653 # those who adapted their codes to check for this flag, but will
654 654 # eventually remove it after a few more releases.
655 655 builtin_mod.__dict__['__IPYTHON__active'] = \
656 656 'Deprecated, check for __IPYTHON__'
657 657
658 658 self.builtin_trap = BuiltinTrap(shell=self)
659 659
660 660 def init_inspector(self):
661 661 # Object inspector
662 662 self.inspector = oinspect.Inspector(oinspect.InspectColors,
663 663 PyColorize.ANSICodeColors,
664 664 'NoColor',
665 665 self.object_info_string_level)
666 666
667 667 def init_io(self):
668 668 # This will just use sys.stdout and sys.stderr. If you want to
669 669 # override sys.stdout and sys.stderr themselves, you need to do that
670 670 # *before* instantiating this class, because io holds onto
671 671 # references to the underlying streams.
672 672 if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline:
673 673 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
674 674 else:
675 675 io.stdout = io.IOStream(sys.stdout)
676 676 io.stderr = io.IOStream(sys.stderr)
677 677
678 678 def init_prompts(self):
679 679 self.prompt_manager = PromptManager(shell=self, parent=self)
680 680 self.configurables.append(self.prompt_manager)
681 681 # Set system prompts, so that scripts can decide if they are running
682 682 # interactively.
683 683 sys.ps1 = 'In : '
684 684 sys.ps2 = '...: '
685 685 sys.ps3 = 'Out: '
686 686
687 687 def init_display_formatter(self):
688 688 self.display_formatter = DisplayFormatter(parent=self)
689 689 self.configurables.append(self.display_formatter)
690 690
691 691 def init_display_pub(self):
692 692 self.display_pub = self.display_pub_class(parent=self)
693 693 self.configurables.append(self.display_pub)
694 694
695 695 def init_data_pub(self):
696 696 if not self.data_pub_class:
697 697 self.data_pub = None
698 698 return
699 699 self.data_pub = self.data_pub_class(parent=self)
700 700 self.configurables.append(self.data_pub)
701 701
702 702 def init_displayhook(self):
703 703 # Initialize displayhook, set in/out prompts and printing system
704 704 self.displayhook = self.displayhook_class(
705 705 parent=self,
706 706 shell=self,
707 707 cache_size=self.cache_size,
708 708 )
709 709 self.configurables.append(self.displayhook)
710 710 # This is a context manager that installs/revmoes the displayhook at
711 711 # the appropriate time.
712 712 self.display_trap = DisplayTrap(hook=self.displayhook)
713 713
714 714 def init_latextool(self):
715 715 """Configure LaTeXTool."""
716 716 cfg = LaTeXTool.instance(parent=self)
717 717 if cfg not in self.configurables:
718 718 self.configurables.append(cfg)
719 719
720 720 def init_virtualenv(self):
721 721 """Add a virtualenv to sys.path so the user can import modules from it.
722 722 This isn't perfect: it doesn't use the Python interpreter with which the
723 723 virtualenv was built, and it ignores the --no-site-packages option. A
724 724 warning will appear suggesting the user installs IPython in the
725 725 virtualenv, but for many cases, it probably works well enough.
726 726
727 727 Adapted from code snippets online.
728 728
729 729 http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv
730 730 """
731 731 if 'VIRTUAL_ENV' not in os.environ:
732 732 # Not in a virtualenv
733 733 return
734 734
735 735 # venv detection:
736 736 # stdlib venv may symlink sys.executable, so we can't use realpath.
737 737 # but others can symlink *to* the venv Python, so we can't just use sys.executable.
738 738 # So we just check every item in the symlink tree (generally <= 3)
739 739 p = os.path.normcase(sys.executable)
740 740 paths = [p]
741 741 while os.path.islink(p):
742 742 p = os.path.normcase(os.path.join(os.path.dirname(p), os.readlink(p)))
743 743 paths.append(p)
744 744 p_venv = os.path.normcase(os.environ['VIRTUAL_ENV'])
745 745 if any(p.startswith(p_venv) for p in paths):
746 746 # Running properly in the virtualenv, don't need to do anything
747 747 return
748 748
749 749 warn("Attempting to work in a virtualenv. If you encounter problems, please "
750 750 "install IPython inside the virtualenv.")
751 751 if sys.platform == "win32":
752 752 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'Lib', 'site-packages')
753 753 else:
754 754 virtual_env = os.path.join(os.environ['VIRTUAL_ENV'], 'lib',
755 755 'python%d.%d' % sys.version_info[:2], 'site-packages')
756 756
757 757 import site
758 758 sys.path.insert(0, virtual_env)
759 759 site.addsitedir(virtual_env)
760 760
761 761 #-------------------------------------------------------------------------
762 762 # Things related to injections into the sys module
763 763 #-------------------------------------------------------------------------
764 764
765 765 def save_sys_module_state(self):
766 766 """Save the state of hooks in the sys module.
767 767
768 768 This has to be called after self.user_module is created.
769 769 """
770 770 self._orig_sys_module_state = {}
771 771 self._orig_sys_module_state['stdin'] = sys.stdin
772 772 self._orig_sys_module_state['stdout'] = sys.stdout
773 773 self._orig_sys_module_state['stderr'] = sys.stderr
774 774 self._orig_sys_module_state['excepthook'] = sys.excepthook
775 775 self._orig_sys_modules_main_name = self.user_module.__name__
776 776 self._orig_sys_modules_main_mod = sys.modules.get(self.user_module.__name__)
777 777
778 778 def restore_sys_module_state(self):
779 779 """Restore the state of the sys module."""
780 780 try:
781 781 for k, v in iteritems(self._orig_sys_module_state):
782 782 setattr(sys, k, v)
783 783 except AttributeError:
784 784 pass
785 785 # Reset what what done in self.init_sys_modules
786 786 if self._orig_sys_modules_main_mod is not None:
787 787 sys.modules[self._orig_sys_modules_main_name] = self._orig_sys_modules_main_mod
788 788
789 789 #-------------------------------------------------------------------------
790 790 # Things related to the banner
791 791 #-------------------------------------------------------------------------
792 792
793 793 @property
794 794 def banner(self):
795 795 banner = self.banner1
796 796 if self.profile and self.profile != 'default':
797 797 banner += '\nIPython profile: %s\n' % self.profile
798 798 if self.banner2:
799 799 banner += '\n' + self.banner2
800 800 return banner
801 801
802 802 def show_banner(self, banner=None):
803 803 if banner is None:
804 804 banner = self.banner
805 805 self.write(banner)
806 806
807 807 #-------------------------------------------------------------------------
808 808 # Things related to hooks
809 809 #-------------------------------------------------------------------------
810 810
811 811 def init_hooks(self):
812 812 # hooks holds pointers used for user-side customizations
813 813 self.hooks = Struct()
814 814
815 815 self.strdispatchers = {}
816 816
817 817 # Set all default hooks, defined in the IPython.hooks module.
818 818 hooks = IPython.core.hooks
819 819 for hook_name in hooks.__all__:
820 820 # default hooks have priority 100, i.e. low; user hooks should have
821 821 # 0-100 priority
822 822 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
823 823
824 824 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
825 825 _warn_deprecated=True):
826 826 """set_hook(name,hook) -> sets an internal IPython hook.
827 827
828 828 IPython exposes some of its internal API as user-modifiable hooks. By
829 829 adding your function to one of these hooks, you can modify IPython's
830 830 behavior to call at runtime your own routines."""
831 831
832 832 # At some point in the future, this should validate the hook before it
833 833 # accepts it. Probably at least check that the hook takes the number
834 834 # of args it's supposed to.
835 835
836 836 f = types.MethodType(hook,self)
837 837
838 838 # check if the hook is for strdispatcher first
839 839 if str_key is not None:
840 840 sdp = self.strdispatchers.get(name, StrDispatch())
841 841 sdp.add_s(str_key, f, priority )
842 842 self.strdispatchers[name] = sdp
843 843 return
844 844 if re_key is not None:
845 845 sdp = self.strdispatchers.get(name, StrDispatch())
846 846 sdp.add_re(re.compile(re_key), f, priority )
847 847 self.strdispatchers[name] = sdp
848 848 return
849 849
850 850 dp = getattr(self.hooks, name, None)
851 851 if name not in IPython.core.hooks.__all__:
852 852 print("Warning! Hook '%s' is not one of %s" % \
853 853 (name, IPython.core.hooks.__all__ ))
854 854
855 855 if _warn_deprecated and (name in IPython.core.hooks.deprecated):
856 856 alternative = IPython.core.hooks.deprecated[name]
857 857 warn("Hook {} is deprecated. Use {} instead.".format(name, alternative))
858 858
859 859 if not dp:
860 860 dp = IPython.core.hooks.CommandChainDispatcher()
861 861
862 862 try:
863 863 dp.add(f,priority)
864 864 except AttributeError:
865 865 # it was not commandchain, plain old func - replace
866 866 dp = f
867 867
868 868 setattr(self.hooks,name, dp)
869 869
870 870 #-------------------------------------------------------------------------
871 871 # Things related to events
872 872 #-------------------------------------------------------------------------
873 873
874 874 def init_events(self):
875 875 self.events = EventManager(self, available_events)
876 876
877 877 self.events.register("pre_execute", self._clear_warning_registry)
878 878
879 879 def register_post_execute(self, func):
880 880 """DEPRECATED: Use ip.events.register('post_run_cell', func)
881 881
882 882 Register a function for calling after code execution.
883 883 """
884 884 warn("ip.register_post_execute is deprecated, use "
885 885 "ip.events.register('post_run_cell', func) instead.")
886 886 self.events.register('post_run_cell', func)
887 887
888 888 def _clear_warning_registry(self):
889 889 # clear the warning registry, so that different code blocks with
890 890 # overlapping line number ranges don't cause spurious suppression of
891 891 # warnings (see gh-6611 for details)
892 892 if "__warningregistry__" in self.user_global_ns:
893 893 del self.user_global_ns["__warningregistry__"]
894 894
895 895 #-------------------------------------------------------------------------
896 896 # Things related to the "main" module
897 897 #-------------------------------------------------------------------------
898 898
899 899 def new_main_mod(self, filename, modname):
900 900 """Return a new 'main' module object for user code execution.
901 901
902 902 ``filename`` should be the path of the script which will be run in the
903 903 module. Requests with the same filename will get the same module, with
904 904 its namespace cleared.
905 905
906 906 ``modname`` should be the module name - normally either '__main__' or
907 907 the basename of the file without the extension.
908 908
909 909 When scripts are executed via %run, we must keep a reference to their
910 910 __main__ module around so that Python doesn't
911 911 clear it, rendering references to module globals useless.
912 912
913 913 This method keeps said reference in a private dict, keyed by the
914 914 absolute path of the script. This way, for multiple executions of the
915 915 same script we only keep one copy of the namespace (the last one),
916 916 thus preventing memory leaks from old references while allowing the
917 917 objects from the last execution to be accessible.
918 918 """
919 919 filename = os.path.abspath(filename)
920 920 try:
921 921 main_mod = self._main_mod_cache[filename]
922 922 except KeyError:
923 923 main_mod = self._main_mod_cache[filename] = types.ModuleType(
924 924 py3compat.cast_bytes_py2(modname),
925 925 doc="Module created for script run in IPython")
926 926 else:
927 927 main_mod.__dict__.clear()
928 928 main_mod.__name__ = modname
929 929
930 930 main_mod.__file__ = filename
931 931 # It seems pydoc (and perhaps others) needs any module instance to
932 932 # implement a __nonzero__ method
933 933 main_mod.__nonzero__ = lambda : True
934 934
935 935 return main_mod
936 936
937 937 def clear_main_mod_cache(self):
938 938 """Clear the cache of main modules.
939 939
940 940 Mainly for use by utilities like %reset.
941 941
942 942 Examples
943 943 --------
944 944
945 945 In [15]: import IPython
946 946
947 947 In [16]: m = _ip.new_main_mod(IPython.__file__, 'IPython')
948 948
949 949 In [17]: len(_ip._main_mod_cache) > 0
950 950 Out[17]: True
951 951
952 952 In [18]: _ip.clear_main_mod_cache()
953 953
954 954 In [19]: len(_ip._main_mod_cache) == 0
955 955 Out[19]: True
956 956 """
957 957 self._main_mod_cache.clear()
958 958
959 959 #-------------------------------------------------------------------------
960 960 # Things related to debugging
961 961 #-------------------------------------------------------------------------
962 962
963 963 def init_pdb(self):
964 964 # Set calling of pdb on exceptions
965 965 # self.call_pdb is a property
966 966 self.call_pdb = self.pdb
967 967
968 968 def _get_call_pdb(self):
969 969 return self._call_pdb
970 970
971 971 def _set_call_pdb(self,val):
972 972
973 973 if val not in (0,1,False,True):
974 974 raise ValueError('new call_pdb value must be boolean')
975 975
976 976 # store value in instance
977 977 self._call_pdb = val
978 978
979 979 # notify the actual exception handlers
980 980 self.InteractiveTB.call_pdb = val
981 981
982 982 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
983 983 'Control auto-activation of pdb at exceptions')
984 984
985 985 def debugger(self,force=False):
986 986 """Call the pydb/pdb debugger.
987 987
988 988 Keywords:
989 989
990 990 - force(False): by default, this routine checks the instance call_pdb
991 991 flag and does not actually invoke the debugger if the flag is false.
992 992 The 'force' option forces the debugger to activate even if the flag
993 993 is false.
994 994 """
995 995
996 996 if not (force or self.call_pdb):
997 997 return
998 998
999 999 if not hasattr(sys,'last_traceback'):
1000 1000 error('No traceback has been produced, nothing to debug.')
1001 1001 return
1002 1002
1003 1003 # use pydb if available
1004 1004 if debugger.has_pydb:
1005 1005 from pydb import pm
1006 1006 else:
1007 1007 # fallback to our internal debugger
1008 1008 pm = lambda : self.InteractiveTB.debugger(force=True)
1009 1009
1010 1010 with self.readline_no_record:
1011 1011 pm()
1012 1012
1013 1013 #-------------------------------------------------------------------------
1014 1014 # Things related to IPython's various namespaces
1015 1015 #-------------------------------------------------------------------------
1016 1016 default_user_namespaces = True
1017 1017
1018 1018 def init_create_namespaces(self, user_module=None, user_ns=None):
1019 1019 # Create the namespace where the user will operate. user_ns is
1020 1020 # normally the only one used, and it is passed to the exec calls as
1021 1021 # the locals argument. But we do carry a user_global_ns namespace
1022 1022 # given as the exec 'globals' argument, This is useful in embedding
1023 1023 # situations where the ipython shell opens in a context where the
1024 1024 # distinction between locals and globals is meaningful. For
1025 1025 # non-embedded contexts, it is just the same object as the user_ns dict.
1026 1026
1027 1027 # FIXME. For some strange reason, __builtins__ is showing up at user
1028 1028 # level as a dict instead of a module. This is a manual fix, but I
1029 1029 # should really track down where the problem is coming from. Alex
1030 1030 # Schmolck reported this problem first.
1031 1031
1032 1032 # A useful post by Alex Martelli on this topic:
1033 1033 # Re: inconsistent value from __builtins__
1034 1034 # Von: Alex Martelli <aleaxit@yahoo.com>
1035 1035 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
1036 1036 # Gruppen: comp.lang.python
1037 1037
1038 1038 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
1039 1039 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
1040 1040 # > <type 'dict'>
1041 1041 # > >>> print type(__builtins__)
1042 1042 # > <type 'module'>
1043 1043 # > Is this difference in return value intentional?
1044 1044
1045 1045 # Well, it's documented that '__builtins__' can be either a dictionary
1046 1046 # or a module, and it's been that way for a long time. Whether it's
1047 1047 # intentional (or sensible), I don't know. In any case, the idea is
1048 1048 # that if you need to access the built-in namespace directly, you
1049 1049 # should start with "import __builtin__" (note, no 's') which will
1050 1050 # definitely give you a module. Yeah, it's somewhat confusing:-(.
1051 1051
1052 1052 # These routines return a properly built module and dict as needed by
1053 1053 # the rest of the code, and can also be used by extension writers to
1054 1054 # generate properly initialized namespaces.
1055 1055 if (user_ns is not None) or (user_module is not None):
1056 1056 self.default_user_namespaces = False
1057 1057 self.user_module, self.user_ns = self.prepare_user_module(user_module, user_ns)
1058 1058
1059 1059 # A record of hidden variables we have added to the user namespace, so
1060 1060 # we can list later only variables defined in actual interactive use.
1061 1061 self.user_ns_hidden = {}
1062 1062
1063 1063 # Now that FakeModule produces a real module, we've run into a nasty
1064 1064 # problem: after script execution (via %run), the module where the user
1065 1065 # code ran is deleted. Now that this object is a true module (needed
1066 1066 # so docetst and other tools work correctly), the Python module
1067 1067 # teardown mechanism runs over it, and sets to None every variable
1068 1068 # present in that module. Top-level references to objects from the
1069 1069 # script survive, because the user_ns is updated with them. However,
1070 1070 # calling functions defined in the script that use other things from
1071 1071 # the script will fail, because the function's closure had references
1072 1072 # to the original objects, which are now all None. So we must protect
1073 1073 # these modules from deletion by keeping a cache.
1074 1074 #
1075 1075 # To avoid keeping stale modules around (we only need the one from the
1076 1076 # last run), we use a dict keyed with the full path to the script, so
1077 1077 # only the last version of the module is held in the cache. Note,
1078 1078 # however, that we must cache the module *namespace contents* (their
1079 1079 # __dict__). Because if we try to cache the actual modules, old ones
1080 1080 # (uncached) could be destroyed while still holding references (such as
1081 1081 # those held by GUI objects that tend to be long-lived)>
1082 1082 #
1083 1083 # The %reset command will flush this cache. See the cache_main_mod()
1084 1084 # and clear_main_mod_cache() methods for details on use.
1085 1085
1086 1086 # This is the cache used for 'main' namespaces
1087 1087 self._main_mod_cache = {}
1088 1088
1089 1089 # A table holding all the namespaces IPython deals with, so that
1090 1090 # introspection facilities can search easily.
1091 1091 self.ns_table = {'user_global':self.user_module.__dict__,
1092 1092 'user_local':self.user_ns,
1093 1093 'builtin':builtin_mod.__dict__
1094 1094 }
1095 1095
1096 1096 @property
1097 1097 def user_global_ns(self):
1098 1098 return self.user_module.__dict__
1099 1099
1100 1100 def prepare_user_module(self, user_module=None, user_ns=None):
1101 1101 """Prepare the module and namespace in which user code will be run.
1102 1102
1103 1103 When IPython is started normally, both parameters are None: a new module
1104 1104 is created automatically, and its __dict__ used as the namespace.
1105 1105
1106 1106 If only user_module is provided, its __dict__ is used as the namespace.
1107 1107 If only user_ns is provided, a dummy module is created, and user_ns
1108 1108 becomes the global namespace. If both are provided (as they may be
1109 1109 when embedding), user_ns is the local namespace, and user_module
1110 1110 provides the global namespace.
1111 1111
1112 1112 Parameters
1113 1113 ----------
1114 1114 user_module : module, optional
1115 1115 The current user module in which IPython is being run. If None,
1116 1116 a clean module will be created.
1117 1117 user_ns : dict, optional
1118 1118 A namespace in which to run interactive commands.
1119 1119
1120 1120 Returns
1121 1121 -------
1122 1122 A tuple of user_module and user_ns, each properly initialised.
1123 1123 """
1124 1124 if user_module is None and user_ns is not None:
1125 1125 user_ns.setdefault("__name__", "__main__")
1126 1126 user_module = DummyMod()
1127 1127 user_module.__dict__ = user_ns
1128 1128
1129 1129 if user_module is None:
1130 1130 user_module = types.ModuleType("__main__",
1131 1131 doc="Automatically created module for IPython interactive environment")
1132 1132
1133 1133 # We must ensure that __builtin__ (without the final 's') is always
1134 1134 # available and pointing to the __builtin__ *module*. For more details:
1135 1135 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1136 1136 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1137 1137 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1138 1138
1139 1139 if user_ns is None:
1140 1140 user_ns = user_module.__dict__
1141 1141
1142 1142 return user_module, user_ns
1143 1143
1144 1144 def init_sys_modules(self):
1145 1145 # We need to insert into sys.modules something that looks like a
1146 1146 # module but which accesses the IPython namespace, for shelve and
1147 1147 # pickle to work interactively. Normally they rely on getting
1148 1148 # everything out of __main__, but for embedding purposes each IPython
1149 1149 # instance has its own private namespace, so we can't go shoving
1150 1150 # everything into __main__.
1151 1151
1152 1152 # note, however, that we should only do this for non-embedded
1153 1153 # ipythons, which really mimic the __main__.__dict__ with their own
1154 1154 # namespace. Embedded instances, on the other hand, should not do
1155 1155 # this because they need to manage the user local/global namespaces
1156 1156 # only, but they live within a 'normal' __main__ (meaning, they
1157 1157 # shouldn't overtake the execution environment of the script they're
1158 1158 # embedded in).
1159 1159
1160 1160 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
1161 1161 main_name = self.user_module.__name__
1162 1162 sys.modules[main_name] = self.user_module
1163 1163
1164 1164 def init_user_ns(self):
1165 1165 """Initialize all user-visible namespaces to their minimum defaults.
1166 1166
1167 1167 Certain history lists are also initialized here, as they effectively
1168 1168 act as user namespaces.
1169 1169
1170 1170 Notes
1171 1171 -----
1172 1172 All data structures here are only filled in, they are NOT reset by this
1173 1173 method. If they were not empty before, data will simply be added to
1174 1174 therm.
1175 1175 """
1176 1176 # This function works in two parts: first we put a few things in
1177 1177 # user_ns, and we sync that contents into user_ns_hidden so that these
1178 1178 # initial variables aren't shown by %who. After the sync, we add the
1179 1179 # rest of what we *do* want the user to see with %who even on a new
1180 1180 # session (probably nothing, so theye really only see their own stuff)
1181 1181
1182 1182 # The user dict must *always* have a __builtin__ reference to the
1183 1183 # Python standard __builtin__ namespace, which must be imported.
1184 1184 # This is so that certain operations in prompt evaluation can be
1185 1185 # reliably executed with builtins. Note that we can NOT use
1186 1186 # __builtins__ (note the 's'), because that can either be a dict or a
1187 1187 # module, and can even mutate at runtime, depending on the context
1188 1188 # (Python makes no guarantees on it). In contrast, __builtin__ is
1189 1189 # always a module object, though it must be explicitly imported.
1190 1190
1191 1191 # For more details:
1192 1192 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1193 1193 ns = dict()
1194 1194
1195 1195 # make global variables for user access to the histories
1196 1196 ns['_ih'] = self.history_manager.input_hist_parsed
1197 1197 ns['_oh'] = self.history_manager.output_hist
1198 1198 ns['_dh'] = self.history_manager.dir_hist
1199 1199
1200 1200 ns['_sh'] = shadowns
1201 1201
1202 1202 # user aliases to input and output histories. These shouldn't show up
1203 1203 # in %who, as they can have very large reprs.
1204 1204 ns['In'] = self.history_manager.input_hist_parsed
1205 1205 ns['Out'] = self.history_manager.output_hist
1206 1206
1207 1207 # Store myself as the public api!!!
1208 1208 ns['get_ipython'] = self.get_ipython
1209 1209
1210 1210 ns['exit'] = self.exiter
1211 1211 ns['quit'] = self.exiter
1212 1212
1213 1213 # Sync what we've added so far to user_ns_hidden so these aren't seen
1214 1214 # by %who
1215 1215 self.user_ns_hidden.update(ns)
1216 1216
1217 1217 # Anything put into ns now would show up in %who. Think twice before
1218 1218 # putting anything here, as we really want %who to show the user their
1219 1219 # stuff, not our variables.
1220 1220
1221 1221 # Finally, update the real user's namespace
1222 1222 self.user_ns.update(ns)
1223 1223
1224 1224 @property
1225 1225 def all_ns_refs(self):
1226 1226 """Get a list of references to all the namespace dictionaries in which
1227 1227 IPython might store a user-created object.
1228 1228
1229 1229 Note that this does not include the displayhook, which also caches
1230 1230 objects from the output."""
1231 1231 return [self.user_ns, self.user_global_ns, self.user_ns_hidden] + \
1232 1232 [m.__dict__ for m in self._main_mod_cache.values()]
1233 1233
1234 1234 def reset(self, new_session=True):
1235 1235 """Clear all internal namespaces, and attempt to release references to
1236 1236 user objects.
1237 1237
1238 1238 If new_session is True, a new history session will be opened.
1239 1239 """
1240 1240 # Clear histories
1241 1241 self.history_manager.reset(new_session)
1242 1242 # Reset counter used to index all histories
1243 1243 if new_session:
1244 1244 self.execution_count = 1
1245 1245
1246 1246 # Flush cached output items
1247 1247 if self.displayhook.do_full_cache:
1248 1248 self.displayhook.flush()
1249 1249
1250 1250 # The main execution namespaces must be cleared very carefully,
1251 1251 # skipping the deletion of the builtin-related keys, because doing so
1252 1252 # would cause errors in many object's __del__ methods.
1253 1253 if self.user_ns is not self.user_global_ns:
1254 1254 self.user_ns.clear()
1255 1255 ns = self.user_global_ns
1256 1256 drop_keys = set(ns.keys())
1257 1257 drop_keys.discard('__builtin__')
1258 1258 drop_keys.discard('__builtins__')
1259 1259 drop_keys.discard('__name__')
1260 1260 for k in drop_keys:
1261 1261 del ns[k]
1262 1262
1263 1263 self.user_ns_hidden.clear()
1264 1264
1265 1265 # Restore the user namespaces to minimal usability
1266 1266 self.init_user_ns()
1267 1267
1268 1268 # Restore the default and user aliases
1269 1269 self.alias_manager.clear_aliases()
1270 1270 self.alias_manager.init_aliases()
1271 1271
1272 1272 # Flush the private list of module references kept for script
1273 1273 # execution protection
1274 1274 self.clear_main_mod_cache()
1275 1275
1276 1276 def del_var(self, varname, by_name=False):
1277 1277 """Delete a variable from the various namespaces, so that, as
1278 1278 far as possible, we're not keeping any hidden references to it.
1279 1279
1280 1280 Parameters
1281 1281 ----------
1282 1282 varname : str
1283 1283 The name of the variable to delete.
1284 1284 by_name : bool
1285 1285 If True, delete variables with the given name in each
1286 1286 namespace. If False (default), find the variable in the user
1287 1287 namespace, and delete references to it.
1288 1288 """
1289 1289 if varname in ('__builtin__', '__builtins__'):
1290 1290 raise ValueError("Refusing to delete %s" % varname)
1291 1291
1292 1292 ns_refs = self.all_ns_refs
1293 1293
1294 1294 if by_name: # Delete by name
1295 1295 for ns in ns_refs:
1296 1296 try:
1297 1297 del ns[varname]
1298 1298 except KeyError:
1299 1299 pass
1300 1300 else: # Delete by object
1301 1301 try:
1302 1302 obj = self.user_ns[varname]
1303 1303 except KeyError:
1304 1304 raise NameError("name '%s' is not defined" % varname)
1305 1305 # Also check in output history
1306 1306 ns_refs.append(self.history_manager.output_hist)
1307 1307 for ns in ns_refs:
1308 1308 to_delete = [n for n, o in iteritems(ns) if o is obj]
1309 1309 for name in to_delete:
1310 1310 del ns[name]
1311 1311
1312 1312 # displayhook keeps extra references, but not in a dictionary
1313 1313 for name in ('_', '__', '___'):
1314 1314 if getattr(self.displayhook, name) is obj:
1315 1315 setattr(self.displayhook, name, None)
1316 1316
1317 1317 def reset_selective(self, regex=None):
1318 1318 """Clear selective variables from internal namespaces based on a
1319 1319 specified regular expression.
1320 1320
1321 1321 Parameters
1322 1322 ----------
1323 1323 regex : string or compiled pattern, optional
1324 1324 A regular expression pattern that will be used in searching
1325 1325 variable names in the users namespaces.
1326 1326 """
1327 1327 if regex is not None:
1328 1328 try:
1329 1329 m = re.compile(regex)
1330 1330 except TypeError:
1331 1331 raise TypeError('regex must be a string or compiled pattern')
1332 1332 # Search for keys in each namespace that match the given regex
1333 1333 # If a match is found, delete the key/value pair.
1334 1334 for ns in self.all_ns_refs:
1335 1335 for var in ns:
1336 1336 if m.search(var):
1337 1337 del ns[var]
1338 1338
1339 1339 def push(self, variables, interactive=True):
1340 1340 """Inject a group of variables into the IPython user namespace.
1341 1341
1342 1342 Parameters
1343 1343 ----------
1344 1344 variables : dict, str or list/tuple of str
1345 1345 The variables to inject into the user's namespace. If a dict, a
1346 1346 simple update is done. If a str, the string is assumed to have
1347 1347 variable names separated by spaces. A list/tuple of str can also
1348 1348 be used to give the variable names. If just the variable names are
1349 1349 give (list/tuple/str) then the variable values looked up in the
1350 1350 callers frame.
1351 1351 interactive : bool
1352 1352 If True (default), the variables will be listed with the ``who``
1353 1353 magic.
1354 1354 """
1355 1355 vdict = None
1356 1356
1357 1357 # We need a dict of name/value pairs to do namespace updates.
1358 1358 if isinstance(variables, dict):
1359 1359 vdict = variables
1360 1360 elif isinstance(variables, string_types+(list, tuple)):
1361 1361 if isinstance(variables, string_types):
1362 1362 vlist = variables.split()
1363 1363 else:
1364 1364 vlist = variables
1365 1365 vdict = {}
1366 1366 cf = sys._getframe(1)
1367 1367 for name in vlist:
1368 1368 try:
1369 1369 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1370 1370 except:
1371 1371 print('Could not get variable %s from %s' %
1372 1372 (name,cf.f_code.co_name))
1373 1373 else:
1374 1374 raise ValueError('variables must be a dict/str/list/tuple')
1375 1375
1376 1376 # Propagate variables to user namespace
1377 1377 self.user_ns.update(vdict)
1378 1378
1379 1379 # And configure interactive visibility
1380 1380 user_ns_hidden = self.user_ns_hidden
1381 1381 if interactive:
1382 1382 for name in vdict:
1383 1383 user_ns_hidden.pop(name, None)
1384 1384 else:
1385 1385 user_ns_hidden.update(vdict)
1386 1386
1387 1387 def drop_by_id(self, variables):
1388 1388 """Remove a dict of variables from the user namespace, if they are the
1389 1389 same as the values in the dictionary.
1390 1390
1391 1391 This is intended for use by extensions: variables that they've added can
1392 1392 be taken back out if they are unloaded, without removing any that the
1393 1393 user has overwritten.
1394 1394
1395 1395 Parameters
1396 1396 ----------
1397 1397 variables : dict
1398 1398 A dictionary mapping object names (as strings) to the objects.
1399 1399 """
1400 1400 for name, obj in iteritems(variables):
1401 1401 if name in self.user_ns and self.user_ns[name] is obj:
1402 1402 del self.user_ns[name]
1403 1403 self.user_ns_hidden.pop(name, None)
1404 1404
1405 1405 #-------------------------------------------------------------------------
1406 1406 # Things related to object introspection
1407 1407 #-------------------------------------------------------------------------
1408 1408
1409 1409 def _ofind(self, oname, namespaces=None):
1410 1410 """Find an object in the available namespaces.
1411 1411
1412 1412 self._ofind(oname) -> dict with keys: found,obj,ospace,ismagic
1413 1413
1414 1414 Has special code to detect magic functions.
1415 1415 """
1416 1416 oname = oname.strip()
1417 1417 #print '1- oname: <%r>' % oname # dbg
1418 1418 if not oname.startswith(ESC_MAGIC) and \
1419 1419 not oname.startswith(ESC_MAGIC2) and \
1420 1420 not py3compat.isidentifier(oname, dotted=True):
1421 1421 return dict(found=False)
1422 1422
1423 1423 alias_ns = None
1424 1424 if namespaces is None:
1425 1425 # Namespaces to search in:
1426 1426 # Put them in a list. The order is important so that we
1427 1427 # find things in the same order that Python finds them.
1428 1428 namespaces = [ ('Interactive', self.user_ns),
1429 1429 ('Interactive (global)', self.user_global_ns),
1430 1430 ('Python builtin', builtin_mod.__dict__),
1431 1431 ]
1432 1432
1433 1433 # initialize results to 'null'
1434 1434 found = False; obj = None; ospace = None; ds = None;
1435 1435 ismagic = False; isalias = False; parent = None
1436 1436
1437 1437 # We need to special-case 'print', which as of python2.6 registers as a
1438 1438 # function but should only be treated as one if print_function was
1439 1439 # loaded with a future import. In this case, just bail.
1440 1440 if (oname == 'print' and not py3compat.PY3 and not \
1441 1441 (self.compile.compiler_flags & __future__.CO_FUTURE_PRINT_FUNCTION)):
1442 1442 return {'found':found, 'obj':obj, 'namespace':ospace,
1443 1443 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1444 1444
1445 1445 # Look for the given name by splitting it in parts. If the head is
1446 1446 # found, then we look for all the remaining parts as members, and only
1447 1447 # declare success if we can find them all.
1448 1448 oname_parts = oname.split('.')
1449 1449 oname_head, oname_rest = oname_parts[0],oname_parts[1:]
1450 1450 for nsname,ns in namespaces:
1451 1451 try:
1452 1452 obj = ns[oname_head]
1453 1453 except KeyError:
1454 1454 continue
1455 1455 else:
1456 1456 #print 'oname_rest:', oname_rest # dbg
1457 1457 for idx, part in enumerate(oname_rest):
1458 1458 try:
1459 1459 parent = obj
1460 1460 # The last part is looked up in a special way to avoid
1461 1461 # descriptor invocation as it may raise or have side
1462 1462 # effects.
1463 1463 if idx == len(oname_rest) - 1:
1464 1464 obj = self._getattr_property(obj, part)
1465 1465 else:
1466 1466 obj = getattr(obj, part)
1467 1467 except:
1468 1468 # Blanket except b/c some badly implemented objects
1469 1469 # allow __getattr__ to raise exceptions other than
1470 1470 # AttributeError, which then crashes IPython.
1471 1471 break
1472 1472 else:
1473 1473 # If we finish the for loop (no break), we got all members
1474 1474 found = True
1475 1475 ospace = nsname
1476 1476 break # namespace loop
1477 1477
1478 1478 # Try to see if it's magic
1479 1479 if not found:
1480 1480 obj = None
1481 1481 if oname.startswith(ESC_MAGIC2):
1482 1482 oname = oname.lstrip(ESC_MAGIC2)
1483 1483 obj = self.find_cell_magic(oname)
1484 1484 elif oname.startswith(ESC_MAGIC):
1485 1485 oname = oname.lstrip(ESC_MAGIC)
1486 1486 obj = self.find_line_magic(oname)
1487 1487 else:
1488 1488 # search without prefix, so run? will find %run?
1489 1489 obj = self.find_line_magic(oname)
1490 1490 if obj is None:
1491 1491 obj = self.find_cell_magic(oname)
1492 1492 if obj is not None:
1493 1493 found = True
1494 1494 ospace = 'IPython internal'
1495 1495 ismagic = True
1496 1496
1497 1497 # Last try: special-case some literals like '', [], {}, etc:
1498 1498 if not found and oname_head in ["''",'""','[]','{}','()']:
1499 1499 obj = eval(oname_head)
1500 1500 found = True
1501 1501 ospace = 'Interactive'
1502 1502
1503 1503 return {'found':found, 'obj':obj, 'namespace':ospace,
1504 1504 'ismagic':ismagic, 'isalias':isalias, 'parent':parent}
1505 1505
1506 1506 @staticmethod
1507 1507 def _getattr_property(obj, attrname):
1508 1508 """Property-aware getattr to use in object finding.
1509 1509
1510 1510 If attrname represents a property, return it unevaluated (in case it has
1511 1511 side effects or raises an error.
1512 1512
1513 1513 """
1514 1514 if not isinstance(obj, type):
1515 1515 try:
1516 1516 # `getattr(type(obj), attrname)` is not guaranteed to return
1517 1517 # `obj`, but does so for property:
1518 1518 #
1519 1519 # property.__get__(self, None, cls) -> self
1520 1520 #
1521 1521 # The universal alternative is to traverse the mro manually
1522 1522 # searching for attrname in class dicts.
1523 1523 attr = getattr(type(obj), attrname)
1524 1524 except AttributeError:
1525 1525 pass
1526 1526 else:
1527 1527 # This relies on the fact that data descriptors (with both
1528 1528 # __get__ & __set__ magic methods) take precedence over
1529 1529 # instance-level attributes:
1530 1530 #
1531 1531 # class A(object):
1532 1532 # @property
1533 1533 # def foobar(self): return 123
1534 1534 # a = A()
1535 1535 # a.__dict__['foobar'] = 345
1536 1536 # a.foobar # == 123
1537 1537 #
1538 1538 # So, a property may be returned right away.
1539 1539 if isinstance(attr, property):
1540 1540 return attr
1541 1541
1542 1542 # Nothing helped, fall back.
1543 1543 return getattr(obj, attrname)
1544 1544
1545 1545 def _object_find(self, oname, namespaces=None):
1546 1546 """Find an object and return a struct with info about it."""
1547 1547 return Struct(self._ofind(oname, namespaces))
1548 1548
1549 1549 def _inspect(self, meth, oname, namespaces=None, **kw):
1550 1550 """Generic interface to the inspector system.
1551 1551
1552 1552 This function is meant to be called by pdef, pdoc & friends."""
1553 1553 info = self._object_find(oname, namespaces)
1554 1554 if info.found:
1555 1555 pmethod = getattr(self.inspector, meth)
1556 1556 formatter = format_screen if info.ismagic else None
1557 1557 if meth == 'pdoc':
1558 1558 pmethod(info.obj, oname, formatter)
1559 1559 elif meth == 'pinfo':
1560 1560 pmethod(info.obj, oname, formatter, info, **kw)
1561 1561 else:
1562 1562 pmethod(info.obj, oname)
1563 1563 else:
1564 1564 print('Object `%s` not found.' % oname)
1565 1565 return 'not found' # so callers can take other action
1566 1566
1567 1567 def object_inspect(self, oname, detail_level=0):
1568 1568 """Get object info about oname"""
1569 1569 with self.builtin_trap:
1570 1570 info = self._object_find(oname)
1571 1571 if info.found:
1572 1572 return self.inspector.info(info.obj, oname, info=info,
1573 1573 detail_level=detail_level
1574 1574 )
1575 1575 else:
1576 1576 return oinspect.object_info(name=oname, found=False)
1577 1577
1578 1578 def object_inspect_text(self, oname, detail_level=0):
1579 1579 """Get object info as formatted text"""
1580 1580 with self.builtin_trap:
1581 1581 info = self._object_find(oname)
1582 1582 if info.found:
1583 1583 return self.inspector._format_info(info.obj, oname, info=info,
1584 1584 detail_level=detail_level
1585 1585 )
1586 1586 else:
1587 1587 raise KeyError(oname)
1588 1588
1589 1589 #-------------------------------------------------------------------------
1590 1590 # Things related to history management
1591 1591 #-------------------------------------------------------------------------
1592 1592
1593 1593 def init_history(self):
1594 1594 """Sets up the command history, and starts regular autosaves."""
1595 1595 self.history_manager = HistoryManager(shell=self, parent=self)
1596 1596 self.configurables.append(self.history_manager)
1597 1597
1598 1598 #-------------------------------------------------------------------------
1599 1599 # Things related to exception handling and tracebacks (not debugging)
1600 1600 #-------------------------------------------------------------------------
1601 1601
1602 1602 def init_traceback_handlers(self, custom_exceptions):
1603 1603 # Syntax error handler.
1604 1604 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1605 1605
1606 1606 # The interactive one is initialized with an offset, meaning we always
1607 1607 # want to remove the topmost item in the traceback, which is our own
1608 1608 # internal code. Valid modes: ['Plain','Context','Verbose']
1609 1609 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1610 1610 color_scheme='NoColor',
1611 1611 tb_offset = 1,
1612 1612 check_cache=check_linecache_ipython)
1613 1613
1614 1614 # The instance will store a pointer to the system-wide exception hook,
1615 1615 # so that runtime code (such as magics) can access it. This is because
1616 1616 # during the read-eval loop, it may get temporarily overwritten.
1617 1617 self.sys_excepthook = sys.excepthook
1618 1618
1619 1619 # and add any custom exception handlers the user may have specified
1620 1620 self.set_custom_exc(*custom_exceptions)
1621 1621
1622 1622 # Set the exception mode
1623 1623 self.InteractiveTB.set_mode(mode=self.xmode)
1624 1624
1625 1625 def set_custom_exc(self, exc_tuple, handler):
1626 1626 """set_custom_exc(exc_tuple,handler)
1627 1627
1628 1628 Set a custom exception handler, which will be called if any of the
1629 1629 exceptions in exc_tuple occur in the mainloop (specifically, in the
1630 1630 run_code() method).
1631 1631
1632 1632 Parameters
1633 1633 ----------
1634 1634
1635 1635 exc_tuple : tuple of exception classes
1636 1636 A *tuple* of exception classes, for which to call the defined
1637 1637 handler. It is very important that you use a tuple, and NOT A
1638 1638 LIST here, because of the way Python's except statement works. If
1639 1639 you only want to trap a single exception, use a singleton tuple::
1640 1640
1641 1641 exc_tuple == (MyCustomException,)
1642 1642
1643 1643 handler : callable
1644 1644 handler must have the following signature::
1645 1645
1646 1646 def my_handler(self, etype, value, tb, tb_offset=None):
1647 1647 ...
1648 1648 return structured_traceback
1649 1649
1650 1650 Your handler must return a structured traceback (a list of strings),
1651 1651 or None.
1652 1652
1653 1653 This will be made into an instance method (via types.MethodType)
1654 1654 of IPython itself, and it will be called if any of the exceptions
1655 1655 listed in the exc_tuple are caught. If the handler is None, an
1656 1656 internal basic one is used, which just prints basic info.
1657 1657
1658 1658 To protect IPython from crashes, if your handler ever raises an
1659 1659 exception or returns an invalid result, it will be immediately
1660 1660 disabled.
1661 1661
1662 1662 WARNING: by putting in your own exception handler into IPython's main
1663 1663 execution loop, you run a very good chance of nasty crashes. This
1664 1664 facility should only be used if you really know what you are doing."""
1665 1665
1666 1666 assert type(exc_tuple)==type(()) , \
1667 1667 "The custom exceptions must be given AS A TUPLE."
1668 1668
1669 1669 def dummy_handler(self,etype,value,tb,tb_offset=None):
1670 1670 print('*** Simple custom exception handler ***')
1671 1671 print('Exception type :',etype)
1672 1672 print('Exception value:',value)
1673 1673 print('Traceback :',tb)
1674 1674 #print 'Source code :','\n'.join(self.buffer)
1675 1675
1676 1676 def validate_stb(stb):
1677 1677 """validate structured traceback return type
1678 1678
1679 1679 return type of CustomTB *should* be a list of strings, but allow
1680 1680 single strings or None, which are harmless.
1681 1681
1682 1682 This function will *always* return a list of strings,
1683 1683 and will raise a TypeError if stb is inappropriate.
1684 1684 """
1685 1685 msg = "CustomTB must return list of strings, not %r" % stb
1686 1686 if stb is None:
1687 1687 return []
1688 1688 elif isinstance(stb, string_types):
1689 1689 return [stb]
1690 1690 elif not isinstance(stb, list):
1691 1691 raise TypeError(msg)
1692 1692 # it's a list
1693 1693 for line in stb:
1694 1694 # check every element
1695 1695 if not isinstance(line, string_types):
1696 1696 raise TypeError(msg)
1697 1697 return stb
1698 1698
1699 1699 if handler is None:
1700 1700 wrapped = dummy_handler
1701 1701 else:
1702 1702 def wrapped(self,etype,value,tb,tb_offset=None):
1703 1703 """wrap CustomTB handler, to protect IPython from user code
1704 1704
1705 1705 This makes it harder (but not impossible) for custom exception
1706 1706 handlers to crash IPython.
1707 1707 """
1708 1708 try:
1709 1709 stb = handler(self,etype,value,tb,tb_offset=tb_offset)
1710 1710 return validate_stb(stb)
1711 1711 except:
1712 1712 # clear custom handler immediately
1713 1713 self.set_custom_exc((), None)
1714 1714 print("Custom TB Handler failed, unregistering", file=io.stderr)
1715 1715 # show the exception in handler first
1716 1716 stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
1717 1717 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1718 1718 print("The original exception:", file=io.stdout)
1719 1719 stb = self.InteractiveTB.structured_traceback(
1720 1720 (etype,value,tb), tb_offset=tb_offset
1721 1721 )
1722 1722 return stb
1723 1723
1724 1724 self.CustomTB = types.MethodType(wrapped,self)
1725 1725 self.custom_exceptions = exc_tuple
1726 1726
1727 1727 def excepthook(self, etype, value, tb):
1728 1728 """One more defense for GUI apps that call sys.excepthook.
1729 1729
1730 1730 GUI frameworks like wxPython trap exceptions and call
1731 1731 sys.excepthook themselves. I guess this is a feature that
1732 1732 enables them to keep running after exceptions that would
1733 1733 otherwise kill their mainloop. This is a bother for IPython
1734 1734 which excepts to catch all of the program exceptions with a try:
1735 1735 except: statement.
1736 1736
1737 1737 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1738 1738 any app directly invokes sys.excepthook, it will look to the user like
1739 1739 IPython crashed. In order to work around this, we can disable the
1740 1740 CrashHandler and replace it with this excepthook instead, which prints a
1741 1741 regular traceback using our InteractiveTB. In this fashion, apps which
1742 1742 call sys.excepthook will generate a regular-looking exception from
1743 1743 IPython, and the CrashHandler will only be triggered by real IPython
1744 1744 crashes.
1745 1745
1746 1746 This hook should be used sparingly, only in places which are not likely
1747 1747 to be true IPython errors.
1748 1748 """
1749 1749 self.showtraceback((etype, value, tb), tb_offset=0)
1750 1750
1751 1751 def _get_exc_info(self, exc_tuple=None):
1752 1752 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1753 1753
1754 1754 Ensures sys.last_type,value,traceback hold the exc_info we found,
1755 1755 from whichever source.
1756 1756
1757 1757 raises ValueError if none of these contain any information
1758 1758 """
1759 1759 if exc_tuple is None:
1760 1760 etype, value, tb = sys.exc_info()
1761 1761 else:
1762 1762 etype, value, tb = exc_tuple
1763 1763
1764 1764 if etype is None:
1765 1765 if hasattr(sys, 'last_type'):
1766 1766 etype, value, tb = sys.last_type, sys.last_value, \
1767 1767 sys.last_traceback
1768 1768
1769 1769 if etype is None:
1770 1770 raise ValueError("No exception to find")
1771 1771
1772 1772 # Now store the exception info in sys.last_type etc.
1773 1773 # WARNING: these variables are somewhat deprecated and not
1774 1774 # necessarily safe to use in a threaded environment, but tools
1775 1775 # like pdb depend on their existence, so let's set them. If we
1776 1776 # find problems in the field, we'll need to revisit their use.
1777 1777 sys.last_type = etype
1778 1778 sys.last_value = value
1779 1779 sys.last_traceback = tb
1780 1780
1781 1781 return etype, value, tb
1782 1782
1783 1783 def show_usage_error(self, exc):
1784 1784 """Show a short message for UsageErrors
1785 1785
1786 1786 These are special exceptions that shouldn't show a traceback.
1787 1787 """
1788 1788 self.write_err("UsageError: %s" % exc)
1789 1789
1790 1790 def get_exception_only(self, exc_tuple=None):
1791 1791 """
1792 1792 Return as a string (ending with a newline) the exception that
1793 1793 just occurred, without any traceback.
1794 1794 """
1795 1795 etype, value, tb = self._get_exc_info(exc_tuple)
1796 1796 msg = traceback.format_exception_only(etype, value)
1797 1797 return ''.join(msg)
1798 1798
1799 1799 def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None,
1800 1800 exception_only=False):
1801 1801 """Display the exception that just occurred.
1802 1802
1803 1803 If nothing is known about the exception, this is the method which
1804 1804 should be used throughout the code for presenting user tracebacks,
1805 1805 rather than directly invoking the InteractiveTB object.
1806 1806
1807 1807 A specific showsyntaxerror() also exists, but this method can take
1808 1808 care of calling it if needed, so unless you are explicitly catching a
1809 1809 SyntaxError exception, don't try to analyze the stack manually and
1810 1810 simply call this method."""
1811 1811
1812 1812 try:
1813 1813 try:
1814 1814 etype, value, tb = self._get_exc_info(exc_tuple)
1815 1815 except ValueError:
1816 1816 self.write_err('No traceback available to show.\n')
1817 1817 return
1818 1818
1819 1819 if issubclass(etype, SyntaxError):
1820 1820 # Though this won't be called by syntax errors in the input
1821 1821 # line, there may be SyntaxError cases with imported code.
1822 1822 self.showsyntaxerror(filename)
1823 1823 elif etype is UsageError:
1824 1824 self.show_usage_error(value)
1825 1825 else:
1826 1826 if exception_only:
1827 1827 stb = ['An exception has occurred, use %tb to see '
1828 1828 'the full traceback.\n']
1829 1829 stb.extend(self.InteractiveTB.get_exception_only(etype,
1830 1830 value))
1831 1831 else:
1832 1832 try:
1833 1833 # Exception classes can customise their traceback - we
1834 1834 # use this in IPython.parallel for exceptions occurring
1835 1835 # in the engines. This should return a list of strings.
1836 1836 stb = value._render_traceback_()
1837 1837 except Exception:
1838 1838 stb = self.InteractiveTB.structured_traceback(etype,
1839 1839 value, tb, tb_offset=tb_offset)
1840 1840
1841 1841 self._showtraceback(etype, value, stb)
1842 1842 if self.call_pdb:
1843 1843 # drop into debugger
1844 1844 self.debugger(force=True)
1845 1845 return
1846 1846
1847 1847 # Actually show the traceback
1848 1848 self._showtraceback(etype, value, stb)
1849 1849
1850 1850 except KeyboardInterrupt:
1851 1851 self.write_err('\n' + self.get_exception_only())
1852 1852
1853 1853 def _showtraceback(self, etype, evalue, stb):
1854 1854 """Actually show a traceback.
1855 1855
1856 1856 Subclasses may override this method to put the traceback on a different
1857 1857 place, like a side channel.
1858 1858 """
1859 1859 print(self.InteractiveTB.stb2text(stb), file=io.stdout)
1860 1860
1861 1861 def showsyntaxerror(self, filename=None):
1862 1862 """Display the syntax error that just occurred.
1863 1863
1864 1864 This doesn't display a stack trace because there isn't one.
1865 1865
1866 1866 If a filename is given, it is stuffed in the exception instead
1867 1867 of what was there before (because Python's parser always uses
1868 1868 "<string>" when reading from a string).
1869 1869 """
1870 1870 etype, value, last_traceback = self._get_exc_info()
1871 1871
1872 1872 if filename and issubclass(etype, SyntaxError):
1873 1873 try:
1874 1874 value.filename = filename
1875 1875 except:
1876 1876 # Not the format we expect; leave it alone
1877 1877 pass
1878 1878
1879 1879 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1880 1880 self._showtraceback(etype, value, stb)
1881 1881
1882 1882 # This is overridden in TerminalInteractiveShell to show a message about
1883 1883 # the %paste magic.
1884 1884 def showindentationerror(self):
1885 1885 """Called by run_cell when there's an IndentationError in code entered
1886 1886 at the prompt.
1887 1887
1888 1888 This is overridden in TerminalInteractiveShell to show a message about
1889 1889 the %paste magic."""
1890 1890 self.showsyntaxerror()
1891 1891
1892 1892 #-------------------------------------------------------------------------
1893 1893 # Things related to readline
1894 1894 #-------------------------------------------------------------------------
1895 1895
1896 1896 def init_readline(self):
1897 1897 """Command history completion/saving/reloading."""
1898 1898
1899 1899 if self.readline_use:
1900 1900 import IPython.utils.rlineimpl as readline
1901 1901
1902 1902 self.rl_next_input = None
1903 1903 self.rl_do_indent = False
1904 1904
1905 1905 if not self.readline_use or not readline.have_readline:
1906 1906 self.has_readline = False
1907 1907 self.readline = None
1908 1908 # Set a number of methods that depend on readline to be no-op
1909 1909 self.readline_no_record = no_op_context
1910 1910 self.set_readline_completer = no_op
1911 1911 self.set_custom_completer = no_op
1912 1912 if self.readline_use:
1913 1913 warn('Readline services not available or not loaded.')
1914 1914 else:
1915 1915 self.has_readline = True
1916 1916 self.readline = readline
1917 1917 sys.modules['readline'] = readline
1918 1918
1919 1919 # Platform-specific configuration
1920 1920 if os.name == 'nt':
1921 1921 # FIXME - check with Frederick to see if we can harmonize
1922 1922 # naming conventions with pyreadline to avoid this
1923 1923 # platform-dependent check
1924 1924 self.readline_startup_hook = readline.set_pre_input_hook
1925 1925 else:
1926 1926 self.readline_startup_hook = readline.set_startup_hook
1927 1927
1928 1928 # Readline config order:
1929 1929 # - IPython config (default value)
1930 1930 # - custom inputrc
1931 1931 # - IPython config (user customized)
1932 1932
1933 1933 # load IPython config before inputrc if default
1934 1934 # skip if libedit because parse_and_bind syntax is different
1935 1935 if not self._custom_readline_config and not readline.uses_libedit:
1936 1936 for rlcommand in self.readline_parse_and_bind:
1937 1937 readline.parse_and_bind(rlcommand)
1938 1938
1939 1939 # Load user's initrc file (readline config)
1940 1940 # Or if libedit is used, load editrc.
1941 1941 inputrc_name = os.environ.get('INPUTRC')
1942 1942 if inputrc_name is None:
1943 1943 inputrc_name = '.inputrc'
1944 1944 if readline.uses_libedit:
1945 1945 inputrc_name = '.editrc'
1946 1946 inputrc_name = os.path.join(self.home_dir, inputrc_name)
1947 1947 if os.path.isfile(inputrc_name):
1948 1948 try:
1949 1949 readline.read_init_file(inputrc_name)
1950 1950 except:
1951 1951 warn('Problems reading readline initialization file <%s>'
1952 1952 % inputrc_name)
1953 1953
1954 1954 # load IPython config after inputrc if user has customized
1955 1955 if self._custom_readline_config:
1956 1956 for rlcommand in self.readline_parse_and_bind:
1957 1957 readline.parse_and_bind(rlcommand)
1958 1958
1959 1959 # Remove some chars from the delimiters list. If we encounter
1960 1960 # unicode chars, discard them.
1961 1961 delims = readline.get_completer_delims()
1962 1962 if not py3compat.PY3:
1963 1963 delims = delims.encode("ascii", "ignore")
1964 1964 for d in self.readline_remove_delims:
1965 1965 delims = delims.replace(d, "")
1966 1966 delims = delims.replace(ESC_MAGIC, '')
1967 1967 readline.set_completer_delims(delims)
1968 1968 # Store these so we can restore them if something like rpy2 modifies
1969 1969 # them.
1970 1970 self.readline_delims = delims
1971 1971 # otherwise we end up with a monster history after a while:
1972 1972 readline.set_history_length(self.history_length)
1973 1973
1974 1974 self.refill_readline_hist()
1975 1975 self.readline_no_record = ReadlineNoRecord(self)
1976 1976
1977 1977 # Configure auto-indent for all platforms
1978 1978 self.set_autoindent(self.autoindent)
1979 1979
1980 1980 def refill_readline_hist(self):
1981 1981 # Load the last 1000 lines from history
1982 1982 self.readline.clear_history()
1983 1983 stdin_encoding = sys.stdin.encoding or "utf-8"
1984 1984 last_cell = u""
1985 1985 for _, _, cell in self.history_manager.get_tail(1000,
1986 1986 include_latest=True):
1987 1987 # Ignore blank lines and consecutive duplicates
1988 1988 cell = cell.rstrip()
1989 1989 if cell and (cell != last_cell):
1990 1990 try:
1991 1991 if self.multiline_history:
1992 1992 self.readline.add_history(py3compat.unicode_to_str(cell,
1993 1993 stdin_encoding))
1994 1994 else:
1995 1995 for line in cell.splitlines():
1996 1996 self.readline.add_history(py3compat.unicode_to_str(line,
1997 1997 stdin_encoding))
1998 1998 last_cell = cell
1999 1999
2000 2000 except TypeError:
2001 2001 # The history DB can get corrupted so it returns strings
2002 2002 # containing null bytes, which readline objects to.
2003 2003 continue
2004 2004
2005 2005 @skip_doctest
2006 def set_next_input(self, s):
2006 def set_next_input(self, s, replace=False):
2007 2007 """ Sets the 'default' input string for the next command line.
2008 2008
2009 2009 Requires readline.
2010 2010
2011 2011 Example::
2012 2012
2013 2013 In [1]: _ip.set_next_input("Hello Word")
2014 2014 In [2]: Hello Word_ # cursor is here
2015 2015 """
2016 2016 self.rl_next_input = py3compat.cast_bytes_py2(s)
2017 2017
2018 2018 # Maybe move this to the terminal subclass?
2019 2019 def pre_readline(self):
2020 2020 """readline hook to be used at the start of each line.
2021 2021
2022 2022 Currently it handles auto-indent only."""
2023 2023
2024 2024 if self.rl_do_indent:
2025 2025 self.readline.insert_text(self._indent_current_str())
2026 2026 if self.rl_next_input is not None:
2027 2027 self.readline.insert_text(self.rl_next_input)
2028 2028 self.rl_next_input = None
2029 2029
2030 2030 def _indent_current_str(self):
2031 2031 """return the current level of indentation as a string"""
2032 2032 return self.input_splitter.indent_spaces * ' '
2033 2033
2034 2034 #-------------------------------------------------------------------------
2035 2035 # Things related to text completion
2036 2036 #-------------------------------------------------------------------------
2037 2037
2038 2038 def init_completer(self):
2039 2039 """Initialize the completion machinery.
2040 2040
2041 2041 This creates completion machinery that can be used by client code,
2042 2042 either interactively in-process (typically triggered by the readline
2043 2043 library), programatically (such as in test suites) or out-of-prcess
2044 2044 (typically over the network by remote frontends).
2045 2045 """
2046 2046 from IPython.core.completer import IPCompleter
2047 2047 from IPython.core.completerlib import (module_completer,
2048 2048 magic_run_completer, cd_completer, reset_completer)
2049 2049
2050 2050 self.Completer = IPCompleter(shell=self,
2051 2051 namespace=self.user_ns,
2052 2052 global_namespace=self.user_global_ns,
2053 2053 use_readline=self.has_readline,
2054 2054 parent=self,
2055 2055 )
2056 2056 self.configurables.append(self.Completer)
2057 2057
2058 2058 # Add custom completers to the basic ones built into IPCompleter
2059 2059 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
2060 2060 self.strdispatchers['complete_command'] = sdisp
2061 2061 self.Completer.custom_completers = sdisp
2062 2062
2063 2063 self.set_hook('complete_command', module_completer, str_key = 'import')
2064 2064 self.set_hook('complete_command', module_completer, str_key = 'from')
2065 2065 self.set_hook('complete_command', magic_run_completer, str_key = '%run')
2066 2066 self.set_hook('complete_command', cd_completer, str_key = '%cd')
2067 2067 self.set_hook('complete_command', reset_completer, str_key = '%reset')
2068 2068
2069 2069 # Only configure readline if we truly are using readline. IPython can
2070 2070 # do tab-completion over the network, in GUIs, etc, where readline
2071 2071 # itself may be absent
2072 2072 if self.has_readline:
2073 2073 self.set_readline_completer()
2074 2074
2075 2075 def complete(self, text, line=None, cursor_pos=None):
2076 2076 """Return the completed text and a list of completions.
2077 2077
2078 2078 Parameters
2079 2079 ----------
2080 2080
2081 2081 text : string
2082 2082 A string of text to be completed on. It can be given as empty and
2083 2083 instead a line/position pair are given. In this case, the
2084 2084 completer itself will split the line like readline does.
2085 2085
2086 2086 line : string, optional
2087 2087 The complete line that text is part of.
2088 2088
2089 2089 cursor_pos : int, optional
2090 2090 The position of the cursor on the input line.
2091 2091
2092 2092 Returns
2093 2093 -------
2094 2094 text : string
2095 2095 The actual text that was completed.
2096 2096
2097 2097 matches : list
2098 2098 A sorted list with all possible completions.
2099 2099
2100 2100 The optional arguments allow the completion to take more context into
2101 2101 account, and are part of the low-level completion API.
2102 2102
2103 2103 This is a wrapper around the completion mechanism, similar to what
2104 2104 readline does at the command line when the TAB key is hit. By
2105 2105 exposing it as a method, it can be used by other non-readline
2106 2106 environments (such as GUIs) for text completion.
2107 2107
2108 2108 Simple usage example:
2109 2109
2110 2110 In [1]: x = 'hello'
2111 2111
2112 2112 In [2]: _ip.complete('x.l')
2113 2113 Out[2]: ('x.l', ['x.ljust', 'x.lower', 'x.lstrip'])
2114 2114 """
2115 2115
2116 2116 # Inject names into __builtin__ so we can complete on the added names.
2117 2117 with self.builtin_trap:
2118 2118 return self.Completer.complete(text, line, cursor_pos)
2119 2119
2120 2120 def set_custom_completer(self, completer, pos=0):
2121 2121 """Adds a new custom completer function.
2122 2122
2123 2123 The position argument (defaults to 0) is the index in the completers
2124 2124 list where you want the completer to be inserted."""
2125 2125
2126 2126 newcomp = types.MethodType(completer,self.Completer)
2127 2127 self.Completer.matchers.insert(pos,newcomp)
2128 2128
2129 2129 def set_readline_completer(self):
2130 2130 """Reset readline's completer to be our own."""
2131 2131 self.readline.set_completer(self.Completer.rlcomplete)
2132 2132
2133 2133 def set_completer_frame(self, frame=None):
2134 2134 """Set the frame of the completer."""
2135 2135 if frame:
2136 2136 self.Completer.namespace = frame.f_locals
2137 2137 self.Completer.global_namespace = frame.f_globals
2138 2138 else:
2139 2139 self.Completer.namespace = self.user_ns
2140 2140 self.Completer.global_namespace = self.user_global_ns
2141 2141
2142 2142 #-------------------------------------------------------------------------
2143 2143 # Things related to magics
2144 2144 #-------------------------------------------------------------------------
2145 2145
2146 2146 def init_magics(self):
2147 2147 from IPython.core import magics as m
2148 2148 self.magics_manager = magic.MagicsManager(shell=self,
2149 2149 parent=self,
2150 2150 user_magics=m.UserMagics(self))
2151 2151 self.configurables.append(self.magics_manager)
2152 2152
2153 2153 # Expose as public API from the magics manager
2154 2154 self.register_magics = self.magics_manager.register
2155 2155 self.define_magic = self.magics_manager.define_magic
2156 2156
2157 2157 self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics,
2158 2158 m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics,
2159 2159 m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics,
2160 2160 m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics,
2161 2161 )
2162 2162
2163 2163 # Register Magic Aliases
2164 2164 mman = self.magics_manager
2165 2165 # FIXME: magic aliases should be defined by the Magics classes
2166 2166 # or in MagicsManager, not here
2167 2167 mman.register_alias('ed', 'edit')
2168 2168 mman.register_alias('hist', 'history')
2169 2169 mman.register_alias('rep', 'recall')
2170 2170 mman.register_alias('SVG', 'svg', 'cell')
2171 2171 mman.register_alias('HTML', 'html', 'cell')
2172 2172 mman.register_alias('file', 'writefile', 'cell')
2173 2173
2174 2174 # FIXME: Move the color initialization to the DisplayHook, which
2175 2175 # should be split into a prompt manager and displayhook. We probably
2176 2176 # even need a centralize colors management object.
2177 2177 self.magic('colors %s' % self.colors)
2178 2178
2179 2179 # Defined here so that it's included in the documentation
2180 2180 @functools.wraps(magic.MagicsManager.register_function)
2181 2181 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2182 2182 self.magics_manager.register_function(func,
2183 2183 magic_kind=magic_kind, magic_name=magic_name)
2184 2184
2185 2185 def run_line_magic(self, magic_name, line):
2186 2186 """Execute the given line magic.
2187 2187
2188 2188 Parameters
2189 2189 ----------
2190 2190 magic_name : str
2191 2191 Name of the desired magic function, without '%' prefix.
2192 2192
2193 2193 line : str
2194 2194 The rest of the input line as a single string.
2195 2195 """
2196 2196 fn = self.find_line_magic(magic_name)
2197 2197 if fn is None:
2198 2198 cm = self.find_cell_magic(magic_name)
2199 2199 etpl = "Line magic function `%%%s` not found%s."
2200 2200 extra = '' if cm is None else (' (But cell magic `%%%%%s` exists, '
2201 2201 'did you mean that instead?)' % magic_name )
2202 2202 error(etpl % (magic_name, extra))
2203 2203 else:
2204 2204 # Note: this is the distance in the stack to the user's frame.
2205 2205 # This will need to be updated if the internal calling logic gets
2206 2206 # refactored, or else we'll be expanding the wrong variables.
2207 2207 stack_depth = 2
2208 2208 magic_arg_s = self.var_expand(line, stack_depth)
2209 2209 # Put magic args in a list so we can call with f(*a) syntax
2210 2210 args = [magic_arg_s]
2211 2211 kwargs = {}
2212 2212 # Grab local namespace if we need it:
2213 2213 if getattr(fn, "needs_local_scope", False):
2214 2214 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
2215 2215 with self.builtin_trap:
2216 2216 result = fn(*args,**kwargs)
2217 2217 return result
2218 2218
2219 2219 def run_cell_magic(self, magic_name, line, cell):
2220 2220 """Execute the given cell magic.
2221 2221
2222 2222 Parameters
2223 2223 ----------
2224 2224 magic_name : str
2225 2225 Name of the desired magic function, without '%' prefix.
2226 2226
2227 2227 line : str
2228 2228 The rest of the first input line as a single string.
2229 2229
2230 2230 cell : str
2231 2231 The body of the cell as a (possibly multiline) string.
2232 2232 """
2233 2233 fn = self.find_cell_magic(magic_name)
2234 2234 if fn is None:
2235 2235 lm = self.find_line_magic(magic_name)
2236 2236 etpl = "Cell magic `%%{0}` not found{1}."
2237 2237 extra = '' if lm is None else (' (But line magic `%{0}` exists, '
2238 2238 'did you mean that instead?)'.format(magic_name))
2239 2239 error(etpl.format(magic_name, extra))
2240 2240 elif cell == '':
2241 2241 message = '%%{0} is a cell magic, but the cell body is empty.'.format(magic_name)
2242 2242 if self.find_line_magic(magic_name) is not None:
2243 2243 message += ' Did you mean the line magic %{0} (single %)?'.format(magic_name)
2244 2244 raise UsageError(message)
2245 2245 else:
2246 2246 # Note: this is the distance in the stack to the user's frame.
2247 2247 # This will need to be updated if the internal calling logic gets
2248 2248 # refactored, or else we'll be expanding the wrong variables.
2249 2249 stack_depth = 2
2250 2250 magic_arg_s = self.var_expand(line, stack_depth)
2251 2251 with self.builtin_trap:
2252 2252 result = fn(magic_arg_s, cell)
2253 2253 return result
2254 2254
2255 2255 def find_line_magic(self, magic_name):
2256 2256 """Find and return a line magic by name.
2257 2257
2258 2258 Returns None if the magic isn't found."""
2259 2259 return self.magics_manager.magics['line'].get(magic_name)
2260 2260
2261 2261 def find_cell_magic(self, magic_name):
2262 2262 """Find and return a cell magic by name.
2263 2263
2264 2264 Returns None if the magic isn't found."""
2265 2265 return self.magics_manager.magics['cell'].get(magic_name)
2266 2266
2267 2267 def find_magic(self, magic_name, magic_kind='line'):
2268 2268 """Find and return a magic of the given type by name.
2269 2269
2270 2270 Returns None if the magic isn't found."""
2271 2271 return self.magics_manager.magics[magic_kind].get(magic_name)
2272 2272
2273 2273 def magic(self, arg_s):
2274 2274 """DEPRECATED. Use run_line_magic() instead.
2275 2275
2276 2276 Call a magic function by name.
2277 2277
2278 2278 Input: a string containing the name of the magic function to call and
2279 2279 any additional arguments to be passed to the magic.
2280 2280
2281 2281 magic('name -opt foo bar') is equivalent to typing at the ipython
2282 2282 prompt:
2283 2283
2284 2284 In[1]: %name -opt foo bar
2285 2285
2286 2286 To call a magic without arguments, simply use magic('name').
2287 2287
2288 2288 This provides a proper Python function to call IPython's magics in any
2289 2289 valid Python code you can type at the interpreter, including loops and
2290 2290 compound statements.
2291 2291 """
2292 2292 # TODO: should we issue a loud deprecation warning here?
2293 2293 magic_name, _, magic_arg_s = arg_s.partition(' ')
2294 2294 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
2295 2295 return self.run_line_magic(magic_name, magic_arg_s)
2296 2296
2297 2297 #-------------------------------------------------------------------------
2298 2298 # Things related to macros
2299 2299 #-------------------------------------------------------------------------
2300 2300
2301 2301 def define_macro(self, name, themacro):
2302 2302 """Define a new macro
2303 2303
2304 2304 Parameters
2305 2305 ----------
2306 2306 name : str
2307 2307 The name of the macro.
2308 2308 themacro : str or Macro
2309 2309 The action to do upon invoking the macro. If a string, a new
2310 2310 Macro object is created by passing the string to it.
2311 2311 """
2312 2312
2313 2313 from IPython.core import macro
2314 2314
2315 2315 if isinstance(themacro, string_types):
2316 2316 themacro = macro.Macro(themacro)
2317 2317 if not isinstance(themacro, macro.Macro):
2318 2318 raise ValueError('A macro must be a string or a Macro instance.')
2319 2319 self.user_ns[name] = themacro
2320 2320
2321 2321 #-------------------------------------------------------------------------
2322 2322 # Things related to the running of system commands
2323 2323 #-------------------------------------------------------------------------
2324 2324
2325 2325 def system_piped(self, cmd):
2326 2326 """Call the given cmd in a subprocess, piping stdout/err
2327 2327
2328 2328 Parameters
2329 2329 ----------
2330 2330 cmd : str
2331 2331 Command to execute (can not end in '&', as background processes are
2332 2332 not supported. Should not be a command that expects input
2333 2333 other than simple text.
2334 2334 """
2335 2335 if cmd.rstrip().endswith('&'):
2336 2336 # this is *far* from a rigorous test
2337 2337 # We do not support backgrounding processes because we either use
2338 2338 # pexpect or pipes to read from. Users can always just call
2339 2339 # os.system() or use ip.system=ip.system_raw
2340 2340 # if they really want a background process.
2341 2341 raise OSError("Background processes not supported.")
2342 2342
2343 2343 # we explicitly do NOT return the subprocess status code, because
2344 2344 # a non-None value would trigger :func:`sys.displayhook` calls.
2345 2345 # Instead, we store the exit_code in user_ns.
2346 2346 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=1))
2347 2347
2348 2348 def system_raw(self, cmd):
2349 2349 """Call the given cmd in a subprocess using os.system on Windows or
2350 2350 subprocess.call using the system shell on other platforms.
2351 2351
2352 2352 Parameters
2353 2353 ----------
2354 2354 cmd : str
2355 2355 Command to execute.
2356 2356 """
2357 2357 cmd = self.var_expand(cmd, depth=1)
2358 2358 # protect os.system from UNC paths on Windows, which it can't handle:
2359 2359 if sys.platform == 'win32':
2360 2360 from IPython.utils._process_win32 import AvoidUNCPath
2361 2361 with AvoidUNCPath() as path:
2362 2362 if path is not None:
2363 2363 cmd = '"pushd %s &&"%s' % (path, cmd)
2364 2364 cmd = py3compat.unicode_to_str(cmd)
2365 2365 try:
2366 2366 ec = os.system(cmd)
2367 2367 except KeyboardInterrupt:
2368 2368 self.write_err('\n' + self.get_exception_only())
2369 2369 ec = -2
2370 2370 else:
2371 2371 cmd = py3compat.unicode_to_str(cmd)
2372 2372 # For posix the result of the subprocess.call() below is an exit
2373 2373 # code, which by convention is zero for success, positive for
2374 2374 # program failure. Exit codes above 128 are reserved for signals,
2375 2375 # and the formula for converting a signal to an exit code is usually
2376 2376 # signal_number+128. To more easily differentiate between exit
2377 2377 # codes and signals, ipython uses negative numbers. For instance
2378 2378 # since control-c is signal 2 but exit code 130, ipython's
2379 2379 # _exit_code variable will read -2. Note that some shells like
2380 2380 # csh and fish don't follow sh/bash conventions for exit codes.
2381 2381 executable = os.environ.get('SHELL', None)
2382 2382 try:
2383 2383 # Use env shell instead of default /bin/sh
2384 2384 ec = subprocess.call(cmd, shell=True, executable=executable)
2385 2385 except KeyboardInterrupt:
2386 2386 # intercept control-C; a long traceback is not useful here
2387 2387 self.write_err('\n' + self.get_exception_only())
2388 2388 ec = 130
2389 2389 if ec > 128:
2390 2390 ec = -(ec - 128)
2391 2391
2392 2392 # We explicitly do NOT return the subprocess status code, because
2393 2393 # a non-None value would trigger :func:`sys.displayhook` calls.
2394 2394 # Instead, we store the exit_code in user_ns. Note the semantics
2395 2395 # of _exit_code: for control-c, _exit_code == -signal.SIGNIT,
2396 2396 # but raising SystemExit(_exit_code) will give status 254!
2397 2397 self.user_ns['_exit_code'] = ec
2398 2398
2399 2399 # use piped system by default, because it is better behaved
2400 2400 system = system_piped
2401 2401
2402 2402 def getoutput(self, cmd, split=True, depth=0):
2403 2403 """Get output (possibly including stderr) from a subprocess.
2404 2404
2405 2405 Parameters
2406 2406 ----------
2407 2407 cmd : str
2408 2408 Command to execute (can not end in '&', as background processes are
2409 2409 not supported.
2410 2410 split : bool, optional
2411 2411 If True, split the output into an IPython SList. Otherwise, an
2412 2412 IPython LSString is returned. These are objects similar to normal
2413 2413 lists and strings, with a few convenience attributes for easier
2414 2414 manipulation of line-based output. You can use '?' on them for
2415 2415 details.
2416 2416 depth : int, optional
2417 2417 How many frames above the caller are the local variables which should
2418 2418 be expanded in the command string? The default (0) assumes that the
2419 2419 expansion variables are in the stack frame calling this function.
2420 2420 """
2421 2421 if cmd.rstrip().endswith('&'):
2422 2422 # this is *far* from a rigorous test
2423 2423 raise OSError("Background processes not supported.")
2424 2424 out = getoutput(self.var_expand(cmd, depth=depth+1))
2425 2425 if split:
2426 2426 out = SList(out.splitlines())
2427 2427 else:
2428 2428 out = LSString(out)
2429 2429 return out
2430 2430
2431 2431 #-------------------------------------------------------------------------
2432 2432 # Things related to aliases
2433 2433 #-------------------------------------------------------------------------
2434 2434
2435 2435 def init_alias(self):
2436 2436 self.alias_manager = AliasManager(shell=self, parent=self)
2437 2437 self.configurables.append(self.alias_manager)
2438 2438
2439 2439 #-------------------------------------------------------------------------
2440 2440 # Things related to extensions
2441 2441 #-------------------------------------------------------------------------
2442 2442
2443 2443 def init_extension_manager(self):
2444 2444 self.extension_manager = ExtensionManager(shell=self, parent=self)
2445 2445 self.configurables.append(self.extension_manager)
2446 2446
2447 2447 #-------------------------------------------------------------------------
2448 2448 # Things related to payloads
2449 2449 #-------------------------------------------------------------------------
2450 2450
2451 2451 def init_payload(self):
2452 2452 self.payload_manager = PayloadManager(parent=self)
2453 2453 self.configurables.append(self.payload_manager)
2454 2454
2455 2455 #-------------------------------------------------------------------------
2456 2456 # Things related to the prefilter
2457 2457 #-------------------------------------------------------------------------
2458 2458
2459 2459 def init_prefilter(self):
2460 2460 self.prefilter_manager = PrefilterManager(shell=self, parent=self)
2461 2461 self.configurables.append(self.prefilter_manager)
2462 2462 # Ultimately this will be refactored in the new interpreter code, but
2463 2463 # for now, we should expose the main prefilter method (there's legacy
2464 2464 # code out there that may rely on this).
2465 2465 self.prefilter = self.prefilter_manager.prefilter_lines
2466 2466
2467 2467 def auto_rewrite_input(self, cmd):
2468 2468 """Print to the screen the rewritten form of the user's command.
2469 2469
2470 2470 This shows visual feedback by rewriting input lines that cause
2471 2471 automatic calling to kick in, like::
2472 2472
2473 2473 /f x
2474 2474
2475 2475 into::
2476 2476
2477 2477 ------> f(x)
2478 2478
2479 2479 after the user's input prompt. This helps the user understand that the
2480 2480 input line was transformed automatically by IPython.
2481 2481 """
2482 2482 if not self.show_rewritten_input:
2483 2483 return
2484 2484
2485 2485 rw = self.prompt_manager.render('rewrite') + cmd
2486 2486
2487 2487 try:
2488 2488 # plain ascii works better w/ pyreadline, on some machines, so
2489 2489 # we use it and only print uncolored rewrite if we have unicode
2490 2490 rw = str(rw)
2491 2491 print(rw, file=io.stdout)
2492 2492 except UnicodeEncodeError:
2493 2493 print("------> " + cmd)
2494 2494
2495 2495 #-------------------------------------------------------------------------
2496 2496 # Things related to extracting values/expressions from kernel and user_ns
2497 2497 #-------------------------------------------------------------------------
2498 2498
2499 2499 def _user_obj_error(self):
2500 2500 """return simple exception dict
2501 2501
2502 2502 for use in user_expressions
2503 2503 """
2504 2504
2505 2505 etype, evalue, tb = self._get_exc_info()
2506 2506 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2507 2507
2508 2508 exc_info = {
2509 2509 u'status' : 'error',
2510 2510 u'traceback' : stb,
2511 2511 u'ename' : unicode_type(etype.__name__),
2512 2512 u'evalue' : py3compat.safe_unicode(evalue),
2513 2513 }
2514 2514
2515 2515 return exc_info
2516 2516
2517 2517 def _format_user_obj(self, obj):
2518 2518 """format a user object to display dict
2519 2519
2520 2520 for use in user_expressions
2521 2521 """
2522 2522
2523 2523 data, md = self.display_formatter.format(obj)
2524 2524 value = {
2525 2525 'status' : 'ok',
2526 2526 'data' : data,
2527 2527 'metadata' : md,
2528 2528 }
2529 2529 return value
2530 2530
2531 2531 def user_expressions(self, expressions):
2532 2532 """Evaluate a dict of expressions in the user's namespace.
2533 2533
2534 2534 Parameters
2535 2535 ----------
2536 2536 expressions : dict
2537 2537 A dict with string keys and string values. The expression values
2538 2538 should be valid Python expressions, each of which will be evaluated
2539 2539 in the user namespace.
2540 2540
2541 2541 Returns
2542 2542 -------
2543 2543 A dict, keyed like the input expressions dict, with the rich mime-typed
2544 2544 display_data of each value.
2545 2545 """
2546 2546 out = {}
2547 2547 user_ns = self.user_ns
2548 2548 global_ns = self.user_global_ns
2549 2549
2550 2550 for key, expr in iteritems(expressions):
2551 2551 try:
2552 2552 value = self._format_user_obj(eval(expr, global_ns, user_ns))
2553 2553 except:
2554 2554 value = self._user_obj_error()
2555 2555 out[key] = value
2556 2556 return out
2557 2557
2558 2558 #-------------------------------------------------------------------------
2559 2559 # Things related to the running of code
2560 2560 #-------------------------------------------------------------------------
2561 2561
2562 2562 def ex(self, cmd):
2563 2563 """Execute a normal python statement in user namespace."""
2564 2564 with self.builtin_trap:
2565 2565 exec(cmd, self.user_global_ns, self.user_ns)
2566 2566
2567 2567 def ev(self, expr):
2568 2568 """Evaluate python expression expr in user namespace.
2569 2569
2570 2570 Returns the result of evaluation
2571 2571 """
2572 2572 with self.builtin_trap:
2573 2573 return eval(expr, self.user_global_ns, self.user_ns)
2574 2574
2575 2575 def safe_execfile(self, fname, *where, **kw):
2576 2576 """A safe version of the builtin execfile().
2577 2577
2578 2578 This version will never throw an exception, but instead print
2579 2579 helpful error messages to the screen. This only works on pure
2580 2580 Python files with the .py extension.
2581 2581
2582 2582 Parameters
2583 2583 ----------
2584 2584 fname : string
2585 2585 The name of the file to be executed.
2586 2586 where : tuple
2587 2587 One or two namespaces, passed to execfile() as (globals,locals).
2588 2588 If only one is given, it is passed as both.
2589 2589 exit_ignore : bool (False)
2590 2590 If True, then silence SystemExit for non-zero status (it is always
2591 2591 silenced for zero status, as it is so common).
2592 2592 raise_exceptions : bool (False)
2593 2593 If True raise exceptions everywhere. Meant for testing.
2594 2594 shell_futures : bool (False)
2595 2595 If True, the code will share future statements with the interactive
2596 2596 shell. It will both be affected by previous __future__ imports, and
2597 2597 any __future__ imports in the code will affect the shell. If False,
2598 2598 __future__ imports are not shared in either direction.
2599 2599
2600 2600 """
2601 2601 kw.setdefault('exit_ignore', False)
2602 2602 kw.setdefault('raise_exceptions', False)
2603 2603 kw.setdefault('shell_futures', False)
2604 2604
2605 2605 fname = os.path.abspath(os.path.expanduser(fname))
2606 2606
2607 2607 # Make sure we can open the file
2608 2608 try:
2609 2609 with open(fname) as thefile:
2610 2610 pass
2611 2611 except:
2612 2612 warn('Could not open file <%s> for safe execution.' % fname)
2613 2613 return
2614 2614
2615 2615 # Find things also in current directory. This is needed to mimic the
2616 2616 # behavior of running a script from the system command line, where
2617 2617 # Python inserts the script's directory into sys.path
2618 2618 dname = os.path.dirname(fname)
2619 2619
2620 2620 with prepended_to_syspath(dname):
2621 2621 try:
2622 2622 glob, loc = (where + (None, ))[:2]
2623 2623 py3compat.execfile(
2624 2624 fname, glob, loc,
2625 2625 self.compile if kw['shell_futures'] else None)
2626 2626 except SystemExit as status:
2627 2627 # If the call was made with 0 or None exit status (sys.exit(0)
2628 2628 # or sys.exit() ), don't bother showing a traceback, as both of
2629 2629 # these are considered normal by the OS:
2630 2630 # > python -c'import sys;sys.exit(0)'; echo $?
2631 2631 # 0
2632 2632 # > python -c'import sys;sys.exit()'; echo $?
2633 2633 # 0
2634 2634 # For other exit status, we show the exception unless
2635 2635 # explicitly silenced, but only in short form.
2636 2636 if kw['raise_exceptions']:
2637 2637 raise
2638 2638 if status.code and not kw['exit_ignore']:
2639 2639 self.showtraceback(exception_only=True)
2640 2640 except:
2641 2641 if kw['raise_exceptions']:
2642 2642 raise
2643 2643 # tb offset is 2 because we wrap execfile
2644 2644 self.showtraceback(tb_offset=2)
2645 2645
2646 2646 def safe_execfile_ipy(self, fname, shell_futures=False):
2647 2647 """Like safe_execfile, but for .ipy or .ipynb files with IPython syntax.
2648 2648
2649 2649 Parameters
2650 2650 ----------
2651 2651 fname : str
2652 2652 The name of the file to execute. The filename must have a
2653 2653 .ipy or .ipynb extension.
2654 2654 shell_futures : bool (False)
2655 2655 If True, the code will share future statements with the interactive
2656 2656 shell. It will both be affected by previous __future__ imports, and
2657 2657 any __future__ imports in the code will affect the shell. If False,
2658 2658 __future__ imports are not shared in either direction.
2659 2659 """
2660 2660 fname = os.path.abspath(os.path.expanduser(fname))
2661 2661
2662 2662 # Make sure we can open the file
2663 2663 try:
2664 2664 with open(fname) as thefile:
2665 2665 pass
2666 2666 except:
2667 2667 warn('Could not open file <%s> for safe execution.' % fname)
2668 2668 return
2669 2669
2670 2670 # Find things also in current directory. This is needed to mimic the
2671 2671 # behavior of running a script from the system command line, where
2672 2672 # Python inserts the script's directory into sys.path
2673 2673 dname = os.path.dirname(fname)
2674 2674
2675 2675 def get_cells():
2676 2676 """generator for sequence of code blocks to run"""
2677 2677 if fname.endswith('.ipynb'):
2678 2678 from IPython.nbformat import read
2679 2679 with io_open(fname) as f:
2680 2680 nb = read(f, as_version=4)
2681 2681 if not nb.cells:
2682 2682 return
2683 2683 for cell in nb.cells:
2684 2684 if cell.cell_type == 'code':
2685 2685 yield cell.source
2686 2686 else:
2687 2687 with open(fname) as f:
2688 2688 yield f.read()
2689 2689
2690 2690 with prepended_to_syspath(dname):
2691 2691 try:
2692 2692 for cell in get_cells():
2693 2693 # self.run_cell currently captures all exceptions
2694 2694 # raised in user code. It would be nice if there were
2695 2695 # versions of run_cell that did raise, so
2696 2696 # we could catch the errors.
2697 2697 self.run_cell(cell, silent=True, shell_futures=shell_futures)
2698 2698 except:
2699 2699 self.showtraceback()
2700 2700 warn('Unknown failure executing file: <%s>' % fname)
2701 2701
2702 2702 def safe_run_module(self, mod_name, where):
2703 2703 """A safe version of runpy.run_module().
2704 2704
2705 2705 This version will never throw an exception, but instead print
2706 2706 helpful error messages to the screen.
2707 2707
2708 2708 `SystemExit` exceptions with status code 0 or None are ignored.
2709 2709
2710 2710 Parameters
2711 2711 ----------
2712 2712 mod_name : string
2713 2713 The name of the module to be executed.
2714 2714 where : dict
2715 2715 The globals namespace.
2716 2716 """
2717 2717 try:
2718 2718 try:
2719 2719 where.update(
2720 2720 runpy.run_module(str(mod_name), run_name="__main__",
2721 2721 alter_sys=True)
2722 2722 )
2723 2723 except SystemExit as status:
2724 2724 if status.code:
2725 2725 raise
2726 2726 except:
2727 2727 self.showtraceback()
2728 2728 warn('Unknown failure executing module: <%s>' % mod_name)
2729 2729
2730 2730 def _run_cached_cell_magic(self, magic_name, line):
2731 2731 """Special method to call a cell magic with the data stored in self.
2732 2732 """
2733 2733 cell = self._current_cell_magic_body
2734 2734 self._current_cell_magic_body = None
2735 2735 return self.run_cell_magic(magic_name, line, cell)
2736 2736
2737 2737 def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True):
2738 2738 """Run a complete IPython cell.
2739 2739
2740 2740 Parameters
2741 2741 ----------
2742 2742 raw_cell : str
2743 2743 The code (including IPython code such as %magic functions) to run.
2744 2744 store_history : bool
2745 2745 If True, the raw and translated cell will be stored in IPython's
2746 2746 history. For user code calling back into IPython's machinery, this
2747 2747 should be set to False.
2748 2748 silent : bool
2749 2749 If True, avoid side-effects, such as implicit displayhooks and
2750 2750 and logging. silent=True forces store_history=False.
2751 2751 shell_futures : bool
2752 2752 If True, the code will share future statements with the interactive
2753 2753 shell. It will both be affected by previous __future__ imports, and
2754 2754 any __future__ imports in the code will affect the shell. If False,
2755 2755 __future__ imports are not shared in either direction.
2756 2756 """
2757 2757 if (not raw_cell) or raw_cell.isspace():
2758 2758 return
2759 2759
2760 2760 if silent:
2761 2761 store_history = False
2762 2762
2763 2763 self.events.trigger('pre_execute')
2764 2764 if not silent:
2765 2765 self.events.trigger('pre_run_cell')
2766 2766
2767 2767 # If any of our input transformation (input_transformer_manager or
2768 2768 # prefilter_manager) raises an exception, we store it in this variable
2769 2769 # so that we can display the error after logging the input and storing
2770 2770 # it in the history.
2771 2771 preprocessing_exc_tuple = None
2772 2772 try:
2773 2773 # Static input transformations
2774 2774 cell = self.input_transformer_manager.transform_cell(raw_cell)
2775 2775 except SyntaxError:
2776 2776 preprocessing_exc_tuple = sys.exc_info()
2777 2777 cell = raw_cell # cell has to exist so it can be stored/logged
2778 2778 else:
2779 2779 if len(cell.splitlines()) == 1:
2780 2780 # Dynamic transformations - only applied for single line commands
2781 2781 with self.builtin_trap:
2782 2782 try:
2783 2783 # use prefilter_lines to handle trailing newlines
2784 2784 # restore trailing newline for ast.parse
2785 2785 cell = self.prefilter_manager.prefilter_lines(cell) + '\n'
2786 2786 except Exception:
2787 2787 # don't allow prefilter errors to crash IPython
2788 2788 preprocessing_exc_tuple = sys.exc_info()
2789 2789
2790 2790 # Store raw and processed history
2791 2791 if store_history:
2792 2792 self.history_manager.store_inputs(self.execution_count,
2793 2793 cell, raw_cell)
2794 2794 if not silent:
2795 2795 self.logger.log(cell, raw_cell)
2796 2796
2797 2797 # Display the exception if input processing failed.
2798 2798 if preprocessing_exc_tuple is not None:
2799 2799 self.showtraceback(preprocessing_exc_tuple)
2800 2800 if store_history:
2801 2801 self.execution_count += 1
2802 2802 return
2803 2803
2804 2804 # Our own compiler remembers the __future__ environment. If we want to
2805 2805 # run code with a separate __future__ environment, use the default
2806 2806 # compiler
2807 2807 compiler = self.compile if shell_futures else CachingCompiler()
2808 2808
2809 2809 with self.builtin_trap:
2810 2810 cell_name = self.compile.cache(cell, self.execution_count)
2811 2811
2812 2812 with self.display_trap:
2813 2813 # Compile to bytecode
2814 2814 try:
2815 2815 code_ast = compiler.ast_parse(cell, filename=cell_name)
2816 2816 except IndentationError:
2817 2817 self.showindentationerror()
2818 2818 if store_history:
2819 2819 self.execution_count += 1
2820 2820 return None
2821 2821 except (OverflowError, SyntaxError, ValueError, TypeError,
2822 2822 MemoryError):
2823 2823 self.showsyntaxerror()
2824 2824 if store_history:
2825 2825 self.execution_count += 1
2826 2826 return None
2827 2827
2828 2828 # Apply AST transformations
2829 2829 try:
2830 2830 code_ast = self.transform_ast(code_ast)
2831 2831 except InputRejected:
2832 2832 self.showtraceback()
2833 2833 if store_history:
2834 2834 self.execution_count += 1
2835 2835 return None
2836 2836
2837 2837 # Execute the user code
2838 2838 interactivity = "none" if silent else self.ast_node_interactivity
2839 2839 self.run_ast_nodes(code_ast.body, cell_name,
2840 2840 interactivity=interactivity, compiler=compiler)
2841 2841
2842 2842 self.events.trigger('post_execute')
2843 2843 if not silent:
2844 2844 self.events.trigger('post_run_cell')
2845 2845
2846 2846 if store_history:
2847 2847 # Write output to the database. Does nothing unless
2848 2848 # history output logging is enabled.
2849 2849 self.history_manager.store_output(self.execution_count)
2850 2850 # Each cell is a *single* input, regardless of how many lines it has
2851 2851 self.execution_count += 1
2852 2852
2853 2853 def transform_ast(self, node):
2854 2854 """Apply the AST transformations from self.ast_transformers
2855 2855
2856 2856 Parameters
2857 2857 ----------
2858 2858 node : ast.Node
2859 2859 The root node to be transformed. Typically called with the ast.Module
2860 2860 produced by parsing user input.
2861 2861
2862 2862 Returns
2863 2863 -------
2864 2864 An ast.Node corresponding to the node it was called with. Note that it
2865 2865 may also modify the passed object, so don't rely on references to the
2866 2866 original AST.
2867 2867 """
2868 2868 for transformer in self.ast_transformers:
2869 2869 try:
2870 2870 node = transformer.visit(node)
2871 2871 except InputRejected:
2872 2872 # User-supplied AST transformers can reject an input by raising
2873 2873 # an InputRejected. Short-circuit in this case so that we
2874 2874 # don't unregister the transform.
2875 2875 raise
2876 2876 except Exception:
2877 2877 warn("AST transformer %r threw an error. It will be unregistered." % transformer)
2878 2878 self.ast_transformers.remove(transformer)
2879 2879
2880 2880 if self.ast_transformers:
2881 2881 ast.fix_missing_locations(node)
2882 2882 return node
2883 2883
2884 2884
2885 2885 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr',
2886 2886 compiler=compile):
2887 2887 """Run a sequence of AST nodes. The execution mode depends on the
2888 2888 interactivity parameter.
2889 2889
2890 2890 Parameters
2891 2891 ----------
2892 2892 nodelist : list
2893 2893 A sequence of AST nodes to run.
2894 2894 cell_name : str
2895 2895 Will be passed to the compiler as the filename of the cell. Typically
2896 2896 the value returned by ip.compile.cache(cell).
2897 2897 interactivity : str
2898 2898 'all', 'last', 'last_expr' or 'none', specifying which nodes should be
2899 2899 run interactively (displaying output from expressions). 'last_expr'
2900 2900 will run the last node interactively only if it is an expression (i.e.
2901 2901 expressions in loops or other blocks are not displayed. Other values
2902 2902 for this parameter will raise a ValueError.
2903 2903 compiler : callable
2904 2904 A function with the same interface as the built-in compile(), to turn
2905 2905 the AST nodes into code objects. Default is the built-in compile().
2906 2906 """
2907 2907 if not nodelist:
2908 2908 return
2909 2909
2910 2910 if interactivity == 'last_expr':
2911 2911 if isinstance(nodelist[-1], ast.Expr):
2912 2912 interactivity = "last"
2913 2913 else:
2914 2914 interactivity = "none"
2915 2915
2916 2916 if interactivity == 'none':
2917 2917 to_run_exec, to_run_interactive = nodelist, []
2918 2918 elif interactivity == 'last':
2919 2919 to_run_exec, to_run_interactive = nodelist[:-1], nodelist[-1:]
2920 2920 elif interactivity == 'all':
2921 2921 to_run_exec, to_run_interactive = [], nodelist
2922 2922 else:
2923 2923 raise ValueError("Interactivity was %r" % interactivity)
2924 2924
2925 2925 exec_count = self.execution_count
2926 2926
2927 2927 try:
2928 2928 for i, node in enumerate(to_run_exec):
2929 2929 mod = ast.Module([node])
2930 2930 code = compiler(mod, cell_name, "exec")
2931 2931 if self.run_code(code):
2932 2932 return True
2933 2933
2934 2934 for i, node in enumerate(to_run_interactive):
2935 2935 mod = ast.Interactive([node])
2936 2936 code = compiler(mod, cell_name, "single")
2937 2937 if self.run_code(code):
2938 2938 return True
2939 2939
2940 2940 # Flush softspace
2941 2941 if softspace(sys.stdout, 0):
2942 2942 print()
2943 2943
2944 2944 except:
2945 2945 # It's possible to have exceptions raised here, typically by
2946 2946 # compilation of odd code (such as a naked 'return' outside a
2947 2947 # function) that did parse but isn't valid. Typically the exception
2948 2948 # is a SyntaxError, but it's safest just to catch anything and show
2949 2949 # the user a traceback.
2950 2950
2951 2951 # We do only one try/except outside the loop to minimize the impact
2952 2952 # on runtime, and also because if any node in the node list is
2953 2953 # broken, we should stop execution completely.
2954 2954 self.showtraceback()
2955 2955
2956 2956 return False
2957 2957
2958 2958 def run_code(self, code_obj):
2959 2959 """Execute a code object.
2960 2960
2961 2961 When an exception occurs, self.showtraceback() is called to display a
2962 2962 traceback.
2963 2963
2964 2964 Parameters
2965 2965 ----------
2966 2966 code_obj : code object
2967 2967 A compiled code object, to be executed
2968 2968
2969 2969 Returns
2970 2970 -------
2971 2971 False : successful execution.
2972 2972 True : an error occurred.
2973 2973 """
2974 2974 # Set our own excepthook in case the user code tries to call it
2975 2975 # directly, so that the IPython crash handler doesn't get triggered
2976 2976 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
2977 2977
2978 2978 # we save the original sys.excepthook in the instance, in case config
2979 2979 # code (such as magics) needs access to it.
2980 2980 self.sys_excepthook = old_excepthook
2981 2981 outflag = 1 # happens in more places, so it's easier as default
2982 2982 try:
2983 2983 try:
2984 2984 self.hooks.pre_run_code_hook()
2985 2985 #rprint('Running code', repr(code_obj)) # dbg
2986 2986 exec(code_obj, self.user_global_ns, self.user_ns)
2987 2987 finally:
2988 2988 # Reset our crash handler in place
2989 2989 sys.excepthook = old_excepthook
2990 2990 except SystemExit:
2991 2991 self.showtraceback(exception_only=True)
2992 2992 warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1)
2993 2993 except self.custom_exceptions:
2994 2994 etype, value, tb = sys.exc_info()
2995 2995 self.CustomTB(etype, value, tb)
2996 2996 except:
2997 2997 self.showtraceback()
2998 2998 else:
2999 2999 outflag = 0
3000 3000 return outflag
3001 3001
3002 3002 # For backwards compatibility
3003 3003 runcode = run_code
3004 3004
3005 3005 #-------------------------------------------------------------------------
3006 3006 # Things related to GUI support and pylab
3007 3007 #-------------------------------------------------------------------------
3008 3008
3009 3009 def enable_gui(self, gui=None):
3010 3010 raise NotImplementedError('Implement enable_gui in a subclass')
3011 3011
3012 3012 def enable_matplotlib(self, gui=None):
3013 3013 """Enable interactive matplotlib and inline figure support.
3014 3014
3015 3015 This takes the following steps:
3016 3016
3017 3017 1. select the appropriate eventloop and matplotlib backend
3018 3018 2. set up matplotlib for interactive use with that backend
3019 3019 3. configure formatters for inline figure display
3020 3020 4. enable the selected gui eventloop
3021 3021
3022 3022 Parameters
3023 3023 ----------
3024 3024 gui : optional, string
3025 3025 If given, dictates the choice of matplotlib GUI backend to use
3026 3026 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3027 3027 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3028 3028 matplotlib (as dictated by the matplotlib build-time options plus the
3029 3029 user's matplotlibrc configuration file). Note that not all backends
3030 3030 make sense in all contexts, for example a terminal ipython can't
3031 3031 display figures inline.
3032 3032 """
3033 3033 from IPython.core import pylabtools as pt
3034 3034 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3035 3035
3036 3036 if gui != 'inline':
3037 3037 # If we have our first gui selection, store it
3038 3038 if self.pylab_gui_select is None:
3039 3039 self.pylab_gui_select = gui
3040 3040 # Otherwise if they are different
3041 3041 elif gui != self.pylab_gui_select:
3042 3042 print ('Warning: Cannot change to a different GUI toolkit: %s.'
3043 3043 ' Using %s instead.' % (gui, self.pylab_gui_select))
3044 3044 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3045 3045
3046 3046 pt.activate_matplotlib(backend)
3047 3047 pt.configure_inline_support(self, backend)
3048 3048
3049 3049 # Now we must activate the gui pylab wants to use, and fix %run to take
3050 3050 # plot updates into account
3051 3051 self.enable_gui(gui)
3052 3052 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3053 3053 pt.mpl_runner(self.safe_execfile)
3054 3054
3055 3055 return gui, backend
3056 3056
3057 3057 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
3058 3058 """Activate pylab support at runtime.
3059 3059
3060 3060 This turns on support for matplotlib, preloads into the interactive
3061 3061 namespace all of numpy and pylab, and configures IPython to correctly
3062 3062 interact with the GUI event loop. The GUI backend to be used can be
3063 3063 optionally selected with the optional ``gui`` argument.
3064 3064
3065 3065 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3066 3066
3067 3067 Parameters
3068 3068 ----------
3069 3069 gui : optional, string
3070 3070 If given, dictates the choice of matplotlib GUI backend to use
3071 3071 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
3072 3072 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
3073 3073 matplotlib (as dictated by the matplotlib build-time options plus the
3074 3074 user's matplotlibrc configuration file). Note that not all backends
3075 3075 make sense in all contexts, for example a terminal ipython can't
3076 3076 display figures inline.
3077 3077 import_all : optional, bool, default: True
3078 3078 Whether to do `from numpy import *` and `from pylab import *`
3079 3079 in addition to module imports.
3080 3080 welcome_message : deprecated
3081 3081 This argument is ignored, no welcome message will be displayed.
3082 3082 """
3083 3083 from IPython.core.pylabtools import import_pylab
3084 3084
3085 3085 gui, backend = self.enable_matplotlib(gui)
3086 3086
3087 3087 # We want to prevent the loading of pylab to pollute the user's
3088 3088 # namespace as shown by the %who* magics, so we execute the activation
3089 3089 # code in an empty namespace, and we update *both* user_ns and
3090 3090 # user_ns_hidden with this information.
3091 3091 ns = {}
3092 3092 import_pylab(ns, import_all)
3093 3093 # warn about clobbered names
3094 3094 ignored = set(["__builtins__"])
3095 3095 both = set(ns).intersection(self.user_ns).difference(ignored)
3096 3096 clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
3097 3097 self.user_ns.update(ns)
3098 3098 self.user_ns_hidden.update(ns)
3099 3099 return gui, backend, clobbered
3100 3100
3101 3101 #-------------------------------------------------------------------------
3102 3102 # Utilities
3103 3103 #-------------------------------------------------------------------------
3104 3104
3105 3105 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
3106 3106 """Expand python variables in a string.
3107 3107
3108 3108 The depth argument indicates how many frames above the caller should
3109 3109 be walked to look for the local namespace where to expand variables.
3110 3110
3111 3111 The global namespace for expansion is always the user's interactive
3112 3112 namespace.
3113 3113 """
3114 3114 ns = self.user_ns.copy()
3115 3115 try:
3116 3116 frame = sys._getframe(depth+1)
3117 3117 except ValueError:
3118 3118 # This is thrown if there aren't that many frames on the stack,
3119 3119 # e.g. if a script called run_line_magic() directly.
3120 3120 pass
3121 3121 else:
3122 3122 ns.update(frame.f_locals)
3123 3123
3124 3124 try:
3125 3125 # We have to use .vformat() here, because 'self' is a valid and common
3126 3126 # name, and expanding **ns for .format() would make it collide with
3127 3127 # the 'self' argument of the method.
3128 3128 cmd = formatter.vformat(cmd, args=[], kwargs=ns)
3129 3129 except Exception:
3130 3130 # if formatter couldn't format, just let it go untransformed
3131 3131 pass
3132 3132 return cmd
3133 3133
3134 3134 def mktempfile(self, data=None, prefix='ipython_edit_'):
3135 3135 """Make a new tempfile and return its filename.
3136 3136
3137 3137 This makes a call to tempfile.mkstemp (created in a tempfile.mkdtemp),
3138 3138 but it registers the created filename internally so ipython cleans it up
3139 3139 at exit time.
3140 3140
3141 3141 Optional inputs:
3142 3142
3143 3143 - data(None): if data is given, it gets written out to the temp file
3144 3144 immediately, and the file is closed again."""
3145 3145
3146 3146 dirname = tempfile.mkdtemp(prefix=prefix)
3147 3147 self.tempdirs.append(dirname)
3148 3148
3149 3149 handle, filename = tempfile.mkstemp('.py', prefix, dir=dirname)
3150 3150 os.close(handle) # On Windows, there can only be one open handle on a file
3151 3151 self.tempfiles.append(filename)
3152 3152
3153 3153 if data:
3154 3154 tmp_file = open(filename,'w')
3155 3155 tmp_file.write(data)
3156 3156 tmp_file.close()
3157 3157 return filename
3158 3158
3159 3159 # TODO: This should be removed when Term is refactored.
3160 3160 def write(self,data):
3161 3161 """Write a string to the default output"""
3162 3162 io.stdout.write(data)
3163 3163
3164 3164 # TODO: This should be removed when Term is refactored.
3165 3165 def write_err(self,data):
3166 3166 """Write a string to the default error output"""
3167 3167 io.stderr.write(data)
3168 3168
3169 3169 def ask_yes_no(self, prompt, default=None):
3170 3170 if self.quiet:
3171 3171 return True
3172 3172 return ask_yes_no(prompt,default)
3173 3173
3174 3174 def show_usage(self):
3175 3175 """Show a usage message"""
3176 3176 page.page(IPython.core.usage.interactive_usage)
3177 3177
3178 3178 def extract_input_lines(self, range_str, raw=False):
3179 3179 """Return as a string a set of input history slices.
3180 3180
3181 3181 Parameters
3182 3182 ----------
3183 3183 range_str : string
3184 3184 The set of slices is given as a string, like "~5/6-~4/2 4:8 9",
3185 3185 since this function is for use by magic functions which get their
3186 3186 arguments as strings. The number before the / is the session
3187 3187 number: ~n goes n back from the current session.
3188 3188
3189 3189 raw : bool, optional
3190 3190 By default, the processed input is used. If this is true, the raw
3191 3191 input history is used instead.
3192 3192
3193 3193 Notes
3194 3194 -----
3195 3195
3196 3196 Slices can be described with two notations:
3197 3197
3198 3198 * ``N:M`` -> standard python form, means including items N...(M-1).
3199 3199 * ``N-M`` -> include items N..M (closed endpoint).
3200 3200 """
3201 3201 lines = self.history_manager.get_range_by_str(range_str, raw=raw)
3202 3202 return "\n".join(x for _, _, x in lines)
3203 3203
3204 3204 def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=True, search_ns=False):
3205 3205 """Get a code string from history, file, url, or a string or macro.
3206 3206
3207 3207 This is mainly used by magic functions.
3208 3208
3209 3209 Parameters
3210 3210 ----------
3211 3211
3212 3212 target : str
3213 3213
3214 3214 A string specifying code to retrieve. This will be tried respectively
3215 3215 as: ranges of input history (see %history for syntax), url,
3216 3216 correspnding .py file, filename, or an expression evaluating to a
3217 3217 string or Macro in the user namespace.
3218 3218
3219 3219 raw : bool
3220 3220 If true (default), retrieve raw history. Has no effect on the other
3221 3221 retrieval mechanisms.
3222 3222
3223 3223 py_only : bool (default False)
3224 3224 Only try to fetch python code, do not try alternative methods to decode file
3225 3225 if unicode fails.
3226 3226
3227 3227 Returns
3228 3228 -------
3229 3229 A string of code.
3230 3230
3231 3231 ValueError is raised if nothing is found, and TypeError if it evaluates
3232 3232 to an object of another type. In each case, .args[0] is a printable
3233 3233 message.
3234 3234 """
3235 3235 code = self.extract_input_lines(target, raw=raw) # Grab history
3236 3236 if code:
3237 3237 return code
3238 3238 utarget = unquote_filename(target)
3239 3239 try:
3240 3240 if utarget.startswith(('http://', 'https://')):
3241 3241 return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie)
3242 3242 except UnicodeDecodeError:
3243 3243 if not py_only :
3244 3244 # Deferred import
3245 3245 try:
3246 3246 from urllib.request import urlopen # Py3
3247 3247 except ImportError:
3248 3248 from urllib import urlopen
3249 3249 response = urlopen(target)
3250 3250 return response.read().decode('latin1')
3251 3251 raise ValueError(("'%s' seem to be unreadable.") % utarget)
3252 3252
3253 3253 potential_target = [target]
3254 3254 try :
3255 3255 potential_target.insert(0,get_py_filename(target))
3256 3256 except IOError:
3257 3257 pass
3258 3258
3259 3259 for tgt in potential_target :
3260 3260 if os.path.isfile(tgt): # Read file
3261 3261 try :
3262 3262 return openpy.read_py_file(tgt, skip_encoding_cookie=skip_encoding_cookie)
3263 3263 except UnicodeDecodeError :
3264 3264 if not py_only :
3265 3265 with io_open(tgt,'r', encoding='latin1') as f :
3266 3266 return f.read()
3267 3267 raise ValueError(("'%s' seem to be unreadable.") % target)
3268 3268 elif os.path.isdir(os.path.expanduser(tgt)):
3269 3269 raise ValueError("'%s' is a directory, not a regular file." % target)
3270 3270
3271 3271 if search_ns:
3272 3272 # Inspect namespace to load object source
3273 3273 object_info = self.object_inspect(target, detail_level=1)
3274 3274 if object_info['found'] and object_info['source']:
3275 3275 return object_info['source']
3276 3276
3277 3277 try: # User namespace
3278 3278 codeobj = eval(target, self.user_ns)
3279 3279 except Exception:
3280 3280 raise ValueError(("'%s' was not found in history, as a file, url, "
3281 3281 "nor in the user namespace.") % target)
3282 3282
3283 3283 if isinstance(codeobj, string_types):
3284 3284 return codeobj
3285 3285 elif isinstance(codeobj, Macro):
3286 3286 return codeobj.value
3287 3287
3288 3288 raise TypeError("%s is neither a string nor a macro." % target,
3289 3289 codeobj)
3290 3290
3291 3291 #-------------------------------------------------------------------------
3292 3292 # Things related to IPython exiting
3293 3293 #-------------------------------------------------------------------------
3294 3294 def atexit_operations(self):
3295 3295 """This will be executed at the time of exit.
3296 3296
3297 3297 Cleanup operations and saving of persistent data that is done
3298 3298 unconditionally by IPython should be performed here.
3299 3299
3300 3300 For things that may depend on startup flags or platform specifics (such
3301 3301 as having readline or not), register a separate atexit function in the
3302 3302 code that has the appropriate information, rather than trying to
3303 3303 clutter
3304 3304 """
3305 3305 # Close the history session (this stores the end time and line count)
3306 3306 # this must be *before* the tempfile cleanup, in case of temporary
3307 3307 # history db
3308 3308 self.history_manager.end_session()
3309 3309
3310 3310 # Cleanup all tempfiles and folders left around
3311 3311 for tfile in self.tempfiles:
3312 3312 try:
3313 3313 os.unlink(tfile)
3314 3314 except OSError:
3315 3315 pass
3316 3316
3317 3317 for tdir in self.tempdirs:
3318 3318 try:
3319 3319 os.rmdir(tdir)
3320 3320 except OSError:
3321 3321 pass
3322 3322
3323 3323 # Clear all user namespaces to release all references cleanly.
3324 3324 self.reset(new_session=False)
3325 3325
3326 3326 # Run user hooks
3327 3327 self.hooks.shutdown_hook()
3328 3328
3329 3329 def cleanup(self):
3330 3330 self.restore_sys_module_state()
3331 3331
3332 3332
3333 3333 class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)):
3334 3334 """An abstract base class for InteractiveShell."""
3335 3335
3336 3336 InteractiveShellABC.register(InteractiveShell)
@@ -1,573 +1,573 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3 /**
4 4 *
5 5 *
6 6 * @module codecell
7 7 * @namespace codecell
8 8 * @class CodeCell
9 9 */
10 10
11 11
12 12 define([
13 13 'base/js/namespace',
14 14 'jquery',
15 15 'base/js/utils',
16 16 'base/js/keyboard',
17 17 'notebook/js/cell',
18 18 'notebook/js/outputarea',
19 19 'notebook/js/completer',
20 20 'notebook/js/celltoolbar',
21 21 'codemirror/lib/codemirror',
22 22 'codemirror/mode/python/python',
23 23 'notebook/js/codemirror-ipython'
24 24 ], function(IPython, $, utils, keyboard, cell, outputarea, completer, celltoolbar, CodeMirror, cmpython, cmip) {
25 25 "use strict";
26 26
27 27 var Cell = cell.Cell;
28 28
29 29 /* local util for codemirror */
30 30 var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
31 31
32 32 /**
33 33 *
34 34 * function to delete until previous non blanking space character
35 35 * or first multiple of 4 tabstop.
36 36 * @private
37 37 */
38 38 CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
39 39 var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
40 40 if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
41 41 var cur = cm.getCursor(), line = cm.getLine(cur.line);
42 42 var tabsize = cm.getOption('tabSize');
43 43 var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
44 44 from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
45 45 var select = cm.getRange(from,cur);
46 46 if( select.match(/^\ +$/) !== null){
47 47 cm.replaceRange("",from,cur);
48 48 } else {
49 49 cm.deleteH(-1,"char");
50 50 }
51 51 };
52 52
53 53 var keycodes = keyboard.keycodes;
54 54
55 55 var CodeCell = function (kernel, options) {
56 56 /**
57 57 * Constructor
58 58 *
59 59 * A Cell conceived to write code.
60 60 *
61 61 * Parameters:
62 62 * kernel: Kernel instance
63 63 * The kernel doesn't have to be set at creation time, in that case
64 64 * it will be null and set_kernel has to be called later.
65 65 * options: dictionary
66 66 * Dictionary of keyword arguments.
67 67 * events: $(Events) instance
68 68 * config: dictionary
69 69 * keyboard_manager: KeyboardManager instance
70 70 * notebook: Notebook instance
71 71 * tooltip: Tooltip instance
72 72 */
73 73 this.kernel = kernel || null;
74 74 this.notebook = options.notebook;
75 75 this.collapsed = false;
76 76 this.events = options.events;
77 77 this.tooltip = options.tooltip;
78 78 this.config = options.config;
79 79
80 80 // create all attributed in constructor function
81 81 // even if null for V8 VM optimisation
82 82 this.input_prompt_number = null;
83 83 this.celltoolbar = null;
84 84 this.output_area = null;
85 85 // Keep a stack of the 'active' output areas (where active means the
86 86 // output area that recieves output). When a user activates an output
87 87 // area, it gets pushed to the stack. Then, when the output area is
88 88 // deactivated, it's popped from the stack. When the stack is empty,
89 89 // the cell's output area is used.
90 90 this.active_output_areas = [];
91 91 var that = this;
92 92 Object.defineProperty(this, 'active_output_area', {
93 93 get: function() {
94 94 if (that.active_output_areas && that.active_output_areas.length > 0) {
95 95 return that.active_output_areas[that.active_output_areas.length-1];
96 96 } else {
97 97 return that.output_area;
98 98 }
99 99 },
100 100 });
101 101
102 102 this.last_msg_id = null;
103 103 this.completer = null;
104 104
105 105
106 106 var config = utils.mergeopt(CodeCell, this.config);
107 107 Cell.apply(this,[{
108 108 config: config,
109 109 keyboard_manager: options.keyboard_manager,
110 110 events: this.events}]);
111 111
112 112 // Attributes we want to override in this subclass.
113 113 this.cell_type = "code";
114 114 this.element.focusout(
115 115 function() { that.auto_highlight(); }
116 116 );
117 117 };
118 118
119 119 CodeCell.options_default = {
120 120 cm_config : {
121 121 extraKeys: {
122 122 "Tab" : "indentMore",
123 123 "Shift-Tab" : "indentLess",
124 124 "Backspace" : "delSpaceToPrevTabStop",
125 125 "Cmd-/" : "toggleComment",
126 126 "Ctrl-/" : "toggleComment"
127 127 },
128 128 mode: 'ipython',
129 129 theme: 'ipython',
130 130 matchBrackets: true
131 131 }
132 132 };
133 133
134 134 CodeCell.msg_cells = {};
135 135
136 136 CodeCell.prototype = Object.create(Cell.prototype);
137 137
138 138 /**
139 139 * @method push_output_area
140 140 */
141 141 CodeCell.prototype.push_output_area = function (output_area) {
142 142 this.active_output_areas.push(output_area);
143 143 };
144 144
145 145 /**
146 146 * @method pop_output_area
147 147 */
148 148 CodeCell.prototype.pop_output_area = function (output_area) {
149 149 var index = this.active_output_areas.lastIndexOf(output_area);
150 150 if (index > -1) {
151 151 this.active_output_areas.splice(index, 1);
152 152 }
153 153 };
154 154
155 155 /**
156 156 * @method auto_highlight
157 157 */
158 158 CodeCell.prototype.auto_highlight = function () {
159 159 this._auto_highlight(this.config.cell_magic_highlight);
160 160 };
161 161
162 162 /** @method create_element */
163 163 CodeCell.prototype.create_element = function () {
164 164 Cell.prototype.create_element.apply(this, arguments);
165 165
166 166 var cell = $('<div></div>').addClass('cell code_cell');
167 167 cell.attr('tabindex','2');
168 168
169 169 var input = $('<div></div>').addClass('input');
170 170 var prompt = $('<div/>').addClass('prompt input_prompt');
171 171 var inner_cell = $('<div/>').addClass('inner_cell');
172 172 this.celltoolbar = new celltoolbar.CellToolbar({
173 173 cell: this,
174 174 notebook: this.notebook});
175 175 inner_cell.append(this.celltoolbar.element);
176 176 var input_area = $('<div/>').addClass('input_area');
177 177 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
178 178 this.code_mirror.on('keydown', $.proxy(this.handle_keyevent,this))
179 179 $(this.code_mirror.getInputField()).attr("spellcheck", "false");
180 180 inner_cell.append(input_area);
181 181 input.append(prompt).append(inner_cell);
182 182
183 183 var widget_area = $('<div/>')
184 184 .addClass('widget-area')
185 185 .hide();
186 186 this.widget_area = widget_area;
187 187 var widget_prompt = $('<div/>')
188 188 .addClass('prompt')
189 189 .appendTo(widget_area);
190 190 var widget_subarea = $('<div/>')
191 191 .addClass('widget-subarea')
192 192 .appendTo(widget_area);
193 193 this.widget_subarea = widget_subarea;
194 194 var widget_clear_buton = $('<button />')
195 195 .addClass('close')
196 196 .html('&times;')
197 197 .click(function() {
198 198 widget_area.slideUp('', function(){ widget_subarea.html(''); });
199 199 })
200 200 .appendTo(widget_prompt);
201 201
202 202 var output = $('<div></div>');
203 203 cell.append(input).append(widget_area).append(output);
204 204 this.element = cell;
205 205 this.output_area = new outputarea.OutputArea({
206 206 selector: output,
207 207 prompt_area: true,
208 208 events: this.events,
209 209 keyboard_manager: this.keyboard_manager});
210 210 this.completer = new completer.Completer(this, this.events);
211 211 };
212 212
213 213 /** @method bind_events */
214 214 CodeCell.prototype.bind_events = function () {
215 215 Cell.prototype.bind_events.apply(this);
216 216 var that = this;
217 217
218 218 this.element.focusout(
219 219 function() { that.auto_highlight(); }
220 220 );
221 221 };
222 222
223 223
224 224 /**
225 225 * This method gets called in CodeMirror's onKeyDown/onKeyPress
226 226 * handlers and is used to provide custom key handling. Its return
227 227 * value is used to determine if CodeMirror should ignore the event:
228 228 * true = ignore, false = don't ignore.
229 229 * @method handle_codemirror_keyevent
230 230 */
231 231
232 232 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
233 233
234 234 var that = this;
235 235 // whatever key is pressed, first, cancel the tooltip request before
236 236 // they are sent, and remove tooltip if any, except for tab again
237 237 var tooltip_closed = null;
238 238 if (event.type === 'keydown' && event.which != keycodes.tab ) {
239 239 tooltip_closed = this.tooltip.remove_and_cancel_tooltip();
240 240 }
241 241
242 242 var cur = editor.getCursor();
243 243 if (event.keyCode === keycodes.enter){
244 244 this.auto_highlight();
245 245 }
246 246
247 247 if (event.which === keycodes.down && event.type === 'keypress' && this.tooltip.time_before_tooltip >= 0) {
248 248 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
249 249 // browser and keyboard layout !
250 250 // Pressing '(' , request tooltip, don't forget to reappend it
251 251 // The second argument says to hide the tooltip if the docstring
252 252 // is actually empty
253 253 this.tooltip.pending(that, true);
254 254 } else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
255 255 // If tooltip is active, cancel it. The call to
256 256 // remove_and_cancel_tooltip above doesn't pass, force=true.
257 257 // Because of this it won't actually close the tooltip
258 258 // if it is in sticky mode. Thus, we have to check again if it is open
259 259 // and close it with force=true.
260 260 if (!this.tooltip._hidden) {
261 261 this.tooltip.remove_and_cancel_tooltip(true);
262 262 }
263 263 // If we closed the tooltip, don't let CM or the global handlers
264 264 // handle this event.
265 265 event.codemirrorIgnore = true;
266 266 event.preventDefault();
267 267 return true;
268 268 } else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
269 269 if (editor.somethingSelected() || editor.getSelections().length !== 1){
270 270 var anchor = editor.getCursor("anchor");
271 271 var head = editor.getCursor("head");
272 272 if( anchor.line != head.line){
273 273 return false;
274 274 }
275 275 }
276 276 this.tooltip.request(that);
277 277 event.codemirrorIgnore = true;
278 278 event.preventDefault();
279 279 return true;
280 280 } else if (event.keyCode === keycodes.tab && event.type == 'keydown') {
281 281 // Tab completion.
282 282 this.tooltip.remove_and_cancel_tooltip();
283 283
284 284 // completion does not work on multicursor, it might be possible though in some cases
285 285 if (editor.somethingSelected() || editor.getSelections().length > 1) {
286 286 return false;
287 287 }
288 288 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
289 289 if (pre_cursor.trim() === "") {
290 290 // Don't autocomplete if the part of the line before the cursor
291 291 // is empty. In this case, let CodeMirror handle indentation.
292 292 return false;
293 293 } else {
294 294 event.codemirrorIgnore = true;
295 295 event.preventDefault();
296 296 this.completer.startCompletion();
297 297 return true;
298 298 }
299 299 }
300 300
301 301 // keyboard event wasn't one of those unique to code cells, let's see
302 302 // if it's one of the generic ones (i.e. check edit mode shortcuts)
303 303 return Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
304 304 };
305 305
306 306 // Kernel related calls.
307 307
308 308 CodeCell.prototype.set_kernel = function (kernel) {
309 309 this.kernel = kernel;
310 310 };
311 311
312 312 /**
313 313 * Execute current code cell to the kernel
314 314 * @method execute
315 315 */
316 316 CodeCell.prototype.execute = function () {
317 317 if (!this.kernel || !this.kernel.is_connected()) {
318 318 console.log("Can't execute, kernel is not connected.");
319 319 return;
320 320 }
321 321
322 322 this.active_output_area.clear_output();
323 323
324 324 // Clear widget area
325 325 this.widget_subarea.html('');
326 326 this.widget_subarea.height('');
327 327 this.widget_area.height('');
328 328 this.widget_area.hide();
329 329
330 330 this.set_input_prompt('*');
331 331 this.element.addClass("running");
332 332 if (this.last_msg_id) {
333 333 this.kernel.clear_callbacks_for_msg(this.last_msg_id);
334 334 }
335 335 var callbacks = this.get_callbacks();
336 336
337 337 var old_msg_id = this.last_msg_id;
338 338 this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
339 339 if (old_msg_id) {
340 340 delete CodeCell.msg_cells[old_msg_id];
341 341 }
342 342 CodeCell.msg_cells[this.last_msg_id] = this;
343 343 this.render();
344 344 this.events.trigger('execute.CodeCell', {cell: this});
345 345 };
346 346
347 347 /**
348 348 * Construct the default callbacks for
349 349 * @method get_callbacks
350 350 */
351 351 CodeCell.prototype.get_callbacks = function () {
352 352 var that = this;
353 353 return {
354 354 shell : {
355 355 reply : $.proxy(this._handle_execute_reply, this),
356 356 payload : {
357 357 set_next_input : $.proxy(this._handle_set_next_input, this),
358 358 page : $.proxy(this._open_with_pager, this)
359 359 }
360 360 },
361 361 iopub : {
362 362 output : function() {
363 363 that.active_output_area.handle_output.apply(that.active_output_area, arguments);
364 364 },
365 365 clear_output : function() {
366 366 that.active_output_area.handle_clear_output.apply(that.active_output_area, arguments);
367 367 },
368 368 },
369 369 input : $.proxy(this._handle_input_request, this)
370 370 };
371 371 };
372 372
373 373 CodeCell.prototype._open_with_pager = function (payload) {
374 374 this.events.trigger('open_with_text.Pager', payload);
375 375 };
376 376
377 377 /**
378 378 * @method _handle_execute_reply
379 379 * @private
380 380 */
381 381 CodeCell.prototype._handle_execute_reply = function (msg) {
382 382 this.set_input_prompt(msg.content.execution_count);
383 383 this.element.removeClass("running");
384 384 this.events.trigger('set_dirty.Notebook', {value: true});
385 385 };
386 386
387 387 /**
388 388 * @method _handle_set_next_input
389 389 * @private
390 390 */
391 391 CodeCell.prototype._handle_set_next_input = function (payload) {
392 var data = {'cell': this, 'text': payload.text};
392 var data = {'cell': this, 'text': payload.text, replace: payload.replace};
393 393 this.events.trigger('set_next_input.Notebook', data);
394 394 };
395 395
396 396 /**
397 397 * @method _handle_input_request
398 398 * @private
399 399 */
400 400 CodeCell.prototype._handle_input_request = function (msg) {
401 401 this.active_output_area.append_raw_input(msg);
402 402 };
403 403
404 404
405 405 // Basic cell manipulation.
406 406
407 407 CodeCell.prototype.select = function () {
408 408 var cont = Cell.prototype.select.apply(this);
409 409 if (cont) {
410 410 this.code_mirror.refresh();
411 411 this.auto_highlight();
412 412 }
413 413 return cont;
414 414 };
415 415
416 416 CodeCell.prototype.render = function () {
417 417 var cont = Cell.prototype.render.apply(this);
418 418 // Always execute, even if we are already in the rendered state
419 419 return cont;
420 420 };
421 421
422 422 CodeCell.prototype.select_all = function () {
423 423 var start = {line: 0, ch: 0};
424 424 var nlines = this.code_mirror.lineCount();
425 425 var last_line = this.code_mirror.getLine(nlines-1);
426 426 var end = {line: nlines-1, ch: last_line.length};
427 427 this.code_mirror.setSelection(start, end);
428 428 };
429 429
430 430
431 431 CodeCell.prototype.collapse_output = function () {
432 432 this.output_area.collapse();
433 433 };
434 434
435 435
436 436 CodeCell.prototype.expand_output = function () {
437 437 this.output_area.expand();
438 438 this.output_area.unscroll_area();
439 439 };
440 440
441 441 CodeCell.prototype.scroll_output = function () {
442 442 this.output_area.expand();
443 443 this.output_area.scroll_if_long();
444 444 };
445 445
446 446 CodeCell.prototype.toggle_output = function () {
447 447 this.output_area.toggle_output();
448 448 };
449 449
450 450 CodeCell.prototype.toggle_output_scroll = function () {
451 451 this.output_area.toggle_scroll();
452 452 };
453 453
454 454
455 455 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
456 456 var ns;
457 457 if (prompt_value === undefined || prompt_value === null) {
458 458 ns = "&nbsp;";
459 459 } else {
460 460 ns = encodeURIComponent(prompt_value);
461 461 }
462 462 return 'In&nbsp;[' + ns + ']:';
463 463 };
464 464
465 465 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
466 466 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
467 467 for(var i=1; i < lines_number; i++) {
468 468 html.push(['...:']);
469 469 }
470 470 return html.join('<br/>');
471 471 };
472 472
473 473 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
474 474
475 475
476 476 CodeCell.prototype.set_input_prompt = function (number) {
477 477 var nline = 1;
478 478 if (this.code_mirror !== undefined) {
479 479 nline = this.code_mirror.lineCount();
480 480 }
481 481 this.input_prompt_number = number;
482 482 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
483 483 // This HTML call is okay because the user contents are escaped.
484 484 this.element.find('div.input_prompt').html(prompt_html);
485 485 };
486 486
487 487
488 488 CodeCell.prototype.clear_input = function () {
489 489 this.code_mirror.setValue('');
490 490 };
491 491
492 492
493 493 CodeCell.prototype.get_text = function () {
494 494 return this.code_mirror.getValue();
495 495 };
496 496
497 497
498 498 CodeCell.prototype.set_text = function (code) {
499 499 return this.code_mirror.setValue(code);
500 500 };
501 501
502 502
503 503 CodeCell.prototype.clear_output = function (wait) {
504 504 this.active_output_area.clear_output(wait);
505 505 this.set_input_prompt();
506 506 };
507 507
508 508
509 509 // JSON serialization
510 510
511 511 CodeCell.prototype.fromJSON = function (data) {
512 512 Cell.prototype.fromJSON.apply(this, arguments);
513 513 if (data.cell_type === 'code') {
514 514 if (data.source !== undefined) {
515 515 this.set_text(data.source);
516 516 // make this value the starting point, so that we can only undo
517 517 // to this state, instead of a blank cell
518 518 this.code_mirror.clearHistory();
519 519 this.auto_highlight();
520 520 }
521 521 this.set_input_prompt(data.execution_count);
522 522 this.output_area.trusted = data.metadata.trusted || false;
523 523 this.output_area.fromJSON(data.outputs);
524 524 if (data.metadata.collapsed !== undefined) {
525 525 if (data.metadata.collapsed) {
526 526 this.collapse_output();
527 527 } else {
528 528 this.expand_output();
529 529 }
530 530 }
531 531 }
532 532 };
533 533
534 534
535 535 CodeCell.prototype.toJSON = function () {
536 536 var data = Cell.prototype.toJSON.apply(this);
537 537 data.source = this.get_text();
538 538 // is finite protect against undefined and '*' value
539 539 if (isFinite(this.input_prompt_number)) {
540 540 data.execution_count = this.input_prompt_number;
541 541 } else {
542 542 data.execution_count = null;
543 543 }
544 544 var outputs = this.output_area.toJSON();
545 545 data.outputs = outputs;
546 546 data.metadata.trusted = this.output_area.trusted;
547 547 data.metadata.collapsed = this.output_area.collapsed;
548 548 return data;
549 549 };
550 550
551 551 /**
552 552 * handle cell level logic when a cell is unselected
553 553 * @method unselect
554 554 * @return is the action being taken
555 555 */
556 556 CodeCell.prototype.unselect = function () {
557 557 var cont = Cell.prototype.unselect.apply(this);
558 558 if (cont) {
559 559 // When a code cell is usnelected, make sure that the corresponding
560 560 // tooltip and completer to that cell is closed.
561 561 this.tooltip.remove_and_cancel_tooltip(true);
562 562 if (this.completer !== null) {
563 563 this.completer.close();
564 564 }
565 565 }
566 566 return cont;
567 567 };
568 568
569 569 // Backwards compatability.
570 570 IPython.CodeCell = CodeCell;
571 571
572 572 return {'CodeCell': CodeCell};
573 573 });
@@ -1,2518 +1,2522 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'base/js/namespace',
6 6 'jquery',
7 7 'base/js/utils',
8 8 'base/js/dialog',
9 9 'notebook/js/cell',
10 10 'notebook/js/textcell',
11 11 'notebook/js/codecell',
12 12 'services/sessions/session',
13 13 'notebook/js/celltoolbar',
14 14 'components/marked/lib/marked',
15 15 'codemirror/lib/codemirror',
16 16 'codemirror/addon/runmode/runmode',
17 17 'notebook/js/mathjaxutils',
18 18 'base/js/keyboard',
19 19 'notebook/js/tooltip',
20 20 'notebook/js/celltoolbarpresets/default',
21 21 'notebook/js/celltoolbarpresets/rawcell',
22 22 'notebook/js/celltoolbarpresets/slideshow',
23 23 'notebook/js/scrollmanager'
24 24 ], function (
25 25 IPython,
26 26 $,
27 27 utils,
28 28 dialog,
29 29 cellmod,
30 30 textcell,
31 31 codecell,
32 32 session,
33 33 celltoolbar,
34 34 marked,
35 35 CodeMirror,
36 36 runMode,
37 37 mathjaxutils,
38 38 keyboard,
39 39 tooltip,
40 40 default_celltoolbar,
41 41 rawcell_celltoolbar,
42 42 slideshow_celltoolbar,
43 43 scrollmanager
44 44 ) {
45 45 "use strict";
46 46
47 47 var Notebook = function (selector, options) {
48 48 /**
49 49 * Constructor
50 50 *
51 51 * A notebook contains and manages cells.
52 52 *
53 53 * Parameters:
54 54 * selector: string
55 55 * options: dictionary
56 56 * Dictionary of keyword arguments.
57 57 * events: $(Events) instance
58 58 * keyboard_manager: KeyboardManager instance
59 59 * contents: Contents instance
60 60 * save_widget: SaveWidget instance
61 61 * config: dictionary
62 62 * base_url : string
63 63 * notebook_path : string
64 64 * notebook_name : string
65 65 */
66 66 this.config = utils.mergeopt(Notebook, options.config);
67 67 this.base_url = options.base_url;
68 68 this.notebook_path = options.notebook_path;
69 69 this.notebook_name = options.notebook_name;
70 70 this.events = options.events;
71 71 this.keyboard_manager = options.keyboard_manager;
72 72 this.contents = options.contents;
73 73 this.save_widget = options.save_widget;
74 74 this.tooltip = new tooltip.Tooltip(this.events);
75 75 this.ws_url = options.ws_url;
76 76 this._session_starting = false;
77 77 this.default_cell_type = this.config.default_cell_type || 'code';
78 78
79 79 // Create default scroll manager.
80 80 this.scroll_manager = new scrollmanager.ScrollManager(this);
81 81
82 82 // TODO: This code smells (and the other `= this` line a couple lines down)
83 83 // We need a better way to deal with circular instance references.
84 84 this.keyboard_manager.notebook = this;
85 85 this.save_widget.notebook = this;
86 86
87 87 mathjaxutils.init();
88 88
89 89 if (marked) {
90 90 marked.setOptions({
91 91 gfm : true,
92 92 tables: true,
93 93 // FIXME: probably want central config for CodeMirror theme when we have js config
94 94 langPrefix: "cm-s-ipython language-",
95 95 highlight: function(code, lang, callback) {
96 96 if (!lang) {
97 97 // no language, no highlight
98 98 if (callback) {
99 99 callback(null, code);
100 100 return;
101 101 } else {
102 102 return code;
103 103 }
104 104 }
105 105 utils.requireCodeMirrorMode(lang, function () {
106 106 var el = document.createElement("div");
107 107 var mode = CodeMirror.getMode({}, lang);
108 108 if (!mode) {
109 109 console.log("No CodeMirror mode: " + lang);
110 110 callback(null, code);
111 111 return;
112 112 }
113 113 try {
114 114 CodeMirror.runMode(code, mode, el);
115 115 callback(null, el.innerHTML);
116 116 } catch (err) {
117 117 console.log("Failed to highlight " + lang + " code", err);
118 118 callback(err, code);
119 119 }
120 120 }, function (err) {
121 121 console.log("No CodeMirror mode: " + lang);
122 122 callback(err, code);
123 123 });
124 124 }
125 125 });
126 126 }
127 127
128 128 this.element = $(selector);
129 129 this.element.scroll();
130 130 this.element.data("notebook", this);
131 131 this.next_prompt_number = 1;
132 132 this.session = null;
133 133 this.kernel = null;
134 134 this.clipboard = null;
135 135 this.undelete_backup = null;
136 136 this.undelete_index = null;
137 137 this.undelete_below = false;
138 138 this.paste_enabled = false;
139 139 this.writable = false;
140 140 // It is important to start out in command mode to match the intial mode
141 141 // of the KeyboardManager.
142 142 this.mode = 'command';
143 143 this.set_dirty(false);
144 144 this.metadata = {};
145 145 this._checkpoint_after_save = false;
146 146 this.last_checkpoint = null;
147 147 this.checkpoints = [];
148 148 this.autosave_interval = 0;
149 149 this.autosave_timer = null;
150 150 // autosave *at most* every two minutes
151 151 this.minimum_autosave_interval = 120000;
152 152 this.notebook_name_blacklist_re = /[\/\\:]/;
153 153 this.nbformat = 4; // Increment this when changing the nbformat
154 154 this.nbformat_minor = this.current_nbformat_minor = 0; // Increment this when changing the nbformat
155 155 this.codemirror_mode = 'ipython';
156 156 this.create_elements();
157 157 this.bind_events();
158 158 this.kernel_selector = null;
159 159 this.dirty = null;
160 160 this.trusted = null;
161 161 this._fully_loaded = false;
162 162
163 163 // Trigger cell toolbar registration.
164 164 default_celltoolbar.register(this);
165 165 rawcell_celltoolbar.register(this);
166 166 slideshow_celltoolbar.register(this);
167 167
168 168 // prevent assign to miss-typed properties.
169 169 Object.seal(this);
170 170 };
171 171
172 172 Notebook.options_default = {
173 173 // can be any cell type, or the special values of
174 174 // 'above', 'below', or 'selected' to get the value from another cell.
175 175 Notebook: {
176 176 default_cell_type: 'code'
177 177 }
178 178 };
179 179
180 180
181 181 /**
182 182 * Create an HTML and CSS representation of the notebook.
183 183 *
184 184 * @method create_elements
185 185 */
186 186 Notebook.prototype.create_elements = function () {
187 187 var that = this;
188 188 this.element.attr('tabindex','-1');
189 189 this.container = $("<div/>").addClass("container").attr("id", "notebook-container");
190 190 // We add this end_space div to the end of the notebook div to:
191 191 // i) provide a margin between the last cell and the end of the notebook
192 192 // ii) to prevent the div from scrolling up when the last cell is being
193 193 // edited, but is too low on the page, which browsers will do automatically.
194 194 var end_space = $('<div/>').addClass('end_space');
195 195 end_space.dblclick(function (e) {
196 196 var ncells = that.ncells();
197 197 that.insert_cell_below('code',ncells-1);
198 198 });
199 199 this.element.append(this.container);
200 200 this.container.append(end_space);
201 201 };
202 202
203 203 /**
204 204 * Bind JavaScript events: key presses and custom IPython events.
205 205 *
206 206 * @method bind_events
207 207 */
208 208 Notebook.prototype.bind_events = function () {
209 209 var that = this;
210 210
211 211 this.events.on('set_next_input.Notebook', function (event, data) {
212 var index = that.find_cell_index(data.cell);
213 var new_cell = that.insert_cell_below('code',index);
214 new_cell.set_text(data.text);
212 if (data.replace) {
213 data.cell.set_text(data.text);
214 } else {
215 var index = that.find_cell_index(data.cell);
216 var new_cell = that.insert_cell_below('code',index);
217 new_cell.set_text(data.text);
218 }
215 219 that.dirty = true;
216 220 });
217 221
218 222 this.events.on('unrecognized_cell.Cell', function () {
219 223 that.warn_nbformat_minor();
220 224 });
221 225
222 226 this.events.on('unrecognized_output.OutputArea', function () {
223 227 that.warn_nbformat_minor();
224 228 });
225 229
226 230 this.events.on('set_dirty.Notebook', function (event, data) {
227 231 that.dirty = data.value;
228 232 });
229 233
230 234 this.events.on('trust_changed.Notebook', function (event, trusted) {
231 235 that.trusted = trusted;
232 236 });
233 237
234 238 this.events.on('select.Cell', function (event, data) {
235 239 var index = that.find_cell_index(data.cell);
236 240 that.select(index);
237 241 });
238 242
239 243 this.events.on('edit_mode.Cell', function (event, data) {
240 244 that.handle_edit_mode(data.cell);
241 245 });
242 246
243 247 this.events.on('command_mode.Cell', function (event, data) {
244 248 that.handle_command_mode(data.cell);
245 249 });
246 250
247 251 this.events.on('spec_changed.Kernel', function(event, data) {
248 252 that.metadata.kernelspec =
249 253 {name: data.name, display_name: data.display_name};
250 254 });
251 255
252 256 this.events.on('kernel_ready.Kernel', function(event, data) {
253 257 var kinfo = data.kernel.info_reply;
254 258 var langinfo = kinfo.language_info || {};
255 259 that.metadata.language_info = langinfo;
256 260 // Mode 'null' should be plain, unhighlighted text.
257 261 var cm_mode = langinfo.codemirror_mode || langinfo.name || 'null';
258 262 that.set_codemirror_mode(cm_mode);
259 263 });
260 264
261 265 var collapse_time = function (time) {
262 266 var app_height = $('#ipython-main-app').height(); // content height
263 267 var splitter_height = $('div#pager_splitter').outerHeight(true);
264 268 var new_height = app_height - splitter_height;
265 269 that.element.animate({height : new_height + 'px'}, time);
266 270 };
267 271
268 272 this.element.bind('collapse_pager', function (event, extrap) {
269 273 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
270 274 collapse_time(time);
271 275 });
272 276
273 277 var expand_time = function (time) {
274 278 var app_height = $('#ipython-main-app').height(); // content height
275 279 var splitter_height = $('div#pager_splitter').outerHeight(true);
276 280 var pager_height = $('div#pager').outerHeight(true);
277 281 var new_height = app_height - pager_height - splitter_height;
278 282 that.element.animate({height : new_height + 'px'}, time);
279 283 };
280 284
281 285 this.element.bind('expand_pager', function (event, extrap) {
282 286 var time = (extrap !== undefined) ? ((extrap.duration !== undefined ) ? extrap.duration : 'fast') : 'fast';
283 287 expand_time(time);
284 288 });
285 289
286 290 // Firefox 22 broke $(window).on("beforeunload")
287 291 // I'm not sure why or how.
288 292 window.onbeforeunload = function (e) {
289 293 // TODO: Make killing the kernel configurable.
290 294 var kill_kernel = false;
291 295 if (kill_kernel) {
292 296 that.session.delete();
293 297 }
294 298 // if we are autosaving, trigger an autosave on nav-away.
295 299 // still warn, because if we don't the autosave may fail.
296 300 if (that.dirty) {
297 301 if ( that.autosave_interval ) {
298 302 // schedule autosave in a timeout
299 303 // this gives you a chance to forcefully discard changes
300 304 // by reloading the page if you *really* want to.
301 305 // the timer doesn't start until you *dismiss* the dialog.
302 306 setTimeout(function () {
303 307 if (that.dirty) {
304 308 that.save_notebook();
305 309 }
306 310 }, 1000);
307 311 return "Autosave in progress, latest changes may be lost.";
308 312 } else {
309 313 return "Unsaved changes will be lost.";
310 314 }
311 315 }
312 316 // Null is the *only* return value that will make the browser not
313 317 // pop up the "don't leave" dialog.
314 318 return null;
315 319 };
316 320 };
317 321
318 322 Notebook.prototype.warn_nbformat_minor = function (event) {
319 323 /**
320 324 * trigger a warning dialog about missing functionality from newer minor versions
321 325 */
322 326 var v = 'v' + this.nbformat + '.';
323 327 var orig_vs = v + this.nbformat_minor;
324 328 var this_vs = v + this.current_nbformat_minor;
325 329 var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " +
326 330 this_vs + ". You can still work with this notebook, but cell and output types " +
327 331 "introduced in later notebook versions will not be available.";
328 332
329 333 dialog.modal({
330 334 notebook: this,
331 335 keyboard_manager: this.keyboard_manager,
332 336 title : "Newer Notebook",
333 337 body : msg,
334 338 buttons : {
335 339 OK : {
336 340 "class" : "btn-danger"
337 341 }
338 342 }
339 343 });
340 344 }
341 345
342 346 /**
343 347 * Set the dirty flag, and trigger the set_dirty.Notebook event
344 348 *
345 349 * @method set_dirty
346 350 */
347 351 Notebook.prototype.set_dirty = function (value) {
348 352 if (value === undefined) {
349 353 value = true;
350 354 }
351 355 if (this.dirty == value) {
352 356 return;
353 357 }
354 358 this.events.trigger('set_dirty.Notebook', {value: value});
355 359 };
356 360
357 361 /**
358 362 * Scroll the top of the page to a given cell.
359 363 *
360 364 * @method scroll_to_cell
361 365 * @param {Number} cell_number An index of the cell to view
362 366 * @param {Number} time Animation time in milliseconds
363 367 * @return {Number} Pixel offset from the top of the container
364 368 */
365 369 Notebook.prototype.scroll_to_cell = function (cell_number, time) {
366 370 var cells = this.get_cells();
367 371 time = time || 0;
368 372 cell_number = Math.min(cells.length-1,cell_number);
369 373 cell_number = Math.max(0 ,cell_number);
370 374 var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ;
371 375 this.element.animate({scrollTop:scroll_value}, time);
372 376 return scroll_value;
373 377 };
374 378
375 379 /**
376 380 * Scroll to the bottom of the page.
377 381 *
378 382 * @method scroll_to_bottom
379 383 */
380 384 Notebook.prototype.scroll_to_bottom = function () {
381 385 this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0);
382 386 };
383 387
384 388 /**
385 389 * Scroll to the top of the page.
386 390 *
387 391 * @method scroll_to_top
388 392 */
389 393 Notebook.prototype.scroll_to_top = function () {
390 394 this.element.animate({scrollTop:0}, 0);
391 395 };
392 396
393 397 // Edit Notebook metadata
394 398
395 399 Notebook.prototype.edit_metadata = function () {
396 400 var that = this;
397 401 dialog.edit_metadata({
398 402 md: this.metadata,
399 403 callback: function (md) {
400 404 that.metadata = md;
401 405 },
402 406 name: 'Notebook',
403 407 notebook: this,
404 408 keyboard_manager: this.keyboard_manager});
405 409 };
406 410
407 411 // Cell indexing, retrieval, etc.
408 412
409 413 /**
410 414 * Get all cell elements in the notebook.
411 415 *
412 416 * @method get_cell_elements
413 417 * @return {jQuery} A selector of all cell elements
414 418 */
415 419 Notebook.prototype.get_cell_elements = function () {
416 420 return this.container.find(".cell").not('.cell .cell');
417 421 };
418 422
419 423 /**
420 424 * Get a particular cell element.
421 425 *
422 426 * @method get_cell_element
423 427 * @param {Number} index An index of a cell to select
424 428 * @return {jQuery} A selector of the given cell.
425 429 */
426 430 Notebook.prototype.get_cell_element = function (index) {
427 431 var result = null;
428 432 var e = this.get_cell_elements().eq(index);
429 433 if (e.length !== 0) {
430 434 result = e;
431 435 }
432 436 return result;
433 437 };
434 438
435 439 /**
436 440 * Try to get a particular cell by msg_id.
437 441 *
438 442 * @method get_msg_cell
439 443 * @param {String} msg_id A message UUID
440 444 * @return {Cell} Cell or null if no cell was found.
441 445 */
442 446 Notebook.prototype.get_msg_cell = function (msg_id) {
443 447 return codecell.CodeCell.msg_cells[msg_id] || null;
444 448 };
445 449
446 450 /**
447 451 * Count the cells in this notebook.
448 452 *
449 453 * @method ncells
450 454 * @return {Number} The number of cells in this notebook
451 455 */
452 456 Notebook.prototype.ncells = function () {
453 457 return this.get_cell_elements().length;
454 458 };
455 459
456 460 /**
457 461 * Get all Cell objects in this notebook.
458 462 *
459 463 * @method get_cells
460 464 * @return {Array} This notebook's Cell objects
461 465 */
462 466 // TODO: we are often calling cells as cells()[i], which we should optimize
463 467 // to cells(i) or a new method.
464 468 Notebook.prototype.get_cells = function () {
465 469 return this.get_cell_elements().toArray().map(function (e) {
466 470 return $(e).data("cell");
467 471 });
468 472 };
469 473
470 474 /**
471 475 * Get a Cell object from this notebook.
472 476 *
473 477 * @method get_cell
474 478 * @param {Number} index An index of a cell to retrieve
475 479 * @return {Cell} Cell or null if no cell was found.
476 480 */
477 481 Notebook.prototype.get_cell = function (index) {
478 482 var result = null;
479 483 var ce = this.get_cell_element(index);
480 484 if (ce !== null) {
481 485 result = ce.data('cell');
482 486 }
483 487 return result;
484 488 };
485 489
486 490 /**
487 491 * Get the cell below a given cell.
488 492 *
489 493 * @method get_next_cell
490 494 * @param {Cell} cell The provided cell
491 495 * @return {Cell} the next cell or null if no cell was found.
492 496 */
493 497 Notebook.prototype.get_next_cell = function (cell) {
494 498 var result = null;
495 499 var index = this.find_cell_index(cell);
496 500 if (this.is_valid_cell_index(index+1)) {
497 501 result = this.get_cell(index+1);
498 502 }
499 503 return result;
500 504 };
501 505
502 506 /**
503 507 * Get the cell above a given cell.
504 508 *
505 509 * @method get_prev_cell
506 510 * @param {Cell} cell The provided cell
507 511 * @return {Cell} The previous cell or null if no cell was found.
508 512 */
509 513 Notebook.prototype.get_prev_cell = function (cell) {
510 514 var result = null;
511 515 var index = this.find_cell_index(cell);
512 516 if (index !== null && index > 0) {
513 517 result = this.get_cell(index-1);
514 518 }
515 519 return result;
516 520 };
517 521
518 522 /**
519 523 * Get the numeric index of a given cell.
520 524 *
521 525 * @method find_cell_index
522 526 * @param {Cell} cell The provided cell
523 527 * @return {Number} The cell's numeric index or null if no cell was found.
524 528 */
525 529 Notebook.prototype.find_cell_index = function (cell) {
526 530 var result = null;
527 531 this.get_cell_elements().filter(function (index) {
528 532 if ($(this).data("cell") === cell) {
529 533 result = index;
530 534 }
531 535 });
532 536 return result;
533 537 };
534 538
535 539 /**
536 540 * Get a given index , or the selected index if none is provided.
537 541 *
538 542 * @method index_or_selected
539 543 * @param {Number} index A cell's index
540 544 * @return {Number} The given index, or selected index if none is provided.
541 545 */
542 546 Notebook.prototype.index_or_selected = function (index) {
543 547 var i;
544 548 if (index === undefined || index === null) {
545 549 i = this.get_selected_index();
546 550 if (i === null) {
547 551 i = 0;
548 552 }
549 553 } else {
550 554 i = index;
551 555 }
552 556 return i;
553 557 };
554 558
555 559 /**
556 560 * Get the currently selected cell.
557 561 * @method get_selected_cell
558 562 * @return {Cell} The selected cell
559 563 */
560 564 Notebook.prototype.get_selected_cell = function () {
561 565 var index = this.get_selected_index();
562 566 return this.get_cell(index);
563 567 };
564 568
565 569 /**
566 570 * Check whether a cell index is valid.
567 571 *
568 572 * @method is_valid_cell_index
569 573 * @param {Number} index A cell index
570 574 * @return True if the index is valid, false otherwise
571 575 */
572 576 Notebook.prototype.is_valid_cell_index = function (index) {
573 577 if (index !== null && index >= 0 && index < this.ncells()) {
574 578 return true;
575 579 } else {
576 580 return false;
577 581 }
578 582 };
579 583
580 584 /**
581 585 * Get the index of the currently selected cell.
582 586
583 587 * @method get_selected_index
584 588 * @return {Number} The selected cell's numeric index
585 589 */
586 590 Notebook.prototype.get_selected_index = function () {
587 591 var result = null;
588 592 this.get_cell_elements().filter(function (index) {
589 593 if ($(this).data("cell").selected === true) {
590 594 result = index;
591 595 }
592 596 });
593 597 return result;
594 598 };
595 599
596 600
597 601 // Cell selection.
598 602
599 603 /**
600 604 * Programmatically select a cell.
601 605 *
602 606 * @method select
603 607 * @param {Number} index A cell's index
604 608 * @return {Notebook} This notebook
605 609 */
606 610 Notebook.prototype.select = function (index) {
607 611 if (this.is_valid_cell_index(index)) {
608 612 var sindex = this.get_selected_index();
609 613 if (sindex !== null && index !== sindex) {
610 614 // If we are about to select a different cell, make sure we are
611 615 // first in command mode.
612 616 if (this.mode !== 'command') {
613 617 this.command_mode();
614 618 }
615 619 this.get_cell(sindex).unselect();
616 620 }
617 621 var cell = this.get_cell(index);
618 622 cell.select();
619 623 if (cell.cell_type === 'heading') {
620 624 this.events.trigger('selected_cell_type_changed.Notebook',
621 625 {'cell_type':cell.cell_type,level:cell.level}
622 626 );
623 627 } else {
624 628 this.events.trigger('selected_cell_type_changed.Notebook',
625 629 {'cell_type':cell.cell_type}
626 630 );
627 631 }
628 632 }
629 633 return this;
630 634 };
631 635
632 636 /**
633 637 * Programmatically select the next cell.
634 638 *
635 639 * @method select_next
636 640 * @return {Notebook} This notebook
637 641 */
638 642 Notebook.prototype.select_next = function () {
639 643 var index = this.get_selected_index();
640 644 this.select(index+1);
641 645 return this;
642 646 };
643 647
644 648 /**
645 649 * Programmatically select the previous cell.
646 650 *
647 651 * @method select_prev
648 652 * @return {Notebook} This notebook
649 653 */
650 654 Notebook.prototype.select_prev = function () {
651 655 var index = this.get_selected_index();
652 656 this.select(index-1);
653 657 return this;
654 658 };
655 659
656 660
657 661 // Edit/Command mode
658 662
659 663 /**
660 664 * Gets the index of the cell that is in edit mode.
661 665 *
662 666 * @method get_edit_index
663 667 *
664 668 * @return index {int}
665 669 **/
666 670 Notebook.prototype.get_edit_index = function () {
667 671 var result = null;
668 672 this.get_cell_elements().filter(function (index) {
669 673 if ($(this).data("cell").mode === 'edit') {
670 674 result = index;
671 675 }
672 676 });
673 677 return result;
674 678 };
675 679
676 680 /**
677 681 * Handle when a a cell blurs and the notebook should enter command mode.
678 682 *
679 683 * @method handle_command_mode
680 684 * @param [cell] {Cell} Cell to enter command mode on.
681 685 **/
682 686 Notebook.prototype.handle_command_mode = function (cell) {
683 687 if (this.mode !== 'command') {
684 688 cell.command_mode();
685 689 this.mode = 'command';
686 690 this.events.trigger('command_mode.Notebook');
687 691 this.keyboard_manager.command_mode();
688 692 }
689 693 };
690 694
691 695 /**
692 696 * Make the notebook enter command mode.
693 697 *
694 698 * @method command_mode
695 699 **/
696 700 Notebook.prototype.command_mode = function () {
697 701 var cell = this.get_cell(this.get_edit_index());
698 702 if (cell && this.mode !== 'command') {
699 703 // We don't call cell.command_mode, but rather call cell.focus_cell()
700 704 // which will blur and CM editor and trigger the call to
701 705 // handle_command_mode.
702 706 cell.focus_cell();
703 707 }
704 708 };
705 709
706 710 /**
707 711 * Handle when a cell fires it's edit_mode event.
708 712 *
709 713 * @method handle_edit_mode
710 714 * @param [cell] {Cell} Cell to enter edit mode on.
711 715 **/
712 716 Notebook.prototype.handle_edit_mode = function (cell) {
713 717 if (cell && this.mode !== 'edit') {
714 718 cell.edit_mode();
715 719 this.mode = 'edit';
716 720 this.events.trigger('edit_mode.Notebook');
717 721 this.keyboard_manager.edit_mode();
718 722 }
719 723 };
720 724
721 725 /**
722 726 * Make a cell enter edit mode.
723 727 *
724 728 * @method edit_mode
725 729 **/
726 730 Notebook.prototype.edit_mode = function () {
727 731 var cell = this.get_selected_cell();
728 732 if (cell && this.mode !== 'edit') {
729 733 cell.unrender();
730 734 cell.focus_editor();
731 735 }
732 736 };
733 737
734 738 /**
735 739 * Focus the currently selected cell.
736 740 *
737 741 * @method focus_cell
738 742 **/
739 743 Notebook.prototype.focus_cell = function () {
740 744 var cell = this.get_selected_cell();
741 745 if (cell === null) {return;} // No cell is selected
742 746 cell.focus_cell();
743 747 };
744 748
745 749 // Cell movement
746 750
747 751 /**
748 752 * Move given (or selected) cell up and select it.
749 753 *
750 754 * @method move_cell_up
751 755 * @param [index] {integer} cell index
752 756 * @return {Notebook} This notebook
753 757 **/
754 758 Notebook.prototype.move_cell_up = function (index) {
755 759 var i = this.index_or_selected(index);
756 760 if (this.is_valid_cell_index(i) && i > 0) {
757 761 var pivot = this.get_cell_element(i-1);
758 762 var tomove = this.get_cell_element(i);
759 763 if (pivot !== null && tomove !== null) {
760 764 tomove.detach();
761 765 pivot.before(tomove);
762 766 this.select(i-1);
763 767 var cell = this.get_selected_cell();
764 768 cell.focus_cell();
765 769 }
766 770 this.set_dirty(true);
767 771 }
768 772 return this;
769 773 };
770 774
771 775
772 776 /**
773 777 * Move given (or selected) cell down and select it
774 778 *
775 779 * @method move_cell_down
776 780 * @param [index] {integer} cell index
777 781 * @return {Notebook} This notebook
778 782 **/
779 783 Notebook.prototype.move_cell_down = function (index) {
780 784 var i = this.index_or_selected(index);
781 785 if (this.is_valid_cell_index(i) && this.is_valid_cell_index(i+1)) {
782 786 var pivot = this.get_cell_element(i+1);
783 787 var tomove = this.get_cell_element(i);
784 788 if (pivot !== null && tomove !== null) {
785 789 tomove.detach();
786 790 pivot.after(tomove);
787 791 this.select(i+1);
788 792 var cell = this.get_selected_cell();
789 793 cell.focus_cell();
790 794 }
791 795 }
792 796 this.set_dirty();
793 797 return this;
794 798 };
795 799
796 800
797 801 // Insertion, deletion.
798 802
799 803 /**
800 804 * Delete a cell from the notebook.
801 805 *
802 806 * @method delete_cell
803 807 * @param [index] A cell's numeric index
804 808 * @return {Notebook} This notebook
805 809 */
806 810 Notebook.prototype.delete_cell = function (index) {
807 811 var i = this.index_or_selected(index);
808 812 var cell = this.get_cell(i);
809 813 if (!cell.is_deletable()) {
810 814 return this;
811 815 }
812 816
813 817 this.undelete_backup = cell.toJSON();
814 818 $('#undelete_cell').removeClass('disabled');
815 819 if (this.is_valid_cell_index(i)) {
816 820 var old_ncells = this.ncells();
817 821 var ce = this.get_cell_element(i);
818 822 ce.remove();
819 823 if (i === 0) {
820 824 // Always make sure we have at least one cell.
821 825 if (old_ncells === 1) {
822 826 this.insert_cell_below('code');
823 827 }
824 828 this.select(0);
825 829 this.undelete_index = 0;
826 830 this.undelete_below = false;
827 831 } else if (i === old_ncells-1 && i !== 0) {
828 832 this.select(i-1);
829 833 this.undelete_index = i - 1;
830 834 this.undelete_below = true;
831 835 } else {
832 836 this.select(i);
833 837 this.undelete_index = i;
834 838 this.undelete_below = false;
835 839 }
836 840 this.events.trigger('delete.Cell', {'cell': cell, 'index': i});
837 841 this.set_dirty(true);
838 842 }
839 843 return this;
840 844 };
841 845
842 846 /**
843 847 * Restore the most recently deleted cell.
844 848 *
845 849 * @method undelete
846 850 */
847 851 Notebook.prototype.undelete_cell = function() {
848 852 if (this.undelete_backup !== null && this.undelete_index !== null) {
849 853 var current_index = this.get_selected_index();
850 854 if (this.undelete_index < current_index) {
851 855 current_index = current_index + 1;
852 856 }
853 857 if (this.undelete_index >= this.ncells()) {
854 858 this.select(this.ncells() - 1);
855 859 }
856 860 else {
857 861 this.select(this.undelete_index);
858 862 }
859 863 var cell_data = this.undelete_backup;
860 864 var new_cell = null;
861 865 if (this.undelete_below) {
862 866 new_cell = this.insert_cell_below(cell_data.cell_type);
863 867 } else {
864 868 new_cell = this.insert_cell_above(cell_data.cell_type);
865 869 }
866 870 new_cell.fromJSON(cell_data);
867 871 if (this.undelete_below) {
868 872 this.select(current_index+1);
869 873 } else {
870 874 this.select(current_index);
871 875 }
872 876 this.undelete_backup = null;
873 877 this.undelete_index = null;
874 878 }
875 879 $('#undelete_cell').addClass('disabled');
876 880 };
877 881
878 882 /**
879 883 * Insert a cell so that after insertion the cell is at given index.
880 884 *
881 885 * If cell type is not provided, it will default to the type of the
882 886 * currently active cell.
883 887 *
884 888 * Similar to insert_above, but index parameter is mandatory
885 889 *
886 890 * Index will be brought back into the accessible range [0,n]
887 891 *
888 892 * @method insert_cell_at_index
889 893 * @param [type] {string} in ['code','markdown', 'raw'], defaults to 'code'
890 894 * @param [index] {int} a valid index where to insert cell
891 895 *
892 896 * @return cell {cell|null} created cell or null
893 897 **/
894 898 Notebook.prototype.insert_cell_at_index = function(type, index){
895 899
896 900 var ncells = this.ncells();
897 901 index = Math.min(index, ncells);
898 902 index = Math.max(index, 0);
899 903 var cell = null;
900 904 type = type || this.default_cell_type;
901 905 if (type === 'above') {
902 906 if (index > 0) {
903 907 type = this.get_cell(index-1).cell_type;
904 908 } else {
905 909 type = 'code';
906 910 }
907 911 } else if (type === 'below') {
908 912 if (index < ncells) {
909 913 type = this.get_cell(index).cell_type;
910 914 } else {
911 915 type = 'code';
912 916 }
913 917 } else if (type === 'selected') {
914 918 type = this.get_selected_cell().cell_type;
915 919 }
916 920
917 921 if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) {
918 922 var cell_options = {
919 923 events: this.events,
920 924 config: this.config,
921 925 keyboard_manager: this.keyboard_manager,
922 926 notebook: this,
923 927 tooltip: this.tooltip
924 928 };
925 929 switch(type) {
926 930 case 'code':
927 931 cell = new codecell.CodeCell(this.kernel, cell_options);
928 932 cell.set_input_prompt();
929 933 break;
930 934 case 'markdown':
931 935 cell = new textcell.MarkdownCell(cell_options);
932 936 break;
933 937 case 'raw':
934 938 cell = new textcell.RawCell(cell_options);
935 939 break;
936 940 default:
937 941 console.log("Unrecognized cell type: ", type, cellmod);
938 942 cell = new cellmod.UnrecognizedCell(cell_options);
939 943 }
940 944
941 945 if(this._insert_element_at_index(cell.element,index)) {
942 946 cell.render();
943 947 this.events.trigger('create.Cell', {'cell': cell, 'index': index});
944 948 cell.refresh();
945 949 // We used to select the cell after we refresh it, but there
946 950 // are now cases were this method is called where select is
947 951 // not appropriate. The selection logic should be handled by the
948 952 // caller of the the top level insert_cell methods.
949 953 this.set_dirty(true);
950 954 }
951 955 }
952 956 return cell;
953 957
954 958 };
955 959
956 960 /**
957 961 * Insert an element at given cell index.
958 962 *
959 963 * @method _insert_element_at_index
960 964 * @param element {dom_element} a cell element
961 965 * @param [index] {int} a valid index where to inser cell
962 966 * @private
963 967 *
964 968 * return true if everything whent fine.
965 969 **/
966 970 Notebook.prototype._insert_element_at_index = function(element, index){
967 971 if (element === undefined){
968 972 return false;
969 973 }
970 974
971 975 var ncells = this.ncells();
972 976
973 977 if (ncells === 0) {
974 978 // special case append if empty
975 979 this.element.find('div.end_space').before(element);
976 980 } else if ( ncells === index ) {
977 981 // special case append it the end, but not empty
978 982 this.get_cell_element(index-1).after(element);
979 983 } else if (this.is_valid_cell_index(index)) {
980 984 // otherwise always somewhere to append to
981 985 this.get_cell_element(index).before(element);
982 986 } else {
983 987 return false;
984 988 }
985 989
986 990 if (this.undelete_index !== null && index <= this.undelete_index) {
987 991 this.undelete_index = this.undelete_index + 1;
988 992 this.set_dirty(true);
989 993 }
990 994 return true;
991 995 };
992 996
993 997 /**
994 998 * Insert a cell of given type above given index, or at top
995 999 * of notebook if index smaller than 0.
996 1000 *
997 1001 * default index value is the one of currently selected cell
998 1002 *
999 1003 * @method insert_cell_above
1000 1004 * @param [type] {string} cell type
1001 1005 * @param [index] {integer}
1002 1006 *
1003 1007 * @return handle to created cell or null
1004 1008 **/
1005 1009 Notebook.prototype.insert_cell_above = function (type, index) {
1006 1010 index = this.index_or_selected(index);
1007 1011 return this.insert_cell_at_index(type, index);
1008 1012 };
1009 1013
1010 1014 /**
1011 1015 * Insert a cell of given type below given index, or at bottom
1012 1016 * of notebook if index greater than number of cells
1013 1017 *
1014 1018 * default index value is the one of currently selected cell
1015 1019 *
1016 1020 * @method insert_cell_below
1017 1021 * @param [type] {string} cell type
1018 1022 * @param [index] {integer}
1019 1023 *
1020 1024 * @return handle to created cell or null
1021 1025 *
1022 1026 **/
1023 1027 Notebook.prototype.insert_cell_below = function (type, index) {
1024 1028 index = this.index_or_selected(index);
1025 1029 return this.insert_cell_at_index(type, index+1);
1026 1030 };
1027 1031
1028 1032
1029 1033 /**
1030 1034 * Insert cell at end of notebook
1031 1035 *
1032 1036 * @method insert_cell_at_bottom
1033 1037 * @param {String} type cell type
1034 1038 *
1035 1039 * @return the added cell; or null
1036 1040 **/
1037 1041 Notebook.prototype.insert_cell_at_bottom = function (type){
1038 1042 var len = this.ncells();
1039 1043 return this.insert_cell_below(type,len-1);
1040 1044 };
1041 1045
1042 1046 /**
1043 1047 * Turn a cell into a code cell.
1044 1048 *
1045 1049 * @method to_code
1046 1050 * @param {Number} [index] A cell's index
1047 1051 */
1048 1052 Notebook.prototype.to_code = function (index) {
1049 1053 var i = this.index_or_selected(index);
1050 1054 if (this.is_valid_cell_index(i)) {
1051 1055 var source_cell = this.get_cell(i);
1052 1056 if (!(source_cell instanceof codecell.CodeCell)) {
1053 1057 var target_cell = this.insert_cell_below('code',i);
1054 1058 var text = source_cell.get_text();
1055 1059 if (text === source_cell.placeholder) {
1056 1060 text = '';
1057 1061 }
1058 1062 //metadata
1059 1063 target_cell.metadata = source_cell.metadata;
1060 1064
1061 1065 target_cell.set_text(text);
1062 1066 // make this value the starting point, so that we can only undo
1063 1067 // to this state, instead of a blank cell
1064 1068 target_cell.code_mirror.clearHistory();
1065 1069 source_cell.element.remove();
1066 1070 this.select(i);
1067 1071 var cursor = source_cell.code_mirror.getCursor();
1068 1072 target_cell.code_mirror.setCursor(cursor);
1069 1073 this.set_dirty(true);
1070 1074 }
1071 1075 }
1072 1076 };
1073 1077
1074 1078 /**
1075 1079 * Turn a cell into a Markdown cell.
1076 1080 *
1077 1081 * @method to_markdown
1078 1082 * @param {Number} [index] A cell's index
1079 1083 */
1080 1084 Notebook.prototype.to_markdown = function (index) {
1081 1085 var i = this.index_or_selected(index);
1082 1086 if (this.is_valid_cell_index(i)) {
1083 1087 var source_cell = this.get_cell(i);
1084 1088
1085 1089 if (!(source_cell instanceof textcell.MarkdownCell)) {
1086 1090 var target_cell = this.insert_cell_below('markdown',i);
1087 1091 var text = source_cell.get_text();
1088 1092
1089 1093 if (text === source_cell.placeholder) {
1090 1094 text = '';
1091 1095 }
1092 1096 // metadata
1093 1097 target_cell.metadata = source_cell.metadata;
1094 1098 // We must show the editor before setting its contents
1095 1099 target_cell.unrender();
1096 1100 target_cell.set_text(text);
1097 1101 // make this value the starting point, so that we can only undo
1098 1102 // to this state, instead of a blank cell
1099 1103 target_cell.code_mirror.clearHistory();
1100 1104 source_cell.element.remove();
1101 1105 this.select(i);
1102 1106 if ((source_cell instanceof textcell.TextCell) && source_cell.rendered) {
1103 1107 target_cell.render();
1104 1108 }
1105 1109 var cursor = source_cell.code_mirror.getCursor();
1106 1110 target_cell.code_mirror.setCursor(cursor);
1107 1111 this.set_dirty(true);
1108 1112 }
1109 1113 }
1110 1114 };
1111 1115
1112 1116 /**
1113 1117 * Turn a cell into a raw text cell.
1114 1118 *
1115 1119 * @method to_raw
1116 1120 * @param {Number} [index] A cell's index
1117 1121 */
1118 1122 Notebook.prototype.to_raw = function (index) {
1119 1123 var i = this.index_or_selected(index);
1120 1124 if (this.is_valid_cell_index(i)) {
1121 1125 var target_cell = null;
1122 1126 var source_cell = this.get_cell(i);
1123 1127
1124 1128 if (!(source_cell instanceof textcell.RawCell)) {
1125 1129 target_cell = this.insert_cell_below('raw',i);
1126 1130 var text = source_cell.get_text();
1127 1131 if (text === source_cell.placeholder) {
1128 1132 text = '';
1129 1133 }
1130 1134 //metadata
1131 1135 target_cell.metadata = source_cell.metadata;
1132 1136 // We must show the editor before setting its contents
1133 1137 target_cell.unrender();
1134 1138 target_cell.set_text(text);
1135 1139 // make this value the starting point, so that we can only undo
1136 1140 // to this state, instead of a blank cell
1137 1141 target_cell.code_mirror.clearHistory();
1138 1142 source_cell.element.remove();
1139 1143 this.select(i);
1140 1144 var cursor = source_cell.code_mirror.getCursor();
1141 1145 target_cell.code_mirror.setCursor(cursor);
1142 1146 this.set_dirty(true);
1143 1147 }
1144 1148 }
1145 1149 };
1146 1150
1147 1151 Notebook.prototype._warn_heading = function () {
1148 1152 /**
1149 1153 * warn about heading cells being removed
1150 1154 */
1151 1155 dialog.modal({
1152 1156 notebook: this,
1153 1157 keyboard_manager: this.keyboard_manager,
1154 1158 title : "Use markdown headings",
1155 1159 body : $("<p/>").text(
1156 1160 'IPython no longer uses special heading cells. ' +
1157 1161 'Instead, write your headings in Markdown cells using # characters:'
1158 1162 ).append($('<pre/>').text(
1159 1163 '## This is a level 2 heading'
1160 1164 )),
1161 1165 buttons : {
1162 1166 "OK" : {}
1163 1167 }
1164 1168 });
1165 1169 };
1166 1170
1167 1171 /**
1168 1172 * Turn a cell into a markdown cell with a heading.
1169 1173 *
1170 1174 * @method to_heading
1171 1175 * @param {Number} [index] A cell's index
1172 1176 * @param {Number} [level] A heading level (e.g., 1 for h1)
1173 1177 */
1174 1178 Notebook.prototype.to_heading = function (index, level) {
1175 1179 this.to_markdown(index);
1176 1180 level = level || 1;
1177 1181 var i = this.index_or_selected(index);
1178 1182 if (this.is_valid_cell_index(i)) {
1179 1183 var cell = this.get_cell(i);
1180 1184 cell.set_heading_level(level);
1181 1185 this.set_dirty(true);
1182 1186 }
1183 1187 };
1184 1188
1185 1189
1186 1190 // Cut/Copy/Paste
1187 1191
1188 1192 /**
1189 1193 * Enable UI elements for pasting cells.
1190 1194 *
1191 1195 * @method enable_paste
1192 1196 */
1193 1197 Notebook.prototype.enable_paste = function () {
1194 1198 var that = this;
1195 1199 if (!this.paste_enabled) {
1196 1200 $('#paste_cell_replace').removeClass('disabled')
1197 1201 .on('click', function () {that.paste_cell_replace();});
1198 1202 $('#paste_cell_above').removeClass('disabled')
1199 1203 .on('click', function () {that.paste_cell_above();});
1200 1204 $('#paste_cell_below').removeClass('disabled')
1201 1205 .on('click', function () {that.paste_cell_below();});
1202 1206 this.paste_enabled = true;
1203 1207 }
1204 1208 };
1205 1209
1206 1210 /**
1207 1211 * Disable UI elements for pasting cells.
1208 1212 *
1209 1213 * @method disable_paste
1210 1214 */
1211 1215 Notebook.prototype.disable_paste = function () {
1212 1216 if (this.paste_enabled) {
1213 1217 $('#paste_cell_replace').addClass('disabled').off('click');
1214 1218 $('#paste_cell_above').addClass('disabled').off('click');
1215 1219 $('#paste_cell_below').addClass('disabled').off('click');
1216 1220 this.paste_enabled = false;
1217 1221 }
1218 1222 };
1219 1223
1220 1224 /**
1221 1225 * Cut a cell.
1222 1226 *
1223 1227 * @method cut_cell
1224 1228 */
1225 1229 Notebook.prototype.cut_cell = function () {
1226 1230 this.copy_cell();
1227 1231 this.delete_cell();
1228 1232 };
1229 1233
1230 1234 /**
1231 1235 * Copy a cell.
1232 1236 *
1233 1237 * @method copy_cell
1234 1238 */
1235 1239 Notebook.prototype.copy_cell = function () {
1236 1240 var cell = this.get_selected_cell();
1237 1241 this.clipboard = cell.toJSON();
1238 1242 // remove undeletable status from the copied cell
1239 1243 if (this.clipboard.metadata.deletable !== undefined) {
1240 1244 delete this.clipboard.metadata.deletable;
1241 1245 }
1242 1246 this.enable_paste();
1243 1247 };
1244 1248
1245 1249 /**
1246 1250 * Replace the selected cell with a cell in the clipboard.
1247 1251 *
1248 1252 * @method paste_cell_replace
1249 1253 */
1250 1254 Notebook.prototype.paste_cell_replace = function () {
1251 1255 if (this.clipboard !== null && this.paste_enabled) {
1252 1256 var cell_data = this.clipboard;
1253 1257 var new_cell = this.insert_cell_above(cell_data.cell_type);
1254 1258 new_cell.fromJSON(cell_data);
1255 1259 var old_cell = this.get_next_cell(new_cell);
1256 1260 this.delete_cell(this.find_cell_index(old_cell));
1257 1261 this.select(this.find_cell_index(new_cell));
1258 1262 }
1259 1263 };
1260 1264
1261 1265 /**
1262 1266 * Paste a cell from the clipboard above the selected cell.
1263 1267 *
1264 1268 * @method paste_cell_above
1265 1269 */
1266 1270 Notebook.prototype.paste_cell_above = function () {
1267 1271 if (this.clipboard !== null && this.paste_enabled) {
1268 1272 var cell_data = this.clipboard;
1269 1273 var new_cell = this.insert_cell_above(cell_data.cell_type);
1270 1274 new_cell.fromJSON(cell_data);
1271 1275 new_cell.focus_cell();
1272 1276 }
1273 1277 };
1274 1278
1275 1279 /**
1276 1280 * Paste a cell from the clipboard below the selected cell.
1277 1281 *
1278 1282 * @method paste_cell_below
1279 1283 */
1280 1284 Notebook.prototype.paste_cell_below = function () {
1281 1285 if (this.clipboard !== null && this.paste_enabled) {
1282 1286 var cell_data = this.clipboard;
1283 1287 var new_cell = this.insert_cell_below(cell_data.cell_type);
1284 1288 new_cell.fromJSON(cell_data);
1285 1289 new_cell.focus_cell();
1286 1290 }
1287 1291 };
1288 1292
1289 1293 // Split/merge
1290 1294
1291 1295 /**
1292 1296 * Split the selected cell into two, at the cursor.
1293 1297 *
1294 1298 * @method split_cell
1295 1299 */
1296 1300 Notebook.prototype.split_cell = function () {
1297 1301 var cell = this.get_selected_cell();
1298 1302 if (cell.is_splittable()) {
1299 1303 var texta = cell.get_pre_cursor();
1300 1304 var textb = cell.get_post_cursor();
1301 1305 cell.set_text(textb);
1302 1306 var new_cell = this.insert_cell_above(cell.cell_type);
1303 1307 // Unrender the new cell so we can call set_text.
1304 1308 new_cell.unrender();
1305 1309 new_cell.set_text(texta);
1306 1310 }
1307 1311 };
1308 1312
1309 1313 /**
1310 1314 * Combine the selected cell into the cell above it.
1311 1315 *
1312 1316 * @method merge_cell_above
1313 1317 */
1314 1318 Notebook.prototype.merge_cell_above = function () {
1315 1319 var index = this.get_selected_index();
1316 1320 var cell = this.get_cell(index);
1317 1321 var render = cell.rendered;
1318 1322 if (!cell.is_mergeable()) {
1319 1323 return;
1320 1324 }
1321 1325 if (index > 0) {
1322 1326 var upper_cell = this.get_cell(index-1);
1323 1327 if (!upper_cell.is_mergeable()) {
1324 1328 return;
1325 1329 }
1326 1330 var upper_text = upper_cell.get_text();
1327 1331 var text = cell.get_text();
1328 1332 if (cell instanceof codecell.CodeCell) {
1329 1333 cell.set_text(upper_text+'\n'+text);
1330 1334 } else {
1331 1335 cell.unrender(); // Must unrender before we set_text.
1332 1336 cell.set_text(upper_text+'\n\n'+text);
1333 1337 if (render) {
1334 1338 // The rendered state of the final cell should match
1335 1339 // that of the original selected cell;
1336 1340 cell.render();
1337 1341 }
1338 1342 }
1339 1343 this.delete_cell(index-1);
1340 1344 this.select(this.find_cell_index(cell));
1341 1345 }
1342 1346 };
1343 1347
1344 1348 /**
1345 1349 * Combine the selected cell into the cell below it.
1346 1350 *
1347 1351 * @method merge_cell_below
1348 1352 */
1349 1353 Notebook.prototype.merge_cell_below = function () {
1350 1354 var index = this.get_selected_index();
1351 1355 var cell = this.get_cell(index);
1352 1356 var render = cell.rendered;
1353 1357 if (!cell.is_mergeable()) {
1354 1358 return;
1355 1359 }
1356 1360 if (index < this.ncells()-1) {
1357 1361 var lower_cell = this.get_cell(index+1);
1358 1362 if (!lower_cell.is_mergeable()) {
1359 1363 return;
1360 1364 }
1361 1365 var lower_text = lower_cell.get_text();
1362 1366 var text = cell.get_text();
1363 1367 if (cell instanceof codecell.CodeCell) {
1364 1368 cell.set_text(text+'\n'+lower_text);
1365 1369 } else {
1366 1370 cell.unrender(); // Must unrender before we set_text.
1367 1371 cell.set_text(text+'\n\n'+lower_text);
1368 1372 if (render) {
1369 1373 // The rendered state of the final cell should match
1370 1374 // that of the original selected cell;
1371 1375 cell.render();
1372 1376 }
1373 1377 }
1374 1378 this.delete_cell(index+1);
1375 1379 this.select(this.find_cell_index(cell));
1376 1380 }
1377 1381 };
1378 1382
1379 1383
1380 1384 // Cell collapsing and output clearing
1381 1385
1382 1386 /**
1383 1387 * Hide a cell's output.
1384 1388 *
1385 1389 * @method collapse_output
1386 1390 * @param {Number} index A cell's numeric index
1387 1391 */
1388 1392 Notebook.prototype.collapse_output = function (index) {
1389 1393 var i = this.index_or_selected(index);
1390 1394 var cell = this.get_cell(i);
1391 1395 if (cell !== null && (cell instanceof codecell.CodeCell)) {
1392 1396 cell.collapse_output();
1393 1397 this.set_dirty(true);
1394 1398 }
1395 1399 };
1396 1400
1397 1401 /**
1398 1402 * Hide each code cell's output area.
1399 1403 *
1400 1404 * @method collapse_all_output
1401 1405 */
1402 1406 Notebook.prototype.collapse_all_output = function () {
1403 1407 this.get_cells().map(function (cell, i) {
1404 1408 if (cell instanceof codecell.CodeCell) {
1405 1409 cell.collapse_output();
1406 1410 }
1407 1411 });
1408 1412 // this should not be set if the `collapse` key is removed from nbformat
1409 1413 this.set_dirty(true);
1410 1414 };
1411 1415
1412 1416 /**
1413 1417 * Show a cell's output.
1414 1418 *
1415 1419 * @method expand_output
1416 1420 * @param {Number} index A cell's numeric index
1417 1421 */
1418 1422 Notebook.prototype.expand_output = function (index) {
1419 1423 var i = this.index_or_selected(index);
1420 1424 var cell = this.get_cell(i);
1421 1425 if (cell !== null && (cell instanceof codecell.CodeCell)) {
1422 1426 cell.expand_output();
1423 1427 this.set_dirty(true);
1424 1428 }
1425 1429 };
1426 1430
1427 1431 /**
1428 1432 * Expand each code cell's output area, and remove scrollbars.
1429 1433 *
1430 1434 * @method expand_all_output
1431 1435 */
1432 1436 Notebook.prototype.expand_all_output = function () {
1433 1437 this.get_cells().map(function (cell, i) {
1434 1438 if (cell instanceof codecell.CodeCell) {
1435 1439 cell.expand_output();
1436 1440 }
1437 1441 });
1438 1442 // this should not be set if the `collapse` key is removed from nbformat
1439 1443 this.set_dirty(true);
1440 1444 };
1441 1445
1442 1446 /**
1443 1447 * Clear the selected CodeCell's output area.
1444 1448 *
1445 1449 * @method clear_output
1446 1450 * @param {Number} index A cell's numeric index
1447 1451 */
1448 1452 Notebook.prototype.clear_output = function (index) {
1449 1453 var i = this.index_or_selected(index);
1450 1454 var cell = this.get_cell(i);
1451 1455 if (cell !== null && (cell instanceof codecell.CodeCell)) {
1452 1456 cell.clear_output();
1453 1457 this.set_dirty(true);
1454 1458 }
1455 1459 };
1456 1460
1457 1461 /**
1458 1462 * Clear each code cell's output area.
1459 1463 *
1460 1464 * @method clear_all_output
1461 1465 */
1462 1466 Notebook.prototype.clear_all_output = function () {
1463 1467 this.get_cells().map(function (cell, i) {
1464 1468 if (cell instanceof codecell.CodeCell) {
1465 1469 cell.clear_output();
1466 1470 }
1467 1471 });
1468 1472 this.set_dirty(true);
1469 1473 };
1470 1474
1471 1475 /**
1472 1476 * Scroll the selected CodeCell's output area.
1473 1477 *
1474 1478 * @method scroll_output
1475 1479 * @param {Number} index A cell's numeric index
1476 1480 */
1477 1481 Notebook.prototype.scroll_output = function (index) {
1478 1482 var i = this.index_or_selected(index);
1479 1483 var cell = this.get_cell(i);
1480 1484 if (cell !== null && (cell instanceof codecell.CodeCell)) {
1481 1485 cell.scroll_output();
1482 1486 this.set_dirty(true);
1483 1487 }
1484 1488 };
1485 1489
1486 1490 /**
1487 1491 * Expand each code cell's output area, and add a scrollbar for long output.
1488 1492 *
1489 1493 * @method scroll_all_output
1490 1494 */
1491 1495 Notebook.prototype.scroll_all_output = function () {
1492 1496 this.get_cells().map(function (cell, i) {
1493 1497 if (cell instanceof codecell.CodeCell) {
1494 1498 cell.scroll_output();
1495 1499 }
1496 1500 });
1497 1501 // this should not be set if the `collapse` key is removed from nbformat
1498 1502 this.set_dirty(true);
1499 1503 };
1500 1504
1501 1505 /** Toggle whether a cell's output is collapsed or expanded.
1502 1506 *
1503 1507 * @method toggle_output
1504 1508 * @param {Number} index A cell's numeric index
1505 1509 */
1506 1510 Notebook.prototype.toggle_output = function (index) {
1507 1511 var i = this.index_or_selected(index);
1508 1512 var cell = this.get_cell(i);
1509 1513 if (cell !== null && (cell instanceof codecell.CodeCell)) {
1510 1514 cell.toggle_output();
1511 1515 this.set_dirty(true);
1512 1516 }
1513 1517 };
1514 1518
1515 1519 /**
1516 1520 * Hide/show the output of all cells.
1517 1521 *
1518 1522 * @method toggle_all_output
1519 1523 */
1520 1524 Notebook.prototype.toggle_all_output = function () {
1521 1525 this.get_cells().map(function (cell, i) {
1522 1526 if (cell instanceof codecell.CodeCell) {
1523 1527 cell.toggle_output();
1524 1528 }
1525 1529 });
1526 1530 // this should not be set if the `collapse` key is removed from nbformat
1527 1531 this.set_dirty(true);
1528 1532 };
1529 1533
1530 1534 /**
1531 1535 * Toggle a scrollbar for long cell outputs.
1532 1536 *
1533 1537 * @method toggle_output_scroll
1534 1538 * @param {Number} index A cell's numeric index
1535 1539 */
1536 1540 Notebook.prototype.toggle_output_scroll = function (index) {
1537 1541 var i = this.index_or_selected(index);
1538 1542 var cell = this.get_cell(i);
1539 1543 if (cell !== null && (cell instanceof codecell.CodeCell)) {
1540 1544 cell.toggle_output_scroll();
1541 1545 this.set_dirty(true);
1542 1546 }
1543 1547 };
1544 1548
1545 1549 /**
1546 1550 * Toggle the scrolling of long output on all cells.
1547 1551 *
1548 1552 * @method toggle_all_output_scrolling
1549 1553 */
1550 1554 Notebook.prototype.toggle_all_output_scroll = function () {
1551 1555 this.get_cells().map(function (cell, i) {
1552 1556 if (cell instanceof codecell.CodeCell) {
1553 1557 cell.toggle_output_scroll();
1554 1558 }
1555 1559 });
1556 1560 // this should not be set if the `collapse` key is removed from nbformat
1557 1561 this.set_dirty(true);
1558 1562 };
1559 1563
1560 1564 // Other cell functions: line numbers, ...
1561 1565
1562 1566 /**
1563 1567 * Toggle line numbers in the selected cell's input area.
1564 1568 *
1565 1569 * @method cell_toggle_line_numbers
1566 1570 */
1567 1571 Notebook.prototype.cell_toggle_line_numbers = function() {
1568 1572 this.get_selected_cell().toggle_line_numbers();
1569 1573 };
1570 1574
1571 1575 /**
1572 1576 * Set the codemirror mode for all code cells, including the default for
1573 1577 * new code cells.
1574 1578 *
1575 1579 * @method set_codemirror_mode
1576 1580 */
1577 1581 Notebook.prototype.set_codemirror_mode = function(newmode){
1578 1582 if (newmode === this.codemirror_mode) {
1579 1583 return;
1580 1584 }
1581 1585 this.codemirror_mode = newmode;
1582 1586 codecell.CodeCell.options_default.cm_config.mode = newmode;
1583 1587 var modename = newmode.mode || newmode.name || newmode;
1584 1588
1585 1589 var that = this;
1586 1590 utils.requireCodeMirrorMode(modename, function () {
1587 1591 that.get_cells().map(function(cell, i) {
1588 1592 if (cell.cell_type === 'code'){
1589 1593 cell.code_mirror.setOption('mode', newmode);
1590 1594 // This is currently redundant, because cm_config ends up as
1591 1595 // codemirror's own .options object, but I don't want to
1592 1596 // rely on that.
1593 1597 cell.cm_config.mode = newmode;
1594 1598 }
1595 1599 });
1596 1600 });
1597 1601 };
1598 1602
1599 1603 // Session related things
1600 1604
1601 1605 /**
1602 1606 * Start a new session and set it on each code cell.
1603 1607 *
1604 1608 * @method start_session
1605 1609 */
1606 1610 Notebook.prototype.start_session = function (kernel_name) {
1607 1611 if (this._session_starting) {
1608 1612 throw new session.SessionAlreadyStarting();
1609 1613 }
1610 1614 this._session_starting = true;
1611 1615
1612 1616 var options = {
1613 1617 base_url: this.base_url,
1614 1618 ws_url: this.ws_url,
1615 1619 notebook_path: this.notebook_path,
1616 1620 notebook_name: this.notebook_name,
1617 1621 kernel_name: kernel_name,
1618 1622 notebook: this
1619 1623 };
1620 1624
1621 1625 var success = $.proxy(this._session_started, this);
1622 1626 var failure = $.proxy(this._session_start_failed, this);
1623 1627
1624 1628 if (this.session !== null) {
1625 1629 this.session.restart(options, success, failure);
1626 1630 } else {
1627 1631 this.session = new session.Session(options);
1628 1632 this.session.start(success, failure);
1629 1633 }
1630 1634 };
1631 1635
1632 1636
1633 1637 /**
1634 1638 * Once a session is started, link the code cells to the kernel and pass the
1635 1639 * comm manager to the widget manager
1636 1640 *
1637 1641 */
1638 1642 Notebook.prototype._session_started = function (){
1639 1643 this._session_starting = false;
1640 1644 this.kernel = this.session.kernel;
1641 1645 var ncells = this.ncells();
1642 1646 for (var i=0; i<ncells; i++) {
1643 1647 var cell = this.get_cell(i);
1644 1648 if (cell instanceof codecell.CodeCell) {
1645 1649 cell.set_kernel(this.session.kernel);
1646 1650 }
1647 1651 }
1648 1652 };
1649 1653 Notebook.prototype._session_start_failed = function (jqxhr, status, error){
1650 1654 this._session_starting = false;
1651 1655 utils.log_ajax_error(jqxhr, status, error);
1652 1656 };
1653 1657
1654 1658 /**
1655 1659 * Prompt the user to restart the IPython kernel.
1656 1660 *
1657 1661 * @method restart_kernel
1658 1662 */
1659 1663 Notebook.prototype.restart_kernel = function () {
1660 1664 var that = this;
1661 1665 dialog.modal({
1662 1666 notebook: this,
1663 1667 keyboard_manager: this.keyboard_manager,
1664 1668 title : "Restart kernel or continue running?",
1665 1669 body : $("<p/>").text(
1666 1670 'Do you want to restart the current kernel? You will lose all variables defined in it.'
1667 1671 ),
1668 1672 buttons : {
1669 1673 "Continue running" : {},
1670 1674 "Restart" : {
1671 1675 "class" : "btn-danger",
1672 1676 "click" : function() {
1673 1677 that.kernel.restart();
1674 1678 }
1675 1679 }
1676 1680 }
1677 1681 });
1678 1682 };
1679 1683
1680 1684 /**
1681 1685 * Execute or render cell outputs and go into command mode.
1682 1686 *
1683 1687 * @method execute_cell
1684 1688 */
1685 1689 Notebook.prototype.execute_cell = function () {
1686 1690 /**
1687 1691 * mode = shift, ctrl, alt
1688 1692 */
1689 1693 var cell = this.get_selected_cell();
1690 1694
1691 1695 cell.execute();
1692 1696 this.command_mode();
1693 1697 this.set_dirty(true);
1694 1698 };
1695 1699
1696 1700 /**
1697 1701 * Execute or render cell outputs and insert a new cell below.
1698 1702 *
1699 1703 * @method execute_cell_and_insert_below
1700 1704 */
1701 1705 Notebook.prototype.execute_cell_and_insert_below = function () {
1702 1706 var cell = this.get_selected_cell();
1703 1707 var cell_index = this.find_cell_index(cell);
1704 1708
1705 1709 cell.execute();
1706 1710
1707 1711 // If we are at the end always insert a new cell and return
1708 1712 if (cell_index === (this.ncells()-1)) {
1709 1713 this.command_mode();
1710 1714 this.insert_cell_below();
1711 1715 this.select(cell_index+1);
1712 1716 this.edit_mode();
1713 1717 this.scroll_to_bottom();
1714 1718 this.set_dirty(true);
1715 1719 return;
1716 1720 }
1717 1721
1718 1722 this.command_mode();
1719 1723 this.insert_cell_below();
1720 1724 this.select(cell_index+1);
1721 1725 this.edit_mode();
1722 1726 this.set_dirty(true);
1723 1727 };
1724 1728
1725 1729 /**
1726 1730 * Execute or render cell outputs and select the next cell.
1727 1731 *
1728 1732 * @method execute_cell_and_select_below
1729 1733 */
1730 1734 Notebook.prototype.execute_cell_and_select_below = function () {
1731 1735
1732 1736 var cell = this.get_selected_cell();
1733 1737 var cell_index = this.find_cell_index(cell);
1734 1738
1735 1739 cell.execute();
1736 1740
1737 1741 // If we are at the end always insert a new cell and return
1738 1742 if (cell_index === (this.ncells()-1)) {
1739 1743 this.command_mode();
1740 1744 this.insert_cell_below();
1741 1745 this.select(cell_index+1);
1742 1746 this.edit_mode();
1743 1747 this.scroll_to_bottom();
1744 1748 this.set_dirty(true);
1745 1749 return;
1746 1750 }
1747 1751
1748 1752 this.command_mode();
1749 1753 this.select(cell_index+1);
1750 1754 this.focus_cell();
1751 1755 this.set_dirty(true);
1752 1756 };
1753 1757
1754 1758 /**
1755 1759 * Execute all cells below the selected cell.
1756 1760 *
1757 1761 * @method execute_cells_below
1758 1762 */
1759 1763 Notebook.prototype.execute_cells_below = function () {
1760 1764 this.execute_cell_range(this.get_selected_index(), this.ncells());
1761 1765 this.scroll_to_bottom();
1762 1766 };
1763 1767
1764 1768 /**
1765 1769 * Execute all cells above the selected cell.
1766 1770 *
1767 1771 * @method execute_cells_above
1768 1772 */
1769 1773 Notebook.prototype.execute_cells_above = function () {
1770 1774 this.execute_cell_range(0, this.get_selected_index());
1771 1775 };
1772 1776
1773 1777 /**
1774 1778 * Execute all cells.
1775 1779 *
1776 1780 * @method execute_all_cells
1777 1781 */
1778 1782 Notebook.prototype.execute_all_cells = function () {
1779 1783 this.execute_cell_range(0, this.ncells());
1780 1784 this.scroll_to_bottom();
1781 1785 };
1782 1786
1783 1787 /**
1784 1788 * Execute a contiguous range of cells.
1785 1789 *
1786 1790 * @method execute_cell_range
1787 1791 * @param {Number} start Index of the first cell to execute (inclusive)
1788 1792 * @param {Number} end Index of the last cell to execute (exclusive)
1789 1793 */
1790 1794 Notebook.prototype.execute_cell_range = function (start, end) {
1791 1795 this.command_mode();
1792 1796 for (var i=start; i<end; i++) {
1793 1797 this.select(i);
1794 1798 this.execute_cell();
1795 1799 }
1796 1800 };
1797 1801
1798 1802 // Persistance and loading
1799 1803
1800 1804 /**
1801 1805 * Getter method for this notebook's name.
1802 1806 *
1803 1807 * @method get_notebook_name
1804 1808 * @return {String} This notebook's name (excluding file extension)
1805 1809 */
1806 1810 Notebook.prototype.get_notebook_name = function () {
1807 1811 var nbname = this.notebook_name.substring(0,this.notebook_name.length-6);
1808 1812 return nbname;
1809 1813 };
1810 1814
1811 1815 /**
1812 1816 * Setter method for this notebook's name.
1813 1817 *
1814 1818 * @method set_notebook_name
1815 1819 * @param {String} name A new name for this notebook
1816 1820 */
1817 1821 Notebook.prototype.set_notebook_name = function (name) {
1818 1822 var parent = utils.url_path_split(this.notebook_path)[0];
1819 1823 this.notebook_name = name;
1820 1824 this.notebook_path = utils.url_path_join(parent, name);
1821 1825 };
1822 1826
1823 1827 /**
1824 1828 * Check that a notebook's name is valid.
1825 1829 *
1826 1830 * @method test_notebook_name
1827 1831 * @param {String} nbname A name for this notebook
1828 1832 * @return {Boolean} True if the name is valid, false if invalid
1829 1833 */
1830 1834 Notebook.prototype.test_notebook_name = function (nbname) {
1831 1835 nbname = nbname || '';
1832 1836 if (nbname.length>0 && !this.notebook_name_blacklist_re.test(nbname)) {
1833 1837 return true;
1834 1838 } else {
1835 1839 return false;
1836 1840 }
1837 1841 };
1838 1842
1839 1843 /**
1840 1844 * Load a notebook from JSON (.ipynb).
1841 1845 *
1842 1846 * @method fromJSON
1843 1847 * @param {Object} data JSON representation of a notebook
1844 1848 */
1845 1849 Notebook.prototype.fromJSON = function (data) {
1846 1850
1847 1851 var content = data.content;
1848 1852 var ncells = this.ncells();
1849 1853 var i;
1850 1854 for (i=0; i<ncells; i++) {
1851 1855 // Always delete cell 0 as they get renumbered as they are deleted.
1852 1856 this.delete_cell(0);
1853 1857 }
1854 1858 // Save the metadata and name.
1855 1859 this.metadata = content.metadata;
1856 1860 this.notebook_name = data.name;
1857 1861 this.notebook_path = data.path;
1858 1862 var trusted = true;
1859 1863
1860 1864 // Trigger an event changing the kernel spec - this will set the default
1861 1865 // codemirror mode
1862 1866 if (this.metadata.kernelspec !== undefined) {
1863 1867 this.events.trigger('spec_changed.Kernel', this.metadata.kernelspec);
1864 1868 }
1865 1869
1866 1870 // Set the codemirror mode from language_info metadata
1867 1871 if (this.metadata.language_info !== undefined) {
1868 1872 var langinfo = this.metadata.language_info;
1869 1873 // Mode 'null' should be plain, unhighlighted text.
1870 1874 var cm_mode = langinfo.codemirror_mode || langinfo.name || 'null';
1871 1875 this.set_codemirror_mode(cm_mode);
1872 1876 }
1873 1877
1874 1878 var new_cells = content.cells;
1875 1879 ncells = new_cells.length;
1876 1880 var cell_data = null;
1877 1881 var new_cell = null;
1878 1882 for (i=0; i<ncells; i++) {
1879 1883 cell_data = new_cells[i];
1880 1884 new_cell = this.insert_cell_at_index(cell_data.cell_type, i);
1881 1885 new_cell.fromJSON(cell_data);
1882 1886 if (new_cell.cell_type == 'code' && !new_cell.output_area.trusted) {
1883 1887 trusted = false;
1884 1888 }
1885 1889 }
1886 1890 if (trusted !== this.trusted) {
1887 1891 this.trusted = trusted;
1888 1892 this.events.trigger("trust_changed.Notebook", trusted);
1889 1893 }
1890 1894 };
1891 1895
1892 1896 /**
1893 1897 * Dump this notebook into a JSON-friendly object.
1894 1898 *
1895 1899 * @method toJSON
1896 1900 * @return {Object} A JSON-friendly representation of this notebook.
1897 1901 */
1898 1902 Notebook.prototype.toJSON = function () {
1899 1903 /**
1900 1904 * remove the conversion indicator, which only belongs in-memory
1901 1905 */
1902 1906 delete this.metadata.orig_nbformat;
1903 1907 delete this.metadata.orig_nbformat_minor;
1904 1908
1905 1909 var cells = this.get_cells();
1906 1910 var ncells = cells.length;
1907 1911 var cell_array = new Array(ncells);
1908 1912 var trusted = true;
1909 1913 for (var i=0; i<ncells; i++) {
1910 1914 var cell = cells[i];
1911 1915 if (cell.cell_type == 'code' && !cell.output_area.trusted) {
1912 1916 trusted = false;
1913 1917 }
1914 1918 cell_array[i] = cell.toJSON();
1915 1919 }
1916 1920 var data = {
1917 1921 cells: cell_array,
1918 1922 metadata: this.metadata,
1919 1923 nbformat: this.nbformat,
1920 1924 nbformat_minor: this.nbformat_minor
1921 1925 };
1922 1926 if (trusted != this.trusted) {
1923 1927 this.trusted = trusted;
1924 1928 this.events.trigger("trust_changed.Notebook", trusted);
1925 1929 }
1926 1930 return data;
1927 1931 };
1928 1932
1929 1933 /**
1930 1934 * Start an autosave timer, for periodically saving the notebook.
1931 1935 *
1932 1936 * @method set_autosave_interval
1933 1937 * @param {Integer} interval the autosave interval in milliseconds
1934 1938 */
1935 1939 Notebook.prototype.set_autosave_interval = function (interval) {
1936 1940 var that = this;
1937 1941 // clear previous interval, so we don't get simultaneous timers
1938 1942 if (this.autosave_timer) {
1939 1943 clearInterval(this.autosave_timer);
1940 1944 }
1941 1945 if (!this.writable) {
1942 1946 // disable autosave if not writable
1943 1947 interval = 0;
1944 1948 }
1945 1949
1946 1950 this.autosave_interval = this.minimum_autosave_interval = interval;
1947 1951 if (interval) {
1948 1952 this.autosave_timer = setInterval(function() {
1949 1953 if (that.dirty) {
1950 1954 that.save_notebook();
1951 1955 }
1952 1956 }, interval);
1953 1957 this.events.trigger("autosave_enabled.Notebook", interval);
1954 1958 } else {
1955 1959 this.autosave_timer = null;
1956 1960 this.events.trigger("autosave_disabled.Notebook");
1957 1961 }
1958 1962 };
1959 1963
1960 1964 /**
1961 1965 * Save this notebook on the server. This becomes a notebook instance's
1962 1966 * .save_notebook method *after* the entire notebook has been loaded.
1963 1967 *
1964 1968 * @method save_notebook
1965 1969 */
1966 1970 Notebook.prototype.save_notebook = function () {
1967 1971 if (!this._fully_loaded) {
1968 1972 this.events.trigger('notebook_save_failed.Notebook',
1969 1973 new Error("Load failed, save is disabled")
1970 1974 );
1971 1975 return;
1972 1976 } else if (!this.writable) {
1973 1977 this.events.trigger('notebook_save_failed.Notebook',
1974 1978 new Error("Notebook is read-only")
1975 1979 );
1976 1980 return;
1977 1981 }
1978 1982
1979 1983 // Create a JSON model to be sent to the server.
1980 1984 var model = {
1981 1985 type : "notebook",
1982 1986 content : this.toJSON()
1983 1987 };
1984 1988 // time the ajax call for autosave tuning purposes.
1985 1989 var start = new Date().getTime();
1986 1990
1987 1991 var that = this;
1988 1992 return this.contents.save(this.notebook_path, model).then(
1989 1993 $.proxy(this.save_notebook_success, this, start),
1990 1994 function (error) {
1991 1995 that.events.trigger('notebook_save_failed.Notebook', error);
1992 1996 }
1993 1997 );
1994 1998 };
1995 1999
1996 2000 /**
1997 2001 * Success callback for saving a notebook.
1998 2002 *
1999 2003 * @method save_notebook_success
2000 2004 * @param {Integer} start Time when the save request start
2001 2005 * @param {Object} data JSON representation of a notebook
2002 2006 */
2003 2007 Notebook.prototype.save_notebook_success = function (start, data) {
2004 2008 this.set_dirty(false);
2005 2009 if (data.message) {
2006 2010 // save succeeded, but validation failed.
2007 2011 var body = $("<div>");
2008 2012 var title = "Notebook validation failed";
2009 2013
2010 2014 body.append($("<p>").text(
2011 2015 "The save operation succeeded," +
2012 2016 " but the notebook does not appear to be valid." +
2013 2017 " The validation error was:"
2014 2018 )).append($("<div>").addClass("validation-error").append(
2015 2019 $("<pre>").text(data.message)
2016 2020 ));
2017 2021 dialog.modal({
2018 2022 notebook: this,
2019 2023 keyboard_manager: this.keyboard_manager,
2020 2024 title: title,
2021 2025 body: body,
2022 2026 buttons : {
2023 2027 OK : {
2024 2028 "class" : "btn-primary"
2025 2029 }
2026 2030 }
2027 2031 });
2028 2032 }
2029 2033 this.events.trigger('notebook_saved.Notebook');
2030 2034 this._update_autosave_interval(start);
2031 2035 if (this._checkpoint_after_save) {
2032 2036 this.create_checkpoint();
2033 2037 this._checkpoint_after_save = false;
2034 2038 }
2035 2039 };
2036 2040
2037 2041 /**
2038 2042 * update the autosave interval based on how long the last save took
2039 2043 *
2040 2044 * @method _update_autosave_interval
2041 2045 * @param {Integer} timestamp when the save request started
2042 2046 */
2043 2047 Notebook.prototype._update_autosave_interval = function (start) {
2044 2048 var duration = (new Date().getTime() - start);
2045 2049 if (this.autosave_interval) {
2046 2050 // new save interval: higher of 10x save duration or parameter (default 30 seconds)
2047 2051 var interval = Math.max(10 * duration, this.minimum_autosave_interval);
2048 2052 // round to 10 seconds, otherwise we will be setting a new interval too often
2049 2053 interval = 10000 * Math.round(interval / 10000);
2050 2054 // set new interval, if it's changed
2051 2055 if (interval != this.autosave_interval) {
2052 2056 this.set_autosave_interval(interval);
2053 2057 }
2054 2058 }
2055 2059 };
2056 2060
2057 2061 /**
2058 2062 * Explicitly trust the output of this notebook.
2059 2063 *
2060 2064 * @method trust_notebook
2061 2065 */
2062 2066 Notebook.prototype.trust_notebook = function () {
2063 2067 var body = $("<div>").append($("<p>")
2064 2068 .text("A trusted IPython notebook may execute hidden malicious code ")
2065 2069 .append($("<strong>")
2066 2070 .append(
2067 2071 $("<em>").text("when you open it")
2068 2072 )
2069 2073 ).append(".").append(
2070 2074 " Selecting trust will immediately reload this notebook in a trusted state."
2071 2075 ).append(
2072 2076 " For more information, see the "
2073 2077 ).append($("<a>").attr("href", "http://ipython.org/ipython-doc/2/notebook/security.html")
2074 2078 .text("IPython security documentation")
2075 2079 ).append(".")
2076 2080 );
2077 2081
2078 2082 var nb = this;
2079 2083 dialog.modal({
2080 2084 notebook: this,
2081 2085 keyboard_manager: this.keyboard_manager,
2082 2086 title: "Trust this notebook?",
2083 2087 body: body,
2084 2088
2085 2089 buttons: {
2086 2090 Cancel : {},
2087 2091 Trust : {
2088 2092 class : "btn-danger",
2089 2093 click : function () {
2090 2094 var cells = nb.get_cells();
2091 2095 for (var i = 0; i < cells.length; i++) {
2092 2096 var cell = cells[i];
2093 2097 if (cell.cell_type == 'code') {
2094 2098 cell.output_area.trusted = true;
2095 2099 }
2096 2100 }
2097 2101 nb.events.on('notebook_saved.Notebook', function () {
2098 2102 window.location.reload();
2099 2103 });
2100 2104 nb.save_notebook();
2101 2105 }
2102 2106 }
2103 2107 }
2104 2108 });
2105 2109 };
2106 2110
2107 2111 Notebook.prototype.copy_notebook = function () {
2108 2112 var that = this;
2109 2113 var base_url = this.base_url;
2110 2114 var w = window.open();
2111 2115 var parent = utils.url_path_split(this.notebook_path)[0];
2112 2116 this.contents.copy(this.notebook_path, parent).then(
2113 2117 function (data) {
2114 2118 w.location = utils.url_join_encode(
2115 2119 base_url, 'notebooks', data.path
2116 2120 );
2117 2121 },
2118 2122 function(error) {
2119 2123 w.close();
2120 2124 that.events.trigger('notebook_copy_failed', error);
2121 2125 }
2122 2126 );
2123 2127 };
2124 2128
2125 2129 Notebook.prototype.rename = function (new_name) {
2126 2130 if (!new_name.match(/\.ipynb$/)) {
2127 2131 new_name = new_name + ".ipynb";
2128 2132 }
2129 2133
2130 2134 var that = this;
2131 2135 var parent = utils.url_path_split(this.notebook_path)[0];
2132 2136 var new_path = utils.url_path_join(parent, new_name);
2133 2137 return this.contents.rename(this.notebook_path, new_path).then(
2134 2138 function (json) {
2135 2139 that.notebook_name = json.name;
2136 2140 that.notebook_path = json.path;
2137 2141 that.session.rename_notebook(json.path);
2138 2142 that.events.trigger('notebook_renamed.Notebook', json);
2139 2143 }
2140 2144 );
2141 2145 };
2142 2146
2143 2147 Notebook.prototype.delete = function () {
2144 2148 this.contents.delete(this.notebook_path);
2145 2149 };
2146 2150
2147 2151 /**
2148 2152 * Request a notebook's data from the server.
2149 2153 *
2150 2154 * @method load_notebook
2151 2155 * @param {String} notebook_path A notebook to load
2152 2156 */
2153 2157 Notebook.prototype.load_notebook = function (notebook_path) {
2154 2158 this.notebook_path = notebook_path;
2155 2159 this.notebook_name = utils.url_path_split(this.notebook_path)[1];
2156 2160 this.events.trigger('notebook_loading.Notebook');
2157 2161 this.contents.get(notebook_path, {type: 'notebook'}).then(
2158 2162 $.proxy(this.load_notebook_success, this),
2159 2163 $.proxy(this.load_notebook_error, this)
2160 2164 );
2161 2165 };
2162 2166
2163 2167 /**
2164 2168 * Success callback for loading a notebook from the server.
2165 2169 *
2166 2170 * Load notebook data from the JSON response.
2167 2171 *
2168 2172 * @method load_notebook_success
2169 2173 * @param {Object} data JSON representation of a notebook
2170 2174 */
2171 2175 Notebook.prototype.load_notebook_success = function (data) {
2172 2176 var failed, msg;
2173 2177 try {
2174 2178 this.fromJSON(data);
2175 2179 } catch (e) {
2176 2180 failed = e;
2177 2181 console.log("Notebook failed to load from JSON:", e);
2178 2182 }
2179 2183 if (failed || data.message) {
2180 2184 // *either* fromJSON failed or validation failed
2181 2185 var body = $("<div>");
2182 2186 var title;
2183 2187 if (failed) {
2184 2188 title = "Notebook failed to load";
2185 2189 body.append($("<p>").text(
2186 2190 "The error was: "
2187 2191 )).append($("<div>").addClass("js-error").text(
2188 2192 failed.toString()
2189 2193 )).append($("<p>").text(
2190 2194 "See the error console for details."
2191 2195 ));
2192 2196 } else {
2193 2197 title = "Notebook validation failed";
2194 2198 }
2195 2199
2196 2200 if (data.message) {
2197 2201 if (failed) {
2198 2202 msg = "The notebook also failed validation:";
2199 2203 } else {
2200 2204 msg = "An invalid notebook may not function properly." +
2201 2205 " The validation error was:";
2202 2206 }
2203 2207 body.append($("<p>").text(
2204 2208 msg
2205 2209 )).append($("<div>").addClass("validation-error").append(
2206 2210 $("<pre>").text(data.message)
2207 2211 ));
2208 2212 }
2209 2213
2210 2214 dialog.modal({
2211 2215 notebook: this,
2212 2216 keyboard_manager: this.keyboard_manager,
2213 2217 title: title,
2214 2218 body: body,
2215 2219 buttons : {
2216 2220 OK : {
2217 2221 "class" : "btn-primary"
2218 2222 }
2219 2223 }
2220 2224 });
2221 2225 }
2222 2226 if (this.ncells() === 0) {
2223 2227 this.insert_cell_below('code');
2224 2228 this.edit_mode(0);
2225 2229 } else {
2226 2230 this.select(0);
2227 2231 this.handle_command_mode(this.get_cell(0));
2228 2232 }
2229 2233 this.set_dirty(false);
2230 2234 this.scroll_to_top();
2231 2235 this.writable = data.writable || false;
2232 2236 var nbmodel = data.content;
2233 2237 var orig_nbformat = nbmodel.metadata.orig_nbformat;
2234 2238 var orig_nbformat_minor = nbmodel.metadata.orig_nbformat_minor;
2235 2239 if (orig_nbformat !== undefined && nbmodel.nbformat !== orig_nbformat) {
2236 2240 var src;
2237 2241 if (nbmodel.nbformat > orig_nbformat) {
2238 2242 src = " an older notebook format ";
2239 2243 } else {
2240 2244 src = " a newer notebook format ";
2241 2245 }
2242 2246
2243 2247 msg = "This notebook has been converted from" + src +
2244 2248 "(v"+orig_nbformat+") to the current notebook " +
2245 2249 "format (v"+nbmodel.nbformat+"). The next time you save this notebook, the " +
2246 2250 "current notebook format will be used.";
2247 2251
2248 2252 if (nbmodel.nbformat > orig_nbformat) {
2249 2253 msg += " Older versions of IPython may not be able to read the new format.";
2250 2254 } else {
2251 2255 msg += " Some features of the original notebook may not be available.";
2252 2256 }
2253 2257 msg += " To preserve the original version, close the " +
2254 2258 "notebook without saving it.";
2255 2259 dialog.modal({
2256 2260 notebook: this,
2257 2261 keyboard_manager: this.keyboard_manager,
2258 2262 title : "Notebook converted",
2259 2263 body : msg,
2260 2264 buttons : {
2261 2265 OK : {
2262 2266 class : "btn-primary"
2263 2267 }
2264 2268 }
2265 2269 });
2266 2270 } else if (this.nbformat_minor < nbmodel.nbformat_minor) {
2267 2271 this.nbformat_minor = nbmodel.nbformat_minor;
2268 2272 }
2269 2273
2270 2274 // Create the session after the notebook is completely loaded to prevent
2271 2275 // code execution upon loading, which is a security risk.
2272 2276 if (this.session === null) {
2273 2277 var kernelspec = this.metadata.kernelspec || {};
2274 2278 var kernel_name = kernelspec.name;
2275 2279
2276 2280 this.start_session(kernel_name);
2277 2281 }
2278 2282 // load our checkpoint list
2279 2283 this.list_checkpoints();
2280 2284
2281 2285 // load toolbar state
2282 2286 if (this.metadata.celltoolbar) {
2283 2287 celltoolbar.CellToolbar.global_show();
2284 2288 celltoolbar.CellToolbar.activate_preset(this.metadata.celltoolbar);
2285 2289 } else {
2286 2290 celltoolbar.CellToolbar.global_hide();
2287 2291 }
2288 2292
2289 2293 if (!this.writable) {
2290 2294 this.set_autosave_interval(0);
2291 2295 this.events.trigger('notebook_read_only.Notebook');
2292 2296 }
2293 2297
2294 2298 // now that we're fully loaded, it is safe to restore save functionality
2295 2299 this._fully_loaded = true;
2296 2300 this.events.trigger('notebook_loaded.Notebook');
2297 2301 };
2298 2302
2299 2303 /**
2300 2304 * Failure callback for loading a notebook from the server.
2301 2305 *
2302 2306 * @method load_notebook_error
2303 2307 * @param {Error} error
2304 2308 */
2305 2309 Notebook.prototype.load_notebook_error = function (error) {
2306 2310 this.events.trigger('notebook_load_failed.Notebook', error);
2307 2311 var msg;
2308 2312 if (error.name === utils.XHR_ERROR && error.xhr.status === 500) {
2309 2313 utils.log_ajax_error(error.xhr, error.xhr_status, error.xhr_error);
2310 2314 msg = "An unknown error occurred while loading this notebook. " +
2311 2315 "This version can load notebook formats " +
2312 2316 "v" + this.nbformat + " or earlier. See the server log for details.";
2313 2317 } else {
2314 2318 msg = error.message;
2315 2319 }
2316 2320 dialog.modal({
2317 2321 notebook: this,
2318 2322 keyboard_manager: this.keyboard_manager,
2319 2323 title: "Error loading notebook",
2320 2324 body : msg,
2321 2325 buttons : {
2322 2326 "OK": {}
2323 2327 }
2324 2328 });
2325 2329 };
2326 2330
2327 2331 /********************* checkpoint-related *********************/
2328 2332
2329 2333 /**
2330 2334 * Save the notebook then immediately create a checkpoint.
2331 2335 *
2332 2336 * @method save_checkpoint
2333 2337 */
2334 2338 Notebook.prototype.save_checkpoint = function () {
2335 2339 this._checkpoint_after_save = true;
2336 2340 this.save_notebook();
2337 2341 };
2338 2342
2339 2343 /**
2340 2344 * Add a checkpoint for this notebook.
2341 2345 * for use as a callback from checkpoint creation.
2342 2346 *
2343 2347 * @method add_checkpoint
2344 2348 */
2345 2349 Notebook.prototype.add_checkpoint = function (checkpoint) {
2346 2350 var found = false;
2347 2351 for (var i = 0; i < this.checkpoints.length; i++) {
2348 2352 var existing = this.checkpoints[i];
2349 2353 if (existing.id == checkpoint.id) {
2350 2354 found = true;
2351 2355 this.checkpoints[i] = checkpoint;
2352 2356 break;
2353 2357 }
2354 2358 }
2355 2359 if (!found) {
2356 2360 this.checkpoints.push(checkpoint);
2357 2361 }
2358 2362 this.last_checkpoint = this.checkpoints[this.checkpoints.length - 1];
2359 2363 };
2360 2364
2361 2365 /**
2362 2366 * List checkpoints for this notebook.
2363 2367 *
2364 2368 * @method list_checkpoints
2365 2369 */
2366 2370 Notebook.prototype.list_checkpoints = function () {
2367 2371 var that = this;
2368 2372 this.contents.list_checkpoints(this.notebook_path).then(
2369 2373 $.proxy(this.list_checkpoints_success, this),
2370 2374 function(error) {
2371 2375 that.events.trigger('list_checkpoints_failed.Notebook', error);
2372 2376 }
2373 2377 );
2374 2378 };
2375 2379
2376 2380 /**
2377 2381 * Success callback for listing checkpoints.
2378 2382 *
2379 2383 * @method list_checkpoint_success
2380 2384 * @param {Object} data JSON representation of a checkpoint
2381 2385 */
2382 2386 Notebook.prototype.list_checkpoints_success = function (data) {
2383 2387 this.checkpoints = data;
2384 2388 if (data.length) {
2385 2389 this.last_checkpoint = data[data.length - 1];
2386 2390 } else {
2387 2391 this.last_checkpoint = null;
2388 2392 }
2389 2393 this.events.trigger('checkpoints_listed.Notebook', [data]);
2390 2394 };
2391 2395
2392 2396 /**
2393 2397 * Create a checkpoint of this notebook on the server from the most recent save.
2394 2398 *
2395 2399 * @method create_checkpoint
2396 2400 */
2397 2401 Notebook.prototype.create_checkpoint = function () {
2398 2402 var that = this;
2399 2403 this.contents.create_checkpoint(this.notebook_path).then(
2400 2404 $.proxy(this.create_checkpoint_success, this),
2401 2405 function (error) {
2402 2406 that.events.trigger('checkpoint_failed.Notebook', error);
2403 2407 }
2404 2408 );
2405 2409 };
2406 2410
2407 2411 /**
2408 2412 * Success callback for creating a checkpoint.
2409 2413 *
2410 2414 * @method create_checkpoint_success
2411 2415 * @param {Object} data JSON representation of a checkpoint
2412 2416 */
2413 2417 Notebook.prototype.create_checkpoint_success = function (data) {
2414 2418 this.add_checkpoint(data);
2415 2419 this.events.trigger('checkpoint_created.Notebook', data);
2416 2420 };
2417 2421
2418 2422 Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) {
2419 2423 var that = this;
2420 2424 checkpoint = checkpoint || this.last_checkpoint;
2421 2425 if ( ! checkpoint ) {
2422 2426 console.log("restore dialog, but no checkpoint to restore to!");
2423 2427 return;
2424 2428 }
2425 2429 var body = $('<div/>').append(
2426 2430 $('<p/>').addClass("p-space").text(
2427 2431 "Are you sure you want to revert the notebook to " +
2428 2432 "the latest checkpoint?"
2429 2433 ).append(
2430 2434 $("<strong/>").text(
2431 2435 " This cannot be undone."
2432 2436 )
2433 2437 )
2434 2438 ).append(
2435 2439 $('<p/>').addClass("p-space").text("The checkpoint was last updated at:")
2436 2440 ).append(
2437 2441 $('<p/>').addClass("p-space").text(
2438 2442 Date(checkpoint.last_modified)
2439 2443 ).css("text-align", "center")
2440 2444 );
2441 2445
2442 2446 dialog.modal({
2443 2447 notebook: this,
2444 2448 keyboard_manager: this.keyboard_manager,
2445 2449 title : "Revert notebook to checkpoint",
2446 2450 body : body,
2447 2451 buttons : {
2448 2452 Revert : {
2449 2453 class : "btn-danger",
2450 2454 click : function () {
2451 2455 that.restore_checkpoint(checkpoint.id);
2452 2456 }
2453 2457 },
2454 2458 Cancel : {}
2455 2459 }
2456 2460 });
2457 2461 };
2458 2462
2459 2463 /**
2460 2464 * Restore the notebook to a checkpoint state.
2461 2465 *
2462 2466 * @method restore_checkpoint
2463 2467 * @param {String} checkpoint ID
2464 2468 */
2465 2469 Notebook.prototype.restore_checkpoint = function (checkpoint) {
2466 2470 this.events.trigger('notebook_restoring.Notebook', checkpoint);
2467 2471 var that = this;
2468 2472 this.contents.restore_checkpoint(this.notebook_path, checkpoint).then(
2469 2473 $.proxy(this.restore_checkpoint_success, this),
2470 2474 function (error) {
2471 2475 that.events.trigger('checkpoint_restore_failed.Notebook', error);
2472 2476 }
2473 2477 );
2474 2478 };
2475 2479
2476 2480 /**
2477 2481 * Success callback for restoring a notebook to a checkpoint.
2478 2482 *
2479 2483 * @method restore_checkpoint_success
2480 2484 */
2481 2485 Notebook.prototype.restore_checkpoint_success = function () {
2482 2486 this.events.trigger('checkpoint_restored.Notebook');
2483 2487 this.load_notebook(this.notebook_path);
2484 2488 };
2485 2489
2486 2490 /**
2487 2491 * Delete a notebook checkpoint.
2488 2492 *
2489 2493 * @method delete_checkpoint
2490 2494 * @param {String} checkpoint ID
2491 2495 */
2492 2496 Notebook.prototype.delete_checkpoint = function (checkpoint) {
2493 2497 this.events.trigger('notebook_restoring.Notebook', checkpoint);
2494 2498 var that = this;
2495 2499 this.contents.delete_checkpoint(this.notebook_path, checkpoint).then(
2496 2500 $.proxy(this.delete_checkpoint_success, this),
2497 2501 function (error) {
2498 2502 that.events.trigger('checkpoint_delete_failed.Notebook', error);
2499 2503 }
2500 2504 );
2501 2505 };
2502 2506
2503 2507 /**
2504 2508 * Success callback for deleting a notebook checkpoint
2505 2509 *
2506 2510 * @method delete_checkpoint_success
2507 2511 */
2508 2512 Notebook.prototype.delete_checkpoint_success = function () {
2509 2513 this.events.trigger('checkpoint_deleted.Notebook');
2510 2514 this.load_notebook(this.notebook_path);
2511 2515 };
2512 2516
2513 2517
2514 2518 // For backwards compatability.
2515 2519 IPython.Notebook = Notebook;
2516 2520
2517 2521 return {'Notebook': Notebook};
2518 2522 });
@@ -1,487 +1,488 b''
1 1 """A ZMQ-based subclass of InteractiveShell.
2 2
3 3 This code is meant to ease the refactoring of the base InteractiveShell into
4 4 something with a cleaner architecture for 2-process use, without actually
5 5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 6 we subclass and override what we want to fix. Once this is working well, we
7 7 can go back to the base class and refactor the code for a cleaner inheritance
8 8 implementation that doesn't rely on so much monkeypatching.
9 9
10 10 But this lets us maintain a fully working IPython as we develop the new
11 11 machinery. This should thus be thought of as scaffolding.
12 12 """
13 13
14 14 # Copyright (c) IPython Development Team.
15 15 # Distributed under the terms of the Modified BSD License.
16 16
17 17 from __future__ import print_function
18 18
19 19 import os
20 20 import sys
21 21 import time
22 22
23 23 from zmq.eventloop import ioloop
24 24
25 25 from IPython.core.interactiveshell import (
26 26 InteractiveShell, InteractiveShellABC
27 27 )
28 28 from IPython.core import page
29 29 from IPython.core.autocall import ZMQExitAutocall
30 30 from IPython.core.displaypub import DisplayPublisher
31 31 from IPython.core.error import UsageError
32 32 from IPython.core.magics import MacroToEdit, CodeMagics
33 33 from IPython.core.magic import magics_class, line_magic, Magics
34 34 from IPython.core.payloadpage import install_payload_page
35 35 from IPython.core.usage import default_gui_banner
36 36 from IPython.display import display, Javascript
37 37 from IPython.kernel.inprocess.socket import SocketABC
38 38 from IPython.kernel import (
39 39 get_connection_file, get_connection_info, connect_qtconsole
40 40 )
41 41 from IPython.testing.skipdoctest import skip_doctest
42 42 from IPython.utils import openpy
43 43 from IPython.utils.jsonutil import json_clean, encode_images
44 44 from IPython.utils.process import arg_split
45 45 from IPython.utils import py3compat
46 46 from IPython.utils.py3compat import unicode_type
47 47 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes, Any
48 48 from IPython.utils.warn import error
49 49 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
50 50 from IPython.kernel.zmq.datapub import ZMQDataPublisher
51 51 from IPython.kernel.zmq.session import extract_header
52 52 from .session import Session
53 53
54 54 #-----------------------------------------------------------------------------
55 55 # Functions and classes
56 56 #-----------------------------------------------------------------------------
57 57
58 58 class ZMQDisplayPublisher(DisplayPublisher):
59 59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
60 60
61 61 session = Instance(Session)
62 62 pub_socket = Instance(SocketABC)
63 63 parent_header = Dict({})
64 64 topic = CBytes(b'display_data')
65 65
66 66 def set_parent(self, parent):
67 67 """Set the parent for outbound messages."""
68 68 self.parent_header = extract_header(parent)
69 69
70 70 def _flush_streams(self):
71 71 """flush IO Streams prior to display"""
72 72 sys.stdout.flush()
73 73 sys.stderr.flush()
74 74
75 75 def publish(self, data, metadata=None, source=None):
76 76 self._flush_streams()
77 77 if metadata is None:
78 78 metadata = {}
79 79 self._validate_data(data, metadata)
80 80 content = {}
81 81 content['data'] = encode_images(data)
82 82 content['metadata'] = metadata
83 83 self.session.send(
84 84 self.pub_socket, u'display_data', json_clean(content),
85 85 parent=self.parent_header, ident=self.topic,
86 86 )
87 87
88 88 def clear_output(self, wait=False):
89 89 content = dict(wait=wait)
90 90 self._flush_streams()
91 91 self.session.send(
92 92 self.pub_socket, u'clear_output', content,
93 93 parent=self.parent_header, ident=self.topic,
94 94 )
95 95
96 96 @magics_class
97 97 class KernelMagics(Magics):
98 98 #------------------------------------------------------------------------
99 99 # Magic overrides
100 100 #------------------------------------------------------------------------
101 101 # Once the base class stops inheriting from magic, this code needs to be
102 102 # moved into a separate machinery as well. For now, at least isolate here
103 103 # the magics which this class needs to implement differently from the base
104 104 # class, or that are unique to it.
105 105
106 106 _find_edit_target = CodeMagics._find_edit_target
107 107
108 108 @skip_doctest
109 109 @line_magic
110 110 def edit(self, parameter_s='', last_call=['','']):
111 111 """Bring up an editor and execute the resulting code.
112 112
113 113 Usage:
114 114 %edit [options] [args]
115 115
116 116 %edit runs an external text editor. You will need to set the command for
117 117 this editor via the ``TerminalInteractiveShell.editor`` option in your
118 118 configuration file before it will work.
119 119
120 120 This command allows you to conveniently edit multi-line code right in
121 121 your IPython session.
122 122
123 123 If called without arguments, %edit opens up an empty editor with a
124 124 temporary file and will execute the contents of this file when you
125 125 close it (don't forget to save it!).
126 126
127 127 Options:
128 128
129 129 -n <number>
130 130 Open the editor at a specified line number. By default, the IPython
131 131 editor hook uses the unix syntax 'editor +N filename', but you can
132 132 configure this by providing your own modified hook if your favorite
133 133 editor supports line-number specifications with a different syntax.
134 134
135 135 -p
136 136 Call the editor with the same data as the previous time it was used,
137 137 regardless of how long ago (in your current session) it was.
138 138
139 139 -r
140 140 Use 'raw' input. This option only applies to input taken from the
141 141 user's history. By default, the 'processed' history is used, so that
142 142 magics are loaded in their transformed version to valid Python. If
143 143 this option is given, the raw input as typed as the command line is
144 144 used instead. When you exit the editor, it will be executed by
145 145 IPython's own processor.
146 146
147 147 Arguments:
148 148
149 149 If arguments are given, the following possibilites exist:
150 150
151 151 - The arguments are numbers or pairs of colon-separated numbers (like
152 152 1 4:8 9). These are interpreted as lines of previous input to be
153 153 loaded into the editor. The syntax is the same of the %macro command.
154 154
155 155 - If the argument doesn't start with a number, it is evaluated as a
156 156 variable and its contents loaded into the editor. You can thus edit
157 157 any string which contains python code (including the result of
158 158 previous edits).
159 159
160 160 - If the argument is the name of an object (other than a string),
161 161 IPython will try to locate the file where it was defined and open the
162 162 editor at the point where it is defined. You can use ``%edit function``
163 163 to load an editor exactly at the point where 'function' is defined,
164 164 edit it and have the file be executed automatically.
165 165
166 166 If the object is a macro (see %macro for details), this opens up your
167 167 specified editor with a temporary file containing the macro's data.
168 168 Upon exit, the macro is reloaded with the contents of the file.
169 169
170 170 Note: opening at an exact line is only supported under Unix, and some
171 171 editors (like kedit and gedit up to Gnome 2.8) do not understand the
172 172 '+NUMBER' parameter necessary for this feature. Good editors like
173 173 (X)Emacs, vi, jed, pico and joe all do.
174 174
175 175 - If the argument is not found as a variable, IPython will look for a
176 176 file with that name (adding .py if necessary) and load it into the
177 177 editor. It will execute its contents with execfile() when you exit,
178 178 loading any code in the file into your interactive namespace.
179 179
180 180 Unlike in the terminal, this is designed to use a GUI editor, and we do
181 181 not know when it has closed. So the file you edit will not be
182 182 automatically executed or printed.
183 183
184 184 Note that %edit is also available through the alias %ed.
185 185 """
186 186
187 187 opts,args = self.parse_options(parameter_s,'prn:')
188 188
189 189 try:
190 190 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
191 191 except MacroToEdit as e:
192 192 # TODO: Implement macro editing over 2 processes.
193 193 print("Macro editing not yet implemented in 2-process model.")
194 194 return
195 195
196 196 # Make sure we send to the client an absolute path, in case the working
197 197 # directory of client and kernel don't match
198 198 filename = os.path.abspath(filename)
199 199
200 200 payload = {
201 201 'source' : 'edit_magic',
202 202 'filename' : filename,
203 203 'line_number' : lineno
204 204 }
205 205 self.shell.payload_manager.write_payload(payload)
206 206
207 207 # A few magics that are adapted to the specifics of using pexpect and a
208 208 # remote terminal
209 209
210 210 @line_magic
211 211 def clear(self, arg_s):
212 212 """Clear the terminal."""
213 213 if os.name == 'posix':
214 214 self.shell.system("clear")
215 215 else:
216 216 self.shell.system("cls")
217 217
218 218 if os.name == 'nt':
219 219 # This is the usual name in windows
220 220 cls = line_magic('cls')(clear)
221 221
222 222 # Terminal pagers won't work over pexpect, but we do have our own pager
223 223
224 224 @line_magic
225 225 def less(self, arg_s):
226 226 """Show a file through the pager.
227 227
228 228 Files ending in .py are syntax-highlighted."""
229 229 if not arg_s:
230 230 raise UsageError('Missing filename.')
231 231
232 232 cont = open(arg_s).read()
233 233 if arg_s.endswith('.py'):
234 234 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
235 235 else:
236 236 cont = open(arg_s).read()
237 237 page.page(cont)
238 238
239 239 more = line_magic('more')(less)
240 240
241 241 # Man calls a pager, so we also need to redefine it
242 242 if os.name == 'posix':
243 243 @line_magic
244 244 def man(self, arg_s):
245 245 """Find the man page for the given command and display in pager."""
246 246 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
247 247 split=False))
248 248
249 249 @line_magic
250 250 def connect_info(self, arg_s):
251 251 """Print information for connecting other clients to this kernel
252 252
253 253 It will print the contents of this session's connection file, as well as
254 254 shortcuts for local clients.
255 255
256 256 In the simplest case, when called from the most recently launched kernel,
257 257 secondary clients can be connected, simply with:
258 258
259 259 $> ipython <app> --existing
260 260
261 261 """
262 262
263 263 from IPython.core.application import BaseIPythonApplication as BaseIPApp
264 264
265 265 if BaseIPApp.initialized():
266 266 app = BaseIPApp.instance()
267 267 security_dir = app.profile_dir.security_dir
268 268 profile = app.profile
269 269 else:
270 270 profile = 'default'
271 271 security_dir = ''
272 272
273 273 try:
274 274 connection_file = get_connection_file()
275 275 info = get_connection_info(unpack=False)
276 276 except Exception as e:
277 277 error("Could not get connection info: %r" % e)
278 278 return
279 279
280 280 # add profile flag for non-default profile
281 281 profile_flag = "--profile %s" % profile if profile != 'default' else ""
282 282
283 283 # if it's in the security dir, truncate to basename
284 284 if security_dir == os.path.dirname(connection_file):
285 285 connection_file = os.path.basename(connection_file)
286 286
287 287
288 288 print (info + '\n')
289 289 print ("Paste the above JSON into a file, and connect with:\n"
290 290 " $> ipython <app> --existing <file>\n"
291 291 "or, if you are local, you can connect with just:\n"
292 292 " $> ipython <app> --existing {0} {1}\n"
293 293 "or even just:\n"
294 294 " $> ipython <app> --existing {1}\n"
295 295 "if this is the most recent IPython session you have started.".format(
296 296 connection_file, profile_flag
297 297 )
298 298 )
299 299
300 300 @line_magic
301 301 def qtconsole(self, arg_s):
302 302 """Open a qtconsole connected to this kernel.
303 303
304 304 Useful for connecting a qtconsole to running notebooks, for better
305 305 debugging.
306 306 """
307 307
308 308 # %qtconsole should imply bind_kernel for engines:
309 309 try:
310 310 from IPython.parallel import bind_kernel
311 311 except ImportError:
312 312 # technically possible, because parallel has higher pyzmq min-version
313 313 pass
314 314 else:
315 315 bind_kernel()
316 316
317 317 try:
318 318 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
319 319 except Exception as e:
320 320 error("Could not start qtconsole: %r" % e)
321 321 return
322 322
323 323 @line_magic
324 324 def autosave(self, arg_s):
325 325 """Set the autosave interval in the notebook (in seconds).
326 326
327 327 The default value is 120, or two minutes.
328 328 ``%autosave 0`` will disable autosave.
329 329
330 330 This magic only has an effect when called from the notebook interface.
331 331 It has no effect when called in a startup file.
332 332 """
333 333
334 334 try:
335 335 interval = int(arg_s)
336 336 except ValueError:
337 337 raise UsageError("%%autosave requires an integer, got %r" % arg_s)
338 338
339 339 # javascript wants milliseconds
340 340 milliseconds = 1000 * interval
341 341 display(Javascript("IPython.notebook.set_autosave_interval(%i)" % milliseconds),
342 342 include=['application/javascript']
343 343 )
344 344 if interval:
345 345 print("Autosaving every %i seconds" % interval)
346 346 else:
347 347 print("Autosave disabled")
348 348
349 349
350 350 class ZMQInteractiveShell(InteractiveShell):
351 351 """A subclass of InteractiveShell for ZMQ."""
352 352
353 353 displayhook_class = Type(ZMQShellDisplayHook)
354 354 display_pub_class = Type(ZMQDisplayPublisher)
355 355 data_pub_class = Type(ZMQDataPublisher)
356 356 kernel = Any()
357 357 parent_header = Any()
358 358
359 359 def _banner1_default(self):
360 360 return default_gui_banner
361 361
362 362 # Override the traitlet in the parent class, because there's no point using
363 363 # readline for the kernel. Can be removed when the readline code is moved
364 364 # to the terminal frontend.
365 365 colors_force = CBool(True)
366 366 readline_use = CBool(False)
367 367 # autoindent has no meaning in a zmqshell, and attempting to enable it
368 368 # will print a warning in the absence of readline.
369 369 autoindent = CBool(False)
370 370
371 371 exiter = Instance(ZMQExitAutocall)
372 372 def _exiter_default(self):
373 373 return ZMQExitAutocall(self)
374 374
375 375 def _exit_now_changed(self, name, old, new):
376 376 """stop eventloop when exit_now fires"""
377 377 if new:
378 378 loop = ioloop.IOLoop.instance()
379 379 loop.add_timeout(time.time()+0.1, loop.stop)
380 380
381 381 keepkernel_on_exit = None
382 382
383 383 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
384 384 # interactive input being read; we provide event loop support in ipkernel
385 385 @staticmethod
386 386 def enable_gui(gui):
387 387 from .eventloops import enable_gui as real_enable_gui
388 388 try:
389 389 real_enable_gui(gui)
390 390 except ValueError as e:
391 391 raise UsageError("%s" % e)
392 392
393 393 def init_environment(self):
394 394 """Configure the user's environment.
395 395
396 396 """
397 397 env = os.environ
398 398 # These two ensure 'ls' produces nice coloring on BSD-derived systems
399 399 env['TERM'] = 'xterm-color'
400 400 env['CLICOLOR'] = '1'
401 401 # Since normal pagers don't work at all (over pexpect we don't have
402 402 # single-key control of the subprocess), try to disable paging in
403 403 # subprocesses as much as possible.
404 404 env['PAGER'] = 'cat'
405 405 env['GIT_PAGER'] = 'cat'
406 406
407 407 # And install the payload version of page.
408 408 install_payload_page()
409 409
410 410 def ask_exit(self):
411 411 """Engage the exit actions."""
412 412 self.exit_now = (not self.keepkernel_on_exit)
413 413 payload = dict(
414 414 source='ask_exit',
415 415 keepkernel=self.keepkernel_on_exit,
416 416 )
417 417 self.payload_manager.write_payload(payload)
418 418
419 419 def _showtraceback(self, etype, evalue, stb):
420 420 # try to preserve ordering of tracebacks and print statements
421 421 sys.stdout.flush()
422 422 sys.stderr.flush()
423 423
424 424 exc_content = {
425 425 u'traceback' : stb,
426 426 u'ename' : unicode_type(etype.__name__),
427 427 u'evalue' : py3compat.safe_unicode(evalue),
428 428 }
429 429
430 430 dh = self.displayhook
431 431 # Send exception info over pub socket for other clients than the caller
432 432 # to pick up
433 433 topic = None
434 434 if dh.topic:
435 435 topic = dh.topic.replace(b'execute_result', b'error')
436 436
437 437 exc_msg = dh.session.send(dh.pub_socket, u'error', json_clean(exc_content), dh.parent_header, ident=topic)
438 438
439 439 # FIXME - Hack: store exception info in shell object. Right now, the
440 440 # caller is reading this info after the fact, we need to fix this logic
441 441 # to remove this hack. Even uglier, we need to store the error status
442 442 # here, because in the main loop, the logic that sets it is being
443 443 # skipped because runlines swallows the exceptions.
444 444 exc_content[u'status'] = u'error'
445 445 self._reply_content = exc_content
446 446 # /FIXME
447 447
448 448 return exc_content
449 449
450 def set_next_input(self, text):
450 def set_next_input(self, text, replace=False):
451 451 """Send the specified text to the frontend to be presented at the next
452 452 input cell."""
453 453 payload = dict(
454 454 source='set_next_input',
455 text=text
455 text=text,
456 replace=replace,
456 457 )
457 458 self.payload_manager.write_payload(payload)
458 459
459 460 def set_parent(self, parent):
460 461 """Set the parent header for associating output with its triggering input"""
461 462 self.parent_header = parent
462 463 self.displayhook.set_parent(parent)
463 464 self.display_pub.set_parent(parent)
464 465 self.data_pub.set_parent(parent)
465 466 try:
466 467 sys.stdout.set_parent(parent)
467 468 except AttributeError:
468 469 pass
469 470 try:
470 471 sys.stderr.set_parent(parent)
471 472 except AttributeError:
472 473 pass
473 474
474 475 def get_parent(self):
475 476 return self.parent_header
476 477
477 478 #-------------------------------------------------------------------------
478 479 # Things related to magics
479 480 #-------------------------------------------------------------------------
480 481
481 482 def init_magics(self):
482 483 super(ZMQInteractiveShell, self).init_magics()
483 484 self.register_magics(KernelMagics)
484 485 self.magics_manager.register_alias('ed', 'edit')
485 486
486 487
487 488 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now