##// END OF EJS Templates
Fixed #4580 -- Deprecated %profile.
Susan Tan -
Show More
@@ -1,654 +1,655 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 warn("%profile is now deprecated. Please use get_ipython().profile instead.")
315 316 from IPython.core.application import BaseIPythonApplication
316 317 if BaseIPythonApplication.initialized():
317 318 print(BaseIPythonApplication.instance().profile)
318 319 else:
319 320 error("profile is an application-level value, but you don't appear to be in an IPython application")
320 321
321 322 @line_magic
322 323 def pprint(self, parameter_s=''):
323 324 """Toggle pretty printing on/off."""
324 325 ptformatter = self.shell.display_formatter.formatters['text/plain']
325 326 ptformatter.pprint = bool(1 - ptformatter.pprint)
326 327 print('Pretty printing has been turned',
327 328 ['OFF','ON'][ptformatter.pprint])
328 329
329 330 @line_magic
330 331 def colors(self, parameter_s=''):
331 332 """Switch color scheme for prompts, info system and exception handlers.
332 333
333 334 Currently implemented schemes: NoColor, Linux, LightBG.
334 335
335 336 Color scheme names are not case-sensitive.
336 337
337 338 Examples
338 339 --------
339 340 To get a plain black and white terminal::
340 341
341 342 %colors nocolor
342 343 """
343 344 def color_switch_err(name):
344 345 warn('Error changing %s color schemes.\n%s' %
345 346 (name, sys.exc_info()[1]))
346 347
347 348
348 349 new_scheme = parameter_s.strip()
349 350 if not new_scheme:
350 351 raise UsageError(
351 352 "%colors: you must specify a color scheme. See '%colors?'")
352 353 # local shortcut
353 354 shell = self.shell
354 355
355 356 import IPython.utils.rlineimpl as readline
356 357
357 358 if not shell.colors_force and \
358 359 not readline.have_readline and \
359 360 (sys.platform == "win32" or sys.platform == "cli"):
360 361 msg = """\
361 362 Proper color support under MS Windows requires the pyreadline library.
362 363 You can find it at:
363 364 http://ipython.org/pyreadline.html
364 365 Gary's readline needs the ctypes module, from:
365 366 http://starship.python.net/crew/theller/ctypes
366 367 (Note that ctypes is already part of Python versions 2.5 and newer).
367 368
368 369 Defaulting color scheme to 'NoColor'"""
369 370 new_scheme = 'NoColor'
370 371 warn(msg)
371 372
372 373 # readline option is 0
373 374 if not shell.colors_force and not shell.has_readline:
374 375 new_scheme = 'NoColor'
375 376
376 377 # Set prompt colors
377 378 try:
378 379 shell.prompt_manager.color_scheme = new_scheme
379 380 except:
380 381 color_switch_err('prompt')
381 382 else:
382 383 shell.colors = \
383 384 shell.prompt_manager.color_scheme_table.active_scheme_name
384 385 # Set exception colors
385 386 try:
386 387 shell.InteractiveTB.set_colors(scheme = new_scheme)
387 388 shell.SyntaxTB.set_colors(scheme = new_scheme)
388 389 except:
389 390 color_switch_err('exception')
390 391
391 392 # Set info (for 'object?') colors
392 393 if shell.color_info:
393 394 try:
394 395 shell.inspector.set_active_scheme(new_scheme)
395 396 except:
396 397 color_switch_err('object inspector')
397 398 else:
398 399 shell.inspector.set_active_scheme('NoColor')
399 400
400 401 @line_magic
401 402 def xmode(self, parameter_s=''):
402 403 """Switch modes for the exception handlers.
403 404
404 405 Valid modes: Plain, Context and Verbose.
405 406
406 407 If called without arguments, acts as a toggle."""
407 408
408 409 def xmode_switch_err(name):
409 410 warn('Error changing %s exception modes.\n%s' %
410 411 (name,sys.exc_info()[1]))
411 412
412 413 shell = self.shell
413 414 new_mode = parameter_s.strip().capitalize()
414 415 try:
415 416 shell.InteractiveTB.set_mode(mode=new_mode)
416 417 print('Exception reporting mode:',shell.InteractiveTB.mode)
417 418 except:
418 419 xmode_switch_err('user')
419 420
420 421 @line_magic
421 422 def quickref(self,arg):
422 423 """ Show a quick reference sheet """
423 424 from IPython.core.usage import quick_reference
424 425 qr = quick_reference + self._magic_docs(brief=True)
425 426 page.page(qr)
426 427
427 428 @line_magic
428 429 def doctest_mode(self, parameter_s=''):
429 430 """Toggle doctest mode on and off.
430 431
431 432 This mode is intended to make IPython behave as much as possible like a
432 433 plain Python shell, from the perspective of how its prompts, exceptions
433 434 and output look. This makes it easy to copy and paste parts of a
434 435 session into doctests. It does so by:
435 436
436 437 - Changing the prompts to the classic ``>>>`` ones.
437 438 - Changing the exception reporting mode to 'Plain'.
438 439 - Disabling pretty-printing of output.
439 440
440 441 Note that IPython also supports the pasting of code snippets that have
441 442 leading '>>>' and '...' prompts in them. This means that you can paste
442 443 doctests from files or docstrings (even if they have leading
443 444 whitespace), and the code will execute correctly. You can then use
444 445 '%history -t' to see the translated history; this will give you the
445 446 input after removal of all the leading prompts and whitespace, which
446 447 can be pasted back into an editor.
447 448
448 449 With these features, you can switch into this mode easily whenever you
449 450 need to do testing and changes to doctests, without having to leave
450 451 your existing IPython session.
451 452 """
452 453
453 454 # Shorthands
454 455 shell = self.shell
455 456 pm = shell.prompt_manager
456 457 meta = shell.meta
457 458 disp_formatter = self.shell.display_formatter
458 459 ptformatter = disp_formatter.formatters['text/plain']
459 460 # dstore is a data store kept in the instance metadata bag to track any
460 461 # changes we make, so we can undo them later.
461 462 dstore = meta.setdefault('doctest_mode',Struct())
462 463 save_dstore = dstore.setdefault
463 464
464 465 # save a few values we'll need to recover later
465 466 mode = save_dstore('mode',False)
466 467 save_dstore('rc_pprint',ptformatter.pprint)
467 468 save_dstore('xmode',shell.InteractiveTB.mode)
468 469 save_dstore('rc_separate_out',shell.separate_out)
469 470 save_dstore('rc_separate_out2',shell.separate_out2)
470 471 save_dstore('rc_prompts_pad_left',pm.justify)
471 472 save_dstore('rc_separate_in',shell.separate_in)
472 473 save_dstore('rc_active_types',disp_formatter.active_types)
473 474 save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template))
474 475
475 476 if mode == False:
476 477 # turn on
477 478 pm.in_template = '>>> '
478 479 pm.in2_template = '... '
479 480 pm.out_template = ''
480 481
481 482 # Prompt separators like plain python
482 483 shell.separate_in = ''
483 484 shell.separate_out = ''
484 485 shell.separate_out2 = ''
485 486
486 487 pm.justify = False
487 488
488 489 ptformatter.pprint = False
489 490 disp_formatter.active_types = ['text/plain']
490 491
491 492 shell.magic('xmode Plain')
492 493 else:
493 494 # turn off
494 495 pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates
495 496
496 497 shell.separate_in = dstore.rc_separate_in
497 498
498 499 shell.separate_out = dstore.rc_separate_out
499 500 shell.separate_out2 = dstore.rc_separate_out2
500 501
501 502 pm.justify = dstore.rc_prompts_pad_left
502 503
503 504 ptformatter.pprint = dstore.rc_pprint
504 505 disp_formatter.active_types = dstore.rc_active_types
505 506
506 507 shell.magic('xmode ' + dstore.xmode)
507 508
508 509 # Store new mode and inform
509 510 dstore.mode = bool(1-int(mode))
510 511 mode_label = ['OFF','ON'][dstore.mode]
511 512 print('Doctest mode is:', mode_label)
512 513
513 514 @line_magic
514 515 def gui(self, parameter_s=''):
515 516 """Enable or disable IPython GUI event loop integration.
516 517
517 518 %gui [GUINAME]
518 519
519 520 This magic replaces IPython's threaded shells that were activated
520 521 using the (pylab/wthread/etc.) command line flags. GUI toolkits
521 522 can now be enabled at runtime and keyboard
522 523 interrupts should work without any problems. The following toolkits
523 524 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
524 525
525 526 %gui wx # enable wxPython event loop integration
526 527 %gui qt4|qt # enable PyQt4 event loop integration
527 528 %gui gtk # enable PyGTK event loop integration
528 529 %gui gtk3 # enable Gtk3 event loop integration
529 530 %gui tk # enable Tk event loop integration
530 531 %gui osx # enable Cocoa event loop integration
531 532 # (requires %matplotlib 1.1)
532 533 %gui # disable all event loop integration
533 534
534 535 WARNING: after any of these has been called you can simply create
535 536 an application object, but DO NOT start the event loop yourself, as
536 537 we have already handled that.
537 538 """
538 539 opts, arg = self.parse_options(parameter_s, '')
539 540 if arg=='': arg = None
540 541 try:
541 542 return self.shell.enable_gui(arg)
542 543 except Exception as e:
543 544 # print simple error message, rather than traceback if we can't
544 545 # hook up the GUI
545 546 error(str(e))
546 547
547 548 @skip_doctest
548 549 @line_magic
549 550 def precision(self, s=''):
550 551 """Set floating point precision for pretty printing.
551 552
552 553 Can set either integer precision or a format string.
553 554
554 555 If numpy has been imported and precision is an int,
555 556 numpy display precision will also be set, via ``numpy.set_printoptions``.
556 557
557 558 If no argument is given, defaults will be restored.
558 559
559 560 Examples
560 561 --------
561 562 ::
562 563
563 564 In [1]: from math import pi
564 565
565 566 In [2]: %precision 3
566 567 Out[2]: u'%.3f'
567 568
568 569 In [3]: pi
569 570 Out[3]: 3.142
570 571
571 572 In [4]: %precision %i
572 573 Out[4]: u'%i'
573 574
574 575 In [5]: pi
575 576 Out[5]: 3
576 577
577 578 In [6]: %precision %e
578 579 Out[6]: u'%e'
579 580
580 581 In [7]: pi**10
581 582 Out[7]: 9.364805e+04
582 583
583 584 In [8]: %precision
584 585 Out[8]: u'%r'
585 586
586 587 In [9]: pi**10
587 588 Out[9]: 93648.047476082982
588 589 """
589 590 ptformatter = self.shell.display_formatter.formatters['text/plain']
590 591 ptformatter.float_precision = s
591 592 return ptformatter.float_format
592 593
593 594 @magic_arguments.magic_arguments()
594 595 @magic_arguments.argument(
595 596 '-e', '--export', action='store_true', default=False,
596 597 help='Export IPython history as a notebook. The filename argument '
597 598 'is used to specify the notebook name and format. For example '
598 599 'a filename of notebook.ipynb will result in a notebook name '
599 600 'of "notebook" and a format of "json". Likewise using a ".py" '
600 601 'file extension will write the notebook as a Python script'
601 602 )
602 603 @magic_arguments.argument(
603 604 '-f', '--format',
604 605 help='Convert an existing IPython notebook to a new format. This option '
605 606 'specifies the new format and can have the values: json, py. '
606 607 'The target filename is chosen automatically based on the new '
607 608 'format. The filename argument gives the name of the source file.'
608 609 )
609 610 @magic_arguments.argument(
610 611 'filename', type=unicode_type,
611 612 help='Notebook name or filename'
612 613 )
613 614 @line_magic
614 615 def notebook(self, s):
615 616 """Export and convert IPython notebooks.
616 617
617 618 This function can export the current IPython history to a notebook file
618 619 or can convert an existing notebook file into a different format. For
619 620 example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
620 621 To export the history to "foo.py" do "%notebook -e foo.py". To convert
621 622 "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
622 623 formats include (json/ipynb, py).
623 624 """
624 625 args = magic_arguments.parse_argstring(self.notebook, s)
625 626
626 627 from IPython.nbformat import current
627 628 args.filename = unquote_filename(args.filename)
628 629 if args.export:
629 630 fname, name, format = current.parse_filename(args.filename)
630 631 cells = []
631 632 hist = list(self.shell.history_manager.get_range())
632 633 for session, prompt_number, input in hist[:-1]:
633 634 cells.append(current.new_code_cell(prompt_number=prompt_number,
634 635 input=input))
635 636 worksheet = current.new_worksheet(cells=cells)
636 637 nb = current.new_notebook(name=name,worksheets=[worksheet])
637 638 with io.open(fname, 'w', encoding='utf-8') as f:
638 639 current.write(nb, f, format);
639 640 elif args.format is not None:
640 641 old_fname, old_name, old_format = current.parse_filename(args.filename)
641 642 new_format = args.format
642 643 if new_format == u'xml':
643 644 raise ValueError('Notebooks cannot be written as xml.')
644 645 elif new_format == u'ipynb' or new_format == u'json':
645 646 new_fname = old_name + u'.ipynb'
646 647 new_format = u'json'
647 648 elif new_format == u'py':
648 649 new_fname = old_name + u'.py'
649 650 else:
650 651 raise ValueError('Invalid notebook format: %s' % new_format)
651 652 with io.open(old_fname, 'r', encoding='utf-8') as f:
652 653 nb = current.read(f, old_format)
653 654 with io.open(new_fname, 'w', encoding='utf-8') as f:
654 655 current.write(nb, f, new_format)
@@ -1,153 +1,153 b''
1 1 # coding: utf-8
2 2 """Tests for profile-related functions.
3 3
4 4 Currently only the startup-dir functionality is tested, but more tests should
5 5 be added for:
6 6
7 7 * ipython profile create
8 8 * ipython profile list
9 9 * ipython profile create --parallel
10 10 * security dir permissions
11 11
12 12 Authors
13 13 -------
14 14
15 15 * MinRK
16 16
17 17 """
18 18 from __future__ import absolute_import
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 import os
25 25 import shutil
26 26 import sys
27 27 import tempfile
28 28
29 29 from unittest import TestCase
30 30
31 31 import nose.tools as nt
32 32
33 33 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
34 34 from IPython.core.profiledir import ProfileDir
35 35
36 36 from IPython.testing import decorators as dec
37 37 from IPython.testing import tools as tt
38 38 from IPython.utils import py3compat
39 39
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Globals
43 43 #-----------------------------------------------------------------------------
44 44 TMP_TEST_DIR = tempfile.mkdtemp()
45 45 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
46 46 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
47 47
48 48 #
49 49 # Setup/teardown functions/decorators
50 50 #
51 51
52 52 def setup():
53 53 """Setup test environment for the module:
54 54
55 55 - Adds dummy home dir tree
56 56 """
57 57 # Do not mask exceptions here. In particular, catching WindowsError is a
58 58 # problem because that exception is only defined on Windows...
59 59 os.makedirs(IP_TEST_DIR)
60 60
61 61
62 62 def teardown():
63 63 """Teardown test environment for the module:
64 64
65 65 - Remove dummy home dir tree
66 66 """
67 67 # Note: we remove the parent test dir, which is the root of all test
68 68 # subdirs we may have created. Use shutil instead of os.removedirs, so
69 69 # that non-empty directories are all recursively removed.
70 70 shutil.rmtree(TMP_TEST_DIR)
71 71
72 72
73 73 #-----------------------------------------------------------------------------
74 74 # Test functions
75 75 #-----------------------------------------------------------------------------
76 76 def win32_without_pywin32():
77 77 if sys.platform == 'win32':
78 78 try:
79 79 import pywin32
80 80 except ImportError:
81 81 return True
82 82 return False
83 83
84 84
85 85 class ProfileStartupTest(TestCase):
86 86 def setUp(self):
87 87 # create profile dir
88 88 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, 'test')
89 89 self.options = ['--ipython-dir', IP_TEST_DIR, '--profile', 'test']
90 90 self.fname = os.path.join(TMP_TEST_DIR, 'test.py')
91 91
92 92 def tearDown(self):
93 93 # We must remove this profile right away so its presence doesn't
94 94 # confuse other tests.
95 95 shutil.rmtree(self.pd.location)
96 96
97 97 def init(self, startup_file, startup, test):
98 98 # write startup python file
99 99 with open(os.path.join(self.pd.startup_dir, startup_file), 'w') as f:
100 100 f.write(startup)
101 101 # write simple test file, to check that the startup file was run
102 102 with open(self.fname, 'w') as f:
103 103 f.write(py3compat.doctest_refactor_print(test))
104 104
105 105 def validate(self, output):
106 106 tt.ipexec_validate(self.fname, output, '', options=self.options)
107 107
108 108 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
109 109 def test_startup_py(self):
110 110 self.init('00-start.py', 'zzz=123\n',
111 111 py3compat.doctest_refactor_print('print zzz\n'))
112 112 self.validate('123')
113 113
114 114 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
115 115 def test_startup_ipy(self):
116 self.init('00-start.ipy', '%profile\n', '')
117 self.validate('test')
116 self.init('00-start.ipy', '%xmode plain\n', '')
117 self.validate('Exception reporting mode: Plain')
118 118
119 119
120 120 def test_list_profiles_in():
121 121 # No need to remove these directories and files, as they will get nuked in
122 122 # the module-level teardown.
123 123 td = tempfile.mkdtemp(dir=TMP_TEST_DIR)
124 124 td = py3compat.str_to_unicode(td)
125 125 for name in ('profile_foo', 'profile_hello', 'not_a_profile'):
126 126 os.mkdir(os.path.join(td, name))
127 127 if dec.unicode_paths:
128 128 os.mkdir(os.path.join(td, u'profile_ünicode'))
129 129
130 130 with open(os.path.join(td, 'profile_file'), 'w') as f:
131 131 f.write("I am not a profile directory")
132 132 profiles = list_profiles_in(td)
133 133
134 134 # unicode normalization can turn u'ünicode' into u'u\0308nicode',
135 135 # so only check for *nicode, and that creating a ProfileDir from the
136 136 # name remains valid
137 137 found_unicode = False
138 138 for p in list(profiles):
139 139 if p.endswith('nicode'):
140 140 pd = ProfileDir.find_profile_dir_by_name(td, p)
141 141 profiles.remove(p)
142 142 found_unicode = True
143 143 break
144 144 if dec.unicode_paths:
145 145 nt.assert_true(found_unicode)
146 146 nt.assert_equal(set(profiles), set(['foo', 'hello']))
147 147
148 148
149 149 def test_list_bundled_profiles():
150 150 # This variable will need to be updated when a new profile gets bundled
151 151 bundled_true = [u'cluster', u'math', u'pysh', u'sympy']
152 152 bundled = sorted(list_bundled_profiles())
153 153 nt.assert_equal(bundled, bundled_true)
General Comments 0
You need to be logged in to leave comments. Login now