##// END OF EJS Templates
Clean up a couple more references to unicode
Thomas Kluyver -
Show More
@@ -1,646 +1,647 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 from IPython.utils.py3compat import unicode_type
30 31 from IPython.utils.warn import warn, error
31 32
32 33 #-----------------------------------------------------------------------------
33 34 # Magics class implementation
34 35 #-----------------------------------------------------------------------------
35 36
36 37 class MagicsDisplay(object):
37 38 def __init__(self, magics_manager):
38 39 self.magics_manager = magics_manager
39 40
40 41 def _lsmagic(self):
41 42 """The main implementation of the %lsmagic"""
42 43 mesc = magic_escapes['line']
43 44 cesc = magic_escapes['cell']
44 45 mman = self.magics_manager
45 46 magics = mman.lsmagic()
46 47 out = ['Available line magics:',
47 48 mesc + (' '+mesc).join(sorted(magics['line'])),
48 49 '',
49 50 'Available cell magics:',
50 51 cesc + (' '+cesc).join(sorted(magics['cell'])),
51 52 '',
52 53 mman.auto_status()]
53 54 return '\n'.join(out)
54 55
55 56 def _repr_pretty_(self, p, cycle):
56 57 p.text(self._lsmagic())
57 58
58 59 def __str__(self):
59 60 return self._lsmagic()
60 61
61 62 def _jsonable(self):
62 63 """turn magics dict into jsonable dict of the same structure
63 64
64 65 replaces object instances with their class names as strings
65 66 """
66 67 magic_dict = {}
67 68 mman = self.magics_manager
68 69 magics = mman.lsmagic()
69 70 for key, subdict in magics.items():
70 71 d = {}
71 72 magic_dict[key] = d
72 73 for name, obj in subdict.items():
73 74 try:
74 75 classname = obj.im_class.__name__
75 76 except AttributeError:
76 77 classname = 'Other'
77 78
78 79 d[name] = classname
79 80 return magic_dict
80 81
81 82 def _repr_json_(self):
82 83 return json.dumps(self._jsonable())
83 84
84 85
85 86 @magics_class
86 87 class BasicMagics(Magics):
87 88 """Magics that provide central IPython functionality.
88 89
89 90 These are various magics that don't fit into specific categories but that
90 91 are all part of the base 'IPython experience'."""
91 92
92 93 @magic_arguments.magic_arguments()
93 94 @magic_arguments.argument(
94 95 '-l', '--line', action='store_true',
95 96 help="""Create a line magic alias."""
96 97 )
97 98 @magic_arguments.argument(
98 99 '-c', '--cell', action='store_true',
99 100 help="""Create a cell magic alias."""
100 101 )
101 102 @magic_arguments.argument(
102 103 'name',
103 104 help="""Name of the magic to be created."""
104 105 )
105 106 @magic_arguments.argument(
106 107 'target',
107 108 help="""Name of the existing line or cell magic."""
108 109 )
109 110 @line_magic
110 111 def alias_magic(self, line=''):
111 112 """Create an alias for an existing line or cell magic.
112 113
113 114 Examples
114 115 --------
115 116 ::
116 117 In [1]: %alias_magic t timeit
117 118 Created `%t` as an alias for `%timeit`.
118 119 Created `%%t` as an alias for `%%timeit`.
119 120
120 121 In [2]: %t -n1 pass
121 122 1 loops, best of 3: 954 ns per loop
122 123
123 124 In [3]: %%t -n1
124 125 ...: pass
125 126 ...:
126 127 1 loops, best of 3: 954 ns per loop
127 128
128 129 In [4]: %alias_magic --cell whereami pwd
129 130 UsageError: Cell magic function `%%pwd` not found.
130 131 In [5]: %alias_magic --line whereami pwd
131 132 Created `%whereami` as an alias for `%pwd`.
132 133
133 134 In [6]: %whereami
134 135 Out[6]: u'/home/testuser'
135 136 """
136 137 args = magic_arguments.parse_argstring(self.alias_magic, line)
137 138 shell = self.shell
138 139 mman = self.shell.magics_manager
139 140 escs = ''.join(magic_escapes.values())
140 141
141 142 target = args.target.lstrip(escs)
142 143 name = args.name.lstrip(escs)
143 144
144 145 # Find the requested magics.
145 146 m_line = shell.find_magic(target, 'line')
146 147 m_cell = shell.find_magic(target, 'cell')
147 148 if args.line and m_line is None:
148 149 raise UsageError('Line magic function `%s%s` not found.' %
149 150 (magic_escapes['line'], target))
150 151 if args.cell and m_cell is None:
151 152 raise UsageError('Cell magic function `%s%s` not found.' %
152 153 (magic_escapes['cell'], target))
153 154
154 155 # If --line and --cell are not specified, default to the ones
155 156 # that are available.
156 157 if not args.line and not args.cell:
157 158 if not m_line and not m_cell:
158 159 raise UsageError(
159 160 'No line or cell magic with name `%s` found.' % target
160 161 )
161 162 args.line = bool(m_line)
162 163 args.cell = bool(m_cell)
163 164
164 165 if args.line:
165 166 mman.register_alias(name, target, 'line')
166 167 print('Created `%s%s` as an alias for `%s%s`.' % (
167 168 magic_escapes['line'], name,
168 169 magic_escapes['line'], target))
169 170
170 171 if args.cell:
171 172 mman.register_alias(name, target, 'cell')
172 173 print('Created `%s%s` as an alias for `%s%s`.' % (
173 174 magic_escapes['cell'], name,
174 175 magic_escapes['cell'], target))
175 176
176 177 @line_magic
177 178 def lsmagic(self, parameter_s=''):
178 179 """List currently available magic functions."""
179 180 return MagicsDisplay(self.shell.magics_manager)
180 181
181 182 def _magic_docs(self, brief=False, rest=False):
182 183 """Return docstrings from magic functions."""
183 184 mman = self.shell.magics_manager
184 185 docs = mman.lsmagic_docs(brief, missing='No documentation')
185 186
186 187 if rest:
187 188 format_string = '**%s%s**::\n\n%s\n\n'
188 189 else:
189 190 format_string = '%s%s:\n%s\n'
190 191
191 192 return ''.join(
192 193 [format_string % (magic_escapes['line'], fname,
193 194 indent(dedent(fndoc)))
194 195 for fname, fndoc in sorted(docs['line'].items())]
195 196 +
196 197 [format_string % (magic_escapes['cell'], fname,
197 198 indent(dedent(fndoc)))
198 199 for fname, fndoc in sorted(docs['cell'].items())]
199 200 )
200 201
201 202 @line_magic
202 203 def magic(self, parameter_s=''):
203 204 """Print information about the magic function system.
204 205
205 206 Supported formats: -latex, -brief, -rest
206 207 """
207 208
208 209 mode = ''
209 210 try:
210 211 mode = parameter_s.split()[0][1:]
211 212 if mode == 'rest':
212 213 rest_docs = []
213 214 except IndexError:
214 215 pass
215 216
216 217 brief = (mode == 'brief')
217 218 rest = (mode == 'rest')
218 219 magic_docs = self._magic_docs(brief, rest)
219 220
220 221 if mode == 'latex':
221 222 print(self.format_latex(magic_docs))
222 223 return
223 224 else:
224 225 magic_docs = format_screen(magic_docs)
225 226
226 227 out = ["""
227 228 IPython's 'magic' functions
228 229 ===========================
229 230
230 231 The magic function system provides a series of functions which allow you to
231 232 control the behavior of IPython itself, plus a lot of system-type
232 233 features. There are two kinds of magics, line-oriented and cell-oriented.
233 234
234 235 Line magics are prefixed with the % character and work much like OS
235 236 command-line calls: they get as an argument the rest of the line, where
236 237 arguments are passed without parentheses or quotes. For example, this will
237 238 time the given statement::
238 239
239 240 %timeit range(1000)
240 241
241 242 Cell magics are prefixed with a double %%, and they are functions that get as
242 243 an argument not only the rest of the line, but also the lines below it in a
243 244 separate argument. These magics are called with two arguments: the rest of the
244 245 call line and the body of the cell, consisting of the lines below the first.
245 246 For example::
246 247
247 248 %%timeit x = numpy.random.randn((100, 100))
248 249 numpy.linalg.svd(x)
249 250
250 251 will time the execution of the numpy svd routine, running the assignment of x
251 252 as part of the setup phase, which is not timed.
252 253
253 254 In a line-oriented client (the terminal or Qt console IPython), starting a new
254 255 input with %% will automatically enter cell mode, and IPython will continue
255 256 reading input until a blank line is given. In the notebook, simply type the
256 257 whole cell as one entity, but keep in mind that the %% escape can only be at
257 258 the very start of the cell.
258 259
259 260 NOTE: If you have 'automagic' enabled (via the command line option or with the
260 261 %automagic function), you don't need to type in the % explicitly for line
261 262 magics; cell magics always require an explicit '%%' escape. By default,
262 263 IPython ships with automagic on, so you should only rarely need the % escape.
263 264
264 265 Example: typing '%cd mydir' (without the quotes) changes you working directory
265 266 to 'mydir', if it exists.
266 267
267 268 For a list of the available magic functions, use %lsmagic. For a description
268 269 of any of them, type %magic_name?, e.g. '%cd?'.
269 270
270 271 Currently the magic system has the following functions:""",
271 272 magic_docs,
272 273 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
273 274 str(self.lsmagic()),
274 275 ]
275 276 page.page('\n'.join(out))
276 277
277 278
278 279 @line_magic
279 280 def page(self, parameter_s=''):
280 281 """Pretty print the object and display it through a pager.
281 282
282 283 %page [options] OBJECT
283 284
284 285 If no object is given, use _ (last output).
285 286
286 287 Options:
287 288
288 289 -r: page str(object), don't pretty-print it."""
289 290
290 291 # After a function contributed by Olivier Aubert, slightly modified.
291 292
292 293 # Process options/args
293 294 opts, args = self.parse_options(parameter_s, 'r')
294 295 raw = 'r' in opts
295 296
296 297 oname = args and args or '_'
297 298 info = self.shell._ofind(oname)
298 299 if info['found']:
299 300 txt = (raw and str or pformat)( info['obj'] )
300 301 page.page(txt)
301 302 else:
302 303 print('Object `%s` not found' % oname)
303 304
304 305 @line_magic
305 306 def profile(self, parameter_s=''):
306 307 """Print your currently active IPython profile."""
307 308 from IPython.core.application import BaseIPythonApplication
308 309 if BaseIPythonApplication.initialized():
309 310 print(BaseIPythonApplication.instance().profile)
310 311 else:
311 312 error("profile is an application-level value, but you don't appear to be in an IPython application")
312 313
313 314 @line_magic
314 315 def pprint(self, parameter_s=''):
315 316 """Toggle pretty printing on/off."""
316 317 ptformatter = self.shell.display_formatter.formatters['text/plain']
317 318 ptformatter.pprint = bool(1 - ptformatter.pprint)
318 319 print('Pretty printing has been turned',
319 320 ['OFF','ON'][ptformatter.pprint])
320 321
321 322 @line_magic
322 323 def colors(self, parameter_s=''):
323 324 """Switch color scheme for prompts, info system and exception handlers.
324 325
325 326 Currently implemented schemes: NoColor, Linux, LightBG.
326 327
327 328 Color scheme names are not case-sensitive.
328 329
329 330 Examples
330 331 --------
331 332 To get a plain black and white terminal::
332 333
333 334 %colors nocolor
334 335 """
335 336 def color_switch_err(name):
336 337 warn('Error changing %s color schemes.\n%s' %
337 338 (name, sys.exc_info()[1]))
338 339
339 340
340 341 new_scheme = parameter_s.strip()
341 342 if not new_scheme:
342 343 raise UsageError(
343 344 "%colors: you must specify a color scheme. See '%colors?'")
344 345 # local shortcut
345 346 shell = self.shell
346 347
347 348 import IPython.utils.rlineimpl as readline
348 349
349 350 if not shell.colors_force and \
350 351 not readline.have_readline and \
351 352 (sys.platform == "win32" or sys.platform == "cli"):
352 353 msg = """\
353 354 Proper color support under MS Windows requires the pyreadline library.
354 355 You can find it at:
355 356 http://ipython.org/pyreadline.html
356 357 Gary's readline needs the ctypes module, from:
357 358 http://starship.python.net/crew/theller/ctypes
358 359 (Note that ctypes is already part of Python versions 2.5 and newer).
359 360
360 361 Defaulting color scheme to 'NoColor'"""
361 362 new_scheme = 'NoColor'
362 363 warn(msg)
363 364
364 365 # readline option is 0
365 366 if not shell.colors_force and not shell.has_readline:
366 367 new_scheme = 'NoColor'
367 368
368 369 # Set prompt colors
369 370 try:
370 371 shell.prompt_manager.color_scheme = new_scheme
371 372 except:
372 373 color_switch_err('prompt')
373 374 else:
374 375 shell.colors = \
375 376 shell.prompt_manager.color_scheme_table.active_scheme_name
376 377 # Set exception colors
377 378 try:
378 379 shell.InteractiveTB.set_colors(scheme = new_scheme)
379 380 shell.SyntaxTB.set_colors(scheme = new_scheme)
380 381 except:
381 382 color_switch_err('exception')
382 383
383 384 # Set info (for 'object?') colors
384 385 if shell.color_info:
385 386 try:
386 387 shell.inspector.set_active_scheme(new_scheme)
387 388 except:
388 389 color_switch_err('object inspector')
389 390 else:
390 391 shell.inspector.set_active_scheme('NoColor')
391 392
392 393 @line_magic
393 394 def xmode(self, parameter_s=''):
394 395 """Switch modes for the exception handlers.
395 396
396 397 Valid modes: Plain, Context and Verbose.
397 398
398 399 If called without arguments, acts as a toggle."""
399 400
400 401 def xmode_switch_err(name):
401 402 warn('Error changing %s exception modes.\n%s' %
402 403 (name,sys.exc_info()[1]))
403 404
404 405 shell = self.shell
405 406 new_mode = parameter_s.strip().capitalize()
406 407 try:
407 408 shell.InteractiveTB.set_mode(mode=new_mode)
408 409 print('Exception reporting mode:',shell.InteractiveTB.mode)
409 410 except:
410 411 xmode_switch_err('user')
411 412
412 413 @line_magic
413 414 def quickref(self,arg):
414 415 """ Show a quick reference sheet """
415 416 from IPython.core.usage import quick_reference
416 417 qr = quick_reference + self._magic_docs(brief=True)
417 418 page.page(qr)
418 419
419 420 @line_magic
420 421 def doctest_mode(self, parameter_s=''):
421 422 """Toggle doctest mode on and off.
422 423
423 424 This mode is intended to make IPython behave as much as possible like a
424 425 plain Python shell, from the perspective of how its prompts, exceptions
425 426 and output look. This makes it easy to copy and paste parts of a
426 427 session into doctests. It does so by:
427 428
428 429 - Changing the prompts to the classic ``>>>`` ones.
429 430 - Changing the exception reporting mode to 'Plain'.
430 431 - Disabling pretty-printing of output.
431 432
432 433 Note that IPython also supports the pasting of code snippets that have
433 434 leading '>>>' and '...' prompts in them. This means that you can paste
434 435 doctests from files or docstrings (even if they have leading
435 436 whitespace), and the code will execute correctly. You can then use
436 437 '%history -t' to see the translated history; this will give you the
437 438 input after removal of all the leading prompts and whitespace, which
438 439 can be pasted back into an editor.
439 440
440 441 With these features, you can switch into this mode easily whenever you
441 442 need to do testing and changes to doctests, without having to leave
442 443 your existing IPython session.
443 444 """
444 445
445 446 # Shorthands
446 447 shell = self.shell
447 448 pm = shell.prompt_manager
448 449 meta = shell.meta
449 450 disp_formatter = self.shell.display_formatter
450 451 ptformatter = disp_formatter.formatters['text/plain']
451 452 # dstore is a data store kept in the instance metadata bag to track any
452 453 # changes we make, so we can undo them later.
453 454 dstore = meta.setdefault('doctest_mode',Struct())
454 455 save_dstore = dstore.setdefault
455 456
456 457 # save a few values we'll need to recover later
457 458 mode = save_dstore('mode',False)
458 459 save_dstore('rc_pprint',ptformatter.pprint)
459 460 save_dstore('xmode',shell.InteractiveTB.mode)
460 461 save_dstore('rc_separate_out',shell.separate_out)
461 462 save_dstore('rc_separate_out2',shell.separate_out2)
462 463 save_dstore('rc_prompts_pad_left',pm.justify)
463 464 save_dstore('rc_separate_in',shell.separate_in)
464 465 save_dstore('rc_active_types',disp_formatter.active_types)
465 466 save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template))
466 467
467 468 if mode == False:
468 469 # turn on
469 470 pm.in_template = '>>> '
470 471 pm.in2_template = '... '
471 472 pm.out_template = ''
472 473
473 474 # Prompt separators like plain python
474 475 shell.separate_in = ''
475 476 shell.separate_out = ''
476 477 shell.separate_out2 = ''
477 478
478 479 pm.justify = False
479 480
480 481 ptformatter.pprint = False
481 482 disp_formatter.active_types = ['text/plain']
482 483
483 484 shell.magic('xmode Plain')
484 485 else:
485 486 # turn off
486 487 pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates
487 488
488 489 shell.separate_in = dstore.rc_separate_in
489 490
490 491 shell.separate_out = dstore.rc_separate_out
491 492 shell.separate_out2 = dstore.rc_separate_out2
492 493
493 494 pm.justify = dstore.rc_prompts_pad_left
494 495
495 496 ptformatter.pprint = dstore.rc_pprint
496 497 disp_formatter.active_types = dstore.rc_active_types
497 498
498 499 shell.magic('xmode ' + dstore.xmode)
499 500
500 501 # Store new mode and inform
501 502 dstore.mode = bool(1-int(mode))
502 503 mode_label = ['OFF','ON'][dstore.mode]
503 504 print('Doctest mode is:', mode_label)
504 505
505 506 @line_magic
506 507 def gui(self, parameter_s=''):
507 508 """Enable or disable IPython GUI event loop integration.
508 509
509 510 %gui [GUINAME]
510 511
511 512 This magic replaces IPython's threaded shells that were activated
512 513 using the (pylab/wthread/etc.) command line flags. GUI toolkits
513 514 can now be enabled at runtime and keyboard
514 515 interrupts should work without any problems. The following toolkits
515 516 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
516 517
517 518 %gui wx # enable wxPython event loop integration
518 519 %gui qt4|qt # enable PyQt4 event loop integration
519 520 %gui gtk # enable PyGTK event loop integration
520 521 %gui gtk3 # enable Gtk3 event loop integration
521 522 %gui tk # enable Tk event loop integration
522 523 %gui osx # enable Cocoa event loop integration
523 524 # (requires %matplotlib 1.1)
524 525 %gui # disable all event loop integration
525 526
526 527 WARNING: after any of these has been called you can simply create
527 528 an application object, but DO NOT start the event loop yourself, as
528 529 we have already handled that.
529 530 """
530 531 opts, arg = self.parse_options(parameter_s, '')
531 532 if arg=='': arg = None
532 533 try:
533 534 return self.shell.enable_gui(arg)
534 535 except Exception as e:
535 536 # print simple error message, rather than traceback if we can't
536 537 # hook up the GUI
537 538 error(str(e))
538 539
539 540 @skip_doctest
540 541 @line_magic
541 542 def precision(self, s=''):
542 543 """Set floating point precision for pretty printing.
543 544
544 545 Can set either integer precision or a format string.
545 546
546 547 If numpy has been imported and precision is an int,
547 548 numpy display precision will also be set, via ``numpy.set_printoptions``.
548 549
549 550 If no argument is given, defaults will be restored.
550 551
551 552 Examples
552 553 --------
553 554 ::
554 555
555 556 In [1]: from math import pi
556 557
557 558 In [2]: %precision 3
558 559 Out[2]: u'%.3f'
559 560
560 561 In [3]: pi
561 562 Out[3]: 3.142
562 563
563 564 In [4]: %precision %i
564 565 Out[4]: u'%i'
565 566
566 567 In [5]: pi
567 568 Out[5]: 3
568 569
569 570 In [6]: %precision %e
570 571 Out[6]: u'%e'
571 572
572 573 In [7]: pi**10
573 574 Out[7]: 9.364805e+04
574 575
575 576 In [8]: %precision
576 577 Out[8]: u'%r'
577 578
578 579 In [9]: pi**10
579 580 Out[9]: 93648.047476082982
580 581 """
581 582 ptformatter = self.shell.display_formatter.formatters['text/plain']
582 583 ptformatter.float_precision = s
583 584 return ptformatter.float_format
584 585
585 586 @magic_arguments.magic_arguments()
586 587 @magic_arguments.argument(
587 588 '-e', '--export', action='store_true', default=False,
588 589 help='Export IPython history as a notebook. The filename argument '
589 590 'is used to specify the notebook name and format. For example '
590 591 'a filename of notebook.ipynb will result in a notebook name '
591 592 'of "notebook" and a format of "json". Likewise using a ".py" '
592 593 'file extension will write the notebook as a Python script'
593 594 )
594 595 @magic_arguments.argument(
595 596 '-f', '--format',
596 597 help='Convert an existing IPython notebook to a new format. This option '
597 598 'specifies the new format and can have the values: json, py. '
598 599 'The target filename is chosen automatically based on the new '
599 600 'format. The filename argument gives the name of the source file.'
600 601 )
601 602 @magic_arguments.argument(
602 'filename', type=unicode,
603 'filename', type=unicode_type,
603 604 help='Notebook name or filename'
604 605 )
605 606 @line_magic
606 607 def notebook(self, s):
607 608 """Export and convert IPython notebooks.
608 609
609 610 This function can export the current IPython history to a notebook file
610 611 or can convert an existing notebook file into a different format. For
611 612 example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
612 613 To export the history to "foo.py" do "%notebook -e foo.py". To convert
613 614 "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
614 615 formats include (json/ipynb, py).
615 616 """
616 617 args = magic_arguments.parse_argstring(self.notebook, s)
617 618
618 619 from IPython.nbformat import current
619 620 args.filename = unquote_filename(args.filename)
620 621 if args.export:
621 622 fname, name, format = current.parse_filename(args.filename)
622 623 cells = []
623 624 hist = list(self.shell.history_manager.get_range())
624 625 for session, prompt_number, input in hist[:-1]:
625 626 cells.append(current.new_code_cell(prompt_number=prompt_number,
626 627 input=input))
627 628 worksheet = current.new_worksheet(cells=cells)
628 629 nb = current.new_notebook(name=name,worksheets=[worksheet])
629 630 with io.open(fname, 'w', encoding='utf-8') as f:
630 631 current.write(nb, f, format);
631 632 elif args.format is not None:
632 633 old_fname, old_name, old_format = current.parse_filename(args.filename)
633 634 new_format = args.format
634 635 if new_format == u'xml':
635 636 raise ValueError('Notebooks cannot be written as xml.')
636 637 elif new_format == u'ipynb' or new_format == u'json':
637 638 new_fname = old_name + u'.ipynb'
638 639 new_format = u'json'
639 640 elif new_format == u'py':
640 641 new_fname = old_name + u'.py'
641 642 else:
642 643 raise ValueError('Invalid notebook format: %s' % new_format)
643 644 with io.open(old_fname, 'r', encoding='utf-8') as f:
644 645 nb = current.read(f, old_format)
645 646 with io.open(new_fname, 'w', encoding='utf-8') as f:
646 647 current.write(nb, f, new_format)
@@ -1,739 +1,740 b''
1 1 """Implementation of magic functions for interaction with the OS.
2 2
3 3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 4 builtin.
5 5 """
6 6 from __future__ import print_function
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2012 The IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # Stdlib
20 20 import io
21 21 import os
22 22 import re
23 23 import sys
24 24 from pprint import pformat
25 25
26 26 # Our own packages
27 27 from IPython.core import magic_arguments
28 28 from IPython.core import oinspect
29 29 from IPython.core import page
30 30 from IPython.core.alias import AliasError, Alias
31 31 from IPython.core.error import UsageError
32 32 from IPython.core.magic import (
33 33 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
34 34 )
35 35 from IPython.testing.skipdoctest import skip_doctest
36 36 from IPython.utils.openpy import source_to_unicode
37 37 from IPython.utils.path import unquote_filename
38 38 from IPython.utils.process import abbrev_cwd
39 from IPython.utils.py3compat import unicode_type
39 40 from IPython.utils.terminal import set_term_title
40 41
41 42 #-----------------------------------------------------------------------------
42 43 # Magic implementation classes
43 44 #-----------------------------------------------------------------------------
44 45 @magics_class
45 46 class OSMagics(Magics):
46 47 """Magics to interact with the underlying OS (shell-type functionality).
47 48 """
48 49
49 50 @skip_doctest
50 51 @line_magic
51 52 def alias(self, parameter_s=''):
52 53 """Define an alias for a system command.
53 54
54 55 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
55 56
56 57 Then, typing 'alias_name params' will execute the system command 'cmd
57 58 params' (from your underlying operating system).
58 59
59 60 Aliases have lower precedence than magic functions and Python normal
60 61 variables, so if 'foo' is both a Python variable and an alias, the
61 62 alias can not be executed until 'del foo' removes the Python variable.
62 63
63 64 You can use the %l specifier in an alias definition to represent the
64 65 whole line when the alias is called. For example::
65 66
66 67 In [2]: alias bracket echo "Input in brackets: <%l>"
67 68 In [3]: bracket hello world
68 69 Input in brackets: <hello world>
69 70
70 71 You can also define aliases with parameters using %s specifiers (one
71 72 per parameter)::
72 73
73 74 In [1]: alias parts echo first %s second %s
74 75 In [2]: %parts A B
75 76 first A second B
76 77 In [3]: %parts A
77 78 Incorrect number of arguments: 2 expected.
78 79 parts is an alias to: 'echo first %s second %s'
79 80
80 81 Note that %l and %s are mutually exclusive. You can only use one or
81 82 the other in your aliases.
82 83
83 84 Aliases expand Python variables just like system calls using ! or !!
84 85 do: all expressions prefixed with '$' get expanded. For details of
85 86 the semantic rules, see PEP-215:
86 87 http://www.python.org/peps/pep-0215.html. This is the library used by
87 88 IPython for variable expansion. If you want to access a true shell
88 89 variable, an extra $ is necessary to prevent its expansion by
89 90 IPython::
90 91
91 92 In [6]: alias show echo
92 93 In [7]: PATH='A Python string'
93 94 In [8]: show $PATH
94 95 A Python string
95 96 In [9]: show $$PATH
96 97 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
97 98
98 99 You can use the alias facility to acess all of $PATH. See the %rehash
99 100 and %rehashx functions, which automatically create aliases for the
100 101 contents of your $PATH.
101 102
102 103 If called with no parameters, %alias prints the current alias table."""
103 104
104 105 par = parameter_s.strip()
105 106 if not par:
106 107 aliases = sorted(self.shell.alias_manager.aliases)
107 108 # stored = self.shell.db.get('stored_aliases', {} )
108 109 # for k, v in stored:
109 110 # atab.append(k, v[0])
110 111
111 112 print("Total number of aliases:", len(aliases))
112 113 sys.stdout.flush()
113 114 return aliases
114 115
115 116 # Now try to define a new one
116 117 try:
117 118 alias,cmd = par.split(None, 1)
118 119 except TypeError:
119 120 print((oinspect.getdoc(self.alias)))
120 121 return
121 122
122 123 try:
123 124 self.shell.alias_manager.define_alias(alias, cmd)
124 125 except AliasError as e:
125 126 print(e)
126 127 # end magic_alias
127 128
128 129 @line_magic
129 130 def unalias(self, parameter_s=''):
130 131 """Remove an alias"""
131 132
132 133 aname = parameter_s.strip()
133 134 try:
134 135 self.shell.alias_manager.undefine_alias(aname)
135 136 except ValueError as e:
136 137 print(e)
137 138 return
138 139
139 140 stored = self.shell.db.get('stored_aliases', {} )
140 141 if aname in stored:
141 142 print("Removing %stored alias",aname)
142 143 del stored[aname]
143 144 self.shell.db['stored_aliases'] = stored
144 145
145 146 @line_magic
146 147 def rehashx(self, parameter_s=''):
147 148 """Update the alias table with all executable files in $PATH.
148 149
149 150 This version explicitly checks that every entry in $PATH is a file
150 151 with execute access (os.X_OK), so it is much slower than %rehash.
151 152
152 153 Under Windows, it checks executability as a match against a
153 154 '|'-separated string of extensions, stored in the IPython config
154 155 variable win_exec_ext. This defaults to 'exe|com|bat'.
155 156
156 157 This function also resets the root module cache of module completer,
157 158 used on slow filesystems.
158 159 """
159 160 from IPython.core.alias import InvalidAliasError
160 161
161 162 # for the benefit of module completer in ipy_completers.py
162 163 del self.shell.db['rootmodules_cache']
163 164
164 165 path = [os.path.abspath(os.path.expanduser(p)) for p in
165 166 os.environ.get('PATH','').split(os.pathsep)]
166 167 path = filter(os.path.isdir,path)
167 168
168 169 syscmdlist = []
169 170 # Now define isexec in a cross platform manner.
170 171 if os.name == 'posix':
171 172 isexec = lambda fname:os.path.isfile(fname) and \
172 173 os.access(fname,os.X_OK)
173 174 else:
174 175 try:
175 176 winext = os.environ['pathext'].replace(';','|').replace('.','')
176 177 except KeyError:
177 178 winext = 'exe|com|bat|py'
178 179 if 'py' not in winext:
179 180 winext += '|py'
180 181 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
181 182 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
182 183 savedir = os.getcwdu()
183 184
184 185 # Now walk the paths looking for executables to alias.
185 186 try:
186 187 # write the whole loop for posix/Windows so we don't have an if in
187 188 # the innermost part
188 189 if os.name == 'posix':
189 190 for pdir in path:
190 191 os.chdir(pdir)
191 192 for ff in os.listdir(pdir):
192 193 if isexec(ff):
193 194 try:
194 195 # Removes dots from the name since ipython
195 196 # will assume names with dots to be python.
196 197 if not self.shell.alias_manager.is_alias(ff):
197 198 self.shell.alias_manager.define_alias(
198 199 ff.replace('.',''), ff)
199 200 except InvalidAliasError:
200 201 pass
201 202 else:
202 203 syscmdlist.append(ff)
203 204 else:
204 205 no_alias = Alias.blacklist
205 206 for pdir in path:
206 207 os.chdir(pdir)
207 208 for ff in os.listdir(pdir):
208 209 base, ext = os.path.splitext(ff)
209 210 if isexec(ff) and base.lower() not in no_alias:
210 211 if ext.lower() == '.exe':
211 212 ff = base
212 213 try:
213 214 # Removes dots from the name since ipython
214 215 # will assume names with dots to be python.
215 216 self.shell.alias_manager.define_alias(
216 217 base.lower().replace('.',''), ff)
217 218 except InvalidAliasError:
218 219 pass
219 220 syscmdlist.append(ff)
220 221 self.shell.db['syscmdlist'] = syscmdlist
221 222 finally:
222 223 os.chdir(savedir)
223 224
224 225 @skip_doctest
225 226 @line_magic
226 227 def pwd(self, parameter_s=''):
227 228 """Return the current working directory path.
228 229
229 230 Examples
230 231 --------
231 232 ::
232 233
233 234 In [9]: pwd
234 235 Out[9]: '/home/tsuser/sprint/ipython'
235 236 """
236 237 return os.getcwdu()
237 238
238 239 @skip_doctest
239 240 @line_magic
240 241 def cd(self, parameter_s=''):
241 242 """Change the current working directory.
242 243
243 244 This command automatically maintains an internal list of directories
244 245 you visit during your IPython session, in the variable _dh. The
245 246 command %dhist shows this history nicely formatted. You can also
246 247 do 'cd -<tab>' to see directory history conveniently.
247 248
248 249 Usage:
249 250
250 251 cd 'dir': changes to directory 'dir'.
251 252
252 253 cd -: changes to the last visited directory.
253 254
254 255 cd -<n>: changes to the n-th directory in the directory history.
255 256
256 257 cd --foo: change to directory that matches 'foo' in history
257 258
258 259 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
259 260 (note: cd <bookmark_name> is enough if there is no
260 261 directory <bookmark_name>, but a bookmark with the name exists.)
261 262 'cd -b <tab>' allows you to tab-complete bookmark names.
262 263
263 264 Options:
264 265
265 266 -q: quiet. Do not print the working directory after the cd command is
266 267 executed. By default IPython's cd command does print this directory,
267 268 since the default prompts do not display path information.
268 269
269 270 Note that !cd doesn't work for this purpose because the shell where
270 271 !command runs is immediately discarded after executing 'command'.
271 272
272 273 Examples
273 274 --------
274 275 ::
275 276
276 277 In [10]: cd parent/child
277 278 /home/tsuser/parent/child
278 279 """
279 280
280 281 oldcwd = os.getcwdu()
281 282 numcd = re.match(r'(-)(\d+)$',parameter_s)
282 283 # jump in directory history by number
283 284 if numcd:
284 285 nn = int(numcd.group(2))
285 286 try:
286 287 ps = self.shell.user_ns['_dh'][nn]
287 288 except IndexError:
288 289 print('The requested directory does not exist in history.')
289 290 return
290 291 else:
291 292 opts = {}
292 293 elif parameter_s.startswith('--'):
293 294 ps = None
294 295 fallback = None
295 296 pat = parameter_s[2:]
296 297 dh = self.shell.user_ns['_dh']
297 298 # first search only by basename (last component)
298 299 for ent in reversed(dh):
299 300 if pat in os.path.basename(ent) and os.path.isdir(ent):
300 301 ps = ent
301 302 break
302 303
303 304 if fallback is None and pat in ent and os.path.isdir(ent):
304 305 fallback = ent
305 306
306 307 # if we have no last part match, pick the first full path match
307 308 if ps is None:
308 309 ps = fallback
309 310
310 311 if ps is None:
311 312 print("No matching entry in directory history")
312 313 return
313 314 else:
314 315 opts = {}
315 316
316 317
317 318 else:
318 319 #turn all non-space-escaping backslashes to slashes,
319 320 # for c:\windows\directory\names\
320 321 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
321 322 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
322 323 # jump to previous
323 324 if ps == '-':
324 325 try:
325 326 ps = self.shell.user_ns['_dh'][-2]
326 327 except IndexError:
327 328 raise UsageError('%cd -: No previous directory to change to.')
328 329 # jump to bookmark if needed
329 330 else:
330 331 if not os.path.isdir(ps) or 'b' in opts:
331 332 bkms = self.shell.db.get('bookmarks', {})
332 333
333 334 if ps in bkms:
334 335 target = bkms[ps]
335 336 print('(bookmark:%s) -> %s' % (ps, target))
336 337 ps = target
337 338 else:
338 339 if 'b' in opts:
339 340 raise UsageError("Bookmark '%s' not found. "
340 341 "Use '%%bookmark -l' to see your bookmarks." % ps)
341 342
342 343 # strip extra quotes on Windows, because os.chdir doesn't like them
343 344 ps = unquote_filename(ps)
344 345 # at this point ps should point to the target dir
345 346 if ps:
346 347 try:
347 348 os.chdir(os.path.expanduser(ps))
348 349 if hasattr(self.shell, 'term_title') and self.shell.term_title:
349 350 set_term_title('IPython: ' + abbrev_cwd())
350 351 except OSError:
351 352 print(sys.exc_info()[1])
352 353 else:
353 354 cwd = os.getcwdu()
354 355 dhist = self.shell.user_ns['_dh']
355 356 if oldcwd != cwd:
356 357 dhist.append(cwd)
357 358 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
358 359
359 360 else:
360 361 os.chdir(self.shell.home_dir)
361 362 if hasattr(self.shell, 'term_title') and self.shell.term_title:
362 363 set_term_title('IPython: ' + '~')
363 364 cwd = os.getcwdu()
364 365 dhist = self.shell.user_ns['_dh']
365 366
366 367 if oldcwd != cwd:
367 368 dhist.append(cwd)
368 369 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
369 370 if not 'q' in opts and self.shell.user_ns['_dh']:
370 371 print(self.shell.user_ns['_dh'][-1])
371 372
372 373
373 374 @line_magic
374 375 def env(self, parameter_s=''):
375 376 """List environment variables."""
376 377
377 378 return dict(os.environ)
378 379
379 380 @line_magic
380 381 def pushd(self, parameter_s=''):
381 382 """Place the current dir on stack and change directory.
382 383
383 384 Usage:\\
384 385 %pushd ['dirname']
385 386 """
386 387
387 388 dir_s = self.shell.dir_stack
388 389 tgt = os.path.expanduser(unquote_filename(parameter_s))
389 390 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
390 391 if tgt:
391 392 self.cd(parameter_s)
392 393 dir_s.insert(0,cwd)
393 394 return self.shell.magic('dirs')
394 395
395 396 @line_magic
396 397 def popd(self, parameter_s=''):
397 398 """Change to directory popped off the top of the stack.
398 399 """
399 400 if not self.shell.dir_stack:
400 401 raise UsageError("%popd on empty stack")
401 402 top = self.shell.dir_stack.pop(0)
402 403 self.cd(top)
403 404 print("popd ->",top)
404 405
405 406 @line_magic
406 407 def dirs(self, parameter_s=''):
407 408 """Return the current directory stack."""
408 409
409 410 return self.shell.dir_stack
410 411
411 412 @line_magic
412 413 def dhist(self, parameter_s=''):
413 414 """Print your history of visited directories.
414 415
415 416 %dhist -> print full history\\
416 417 %dhist n -> print last n entries only\\
417 418 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
418 419
419 420 This history is automatically maintained by the %cd command, and
420 421 always available as the global list variable _dh. You can use %cd -<n>
421 422 to go to directory number <n>.
422 423
423 424 Note that most of time, you should view directory history by entering
424 425 cd -<TAB>.
425 426
426 427 """
427 428
428 429 dh = self.shell.user_ns['_dh']
429 430 if parameter_s:
430 431 try:
431 432 args = map(int,parameter_s.split())
432 433 except:
433 434 self.arg_err(self.dhist)
434 435 return
435 436 if len(args) == 1:
436 437 ini,fin = max(len(dh)-(args[0]),0),len(dh)
437 438 elif len(args) == 2:
438 439 ini,fin = args
439 440 fin = min(fin, len(dh))
440 441 else:
441 442 self.arg_err(self.dhist)
442 443 return
443 444 else:
444 445 ini,fin = 0,len(dh)
445 446 print('Directory history (kept in _dh)')
446 447 for i in range(ini, fin):
447 448 print("%d: %s" % (i, dh[i]))
448 449
449 450 @skip_doctest
450 451 @line_magic
451 452 def sc(self, parameter_s=''):
452 453 """Shell capture - run shell command and capture output (DEPRECATED use !).
453 454
454 455 DEPRECATED. Suboptimal, retained for backwards compatibility.
455 456
456 457 You should use the form 'var = !command' instead. Example:
457 458
458 459 "%sc -l myfiles = ls ~" should now be written as
459 460
460 461 "myfiles = !ls ~"
461 462
462 463 myfiles.s, myfiles.l and myfiles.n still apply as documented
463 464 below.
464 465
465 466 --
466 467 %sc [options] varname=command
467 468
468 469 IPython will run the given command using commands.getoutput(), and
469 470 will then update the user's interactive namespace with a variable
470 471 called varname, containing the value of the call. Your command can
471 472 contain shell wildcards, pipes, etc.
472 473
473 474 The '=' sign in the syntax is mandatory, and the variable name you
474 475 supply must follow Python's standard conventions for valid names.
475 476
476 477 (A special format without variable name exists for internal use)
477 478
478 479 Options:
479 480
480 481 -l: list output. Split the output on newlines into a list before
481 482 assigning it to the given variable. By default the output is stored
482 483 as a single string.
483 484
484 485 -v: verbose. Print the contents of the variable.
485 486
486 487 In most cases you should not need to split as a list, because the
487 488 returned value is a special type of string which can automatically
488 489 provide its contents either as a list (split on newlines) or as a
489 490 space-separated string. These are convenient, respectively, either
490 491 for sequential processing or to be passed to a shell command.
491 492
492 493 For example::
493 494
494 495 # Capture into variable a
495 496 In [1]: sc a=ls *py
496 497
497 498 # a is a string with embedded newlines
498 499 In [2]: a
499 500 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
500 501
501 502 # which can be seen as a list:
502 503 In [3]: a.l
503 504 Out[3]: ['setup.py', 'win32_manual_post_install.py']
504 505
505 506 # or as a whitespace-separated string:
506 507 In [4]: a.s
507 508 Out[4]: 'setup.py win32_manual_post_install.py'
508 509
509 510 # a.s is useful to pass as a single command line:
510 511 In [5]: !wc -l $a.s
511 512 146 setup.py
512 513 130 win32_manual_post_install.py
513 514 276 total
514 515
515 516 # while the list form is useful to loop over:
516 517 In [6]: for f in a.l:
517 518 ...: !wc -l $f
518 519 ...:
519 520 146 setup.py
520 521 130 win32_manual_post_install.py
521 522
522 523 Similarly, the lists returned by the -l option are also special, in
523 524 the sense that you can equally invoke the .s attribute on them to
524 525 automatically get a whitespace-separated string from their contents::
525 526
526 527 In [7]: sc -l b=ls *py
527 528
528 529 In [8]: b
529 530 Out[8]: ['setup.py', 'win32_manual_post_install.py']
530 531
531 532 In [9]: b.s
532 533 Out[9]: 'setup.py win32_manual_post_install.py'
533 534
534 535 In summary, both the lists and strings used for output capture have
535 536 the following special attributes::
536 537
537 538 .l (or .list) : value as list.
538 539 .n (or .nlstr): value as newline-separated string.
539 540 .s (or .spstr): value as space-separated string.
540 541 """
541 542
542 543 opts,args = self.parse_options(parameter_s, 'lv')
543 544 # Try to get a variable name and command to run
544 545 try:
545 546 # the variable name must be obtained from the parse_options
546 547 # output, which uses shlex.split to strip options out.
547 548 var,_ = args.split('=', 1)
548 549 var = var.strip()
549 550 # But the command has to be extracted from the original input
550 551 # parameter_s, not on what parse_options returns, to avoid the
551 552 # quote stripping which shlex.split performs on it.
552 553 _,cmd = parameter_s.split('=', 1)
553 554 except ValueError:
554 555 var,cmd = '',''
555 556 # If all looks ok, proceed
556 557 split = 'l' in opts
557 558 out = self.shell.getoutput(cmd, split=split)
558 559 if 'v' in opts:
559 560 print('%s ==\n%s' % (var, pformat(out)))
560 561 if var:
561 562 self.shell.user_ns.update({var:out})
562 563 else:
563 564 return out
564 565
565 566 @line_cell_magic
566 567 def sx(self, line='', cell=None):
567 568 """Shell execute - run shell command and capture output (!! is short-hand).
568 569
569 570 %sx command
570 571
571 572 IPython will run the given command using commands.getoutput(), and
572 573 return the result formatted as a list (split on '\\n'). Since the
573 574 output is _returned_, it will be stored in ipython's regular output
574 575 cache Out[N] and in the '_N' automatic variables.
575 576
576 577 Notes:
577 578
578 579 1) If an input line begins with '!!', then %sx is automatically
579 580 invoked. That is, while::
580 581
581 582 !ls
582 583
583 584 causes ipython to simply issue system('ls'), typing::
584 585
585 586 !!ls
586 587
587 588 is a shorthand equivalent to::
588 589
589 590 %sx ls
590 591
591 592 2) %sx differs from %sc in that %sx automatically splits into a list,
592 593 like '%sc -l'. The reason for this is to make it as easy as possible
593 594 to process line-oriented shell output via further python commands.
594 595 %sc is meant to provide much finer control, but requires more
595 596 typing.
596 597
597 598 3) Just like %sc -l, this is a list with special attributes:
598 599 ::
599 600
600 601 .l (or .list) : value as list.
601 602 .n (or .nlstr): value as newline-separated string.
602 603 .s (or .spstr): value as whitespace-separated string.
603 604
604 605 This is very useful when trying to use such lists as arguments to
605 606 system commands."""
606 607
607 608 if cell is None:
608 609 # line magic
609 610 return self.shell.getoutput(line)
610 611 else:
611 612 opts,args = self.parse_options(line, '', 'out=')
612 613 output = self.shell.getoutput(cell)
613 614 out_name = opts.get('out', opts.get('o'))
614 615 if out_name:
615 616 self.shell.user_ns[out_name] = output
616 617 else:
617 618 return output
618 619
619 620 system = line_cell_magic('system')(sx)
620 621 bang = cell_magic('!')(sx)
621 622
622 623 @line_magic
623 624 def bookmark(self, parameter_s=''):
624 625 """Manage IPython's bookmark system.
625 626
626 627 %bookmark <name> - set bookmark to current dir
627 628 %bookmark <name> <dir> - set bookmark to <dir>
628 629 %bookmark -l - list all bookmarks
629 630 %bookmark -d <name> - remove bookmark
630 631 %bookmark -r - remove all bookmarks
631 632
632 633 You can later on access a bookmarked folder with::
633 634
634 635 %cd -b <name>
635 636
636 637 or simply '%cd <name>' if there is no directory called <name> AND
637 638 there is such a bookmark defined.
638 639
639 640 Your bookmarks persist through IPython sessions, but they are
640 641 associated with each profile."""
641 642
642 643 opts,args = self.parse_options(parameter_s,'drl',mode='list')
643 644 if len(args) > 2:
644 645 raise UsageError("%bookmark: too many arguments")
645 646
646 647 bkms = self.shell.db.get('bookmarks',{})
647 648
648 649 if 'd' in opts:
649 650 try:
650 651 todel = args[0]
651 652 except IndexError:
652 653 raise UsageError(
653 654 "%bookmark -d: must provide a bookmark to delete")
654 655 else:
655 656 try:
656 657 del bkms[todel]
657 658 except KeyError:
658 659 raise UsageError(
659 660 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
660 661
661 662 elif 'r' in opts:
662 663 bkms = {}
663 664 elif 'l' in opts:
664 665 bks = bkms.keys()
665 666 bks.sort()
666 667 if bks:
667 668 size = max(map(len, bks))
668 669 else:
669 670 size = 0
670 671 fmt = '%-'+str(size)+'s -> %s'
671 672 print('Current bookmarks:')
672 673 for bk in bks:
673 674 print(fmt % (bk, bkms[bk]))
674 675 else:
675 676 if not args:
676 677 raise UsageError("%bookmark: You must specify the bookmark name")
677 678 elif len(args)==1:
678 679 bkms[args[0]] = os.getcwdu()
679 680 elif len(args)==2:
680 681 bkms[args[0]] = args[1]
681 682 self.shell.db['bookmarks'] = bkms
682 683
683 684 @line_magic
684 685 def pycat(self, parameter_s=''):
685 686 """Show a syntax-highlighted file through a pager.
686 687
687 688 This magic is similar to the cat utility, but it will assume the file
688 689 to be Python source and will show it with syntax highlighting.
689 690
690 691 This magic command can either take a local filename, an url,
691 692 an history range (see %history) or a macro as argument ::
692 693
693 694 %pycat myscript.py
694 695 %pycat 7-27
695 696 %pycat myMacro
696 697 %pycat http://www.example.com/myscript.py
697 698 """
698 699 if not parameter_s:
699 700 raise UsageError('Missing filename, URL, input history range, '
700 701 'or macro.')
701 702
702 703 try :
703 704 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
704 705 except (ValueError, IOError):
705 706 print("Error: no such file, variable, URL, history range or macro")
706 707 return
707 708
708 709 page.page(self.shell.pycolorize(source_to_unicode(cont)))
709 710
710 711 @magic_arguments.magic_arguments()
711 712 @magic_arguments.argument(
712 713 '-a', '--append', action='store_true', default=False,
713 714 help='Append contents of the cell to an existing file. '
714 715 'The file will be created if it does not exist.'
715 716 )
716 717 @magic_arguments.argument(
717 'filename', type=unicode,
718 'filename', type=unicode_type,
718 719 help='file to write'
719 720 )
720 721 @cell_magic
721 722 def writefile(self, line, cell):
722 723 """Write the contents of the cell to a file.
723 724
724 725 The file will be overwritten unless the -a (--append) flag is specified.
725 726 """
726 727 args = magic_arguments.parse_argstring(self.writefile, line)
727 728 filename = os.path.expanduser(unquote_filename(args.filename))
728 729
729 730 if os.path.exists(filename):
730 731 if args.append:
731 732 print("Appending to %s" % filename)
732 733 else:
733 734 print("Overwriting %s" % filename)
734 735 else:
735 736 print("Writing %s" % filename)
736 737
737 738 mode = 'a' if args.append else 'w'
738 739 with io.open(filename, mode, encoding='utf-8') as f:
739 740 f.write(cell)
General Comments 0
You need to be logged in to leave comments. Login now