##// END OF EJS Templates
%lsmagic returns a RichRepr of the magics dict...
MinRK -
Show More
@@ -1,693 +1,677 b''
1 1 # encoding: utf-8
2 2 """Magic functions for InteractiveShell.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 7 # Copyright (C) 2001 Fernando Perez <fperez@colorado.edu>
8 8 # Copyright (C) 2008 The IPython Development Team
9 9
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17 # Stdlib
18 18 import json
19 19 import os
20 20 import re
21 21 import sys
22 22 import types
23 23 from getopt import getopt, GetoptError
24 24
25 25 # Our own
26 26 from IPython.config.configurable import Configurable
27 27 from IPython.core import oinspect
28 28 from IPython.core.error import UsageError
29 29 from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2
30 30 from IPython.external.decorator import decorator
31 31 from IPython.utils.ipstruct import Struct
32 32 from IPython.utils.process import arg_split
33 33 from IPython.utils.text import dedent
34 34 from IPython.utils.traitlets import Bool, Dict, Instance, MetaHasTraits
35 35 from IPython.utils.warn import error
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Globals
39 39 #-----------------------------------------------------------------------------
40 40
41 41 # A dict we'll use for each class that has magics, used as temporary storage to
42 42 # pass information between the @line/cell_magic method decorators and the
43 43 # @magics_class class decorator, because the method decorators have no
44 44 # access to the class when they run. See for more details:
45 45 # http://stackoverflow.com/questions/2366713/can-a-python-decorator-of-an-instance-method-access-the-class
46 46
47 47 magics = dict(line={}, cell={})
48 48
49 49 magic_kinds = ('line', 'cell')
50 50 magic_spec = ('line', 'cell', 'line_cell')
51 51 magic_escapes = dict(line=ESC_MAGIC, cell=ESC_MAGIC2)
52 52
53 53 #-----------------------------------------------------------------------------
54 54 # Utility classes and functions
55 55 #-----------------------------------------------------------------------------
56 56
57 57 class Bunch: pass
58 58
59 59
60 60 def on_off(tag):
61 61 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
62 62 return ['OFF','ON'][tag]
63 63
64 64
65 65 def compress_dhist(dh):
66 66 """Compress a directory history into a new one with at most 20 entries.
67 67
68 68 Return a new list made from the first and last 10 elements of dhist after
69 69 removal of duplicates.
70 70 """
71 71 head, tail = dh[:-10], dh[-10:]
72 72
73 73 newhead = []
74 74 done = set()
75 75 for h in head:
76 76 if h in done:
77 77 continue
78 78 newhead.append(h)
79 79 done.add(h)
80 80
81 81 return newhead + tail
82 82
83 83
84 84 def needs_local_scope(func):
85 85 """Decorator to mark magic functions which need to local scope to run."""
86 86 func.needs_local_scope = True
87 87 return func
88 88
89 89 #-----------------------------------------------------------------------------
90 90 # Class and method decorators for registering magics
91 91 #-----------------------------------------------------------------------------
92 92
93 93 def magics_class(cls):
94 94 """Class decorator for all subclasses of the main Magics class.
95 95
96 96 Any class that subclasses Magics *must* also apply this decorator, to
97 97 ensure that all the methods that have been decorated as line/cell magics
98 98 get correctly registered in the class instance. This is necessary because
99 99 when method decorators run, the class does not exist yet, so they
100 100 temporarily store their information into a module global. Application of
101 101 this class decorator copies that global data to the class instance and
102 102 clears the global.
103 103
104 104 Obviously, this mechanism is not thread-safe, which means that the
105 105 *creation* of subclasses of Magic should only be done in a single-thread
106 106 context. Instantiation of the classes has no restrictions. Given that
107 107 these classes are typically created at IPython startup time and before user
108 108 application code becomes active, in practice this should not pose any
109 109 problems.
110 110 """
111 111 cls.registered = True
112 112 cls.magics = dict(line = magics['line'],
113 113 cell = magics['cell'])
114 114 magics['line'] = {}
115 115 magics['cell'] = {}
116 116 return cls
117 117
118 118
119 119 def record_magic(dct, magic_kind, magic_name, func):
120 120 """Utility function to store a function as a magic of a specific kind.
121 121
122 122 Parameters
123 123 ----------
124 124 dct : dict
125 125 A dictionary with 'line' and 'cell' subdicts.
126 126
127 127 magic_kind : str
128 128 Kind of magic to be stored.
129 129
130 130 magic_name : str
131 131 Key to store the magic as.
132 132
133 133 func : function
134 134 Callable object to store.
135 135 """
136 136 if magic_kind == 'line_cell':
137 137 dct['line'][magic_name] = dct['cell'][magic_name] = func
138 138 else:
139 139 dct[magic_kind][magic_name] = func
140 140
141 141
142 142 def validate_type(magic_kind):
143 143 """Ensure that the given magic_kind is valid.
144 144
145 145 Check that the given magic_kind is one of the accepted spec types (stored
146 146 in the global `magic_spec`), raise ValueError otherwise.
147 147 """
148 148 if magic_kind not in magic_spec:
149 149 raise ValueError('magic_kind must be one of %s, %s given' %
150 150 magic_kinds, magic_kind)
151 151
152 152
153 153 # The docstrings for the decorator below will be fairly similar for the two
154 154 # types (method and function), so we generate them here once and reuse the
155 155 # templates below.
156 156 _docstring_template = \
157 157 """Decorate the given {0} as {1} magic.
158 158
159 159 The decorator can be used with or without arguments, as follows.
160 160
161 161 i) without arguments: it will create a {1} magic named as the {0} being
162 162 decorated::
163 163
164 164 @deco
165 165 def foo(...)
166 166
167 167 will create a {1} magic named `foo`.
168 168
169 169 ii) with one string argument: which will be used as the actual name of the
170 170 resulting magic::
171 171
172 172 @deco('bar')
173 173 def foo(...)
174 174
175 175 will create a {1} magic named `bar`.
176 176 """
177 177
178 178 # These two are decorator factories. While they are conceptually very similar,
179 179 # there are enough differences in the details that it's simpler to have them
180 180 # written as completely standalone functions rather than trying to share code
181 181 # and make a single one with convoluted logic.
182 182
183 183 def _method_magic_marker(magic_kind):
184 184 """Decorator factory for methods in Magics subclasses.
185 185 """
186 186
187 187 validate_type(magic_kind)
188 188
189 189 # This is a closure to capture the magic_kind. We could also use a class,
190 190 # but it's overkill for just that one bit of state.
191 191 def magic_deco(arg):
192 192 call = lambda f, *a, **k: f(*a, **k)
193 193
194 194 if callable(arg):
195 195 # "Naked" decorator call (just @foo, no args)
196 196 func = arg
197 197 name = func.func_name
198 198 retval = decorator(call, func)
199 199 record_magic(magics, magic_kind, name, name)
200 200 elif isinstance(arg, basestring):
201 201 # Decorator called with arguments (@foo('bar'))
202 202 name = arg
203 203 def mark(func, *a, **kw):
204 204 record_magic(magics, magic_kind, name, func.func_name)
205 205 return decorator(call, func)
206 206 retval = mark
207 207 else:
208 208 raise TypeError("Decorator can only be called with "
209 209 "string or function")
210 210 return retval
211 211
212 212 # Ensure the resulting decorator has a usable docstring
213 213 magic_deco.__doc__ = _docstring_template.format('method', magic_kind)
214 214 return magic_deco
215 215
216 216
217 217 def _function_magic_marker(magic_kind):
218 218 """Decorator factory for standalone functions.
219 219 """
220 220 validate_type(magic_kind)
221 221
222 222 # This is a closure to capture the magic_kind. We could also use a class,
223 223 # but it's overkill for just that one bit of state.
224 224 def magic_deco(arg):
225 225 call = lambda f, *a, **k: f(*a, **k)
226 226
227 227 # Find get_ipython() in the caller's namespace
228 228 caller = sys._getframe(1)
229 229 for ns in ['f_locals', 'f_globals', 'f_builtins']:
230 230 get_ipython = getattr(caller, ns).get('get_ipython')
231 231 if get_ipython is not None:
232 232 break
233 233 else:
234 234 raise NameError('Decorator can only run in context where '
235 235 '`get_ipython` exists')
236 236
237 237 ip = get_ipython()
238 238
239 239 if callable(arg):
240 240 # "Naked" decorator call (just @foo, no args)
241 241 func = arg
242 242 name = func.func_name
243 243 ip.register_magic_function(func, magic_kind, name)
244 244 retval = decorator(call, func)
245 245 elif isinstance(arg, basestring):
246 246 # Decorator called with arguments (@foo('bar'))
247 247 name = arg
248 248 def mark(func, *a, **kw):
249 249 ip.register_magic_function(func, magic_kind, name)
250 250 return decorator(call, func)
251 251 retval = mark
252 252 else:
253 253 raise TypeError("Decorator can only be called with "
254 254 "string or function")
255 255 return retval
256 256
257 257 # Ensure the resulting decorator has a usable docstring
258 258 ds = _docstring_template.format('function', magic_kind)
259 259
260 260 ds += dedent("""
261 261 Note: this decorator can only be used in a context where IPython is already
262 262 active, so that the `get_ipython()` call succeeds. You can therefore use
263 263 it in your startup files loaded after IPython initializes, but *not* in the
264 264 IPython configuration file itself, which is executed before IPython is
265 265 fully up and running. Any file located in the `startup` subdirectory of
266 266 your configuration profile will be OK in this sense.
267 267 """)
268 268
269 269 magic_deco.__doc__ = ds
270 270 return magic_deco
271 271
272 272
273 273 # Create the actual decorators for public use
274 274
275 275 # These three are used to decorate methods in class definitions
276 276 line_magic = _method_magic_marker('line')
277 277 cell_magic = _method_magic_marker('cell')
278 278 line_cell_magic = _method_magic_marker('line_cell')
279 279
280 280 # These three decorate standalone functions and perform the decoration
281 281 # immediately. They can only run where get_ipython() works
282 282 register_line_magic = _function_magic_marker('line')
283 283 register_cell_magic = _function_magic_marker('cell')
284 284 register_line_cell_magic = _function_magic_marker('line_cell')
285 285
286 286 #-----------------------------------------------------------------------------
287 287 # Core Magic classes
288 288 #-----------------------------------------------------------------------------
289 289
290 290 class MagicsManager(Configurable):
291 291 """Object that handles all magic-related functionality for IPython.
292 292 """
293 293 # Non-configurable class attributes
294 294
295 295 # A two-level dict, first keyed by magic type, then by magic function, and
296 296 # holding the actual callable object as value. This is the dict used for
297 297 # magic function dispatch
298 298 magics = Dict
299 299
300 300 # A registry of the original objects that we've been given holding magics.
301 301 registry = Dict
302 302
303 303 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
304 304
305 305 auto_magic = Bool(True, config=True, help=
306 306 "Automatically call line magics without requiring explicit % prefix")
307 307
308 308 def _auto_magic_changed(self, name, value):
309 309 self.shell.automagic = value
310 310
311 311 _auto_status = [
312 312 'Automagic is OFF, % prefix IS needed for line magics.',
313 313 'Automagic is ON, % prefix IS NOT needed for line magics.']
314 314
315 315 user_magics = Instance('IPython.core.magics.UserMagics')
316 316
317 317 def __init__(self, shell=None, config=None, user_magics=None, **traits):
318 318
319 319 super(MagicsManager, self).__init__(shell=shell, config=config,
320 320 user_magics=user_magics, **traits)
321 321 self.magics = dict(line={}, cell={})
322 322 # Let's add the user_magics to the registry for uniformity, so *all*
323 323 # registered magic containers can be found there.
324 324 self.registry[user_magics.__class__.__name__] = user_magics
325 325
326 326 def auto_status(self):
327 327 """Return descriptive string with automagic status."""
328 328 return self._auto_status[self.auto_magic]
329 329
330 def lsmagic_info(self):
331 """Return the magics as a list of dicts"""
332 magic_list = []
333 for m_type in self.magics:
334 for m_name,mgc in self.magics[m_type].items():
335 try:
336 magic_list.append({'name':m_name,'type':m_type,'class':mgc.im_class.__name__})
337 except AttributeError:
338 magic_list.append({'name':m_name,'type':m_type,'class':'Other'})
339 return magic_list
340
341 def lsmagic_json(self):
342 """Wrap lsmagic_info() in a JSON object"""
343 from IPython.display import JSON
344 return JSON(json.dumps(self.lsmagic_info()))
345
346 330 def lsmagic(self):
347 331 """Return a dict of currently available magic functions.
348 332
349 333 The return dict has the keys 'line' and 'cell', corresponding to the
350 334 two types of magics we support. Each value is a list of names.
351 335 """
352 336 return self.magics
353 337
354 338 def lsmagic_docs(self, brief=False, missing=''):
355 339 """Return dict of documentation of magic functions.
356 340
357 341 The return dict has the keys 'line' and 'cell', corresponding to the
358 342 two types of magics we support. Each value is a dict keyed by magic
359 343 name whose value is the function docstring. If a docstring is
360 344 unavailable, the value of `missing` is used instead.
361 345
362 346 If brief is True, only the first line of each docstring will be returned.
363 347 """
364 348 docs = {}
365 349 for m_type in self.magics:
366 350 m_docs = {}
367 351 for m_name, m_func in self.magics[m_type].iteritems():
368 352 if m_func.__doc__:
369 353 if brief:
370 354 m_docs[m_name] = m_func.__doc__.split('\n', 1)[0]
371 355 else:
372 356 m_docs[m_name] = m_func.__doc__.rstrip()
373 357 else:
374 358 m_docs[m_name] = missing
375 359 docs[m_type] = m_docs
376 360 return docs
377 361
378 362 def register(self, *magic_objects):
379 363 """Register one or more instances of Magics.
380 364
381 365 Take one or more classes or instances of classes that subclass the main
382 366 `core.Magic` class, and register them with IPython to use the magic
383 367 functions they provide. The registration process will then ensure that
384 368 any methods that have decorated to provide line and/or cell magics will
385 369 be recognized with the `%x`/`%%x` syntax as a line/cell magic
386 370 respectively.
387 371
388 372 If classes are given, they will be instantiated with the default
389 373 constructor. If your classes need a custom constructor, you should
390 374 instanitate them first and pass the instance.
391 375
392 376 The provided arguments can be an arbitrary mix of classes and instances.
393 377
394 378 Parameters
395 379 ----------
396 380 magic_objects : one or more classes or instances
397 381 """
398 382 # Start by validating them to ensure they have all had their magic
399 383 # methods registered at the instance level
400 384 for m in magic_objects:
401 385 if not m.registered:
402 386 raise ValueError("Class of magics %r was constructed without "
403 387 "the @register_magics class decorator")
404 388 if type(m) in (type, MetaHasTraits):
405 389 # If we're given an uninstantiated class
406 390 m = m(shell=self.shell)
407 391
408 392 # Now that we have an instance, we can register it and update the
409 393 # table of callables
410 394 self.registry[m.__class__.__name__] = m
411 395 for mtype in magic_kinds:
412 396 self.magics[mtype].update(m.magics[mtype])
413 397
414 398 def register_function(self, func, magic_kind='line', magic_name=None):
415 399 """Expose a standalone function as magic function for IPython.
416 400
417 401 This will create an IPython magic (line, cell or both) from a
418 402 standalone function. The functions should have the following
419 403 signatures:
420 404
421 405 * For line magics: `def f(line)`
422 406 * For cell magics: `def f(line, cell)`
423 407 * For a function that does both: `def f(line, cell=None)`
424 408
425 409 In the latter case, the function will be called with `cell==None` when
426 410 invoked as `%f`, and with cell as a string when invoked as `%%f`.
427 411
428 412 Parameters
429 413 ----------
430 414 func : callable
431 415 Function to be registered as a magic.
432 416
433 417 magic_kind : str
434 418 Kind of magic, one of 'line', 'cell' or 'line_cell'
435 419
436 420 magic_name : optional str
437 421 If given, the name the magic will have in the IPython namespace. By
438 422 default, the name of the function itself is used.
439 423 """
440 424
441 425 # Create the new method in the user_magics and register it in the
442 426 # global table
443 427 validate_type(magic_kind)
444 428 magic_name = func.func_name if magic_name is None else magic_name
445 429 setattr(self.user_magics, magic_name, func)
446 430 record_magic(self.magics, magic_kind, magic_name, func)
447 431
448 432 def define_magic(self, name, func):
449 433 """[Deprecated] Expose own function as magic function for IPython.
450 434
451 435 Example::
452 436
453 437 def foo_impl(self, parameter_s=''):
454 438 'My very own magic!. (Use docstrings, IPython reads them).'
455 439 print 'Magic function. Passed parameter is between < >:'
456 440 print '<%s>' % parameter_s
457 441 print 'The self object is:', self
458 442
459 443 ip.define_magic('foo',foo_impl)
460 444 """
461 445 meth = types.MethodType(func, self.user_magics)
462 446 setattr(self.user_magics, name, meth)
463 447 record_magic(self.magics, 'line', name, meth)
464 448
465 449 def register_alias(self, alias_name, magic_name, magic_kind='line'):
466 450 """Register an alias to a magic function.
467 451
468 452 The alias is an instance of :class:`MagicAlias`, which holds the
469 453 name and kind of the magic it should call. Binding is done at
470 454 call time, so if the underlying magic function is changed the alias
471 455 will call the new function.
472 456
473 457 Parameters
474 458 ----------
475 459 alias_name : str
476 460 The name of the magic to be registered.
477 461
478 462 magic_name : str
479 463 The name of an existing magic.
480 464
481 465 magic_kind : str
482 466 Kind of magic, one of 'line' or 'cell'
483 467 """
484 468
485 469 # `validate_type` is too permissive, as it allows 'line_cell'
486 470 # which we do not handle.
487 471 if magic_kind not in magic_kinds:
488 472 raise ValueError('magic_kind must be one of %s, %s given' %
489 473 magic_kinds, magic_kind)
490 474
491 475 alias = MagicAlias(self.shell, magic_name, magic_kind)
492 476 setattr(self.user_magics, alias_name, alias)
493 477 record_magic(self.magics, magic_kind, alias_name, alias)
494 478
495 479 # Key base class that provides the central functionality for magics.
496 480
497 481 class Magics(object):
498 482 """Base class for implementing magic functions.
499 483
500 484 Shell functions which can be reached as %function_name. All magic
501 485 functions should accept a string, which they can parse for their own
502 486 needs. This can make some functions easier to type, eg `%cd ../`
503 487 vs. `%cd("../")`
504 488
505 489 Classes providing magic functions need to subclass this class, and they
506 490 MUST:
507 491
508 492 - Use the method decorators `@line_magic` and `@cell_magic` to decorate
509 493 individual methods as magic functions, AND
510 494
511 495 - Use the class decorator `@magics_class` to ensure that the magic
512 496 methods are properly registered at the instance level upon instance
513 497 initialization.
514 498
515 499 See :mod:`magic_functions` for examples of actual implementation classes.
516 500 """
517 501 # Dict holding all command-line options for each magic.
518 502 options_table = None
519 503 # Dict for the mapping of magic names to methods, set by class decorator
520 504 magics = None
521 505 # Flag to check that the class decorator was properly applied
522 506 registered = False
523 507 # Instance of IPython shell
524 508 shell = None
525 509
526 510 def __init__(self, shell):
527 511 if not(self.__class__.registered):
528 512 raise ValueError('Magics subclass without registration - '
529 513 'did you forget to apply @magics_class?')
530 514 self.shell = shell
531 515 self.options_table = {}
532 516 # The method decorators are run when the instance doesn't exist yet, so
533 517 # they can only record the names of the methods they are supposed to
534 518 # grab. Only now, that the instance exists, can we create the proper
535 519 # mapping to bound methods. So we read the info off the original names
536 520 # table and replace each method name by the actual bound method.
537 521 # But we mustn't clobber the *class* mapping, in case of multiple instances.
538 522 class_magics = self.magics
539 523 self.magics = {}
540 524 for mtype in magic_kinds:
541 525 tab = self.magics[mtype] = {}
542 526 cls_tab = class_magics[mtype]
543 527 for magic_name, meth_name in cls_tab.iteritems():
544 528 if isinstance(meth_name, basestring):
545 529 # it's a method name, grab it
546 530 tab[magic_name] = getattr(self, meth_name)
547 531 else:
548 532 # it's the real thing
549 533 tab[magic_name] = meth_name
550 534
551 535 def arg_err(self,func):
552 536 """Print docstring if incorrect arguments were passed"""
553 537 print 'Error in arguments:'
554 538 print oinspect.getdoc(func)
555 539
556 540 def format_latex(self, strng):
557 541 """Format a string for latex inclusion."""
558 542
559 543 # Characters that need to be escaped for latex:
560 544 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
561 545 # Magic command names as headers:
562 546 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
563 547 re.MULTILINE)
564 548 # Magic commands
565 549 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
566 550 re.MULTILINE)
567 551 # Paragraph continue
568 552 par_re = re.compile(r'\\$',re.MULTILINE)
569 553
570 554 # The "\n" symbol
571 555 newline_re = re.compile(r'\\n')
572 556
573 557 # Now build the string for output:
574 558 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
575 559 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
576 560 strng)
577 561 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
578 562 strng = par_re.sub(r'\\\\',strng)
579 563 strng = escape_re.sub(r'\\\1',strng)
580 564 strng = newline_re.sub(r'\\textbackslash{}n',strng)
581 565 return strng
582 566
583 567 def parse_options(self, arg_str, opt_str, *long_opts, **kw):
584 568 """Parse options passed to an argument string.
585 569
586 570 The interface is similar to that of getopt(), but it returns back a
587 571 Struct with the options as keys and the stripped argument string still
588 572 as a string.
589 573
590 574 arg_str is quoted as a true sys.argv vector by using shlex.split.
591 575 This allows us to easily expand variables, glob files, quote
592 576 arguments, etc.
593 577
594 578 Options:
595 579 -mode: default 'string'. If given as 'list', the argument string is
596 580 returned as a list (split on whitespace) instead of a string.
597 581
598 582 -list_all: put all option values in lists. Normally only options
599 583 appearing more than once are put in a list.
600 584
601 585 -posix (True): whether to split the input line in POSIX mode or not,
602 586 as per the conventions outlined in the shlex module from the
603 587 standard library."""
604 588
605 589 # inject default options at the beginning of the input line
606 590 caller = sys._getframe(1).f_code.co_name
607 591 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
608 592
609 593 mode = kw.get('mode','string')
610 594 if mode not in ['string','list']:
611 595 raise ValueError('incorrect mode given: %s' % mode)
612 596 # Get options
613 597 list_all = kw.get('list_all',0)
614 598 posix = kw.get('posix', os.name == 'posix')
615 599 strict = kw.get('strict', True)
616 600
617 601 # Check if we have more than one argument to warrant extra processing:
618 602 odict = {} # Dictionary with options
619 603 args = arg_str.split()
620 604 if len(args) >= 1:
621 605 # If the list of inputs only has 0 or 1 thing in it, there's no
622 606 # need to look for options
623 607 argv = arg_split(arg_str, posix, strict)
624 608 # Do regular option processing
625 609 try:
626 610 opts,args = getopt(argv, opt_str, long_opts)
627 611 except GetoptError as e:
628 612 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
629 613 " ".join(long_opts)))
630 614 for o,a in opts:
631 615 if o.startswith('--'):
632 616 o = o[2:]
633 617 else:
634 618 o = o[1:]
635 619 try:
636 620 odict[o].append(a)
637 621 except AttributeError:
638 622 odict[o] = [odict[o],a]
639 623 except KeyError:
640 624 if list_all:
641 625 odict[o] = [a]
642 626 else:
643 627 odict[o] = a
644 628
645 629 # Prepare opts,args for return
646 630 opts = Struct(odict)
647 631 if mode == 'string':
648 632 args = ' '.join(args)
649 633
650 634 return opts,args
651 635
652 636 def default_option(self, fn, optstr):
653 637 """Make an entry in the options_table for fn, with value optstr"""
654 638
655 639 if fn not in self.lsmagic():
656 640 error("%s is not a magic function" % fn)
657 641 self.options_table[fn] = optstr
658 642
659 643 class MagicAlias(object):
660 644 """An alias to another magic function.
661 645
662 646 An alias is determined by its magic name and magic kind. Lookup
663 647 is done at call time, so if the underlying magic changes the alias
664 648 will call the new function.
665 649
666 650 Use the :meth:`MagicsManager.register_alias` method or the
667 651 `%alias_magic` magic function to create and register a new alias.
668 652 """
669 653 def __init__(self, shell, magic_name, magic_kind):
670 654 self.shell = shell
671 655 self.magic_name = magic_name
672 656 self.magic_kind = magic_kind
673 657
674 658 self.pretty_target = '%s%s' % (magic_escapes[self.magic_kind], self.magic_name)
675 659 self.__doc__ = "Alias for `%s`." % self.pretty_target
676 660
677 661 self._in_call = False
678 662
679 663 def __call__(self, *args, **kwargs):
680 664 """Call the magic alias."""
681 665 fn = self.shell.find_magic(self.magic_name, self.magic_kind)
682 666 if fn is None:
683 667 raise UsageError("Magic `%s` not found." % self.pretty_target)
684 668
685 669 # Protect against infinite recursion.
686 670 if self._in_call:
687 671 raise UsageError("Infinite recursion detected; "
688 672 "magic aliases cannot call themselves.")
689 673 self._in_call = True
690 674 try:
691 675 return fn(*args, **kwargs)
692 676 finally:
693 677 self._in_call = False
@@ -1,612 +1,648 b''
1 1 """Implementation of basic magic functions.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012 The IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 # Stdlib
17 17 import io
18 import json
18 19 import sys
19 20 from pprint import pformat
20 21
21 22 # Our own packages
22 23 from IPython.core import magic_arguments
23 24 from IPython.core.error import UsageError
24 25 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
25 26 from IPython.utils.text import format_screen, dedent, indent
26 27 from IPython.core import magic_arguments, page
27 28 from IPython.testing.skipdoctest import skip_doctest
28 29 from IPython.utils.ipstruct import Struct
29 30 from IPython.utils.path import unquote_filename
30 31 from IPython.utils.warn import warn, error
31 32
32 33 #-----------------------------------------------------------------------------
33 34 # Magics class implementation
34 35 #-----------------------------------------------------------------------------
35 36
37 class MagicsDisplay(object):
38 def __init__(self, magics_manager):
39 self.magics_manager = magics_manager
40
41 def _lsmagic(self):
42 """The main implementation of the %lsmagic"""
43 mesc = magic_escapes['line']
44 cesc = magic_escapes['cell']
45 mman = self.magics_manager
46 magics = mman.lsmagic()
47 out = ['Available line magics:',
48 mesc + (' '+mesc).join(sorted(magics['line'])),
49 '',
50 'Available cell magics:',
51 cesc + (' '+cesc).join(sorted(magics['cell'])),
52 '',
53 mman.auto_status()]
54 return '\n'.join(out)
55
56 def _repr_pretty_(self, p, cycle):
57 p.text(self._lsmagic())
58
59 def __str__(self):
60 return self._lsmagic()
61
62 def _jsonable(self):
63 """turn magics dict into jsonable dict of the same structure
64
65 replaces object instances with their class names as strings
66 """
67 magic_dict = {}
68 mman = self.magics_manager
69 magics = mman.lsmagic()
70 for key, subdict in magics.items():
71 d = {}
72 magic_dict[key] = d
73 for name, obj in subdict.items():
74 try:
75 classname = obj.im_class.__name__
76 except AttributeError:
77 classname = 'Other'
78
79 d[name] = classname
80 return magic_dict
81
82 def _repr_json_(self):
83 return json.dumps(self._jsonable())
84
85
36 86 @magics_class
37 87 class BasicMagics(Magics):
38 88 """Magics that provide central IPython functionality.
39 89
40 90 These are various magics that don't fit into specific categories but that
41 91 are all part of the base 'IPython experience'."""
42 92
43 93 @magic_arguments.magic_arguments()
44 94 @magic_arguments.argument(
45 95 '-l', '--line', action='store_true',
46 96 help="""Create a line magic alias."""
47 97 )
48 98 @magic_arguments.argument(
49 99 '-c', '--cell', action='store_true',
50 100 help="""Create a cell magic alias."""
51 101 )
52 102 @magic_arguments.argument(
53 103 'name',
54 104 help="""Name of the magic to be created."""
55 105 )
56 106 @magic_arguments.argument(
57 107 'target',
58 108 help="""Name of the existing line or cell magic."""
59 109 )
60 110 @line_magic
61 111 def alias_magic(self, line=''):
62 112 """Create an alias for an existing line or cell magic.
63 113
64 114 Examples
65 115 --------
66 116 ::
67 117 In [1]: %alias_magic t timeit
68 118 Created `%t` as an alias for `%timeit`.
69 119 Created `%%t` as an alias for `%%timeit`.
70 120
71 121 In [2]: %t -n1 pass
72 122 1 loops, best of 3: 954 ns per loop
73 123
74 124 In [3]: %%t -n1
75 125 ...: pass
76 126 ...:
77 127 1 loops, best of 3: 954 ns per loop
78 128
79 129 In [4]: %alias_magic --cell whereami pwd
80 130 UsageError: Cell magic function `%%pwd` not found.
81 131 In [5]: %alias_magic --line whereami pwd
82 132 Created `%whereami` as an alias for `%pwd`.
83 133
84 134 In [6]: %whereami
85 135 Out[6]: u'/home/testuser'
86 136 """
87 137 args = magic_arguments.parse_argstring(self.alias_magic, line)
88 138 shell = self.shell
89 139 mman = self.shell.magics_manager
90 140 escs = ''.join(magic_escapes.values())
91 141
92 142 target = args.target.lstrip(escs)
93 143 name = args.name.lstrip(escs)
94 144
95 145 # Find the requested magics.
96 146 m_line = shell.find_magic(target, 'line')
97 147 m_cell = shell.find_magic(target, 'cell')
98 148 if args.line and m_line is None:
99 149 raise UsageError('Line magic function `%s%s` not found.' %
100 150 (magic_escapes['line'], target))
101 151 if args.cell and m_cell is None:
102 152 raise UsageError('Cell magic function `%s%s` not found.' %
103 153 (magic_escapes['cell'], target))
104 154
105 155 # If --line and --cell are not specified, default to the ones
106 156 # that are available.
107 157 if not args.line and not args.cell:
108 158 if not m_line and not m_cell:
109 159 raise UsageError(
110 160 'No line or cell magic with name `%s` found.' % target
111 161 )
112 162 args.line = bool(m_line)
113 163 args.cell = bool(m_cell)
114 164
115 165 if args.line:
116 166 mman.register_alias(name, target, 'line')
117 167 print('Created `%s%s` as an alias for `%s%s`.' % (
118 168 magic_escapes['line'], name,
119 169 magic_escapes['line'], target))
120 170
121 171 if args.cell:
122 172 mman.register_alias(name, target, 'cell')
123 173 print('Created `%s%s` as an alias for `%s%s`.' % (
124 174 magic_escapes['cell'], name,
125 175 magic_escapes['cell'], target))
126 176
127 def _lsmagic(self):
128 mesc = magic_escapes['line']
129 cesc = magic_escapes['cell']
130 mman = self.shell.magics_manager
131 magics = mman.lsmagic()
132 out = ['Available line magics:',
133 mesc + (' '+mesc).join(sorted(magics['line'])),
134 '',
135 'Available cell magics:',
136 cesc + (' '+cesc).join(sorted(magics['cell'])),
137 '',
138 mman.auto_status()]
139 return '\n'.join(out)
140
141 177 @line_magic
142 178 def lsmagic(self, parameter_s=''):
143 179 """List currently available magic functions."""
144 print(self._lsmagic())
180 return MagicsDisplay(self.shell.magics_manager)
145 181
146 182 def _magic_docs(self, brief=False, rest=False):
147 183 """Return docstrings from magic functions."""
148 184 mman = self.shell.magics_manager
149 185 docs = mman.lsmagic_docs(brief, missing='No documentation')
150 186
151 187 if rest:
152 188 format_string = '**%s%s**::\n\n%s\n\n'
153 189 else:
154 190 format_string = '%s%s:\n%s\n'
155 191
156 192 return ''.join(
157 193 [format_string % (magic_escapes['line'], fname,
158 194 indent(dedent(fndoc)))
159 195 for fname, fndoc in sorted(docs['line'].items())]
160 196 +
161 197 [format_string % (magic_escapes['cell'], fname,
162 198 indent(dedent(fndoc)))
163 199 for fname, fndoc in sorted(docs['cell'].items())]
164 200 )
165 201
166 202 @line_magic
167 203 def magic(self, parameter_s=''):
168 204 """Print information about the magic function system.
169 205
170 206 Supported formats: -latex, -brief, -rest
171 207 """
172 208
173 209 mode = ''
174 210 try:
175 211 mode = parameter_s.split()[0][1:]
176 212 if mode == 'rest':
177 213 rest_docs = []
178 214 except IndexError:
179 215 pass
180 216
181 217 brief = (mode == 'brief')
182 218 rest = (mode == 'rest')
183 219 magic_docs = self._magic_docs(brief, rest)
184 220
185 221 if mode == 'latex':
186 222 print(self.format_latex(magic_docs))
187 223 return
188 224 else:
189 225 magic_docs = format_screen(magic_docs)
190 226
191 227 out = ["""
192 228 IPython's 'magic' functions
193 229 ===========================
194 230
195 231 The magic function system provides a series of functions which allow you to
196 232 control the behavior of IPython itself, plus a lot of system-type
197 233 features. There are two kinds of magics, line-oriented and cell-oriented.
198 234
199 235 Line magics are prefixed with the % character and work much like OS
200 236 command-line calls: they get as an argument the rest of the line, where
201 237 arguments are passed without parentheses or quotes. For example, this will
202 238 time the given statement::
203 239
204 240 %timeit range(1000)
205 241
206 242 Cell magics are prefixed with a double %%, and they are functions that get as
207 243 an argument not only the rest of the line, but also the lines below it in a
208 244 separate argument. These magics are called with two arguments: the rest of the
209 245 call line and the body of the cell, consisting of the lines below the first.
210 246 For example::
211 247
212 248 %%timeit x = numpy.random.randn((100, 100))
213 249 numpy.linalg.svd(x)
214 250
215 251 will time the execution of the numpy svd routine, running the assignment of x
216 252 as part of the setup phase, which is not timed.
217 253
218 254 In a line-oriented client (the terminal or Qt console IPython), starting a new
219 255 input with %% will automatically enter cell mode, and IPython will continue
220 256 reading input until a blank line is given. In the notebook, simply type the
221 257 whole cell as one entity, but keep in mind that the %% escape can only be at
222 258 the very start of the cell.
223 259
224 260 NOTE: If you have 'automagic' enabled (via the command line option or with the
225 261 %automagic function), you don't need to type in the % explicitly for line
226 262 magics; cell magics always require an explicit '%%' escape. By default,
227 263 IPython ships with automagic on, so you should only rarely need the % escape.
228 264
229 265 Example: typing '%cd mydir' (without the quotes) changes you working directory
230 266 to 'mydir', if it exists.
231 267
232 268 For a list of the available magic functions, use %lsmagic. For a description
233 269 of any of them, type %magic_name?, e.g. '%cd?'.
234 270
235 271 Currently the magic system has the following functions:""",
236 272 magic_docs,
237 273 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
238 274 self._lsmagic(),
239 275 ]
240 276 page.page('\n'.join(out))
241 277
242 278
243 279 @line_magic
244 280 def page(self, parameter_s=''):
245 281 """Pretty print the object and display it through a pager.
246 282
247 283 %page [options] OBJECT
248 284
249 285 If no object is given, use _ (last output).
250 286
251 287 Options:
252 288
253 289 -r: page str(object), don't pretty-print it."""
254 290
255 291 # After a function contributed by Olivier Aubert, slightly modified.
256 292
257 293 # Process options/args
258 294 opts, args = self.parse_options(parameter_s, 'r')
259 295 raw = 'r' in opts
260 296
261 297 oname = args and args or '_'
262 298 info = self.shell._ofind(oname)
263 299 if info['found']:
264 300 txt = (raw and str or pformat)( info['obj'] )
265 301 page.page(txt)
266 302 else:
267 303 print('Object `%s` not found' % oname)
268 304
269 305 @line_magic
270 306 def profile(self, parameter_s=''):
271 307 """Print your currently active IPython profile."""
272 308 from IPython.core.application import BaseIPythonApplication
273 309 if BaseIPythonApplication.initialized():
274 310 print(BaseIPythonApplication.instance().profile)
275 311 else:
276 312 error("profile is an application-level value, but you don't appear to be in an IPython application")
277 313
278 314 @line_magic
279 315 def pprint(self, parameter_s=''):
280 316 """Toggle pretty printing on/off."""
281 317 ptformatter = self.shell.display_formatter.formatters['text/plain']
282 318 ptformatter.pprint = bool(1 - ptformatter.pprint)
283 319 print('Pretty printing has been turned',
284 320 ['OFF','ON'][ptformatter.pprint])
285 321
286 322 @line_magic
287 323 def colors(self, parameter_s=''):
288 324 """Switch color scheme for prompts, info system and exception handlers.
289 325
290 326 Currently implemented schemes: NoColor, Linux, LightBG.
291 327
292 328 Color scheme names are not case-sensitive.
293 329
294 330 Examples
295 331 --------
296 332 To get a plain black and white terminal::
297 333
298 334 %colors nocolor
299 335 """
300 336 def color_switch_err(name):
301 337 warn('Error changing %s color schemes.\n%s' %
302 338 (name, sys.exc_info()[1]))
303 339
304 340
305 341 new_scheme = parameter_s.strip()
306 342 if not new_scheme:
307 343 raise UsageError(
308 344 "%colors: you must specify a color scheme. See '%colors?'")
309 345 return
310 346 # local shortcut
311 347 shell = self.shell
312 348
313 349 import IPython.utils.rlineimpl as readline
314 350
315 351 if not shell.colors_force and \
316 352 not readline.have_readline and \
317 353 (sys.platform == "win32" or sys.platform == "cli"):
318 354 msg = """\
319 355 Proper color support under MS Windows requires the pyreadline library.
320 356 You can find it at:
321 357 http://ipython.org/pyreadline.html
322 358 Gary's readline needs the ctypes module, from:
323 359 http://starship.python.net/crew/theller/ctypes
324 360 (Note that ctypes is already part of Python versions 2.5 and newer).
325 361
326 362 Defaulting color scheme to 'NoColor'"""
327 363 new_scheme = 'NoColor'
328 364 warn(msg)
329 365
330 366 # readline option is 0
331 367 if not shell.colors_force and not shell.has_readline:
332 368 new_scheme = 'NoColor'
333 369
334 370 # Set prompt colors
335 371 try:
336 372 shell.prompt_manager.color_scheme = new_scheme
337 373 except:
338 374 color_switch_err('prompt')
339 375 else:
340 376 shell.colors = \
341 377 shell.prompt_manager.color_scheme_table.active_scheme_name
342 378 # Set exception colors
343 379 try:
344 380 shell.InteractiveTB.set_colors(scheme = new_scheme)
345 381 shell.SyntaxTB.set_colors(scheme = new_scheme)
346 382 except:
347 383 color_switch_err('exception')
348 384
349 385 # Set info (for 'object?') colors
350 386 if shell.color_info:
351 387 try:
352 388 shell.inspector.set_active_scheme(new_scheme)
353 389 except:
354 390 color_switch_err('object inspector')
355 391 else:
356 392 shell.inspector.set_active_scheme('NoColor')
357 393
358 394 @line_magic
359 395 def xmode(self, parameter_s=''):
360 396 """Switch modes for the exception handlers.
361 397
362 398 Valid modes: Plain, Context and Verbose.
363 399
364 400 If called without arguments, acts as a toggle."""
365 401
366 402 def xmode_switch_err(name):
367 403 warn('Error changing %s exception modes.\n%s' %
368 404 (name,sys.exc_info()[1]))
369 405
370 406 shell = self.shell
371 407 new_mode = parameter_s.strip().capitalize()
372 408 try:
373 409 shell.InteractiveTB.set_mode(mode=new_mode)
374 410 print('Exception reporting mode:',shell.InteractiveTB.mode)
375 411 except:
376 412 xmode_switch_err('user')
377 413
378 414 @line_magic
379 415 def quickref(self,arg):
380 416 """ Show a quick reference sheet """
381 417 from IPython.core.usage import quick_reference
382 418 qr = quick_reference + self._magic_docs(brief=True)
383 419 page.page(qr)
384 420
385 421 @line_magic
386 422 def doctest_mode(self, parameter_s=''):
387 423 """Toggle doctest mode on and off.
388 424
389 425 This mode is intended to make IPython behave as much as possible like a
390 426 plain Python shell, from the perspective of how its prompts, exceptions
391 427 and output look. This makes it easy to copy and paste parts of a
392 428 session into doctests. It does so by:
393 429
394 430 - Changing the prompts to the classic ``>>>`` ones.
395 431 - Changing the exception reporting mode to 'Plain'.
396 432 - Disabling pretty-printing of output.
397 433
398 434 Note that IPython also supports the pasting of code snippets that have
399 435 leading '>>>' and '...' prompts in them. This means that you can paste
400 436 doctests from files or docstrings (even if they have leading
401 437 whitespace), and the code will execute correctly. You can then use
402 438 '%history -t' to see the translated history; this will give you the
403 439 input after removal of all the leading prompts and whitespace, which
404 440 can be pasted back into an editor.
405 441
406 442 With these features, you can switch into this mode easily whenever you
407 443 need to do testing and changes to doctests, without having to leave
408 444 your existing IPython session.
409 445 """
410 446
411 447 # Shorthands
412 448 shell = self.shell
413 449 pm = shell.prompt_manager
414 450 meta = shell.meta
415 451 disp_formatter = self.shell.display_formatter
416 452 ptformatter = disp_formatter.formatters['text/plain']
417 453 # dstore is a data store kept in the instance metadata bag to track any
418 454 # changes we make, so we can undo them later.
419 455 dstore = meta.setdefault('doctest_mode',Struct())
420 456 save_dstore = dstore.setdefault
421 457
422 458 # save a few values we'll need to recover later
423 459 mode = save_dstore('mode',False)
424 460 save_dstore('rc_pprint',ptformatter.pprint)
425 461 save_dstore('xmode',shell.InteractiveTB.mode)
426 462 save_dstore('rc_separate_out',shell.separate_out)
427 463 save_dstore('rc_separate_out2',shell.separate_out2)
428 464 save_dstore('rc_prompts_pad_left',pm.justify)
429 465 save_dstore('rc_separate_in',shell.separate_in)
430 466 save_dstore('rc_active_types',disp_formatter.active_types)
431 467 save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template))
432 468
433 469 if mode == False:
434 470 # turn on
435 471 pm.in_template = '>>> '
436 472 pm.in2_template = '... '
437 473 pm.out_template = ''
438 474
439 475 # Prompt separators like plain python
440 476 shell.separate_in = ''
441 477 shell.separate_out = ''
442 478 shell.separate_out2 = ''
443 479
444 480 pm.justify = False
445 481
446 482 ptformatter.pprint = False
447 483 disp_formatter.active_types = ['text/plain']
448 484
449 485 shell.magic('xmode Plain')
450 486 else:
451 487 # turn off
452 488 pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates
453 489
454 490 shell.separate_in = dstore.rc_separate_in
455 491
456 492 shell.separate_out = dstore.rc_separate_out
457 493 shell.separate_out2 = dstore.rc_separate_out2
458 494
459 495 pm.justify = dstore.rc_prompts_pad_left
460 496
461 497 ptformatter.pprint = dstore.rc_pprint
462 498 disp_formatter.active_types = dstore.rc_active_types
463 499
464 500 shell.magic('xmode ' + dstore.xmode)
465 501
466 502 # Store new mode and inform
467 503 dstore.mode = bool(1-int(mode))
468 504 mode_label = ['OFF','ON'][dstore.mode]
469 505 print('Doctest mode is:', mode_label)
470 506
471 507 @line_magic
472 508 def gui(self, parameter_s=''):
473 509 """Enable or disable IPython GUI event loop integration.
474 510
475 511 %gui [GUINAME]
476 512
477 513 This magic replaces IPython's threaded shells that were activated
478 514 using the (pylab/wthread/etc.) command line flags. GUI toolkits
479 515 can now be enabled at runtime and keyboard
480 516 interrupts should work without any problems. The following toolkits
481 517 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
482 518
483 519 %gui wx # enable wxPython event loop integration
484 520 %gui qt4|qt # enable PyQt4 event loop integration
485 521 %gui gtk # enable PyGTK event loop integration
486 522 %gui gtk3 # enable Gtk3 event loop integration
487 523 %gui tk # enable Tk event loop integration
488 524 %gui osx # enable Cocoa event loop integration
489 525 # (requires %matplotlib 1.1)
490 526 %gui # disable all event loop integration
491 527
492 528 WARNING: after any of these has been called you can simply create
493 529 an application object, but DO NOT start the event loop yourself, as
494 530 we have already handled that.
495 531 """
496 532 opts, arg = self.parse_options(parameter_s, '')
497 533 if arg=='': arg = None
498 534 try:
499 535 return self.shell.enable_gui(arg)
500 536 except Exception as e:
501 537 # print simple error message, rather than traceback if we can't
502 538 # hook up the GUI
503 539 error(str(e))
504 540
505 541 @skip_doctest
506 542 @line_magic
507 543 def precision(self, s=''):
508 544 """Set floating point precision for pretty printing.
509 545
510 546 Can set either integer precision or a format string.
511 547
512 548 If numpy has been imported and precision is an int,
513 549 numpy display precision will also be set, via ``numpy.set_printoptions``.
514 550
515 551 If no argument is given, defaults will be restored.
516 552
517 553 Examples
518 554 --------
519 555 ::
520 556
521 557 In [1]: from math import pi
522 558
523 559 In [2]: %precision 3
524 560 Out[2]: u'%.3f'
525 561
526 562 In [3]: pi
527 563 Out[3]: 3.142
528 564
529 565 In [4]: %precision %i
530 566 Out[4]: u'%i'
531 567
532 568 In [5]: pi
533 569 Out[5]: 3
534 570
535 571 In [6]: %precision %e
536 572 Out[6]: u'%e'
537 573
538 574 In [7]: pi**10
539 575 Out[7]: 9.364805e+04
540 576
541 577 In [8]: %precision
542 578 Out[8]: u'%r'
543 579
544 580 In [9]: pi**10
545 581 Out[9]: 93648.047476082982
546 582 """
547 583 ptformatter = self.shell.display_formatter.formatters['text/plain']
548 584 ptformatter.float_precision = s
549 585 return ptformatter.float_format
550 586
551 587 @magic_arguments.magic_arguments()
552 588 @magic_arguments.argument(
553 589 '-e', '--export', action='store_true', default=False,
554 590 help='Export IPython history as a notebook. The filename argument '
555 591 'is used to specify the notebook name and format. For example '
556 592 'a filename of notebook.ipynb will result in a notebook name '
557 593 'of "notebook" and a format of "json". Likewise using a ".py" '
558 594 'file extension will write the notebook as a Python script'
559 595 )
560 596 @magic_arguments.argument(
561 597 '-f', '--format',
562 598 help='Convert an existing IPython notebook to a new format. This option '
563 599 'specifies the new format and can have the values: json, py. '
564 600 'The target filename is chosen automatically based on the new '
565 601 'format. The filename argument gives the name of the source file.'
566 602 )
567 603 @magic_arguments.argument(
568 604 'filename', type=unicode,
569 605 help='Notebook name or filename'
570 606 )
571 607 @line_magic
572 608 def notebook(self, s):
573 609 """Export and convert IPython notebooks.
574 610
575 611 This function can export the current IPython history to a notebook file
576 612 or can convert an existing notebook file into a different format. For
577 613 example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
578 614 To export the history to "foo.py" do "%notebook -e foo.py". To convert
579 615 "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
580 616 formats include (json/ipynb, py).
581 617 """
582 618 args = magic_arguments.parse_argstring(self.notebook, s)
583 619
584 620 from IPython.nbformat import current
585 621 args.filename = unquote_filename(args.filename)
586 622 if args.export:
587 623 fname, name, format = current.parse_filename(args.filename)
588 624 cells = []
589 625 hist = list(self.shell.history_manager.get_range())
590 626 for session, prompt_number, input in hist[:-1]:
591 627 cells.append(current.new_code_cell(prompt_number=prompt_number,
592 628 input=input))
593 629 worksheet = current.new_worksheet(cells=cells)
594 630 nb = current.new_notebook(name=name,worksheets=[worksheet])
595 631 with io.open(fname, 'w', encoding='utf-8') as f:
596 632 current.write(nb, f, format);
597 633 elif args.format is not None:
598 634 old_fname, old_name, old_format = current.parse_filename(args.filename)
599 635 new_format = args.format
600 636 if new_format == u'xml':
601 637 raise ValueError('Notebooks cannot be written as xml.')
602 638 elif new_format == u'ipynb' or new_format == u'json':
603 639 new_fname = old_name + u'.ipynb'
604 640 new_format = u'json'
605 641 elif new_format == u'py':
606 642 new_fname = old_name + u'.py'
607 643 else:
608 644 raise ValueError('Invalid notebook format: %s' % new_format)
609 645 with io.open(old_fname, 'r', encoding='utf-8') as f:
610 646 nb = current.read(f, old_format)
611 647 with io.open(new_fname, 'w', encoding='utf-8') as f:
612 648 current.write(nb, f, new_format)
@@ -1,992 +1,993 b''
1 1 """The Qt MainWindow for the QtConsole
2 2
3 3 This is a tabbed pseudo-terminal of IPython sessions, with a menu bar for
4 4 common actions.
5 5
6 6 Authors:
7 7
8 8 * Evan Patterson
9 9 * Min RK
10 10 * Erik Tollerud
11 11 * Fernando Perez
12 12 * Bussonnier Matthias
13 13 * Thomas Kluyver
14 14 * Paul Ivanov
15 15
16 16 """
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 # stdlib imports
23 23 import json
24 24 import re
25 25 import sys
26 26 import webbrowser
27 27 from threading import Thread
28 28
29 29 # System library imports
30 30 from IPython.external.qt import QtGui,QtCore
31 31
32 from IPython.core.magic import magic_escapes
33
32 34 def background(f):
33 35 """call a function in a simple thread, to prevent blocking"""
34 36 t = Thread(target=f)
35 37 t.start()
36 38 return t
37 39
38 40 #-----------------------------------------------------------------------------
39 41 # Classes
40 42 #-----------------------------------------------------------------------------
41 43
42 44 class MainWindow(QtGui.QMainWindow):
43 45
44 46 #---------------------------------------------------------------------------
45 47 # 'object' interface
46 48 #---------------------------------------------------------------------------
47 49
48 50 _magic_menu_dict = {}
49 51
50 52 def __init__(self, app,
51 53 confirm_exit=True,
52 54 new_frontend_factory=None, slave_frontend_factory=None,
53 55 ):
54 56 """ Create a tabbed MainWindow for managing IPython FrontendWidgets
55 57
56 58 Parameters
57 59 ----------
58 60
59 61 app : reference to QApplication parent
60 62 confirm_exit : bool, optional
61 63 Whether we should prompt on close of tabs
62 64 new_frontend_factory : callable
63 65 A callable that returns a new IPythonWidget instance, attached to
64 66 its own running kernel.
65 67 slave_frontend_factory : callable
66 68 A callable that takes an existing IPythonWidget, and returns a new
67 69 IPythonWidget instance, attached to the same kernel.
68 70 """
69 71
70 72 super(MainWindow, self).__init__()
71 73 self._kernel_counter = 0
72 74 self._app = app
73 75 self.confirm_exit = confirm_exit
74 76 self.new_frontend_factory = new_frontend_factory
75 77 self.slave_frontend_factory = slave_frontend_factory
76 78
77 79 self.tab_widget = QtGui.QTabWidget(self)
78 80 self.tab_widget.setDocumentMode(True)
79 81 self.tab_widget.setTabsClosable(True)
80 82 self.tab_widget.tabCloseRequested[int].connect(self.close_tab)
81 83
82 84 self.setCentralWidget(self.tab_widget)
83 85 # hide tab bar at first, since we have no tabs:
84 86 self.tab_widget.tabBar().setVisible(False)
85 87 # prevent focus in tab bar
86 88 self.tab_widget.setFocusPolicy(QtCore.Qt.NoFocus)
87 89
88 90 def update_tab_bar_visibility(self):
89 91 """ update visibility of the tabBar depending of the number of tab
90 92
91 93 0 or 1 tab, tabBar hidden
92 94 2+ tabs, tabBar visible
93 95
94 96 send a self.close if number of tab ==0
95 97
96 98 need to be called explicitly, or be connected to tabInserted/tabRemoved
97 99 """
98 100 if self.tab_widget.count() <= 1:
99 101 self.tab_widget.tabBar().setVisible(False)
100 102 else:
101 103 self.tab_widget.tabBar().setVisible(True)
102 104 if self.tab_widget.count()==0 :
103 105 self.close()
104 106
105 107 @property
106 108 def next_kernel_id(self):
107 109 """constantly increasing counter for kernel IDs"""
108 110 c = self._kernel_counter
109 111 self._kernel_counter += 1
110 112 return c
111 113
112 114 @property
113 115 def active_frontend(self):
114 116 return self.tab_widget.currentWidget()
115 117
116 118 def create_tab_with_new_frontend(self):
117 119 """create a new frontend and attach it to a new tab"""
118 120 widget = self.new_frontend_factory()
119 121 self.add_tab_with_frontend(widget)
120 122
121 123 def create_tab_with_current_kernel(self):
122 124 """create a new frontend attached to the same kernel as the current tab"""
123 125 current_widget = self.tab_widget.currentWidget()
124 126 current_widget_index = self.tab_widget.indexOf(current_widget)
125 127 current_widget_name = self.tab_widget.tabText(current_widget_index)
126 128 widget = self.slave_frontend_factory(current_widget)
127 129 if 'slave' in current_widget_name:
128 130 # don't keep stacking slaves
129 131 name = current_widget_name
130 132 else:
131 133 name = '(%s) slave' % current_widget_name
132 134 self.add_tab_with_frontend(widget,name=name)
133 135
134 136 def close_tab(self,current_tab):
135 137 """ Called when you need to try to close a tab.
136 138
137 139 It takes the number of the tab to be closed as argument, or a reference
138 140 to the widget inside this tab
139 141 """
140 142
141 143 # let's be sure "tab" and "closing widget" are respectively the index
142 144 # of the tab to close and a reference to the frontend to close
143 145 if type(current_tab) is not int :
144 146 current_tab = self.tab_widget.indexOf(current_tab)
145 147 closing_widget=self.tab_widget.widget(current_tab)
146 148
147 149
148 150 # when trying to be closed, widget might re-send a request to be
149 151 # closed again, but will be deleted when event will be processed. So
150 152 # need to check that widget still exists and skip if not. One example
151 153 # of this is when 'exit' is sent in a slave tab. 'exit' will be
152 154 # re-sent by this function on the master widget, which ask all slave
153 155 # widgets to exit
154 156 if closing_widget==None:
155 157 return
156 158
157 159 #get a list of all slave widgets on the same kernel.
158 160 slave_tabs = self.find_slave_widgets(closing_widget)
159 161
160 162 keepkernel = None #Use the prompt by default
161 163 if hasattr(closing_widget,'_keep_kernel_on_exit'): #set by exit magic
162 164 keepkernel = closing_widget._keep_kernel_on_exit
163 165 # If signal sent by exit magic (_keep_kernel_on_exit, exist and not None)
164 166 # we set local slave tabs._hidden to True to avoid prompting for kernel
165 167 # restart when they get the signal. and then "forward" the 'exit'
166 168 # to the main window
167 169 if keepkernel is not None:
168 170 for tab in slave_tabs:
169 171 tab._hidden = True
170 172 if closing_widget in slave_tabs:
171 173 try :
172 174 self.find_master_tab(closing_widget).execute('exit')
173 175 except AttributeError:
174 176 self.log.info("Master already closed or not local, closing only current tab")
175 177 self.tab_widget.removeTab(current_tab)
176 178 self.update_tab_bar_visibility()
177 179 return
178 180
179 181 kernel_client = closing_widget.kernel_client
180 182 kernel_manager = closing_widget.kernel_manager
181 183
182 184 if keepkernel is None and not closing_widget._confirm_exit:
183 185 # don't prompt, just terminate the kernel if we own it
184 186 # or leave it alone if we don't
185 187 keepkernel = closing_widget._existing
186 188 if keepkernel is None: #show prompt
187 189 if kernel_client and kernel_client.channels_running:
188 190 title = self.window().windowTitle()
189 191 cancel = QtGui.QMessageBox.Cancel
190 192 okay = QtGui.QMessageBox.Ok
191 193 if closing_widget._may_close:
192 194 msg = "You are closing the tab : "+'"'+self.tab_widget.tabText(current_tab)+'"'
193 195 info = "Would you like to quit the Kernel and close all attached Consoles as well?"
194 196 justthis = QtGui.QPushButton("&No, just this Tab", self)
195 197 justthis.setShortcut('N')
196 198 closeall = QtGui.QPushButton("&Yes, close all", self)
197 199 closeall.setShortcut('Y')
198 200 # allow ctrl-d ctrl-d exit, like in terminal
199 201 closeall.setShortcut('Ctrl+D')
200 202 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
201 203 title, msg)
202 204 box.setInformativeText(info)
203 205 box.addButton(cancel)
204 206 box.addButton(justthis, QtGui.QMessageBox.NoRole)
205 207 box.addButton(closeall, QtGui.QMessageBox.YesRole)
206 208 box.setDefaultButton(closeall)
207 209 box.setEscapeButton(cancel)
208 210 pixmap = QtGui.QPixmap(self._app.icon.pixmap(QtCore.QSize(64,64)))
209 211 box.setIconPixmap(pixmap)
210 212 reply = box.exec_()
211 213 if reply == 1: # close All
212 214 for slave in slave_tabs:
213 215 background(slave.kernel_client.stop_channels)
214 216 self.tab_widget.removeTab(self.tab_widget.indexOf(slave))
215 217 closing_widget.execute("exit")
216 218 self.tab_widget.removeTab(current_tab)
217 219 background(kernel_client.stop_channels)
218 220 elif reply == 0: # close Console
219 221 if not closing_widget._existing:
220 222 # Have kernel: don't quit, just close the tab
221 223 closing_widget.execute("exit True")
222 224 self.tab_widget.removeTab(current_tab)
223 225 background(kernel_client.stop_channels)
224 226 else:
225 227 reply = QtGui.QMessageBox.question(self, title,
226 228 "Are you sure you want to close this Console?"+
227 229 "\nThe Kernel and other Consoles will remain active.",
228 230 okay|cancel,
229 231 defaultButton=okay
230 232 )
231 233 if reply == okay:
232 234 self.tab_widget.removeTab(current_tab)
233 235 elif keepkernel: #close console but leave kernel running (no prompt)
234 236 self.tab_widget.removeTab(current_tab)
235 237 background(kernel_client.stop_channels)
236 238 else: #close console and kernel (no prompt)
237 239 self.tab_widget.removeTab(current_tab)
238 240 if kernel_client and kernel_client.channels_running:
239 241 for slave in slave_tabs:
240 242 background(slave.kernel_client.stop_channels)
241 243 self.tab_widget.removeTab(self.tab_widget.indexOf(slave))
242 244 if kernel_manager:
243 245 kernel_manager.shutdown_kernel()
244 246 background(kernel_client.stop_channels)
245 247
246 248 self.update_tab_bar_visibility()
247 249
248 250 def add_tab_with_frontend(self,frontend,name=None):
249 251 """ insert a tab with a given frontend in the tab bar, and give it a name
250 252
251 253 """
252 254 if not name:
253 255 name = 'kernel %i' % self.next_kernel_id
254 256 self.tab_widget.addTab(frontend,name)
255 257 self.update_tab_bar_visibility()
256 258 self.make_frontend_visible(frontend)
257 259 frontend.exit_requested.connect(self.close_tab)
258 260
259 261 def next_tab(self):
260 262 self.tab_widget.setCurrentIndex((self.tab_widget.currentIndex()+1))
261 263
262 264 def prev_tab(self):
263 265 self.tab_widget.setCurrentIndex((self.tab_widget.currentIndex()-1))
264 266
265 267 def make_frontend_visible(self,frontend):
266 268 widget_index=self.tab_widget.indexOf(frontend)
267 269 if widget_index > 0 :
268 270 self.tab_widget.setCurrentIndex(widget_index)
269 271
270 272 def find_master_tab(self,tab,as_list=False):
271 273 """
272 274 Try to return the frontend that owns the kernel attached to the given widget/tab.
273 275
274 276 Only finds frontend owned by the current application. Selection
275 277 based on port of the kernel might be inaccurate if several kernel
276 278 on different ip use same port number.
277 279
278 280 This function does the conversion tabNumber/widget if needed.
279 281 Might return None if no master widget (non local kernel)
280 282 Will crash IPython if more than 1 masterWidget
281 283
282 284 When asList set to True, always return a list of widget(s) owning
283 285 the kernel. The list might be empty or containing several Widget.
284 286 """
285 287
286 288 #convert from/to int/richIpythonWidget if needed
287 289 if isinstance(tab, int):
288 290 tab = self.tab_widget.widget(tab)
289 291 km=tab.kernel_client
290 292
291 293 #build list of all widgets
292 294 widget_list = [self.tab_widget.widget(i) for i in range(self.tab_widget.count())]
293 295
294 296 # widget that are candidate to be the owner of the kernel does have all the same port of the curent widget
295 297 # And should have a _may_close attribute
296 298 filtered_widget_list = [ widget for widget in widget_list if
297 299 widget.kernel_client.connection_file == km.connection_file and
298 300 hasattr(widget,'_may_close') ]
299 301 # the master widget is the one that may close the kernel
300 302 master_widget= [ widget for widget in filtered_widget_list if widget._may_close]
301 303 if as_list:
302 304 return master_widget
303 305 assert(len(master_widget)<=1 )
304 306 if len(master_widget)==0:
305 307 return None
306 308
307 309 return master_widget[0]
308 310
309 311 def find_slave_widgets(self,tab):
310 312 """return all the frontends that do not own the kernel attached to the given widget/tab.
311 313
312 314 Only find frontends owned by the current application. Selection
313 315 based on connection file of the kernel.
314 316
315 317 This function does the conversion tabNumber/widget if needed.
316 318 """
317 319 #convert from/to int/richIpythonWidget if needed
318 320 if isinstance(tab, int):
319 321 tab = self.tab_widget.widget(tab)
320 322 km=tab.kernel_client
321 323
322 324 #build list of all widgets
323 325 widget_list = [self.tab_widget.widget(i) for i in range(self.tab_widget.count())]
324 326
325 327 # widget that are candidate not to be the owner of the kernel does have all the same port of the curent widget
326 328 filtered_widget_list = ( widget for widget in widget_list if
327 329 widget.kernel_client.connection_file == km.connection_file)
328 330 # Get a list of all widget owning the same kernel and removed it from
329 331 # the previous cadidate. (better using sets ?)
330 332 master_widget_list = self.find_master_tab(tab, as_list=True)
331 333 slave_list = [widget for widget in filtered_widget_list if widget not in master_widget_list]
332 334
333 335 return slave_list
334 336
335 337 # Populate the menu bar with common actions and shortcuts
336 338 def add_menu_action(self, menu, action, defer_shortcut=False):
337 339 """Add action to menu as well as self
338 340
339 341 So that when the menu bar is invisible, its actions are still available.
340 342
341 343 If defer_shortcut is True, set the shortcut context to widget-only,
342 344 where it will avoid conflict with shortcuts already bound to the
343 345 widgets themselves.
344 346 """
345 347 menu.addAction(action)
346 348 self.addAction(action)
347 349
348 350 if defer_shortcut:
349 351 action.setShortcutContext(QtCore.Qt.WidgetShortcut)
350 352
351 353 def init_menu_bar(self):
352 354 #create menu in the order they should appear in the menu bar
353 355 self.init_file_menu()
354 356 self.init_edit_menu()
355 357 self.init_view_menu()
356 358 self.init_kernel_menu()
357 359 self.init_magic_menu()
358 360 self.init_window_menu()
359 361 self.init_help_menu()
360 362
361 363 def init_file_menu(self):
362 364 self.file_menu = self.menuBar().addMenu("&File")
363 365
364 366 self.new_kernel_tab_act = QtGui.QAction("New Tab with &New kernel",
365 367 self,
366 368 shortcut="Ctrl+T",
367 369 triggered=self.create_tab_with_new_frontend)
368 370 self.add_menu_action(self.file_menu, self.new_kernel_tab_act)
369 371
370 372 self.slave_kernel_tab_act = QtGui.QAction("New Tab with Sa&me kernel",
371 373 self,
372 374 shortcut="Ctrl+Shift+T",
373 375 triggered=self.create_tab_with_current_kernel)
374 376 self.add_menu_action(self.file_menu, self.slave_kernel_tab_act)
375 377
376 378 self.file_menu.addSeparator()
377 379
378 380 self.close_action=QtGui.QAction("&Close Tab",
379 381 self,
380 382 shortcut=QtGui.QKeySequence.Close,
381 383 triggered=self.close_active_frontend
382 384 )
383 385 self.add_menu_action(self.file_menu, self.close_action)
384 386
385 387 self.export_action=QtGui.QAction("&Save to HTML/XHTML",
386 388 self,
387 389 shortcut=QtGui.QKeySequence.Save,
388 390 triggered=self.export_action_active_frontend
389 391 )
390 392 self.add_menu_action(self.file_menu, self.export_action, True)
391 393
392 394 self.file_menu.addSeparator()
393 395
394 396 printkey = QtGui.QKeySequence(QtGui.QKeySequence.Print)
395 397 if printkey.matches("Ctrl+P") and sys.platform != 'darwin':
396 398 # Only override the default if there is a collision.
397 399 # Qt ctrl = cmd on OSX, so the match gets a false positive on OSX.
398 400 printkey = "Ctrl+Shift+P"
399 401 self.print_action = QtGui.QAction("&Print",
400 402 self,
401 403 shortcut=printkey,
402 404 triggered=self.print_action_active_frontend)
403 405 self.add_menu_action(self.file_menu, self.print_action, True)
404 406
405 407 if sys.platform != 'darwin':
406 408 # OSX always has Quit in the Application menu, only add it
407 409 # to the File menu elsewhere.
408 410
409 411 self.file_menu.addSeparator()
410 412
411 413 self.quit_action = QtGui.QAction("&Quit",
412 414 self,
413 415 shortcut=QtGui.QKeySequence.Quit,
414 416 triggered=self.close,
415 417 )
416 418 self.add_menu_action(self.file_menu, self.quit_action)
417 419
418 420
419 421 def init_edit_menu(self):
420 422 self.edit_menu = self.menuBar().addMenu("&Edit")
421 423
422 424 self.undo_action = QtGui.QAction("&Undo",
423 425 self,
424 426 shortcut=QtGui.QKeySequence.Undo,
425 427 statusTip="Undo last action if possible",
426 428 triggered=self.undo_active_frontend
427 429 )
428 430 self.add_menu_action(self.edit_menu, self.undo_action)
429 431
430 432 self.redo_action = QtGui.QAction("&Redo",
431 433 self,
432 434 shortcut=QtGui.QKeySequence.Redo,
433 435 statusTip="Redo last action if possible",
434 436 triggered=self.redo_active_frontend)
435 437 self.add_menu_action(self.edit_menu, self.redo_action)
436 438
437 439 self.edit_menu.addSeparator()
438 440
439 441 self.cut_action = QtGui.QAction("&Cut",
440 442 self,
441 443 shortcut=QtGui.QKeySequence.Cut,
442 444 triggered=self.cut_active_frontend
443 445 )
444 446 self.add_menu_action(self.edit_menu, self.cut_action, True)
445 447
446 448 self.copy_action = QtGui.QAction("&Copy",
447 449 self,
448 450 shortcut=QtGui.QKeySequence.Copy,
449 451 triggered=self.copy_active_frontend
450 452 )
451 453 self.add_menu_action(self.edit_menu, self.copy_action, True)
452 454
453 455 self.copy_raw_action = QtGui.QAction("Copy (&Raw Text)",
454 456 self,
455 457 shortcut="Ctrl+Shift+C",
456 458 triggered=self.copy_raw_active_frontend
457 459 )
458 460 self.add_menu_action(self.edit_menu, self.copy_raw_action, True)
459 461
460 462 self.paste_action = QtGui.QAction("&Paste",
461 463 self,
462 464 shortcut=QtGui.QKeySequence.Paste,
463 465 triggered=self.paste_active_frontend
464 466 )
465 467 self.add_menu_action(self.edit_menu, self.paste_action, True)
466 468
467 469 self.edit_menu.addSeparator()
468 470
469 471 selectall = QtGui.QKeySequence(QtGui.QKeySequence.SelectAll)
470 472 if selectall.matches("Ctrl+A") and sys.platform != 'darwin':
471 473 # Only override the default if there is a collision.
472 474 # Qt ctrl = cmd on OSX, so the match gets a false positive on OSX.
473 475 selectall = "Ctrl+Shift+A"
474 476 self.select_all_action = QtGui.QAction("Select &All",
475 477 self,
476 478 shortcut=selectall,
477 479 triggered=self.select_all_active_frontend
478 480 )
479 481 self.add_menu_action(self.edit_menu, self.select_all_action, True)
480 482
481 483
482 484 def init_view_menu(self):
483 485 self.view_menu = self.menuBar().addMenu("&View")
484 486
485 487 if sys.platform != 'darwin':
486 488 # disable on OSX, where there is always a menu bar
487 489 self.toggle_menu_bar_act = QtGui.QAction("Toggle &Menu Bar",
488 490 self,
489 491 shortcut="Ctrl+Shift+M",
490 492 statusTip="Toggle visibility of menubar",
491 493 triggered=self.toggle_menu_bar)
492 494 self.add_menu_action(self.view_menu, self.toggle_menu_bar_act)
493 495
494 496 fs_key = "Ctrl+Meta+F" if sys.platform == 'darwin' else "F11"
495 497 self.full_screen_act = QtGui.QAction("&Full Screen",
496 498 self,
497 499 shortcut=fs_key,
498 500 statusTip="Toggle between Fullscreen and Normal Size",
499 501 triggered=self.toggleFullScreen)
500 502 self.add_menu_action(self.view_menu, self.full_screen_act)
501 503
502 504 self.view_menu.addSeparator()
503 505
504 506 self.increase_font_size = QtGui.QAction("Zoom &In",
505 507 self,
506 508 shortcut=QtGui.QKeySequence.ZoomIn,
507 509 triggered=self.increase_font_size_active_frontend
508 510 )
509 511 self.add_menu_action(self.view_menu, self.increase_font_size, True)
510 512
511 513 self.decrease_font_size = QtGui.QAction("Zoom &Out",
512 514 self,
513 515 shortcut=QtGui.QKeySequence.ZoomOut,
514 516 triggered=self.decrease_font_size_active_frontend
515 517 )
516 518 self.add_menu_action(self.view_menu, self.decrease_font_size, True)
517 519
518 520 self.reset_font_size = QtGui.QAction("Zoom &Reset",
519 521 self,
520 522 shortcut="Ctrl+0",
521 523 triggered=self.reset_font_size_active_frontend
522 524 )
523 525 self.add_menu_action(self.view_menu, self.reset_font_size, True)
524 526
525 527 self.view_menu.addSeparator()
526 528
527 529 self.clear_action = QtGui.QAction("&Clear Screen",
528 530 self,
529 531 shortcut='Ctrl+L',
530 532 statusTip="Clear the console",
531 533 triggered=self.clear_magic_active_frontend)
532 534 self.add_menu_action(self.view_menu, self.clear_action)
533 535
534 536 self.pager_menu = self.view_menu.addMenu("&Pager")
535 537
536 538 hsplit_action = QtGui.QAction(".. &Horizontal Split",
537 539 self,
538 540 triggered=lambda: self.set_paging_active_frontend('hsplit'))
539 541
540 542 vsplit_action = QtGui.QAction(" : &Vertical Split",
541 543 self,
542 544 triggered=lambda: self.set_paging_active_frontend('vsplit'))
543 545
544 546 inside_action = QtGui.QAction(" &Inside Pager",
545 547 self,
546 548 triggered=lambda: self.set_paging_active_frontend('inside'))
547 549
548 550 self.pager_menu.addAction(hsplit_action)
549 551 self.pager_menu.addAction(vsplit_action)
550 552 self.pager_menu.addAction(inside_action)
551 553
552 554 def init_kernel_menu(self):
553 555 self.kernel_menu = self.menuBar().addMenu("&Kernel")
554 556 # Qt on OSX maps Ctrl to Cmd, and Meta to Ctrl
555 557 # keep the signal shortcuts to ctrl, rather than
556 558 # platform-default like we do elsewhere.
557 559
558 560 ctrl = "Meta" if sys.platform == 'darwin' else "Ctrl"
559 561
560 562 self.interrupt_kernel_action = QtGui.QAction("&Interrupt current Kernel",
561 563 self,
562 564 triggered=self.interrupt_kernel_active_frontend,
563 565 shortcut=ctrl+"+C",
564 566 )
565 567 self.add_menu_action(self.kernel_menu, self.interrupt_kernel_action)
566 568
567 569 self.restart_kernel_action = QtGui.QAction("&Restart current Kernel",
568 570 self,
569 571 triggered=self.restart_kernel_active_frontend,
570 572 shortcut=ctrl+"+.",
571 573 )
572 574 self.add_menu_action(self.kernel_menu, self.restart_kernel_action)
573 575
574 576 self.kernel_menu.addSeparator()
575 577
576 578 self.confirm_restart_kernel_action = QtGui.QAction("&Confirm kernel restart",
577 579 self,
578 580 checkable=True,
579 581 checked=self.active_frontend.confirm_restart,
580 582 triggered=self.toggle_confirm_restart_active_frontend
581 583 )
582 584
583 585 self.add_menu_action(self.kernel_menu, self.confirm_restart_kernel_action)
584 586 self.tab_widget.currentChanged.connect(self.update_restart_checkbox)
585 587
586 588 def _make_dynamic_magic(self,magic):
587 589 """Return a function `fun` that will execute `magic` on active frontend.
588 590
589 591 Parameters
590 592 ----------
591 593 magic : string
592 594 string that will be executed as is when the returned function is called
593 595
594 596 Returns
595 597 -------
596 598 fun : function
597 599 function with no parameters, when called will execute `magic` on the
598 600 current active frontend at call time
599 601
600 602 See Also
601 603 --------
602 604 populate_all_magic_menu : generate the "All Magics..." menu
603 605
604 606 Notes
605 607 -----
606 608 `fun` executes `magic` in active frontend at the moment it is triggered,
607 609 not the active frontend at the moment it was created.
608 610
609 611 This function is mostly used to create the "All Magics..." Menu at run time.
610 612 """
611 613 # need two level nested function to be sure to pass magic
612 614 # to active frontend **at run time**.
613 615 def inner_dynamic_magic():
614 616 self.active_frontend.execute(magic)
615 617 inner_dynamic_magic.__name__ = "dynamics_magic_s"
616 618 return inner_dynamic_magic
617 619
618 620 def populate_all_magic_menu(self, display_data=None):
619 621 """Clean "All Magics..." menu and repopulate it with `display_data`
620 622
621 623 Parameters
622 624 ----------
623 625 display_data : dict,
624 dict of display_data for the magics list.
625 Expects json data, as the result of MagicsManager.lsmagic_json()
626 dict of display_data for the magics dict of a MagicsManager.
627 Expects json data, as the result of %lsmagic
626 628
627 629 """
628 630 for k,v in self._magic_menu_dict.items():
629 631 v.clear()
630 632 self.all_magic_menu.clear()
631 633
632 634 if not display_data:
633 635 return
634
635 mlist = json.loads(display_data['data'].get('application/json', []))
636
637 for magic in mlist:
638 cell = (magic['type'] == 'cell')
639 name = magic['name']
640 mclass = magic['class']
641 if cell :
642 prefix='%%'
643 else :
644 prefix='%'
645 magic_menu = self._get_magic_menu(mclass)
646
647 pmagic = '%s%s'%(prefix,name)
648
649 xaction = QtGui.QAction(pmagic,
650 self,
651 triggered=self._make_dynamic_magic(pmagic)
652 )
653 magic_menu.addAction(xaction)
654 self.all_magic_menu.addAction(xaction)
636
637 if display_data['status'] != 'ok':
638 self.log.warn("%%lsmagic user-expression failed: %s" % display_data)
639 return
640
641 mdict = json.loads(display_data['data'].get('application/json', {}))
642
643 for mtype in sorted(mdict):
644 subdict = mdict[mtype]
645 prefix = magic_escapes[mtype]
646 for name in sorted(subdict):
647 mclass = subdict[name]
648 magic_menu = self._get_magic_menu(mclass)
649 pmagic = prefix + name
650 xaction = QtGui.QAction(pmagic,
651 self,
652 triggered=self._make_dynamic_magic(pmagic)
653 )
654 magic_menu.addAction(xaction)
655 self.all_magic_menu.addAction(xaction)
655 656
656 657 def update_all_magic_menu(self):
657 658 """ Update the list of magics in the "All Magics..." Menu
658 659
659 660 Request the kernel with the list of available magics and populate the
660 661 menu with the list received back
661 662
662 663 """
663 self.active_frontend._silent_exec_callback('get_ipython().magics_manager.lsmagic_json()',
664 self.active_frontend._silent_exec_callback('get_ipython().magic("lsmagic")',
664 665 self.populate_all_magic_menu)
665 666
666 667 def _get_magic_menu(self,menuidentifier, menulabel=None):
667 668 """return a submagic menu by name, and create it if needed
668 669
669 670 parameters:
670 671 -----------
671 672
672 673 menulabel : str
673 674 Label for the menu
674 675
675 676 Will infere the menu name from the identifier at creation if menulabel not given.
676 677 To do so you have too give menuidentifier as a CamelCassedString
677 678 """
678 679 menu = self._magic_menu_dict.get(menuidentifier,None)
679 680 if not menu :
680 681 if not menulabel:
681 682 menulabel = re.sub("([a-zA-Z]+)([A-Z][a-z])","\g<1> \g<2>",menuidentifier)
682 683 menu = QtGui.QMenu(menulabel,self.magic_menu)
683 684 self._magic_menu_dict[menuidentifier]=menu
684 685 self.magic_menu.insertMenu(self.magic_menu_separator,menu)
685 686 return menu
686 687
687 688
688 689
689 690 def init_magic_menu(self):
690 691 self.magic_menu = self.menuBar().addMenu("&Magic")
691 692 self.magic_menu_separator = self.magic_menu.addSeparator()
692 693
693 694 self.all_magic_menu = self._get_magic_menu("AllMagics", menulabel="&All Magics...")
694 695
695 696 # This action should usually not appear as it will be cleared when menu
696 697 # is updated at first kernel response. Though, it is necessary when
697 698 # connecting through X-forwarding, as in this case, the menu is not
698 699 # auto updated, SO DO NOT DELETE.
699 700 self.pop = QtGui.QAction("&Update All Magic Menu ",
700 701 self, triggered=self.update_all_magic_menu)
701 702 self.add_menu_action(self.all_magic_menu, self.pop)
702 703 # we need to populate the 'Magic Menu' once the kernel has answer at
703 704 # least once let's do it immediately, but it's assured to works
704 705 self.pop.trigger()
705 706
706 707 self.reset_action = QtGui.QAction("&Reset",
707 708 self,
708 709 statusTip="Clear all variables from workspace",
709 710 triggered=self.reset_magic_active_frontend)
710 711 self.add_menu_action(self.magic_menu, self.reset_action)
711 712
712 713 self.history_action = QtGui.QAction("&History",
713 714 self,
714 715 statusTip="show command history",
715 716 triggered=self.history_magic_active_frontend)
716 717 self.add_menu_action(self.magic_menu, self.history_action)
717 718
718 719 self.save_action = QtGui.QAction("E&xport History ",
719 720 self,
720 721 statusTip="Export History as Python File",
721 722 triggered=self.save_magic_active_frontend)
722 723 self.add_menu_action(self.magic_menu, self.save_action)
723 724
724 725 self.who_action = QtGui.QAction("&Who",
725 726 self,
726 727 statusTip="List interactive variables",
727 728 triggered=self.who_magic_active_frontend)
728 729 self.add_menu_action(self.magic_menu, self.who_action)
729 730
730 731 self.who_ls_action = QtGui.QAction("Wh&o ls",
731 732 self,
732 733 statusTip="Return a list of interactive variables",
733 734 triggered=self.who_ls_magic_active_frontend)
734 735 self.add_menu_action(self.magic_menu, self.who_ls_action)
735 736
736 737 self.whos_action = QtGui.QAction("Who&s",
737 738 self,
738 739 statusTip="List interactive variables with details",
739 740 triggered=self.whos_magic_active_frontend)
740 741 self.add_menu_action(self.magic_menu, self.whos_action)
741 742
742 743 def init_window_menu(self):
743 744 self.window_menu = self.menuBar().addMenu("&Window")
744 745 if sys.platform == 'darwin':
745 746 # add min/maximize actions to OSX, which lacks default bindings.
746 747 self.minimizeAct = QtGui.QAction("Mini&mize",
747 748 self,
748 749 shortcut="Ctrl+m",
749 750 statusTip="Minimize the window/Restore Normal Size",
750 751 triggered=self.toggleMinimized)
751 752 # maximize is called 'Zoom' on OSX for some reason
752 753 self.maximizeAct = QtGui.QAction("&Zoom",
753 754 self,
754 755 shortcut="Ctrl+Shift+M",
755 756 statusTip="Maximize the window/Restore Normal Size",
756 757 triggered=self.toggleMaximized)
757 758
758 759 self.add_menu_action(self.window_menu, self.minimizeAct)
759 760 self.add_menu_action(self.window_menu, self.maximizeAct)
760 761 self.window_menu.addSeparator()
761 762
762 763 prev_key = "Ctrl+Shift+Left" if sys.platform == 'darwin' else "Ctrl+PgUp"
763 764 self.prev_tab_act = QtGui.QAction("Pre&vious Tab",
764 765 self,
765 766 shortcut=prev_key,
766 767 statusTip="Select previous tab",
767 768 triggered=self.prev_tab)
768 769 self.add_menu_action(self.window_menu, self.prev_tab_act)
769 770
770 771 next_key = "Ctrl+Shift+Right" if sys.platform == 'darwin' else "Ctrl+PgDown"
771 772 self.next_tab_act = QtGui.QAction("Ne&xt Tab",
772 773 self,
773 774 shortcut=next_key,
774 775 statusTip="Select next tab",
775 776 triggered=self.next_tab)
776 777 self.add_menu_action(self.window_menu, self.next_tab_act)
777 778
778 779 def init_help_menu(self):
779 780 # please keep the Help menu in Mac Os even if empty. It will
780 781 # automatically contain a search field to search inside menus and
781 782 # please keep it spelled in English, as long as Qt Doesn't support
782 783 # a QAction.MenuRole like HelpMenuRole otherwise it will lose
783 784 # this search field functionality
784 785
785 786 self.help_menu = self.menuBar().addMenu("&Help")
786 787
787 788
788 789 # Help Menu
789 790
790 791 self.intro_active_frontend_action = QtGui.QAction("&Intro to IPython",
791 792 self,
792 793 triggered=self.intro_active_frontend
793 794 )
794 795 self.add_menu_action(self.help_menu, self.intro_active_frontend_action)
795 796
796 797 self.quickref_active_frontend_action = QtGui.QAction("IPython &Cheat Sheet",
797 798 self,
798 799 triggered=self.quickref_active_frontend
799 800 )
800 801 self.add_menu_action(self.help_menu, self.quickref_active_frontend_action)
801 802
802 803 self.guiref_active_frontend_action = QtGui.QAction("&Qt Console",
803 804 self,
804 805 triggered=self.guiref_active_frontend
805 806 )
806 807 self.add_menu_action(self.help_menu, self.guiref_active_frontend_action)
807 808
808 809 self.onlineHelpAct = QtGui.QAction("Open Online &Help",
809 810 self,
810 811 triggered=self._open_online_help)
811 812 self.add_menu_action(self.help_menu, self.onlineHelpAct)
812 813
813 814 # minimize/maximize/fullscreen actions:
814 815
815 816 def toggle_menu_bar(self):
816 817 menu_bar = self.menuBar()
817 818 if menu_bar.isVisible():
818 819 menu_bar.setVisible(False)
819 820 else:
820 821 menu_bar.setVisible(True)
821 822
822 823 def toggleMinimized(self):
823 824 if not self.isMinimized():
824 825 self.showMinimized()
825 826 else:
826 827 self.showNormal()
827 828
828 829 def _open_online_help(self):
829 830 filename="http://ipython.org/ipython-doc/stable/index.html"
830 831 webbrowser.open(filename, new=1, autoraise=True)
831 832
832 833 def toggleMaximized(self):
833 834 if not self.isMaximized():
834 835 self.showMaximized()
835 836 else:
836 837 self.showNormal()
837 838
838 839 # Min/Max imizing while in full screen give a bug
839 840 # when going out of full screen, at least on OSX
840 841 def toggleFullScreen(self):
841 842 if not self.isFullScreen():
842 843 self.showFullScreen()
843 844 if sys.platform == 'darwin':
844 845 self.maximizeAct.setEnabled(False)
845 846 self.minimizeAct.setEnabled(False)
846 847 else:
847 848 self.showNormal()
848 849 if sys.platform == 'darwin':
849 850 self.maximizeAct.setEnabled(True)
850 851 self.minimizeAct.setEnabled(True)
851 852
852 853 def set_paging_active_frontend(self, paging):
853 854 self.active_frontend._set_paging(paging)
854 855
855 856 def close_active_frontend(self):
856 857 self.close_tab(self.active_frontend)
857 858
858 859 def restart_kernel_active_frontend(self):
859 860 self.active_frontend.request_restart_kernel()
860 861
861 862 def interrupt_kernel_active_frontend(self):
862 863 self.active_frontend.request_interrupt_kernel()
863 864
864 865 def toggle_confirm_restart_active_frontend(self):
865 866 widget = self.active_frontend
866 867 widget.confirm_restart = not widget.confirm_restart
867 868 self.confirm_restart_kernel_action.setChecked(widget.confirm_restart)
868 869
869 870 def update_restart_checkbox(self):
870 871 if self.active_frontend is None:
871 872 return
872 873 widget = self.active_frontend
873 874 self.confirm_restart_kernel_action.setChecked(widget.confirm_restart)
874 875
875 876 def cut_active_frontend(self):
876 877 widget = self.active_frontend
877 878 if widget.can_cut():
878 879 widget.cut()
879 880
880 881 def copy_active_frontend(self):
881 882 widget = self.active_frontend
882 883 widget.copy()
883 884
884 885 def copy_raw_active_frontend(self):
885 886 self.active_frontend._copy_raw_action.trigger()
886 887
887 888 def paste_active_frontend(self):
888 889 widget = self.active_frontend
889 890 if widget.can_paste():
890 891 widget.paste()
891 892
892 893 def undo_active_frontend(self):
893 894 self.active_frontend.undo()
894 895
895 896 def redo_active_frontend(self):
896 897 self.active_frontend.redo()
897 898
898 899 def reset_magic_active_frontend(self):
899 900 self.active_frontend.execute("%reset")
900 901
901 902 def history_magic_active_frontend(self):
902 903 self.active_frontend.execute("%history")
903 904
904 905 def save_magic_active_frontend(self):
905 906 self.active_frontend.save_magic()
906 907
907 908 def clear_magic_active_frontend(self):
908 909 self.active_frontend.execute("%clear")
909 910
910 911 def who_magic_active_frontend(self):
911 912 self.active_frontend.execute("%who")
912 913
913 914 def who_ls_magic_active_frontend(self):
914 915 self.active_frontend.execute("%who_ls")
915 916
916 917 def whos_magic_active_frontend(self):
917 918 self.active_frontend.execute("%whos")
918 919
919 920 def print_action_active_frontend(self):
920 921 self.active_frontend.print_action.trigger()
921 922
922 923 def export_action_active_frontend(self):
923 924 self.active_frontend.export_action.trigger()
924 925
925 926 def select_all_active_frontend(self):
926 927 self.active_frontend.select_all_action.trigger()
927 928
928 929 def increase_font_size_active_frontend(self):
929 930 self.active_frontend.increase_font_size.trigger()
930 931
931 932 def decrease_font_size_active_frontend(self):
932 933 self.active_frontend.decrease_font_size.trigger()
933 934
934 935 def reset_font_size_active_frontend(self):
935 936 self.active_frontend.reset_font_size.trigger()
936 937
937 938 def guiref_active_frontend(self):
938 939 self.active_frontend.execute("%guiref")
939 940
940 941 def intro_active_frontend(self):
941 942 self.active_frontend.execute("?")
942 943
943 944 def quickref_active_frontend(self):
944 945 self.active_frontend.execute("%quickref")
945 946 #---------------------------------------------------------------------------
946 947 # QWidget interface
947 948 #---------------------------------------------------------------------------
948 949
949 950 def closeEvent(self, event):
950 951 """ Forward the close event to every tabs contained by the windows
951 952 """
952 953 if self.tab_widget.count() == 0:
953 954 # no tabs, just close
954 955 event.accept()
955 956 return
956 957 # Do Not loop on the widget count as it change while closing
957 958 title = self.window().windowTitle()
958 959 cancel = QtGui.QMessageBox.Cancel
959 960 okay = QtGui.QMessageBox.Ok
960 961
961 962 if self.confirm_exit:
962 963 if self.tab_widget.count() > 1:
963 964 msg = "Close all tabs, stop all kernels, and Quit?"
964 965 else:
965 966 msg = "Close console, stop kernel, and Quit?"
966 967 info = "Kernels not started here (e.g. notebooks) will be left alone."
967 968 closeall = QtGui.QPushButton("&Quit", self)
968 969 closeall.setShortcut('Q')
969 970 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
970 971 title, msg)
971 972 box.setInformativeText(info)
972 973 box.addButton(cancel)
973 974 box.addButton(closeall, QtGui.QMessageBox.YesRole)
974 975 box.setDefaultButton(closeall)
975 976 box.setEscapeButton(cancel)
976 977 pixmap = QtGui.QPixmap(self._app.icon.pixmap(QtCore.QSize(64,64)))
977 978 box.setIconPixmap(pixmap)
978 979 reply = box.exec_()
979 980 else:
980 981 reply = okay
981 982
982 983 if reply == cancel:
983 984 event.ignore()
984 985 return
985 986 if reply == okay:
986 987 while self.tab_widget.count() >= 1:
987 988 # prevent further confirmations:
988 989 widget = self.active_frontend
989 990 widget._confirm_exit = False
990 991 self.close_tab(widget)
991 992 event.accept()
992 993
General Comments 0
You need to be logged in to leave comments. Login now