##// END OF EJS Templates
%gui qt5
Stefan Zimmermann -
Show More
@@ -1,655 +1,656 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 18 import json
19 19 import sys
20 20 from pprint import pformat
21 21
22 22 # Our own packages
23 23 from IPython.core import magic_arguments, page
24 24 from IPython.core.error import UsageError
25 25 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
26 26 from IPython.utils.text import format_screen, dedent, indent
27 27 from IPython.testing.skipdoctest import skip_doctest
28 28 from IPython.utils.ipstruct import Struct
29 29 from IPython.utils.path import unquote_filename
30 30 from IPython.utils.py3compat import unicode_type
31 31 from IPython.utils.warn import warn, error
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Magics class implementation
35 35 #-----------------------------------------------------------------------------
36 36
37 37 class MagicsDisplay(object):
38 38 def __init__(self, magics_manager):
39 39 self.magics_manager = magics_manager
40 40
41 41 def _lsmagic(self):
42 42 """The main implementation of the %lsmagic"""
43 43 mesc = magic_escapes['line']
44 44 cesc = magic_escapes['cell']
45 45 mman = self.magics_manager
46 46 magics = mman.lsmagic()
47 47 out = ['Available line magics:',
48 48 mesc + (' '+mesc).join(sorted(magics['line'])),
49 49 '',
50 50 'Available cell magics:',
51 51 cesc + (' '+cesc).join(sorted(magics['cell'])),
52 52 '',
53 53 mman.auto_status()]
54 54 return '\n'.join(out)
55 55
56 56 def _repr_pretty_(self, p, cycle):
57 57 p.text(self._lsmagic())
58 58
59 59 def __str__(self):
60 60 return self._lsmagic()
61 61
62 62 def _jsonable(self):
63 63 """turn magics dict into jsonable dict of the same structure
64 64
65 65 replaces object instances with their class names as strings
66 66 """
67 67 magic_dict = {}
68 68 mman = self.magics_manager
69 69 magics = mman.lsmagic()
70 70 for key, subdict in magics.items():
71 71 d = {}
72 72 magic_dict[key] = d
73 73 for name, obj in subdict.items():
74 74 try:
75 75 classname = obj.__self__.__class__.__name__
76 76 except AttributeError:
77 77 classname = 'Other'
78 78
79 79 d[name] = classname
80 80 return magic_dict
81 81
82 82 def _repr_json_(self):
83 83 return json.dumps(self._jsonable())
84 84
85 85
86 86 @magics_class
87 87 class BasicMagics(Magics):
88 88 """Magics that provide central IPython functionality.
89 89
90 90 These are various magics that don't fit into specific categories but that
91 91 are all part of the base 'IPython experience'."""
92 92
93 93 @magic_arguments.magic_arguments()
94 94 @magic_arguments.argument(
95 95 '-l', '--line', action='store_true',
96 96 help="""Create a line magic alias."""
97 97 )
98 98 @magic_arguments.argument(
99 99 '-c', '--cell', action='store_true',
100 100 help="""Create a cell magic alias."""
101 101 )
102 102 @magic_arguments.argument(
103 103 'name',
104 104 help="""Name of the magic to be created."""
105 105 )
106 106 @magic_arguments.argument(
107 107 'target',
108 108 help="""Name of the existing line or cell magic."""
109 109 )
110 110 @line_magic
111 111 def alias_magic(self, line=''):
112 112 """Create an alias for an existing line or cell magic.
113 113
114 114 Examples
115 115 --------
116 116 ::
117 117
118 118 In [1]: %alias_magic t timeit
119 119 Created `%t` as an alias for `%timeit`.
120 120 Created `%%t` as an alias for `%%timeit`.
121 121
122 122 In [2]: %t -n1 pass
123 123 1 loops, best of 3: 954 ns per loop
124 124
125 125 In [3]: %%t -n1
126 126 ...: pass
127 127 ...:
128 128 1 loops, best of 3: 954 ns per loop
129 129
130 130 In [4]: %alias_magic --cell whereami pwd
131 131 UsageError: Cell magic function `%%pwd` not found.
132 132 In [5]: %alias_magic --line whereami pwd
133 133 Created `%whereami` as an alias for `%pwd`.
134 134
135 135 In [6]: %whereami
136 136 Out[6]: u'/home/testuser'
137 137 """
138 138 args = magic_arguments.parse_argstring(self.alias_magic, line)
139 139 shell = self.shell
140 140 mman = self.shell.magics_manager
141 141 escs = ''.join(magic_escapes.values())
142 142
143 143 target = args.target.lstrip(escs)
144 144 name = args.name.lstrip(escs)
145 145
146 146 # Find the requested magics.
147 147 m_line = shell.find_magic(target, 'line')
148 148 m_cell = shell.find_magic(target, 'cell')
149 149 if args.line and m_line is None:
150 150 raise UsageError('Line magic function `%s%s` not found.' %
151 151 (magic_escapes['line'], target))
152 152 if args.cell and m_cell is None:
153 153 raise UsageError('Cell magic function `%s%s` not found.' %
154 154 (magic_escapes['cell'], target))
155 155
156 156 # If --line and --cell are not specified, default to the ones
157 157 # that are available.
158 158 if not args.line and not args.cell:
159 159 if not m_line and not m_cell:
160 160 raise UsageError(
161 161 'No line or cell magic with name `%s` found.' % target
162 162 )
163 163 args.line = bool(m_line)
164 164 args.cell = bool(m_cell)
165 165
166 166 if args.line:
167 167 mman.register_alias(name, target, 'line')
168 168 print('Created `%s%s` as an alias for `%s%s`.' % (
169 169 magic_escapes['line'], name,
170 170 magic_escapes['line'], target))
171 171
172 172 if args.cell:
173 173 mman.register_alias(name, target, 'cell')
174 174 print('Created `%s%s` as an alias for `%s%s`.' % (
175 175 magic_escapes['cell'], name,
176 176 magic_escapes['cell'], target))
177 177
178 178 @line_magic
179 179 def lsmagic(self, parameter_s=''):
180 180 """List currently available magic functions."""
181 181 return MagicsDisplay(self.shell.magics_manager)
182 182
183 183 def _magic_docs(self, brief=False, rest=False):
184 184 """Return docstrings from magic functions."""
185 185 mman = self.shell.magics_manager
186 186 docs = mman.lsmagic_docs(brief, missing='No documentation')
187 187
188 188 if rest:
189 189 format_string = '**%s%s**::\n\n%s\n\n'
190 190 else:
191 191 format_string = '%s%s:\n%s\n'
192 192
193 193 return ''.join(
194 194 [format_string % (magic_escapes['line'], fname,
195 195 indent(dedent(fndoc)))
196 196 for fname, fndoc in sorted(docs['line'].items())]
197 197 +
198 198 [format_string % (magic_escapes['cell'], fname,
199 199 indent(dedent(fndoc)))
200 200 for fname, fndoc in sorted(docs['cell'].items())]
201 201 )
202 202
203 203 @line_magic
204 204 def magic(self, parameter_s=''):
205 205 """Print information about the magic function system.
206 206
207 207 Supported formats: -latex, -brief, -rest
208 208 """
209 209
210 210 mode = ''
211 211 try:
212 212 mode = parameter_s.split()[0][1:]
213 213 if mode == 'rest':
214 214 rest_docs = []
215 215 except IndexError:
216 216 pass
217 217
218 218 brief = (mode == 'brief')
219 219 rest = (mode == 'rest')
220 220 magic_docs = self._magic_docs(brief, rest)
221 221
222 222 if mode == 'latex':
223 223 print(self.format_latex(magic_docs))
224 224 return
225 225 else:
226 226 magic_docs = format_screen(magic_docs)
227 227
228 228 out = ["""
229 229 IPython's 'magic' functions
230 230 ===========================
231 231
232 232 The magic function system provides a series of functions which allow you to
233 233 control the behavior of IPython itself, plus a lot of system-type
234 234 features. There are two kinds of magics, line-oriented and cell-oriented.
235 235
236 236 Line magics are prefixed with the % character and work much like OS
237 237 command-line calls: they get as an argument the rest of the line, where
238 238 arguments are passed without parentheses or quotes. For example, this will
239 239 time the given statement::
240 240
241 241 %timeit range(1000)
242 242
243 243 Cell magics are prefixed with a double %%, and they are functions that get as
244 244 an argument not only the rest of the line, but also the lines below it in a
245 245 separate argument. These magics are called with two arguments: the rest of the
246 246 call line and the body of the cell, consisting of the lines below the first.
247 247 For example::
248 248
249 249 %%timeit x = numpy.random.randn((100, 100))
250 250 numpy.linalg.svd(x)
251 251
252 252 will time the execution of the numpy svd routine, running the assignment of x
253 253 as part of the setup phase, which is not timed.
254 254
255 255 In a line-oriented client (the terminal or Qt console IPython), starting a new
256 256 input with %% will automatically enter cell mode, and IPython will continue
257 257 reading input until a blank line is given. In the notebook, simply type the
258 258 whole cell as one entity, but keep in mind that the %% escape can only be at
259 259 the very start of the cell.
260 260
261 261 NOTE: If you have 'automagic' enabled (via the command line option or with the
262 262 %automagic function), you don't need to type in the % explicitly for line
263 263 magics; cell magics always require an explicit '%%' escape. By default,
264 264 IPython ships with automagic on, so you should only rarely need the % escape.
265 265
266 266 Example: typing '%cd mydir' (without the quotes) changes you working directory
267 267 to 'mydir', if it exists.
268 268
269 269 For a list of the available magic functions, use %lsmagic. For a description
270 270 of any of them, type %magic_name?, e.g. '%cd?'.
271 271
272 272 Currently the magic system has the following functions:""",
273 273 magic_docs,
274 274 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
275 275 str(self.lsmagic()),
276 276 ]
277 277 page.page('\n'.join(out))
278 278
279 279
280 280 @line_magic
281 281 def page(self, parameter_s=''):
282 282 """Pretty print the object and display it through a pager.
283 283
284 284 %page [options] OBJECT
285 285
286 286 If no object is given, use _ (last output).
287 287
288 288 Options:
289 289
290 290 -r: page str(object), don't pretty-print it."""
291 291
292 292 # After a function contributed by Olivier Aubert, slightly modified.
293 293
294 294 # Process options/args
295 295 opts, args = self.parse_options(parameter_s, 'r')
296 296 raw = 'r' in opts
297 297
298 298 oname = args and args or '_'
299 299 info = self.shell._ofind(oname)
300 300 if info['found']:
301 301 txt = (raw and str or pformat)( info['obj'] )
302 302 page.page(txt)
303 303 else:
304 304 print('Object `%s` not found' % oname)
305 305
306 306 @line_magic
307 307 def profile(self, parameter_s=''):
308 308 """Print your currently active IPython profile.
309 309
310 310 See Also
311 311 --------
312 312 prun : run code using the Python profiler
313 313 (:meth:`~IPython.core.magics.execution.ExecutionMagics.prun`)
314 314 """
315 315 warn("%profile is now deprecated. Please use get_ipython().profile instead.")
316 316 from IPython.core.application import BaseIPythonApplication
317 317 if BaseIPythonApplication.initialized():
318 318 print(BaseIPythonApplication.instance().profile)
319 319 else:
320 320 error("profile is an application-level value, but you don't appear to be in an IPython application")
321 321
322 322 @line_magic
323 323 def pprint(self, parameter_s=''):
324 324 """Toggle pretty printing on/off."""
325 325 ptformatter = self.shell.display_formatter.formatters['text/plain']
326 326 ptformatter.pprint = bool(1 - ptformatter.pprint)
327 327 print('Pretty printing has been turned',
328 328 ['OFF','ON'][ptformatter.pprint])
329 329
330 330 @line_magic
331 331 def colors(self, parameter_s=''):
332 332 """Switch color scheme for prompts, info system and exception handlers.
333 333
334 334 Currently implemented schemes: NoColor, Linux, LightBG.
335 335
336 336 Color scheme names are not case-sensitive.
337 337
338 338 Examples
339 339 --------
340 340 To get a plain black and white terminal::
341 341
342 342 %colors nocolor
343 343 """
344 344 def color_switch_err(name):
345 345 warn('Error changing %s color schemes.\n%s' %
346 346 (name, sys.exc_info()[1]))
347 347
348 348
349 349 new_scheme = parameter_s.strip()
350 350 if not new_scheme:
351 351 raise UsageError(
352 352 "%colors: you must specify a color scheme. See '%colors?'")
353 353 # local shortcut
354 354 shell = self.shell
355 355
356 356 import IPython.utils.rlineimpl as readline
357 357
358 358 if not shell.colors_force and \
359 359 not readline.have_readline and \
360 360 (sys.platform == "win32" or sys.platform == "cli"):
361 361 msg = """\
362 362 Proper color support under MS Windows requires the pyreadline library.
363 363 You can find it at:
364 364 http://ipython.org/pyreadline.html
365 365 Gary's readline needs the ctypes module, from:
366 366 http://starship.python.net/crew/theller/ctypes
367 367 (Note that ctypes is already part of Python versions 2.5 and newer).
368 368
369 369 Defaulting color scheme to 'NoColor'"""
370 370 new_scheme = 'NoColor'
371 371 warn(msg)
372 372
373 373 # readline option is 0
374 374 if not shell.colors_force and not shell.has_readline:
375 375 new_scheme = 'NoColor'
376 376
377 377 # Set prompt colors
378 378 try:
379 379 shell.prompt_manager.color_scheme = new_scheme
380 380 except:
381 381 color_switch_err('prompt')
382 382 else:
383 383 shell.colors = \
384 384 shell.prompt_manager.color_scheme_table.active_scheme_name
385 385 # Set exception colors
386 386 try:
387 387 shell.InteractiveTB.set_colors(scheme = new_scheme)
388 388 shell.SyntaxTB.set_colors(scheme = new_scheme)
389 389 except:
390 390 color_switch_err('exception')
391 391
392 392 # Set info (for 'object?') colors
393 393 if shell.color_info:
394 394 try:
395 395 shell.inspector.set_active_scheme(new_scheme)
396 396 except:
397 397 color_switch_err('object inspector')
398 398 else:
399 399 shell.inspector.set_active_scheme('NoColor')
400 400
401 401 @line_magic
402 402 def xmode(self, parameter_s=''):
403 403 """Switch modes for the exception handlers.
404 404
405 405 Valid modes: Plain, Context and Verbose.
406 406
407 407 If called without arguments, acts as a toggle."""
408 408
409 409 def xmode_switch_err(name):
410 410 warn('Error changing %s exception modes.\n%s' %
411 411 (name,sys.exc_info()[1]))
412 412
413 413 shell = self.shell
414 414 new_mode = parameter_s.strip().capitalize()
415 415 try:
416 416 shell.InteractiveTB.set_mode(mode=new_mode)
417 417 print('Exception reporting mode:',shell.InteractiveTB.mode)
418 418 except:
419 419 xmode_switch_err('user')
420 420
421 421 @line_magic
422 422 def quickref(self,arg):
423 423 """ Show a quick reference sheet """
424 424 from IPython.core.usage import quick_reference
425 425 qr = quick_reference + self._magic_docs(brief=True)
426 426 page.page(qr)
427 427
428 428 @line_magic
429 429 def doctest_mode(self, parameter_s=''):
430 430 """Toggle doctest mode on and off.
431 431
432 432 This mode is intended to make IPython behave as much as possible like a
433 433 plain Python shell, from the perspective of how its prompts, exceptions
434 434 and output look. This makes it easy to copy and paste parts of a
435 435 session into doctests. It does so by:
436 436
437 437 - Changing the prompts to the classic ``>>>`` ones.
438 438 - Changing the exception reporting mode to 'Plain'.
439 439 - Disabling pretty-printing of output.
440 440
441 441 Note that IPython also supports the pasting of code snippets that have
442 442 leading '>>>' and '...' prompts in them. This means that you can paste
443 443 doctests from files or docstrings (even if they have leading
444 444 whitespace), and the code will execute correctly. You can then use
445 445 '%history -t' to see the translated history; this will give you the
446 446 input after removal of all the leading prompts and whitespace, which
447 447 can be pasted back into an editor.
448 448
449 449 With these features, you can switch into this mode easily whenever you
450 450 need to do testing and changes to doctests, without having to leave
451 451 your existing IPython session.
452 452 """
453 453
454 454 # Shorthands
455 455 shell = self.shell
456 456 pm = shell.prompt_manager
457 457 meta = shell.meta
458 458 disp_formatter = self.shell.display_formatter
459 459 ptformatter = disp_formatter.formatters['text/plain']
460 460 # dstore is a data store kept in the instance metadata bag to track any
461 461 # changes we make, so we can undo them later.
462 462 dstore = meta.setdefault('doctest_mode',Struct())
463 463 save_dstore = dstore.setdefault
464 464
465 465 # save a few values we'll need to recover later
466 466 mode = save_dstore('mode',False)
467 467 save_dstore('rc_pprint',ptformatter.pprint)
468 468 save_dstore('xmode',shell.InteractiveTB.mode)
469 469 save_dstore('rc_separate_out',shell.separate_out)
470 470 save_dstore('rc_separate_out2',shell.separate_out2)
471 471 save_dstore('rc_prompts_pad_left',pm.justify)
472 472 save_dstore('rc_separate_in',shell.separate_in)
473 473 save_dstore('rc_active_types',disp_formatter.active_types)
474 474 save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template))
475 475
476 476 if mode == False:
477 477 # turn on
478 478 pm.in_template = '>>> '
479 479 pm.in2_template = '... '
480 480 pm.out_template = ''
481 481
482 482 # Prompt separators like plain python
483 483 shell.separate_in = ''
484 484 shell.separate_out = ''
485 485 shell.separate_out2 = ''
486 486
487 487 pm.justify = False
488 488
489 489 ptformatter.pprint = False
490 490 disp_formatter.active_types = ['text/plain']
491 491
492 492 shell.magic('xmode Plain')
493 493 else:
494 494 # turn off
495 495 pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates
496 496
497 497 shell.separate_in = dstore.rc_separate_in
498 498
499 499 shell.separate_out = dstore.rc_separate_out
500 500 shell.separate_out2 = dstore.rc_separate_out2
501 501
502 502 pm.justify = dstore.rc_prompts_pad_left
503 503
504 504 ptformatter.pprint = dstore.rc_pprint
505 505 disp_formatter.active_types = dstore.rc_active_types
506 506
507 507 shell.magic('xmode ' + dstore.xmode)
508 508
509 509 # Store new mode and inform
510 510 dstore.mode = bool(1-int(mode))
511 511 mode_label = ['OFF','ON'][dstore.mode]
512 512 print('Doctest mode is:', mode_label)
513 513
514 514 @line_magic
515 515 def gui(self, parameter_s=''):
516 516 """Enable or disable IPython GUI event loop integration.
517 517
518 518 %gui [GUINAME]
519 519
520 520 This magic replaces IPython's threaded shells that were activated
521 521 using the (pylab/wthread/etc.) command line flags. GUI toolkits
522 522 can now be enabled at runtime and keyboard
523 523 interrupts should work without any problems. The following toolkits
524 524 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
525 525
526 526 %gui wx # enable wxPython event loop integration
527 527 %gui qt4|qt # enable PyQt4 event loop integration
528 %gui qt5 # enable PyQt5 event loop integration
528 529 %gui gtk # enable PyGTK event loop integration
529 530 %gui gtk3 # enable Gtk3 event loop integration
530 531 %gui tk # enable Tk event loop integration
531 532 %gui osx # enable Cocoa event loop integration
532 533 # (requires %matplotlib 1.1)
533 534 %gui # disable all event loop integration
534 535
535 536 WARNING: after any of these has been called you can simply create
536 537 an application object, but DO NOT start the event loop yourself, as
537 538 we have already handled that.
538 539 """
539 540 opts, arg = self.parse_options(parameter_s, '')
540 541 if arg=='': arg = None
541 542 try:
542 543 return self.shell.enable_gui(arg)
543 544 except Exception as e:
544 545 # print simple error message, rather than traceback if we can't
545 546 # hook up the GUI
546 547 error(str(e))
547 548
548 549 @skip_doctest
549 550 @line_magic
550 551 def precision(self, s=''):
551 552 """Set floating point precision for pretty printing.
552 553
553 554 Can set either integer precision or a format string.
554 555
555 556 If numpy has been imported and precision is an int,
556 557 numpy display precision will also be set, via ``numpy.set_printoptions``.
557 558
558 559 If no argument is given, defaults will be restored.
559 560
560 561 Examples
561 562 --------
562 563 ::
563 564
564 565 In [1]: from math import pi
565 566
566 567 In [2]: %precision 3
567 568 Out[2]: u'%.3f'
568 569
569 570 In [3]: pi
570 571 Out[3]: 3.142
571 572
572 573 In [4]: %precision %i
573 574 Out[4]: u'%i'
574 575
575 576 In [5]: pi
576 577 Out[5]: 3
577 578
578 579 In [6]: %precision %e
579 580 Out[6]: u'%e'
580 581
581 582 In [7]: pi**10
582 583 Out[7]: 9.364805e+04
583 584
584 585 In [8]: %precision
585 586 Out[8]: u'%r'
586 587
587 588 In [9]: pi**10
588 589 Out[9]: 93648.047476082982
589 590 """
590 591 ptformatter = self.shell.display_formatter.formatters['text/plain']
591 592 ptformatter.float_precision = s
592 593 return ptformatter.float_format
593 594
594 595 @magic_arguments.magic_arguments()
595 596 @magic_arguments.argument(
596 597 '-e', '--export', action='store_true', default=False,
597 598 help='Export IPython history as a notebook. The filename argument '
598 599 'is used to specify the notebook name and format. For example '
599 600 'a filename of notebook.ipynb will result in a notebook name '
600 601 'of "notebook" and a format of "json". Likewise using a ".py" '
601 602 'file extension will write the notebook as a Python script'
602 603 )
603 604 @magic_arguments.argument(
604 605 '-f', '--format',
605 606 help='Convert an existing IPython notebook to a new format. This option '
606 607 'specifies the new format and can have the values: json, py. '
607 608 'The target filename is chosen automatically based on the new '
608 609 'format. The filename argument gives the name of the source file.'
609 610 )
610 611 @magic_arguments.argument(
611 612 'filename', type=unicode_type,
612 613 help='Notebook name or filename'
613 614 )
614 615 @line_magic
615 616 def notebook(self, s):
616 617 """Export and convert IPython notebooks.
617 618
618 619 This function can export the current IPython history to a notebook file
619 620 or can convert an existing notebook file into a different format. For
620 621 example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
621 622 To export the history to "foo.py" do "%notebook -e foo.py". To convert
622 623 "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
623 624 formats include (json/ipynb, py).
624 625 """
625 626 args = magic_arguments.parse_argstring(self.notebook, s)
626 627
627 628 from IPython.nbformat import current
628 629 args.filename = unquote_filename(args.filename)
629 630 if args.export:
630 631 fname, name, format = current.parse_filename(args.filename)
631 632 cells = []
632 633 hist = list(self.shell.history_manager.get_range())
633 634 for session, prompt_number, input in hist[:-1]:
634 635 cells.append(current.new_code_cell(prompt_number=prompt_number,
635 636 input=input))
636 637 worksheet = current.new_worksheet(cells=cells)
637 638 nb = current.new_notebook(name=name,worksheets=[worksheet])
638 639 with io.open(fname, 'w', encoding='utf-8') as f:
639 640 current.write(nb, f, format);
640 641 elif args.format is not None:
641 642 old_fname, old_name, old_format = current.parse_filename(args.filename)
642 643 new_format = args.format
643 644 if new_format == u'xml':
644 645 raise ValueError('Notebooks cannot be written as xml.')
645 646 elif new_format == u'ipynb' or new_format == u'json':
646 647 new_fname = old_name + u'.ipynb'
647 648 new_format = u'json'
648 649 elif new_format == u'py':
649 650 new_fname = old_name + u'.py'
650 651 else:
651 652 raise ValueError('Invalid notebook format: %s' % new_format)
652 653 with io.open(old_fname, 'r', encoding='utf-8') as f:
653 654 nb = current.read(f, old_format)
654 655 with io.open(new_fname, 'w', encoding='utf-8') as f:
655 656 current.write(nb, f, new_format)
@@ -1,569 +1,577 b''
1 1 # coding: utf-8
2 2 """
3 3 Inputhook management for GUI event loop integration.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
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 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 try:
18 18 import ctypes
19 19 except ImportError:
20 20 ctypes = None
21 21 except SystemError: # IronPython issue, 2/8/2014
22 22 ctypes = None
23 23 import os
24 24 import sys
25 25 from distutils.version import LooseVersion as V
26 26
27 27 from IPython.utils.warn import warn
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Constants
31 31 #-----------------------------------------------------------------------------
32 32
33 33 # Constants for identifying the GUI toolkits.
34 34 GUI_WX = 'wx'
35 35 GUI_QT = 'qt'
36 36 GUI_QT4 = 'qt4'
37 37 GUI_GTK = 'gtk'
38 38 GUI_TK = 'tk'
39 39 GUI_OSX = 'osx'
40 40 GUI_GLUT = 'glut'
41 41 GUI_PYGLET = 'pyglet'
42 42 GUI_GTK3 = 'gtk3'
43 43 GUI_NONE = 'none' # i.e. disable
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Utilities
47 47 #-----------------------------------------------------------------------------
48 48
49 49 def _stdin_ready_posix():
50 50 """Return True if there's something to read on stdin (posix version)."""
51 51 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
52 52 return bool(infds)
53 53
54 54 def _stdin_ready_nt():
55 55 """Return True if there's something to read on stdin (nt version)."""
56 56 return msvcrt.kbhit()
57 57
58 58 def _stdin_ready_other():
59 59 """Return True, assuming there's something to read on stdin."""
60 60 return True #
61 61
62 62
63 63 def _ignore_CTRL_C_posix():
64 64 """Ignore CTRL+C (SIGINT)."""
65 65 signal.signal(signal.SIGINT, signal.SIG_IGN)
66 66
67 67 def _allow_CTRL_C_posix():
68 68 """Take CTRL+C into account (SIGINT)."""
69 69 signal.signal(signal.SIGINT, signal.default_int_handler)
70 70
71 71 def _ignore_CTRL_C_other():
72 72 """Ignore CTRL+C (not implemented)."""
73 73 pass
74 74
75 75 def _allow_CTRL_C_other():
76 76 """Take CTRL+C into account (not implemented)."""
77 77 pass
78 78
79 79 if os.name == 'posix':
80 80 import select
81 81 import signal
82 82 stdin_ready = _stdin_ready_posix
83 83 ignore_CTRL_C = _ignore_CTRL_C_posix
84 84 allow_CTRL_C = _allow_CTRL_C_posix
85 85 elif os.name == 'nt':
86 86 import msvcrt
87 87 stdin_ready = _stdin_ready_nt
88 88 ignore_CTRL_C = _ignore_CTRL_C_other
89 89 allow_CTRL_C = _allow_CTRL_C_other
90 90 else:
91 91 stdin_ready = _stdin_ready_other
92 92 ignore_CTRL_C = _ignore_CTRL_C_other
93 93 allow_CTRL_C = _allow_CTRL_C_other
94 94
95 95
96 96 #-----------------------------------------------------------------------------
97 97 # Main InputHookManager class
98 98 #-----------------------------------------------------------------------------
99 99
100 100
101 101 class InputHookManager(object):
102 102 """Manage PyOS_InputHook for different GUI toolkits.
103 103
104 104 This class installs various hooks under ``PyOSInputHook`` to handle
105 105 GUI event loop integration.
106 106 """
107 107
108 108 def __init__(self):
109 109 if ctypes is None:
110 110 warn("IPython GUI event loop requires ctypes, %gui will not be available")
111 111 return
112 112 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
113 113 self.guihooks = {}
114 114 self.aliases = {}
115 115 self.apps = {}
116 116 self._reset()
117 117
118 118 def _reset(self):
119 119 self._callback_pyfunctype = None
120 120 self._callback = None
121 121 self._installed = False
122 122 self._current_gui = None
123 123
124 124 def get_pyos_inputhook(self):
125 125 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
126 126 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
127 127
128 128 def get_pyos_inputhook_as_func(self):
129 129 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
130 130 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
131 131
132 132 def set_inputhook(self, callback):
133 133 """Set PyOS_InputHook to callback and return the previous one."""
134 134 # On platforms with 'readline' support, it's all too likely to
135 135 # have a KeyboardInterrupt signal delivered *even before* an
136 136 # initial ``try:`` clause in the callback can be executed, so
137 137 # we need to disable CTRL+C in this situation.
138 138 ignore_CTRL_C()
139 139 self._callback = callback
140 140 self._callback_pyfunctype = self.PYFUNC(callback)
141 141 pyos_inputhook_ptr = self.get_pyos_inputhook()
142 142 original = self.get_pyos_inputhook_as_func()
143 143 pyos_inputhook_ptr.value = \
144 144 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
145 145 self._installed = True
146 146 return original
147 147
148 148 def clear_inputhook(self, app=None):
149 149 """Set PyOS_InputHook to NULL and return the previous one.
150 150
151 151 Parameters
152 152 ----------
153 153 app : optional, ignored
154 154 This parameter is allowed only so that clear_inputhook() can be
155 155 called with a similar interface as all the ``enable_*`` methods. But
156 156 the actual value of the parameter is ignored. This uniform interface
157 157 makes it easier to have user-level entry points in the main IPython
158 158 app like :meth:`enable_gui`."""
159 159 pyos_inputhook_ptr = self.get_pyos_inputhook()
160 160 original = self.get_pyos_inputhook_as_func()
161 161 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
162 162 allow_CTRL_C()
163 163 self._reset()
164 164 return original
165 165
166 166 def clear_app_refs(self, gui=None):
167 167 """Clear IPython's internal reference to an application instance.
168 168
169 169 Whenever we create an app for a user on qt4 or wx, we hold a
170 170 reference to the app. This is needed because in some cases bad things
171 171 can happen if a user doesn't hold a reference themselves. This
172 172 method is provided to clear the references we are holding.
173 173
174 174 Parameters
175 175 ----------
176 176 gui : None or str
177 177 If None, clear all app references. If ('wx', 'qt4') clear
178 178 the app for that toolkit. References are not held for gtk or tk
179 179 as those toolkits don't have the notion of an app.
180 180 """
181 181 if gui is None:
182 182 self.apps = {}
183 183 elif gui in self.apps:
184 184 del self.apps[gui]
185 185
186 186 def register(self, toolkitname, *aliases):
187 187 """Register a class to provide the event loop for a given GUI.
188 188
189 189 This is intended to be used as a class decorator. It should be passed
190 190 the names with which to register this GUI integration. The classes
191 191 themselves should subclass :class:`InputHookBase`.
192 192
193 193 ::
194 194
195 195 @inputhook_manager.register('qt')
196 196 class QtInputHook(InputHookBase):
197 197 def enable(self, app=None):
198 198 ...
199 199 """
200 200 def decorator(cls):
201 201 inst = cls(self)
202 202 self.guihooks[toolkitname] = inst
203 203 for a in aliases:
204 204 self.aliases[a] = toolkitname
205 205 return cls
206 206 return decorator
207 207
208 208 def current_gui(self):
209 209 """Return a string indicating the currently active GUI or None."""
210 210 return self._current_gui
211 211
212 212 def enable_gui(self, gui=None, app=None):
213 213 """Switch amongst GUI input hooks by name.
214 214
215 215 This is a higher level method than :meth:`set_inputhook` - it uses the
216 216 GUI name to look up a registered object which enables the input hook
217 217 for that GUI.
218 218
219 219 Parameters
220 220 ----------
221 221 gui : optional, string or None
222 222 If None (or 'none'), clears input hook, otherwise it must be one
223 223 of the recognized GUI names (see ``GUI_*`` constants in module).
224 224
225 225 app : optional, existing application object.
226 226 For toolkits that have the concept of a global app, you can supply an
227 227 existing one. If not given, the toolkit will be probed for one, and if
228 228 none is found, a new one will be created. Note that GTK does not have
229 229 this concept, and passing an app if ``gui=="GTK"`` will raise an error.
230 230
231 231 Returns
232 232 -------
233 233 The output of the underlying gui switch routine, typically the actual
234 234 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
235 235 one.
236 236 """
237 237 if gui in (None, GUI_NONE):
238 238 return self.disable_gui()
239 239
240 240 if gui in self.aliases:
241 241 return self.enable_gui(self.aliases[gui], app)
242 242
243 243 try:
244 244 gui_hook = self.guihooks[gui]
245 245 except KeyError:
246 246 e = "Invalid GUI request {!r}, valid ones are: {}"
247 247 raise ValueError(e.format(gui, ', '.join(self.guihooks)))
248 248 self._current_gui = gui
249 249 return gui_hook.enable(app)
250 250
251 251 def disable_gui(self):
252 252 """Disable GUI event loop integration.
253 253
254 254 If an application was registered, this sets its ``_in_event_loop``
255 255 attribute to False. It then calls :meth:`clear_inputhook`.
256 256 """
257 257 gui = self._current_gui
258 258 if gui in self.apps:
259 259 self.apps[gui]._in_event_loop = False
260 260 return self.clear_inputhook()
261 261
262 262 class InputHookBase(object):
263 263 """Base class for input hooks for specific toolkits.
264 264
265 265 Subclasses should define an :meth:`enable` method with one argument, ``app``,
266 266 which will either be an instance of the toolkit's application class, or None.
267 267 They may also define a :meth:`disable` method with no arguments.
268 268 """
269 269 def __init__(self, manager):
270 270 self.manager = manager
271 271
272 272 def disable(self):
273 273 pass
274 274
275 275 inputhook_manager = InputHookManager()
276 276
277 277 @inputhook_manager.register('wx')
278 278 class WxInputHook(InputHookBase):
279 279 def enable(self, app=None):
280 280 """Enable event loop integration with wxPython.
281 281
282 282 Parameters
283 283 ----------
284 284 app : WX Application, optional.
285 285 Running application to use. If not given, we probe WX for an
286 286 existing application object, and create a new one if none is found.
287 287
288 288 Notes
289 289 -----
290 290 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
291 291 the wxPython to integrate with terminal based applications like
292 292 IPython.
293 293
294 294 If ``app`` is not given we probe for an existing one, and return it if
295 295 found. If no existing app is found, we create an :class:`wx.App` as
296 296 follows::
297 297
298 298 import wx
299 299 app = wx.App(redirect=False, clearSigInt=False)
300 300 """
301 301 import wx
302 302
303 303 wx_version = V(wx.__version__).version
304 304
305 305 if wx_version < [2, 8]:
306 306 raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
307 307
308 308 from IPython.lib.inputhookwx import inputhook_wx
309 309 from IPython.external.appnope import nope
310 310 self.manager.set_inputhook(inputhook_wx)
311 311 nope()
312 312
313 313 import wx
314 314 if app is None:
315 315 app = wx.GetApp()
316 316 if app is None:
317 317 app = wx.App(redirect=False, clearSigInt=False)
318 318 app._in_event_loop = True
319 319 self.manager.apps[GUI_WX] = app
320 320 return app
321 321
322 322 def disable(self):
323 323 """Disable event loop integration with wxPython.
324 324
325 325 This restores appnapp on OS X
326 326 """
327 327 from IPython.external.appnope import nap
328 328 nap()
329 329
330 330 @inputhook_manager.register('qt', 'qt4')
331 331 class Qt4InputHook(InputHookBase):
332 332 def enable(self, app=None):
333 333 """Enable event loop integration with PyQt4.
334 334
335 335 Parameters
336 336 ----------
337 337 app : Qt Application, optional.
338 338 Running application to use. If not given, we probe Qt for an
339 339 existing application object, and create a new one if none is found.
340 340
341 341 Notes
342 342 -----
343 343 This methods sets the PyOS_InputHook for PyQt4, which allows
344 344 the PyQt4 to integrate with terminal based applications like
345 345 IPython.
346 346
347 347 If ``app`` is not given we probe for an existing one, and return it if
348 348 found. If no existing app is found, we create an :class:`QApplication`
349 349 as follows::
350 350
351 351 from PyQt4 import QtCore
352 352 app = QtGui.QApplication(sys.argv)
353 353 """
354 354 from IPython.lib.inputhookqt4 import create_inputhook_qt4
355 355 from IPython.external.appnope import nope
356 356 app, inputhook_qt4 = create_inputhook_qt4(self, app)
357 357 self.manager.set_inputhook(inputhook_qt4)
358 358 nope()
359 359
360 360 app._in_event_loop = True
361 361 self.manager.apps[GUI_QT4] = app
362 362 return app
363 363
364 364 def disable_qt4(self):
365 365 """Disable event loop integration with PyQt4.
366 366
367 367 This restores appnapp on OS X
368 368 """
369 369 from IPython.external.appnope import nap
370 370 nap()
371 371
372
373 @inputhook_manager.register('qt5')
374 class Qt5InputHook(Qt4InputHook):
375 def enable(self, app=None):
376 os.environ['QT_API'] = 'pyqt5'
377 return Qt4InputHook.enable(self, app)
378
379
372 380 @inputhook_manager.register('gtk')
373 381 class GtkInputHook(InputHookBase):
374 382 def enable(self, app=None):
375 383 """Enable event loop integration with PyGTK.
376 384
377 385 Parameters
378 386 ----------
379 387 app : ignored
380 388 Ignored, it's only a placeholder to keep the call signature of all
381 389 gui activation methods consistent, which simplifies the logic of
382 390 supporting magics.
383 391
384 392 Notes
385 393 -----
386 394 This methods sets the PyOS_InputHook for PyGTK, which allows
387 395 the PyGTK to integrate with terminal based applications like
388 396 IPython.
389 397 """
390 398 import gtk
391 399 try:
392 400 gtk.set_interactive(True)
393 401 except AttributeError:
394 402 # For older versions of gtk, use our own ctypes version
395 403 from IPython.lib.inputhookgtk import inputhook_gtk
396 404 self.manager.set_inputhook(inputhook_gtk)
397 405
398 406
399 407 @inputhook_manager.register('tk')
400 408 class TkInputHook(InputHookBase):
401 409 def enable(self, app=None):
402 410 """Enable event loop integration with Tk.
403 411
404 412 Parameters
405 413 ----------
406 414 app : toplevel :class:`Tkinter.Tk` widget, optional.
407 415 Running toplevel widget to use. If not given, we probe Tk for an
408 416 existing one, and create a new one if none is found.
409 417
410 418 Notes
411 419 -----
412 420 If you have already created a :class:`Tkinter.Tk` object, the only
413 421 thing done by this method is to register with the
414 422 :class:`InputHookManager`, since creating that object automatically
415 423 sets ``PyOS_InputHook``.
416 424 """
417 425 if app is None:
418 426 try:
419 427 from tkinter import Tk # Py 3
420 428 except ImportError:
421 429 from Tkinter import Tk # Py 2
422 430 app = Tk()
423 431 app.withdraw()
424 432 self.manager.apps[GUI_TK] = app
425 433 return app
426 434
427 435
428 436 @inputhook_manager.register('glut')
429 437 class GlutInputHook(InputHookBase):
430 438 def enable(self, app=None):
431 439 """Enable event loop integration with GLUT.
432 440
433 441 Parameters
434 442 ----------
435 443
436 444 app : ignored
437 445 Ignored, it's only a placeholder to keep the call signature of all
438 446 gui activation methods consistent, which simplifies the logic of
439 447 supporting magics.
440 448
441 449 Notes
442 450 -----
443 451
444 452 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
445 453 integrate with terminal based applications like IPython. Due to GLUT
446 454 limitations, it is currently not possible to start the event loop
447 455 without first creating a window. You should thus not create another
448 456 window but use instead the created one. See 'gui-glut.py' in the
449 457 docs/examples/lib directory.
450 458
451 459 The default screen mode is set to:
452 460 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
453 461 """
454 462
455 463 import OpenGL.GLUT as glut
456 464 from IPython.lib.inputhookglut import glut_display_mode, \
457 465 glut_close, glut_display, \
458 466 glut_idle, inputhook_glut
459 467
460 468 if GUI_GLUT not in self.manager.apps:
461 469 glut.glutInit( sys.argv )
462 470 glut.glutInitDisplayMode( glut_display_mode )
463 471 # This is specific to freeglut
464 472 if bool(glut.glutSetOption):
465 473 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
466 474 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
467 475 glut.glutCreateWindow( sys.argv[0] )
468 476 glut.glutReshapeWindow( 1, 1 )
469 477 glut.glutHideWindow( )
470 478 glut.glutWMCloseFunc( glut_close )
471 479 glut.glutDisplayFunc( glut_display )
472 480 glut.glutIdleFunc( glut_idle )
473 481 else:
474 482 glut.glutWMCloseFunc( glut_close )
475 483 glut.glutDisplayFunc( glut_display )
476 484 glut.glutIdleFunc( glut_idle)
477 485 self.manager.set_inputhook( inputhook_glut )
478 486 self.manager.apps[GUI_GLUT] = True
479 487
480 488
481 489 def disable(self):
482 490 """Disable event loop integration with glut.
483 491
484 492 This sets PyOS_InputHook to NULL and set the display function to a
485 493 dummy one and set the timer to a dummy timer that will be triggered
486 494 very far in the future.
487 495 """
488 496 import OpenGL.GLUT as glut
489 497 from glut_support import glutMainLoopEvent
490 498
491 499 glut.glutHideWindow() # This is an event to be processed below
492 500 glutMainLoopEvent()
493 501 super(GlutInputHook, self).disable()
494 502
495 503 @inputhook_manager.register('pyglet')
496 504 class PygletInputHook(InputHookBase):
497 505 def enable(self, app=None):
498 506 """Enable event loop integration with pyglet.
499 507
500 508 Parameters
501 509 ----------
502 510 app : ignored
503 511 Ignored, it's only a placeholder to keep the call signature of all
504 512 gui activation methods consistent, which simplifies the logic of
505 513 supporting magics.
506 514
507 515 Notes
508 516 -----
509 517 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
510 518 pyglet to integrate with terminal based applications like
511 519 IPython.
512 520
513 521 """
514 522 from IPython.lib.inputhookpyglet import inputhook_pyglet
515 523 self.manager.set_inputhook(inputhook_pyglet)
516 524 return app
517 525
518 526
519 527 @inputhook_manager.register('gtk3')
520 528 class Gtk3InputHook(InputHookBase):
521 529 def enable(self, app=None):
522 530 """Enable event loop integration with Gtk3 (gir bindings).
523 531
524 532 Parameters
525 533 ----------
526 534 app : ignored
527 535 Ignored, it's only a placeholder to keep the call signature of all
528 536 gui activation methods consistent, which simplifies the logic of
529 537 supporting magics.
530 538
531 539 Notes
532 540 -----
533 541 This methods sets the PyOS_InputHook for Gtk3, which allows
534 542 the Gtk3 to integrate with terminal based applications like
535 543 IPython.
536 544 """
537 545 from IPython.lib.inputhookgtk3 import inputhook_gtk3
538 546 self.manager.set_inputhook(inputhook_gtk3)
539 547 self.manager._current_gui = GUI_GTK
540 548
541 549
542 550 clear_inputhook = inputhook_manager.clear_inputhook
543 551 set_inputhook = inputhook_manager.set_inputhook
544 552 current_gui = inputhook_manager.current_gui
545 553 clear_app_refs = inputhook_manager.clear_app_refs
546 554 enable_gui = inputhook_manager.enable_gui
547 555 disable_gui = inputhook_manager.disable_gui
548 556 register = inputhook_manager.register
549 557 guis = inputhook_manager.guihooks
550 558
551 559 # Deprecated methods: kept for backwards compatibility, do not use in new code
552 560 def _make_deprecated_enable(name):
553 561 def enable_toolkit(app=None):
554 562 warn("This function is deprecated - use enable_gui(%r) instead" % name)
555 563 inputhook_manager.enable_gui(name, app)
556 564
557 565 enable_wx = _make_deprecated_enable('wx')
558 566 enable_qt4 = _make_deprecated_enable('qt4')
559 567 enable_gtk = _make_deprecated_enable('gtk')
560 568 enable_tk = _make_deprecated_enable('tk')
561 569 enable_glut = _make_deprecated_enable('glut')
562 570 enable_pyglet = _make_deprecated_enable('pyglet')
563 571 enable_gtk3 = _make_deprecated_enable('gtk3')
564 572
565 573 def _deprecated_disable():
566 574 warn("This function is deprecated: use disable_gui() instead")
567 575 inputhook_manager.disable_gui()
568 576 disable_wx = disable_qt4 = disable_gtk = disable_gtk3 = disable_glut = \
569 577 disable_pyglet = _deprecated_disable
General Comments 0
You need to be logged in to leave comments. Login now