##// END OF EJS Templates
Use StringIO.StringIO on Python 2....
Thomas Kluyver -
Show More
@@ -1,654 +1,657 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Display formatters.
3 3
4 4 Inheritance diagram:
5 5
6 6 .. inheritance-diagram:: IPython.core.formatters
7 7 :parts: 3
8 8
9 9 Authors:
10 10
11 11 * Robert Kern
12 12 * Brian Granger
13 13 """
14 14 #-----------------------------------------------------------------------------
15 15 # Copyright (C) 2010-2011, IPython Development Team.
16 16 #
17 17 # Distributed under the terms of the Modified BSD License.
18 18 #
19 19 # The full license is in the file COPYING.txt, distributed with this software.
20 20 #-----------------------------------------------------------------------------
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 26 # Stdlib imports
27 27 import abc
28 28 import sys
29 29 import warnings
30 # We must use StringIO, as cStringIO doesn't handle unicode properly.
31 from io import StringIO
32 30
33 31 # Our own imports
34 32 from IPython.config.configurable import Configurable
35 33 from IPython.lib import pretty
36 34 from IPython.utils.traitlets import (
37 35 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
38 36 )
39 from IPython.utils.py3compat import unicode_to_str, with_metaclass
37 from IPython.utils.py3compat import unicode_to_str, with_metaclass, PY3
38
39 if PY3:
40 from io import StringIO
41 else:
42 from StringIO import StringIO
40 43
41 44
42 45 #-----------------------------------------------------------------------------
43 46 # The main DisplayFormatter class
44 47 #-----------------------------------------------------------------------------
45 48
46 49
47 50 class DisplayFormatter(Configurable):
48 51
49 52 # When set to true only the default plain text formatter will be used.
50 53 plain_text_only = Bool(False, config=True)
51 54 def _plain_text_only_changed(self, name, old, new):
52 55 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
53 56
54 57 Use DisplayFormatter.active_types = ['text/plain']
55 58 for the same effect.
56 59 """, DeprecationWarning)
57 60 if new:
58 61 self.active_types = ['text/plain']
59 62 else:
60 63 self.active_types = self.format_types
61 64
62 65 active_types = List(Unicode, config=True,
63 66 help="""List of currently active mime-types to display.
64 67 You can use this to set a white-list for formats to display.
65 68
66 69 Most users will not need to change this value.
67 70 """)
68 71 def _active_types_default(self):
69 72 return self.format_types
70 73
71 74 def _active_types_changed(self, name, old, new):
72 75 for key, formatter in self.formatters.items():
73 76 if key in new:
74 77 formatter.enabled = True
75 78 else:
76 79 formatter.enabled = False
77 80
78 81 # A dict of formatter whose keys are format types (MIME types) and whose
79 82 # values are subclasses of BaseFormatter.
80 83 formatters = Dict()
81 84 def _formatters_default(self):
82 85 """Activate the default formatters."""
83 86 formatter_classes = [
84 87 PlainTextFormatter,
85 88 HTMLFormatter,
86 89 SVGFormatter,
87 90 PNGFormatter,
88 91 JPEGFormatter,
89 92 LatexFormatter,
90 93 JSONFormatter,
91 94 JavascriptFormatter
92 95 ]
93 96 d = {}
94 97 for cls in formatter_classes:
95 98 f = cls(parent=self)
96 99 d[f.format_type] = f
97 100 return d
98 101
99 102 def format(self, obj, include=None, exclude=None):
100 103 """Return a format data dict for an object.
101 104
102 105 By default all format types will be computed.
103 106
104 107 The following MIME types are currently implemented:
105 108
106 109 * text/plain
107 110 * text/html
108 111 * text/latex
109 112 * application/json
110 113 * application/javascript
111 114 * image/png
112 115 * image/jpeg
113 116 * image/svg+xml
114 117
115 118 Parameters
116 119 ----------
117 120 obj : object
118 121 The Python object whose format data will be computed.
119 122 include : list or tuple, optional
120 123 A list of format type strings (MIME types) to include in the
121 124 format data dict. If this is set *only* the format types included
122 125 in this list will be computed.
123 126 exclude : list or tuple, optional
124 127 A list of format type string (MIME types) to exclude in the format
125 128 data dict. If this is set all format types will be computed,
126 129 except for those included in this argument.
127 130
128 131 Returns
129 132 -------
130 133 (format_dict, metadata_dict) : tuple of two dicts
131 134
132 135 format_dict is a dictionary of key/value pairs, one of each format that was
133 136 generated for the object. The keys are the format types, which
134 137 will usually be MIME type strings and the values and JSON'able
135 138 data structure containing the raw data for the representation in
136 139 that format.
137 140
138 141 metadata_dict is a dictionary of metadata about each mime-type output.
139 142 Its keys will be a strict subset of the keys in format_dict.
140 143 """
141 144 format_dict = {}
142 145 md_dict = {}
143 146
144 147 for format_type, formatter in self.formatters.items():
145 148 if include and format_type not in include:
146 149 continue
147 150 if exclude and format_type in exclude:
148 151 continue
149 152
150 153 md = None
151 154 try:
152 155 data = formatter(obj)
153 156 except:
154 157 # FIXME: log the exception
155 158 raise
156 159
157 160 # formatters can return raw data or (data, metadata)
158 161 if isinstance(data, tuple) and len(data) == 2:
159 162 data, md = data
160 163
161 164 if data is not None:
162 165 format_dict[format_type] = data
163 166 if md is not None:
164 167 md_dict[format_type] = md
165 168
166 169 return format_dict, md_dict
167 170
168 171 @property
169 172 def format_types(self):
170 173 """Return the format types (MIME types) of the active formatters."""
171 174 return list(self.formatters.keys())
172 175
173 176
174 177 #-----------------------------------------------------------------------------
175 178 # Formatters for specific format types (text, html, svg, etc.)
176 179 #-----------------------------------------------------------------------------
177 180
178 181
179 182 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
180 183 """ Abstract base class for Formatters.
181 184
182 185 A formatter is a callable class that is responsible for computing the
183 186 raw format data for a particular format type (MIME type). For example,
184 187 an HTML formatter would have a format type of `text/html` and would return
185 188 the HTML representation of the object when called.
186 189 """
187 190
188 191 # The format type of the data returned, usually a MIME type.
189 192 format_type = 'text/plain'
190 193
191 194 # Is the formatter enabled...
192 195 enabled = True
193 196
194 197 @abc.abstractmethod
195 198 def __call__(self, obj):
196 199 """Return a JSON'able representation of the object.
197 200
198 201 If the object cannot be formatted by this formatter, then return None
199 202 """
200 203 try:
201 204 return repr(obj)
202 205 except TypeError:
203 206 return None
204 207
205 208
206 209 class BaseFormatter(Configurable):
207 210 """A base formatter class that is configurable.
208 211
209 212 This formatter should usually be used as the base class of all formatters.
210 213 It is a traited :class:`Configurable` class and includes an extensible
211 214 API for users to determine how their objects are formatted. The following
212 215 logic is used to find a function to format an given object.
213 216
214 217 1. The object is introspected to see if it has a method with the name
215 218 :attr:`print_method`. If is does, that object is passed to that method
216 219 for formatting.
217 220 2. If no print method is found, three internal dictionaries are consulted
218 221 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
219 222 and :attr:`deferred_printers`.
220 223
221 224 Users should use these dictionaries to register functions that will be
222 225 used to compute the format data for their objects (if those objects don't
223 226 have the special print methods). The easiest way of using these
224 227 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
225 228 methods.
226 229
227 230 If no function/callable is found to compute the format data, ``None`` is
228 231 returned and this format type is not used.
229 232 """
230 233
231 234 format_type = Unicode('text/plain')
232 235
233 236 enabled = Bool(True, config=True)
234 237
235 238 print_method = ObjectName('__repr__')
236 239
237 240 # The singleton printers.
238 241 # Maps the IDs of the builtin singleton objects to the format functions.
239 242 singleton_printers = Dict(config=True)
240 243 def _singleton_printers_default(self):
241 244 return {}
242 245
243 246 # The type-specific printers.
244 247 # Map type objects to the format functions.
245 248 type_printers = Dict(config=True)
246 249 def _type_printers_default(self):
247 250 return {}
248 251
249 252 # The deferred-import type-specific printers.
250 253 # Map (modulename, classname) pairs to the format functions.
251 254 deferred_printers = Dict(config=True)
252 255 def _deferred_printers_default(self):
253 256 return {}
254 257
255 258 def __call__(self, obj):
256 259 """Compute the format for an object."""
257 260 if self.enabled:
258 261 obj_id = id(obj)
259 262 try:
260 263 obj_class = getattr(obj, '__class__', None) or type(obj)
261 264 # First try to find registered singleton printers for the type.
262 265 try:
263 266 printer = self.singleton_printers[obj_id]
264 267 except (TypeError, KeyError):
265 268 pass
266 269 else:
267 270 return printer(obj)
268 271 # Next look for type_printers.
269 272 for cls in pretty._get_mro(obj_class):
270 273 if cls in self.type_printers:
271 274 return self.type_printers[cls](obj)
272 275 else:
273 276 printer = self._in_deferred_types(cls)
274 277 if printer is not None:
275 278 return printer(obj)
276 279 # Finally look for special method names.
277 280 if hasattr(obj_class, self.print_method):
278 281 printer = getattr(obj_class, self.print_method)
279 282 return printer(obj)
280 283 return None
281 284 except Exception:
282 285 pass
283 286 else:
284 287 return None
285 288
286 289 def for_type(self, typ, func):
287 290 """Add a format function for a given type.
288 291
289 292 Parameters
290 293 -----------
291 294 typ : class
292 295 The class of the object that will be formatted using `func`.
293 296 func : callable
294 297 The callable that will be called to compute the format data. The
295 298 call signature of this function is simple, it must take the
296 299 object to be formatted and return the raw data for the given
297 300 format. Subclasses may use a different call signature for the
298 301 `func` argument.
299 302 """
300 303 oldfunc = self.type_printers.get(typ, None)
301 304 if func is not None:
302 305 # To support easy restoration of old printers, we need to ignore
303 306 # Nones.
304 307 self.type_printers[typ] = func
305 308 return oldfunc
306 309
307 310 def for_type_by_name(self, type_module, type_name, func):
308 311 """Add a format function for a type specified by the full dotted
309 312 module and name of the type, rather than the type of the object.
310 313
311 314 Parameters
312 315 ----------
313 316 type_module : str
314 317 The full dotted name of the module the type is defined in, like
315 318 ``numpy``.
316 319 type_name : str
317 320 The name of the type (the class name), like ``dtype``
318 321 func : callable
319 322 The callable that will be called to compute the format data. The
320 323 call signature of this function is simple, it must take the
321 324 object to be formatted and return the raw data for the given
322 325 format. Subclasses may use a different call signature for the
323 326 `func` argument.
324 327 """
325 328 key = (type_module, type_name)
326 329 oldfunc = self.deferred_printers.get(key, None)
327 330 if func is not None:
328 331 # To support easy restoration of old printers, we need to ignore
329 332 # Nones.
330 333 self.deferred_printers[key] = func
331 334 return oldfunc
332 335
333 336 def _in_deferred_types(self, cls):
334 337 """
335 338 Check if the given class is specified in the deferred type registry.
336 339
337 340 Returns the printer from the registry if it exists, and None if the
338 341 class is not in the registry. Successful matches will be moved to the
339 342 regular type registry for future use.
340 343 """
341 344 mod = getattr(cls, '__module__', None)
342 345 name = getattr(cls, '__name__', None)
343 346 key = (mod, name)
344 347 printer = None
345 348 if key in self.deferred_printers:
346 349 # Move the printer over to the regular registry.
347 350 printer = self.deferred_printers.pop(key)
348 351 self.type_printers[cls] = printer
349 352 return printer
350 353
351 354
352 355 class PlainTextFormatter(BaseFormatter):
353 356 """The default pretty-printer.
354 357
355 358 This uses :mod:`IPython.lib.pretty` to compute the format data of
356 359 the object. If the object cannot be pretty printed, :func:`repr` is used.
357 360 See the documentation of :mod:`IPython.lib.pretty` for details on
358 361 how to write pretty printers. Here is a simple example::
359 362
360 363 def dtype_pprinter(obj, p, cycle):
361 364 if cycle:
362 365 return p.text('dtype(...)')
363 366 if hasattr(obj, 'fields'):
364 367 if obj.fields is None:
365 368 p.text(repr(obj))
366 369 else:
367 370 p.begin_group(7, 'dtype([')
368 371 for i, field in enumerate(obj.descr):
369 372 if i > 0:
370 373 p.text(',')
371 374 p.breakable()
372 375 p.pretty(field)
373 376 p.end_group(7, '])')
374 377 """
375 378
376 379 # The format type of data returned.
377 380 format_type = Unicode('text/plain')
378 381
379 382 # This subclass ignores this attribute as it always need to return
380 383 # something.
381 384 enabled = Bool(True, config=False)
382 385
383 386 # Look for a _repr_pretty_ methods to use for pretty printing.
384 387 print_method = ObjectName('_repr_pretty_')
385 388
386 389 # Whether to pretty-print or not.
387 390 pprint = Bool(True, config=True)
388 391
389 392 # Whether to be verbose or not.
390 393 verbose = Bool(False, config=True)
391 394
392 395 # The maximum width.
393 396 max_width = Integer(79, config=True)
394 397
395 398 # The newline character.
396 399 newline = Unicode('\n', config=True)
397 400
398 401 # format-string for pprinting floats
399 402 float_format = Unicode('%r')
400 403 # setter for float precision, either int or direct format-string
401 404 float_precision = CUnicode('', config=True)
402 405
403 406 def _float_precision_changed(self, name, old, new):
404 407 """float_precision changed, set float_format accordingly.
405 408
406 409 float_precision can be set by int or str.
407 410 This will set float_format, after interpreting input.
408 411 If numpy has been imported, numpy print precision will also be set.
409 412
410 413 integer `n` sets format to '%.nf', otherwise, format set directly.
411 414
412 415 An empty string returns to defaults (repr for float, 8 for numpy).
413 416
414 417 This parameter can be set via the '%precision' magic.
415 418 """
416 419
417 420 if '%' in new:
418 421 # got explicit format string
419 422 fmt = new
420 423 try:
421 424 fmt%3.14159
422 425 except Exception:
423 426 raise ValueError("Precision must be int or format string, not %r"%new)
424 427 elif new:
425 428 # otherwise, should be an int
426 429 try:
427 430 i = int(new)
428 431 assert i >= 0
429 432 except ValueError:
430 433 raise ValueError("Precision must be int or format string, not %r"%new)
431 434 except AssertionError:
432 435 raise ValueError("int precision must be non-negative, not %r"%i)
433 436
434 437 fmt = '%%.%if'%i
435 438 if 'numpy' in sys.modules:
436 439 # set numpy precision if it has been imported
437 440 import numpy
438 441 numpy.set_printoptions(precision=i)
439 442 else:
440 443 # default back to repr
441 444 fmt = '%r'
442 445 if 'numpy' in sys.modules:
443 446 import numpy
444 447 # numpy default is 8
445 448 numpy.set_printoptions(precision=8)
446 449 self.float_format = fmt
447 450
448 451 # Use the default pretty printers from IPython.lib.pretty.
449 452 def _singleton_printers_default(self):
450 453 return pretty._singleton_pprinters.copy()
451 454
452 455 def _type_printers_default(self):
453 456 d = pretty._type_pprinters.copy()
454 457 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
455 458 return d
456 459
457 460 def _deferred_printers_default(self):
458 461 return pretty._deferred_type_pprinters.copy()
459 462
460 463 #### FormatterABC interface ####
461 464
462 465 def __call__(self, obj):
463 466 """Compute the pretty representation of the object."""
464 467 if not self.pprint:
465 468 try:
466 469 return repr(obj)
467 470 except TypeError:
468 471 return ''
469 472 else:
470 473 # This uses use StringIO, as cStringIO doesn't handle unicode.
471 474 stream = StringIO()
472 475 # self.newline.encode() is a quick fix for issue gh-597. We need to
473 476 # ensure that stream does not get a mix of unicode and bytestrings,
474 477 # or it will cause trouble.
475 478 printer = pretty.RepresentationPrinter(stream, self.verbose,
476 479 self.max_width, unicode_to_str(self.newline),
477 480 singleton_pprinters=self.singleton_printers,
478 481 type_pprinters=self.type_printers,
479 482 deferred_pprinters=self.deferred_printers)
480 483 printer.pretty(obj)
481 484 printer.flush()
482 485 return stream.getvalue()
483 486
484 487
485 488 class HTMLFormatter(BaseFormatter):
486 489 """An HTML formatter.
487 490
488 491 To define the callables that compute the HTML representation of your
489 492 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
490 493 or :meth:`for_type_by_name` methods to register functions that handle
491 494 this.
492 495
493 496 The return value of this formatter should be a valid HTML snippet that
494 497 could be injected into an existing DOM. It should *not* include the
495 498 ```<html>`` or ```<body>`` tags.
496 499 """
497 500 format_type = Unicode('text/html')
498 501
499 502 print_method = ObjectName('_repr_html_')
500 503
501 504
502 505 class SVGFormatter(BaseFormatter):
503 506 """An SVG formatter.
504 507
505 508 To define the callables that compute the SVG representation of your
506 509 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
507 510 or :meth:`for_type_by_name` methods to register functions that handle
508 511 this.
509 512
510 513 The return value of this formatter should be valid SVG enclosed in
511 514 ```<svg>``` tags, that could be injected into an existing DOM. It should
512 515 *not* include the ```<html>`` or ```<body>`` tags.
513 516 """
514 517 format_type = Unicode('image/svg+xml')
515 518
516 519 print_method = ObjectName('_repr_svg_')
517 520
518 521
519 522 class PNGFormatter(BaseFormatter):
520 523 """A PNG formatter.
521 524
522 525 To define the callables that compute the PNG representation of your
523 526 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
524 527 or :meth:`for_type_by_name` methods to register functions that handle
525 528 this.
526 529
527 530 The return value of this formatter should be raw PNG data, *not*
528 531 base64 encoded.
529 532 """
530 533 format_type = Unicode('image/png')
531 534
532 535 print_method = ObjectName('_repr_png_')
533 536
534 537
535 538 class JPEGFormatter(BaseFormatter):
536 539 """A JPEG formatter.
537 540
538 541 To define the callables that compute the JPEG representation of your
539 542 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
540 543 or :meth:`for_type_by_name` methods to register functions that handle
541 544 this.
542 545
543 546 The return value of this formatter should be raw JPEG data, *not*
544 547 base64 encoded.
545 548 """
546 549 format_type = Unicode('image/jpeg')
547 550
548 551 print_method = ObjectName('_repr_jpeg_')
549 552
550 553
551 554 class LatexFormatter(BaseFormatter):
552 555 """A LaTeX formatter.
553 556
554 557 To define the callables that compute the LaTeX representation of your
555 558 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
556 559 or :meth:`for_type_by_name` methods to register functions that handle
557 560 this.
558 561
559 562 The return value of this formatter should be a valid LaTeX equation,
560 563 enclosed in either ```$```, ```$$``` or another LaTeX equation
561 564 environment.
562 565 """
563 566 format_type = Unicode('text/latex')
564 567
565 568 print_method = ObjectName('_repr_latex_')
566 569
567 570
568 571 class JSONFormatter(BaseFormatter):
569 572 """A JSON string formatter.
570 573
571 574 To define the callables that compute the JSON string representation of
572 575 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
573 576 or :meth:`for_type_by_name` methods to register functions that handle
574 577 this.
575 578
576 579 The return value of this formatter should be a valid JSON string.
577 580 """
578 581 format_type = Unicode('application/json')
579 582
580 583 print_method = ObjectName('_repr_json_')
581 584
582 585
583 586 class JavascriptFormatter(BaseFormatter):
584 587 """A Javascript formatter.
585 588
586 589 To define the callables that compute the Javascript representation of
587 590 your objects, define a :meth:`_repr_javascript_` method or use the
588 591 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
589 592 that handle this.
590 593
591 594 The return value of this formatter should be valid Javascript code and
592 595 should *not* be enclosed in ```<script>``` tags.
593 596 """
594 597 format_type = Unicode('application/javascript')
595 598
596 599 print_method = ObjectName('_repr_javascript_')
597 600
598 601 FormatterABC.register(BaseFormatter)
599 602 FormatterABC.register(PlainTextFormatter)
600 603 FormatterABC.register(HTMLFormatter)
601 604 FormatterABC.register(SVGFormatter)
602 605 FormatterABC.register(PNGFormatter)
603 606 FormatterABC.register(JPEGFormatter)
604 607 FormatterABC.register(LatexFormatter)
605 608 FormatterABC.register(JSONFormatter)
606 609 FormatterABC.register(JavascriptFormatter)
607 610
608 611
609 612 def format_display_data(obj, include=None, exclude=None):
610 613 """Return a format data dict for an object.
611 614
612 615 By default all format types will be computed.
613 616
614 617 The following MIME types are currently implemented:
615 618
616 619 * text/plain
617 620 * text/html
618 621 * text/latex
619 622 * application/json
620 623 * application/javascript
621 624 * image/png
622 625 * image/jpeg
623 626 * image/svg+xml
624 627
625 628 Parameters
626 629 ----------
627 630 obj : object
628 631 The Python object whose format data will be computed.
629 632
630 633 Returns
631 634 -------
632 635 format_dict : dict
633 636 A dictionary of key/value pairs, one or each format that was
634 637 generated for the object. The keys are the format types, which
635 638 will usually be MIME type strings and the values and JSON'able
636 639 data structure containing the raw data for the representation in
637 640 that format.
638 641 include : list or tuple, optional
639 642 A list of format type strings (MIME types) to include in the
640 643 format data dict. If this is set *only* the format types included
641 644 in this list will be computed.
642 645 exclude : list or tuple, optional
643 646 A list of format type string (MIME types) to exclue in the format
644 647 data dict. If this is set all format types will be computed,
645 648 except for those included in this argument.
646 649 """
647 650 from IPython.core.interactiveshell import InteractiveShell
648 651
649 652 InteractiveShell.instance().display_formatter.format(
650 653 obj,
651 654 include,
652 655 exclude
653 656 )
654 657
@@ -1,531 +1,535 b''
1 1 import abc
2 2 import functools
3 3 import re
4 from io import StringIO
5 4
6 5 from IPython.core.splitinput import LineInfo
7 6 from IPython.utils import tokenize2
8 7 from IPython.utils.openpy import cookie_comment_re
9 from IPython.utils.py3compat import with_metaclass
8 from IPython.utils.py3compat import with_metaclass, PY3
10 9 from IPython.utils.tokenize2 import generate_tokens, untokenize, TokenError
11 10
11 if PY3:
12 from io import StringIO
13 else:
14 from StringIO import StringIO
15
12 16 #-----------------------------------------------------------------------------
13 17 # Globals
14 18 #-----------------------------------------------------------------------------
15 19
16 20 # The escape sequences that define the syntax transformations IPython will
17 21 # apply to user input. These can NOT be just changed here: many regular
18 22 # expressions and other parts of the code may use their hardcoded values, and
19 23 # for all intents and purposes they constitute the 'IPython syntax', so they
20 24 # should be considered fixed.
21 25
22 26 ESC_SHELL = '!' # Send line to underlying system shell
23 27 ESC_SH_CAP = '!!' # Send line to system shell and capture output
24 28 ESC_HELP = '?' # Find information about object
25 29 ESC_HELP2 = '??' # Find extra-detailed information about object
26 30 ESC_MAGIC = '%' # Call magic function
27 31 ESC_MAGIC2 = '%%' # Call cell-magic function
28 32 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
29 33 ESC_QUOTE2 = ';' # Quote all args as a single string, call
30 34 ESC_PAREN = '/' # Call first argument with rest of line as arguments
31 35
32 36 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
33 37 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
34 38 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
35 39
36 40
37 41 class InputTransformer(with_metaclass(abc.ABCMeta, object)):
38 42 """Abstract base class for line-based input transformers."""
39 43
40 44 @abc.abstractmethod
41 45 def push(self, line):
42 46 """Send a line of input to the transformer, returning the transformed
43 47 input or None if the transformer is waiting for more input.
44 48
45 49 Must be overridden by subclasses.
46 50 """
47 51 pass
48 52
49 53 @abc.abstractmethod
50 54 def reset(self):
51 55 """Return, transformed any lines that the transformer has accumulated,
52 56 and reset its internal state.
53 57
54 58 Must be overridden by subclasses.
55 59 """
56 60 pass
57 61
58 62 @classmethod
59 63 def wrap(cls, func):
60 64 """Can be used by subclasses as a decorator, to return a factory that
61 65 will allow instantiation with the decorated object.
62 66 """
63 67 @functools.wraps(func)
64 68 def transformer_factory(**kwargs):
65 69 return cls(func, **kwargs)
66 70
67 71 return transformer_factory
68 72
69 73 class StatelessInputTransformer(InputTransformer):
70 74 """Wrapper for a stateless input transformer implemented as a function."""
71 75 def __init__(self, func):
72 76 self.func = func
73 77
74 78 def __repr__(self):
75 79 return "StatelessInputTransformer(func={0!r})".format(self.func)
76 80
77 81 def push(self, line):
78 82 """Send a line of input to the transformer, returning the
79 83 transformed input."""
80 84 return self.func(line)
81 85
82 86 def reset(self):
83 87 """No-op - exists for compatibility."""
84 88 pass
85 89
86 90 class CoroutineInputTransformer(InputTransformer):
87 91 """Wrapper for an input transformer implemented as a coroutine."""
88 92 def __init__(self, coro, **kwargs):
89 93 # Prime it
90 94 self.coro = coro(**kwargs)
91 95 next(self.coro)
92 96
93 97 def __repr__(self):
94 98 return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
95 99
96 100 def push(self, line):
97 101 """Send a line of input to the transformer, returning the
98 102 transformed input or None if the transformer is waiting for more
99 103 input.
100 104 """
101 105 return self.coro.send(line)
102 106
103 107 def reset(self):
104 108 """Return, transformed any lines that the transformer has
105 109 accumulated, and reset its internal state.
106 110 """
107 111 return self.coro.send(None)
108 112
109 113 class TokenInputTransformer(InputTransformer):
110 114 """Wrapper for a token-based input transformer.
111 115
112 116 func should accept a list of tokens (5-tuples, see tokenize docs), and
113 117 return an iterable which can be passed to tokenize.untokenize().
114 118 """
115 119 def __init__(self, func):
116 120 self.func = func
117 121 self.current_line = ""
118 122 self.line_used = False
119 123 self.reset_tokenizer()
120 124
121 125 def reset_tokenizer(self):
122 126 self.tokenizer = generate_tokens(self.get_line)
123 127
124 128 def get_line(self):
125 129 if self.line_used:
126 130 raise TokenError
127 131 self.line_used = True
128 132 return self.current_line
129 133
130 134 def push(self, line):
131 135 self.current_line += line + "\n"
132 136 if self.current_line.isspace():
133 137 return self.reset()
134 138
135 139 self.line_used = False
136 140 tokens = []
137 141 stop_at_NL = False
138 142 try:
139 143 for intok in self.tokenizer:
140 144 tokens.append(intok)
141 145 t = intok[0]
142 146 if t == tokenize2.NEWLINE or (stop_at_NL and t == tokenize2.NL):
143 147 # Stop before we try to pull a line we don't have yet
144 148 break
145 149 elif t == tokenize2.ERRORTOKEN:
146 150 stop_at_NL = True
147 151 except TokenError:
148 152 # Multi-line statement - stop and try again with the next line
149 153 self.reset_tokenizer()
150 154 return None
151 155
152 156 return self.output(tokens)
153 157
154 158 def output(self, tokens):
155 159 self.current_line = ""
156 160 self.reset_tokenizer()
157 161 return untokenize(self.func(tokens)).rstrip('\n')
158 162
159 163 def reset(self):
160 164 l = self.current_line
161 165 self.current_line = ""
162 166 self.reset_tokenizer()
163 167 if l:
164 168 return l.rstrip('\n')
165 169
166 170 class assemble_python_lines(TokenInputTransformer):
167 171 def __init__(self):
168 172 super(assemble_python_lines, self).__init__(None)
169 173
170 174 def output(self, tokens):
171 175 return self.reset()
172 176
173 177 @CoroutineInputTransformer.wrap
174 178 def assemble_logical_lines():
175 179 """Join lines following explicit line continuations (\)"""
176 180 line = ''
177 181 while True:
178 182 line = (yield line)
179 183 if not line or line.isspace():
180 184 continue
181 185
182 186 parts = []
183 187 while line is not None:
184 188 if line.endswith('\\') and (not has_comment(line)):
185 189 parts.append(line[:-1])
186 190 line = (yield None) # Get another line
187 191 else:
188 192 parts.append(line)
189 193 break
190 194
191 195 # Output
192 196 line = ''.join(parts)
193 197
194 198 # Utilities
195 199 def _make_help_call(target, esc, lspace, next_input=None):
196 200 """Prepares a pinfo(2)/psearch call from a target name and the escape
197 201 (i.e. ? or ??)"""
198 202 method = 'pinfo2' if esc == '??' \
199 203 else 'psearch' if '*' in target \
200 204 else 'pinfo'
201 205 arg = " ".join([method, target])
202 206 if next_input is None:
203 207 return '%sget_ipython().magic(%r)' % (lspace, arg)
204 208 else:
205 209 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
206 210 (lspace, next_input, arg)
207 211
208 212 # These define the transformations for the different escape characters.
209 213 def _tr_system(line_info):
210 214 "Translate lines escaped with: !"
211 215 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
212 216 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
213 217
214 218 def _tr_system2(line_info):
215 219 "Translate lines escaped with: !!"
216 220 cmd = line_info.line.lstrip()[2:]
217 221 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
218 222
219 223 def _tr_help(line_info):
220 224 "Translate lines escaped with: ?/??"
221 225 # A naked help line should just fire the intro help screen
222 226 if not line_info.line[1:]:
223 227 return 'get_ipython().show_usage()'
224 228
225 229 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
226 230
227 231 def _tr_magic(line_info):
228 232 "Translate lines escaped with: %"
229 233 tpl = '%sget_ipython().magic(%r)'
230 234 if line_info.line.startswith(ESC_MAGIC2):
231 235 return line_info.line
232 236 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
233 237 return tpl % (line_info.pre, cmd)
234 238
235 239 def _tr_quote(line_info):
236 240 "Translate lines escaped with: ,"
237 241 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
238 242 '", "'.join(line_info.the_rest.split()) )
239 243
240 244 def _tr_quote2(line_info):
241 245 "Translate lines escaped with: ;"
242 246 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
243 247 line_info.the_rest)
244 248
245 249 def _tr_paren(line_info):
246 250 "Translate lines escaped with: /"
247 251 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
248 252 ", ".join(line_info.the_rest.split()))
249 253
250 254 tr = { ESC_SHELL : _tr_system,
251 255 ESC_SH_CAP : _tr_system2,
252 256 ESC_HELP : _tr_help,
253 257 ESC_HELP2 : _tr_help,
254 258 ESC_MAGIC : _tr_magic,
255 259 ESC_QUOTE : _tr_quote,
256 260 ESC_QUOTE2 : _tr_quote2,
257 261 ESC_PAREN : _tr_paren }
258 262
259 263 @StatelessInputTransformer.wrap
260 264 def escaped_commands(line):
261 265 """Transform escaped commands - %magic, !system, ?help + various autocalls.
262 266 """
263 267 if not line or line.isspace():
264 268 return line
265 269 lineinf = LineInfo(line)
266 270 if lineinf.esc not in tr:
267 271 return line
268 272
269 273 return tr[lineinf.esc](lineinf)
270 274
271 275 _initial_space_re = re.compile(r'\s*')
272 276
273 277 _help_end_re = re.compile(r"""(%{0,2}
274 278 [a-zA-Z_*][\w*]* # Variable name
275 279 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
276 280 )
277 281 (\?\??)$ # ? or ??
278 282 """,
279 283 re.VERBOSE)
280 284
281 285 # Extra pseudotokens for multiline strings and data structures
282 286 _MULTILINE_STRING = object()
283 287 _MULTILINE_STRUCTURE = object()
284 288
285 289 def _line_tokens(line):
286 290 """Helper for has_comment and ends_in_comment_or_string."""
287 291 readline = StringIO(line).readline
288 292 toktypes = set()
289 293 try:
290 294 for t in generate_tokens(readline):
291 295 toktypes.add(t[0])
292 296 except TokenError as e:
293 297 # There are only two cases where a TokenError is raised.
294 298 if 'multi-line string' in e.args[0]:
295 299 toktypes.add(_MULTILINE_STRING)
296 300 else:
297 301 toktypes.add(_MULTILINE_STRUCTURE)
298 302 return toktypes
299 303
300 304 def has_comment(src):
301 305 """Indicate whether an input line has (i.e. ends in, or is) a comment.
302 306
303 307 This uses tokenize, so it can distinguish comments from # inside strings.
304 308
305 309 Parameters
306 310 ----------
307 311 src : string
308 312 A single line input string.
309 313
310 314 Returns
311 315 -------
312 316 comment : bool
313 317 True if source has a comment.
314 318 """
315 319 return (tokenize2.COMMENT in _line_tokens(src))
316 320
317 321 def ends_in_comment_or_string(src):
318 322 """Indicates whether or not an input line ends in a comment or within
319 323 a multiline string.
320 324
321 325 Parameters
322 326 ----------
323 327 src : string
324 328 A single line input string.
325 329
326 330 Returns
327 331 -------
328 332 comment : bool
329 333 True if source ends in a comment or multiline string.
330 334 """
331 335 toktypes = _line_tokens(src)
332 336 return (tokenize2.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
333 337
334 338
335 339 @StatelessInputTransformer.wrap
336 340 def help_end(line):
337 341 """Translate lines with ?/?? at the end"""
338 342 m = _help_end_re.search(line)
339 343 if m is None or ends_in_comment_or_string(line):
340 344 return line
341 345 target = m.group(1)
342 346 esc = m.group(3)
343 347 lspace = _initial_space_re.match(line).group(0)
344 348
345 349 # If we're mid-command, put it back on the next prompt for the user.
346 350 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
347 351
348 352 return _make_help_call(target, esc, lspace, next_input)
349 353
350 354
351 355 @CoroutineInputTransformer.wrap
352 356 def cellmagic(end_on_blank_line=False):
353 357 """Captures & transforms cell magics.
354 358
355 359 After a cell magic is started, this stores up any lines it gets until it is
356 360 reset (sent None).
357 361 """
358 362 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
359 363 cellmagic_help_re = re.compile('%%\w+\?')
360 364 line = ''
361 365 while True:
362 366 line = (yield line)
363 367 # consume leading empty lines
364 368 while not line:
365 369 line = (yield line)
366 370
367 371 if not line.startswith(ESC_MAGIC2):
368 372 # This isn't a cell magic, idle waiting for reset then start over
369 373 while line is not None:
370 374 line = (yield line)
371 375 continue
372 376
373 377 if cellmagic_help_re.match(line):
374 378 # This case will be handled by help_end
375 379 continue
376 380
377 381 first = line
378 382 body = []
379 383 line = (yield None)
380 384 while (line is not None) and \
381 385 ((line.strip() != '') or not end_on_blank_line):
382 386 body.append(line)
383 387 line = (yield None)
384 388
385 389 # Output
386 390 magic_name, _, first = first.partition(' ')
387 391 magic_name = magic_name.lstrip(ESC_MAGIC2)
388 392 line = tpl % (magic_name, first, u'\n'.join(body))
389 393
390 394
391 395 def _strip_prompts(prompt_re, initial_re=None):
392 396 """Remove matching input prompts from a block of input.
393 397
394 398 Parameters
395 399 ----------
396 400 prompt_re : regular expression
397 401 A regular expression matching any input prompt (including continuation)
398 402 initial_re : regular expression, optional
399 403 A regular expression matching only the initial prompt, but not continuation.
400 404 If no initial expression is given, prompt_re will be used everywhere.
401 405 Used mainly for plain Python prompts, where the continuation prompt
402 406 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
403 407
404 408 If initial_re and prompt_re differ,
405 409 only initial_re will be tested against the first line.
406 410 If any prompt is found on the first two lines,
407 411 prompts will be stripped from the rest of the block.
408 412 """
409 413 if initial_re is None:
410 414 initial_re = prompt_re
411 415 line = ''
412 416 while True:
413 417 line = (yield line)
414 418
415 419 # First line of cell
416 420 if line is None:
417 421 continue
418 422 out, n1 = initial_re.subn('', line, count=1)
419 423 line = (yield out)
420 424
421 425 if line is None:
422 426 continue
423 427 # check for any prompt on the second line of the cell,
424 428 # because people often copy from just after the first prompt,
425 429 # so we might not see it in the first line.
426 430 out, n2 = prompt_re.subn('', line, count=1)
427 431 line = (yield out)
428 432
429 433 if n1 or n2:
430 434 # Found a prompt in the first two lines - check for it in
431 435 # the rest of the cell as well.
432 436 while line is not None:
433 437 line = (yield prompt_re.sub('', line, count=1))
434 438
435 439 else:
436 440 # Prompts not in input - wait for reset
437 441 while line is not None:
438 442 line = (yield line)
439 443
440 444 @CoroutineInputTransformer.wrap
441 445 def classic_prompt():
442 446 """Strip the >>>/... prompts of the Python interactive shell."""
443 447 # FIXME: non-capturing version (?:...) usable?
444 448 prompt_re = re.compile(r'^(>>> ?|\.\.\. ?)')
445 449 initial_re = re.compile(r'^(>>> ?)')
446 450 return _strip_prompts(prompt_re, initial_re)
447 451
448 452 @CoroutineInputTransformer.wrap
449 453 def ipy_prompt():
450 454 """Strip IPython's In [1]:/...: prompts."""
451 455 # FIXME: non-capturing version (?:...) usable?
452 456 # FIXME: r'^(In \[\d+\]: | {3}\.{3,}: )' clearer?
453 457 prompt_re = re.compile(r'^(In \[\d+\]: |\ \ \ \.\.\.+: )')
454 458 return _strip_prompts(prompt_re)
455 459
456 460
457 461 @CoroutineInputTransformer.wrap
458 462 def leading_indent():
459 463 """Remove leading indentation.
460 464
461 465 If the first line starts with a spaces or tabs, the same whitespace will be
462 466 removed from each following line until it is reset.
463 467 """
464 468 space_re = re.compile(r'^[ \t]+')
465 469 line = ''
466 470 while True:
467 471 line = (yield line)
468 472
469 473 if line is None:
470 474 continue
471 475
472 476 m = space_re.match(line)
473 477 if m:
474 478 space = m.group(0)
475 479 while line is not None:
476 480 if line.startswith(space):
477 481 line = line[len(space):]
478 482 line = (yield line)
479 483 else:
480 484 # No leading spaces - wait for reset
481 485 while line is not None:
482 486 line = (yield line)
483 487
484 488
485 489 @CoroutineInputTransformer.wrap
486 490 def strip_encoding_cookie():
487 491 """Remove encoding comment if found in first two lines
488 492
489 493 If the first or second line has the `# coding: utf-8` comment,
490 494 it will be removed.
491 495 """
492 496 line = ''
493 497 while True:
494 498 line = (yield line)
495 499 # check comment on first two lines
496 500 for i in range(2):
497 501 if line is None:
498 502 break
499 503 if cookie_comment_re.match(line):
500 504 line = (yield "")
501 505 else:
502 506 line = (yield line)
503 507
504 508 # no-op on the rest of the cell
505 509 while line is not None:
506 510 line = (yield line)
507 511
508 512
509 513 assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
510 514 r'\s*=\s*!\s*(?P<cmd>.*)')
511 515 assign_system_template = '%s = get_ipython().getoutput(%r)'
512 516 @StatelessInputTransformer.wrap
513 517 def assign_from_system(line):
514 518 """Transform assignment from system commands (e.g. files = !ls)"""
515 519 m = assign_system_re.match(line)
516 520 if m is None:
517 521 return line
518 522
519 523 return assign_system_template % m.group('lhs', 'cmd')
520 524
521 525 assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
522 526 r'\s*=\s*%\s*(?P<cmd>.*)')
523 527 assign_magic_template = '%s = get_ipython().magic(%r)'
524 528 @StatelessInputTransformer.wrap
525 529 def assign_from_magic(line):
526 530 """Transform assignment from magic commands (e.g. a = %who_ls)"""
527 531 m = assign_magic_re.match(line)
528 532 if m is None:
529 533 return line
530 534
531 535 return assign_magic_template % m.group('lhs', 'cmd')
@@ -1,1291 +1,1294 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Implementation of execution-related magic functions.
3 3 """
4 4 from __future__ import print_function
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2012 The IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 # Stdlib
18 18 import ast
19 19 import bdb
20 20 import os
21 21 import sys
22 22 import time
23 from io import StringIO
24 23
25 24 # cProfile was added in Python2.5
26 25 try:
27 26 import cProfile as profile
28 27 import pstats
29 28 except ImportError:
30 29 # profile isn't bundled by default in Debian for license reasons
31 30 try:
32 31 import profile, pstats
33 32 except ImportError:
34 33 profile = pstats = None
35 34
36 35 # Our own packages
37 36 from IPython.core import debugger, oinspect
38 37 from IPython.core import magic_arguments
39 38 from IPython.core import page
40 39 from IPython.core.error import UsageError
41 40 from IPython.core.macro import Macro
42 41 from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,
43 42 line_cell_magic, on_off, needs_local_scope)
44 43 from IPython.testing.skipdoctest import skip_doctest
45 44 from IPython.utils import py3compat
46 from IPython.utils.py3compat import builtin_mod, iteritems
45 from IPython.utils.py3compat import builtin_mod, iteritems, PY3
47 46 from IPython.utils.contexts import preserve_keys
48 47 from IPython.utils.io import capture_output
49 48 from IPython.utils.ipstruct import Struct
50 49 from IPython.utils.module_paths import find_mod
51 50 from IPython.utils.path import get_py_filename, unquote_filename, shellglob
52 51 from IPython.utils.timing import clock, clock2
53 52 from IPython.utils.warn import warn, error
54 53
54 if PY3:
55 from io import StringIO
56 else:
57 from StringIO import StringIO
55 58
56 59 #-----------------------------------------------------------------------------
57 60 # Magic implementation classes
58 61 #-----------------------------------------------------------------------------
59 62
60 63
61 64 class TimeitResult(object):
62 65 """
63 66 Object returned by the timeit magic with info about the run.
64 67
65 68 Contain the following attributes :
66 69
67 70 loops: (int) number of loop done per measurement
68 71 repeat: (int) number of time the mesurement has been repeated
69 72 best: (float) best execusion time / number
70 73 all_runs: (list of float) execusion time of each run (in s)
71 74 compile_time: (float) time of statement compilation (s)
72 75
73 76 """
74 77
75 78 def __init__(self, loops, repeat, best, all_runs, compile_time, precision):
76 79 self.loops = loops
77 80 self.repeat = repeat
78 81 self.best = best
79 82 self.all_runs = all_runs
80 83 self.compile_time = compile_time
81 84 self._precision = precision
82 85
83 86 def _repr_pretty_(self, p , cycle):
84 87 unic = u"%d loops, best of %d: %s per loop" % (self.loops, self.repeat,
85 88 _format_time(self.best, self._precision))
86 89 p.text(u'<TimeitResult : '+unic+u'>')
87 90
88 91
89 92 class TimeitTemplateFiller(ast.NodeTransformer):
90 93 "This is quite tightly tied to the template definition above."
91 94 def __init__(self, ast_setup, ast_stmt):
92 95 self.ast_setup = ast_setup
93 96 self.ast_stmt = ast_stmt
94 97
95 98 def visit_FunctionDef(self, node):
96 99 "Fill in the setup statement"
97 100 self.generic_visit(node)
98 101 if node.name == "inner":
99 102 node.body[:1] = self.ast_setup.body
100 103
101 104 return node
102 105
103 106 def visit_For(self, node):
104 107 "Fill in the statement to be timed"
105 108 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
106 109 node.body = self.ast_stmt.body
107 110 return node
108 111
109 112
110 113 @magics_class
111 114 class ExecutionMagics(Magics):
112 115 """Magics related to code execution, debugging, profiling, etc.
113 116
114 117 """
115 118
116 119 def __init__(self, shell):
117 120 super(ExecutionMagics, self).__init__(shell)
118 121 if profile is None:
119 122 self.prun = self.profile_missing_notice
120 123 # Default execution function used to actually run user code.
121 124 self.default_runner = None
122 125
123 126 def profile_missing_notice(self, *args, **kwargs):
124 127 error("""\
125 128 The profile module could not be found. It has been removed from the standard
126 129 python packages because of its non-free license. To use profiling, install the
127 130 python-profiler package from non-free.""")
128 131
129 132 @skip_doctest
130 133 @line_cell_magic
131 134 def prun(self, parameter_s='', cell=None):
132 135
133 136 """Run a statement through the python code profiler.
134 137
135 138 Usage, in line mode:
136 139 %prun [options] statement
137 140
138 141 Usage, in cell mode:
139 142 %%prun [options] [statement]
140 143 code...
141 144 code...
142 145
143 146 In cell mode, the additional code lines are appended to the (possibly
144 147 empty) statement in the first line. Cell mode allows you to easily
145 148 profile multiline blocks without having to put them in a separate
146 149 function.
147 150
148 151 The given statement (which doesn't require quote marks) is run via the
149 152 python profiler in a manner similar to the profile.run() function.
150 153 Namespaces are internally managed to work correctly; profile.run
151 154 cannot be used in IPython because it makes certain assumptions about
152 155 namespaces which do not hold under IPython.
153 156
154 157 Options:
155 158
156 159 -l <limit>
157 160 you can place restrictions on what or how much of the
158 161 profile gets printed. The limit value can be:
159 162
160 163 * A string: only information for function names containing this string
161 164 is printed.
162 165
163 166 * An integer: only these many lines are printed.
164 167
165 168 * A float (between 0 and 1): this fraction of the report is printed
166 169 (for example, use a limit of 0.4 to see the topmost 40% only).
167 170
168 171 You can combine several limits with repeated use of the option. For
169 172 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
170 173 information about class constructors.
171 174
172 175 -r
173 176 return the pstats.Stats object generated by the profiling. This
174 177 object has all the information about the profile in it, and you can
175 178 later use it for further analysis or in other functions.
176 179
177 180 -s <key>
178 181 sort profile by given key. You can provide more than one key
179 182 by using the option several times: '-s key1 -s key2 -s key3...'. The
180 183 default sorting key is 'time'.
181 184
182 185 The following is copied verbatim from the profile documentation
183 186 referenced below:
184 187
185 188 When more than one key is provided, additional keys are used as
186 189 secondary criteria when the there is equality in all keys selected
187 190 before them.
188 191
189 192 Abbreviations can be used for any key names, as long as the
190 193 abbreviation is unambiguous. The following are the keys currently
191 194 defined:
192 195
193 196 ============ =====================
194 197 Valid Arg Meaning
195 198 ============ =====================
196 199 "calls" call count
197 200 "cumulative" cumulative time
198 201 "file" file name
199 202 "module" file name
200 203 "pcalls" primitive call count
201 204 "line" line number
202 205 "name" function name
203 206 "nfl" name/file/line
204 207 "stdname" standard name
205 208 "time" internal time
206 209 ============ =====================
207 210
208 211 Note that all sorts on statistics are in descending order (placing
209 212 most time consuming items first), where as name, file, and line number
210 213 searches are in ascending order (i.e., alphabetical). The subtle
211 214 distinction between "nfl" and "stdname" is that the standard name is a
212 215 sort of the name as printed, which means that the embedded line
213 216 numbers get compared in an odd way. For example, lines 3, 20, and 40
214 217 would (if the file names were the same) appear in the string order
215 218 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
216 219 line numbers. In fact, sort_stats("nfl") is the same as
217 220 sort_stats("name", "file", "line").
218 221
219 222 -T <filename>
220 223 save profile results as shown on screen to a text
221 224 file. The profile is still shown on screen.
222 225
223 226 -D <filename>
224 227 save (via dump_stats) profile statistics to given
225 228 filename. This data is in a format understood by the pstats module, and
226 229 is generated by a call to the dump_stats() method of profile
227 230 objects. The profile is still shown on screen.
228 231
229 232 -q
230 233 suppress output to the pager. Best used with -T and/or -D above.
231 234
232 235 If you want to run complete programs under the profiler's control, use
233 236 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
234 237 contains profiler specific options as described here.
235 238
236 239 You can read the complete documentation for the profile module with::
237 240
238 241 In [1]: import profile; profile.help()
239 242 """
240 243 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
241 244 list_all=True, posix=False)
242 245 if cell is not None:
243 246 arg_str += '\n' + cell
244 247 arg_str = self.shell.input_splitter.transform_cell(arg_str)
245 248 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
246 249
247 250 def _run_with_profiler(self, code, opts, namespace):
248 251 """
249 252 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
250 253
251 254 Parameters
252 255 ----------
253 256 code : str
254 257 Code to be executed.
255 258 opts : Struct
256 259 Options parsed by `self.parse_options`.
257 260 namespace : dict
258 261 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
259 262
260 263 """
261 264
262 265 # Fill default values for unspecified options:
263 266 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
264 267
265 268 prof = profile.Profile()
266 269 try:
267 270 prof = prof.runctx(code, namespace, namespace)
268 271 sys_exit = ''
269 272 except SystemExit:
270 273 sys_exit = """*** SystemExit exception caught in code being profiled."""
271 274
272 275 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
273 276
274 277 lims = opts.l
275 278 if lims:
276 279 lims = [] # rebuild lims with ints/floats/strings
277 280 for lim in opts.l:
278 281 try:
279 282 lims.append(int(lim))
280 283 except ValueError:
281 284 try:
282 285 lims.append(float(lim))
283 286 except ValueError:
284 287 lims.append(lim)
285 288
286 289 # Trap output.
287 290 stdout_trap = StringIO()
288 291 stats_stream = stats.stream
289 292 try:
290 293 stats.stream = stdout_trap
291 294 stats.print_stats(*lims)
292 295 finally:
293 296 stats.stream = stats_stream
294 297
295 298 output = stdout_trap.getvalue()
296 299 output = output.rstrip()
297 300
298 301 if 'q' not in opts:
299 302 page.page(output)
300 303 print(sys_exit, end=' ')
301 304
302 305 dump_file = opts.D[0]
303 306 text_file = opts.T[0]
304 307 if dump_file:
305 308 dump_file = unquote_filename(dump_file)
306 309 prof.dump_stats(dump_file)
307 310 print('\n*** Profile stats marshalled to file',\
308 311 repr(dump_file)+'.',sys_exit)
309 312 if text_file:
310 313 text_file = unquote_filename(text_file)
311 314 pfile = open(text_file,'w')
312 315 pfile.write(output)
313 316 pfile.close()
314 317 print('\n*** Profile printout saved to text file',\
315 318 repr(text_file)+'.',sys_exit)
316 319
317 320 if 'r' in opts:
318 321 return stats
319 322 else:
320 323 return None
321 324
322 325 @line_magic
323 326 def pdb(self, parameter_s=''):
324 327 """Control the automatic calling of the pdb interactive debugger.
325 328
326 329 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
327 330 argument it works as a toggle.
328 331
329 332 When an exception is triggered, IPython can optionally call the
330 333 interactive pdb debugger after the traceback printout. %pdb toggles
331 334 this feature on and off.
332 335
333 336 The initial state of this feature is set in your configuration
334 337 file (the option is ``InteractiveShell.pdb``).
335 338
336 339 If you want to just activate the debugger AFTER an exception has fired,
337 340 without having to type '%pdb on' and rerunning your code, you can use
338 341 the %debug magic."""
339 342
340 343 par = parameter_s.strip().lower()
341 344
342 345 if par:
343 346 try:
344 347 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
345 348 except KeyError:
346 349 print ('Incorrect argument. Use on/1, off/0, '
347 350 'or nothing for a toggle.')
348 351 return
349 352 else:
350 353 # toggle
351 354 new_pdb = not self.shell.call_pdb
352 355
353 356 # set on the shell
354 357 self.shell.call_pdb = new_pdb
355 358 print('Automatic pdb calling has been turned',on_off(new_pdb))
356 359
357 360 @skip_doctest
358 361 @magic_arguments.magic_arguments()
359 362 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
360 363 help="""
361 364 Set break point at LINE in FILE.
362 365 """
363 366 )
364 367 @magic_arguments.argument('statement', nargs='*',
365 368 help="""
366 369 Code to run in debugger.
367 370 You can omit this in cell magic mode.
368 371 """
369 372 )
370 373 @line_cell_magic
371 374 def debug(self, line='', cell=None):
372 375 """Activate the interactive debugger.
373 376
374 377 This magic command support two ways of activating debugger.
375 378 One is to activate debugger before executing code. This way, you
376 379 can set a break point, to step through the code from the point.
377 380 You can use this mode by giving statements to execute and optionally
378 381 a breakpoint.
379 382
380 383 The other one is to activate debugger in post-mortem mode. You can
381 384 activate this mode simply running %debug without any argument.
382 385 If an exception has just occurred, this lets you inspect its stack
383 386 frames interactively. Note that this will always work only on the last
384 387 traceback that occurred, so you must call this quickly after an
385 388 exception that you wish to inspect has fired, because if another one
386 389 occurs, it clobbers the previous one.
387 390
388 391 If you want IPython to automatically do this on every exception, see
389 392 the %pdb magic for more details.
390 393 """
391 394 args = magic_arguments.parse_argstring(self.debug, line)
392 395
393 396 if not (args.breakpoint or args.statement or cell):
394 397 self._debug_post_mortem()
395 398 else:
396 399 code = "\n".join(args.statement)
397 400 if cell:
398 401 code += "\n" + cell
399 402 self._debug_exec(code, args.breakpoint)
400 403
401 404 def _debug_post_mortem(self):
402 405 self.shell.debugger(force=True)
403 406
404 407 def _debug_exec(self, code, breakpoint):
405 408 if breakpoint:
406 409 (filename, bp_line) = breakpoint.split(':', 1)
407 410 bp_line = int(bp_line)
408 411 else:
409 412 (filename, bp_line) = (None, None)
410 413 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
411 414
412 415 @line_magic
413 416 def tb(self, s):
414 417 """Print the last traceback with the currently active exception mode.
415 418
416 419 See %xmode for changing exception reporting modes."""
417 420 self.shell.showtraceback()
418 421
419 422 @skip_doctest
420 423 @line_magic
421 424 def run(self, parameter_s='', runner=None,
422 425 file_finder=get_py_filename):
423 426 """Run the named file inside IPython as a program.
424 427
425 428 Usage::
426 429
427 430 %run [-n -i -e -G]
428 431 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
429 432 ( -m mod | file ) [args]
430 433
431 434 Parameters after the filename are passed as command-line arguments to
432 435 the program (put in sys.argv). Then, control returns to IPython's
433 436 prompt.
434 437
435 438 This is similar to running at a system prompt ``python file args``,
436 439 but with the advantage of giving you IPython's tracebacks, and of
437 440 loading all variables into your interactive namespace for further use
438 441 (unless -p is used, see below).
439 442
440 443 The file is executed in a namespace initially consisting only of
441 444 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
442 445 sees its environment as if it were being run as a stand-alone program
443 446 (except for sharing global objects such as previously imported
444 447 modules). But after execution, the IPython interactive namespace gets
445 448 updated with all variables defined in the program (except for __name__
446 449 and sys.argv). This allows for very convenient loading of code for
447 450 interactive work, while giving each program a 'clean sheet' to run in.
448 451
449 452 Arguments are expanded using shell-like glob match. Patterns
450 453 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
451 454 tilde '~' will be expanded into user's home directory. Unlike
452 455 real shells, quotation does not suppress expansions. Use
453 456 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
454 457 To completely disable these expansions, you can use -G flag.
455 458
456 459 Options:
457 460
458 461 -n
459 462 __name__ is NOT set to '__main__', but to the running file's name
460 463 without extension (as python does under import). This allows running
461 464 scripts and reloading the definitions in them without calling code
462 465 protected by an ``if __name__ == "__main__"`` clause.
463 466
464 467 -i
465 468 run the file in IPython's namespace instead of an empty one. This
466 469 is useful if you are experimenting with code written in a text editor
467 470 which depends on variables defined interactively.
468 471
469 472 -e
470 473 ignore sys.exit() calls or SystemExit exceptions in the script
471 474 being run. This is particularly useful if IPython is being used to
472 475 run unittests, which always exit with a sys.exit() call. In such
473 476 cases you are interested in the output of the test results, not in
474 477 seeing a traceback of the unittest module.
475 478
476 479 -t
477 480 print timing information at the end of the run. IPython will give
478 481 you an estimated CPU time consumption for your script, which under
479 482 Unix uses the resource module to avoid the wraparound problems of
480 483 time.clock(). Under Unix, an estimate of time spent on system tasks
481 484 is also given (for Windows platforms this is reported as 0.0).
482 485
483 486 If -t is given, an additional ``-N<N>`` option can be given, where <N>
484 487 must be an integer indicating how many times you want the script to
485 488 run. The final timing report will include total and per run results.
486 489
487 490 For example (testing the script uniq_stable.py)::
488 491
489 492 In [1]: run -t uniq_stable
490 493
491 494 IPython CPU timings (estimated):
492 495 User : 0.19597 s.
493 496 System: 0.0 s.
494 497
495 498 In [2]: run -t -N5 uniq_stable
496 499
497 500 IPython CPU timings (estimated):
498 501 Total runs performed: 5
499 502 Times : Total Per run
500 503 User : 0.910862 s, 0.1821724 s.
501 504 System: 0.0 s, 0.0 s.
502 505
503 506 -d
504 507 run your program under the control of pdb, the Python debugger.
505 508 This allows you to execute your program step by step, watch variables,
506 509 etc. Internally, what IPython does is similar to calling::
507 510
508 511 pdb.run('execfile("YOURFILENAME")')
509 512
510 513 with a breakpoint set on line 1 of your file. You can change the line
511 514 number for this automatic breakpoint to be <N> by using the -bN option
512 515 (where N must be an integer). For example::
513 516
514 517 %run -d -b40 myscript
515 518
516 519 will set the first breakpoint at line 40 in myscript.py. Note that
517 520 the first breakpoint must be set on a line which actually does
518 521 something (not a comment or docstring) for it to stop execution.
519 522
520 523 Or you can specify a breakpoint in a different file::
521 524
522 525 %run -d -b myotherfile.py:20 myscript
523 526
524 527 When the pdb debugger starts, you will see a (Pdb) prompt. You must
525 528 first enter 'c' (without quotes) to start execution up to the first
526 529 breakpoint.
527 530
528 531 Entering 'help' gives information about the use of the debugger. You
529 532 can easily see pdb's full documentation with "import pdb;pdb.help()"
530 533 at a prompt.
531 534
532 535 -p
533 536 run program under the control of the Python profiler module (which
534 537 prints a detailed report of execution times, function calls, etc).
535 538
536 539 You can pass other options after -p which affect the behavior of the
537 540 profiler itself. See the docs for %prun for details.
538 541
539 542 In this mode, the program's variables do NOT propagate back to the
540 543 IPython interactive namespace (because they remain in the namespace
541 544 where the profiler executes them).
542 545
543 546 Internally this triggers a call to %prun, see its documentation for
544 547 details on the options available specifically for profiling.
545 548
546 549 There is one special usage for which the text above doesn't apply:
547 550 if the filename ends with .ipy, the file is run as ipython script,
548 551 just as if the commands were written on IPython prompt.
549 552
550 553 -m
551 554 specify module name to load instead of script path. Similar to
552 555 the -m option for the python interpreter. Use this option last if you
553 556 want to combine with other %run options. Unlike the python interpreter
554 557 only source modules are allowed no .pyc or .pyo files.
555 558 For example::
556 559
557 560 %run -m example
558 561
559 562 will run the example module.
560 563
561 564 -G
562 565 disable shell-like glob expansion of arguments.
563 566
564 567 """
565 568
566 569 # get arguments and set sys.argv for program to be run.
567 570 opts, arg_lst = self.parse_options(parameter_s,
568 571 'nidtN:b:pD:l:rs:T:em:G',
569 572 mode='list', list_all=1)
570 573 if "m" in opts:
571 574 modulename = opts["m"][0]
572 575 modpath = find_mod(modulename)
573 576 if modpath is None:
574 577 warn('%r is not a valid modulename on sys.path'%modulename)
575 578 return
576 579 arg_lst = [modpath] + arg_lst
577 580 try:
578 581 filename = file_finder(arg_lst[0])
579 582 except IndexError:
580 583 warn('you must provide at least a filename.')
581 584 print('\n%run:\n', oinspect.getdoc(self.run))
582 585 return
583 586 except IOError as e:
584 587 try:
585 588 msg = str(e)
586 589 except UnicodeError:
587 590 msg = e.message
588 591 error(msg)
589 592 return
590 593
591 594 if filename.lower().endswith('.ipy'):
592 595 with preserve_keys(self.shell.user_ns, '__file__'):
593 596 self.shell.user_ns['__file__'] = filename
594 597 self.shell.safe_execfile_ipy(filename)
595 598 return
596 599
597 600 # Control the response to exit() calls made by the script being run
598 601 exit_ignore = 'e' in opts
599 602
600 603 # Make sure that the running script gets a proper sys.argv as if it
601 604 # were run from a system shell.
602 605 save_argv = sys.argv # save it for later restoring
603 606
604 607 if 'G' in opts:
605 608 args = arg_lst[1:]
606 609 else:
607 610 # tilde and glob expansion
608 611 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
609 612
610 613 sys.argv = [filename] + args # put in the proper filename
611 614 # protect sys.argv from potential unicode strings on Python 2:
612 615 if not py3compat.PY3:
613 616 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
614 617
615 618 if 'i' in opts:
616 619 # Run in user's interactive namespace
617 620 prog_ns = self.shell.user_ns
618 621 __name__save = self.shell.user_ns['__name__']
619 622 prog_ns['__name__'] = '__main__'
620 623 main_mod = self.shell.user_module
621 624
622 625 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
623 626 # set the __file__ global in the script's namespace
624 627 # TK: Is this necessary in interactive mode?
625 628 prog_ns['__file__'] = filename
626 629 else:
627 630 # Run in a fresh, empty namespace
628 631 if 'n' in opts:
629 632 name = os.path.splitext(os.path.basename(filename))[0]
630 633 else:
631 634 name = '__main__'
632 635
633 636 # The shell MUST hold a reference to prog_ns so after %run
634 637 # exits, the python deletion mechanism doesn't zero it out
635 638 # (leaving dangling references). See interactiveshell for details
636 639 main_mod = self.shell.new_main_mod(filename, name)
637 640 prog_ns = main_mod.__dict__
638 641
639 642 # pickle fix. See interactiveshell for an explanation. But we need to
640 643 # make sure that, if we overwrite __main__, we replace it at the end
641 644 main_mod_name = prog_ns['__name__']
642 645
643 646 if main_mod_name == '__main__':
644 647 restore_main = sys.modules['__main__']
645 648 else:
646 649 restore_main = False
647 650
648 651 # This needs to be undone at the end to prevent holding references to
649 652 # every single object ever created.
650 653 sys.modules[main_mod_name] = main_mod
651 654
652 655 if 'p' in opts or 'd' in opts:
653 656 if 'm' in opts:
654 657 code = 'run_module(modulename, prog_ns)'
655 658 code_ns = {
656 659 'run_module': self.shell.safe_run_module,
657 660 'prog_ns': prog_ns,
658 661 'modulename': modulename,
659 662 }
660 663 else:
661 664 code = 'execfile(filename, prog_ns)'
662 665 code_ns = {
663 666 'execfile': self.shell.safe_execfile,
664 667 'prog_ns': prog_ns,
665 668 'filename': get_py_filename(filename),
666 669 }
667 670
668 671 try:
669 672 stats = None
670 673 with self.shell.readline_no_record:
671 674 if 'p' in opts:
672 675 stats = self._run_with_profiler(code, opts, code_ns)
673 676 else:
674 677 if 'd' in opts:
675 678 bp_file, bp_line = parse_breakpoint(
676 679 opts.get('b', ['1'])[0], filename)
677 680 self._run_with_debugger(
678 681 code, code_ns, filename, bp_line, bp_file)
679 682 else:
680 683 if 'm' in opts:
681 684 def run():
682 685 self.shell.safe_run_module(modulename, prog_ns)
683 686 else:
684 687 if runner is None:
685 688 runner = self.default_runner
686 689 if runner is None:
687 690 runner = self.shell.safe_execfile
688 691
689 692 def run():
690 693 runner(filename, prog_ns, prog_ns,
691 694 exit_ignore=exit_ignore)
692 695
693 696 if 't' in opts:
694 697 # timed execution
695 698 try:
696 699 nruns = int(opts['N'][0])
697 700 if nruns < 1:
698 701 error('Number of runs must be >=1')
699 702 return
700 703 except (KeyError):
701 704 nruns = 1
702 705 self._run_with_timing(run, nruns)
703 706 else:
704 707 # regular execution
705 708 run()
706 709
707 710 if 'i' in opts:
708 711 self.shell.user_ns['__name__'] = __name__save
709 712 else:
710 713 # update IPython interactive namespace
711 714
712 715 # Some forms of read errors on the file may mean the
713 716 # __name__ key was never set; using pop we don't have to
714 717 # worry about a possible KeyError.
715 718 prog_ns.pop('__name__', None)
716 719
717 720 with preserve_keys(self.shell.user_ns, '__file__'):
718 721 self.shell.user_ns.update(prog_ns)
719 722 finally:
720 723 # It's a bit of a mystery why, but __builtins__ can change from
721 724 # being a module to becoming a dict missing some key data after
722 725 # %run. As best I can see, this is NOT something IPython is doing
723 726 # at all, and similar problems have been reported before:
724 727 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
725 728 # Since this seems to be done by the interpreter itself, the best
726 729 # we can do is to at least restore __builtins__ for the user on
727 730 # exit.
728 731 self.shell.user_ns['__builtins__'] = builtin_mod
729 732
730 733 # Ensure key global structures are restored
731 734 sys.argv = save_argv
732 735 if restore_main:
733 736 sys.modules['__main__'] = restore_main
734 737 else:
735 738 # Remove from sys.modules the reference to main_mod we'd
736 739 # added. Otherwise it will trap references to objects
737 740 # contained therein.
738 741 del sys.modules[main_mod_name]
739 742
740 743 return stats
741 744
742 745 def _run_with_debugger(self, code, code_ns, filename=None,
743 746 bp_line=None, bp_file=None):
744 747 """
745 748 Run `code` in debugger with a break point.
746 749
747 750 Parameters
748 751 ----------
749 752 code : str
750 753 Code to execute.
751 754 code_ns : dict
752 755 A namespace in which `code` is executed.
753 756 filename : str
754 757 `code` is ran as if it is in `filename`.
755 758 bp_line : int, optional
756 759 Line number of the break point.
757 760 bp_file : str, optional
758 761 Path to the file in which break point is specified.
759 762 `filename` is used if not given.
760 763
761 764 Raises
762 765 ------
763 766 UsageError
764 767 If the break point given by `bp_line` is not valid.
765 768
766 769 """
767 770 deb = debugger.Pdb(self.shell.colors)
768 771 # reset Breakpoint state, which is moronically kept
769 772 # in a class
770 773 bdb.Breakpoint.next = 1
771 774 bdb.Breakpoint.bplist = {}
772 775 bdb.Breakpoint.bpbynumber = [None]
773 776 if bp_line is not None:
774 777 # Set an initial breakpoint to stop execution
775 778 maxtries = 10
776 779 bp_file = bp_file or filename
777 780 checkline = deb.checkline(bp_file, bp_line)
778 781 if not checkline:
779 782 for bp in range(bp_line + 1, bp_line + maxtries + 1):
780 783 if deb.checkline(bp_file, bp):
781 784 break
782 785 else:
783 786 msg = ("\nI failed to find a valid line to set "
784 787 "a breakpoint\n"
785 788 "after trying up to line: %s.\n"
786 789 "Please set a valid breakpoint manually "
787 790 "with the -b option." % bp)
788 791 raise UsageError(msg)
789 792 # if we find a good linenumber, set the breakpoint
790 793 deb.do_break('%s:%s' % (bp_file, bp_line))
791 794
792 795 if filename:
793 796 # Mimic Pdb._runscript(...)
794 797 deb._wait_for_mainpyfile = True
795 798 deb.mainpyfile = deb.canonic(filename)
796 799
797 800 # Start file run
798 801 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
799 802 try:
800 803 if filename:
801 804 # save filename so it can be used by methods on the deb object
802 805 deb._exec_filename = filename
803 806 deb.run(code, code_ns)
804 807
805 808 except:
806 809 etype, value, tb = sys.exc_info()
807 810 # Skip three frames in the traceback: the %run one,
808 811 # one inside bdb.py, and the command-line typed by the
809 812 # user (run by exec in pdb itself).
810 813 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
811 814
812 815 @staticmethod
813 816 def _run_with_timing(run, nruns):
814 817 """
815 818 Run function `run` and print timing information.
816 819
817 820 Parameters
818 821 ----------
819 822 run : callable
820 823 Any callable object which takes no argument.
821 824 nruns : int
822 825 Number of times to execute `run`.
823 826
824 827 """
825 828 twall0 = time.time()
826 829 if nruns == 1:
827 830 t0 = clock2()
828 831 run()
829 832 t1 = clock2()
830 833 t_usr = t1[0] - t0[0]
831 834 t_sys = t1[1] - t0[1]
832 835 print("\nIPython CPU timings (estimated):")
833 836 print(" User : %10.2f s." % t_usr)
834 837 print(" System : %10.2f s." % t_sys)
835 838 else:
836 839 runs = range(nruns)
837 840 t0 = clock2()
838 841 for nr in runs:
839 842 run()
840 843 t1 = clock2()
841 844 t_usr = t1[0] - t0[0]
842 845 t_sys = t1[1] - t0[1]
843 846 print("\nIPython CPU timings (estimated):")
844 847 print("Total runs performed:", nruns)
845 848 print(" Times : %10s %10s" % ('Total', 'Per run'))
846 849 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
847 850 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
848 851 twall1 = time.time()
849 852 print("Wall time: %10.2f s." % (twall1 - twall0))
850 853
851 854 @skip_doctest
852 855 @line_cell_magic
853 856 def timeit(self, line='', cell=None):
854 857 """Time execution of a Python statement or expression
855 858
856 859 Usage, in line mode:
857 860 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
858 861 or in cell mode:
859 862 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
860 863 code
861 864 code...
862 865
863 866 Time execution of a Python statement or expression using the timeit
864 867 module. This function can be used both as a line and cell magic:
865 868
866 869 - In line mode you can time a single-line statement (though multiple
867 870 ones can be chained with using semicolons).
868 871
869 872 - In cell mode, the statement in the first line is used as setup code
870 873 (executed but not timed) and the body of the cell is timed. The cell
871 874 body has access to any variables created in the setup code.
872 875
873 876 Options:
874 877 -n<N>: execute the given statement <N> times in a loop. If this value
875 878 is not given, a fitting value is chosen.
876 879
877 880 -r<R>: repeat the loop iteration <R> times and take the best result.
878 881 Default: 3
879 882
880 883 -t: use time.time to measure the time, which is the default on Unix.
881 884 This function measures wall time.
882 885
883 886 -c: use time.clock to measure the time, which is the default on
884 887 Windows and measures wall time. On Unix, resource.getrusage is used
885 888 instead and returns the CPU user time.
886 889
887 890 -p<P>: use a precision of <P> digits to display the timing result.
888 891 Default: 3
889 892
890 893 -q: Quiet, do not print result.
891 894
892 895 -o: return a TimeitResult that can be stored in a variable to inspect
893 896 the result in more details.
894 897
895 898
896 899 Examples
897 900 --------
898 901 ::
899 902
900 903 In [1]: %timeit pass
901 904 10000000 loops, best of 3: 53.3 ns per loop
902 905
903 906 In [2]: u = None
904 907
905 908 In [3]: %timeit u is None
906 909 10000000 loops, best of 3: 184 ns per loop
907 910
908 911 In [4]: %timeit -r 4 u == None
909 912 1000000 loops, best of 4: 242 ns per loop
910 913
911 914 In [5]: import time
912 915
913 916 In [6]: %timeit -n1 time.sleep(2)
914 917 1 loops, best of 3: 2 s per loop
915 918
916 919
917 920 The times reported by %timeit will be slightly higher than those
918 921 reported by the timeit.py script when variables are accessed. This is
919 922 due to the fact that %timeit executes the statement in the namespace
920 923 of the shell, compared with timeit.py, which uses a single setup
921 924 statement to import function or create variables. Generally, the bias
922 925 does not matter as long as results from timeit.py are not mixed with
923 926 those from %timeit."""
924 927
925 928 import timeit
926 929
927 930 opts, stmt = self.parse_options(line,'n:r:tcp:qo',
928 931 posix=False, strict=False)
929 932 if stmt == "" and cell is None:
930 933 return
931 934
932 935 timefunc = timeit.default_timer
933 936 number = int(getattr(opts, "n", 0))
934 937 repeat = int(getattr(opts, "r", timeit.default_repeat))
935 938 precision = int(getattr(opts, "p", 3))
936 939 quiet = 'q' in opts
937 940 return_result = 'o' in opts
938 941 if hasattr(opts, "t"):
939 942 timefunc = time.time
940 943 if hasattr(opts, "c"):
941 944 timefunc = clock
942 945
943 946 timer = timeit.Timer(timer=timefunc)
944 947 # this code has tight coupling to the inner workings of timeit.Timer,
945 948 # but is there a better way to achieve that the code stmt has access
946 949 # to the shell namespace?
947 950 transform = self.shell.input_splitter.transform_cell
948 951
949 952 if cell is None:
950 953 # called as line magic
951 954 ast_setup = ast.parse("pass")
952 955 ast_stmt = ast.parse(transform(stmt))
953 956 else:
954 957 ast_setup = ast.parse(transform(stmt))
955 958 ast_stmt = ast.parse(transform(cell))
956 959
957 960 ast_setup = self.shell.transform_ast(ast_setup)
958 961 ast_stmt = self.shell.transform_ast(ast_stmt)
959 962
960 963 # This codestring is taken from timeit.template - we fill it in as an
961 964 # AST, so that we can apply our AST transformations to the user code
962 965 # without affecting the timing code.
963 966 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
964 967 ' setup\n'
965 968 ' _t0 = _timer()\n'
966 969 ' for _i in _it:\n'
967 970 ' stmt\n'
968 971 ' _t1 = _timer()\n'
969 972 ' return _t1 - _t0\n')
970 973
971 974 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
972 975 timeit_ast = ast.fix_missing_locations(timeit_ast)
973 976
974 977 # Track compilation time so it can be reported if too long
975 978 # Minimum time above which compilation time will be reported
976 979 tc_min = 0.1
977 980
978 981 t0 = clock()
979 982 code = compile(timeit_ast, "<magic-timeit>", "exec")
980 983 tc = clock()-t0
981 984
982 985 ns = {}
983 986 exec(code, self.shell.user_ns, ns)
984 987 timer.inner = ns["inner"]
985 988
986 989 if number == 0:
987 990 # determine number so that 0.2 <= total time < 2.0
988 991 number = 1
989 992 for _ in range(1, 10):
990 993 if timer.timeit(number) >= 0.2:
991 994 break
992 995 number *= 10
993 996 all_runs = timer.repeat(repeat, number)
994 997 best = min(all_runs) / number
995 998 if not quiet :
996 999 print(u"%d loops, best of %d: %s per loop" % (number, repeat,
997 1000 _format_time(best, precision)))
998 1001 if tc > tc_min:
999 1002 print("Compiler time: %.2f s" % tc)
1000 1003 if return_result:
1001 1004 return TimeitResult(number, repeat, best, all_runs, tc, precision)
1002 1005
1003 1006 @skip_doctest
1004 1007 @needs_local_scope
1005 1008 @line_cell_magic
1006 1009 def time(self,line='', cell=None, local_ns=None):
1007 1010 """Time execution of a Python statement or expression.
1008 1011
1009 1012 The CPU and wall clock times are printed, and the value of the
1010 1013 expression (if any) is returned. Note that under Win32, system time
1011 1014 is always reported as 0, since it can not be measured.
1012 1015
1013 1016 This function can be used both as a line and cell magic:
1014 1017
1015 1018 - In line mode you can time a single-line statement (though multiple
1016 1019 ones can be chained with using semicolons).
1017 1020
1018 1021 - In cell mode, you can time the cell body (a directly
1019 1022 following statement raises an error).
1020 1023
1021 1024 This function provides very basic timing functionality. Use the timeit
1022 1025 magic for more controll over the measurement.
1023 1026
1024 1027 Examples
1025 1028 --------
1026 1029 ::
1027 1030
1028 1031 In [1]: %time 2**128
1029 1032 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1030 1033 Wall time: 0.00
1031 1034 Out[1]: 340282366920938463463374607431768211456L
1032 1035
1033 1036 In [2]: n = 1000000
1034 1037
1035 1038 In [3]: %time sum(range(n))
1036 1039 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1037 1040 Wall time: 1.37
1038 1041 Out[3]: 499999500000L
1039 1042
1040 1043 In [4]: %time print 'hello world'
1041 1044 hello world
1042 1045 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1043 1046 Wall time: 0.00
1044 1047
1045 1048 Note that the time needed by Python to compile the given expression
1046 1049 will be reported if it is more than 0.1s. In this example, the
1047 1050 actual exponentiation is done by Python at compilation time, so while
1048 1051 the expression can take a noticeable amount of time to compute, that
1049 1052 time is purely due to the compilation:
1050 1053
1051 1054 In [5]: %time 3**9999;
1052 1055 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1053 1056 Wall time: 0.00 s
1054 1057
1055 1058 In [6]: %time 3**999999;
1056 1059 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1057 1060 Wall time: 0.00 s
1058 1061 Compiler : 0.78 s
1059 1062 """
1060 1063
1061 1064 # fail immediately if the given expression can't be compiled
1062 1065
1063 1066 if line and cell:
1064 1067 raise UsageError("Can't use statement directly after '%%time'!")
1065 1068
1066 1069 if cell:
1067 1070 expr = self.shell.input_transformer_manager.transform_cell(cell)
1068 1071 else:
1069 1072 expr = self.shell.input_transformer_manager.transform_cell(line)
1070 1073
1071 1074 # Minimum time above which parse time will be reported
1072 1075 tp_min = 0.1
1073 1076
1074 1077 t0 = clock()
1075 1078 expr_ast = ast.parse(expr)
1076 1079 tp = clock()-t0
1077 1080
1078 1081 # Apply AST transformations
1079 1082 expr_ast = self.shell.transform_ast(expr_ast)
1080 1083
1081 1084 # Minimum time above which compilation time will be reported
1082 1085 tc_min = 0.1
1083 1086
1084 1087 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1085 1088 mode = 'eval'
1086 1089 source = '<timed eval>'
1087 1090 expr_ast = ast.Expression(expr_ast.body[0].value)
1088 1091 else:
1089 1092 mode = 'exec'
1090 1093 source = '<timed exec>'
1091 1094 t0 = clock()
1092 1095 code = compile(expr_ast, source, mode)
1093 1096 tc = clock()-t0
1094 1097
1095 1098 # skew measurement as little as possible
1096 1099 glob = self.shell.user_ns
1097 1100 wtime = time.time
1098 1101 # time execution
1099 1102 wall_st = wtime()
1100 1103 if mode=='eval':
1101 1104 st = clock2()
1102 1105 out = eval(code, glob, local_ns)
1103 1106 end = clock2()
1104 1107 else:
1105 1108 st = clock2()
1106 1109 exec(code, glob, local_ns)
1107 1110 end = clock2()
1108 1111 out = None
1109 1112 wall_end = wtime()
1110 1113 # Compute actual times and report
1111 1114 wall_time = wall_end-wall_st
1112 1115 cpu_user = end[0]-st[0]
1113 1116 cpu_sys = end[1]-st[1]
1114 1117 cpu_tot = cpu_user+cpu_sys
1115 1118 # On windows cpu_sys is always zero, so no new information to the next print
1116 1119 if sys.platform != 'win32':
1117 1120 print("CPU times: user %s, sys: %s, total: %s" % \
1118 1121 (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot)))
1119 1122 print("Wall time: %s" % _format_time(wall_time))
1120 1123 if tc > tc_min:
1121 1124 print("Compiler : %s" % _format_time(tc))
1122 1125 if tp > tp_min:
1123 1126 print("Parser : %s" % _format_time(tp))
1124 1127 return out
1125 1128
1126 1129 @skip_doctest
1127 1130 @line_magic
1128 1131 def macro(self, parameter_s=''):
1129 1132 """Define a macro for future re-execution. It accepts ranges of history,
1130 1133 filenames or string objects.
1131 1134
1132 1135 Usage:\\
1133 1136 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1134 1137
1135 1138 Options:
1136 1139
1137 1140 -r: use 'raw' input. By default, the 'processed' history is used,
1138 1141 so that magics are loaded in their transformed version to valid
1139 1142 Python. If this option is given, the raw input as typed at the
1140 1143 command line is used instead.
1141 1144
1142 1145 -q: quiet macro definition. By default, a tag line is printed
1143 1146 to indicate the macro has been created, and then the contents of
1144 1147 the macro are printed. If this option is given, then no printout
1145 1148 is produced once the macro is created.
1146 1149
1147 1150 This will define a global variable called `name` which is a string
1148 1151 made of joining the slices and lines you specify (n1,n2,... numbers
1149 1152 above) from your input history into a single string. This variable
1150 1153 acts like an automatic function which re-executes those lines as if
1151 1154 you had typed them. You just type 'name' at the prompt and the code
1152 1155 executes.
1153 1156
1154 1157 The syntax for indicating input ranges is described in %history.
1155 1158
1156 1159 Note: as a 'hidden' feature, you can also use traditional python slice
1157 1160 notation, where N:M means numbers N through M-1.
1158 1161
1159 1162 For example, if your history contains (print using %hist -n )::
1160 1163
1161 1164 44: x=1
1162 1165 45: y=3
1163 1166 46: z=x+y
1164 1167 47: print x
1165 1168 48: a=5
1166 1169 49: print 'x',x,'y',y
1167 1170
1168 1171 you can create a macro with lines 44 through 47 (included) and line 49
1169 1172 called my_macro with::
1170 1173
1171 1174 In [55]: %macro my_macro 44-47 49
1172 1175
1173 1176 Now, typing `my_macro` (without quotes) will re-execute all this code
1174 1177 in one pass.
1175 1178
1176 1179 You don't need to give the line-numbers in order, and any given line
1177 1180 number can appear multiple times. You can assemble macros with any
1178 1181 lines from your input history in any order.
1179 1182
1180 1183 The macro is a simple object which holds its value in an attribute,
1181 1184 but IPython's display system checks for macros and executes them as
1182 1185 code instead of printing them when you type their name.
1183 1186
1184 1187 You can view a macro's contents by explicitly printing it with::
1185 1188
1186 1189 print macro_name
1187 1190
1188 1191 """
1189 1192 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1190 1193 if not args: # List existing macros
1191 1194 return sorted(k for k,v in iteritems(self.shell.user_ns) if\
1192 1195 isinstance(v, Macro))
1193 1196 if len(args) == 1:
1194 1197 raise UsageError(
1195 1198 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1196 1199 name, codefrom = args[0], " ".join(args[1:])
1197 1200
1198 1201 #print 'rng',ranges # dbg
1199 1202 try:
1200 1203 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1201 1204 except (ValueError, TypeError) as e:
1202 1205 print(e.args[0])
1203 1206 return
1204 1207 macro = Macro(lines)
1205 1208 self.shell.define_macro(name, macro)
1206 1209 if not ( 'q' in opts) :
1207 1210 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1208 1211 print('=== Macro contents: ===')
1209 1212 print(macro, end=' ')
1210 1213
1211 1214 @magic_arguments.magic_arguments()
1212 1215 @magic_arguments.argument('output', type=str, default='', nargs='?',
1213 1216 help="""The name of the variable in which to store output.
1214 1217 This is a utils.io.CapturedIO object with stdout/err attributes
1215 1218 for the text of the captured output.
1216 1219
1217 1220 CapturedOutput also has a show() method for displaying the output,
1218 1221 and __call__ as well, so you can use that to quickly display the
1219 1222 output.
1220 1223
1221 1224 If unspecified, captured output is discarded.
1222 1225 """
1223 1226 )
1224 1227 @magic_arguments.argument('--no-stderr', action="store_true",
1225 1228 help="""Don't capture stderr."""
1226 1229 )
1227 1230 @magic_arguments.argument('--no-stdout', action="store_true",
1228 1231 help="""Don't capture stdout."""
1229 1232 )
1230 1233 @magic_arguments.argument('--no-display', action="store_true",
1231 1234 help="""Don't capture IPython's rich display."""
1232 1235 )
1233 1236 @cell_magic
1234 1237 def capture(self, line, cell):
1235 1238 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1236 1239 args = magic_arguments.parse_argstring(self.capture, line)
1237 1240 out = not args.no_stdout
1238 1241 err = not args.no_stderr
1239 1242 disp = not args.no_display
1240 1243 with capture_output(out, err, disp) as io:
1241 1244 self.shell.run_cell(cell)
1242 1245 if args.output:
1243 1246 self.shell.user_ns[args.output] = io
1244 1247
1245 1248 def parse_breakpoint(text, current_file):
1246 1249 '''Returns (file, line) for file:line and (current_file, line) for line'''
1247 1250 colon = text.find(':')
1248 1251 if colon == -1:
1249 1252 return current_file, int(text)
1250 1253 else:
1251 1254 return text[:colon], int(text[colon+1:])
1252 1255
1253 1256 def _format_time(timespan, precision=3):
1254 1257 """Formats the timespan in a human readable form"""
1255 1258 import math
1256 1259
1257 1260 if timespan >= 60.0:
1258 1261 # we have more than a minute, format that in a human readable form
1259 1262 # Idea from http://snipplr.com/view/5713/
1260 1263 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1261 1264 time = []
1262 1265 leftover = timespan
1263 1266 for suffix, length in parts:
1264 1267 value = int(leftover / length)
1265 1268 if value > 0:
1266 1269 leftover = leftover % length
1267 1270 time.append(u'%s%s' % (str(value), suffix))
1268 1271 if leftover < 1:
1269 1272 break
1270 1273 return " ".join(time)
1271 1274
1272 1275
1273 1276 # Unfortunately the unicode 'micro' symbol can cause problems in
1274 1277 # certain terminals.
1275 1278 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1276 1279 # Try to prevent crashes by being more secure than it needs to
1277 1280 # E.g. eclipse is able to print a Β΅, but has no sys.stdout.encoding set.
1278 1281 units = [u"s", u"ms",u'us',"ns"] # the save value
1279 1282 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1280 1283 try:
1281 1284 u'\xb5'.encode(sys.stdout.encoding)
1282 1285 units = [u"s", u"ms",u'\xb5s',"ns"]
1283 1286 except:
1284 1287 pass
1285 1288 scaling = [1, 1e3, 1e6, 1e9]
1286 1289
1287 1290 if timespan > 0.0:
1288 1291 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1289 1292 else:
1290 1293 order = 3
1291 1294 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
@@ -1,672 +1,676 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the key interactiveshell module.
3 3
4 4 Historically the main classes in interactiveshell have been under-tested. This
5 5 module should grow as many single-method tests as possible to trap many of the
6 6 recurring bugs we seem to encounter with high-level interaction.
7 7
8 8 Authors
9 9 -------
10 10 * Fernando Perez
11 11 """
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22 # stdlib
23 23 import ast
24 24 import os
25 25 import signal
26 26 import shutil
27 27 import sys
28 28 import tempfile
29 29 import unittest
30 30 from os.path import join
31 from io import StringIO
32 31
33 32 # third-party
34 33 import nose.tools as nt
35 34
36 35 # Our own
37 36 from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths
38 37 from IPython.testing import tools as tt
39 38 from IPython.utils import io
40 from IPython.utils.py3compat import unicode_type
39 from IPython.utils.py3compat import unicode_type, PY3
40
41 if PY3:
42 from io import StringIO
43 else:
44 from StringIO import StringIO
41 45
42 46 #-----------------------------------------------------------------------------
43 47 # Globals
44 48 #-----------------------------------------------------------------------------
45 49 # This is used by every single test, no point repeating it ad nauseam
46 50 ip = get_ipython()
47 51
48 52 #-----------------------------------------------------------------------------
49 53 # Tests
50 54 #-----------------------------------------------------------------------------
51 55
52 56 class InteractiveShellTestCase(unittest.TestCase):
53 57 def test_naked_string_cells(self):
54 58 """Test that cells with only naked strings are fully executed"""
55 59 # First, single-line inputs
56 60 ip.run_cell('"a"\n')
57 61 self.assertEqual(ip.user_ns['_'], 'a')
58 62 # And also multi-line cells
59 63 ip.run_cell('"""a\nb"""\n')
60 64 self.assertEqual(ip.user_ns['_'], 'a\nb')
61 65
62 66 def test_run_empty_cell(self):
63 67 """Just make sure we don't get a horrible error with a blank
64 68 cell of input. Yes, I did overlook that."""
65 69 old_xc = ip.execution_count
66 70 ip.run_cell('')
67 71 self.assertEqual(ip.execution_count, old_xc)
68 72
69 73 def test_run_cell_multiline(self):
70 74 """Multi-block, multi-line cells must execute correctly.
71 75 """
72 76 src = '\n'.join(["x=1",
73 77 "y=2",
74 78 "if 1:",
75 79 " x += 1",
76 80 " y += 1",])
77 81 ip.run_cell(src)
78 82 self.assertEqual(ip.user_ns['x'], 2)
79 83 self.assertEqual(ip.user_ns['y'], 3)
80 84
81 85 def test_multiline_string_cells(self):
82 86 "Code sprinkled with multiline strings should execute (GH-306)"
83 87 ip.run_cell('tmp=0')
84 88 self.assertEqual(ip.user_ns['tmp'], 0)
85 89 ip.run_cell('tmp=1;"""a\nb"""\n')
86 90 self.assertEqual(ip.user_ns['tmp'], 1)
87 91
88 92 def test_dont_cache_with_semicolon(self):
89 93 "Ending a line with semicolon should not cache the returned object (GH-307)"
90 94 oldlen = len(ip.user_ns['Out'])
91 95 a = ip.run_cell('1;', store_history=True)
92 96 newlen = len(ip.user_ns['Out'])
93 97 self.assertEqual(oldlen, newlen)
94 98 #also test the default caching behavior
95 99 ip.run_cell('1', store_history=True)
96 100 newlen = len(ip.user_ns['Out'])
97 101 self.assertEqual(oldlen+1, newlen)
98 102
99 103 def test_In_variable(self):
100 104 "Verify that In variable grows with user input (GH-284)"
101 105 oldlen = len(ip.user_ns['In'])
102 106 ip.run_cell('1;', store_history=True)
103 107 newlen = len(ip.user_ns['In'])
104 108 self.assertEqual(oldlen+1, newlen)
105 109 self.assertEqual(ip.user_ns['In'][-1],'1;')
106 110
107 111 def test_magic_names_in_string(self):
108 112 ip.run_cell('a = """\n%exit\n"""')
109 113 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
110 114
111 115 def test_trailing_newline(self):
112 116 """test that running !(command) does not raise a SyntaxError"""
113 117 ip.run_cell('!(true)\n', False)
114 118 ip.run_cell('!(true)\n\n\n', False)
115 119
116 120 def test_gh_597(self):
117 121 """Pretty-printing lists of objects with non-ascii reprs may cause
118 122 problems."""
119 123 class Spam(object):
120 124 def __repr__(self):
121 125 return "\xe9"*50
122 126 import IPython.core.formatters
123 127 f = IPython.core.formatters.PlainTextFormatter()
124 128 f([Spam(),Spam()])
125 129
126 130
127 131 def test_future_flags(self):
128 132 """Check that future flags are used for parsing code (gh-777)"""
129 133 ip.run_cell('from __future__ import print_function')
130 134 try:
131 135 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
132 136 assert 'prfunc_return_val' in ip.user_ns
133 137 finally:
134 138 # Reset compiler flags so we don't mess up other tests.
135 139 ip.compile.reset_compiler_flags()
136 140
137 141 def test_future_unicode(self):
138 142 """Check that unicode_literals is imported from __future__ (gh #786)"""
139 143 try:
140 144 ip.run_cell(u'byte_str = "a"')
141 145 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
142 146 ip.run_cell('from __future__ import unicode_literals')
143 147 ip.run_cell(u'unicode_str = "a"')
144 148 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
145 149 finally:
146 150 # Reset compiler flags so we don't mess up other tests.
147 151 ip.compile.reset_compiler_flags()
148 152
149 153 def test_can_pickle(self):
150 154 "Can we pickle objects defined interactively (GH-29)"
151 155 ip = get_ipython()
152 156 ip.reset()
153 157 ip.run_cell(("class Mylist(list):\n"
154 158 " def __init__(self,x=[]):\n"
155 159 " list.__init__(self,x)"))
156 160 ip.run_cell("w=Mylist([1,2,3])")
157 161
158 162 from pickle import dumps
159 163
160 164 # We need to swap in our main module - this is only necessary
161 165 # inside the test framework, because IPython puts the interactive module
162 166 # in place (but the test framework undoes this).
163 167 _main = sys.modules['__main__']
164 168 sys.modules['__main__'] = ip.user_module
165 169 try:
166 170 res = dumps(ip.user_ns["w"])
167 171 finally:
168 172 sys.modules['__main__'] = _main
169 173 self.assertTrue(isinstance(res, bytes))
170 174
171 175 def test_global_ns(self):
172 176 "Code in functions must be able to access variables outside them."
173 177 ip = get_ipython()
174 178 ip.run_cell("a = 10")
175 179 ip.run_cell(("def f(x):\n"
176 180 " return x + a"))
177 181 ip.run_cell("b = f(12)")
178 182 self.assertEqual(ip.user_ns["b"], 22)
179 183
180 184 def test_bad_custom_tb(self):
181 185 """Check that InteractiveShell is protected from bad custom exception handlers"""
182 186 from IPython.utils import io
183 187 save_stderr = io.stderr
184 188 try:
185 189 # capture stderr
186 190 io.stderr = StringIO()
187 191 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
188 192 self.assertEqual(ip.custom_exceptions, (IOError,))
189 193 ip.run_cell(u'raise IOError("foo")')
190 194 self.assertEqual(ip.custom_exceptions, ())
191 195 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
192 196 finally:
193 197 io.stderr = save_stderr
194 198
195 199 def test_bad_custom_tb_return(self):
196 200 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
197 201 from IPython.utils import io
198 202 save_stderr = io.stderr
199 203 try:
200 204 # capture stderr
201 205 io.stderr = StringIO()
202 206 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
203 207 self.assertEqual(ip.custom_exceptions, (NameError,))
204 208 ip.run_cell(u'a=abracadabra')
205 209 self.assertEqual(ip.custom_exceptions, ())
206 210 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
207 211 finally:
208 212 io.stderr = save_stderr
209 213
210 214 def test_drop_by_id(self):
211 215 myvars = {"a":object(), "b":object(), "c": object()}
212 216 ip.push(myvars, interactive=False)
213 217 for name in myvars:
214 218 assert name in ip.user_ns, name
215 219 assert name in ip.user_ns_hidden, name
216 220 ip.user_ns['b'] = 12
217 221 ip.drop_by_id(myvars)
218 222 for name in ["a", "c"]:
219 223 assert name not in ip.user_ns, name
220 224 assert name not in ip.user_ns_hidden, name
221 225 assert ip.user_ns['b'] == 12
222 226 ip.reset()
223 227
224 228 def test_var_expand(self):
225 229 ip.user_ns['f'] = u'Ca\xf1o'
226 230 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
227 231 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
228 232 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
229 233 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
230 234
231 235 ip.user_ns['f'] = b'Ca\xc3\xb1o'
232 236 # This should not raise any exception:
233 237 ip.var_expand(u'echo $f')
234 238
235 239 def test_var_expand_local(self):
236 240 """Test local variable expansion in !system and %magic calls"""
237 241 # !system
238 242 ip.run_cell('def test():\n'
239 243 ' lvar = "ttt"\n'
240 244 ' ret = !echo {lvar}\n'
241 245 ' return ret[0]\n')
242 246 res = ip.user_ns['test']()
243 247 nt.assert_in('ttt', res)
244 248
245 249 # %magic
246 250 ip.run_cell('def makemacro():\n'
247 251 ' macroname = "macro_var_expand_locals"\n'
248 252 ' %macro {macroname} codestr\n')
249 253 ip.user_ns['codestr'] = "str(12)"
250 254 ip.run_cell('makemacro()')
251 255 nt.assert_in('macro_var_expand_locals', ip.user_ns)
252 256
253 257 def test_var_expand_self(self):
254 258 """Test variable expansion with the name 'self', which was failing.
255 259
256 260 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
257 261 """
258 262 ip.run_cell('class cTest:\n'
259 263 ' classvar="see me"\n'
260 264 ' def test(self):\n'
261 265 ' res = !echo Variable: {self.classvar}\n'
262 266 ' return res[0]\n')
263 267 nt.assert_in('see me', ip.user_ns['cTest']().test())
264 268
265 269 def test_bad_var_expand(self):
266 270 """var_expand on invalid formats shouldn't raise"""
267 271 # SyntaxError
268 272 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
269 273 # NameError
270 274 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
271 275 # ZeroDivisionError
272 276 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
273 277
274 278 def test_silent_nopostexec(self):
275 279 """run_cell(silent=True) doesn't invoke post-exec funcs"""
276 280 d = dict(called=False)
277 281 def set_called():
278 282 d['called'] = True
279 283
280 284 ip.register_post_execute(set_called)
281 285 ip.run_cell("1", silent=True)
282 286 self.assertFalse(d['called'])
283 287 # double-check that non-silent exec did what we expected
284 288 # silent to avoid
285 289 ip.run_cell("1")
286 290 self.assertTrue(d['called'])
287 291 # remove post-exec
288 292 ip._post_execute.pop(set_called)
289 293
290 294 def test_silent_noadvance(self):
291 295 """run_cell(silent=True) doesn't advance execution_count"""
292 296 ec = ip.execution_count
293 297 # silent should force store_history=False
294 298 ip.run_cell("1", store_history=True, silent=True)
295 299
296 300 self.assertEqual(ec, ip.execution_count)
297 301 # double-check that non-silent exec did what we expected
298 302 # silent to avoid
299 303 ip.run_cell("1", store_history=True)
300 304 self.assertEqual(ec+1, ip.execution_count)
301 305
302 306 def test_silent_nodisplayhook(self):
303 307 """run_cell(silent=True) doesn't trigger displayhook"""
304 308 d = dict(called=False)
305 309
306 310 trap = ip.display_trap
307 311 save_hook = trap.hook
308 312
309 313 def failing_hook(*args, **kwargs):
310 314 d['called'] = True
311 315
312 316 try:
313 317 trap.hook = failing_hook
314 318 ip.run_cell("1", silent=True)
315 319 self.assertFalse(d['called'])
316 320 # double-check that non-silent exec did what we expected
317 321 # silent to avoid
318 322 ip.run_cell("1")
319 323 self.assertTrue(d['called'])
320 324 finally:
321 325 trap.hook = save_hook
322 326
323 327 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
324 328 def test_print_softspace(self):
325 329 """Verify that softspace is handled correctly when executing multiple
326 330 statements.
327 331
328 332 In [1]: print 1; print 2
329 333 1
330 334 2
331 335
332 336 In [2]: print 1,; print 2
333 337 1 2
334 338 """
335 339
336 340 def test_ofind_line_magic(self):
337 341 from IPython.core.magic import register_line_magic
338 342
339 343 @register_line_magic
340 344 def lmagic(line):
341 345 "A line magic"
342 346
343 347 # Get info on line magic
344 348 lfind = ip._ofind('lmagic')
345 349 info = dict(found=True, isalias=False, ismagic=True,
346 350 namespace = 'IPython internal', obj= lmagic.__wrapped__,
347 351 parent = None)
348 352 nt.assert_equal(lfind, info)
349 353
350 354 def test_ofind_cell_magic(self):
351 355 from IPython.core.magic import register_cell_magic
352 356
353 357 @register_cell_magic
354 358 def cmagic(line, cell):
355 359 "A cell magic"
356 360
357 361 # Get info on cell magic
358 362 find = ip._ofind('cmagic')
359 363 info = dict(found=True, isalias=False, ismagic=True,
360 364 namespace = 'IPython internal', obj= cmagic.__wrapped__,
361 365 parent = None)
362 366 nt.assert_equal(find, info)
363 367
364 368 def test_custom_exception(self):
365 369 called = []
366 370 def my_handler(shell, etype, value, tb, tb_offset=None):
367 371 called.append(etype)
368 372 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
369 373
370 374 ip.set_custom_exc((ValueError,), my_handler)
371 375 try:
372 376 ip.run_cell("raise ValueError('test')")
373 377 # Check that this was called, and only once.
374 378 self.assertEqual(called, [ValueError])
375 379 finally:
376 380 # Reset the custom exception hook
377 381 ip.set_custom_exc((), None)
378 382
379 383 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
380 384 def test_future_environment(self):
381 385 "Can we run code with & without the shell's __future__ imports?"
382 386 ip.run_cell("from __future__ import division")
383 387 ip.run_cell("a = 1/2", shell_futures=True)
384 388 self.assertEqual(ip.user_ns['a'], 0.5)
385 389 ip.run_cell("b = 1/2", shell_futures=False)
386 390 self.assertEqual(ip.user_ns['b'], 0)
387 391
388 392 ip.compile.reset_compiler_flags()
389 393 # This shouldn't leak to the shell's compiler
390 394 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
391 395 self.assertEqual(ip.user_ns['c'], 0.5)
392 396 ip.run_cell("d = 1/2", shell_futures=True)
393 397 self.assertEqual(ip.user_ns['d'], 0)
394 398
395 399
396 400 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
397 401
398 402 @onlyif_unicode_paths
399 403 def setUp(self):
400 404 self.BASETESTDIR = tempfile.mkdtemp()
401 405 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
402 406 os.mkdir(self.TESTDIR)
403 407 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
404 408 sfile.write("pass\n")
405 409 self.oldpath = os.getcwdu()
406 410 os.chdir(self.TESTDIR)
407 411 self.fname = u"Γ₯Àâtestscript.py"
408 412
409 413 def tearDown(self):
410 414 os.chdir(self.oldpath)
411 415 shutil.rmtree(self.BASETESTDIR)
412 416
413 417 @onlyif_unicode_paths
414 418 def test_1(self):
415 419 """Test safe_execfile with non-ascii path
416 420 """
417 421 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
418 422
419 423 class ExitCodeChecks(tt.TempFileMixin):
420 424 def test_exit_code_ok(self):
421 425 self.system('exit 0')
422 426 self.assertEqual(ip.user_ns['_exit_code'], 0)
423 427
424 428 def test_exit_code_error(self):
425 429 self.system('exit 1')
426 430 self.assertEqual(ip.user_ns['_exit_code'], 1)
427 431
428 432 @skipif(not hasattr(signal, 'SIGALRM'))
429 433 def test_exit_code_signal(self):
430 434 self.mktmp("import signal, time\n"
431 435 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
432 436 "time.sleep(1)\n")
433 437 self.system("%s %s" % (sys.executable, self.fname))
434 438 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
435 439
436 440 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
437 441 system = ip.system_raw
438 442
439 443 @onlyif_unicode_paths
440 444 def test_1(self):
441 445 """Test system_raw with non-ascii cmd
442 446 """
443 447 cmd = u'''python -c "'Γ₯Àâ'" '''
444 448 ip.system_raw(cmd)
445 449
446 450 # TODO: Exit codes are currently ignored on Windows.
447 451 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
448 452 system = ip.system_piped
449 453
450 454 @skip_win32
451 455 def test_exit_code_ok(self):
452 456 ExitCodeChecks.test_exit_code_ok(self)
453 457
454 458 @skip_win32
455 459 def test_exit_code_error(self):
456 460 ExitCodeChecks.test_exit_code_error(self)
457 461
458 462 @skip_win32
459 463 def test_exit_code_signal(self):
460 464 ExitCodeChecks.test_exit_code_signal(self)
461 465
462 466 class TestModules(unittest.TestCase, tt.TempFileMixin):
463 467 def test_extraneous_loads(self):
464 468 """Test we're not loading modules on startup that we shouldn't.
465 469 """
466 470 self.mktmp("import sys\n"
467 471 "print('numpy' in sys.modules)\n"
468 472 "print('IPython.parallel' in sys.modules)\n"
469 473 "print('IPython.kernel.zmq' in sys.modules)\n"
470 474 )
471 475 out = "False\nFalse\nFalse\n"
472 476 tt.ipexec_validate(self.fname, out)
473 477
474 478 class Negator(ast.NodeTransformer):
475 479 """Negates all number literals in an AST."""
476 480 def visit_Num(self, node):
477 481 node.n = -node.n
478 482 return node
479 483
480 484 class TestAstTransform(unittest.TestCase):
481 485 def setUp(self):
482 486 self.negator = Negator()
483 487 ip.ast_transformers.append(self.negator)
484 488
485 489 def tearDown(self):
486 490 ip.ast_transformers.remove(self.negator)
487 491
488 492 def test_run_cell(self):
489 493 with tt.AssertPrints('-34'):
490 494 ip.run_cell('print (12 + 22)')
491 495
492 496 # A named reference to a number shouldn't be transformed.
493 497 ip.user_ns['n'] = 55
494 498 with tt.AssertNotPrints('-55'):
495 499 ip.run_cell('print (n)')
496 500
497 501 def test_timeit(self):
498 502 called = set()
499 503 def f(x):
500 504 called.add(x)
501 505 ip.push({'f':f})
502 506
503 507 with tt.AssertPrints("best of "):
504 508 ip.run_line_magic("timeit", "-n1 f(1)")
505 509 self.assertEqual(called, set([-1]))
506 510 called.clear()
507 511
508 512 with tt.AssertPrints("best of "):
509 513 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
510 514 self.assertEqual(called, set([-2, -3]))
511 515
512 516 def test_time(self):
513 517 called = []
514 518 def f(x):
515 519 called.append(x)
516 520 ip.push({'f':f})
517 521
518 522 # Test with an expression
519 523 with tt.AssertPrints("Wall time: "):
520 524 ip.run_line_magic("time", "f(5+9)")
521 525 self.assertEqual(called, [-14])
522 526 called[:] = []
523 527
524 528 # Test with a statement (different code path)
525 529 with tt.AssertPrints("Wall time: "):
526 530 ip.run_line_magic("time", "a = f(-3 + -2)")
527 531 self.assertEqual(called, [5])
528 532
529 533 def test_macro(self):
530 534 ip.push({'a':10})
531 535 # The AST transformation makes this do a+=-1
532 536 ip.define_macro("amacro", "a+=1\nprint(a)")
533 537
534 538 with tt.AssertPrints("9"):
535 539 ip.run_cell("amacro")
536 540 with tt.AssertPrints("8"):
537 541 ip.run_cell("amacro")
538 542
539 543 class IntegerWrapper(ast.NodeTransformer):
540 544 """Wraps all integers in a call to Integer()"""
541 545 def visit_Num(self, node):
542 546 if isinstance(node.n, int):
543 547 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
544 548 args=[node], keywords=[])
545 549 return node
546 550
547 551 class TestAstTransform2(unittest.TestCase):
548 552 def setUp(self):
549 553 self.intwrapper = IntegerWrapper()
550 554 ip.ast_transformers.append(self.intwrapper)
551 555
552 556 self.calls = []
553 557 def Integer(*args):
554 558 self.calls.append(args)
555 559 return args
556 560 ip.push({"Integer": Integer})
557 561
558 562 def tearDown(self):
559 563 ip.ast_transformers.remove(self.intwrapper)
560 564 del ip.user_ns['Integer']
561 565
562 566 def test_run_cell(self):
563 567 ip.run_cell("n = 2")
564 568 self.assertEqual(self.calls, [(2,)])
565 569
566 570 # This shouldn't throw an error
567 571 ip.run_cell("o = 2.0")
568 572 self.assertEqual(ip.user_ns['o'], 2.0)
569 573
570 574 def test_timeit(self):
571 575 called = set()
572 576 def f(x):
573 577 called.add(x)
574 578 ip.push({'f':f})
575 579
576 580 with tt.AssertPrints("best of "):
577 581 ip.run_line_magic("timeit", "-n1 f(1)")
578 582 self.assertEqual(called, set([(1,)]))
579 583 called.clear()
580 584
581 585 with tt.AssertPrints("best of "):
582 586 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
583 587 self.assertEqual(called, set([(2,), (3,)]))
584 588
585 589 class ErrorTransformer(ast.NodeTransformer):
586 590 """Throws an error when it sees a number."""
587 591 def visit_Num(self):
588 592 raise ValueError("test")
589 593
590 594 class TestAstTransformError(unittest.TestCase):
591 595 def test_unregistering(self):
592 596 err_transformer = ErrorTransformer()
593 597 ip.ast_transformers.append(err_transformer)
594 598
595 599 with tt.AssertPrints("unregister", channel='stderr'):
596 600 ip.run_cell("1 + 2")
597 601
598 602 # This should have been removed.
599 603 nt.assert_not_in(err_transformer, ip.ast_transformers)
600 604
601 605 def test__IPYTHON__():
602 606 # This shouldn't raise a NameError, that's all
603 607 __IPYTHON__
604 608
605 609
606 610 class DummyRepr(object):
607 611 def __repr__(self):
608 612 return "DummyRepr"
609 613
610 614 def _repr_html_(self):
611 615 return "<b>dummy</b>"
612 616
613 617 def _repr_javascript_(self):
614 618 return "console.log('hi');", {'key': 'value'}
615 619
616 620
617 621 def test_user_variables():
618 622 # enable all formatters
619 623 ip.display_formatter.active_types = ip.display_formatter.format_types
620 624
621 625 ip.user_ns['dummy'] = d = DummyRepr()
622 626 keys = set(['dummy', 'doesnotexist'])
623 627 r = ip.user_variables(keys)
624 628
625 629 nt.assert_equal(keys, set(r.keys()))
626 630 dummy = r['dummy']
627 631 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
628 632 nt.assert_equal(dummy['status'], 'ok')
629 633 data = dummy['data']
630 634 metadata = dummy['metadata']
631 635 nt.assert_equal(data.get('text/html'), d._repr_html_())
632 636 js, jsmd = d._repr_javascript_()
633 637 nt.assert_equal(data.get('application/javascript'), js)
634 638 nt.assert_equal(metadata.get('application/javascript'), jsmd)
635 639
636 640 dne = r['doesnotexist']
637 641 nt.assert_equal(dne['status'], 'error')
638 642 nt.assert_equal(dne['ename'], 'KeyError')
639 643
640 644 # back to text only
641 645 ip.display_formatter.active_types = ['text/plain']
642 646
643 647 def test_user_expression():
644 648 # enable all formatters
645 649 ip.display_formatter.active_types = ip.display_formatter.format_types
646 650 query = {
647 651 'a' : '1 + 2',
648 652 'b' : '1/0',
649 653 }
650 654 r = ip.user_expressions(query)
651 655 import pprint
652 656 pprint.pprint(r)
653 657 nt.assert_equal(r.keys(), query.keys())
654 658 a = r['a']
655 659 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
656 660 nt.assert_equal(a['status'], 'ok')
657 661 data = a['data']
658 662 metadata = a['metadata']
659 663 nt.assert_equal(data.get('text/plain'), '3')
660 664
661 665 b = r['b']
662 666 nt.assert_equal(b['status'], 'error')
663 667 nt.assert_equal(b['ename'], 'ZeroDivisionError')
664 668
665 669 # back to text only
666 670 ip.display_formatter.active_types = ['text/plain']
667 671
668 672
669 673
670 674
671 675
672 676
@@ -1,940 +1,944 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions.
3 3
4 4 Needs to be run by nose (to make ipython session available).
5 5 """
6 6 from __future__ import absolute_import
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Imports
10 10 #-----------------------------------------------------------------------------
11 11
12 12 import io
13 13 import os
14 14 import sys
15 from io import StringIO
16 15 from unittest import TestCase
17 16
18 17 try:
19 18 from importlib import invalidate_caches # Required from Python 3.3
20 19 except ImportError:
21 20 def invalidate_caches():
22 21 pass
23 22
24 23 import nose.tools as nt
25 24
26 25 from IPython.core import magic
27 26 from IPython.core.magic import (Magics, magics_class, line_magic,
28 27 cell_magic, line_cell_magic,
29 28 register_line_magic, register_cell_magic,
30 29 register_line_cell_magic)
31 30 from IPython.core.magics import execution, script, code
32 31 from IPython.nbformat.v3.tests.nbexamples import nb0
33 32 from IPython.nbformat import current
34 33 from IPython.testing import decorators as dec
35 34 from IPython.testing import tools as tt
36 35 from IPython.utils import py3compat
37 36 from IPython.utils.io import capture_output
38 37 from IPython.utils.tempdir import TemporaryDirectory
39 38 from IPython.utils.process import find_cmd
40 39
40 if py3compat.PY3:
41 from io import StringIO
42 else:
43 from StringIO import StringIO
44
41 45 #-----------------------------------------------------------------------------
42 46 # Test functions begin
43 47 #-----------------------------------------------------------------------------
44 48
45 49 @magic.magics_class
46 50 class DummyMagics(magic.Magics): pass
47 51
48 52 def test_extract_code_ranges():
49 53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
50 54 expected = [(0, 1),
51 55 (2, 3),
52 56 (4, 6),
53 57 (6, 9),
54 58 (9, 14),
55 59 (16, None),
56 60 (None, 9),
57 61 (9, None),
58 62 (None, 13),
59 63 (None, None)]
60 64 actual = list(code.extract_code_ranges(instr))
61 65 nt.assert_equal(actual, expected)
62 66
63 67 def test_extract_symbols():
64 68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
65 69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
66 70 expected = [([], ['a']),
67 71 (["def b():\n return 42\n"], []),
68 72 (["class A: pass\n"], []),
69 73 (["class A: pass\n", "def b():\n return 42\n"], []),
70 74 (["class A: pass\n"], ['a']),
71 75 ([], ['z'])]
72 76 for symbols, exp in zip(symbols_args, expected):
73 77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
74 78
75 79
76 80 def test_extract_symbols_raises_exception_with_non_python_code():
77 81 source = ("=begin A Ruby program :)=end\n"
78 82 "def hello\n"
79 83 "puts 'Hello world'\n"
80 84 "end")
81 85 with nt.assert_raises(SyntaxError):
82 86 code.extract_symbols(source, "hello")
83 87
84 88 def test_config():
85 89 """ test that config magic does not raise
86 90 can happen if Configurable init is moved too early into
87 91 Magics.__init__ as then a Config object will be registerd as a
88 92 magic.
89 93 """
90 94 ## should not raise.
91 95 _ip.magic('config')
92 96
93 97 def test_rehashx():
94 98 # clear up everything
95 99 _ip = get_ipython()
96 100 _ip.alias_manager.clear_aliases()
97 101 del _ip.db['syscmdlist']
98 102
99 103 _ip.magic('rehashx')
100 104 # Practically ALL ipython development systems will have more than 10 aliases
101 105
102 106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
103 107 for name, cmd in _ip.alias_manager.aliases:
104 108 # we must strip dots from alias names
105 109 nt.assert_not_in('.', name)
106 110
107 111 # rehashx must fill up syscmdlist
108 112 scoms = _ip.db['syscmdlist']
109 113 nt.assert_true(len(scoms) > 10)
110 114
111 115
112 116 def test_magic_parse_options():
113 117 """Test that we don't mangle paths when parsing magic options."""
114 118 ip = get_ipython()
115 119 path = 'c:\\x'
116 120 m = DummyMagics(ip)
117 121 opts = m.parse_options('-f %s' % path,'f:')[0]
118 122 # argv splitting is os-dependent
119 123 if os.name == 'posix':
120 124 expected = 'c:x'
121 125 else:
122 126 expected = path
123 127 nt.assert_equal(opts['f'], expected)
124 128
125 129 def test_magic_parse_long_options():
126 130 """Magic.parse_options can handle --foo=bar long options"""
127 131 ip = get_ipython()
128 132 m = DummyMagics(ip)
129 133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
130 134 nt.assert_in('foo', opts)
131 135 nt.assert_in('bar', opts)
132 136 nt.assert_equal(opts['bar'], "bubble")
133 137
134 138
135 139 @dec.skip_without('sqlite3')
136 140 def doctest_hist_f():
137 141 """Test %hist -f with temporary filename.
138 142
139 143 In [9]: import tempfile
140 144
141 145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
142 146
143 147 In [11]: %hist -nl -f $tfile 3
144 148
145 149 In [13]: import os; os.unlink(tfile)
146 150 """
147 151
148 152
149 153 @dec.skip_without('sqlite3')
150 154 def doctest_hist_r():
151 155 """Test %hist -r
152 156
153 157 XXX - This test is not recording the output correctly. For some reason, in
154 158 testing mode the raw history isn't getting populated. No idea why.
155 159 Disabling the output checking for now, though at least we do run it.
156 160
157 161 In [1]: 'hist' in _ip.lsmagic()
158 162 Out[1]: True
159 163
160 164 In [2]: x=1
161 165
162 166 In [3]: %hist -rl 2
163 167 x=1 # random
164 168 %hist -r 2
165 169 """
166 170
167 171
168 172 @dec.skip_without('sqlite3')
169 173 def doctest_hist_op():
170 174 """Test %hist -op
171 175
172 176 In [1]: class b(float):
173 177 ...: pass
174 178 ...:
175 179
176 180 In [2]: class s(object):
177 181 ...: def __str__(self):
178 182 ...: return 's'
179 183 ...:
180 184
181 185 In [3]:
182 186
183 187 In [4]: class r(b):
184 188 ...: def __repr__(self):
185 189 ...: return 'r'
186 190 ...:
187 191
188 192 In [5]: class sr(s,r): pass
189 193 ...:
190 194
191 195 In [6]:
192 196
193 197 In [7]: bb=b()
194 198
195 199 In [8]: ss=s()
196 200
197 201 In [9]: rr=r()
198 202
199 203 In [10]: ssrr=sr()
200 204
201 205 In [11]: 4.5
202 206 Out[11]: 4.5
203 207
204 208 In [12]: str(ss)
205 209 Out[12]: 's'
206 210
207 211 In [13]:
208 212
209 213 In [14]: %hist -op
210 214 >>> class b:
211 215 ... pass
212 216 ...
213 217 >>> class s(b):
214 218 ... def __str__(self):
215 219 ... return 's'
216 220 ...
217 221 >>>
218 222 >>> class r(b):
219 223 ... def __repr__(self):
220 224 ... return 'r'
221 225 ...
222 226 >>> class sr(s,r): pass
223 227 >>>
224 228 >>> bb=b()
225 229 >>> ss=s()
226 230 >>> rr=r()
227 231 >>> ssrr=sr()
228 232 >>> 4.5
229 233 4.5
230 234 >>> str(ss)
231 235 's'
232 236 >>>
233 237 """
234 238
235 239
236 240 @dec.skip_without('sqlite3')
237 241 def test_macro():
238 242 ip = get_ipython()
239 243 ip.history_manager.reset() # Clear any existing history.
240 244 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
241 245 for i, cmd in enumerate(cmds, start=1):
242 246 ip.history_manager.store_inputs(i, cmd)
243 247 ip.magic("macro test 1-3")
244 248 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
245 249
246 250 # List macros
247 251 nt.assert_in("test", ip.magic("macro"))
248 252
249 253
250 254 @dec.skip_without('sqlite3')
251 255 def test_macro_run():
252 256 """Test that we can run a multi-line macro successfully."""
253 257 ip = get_ipython()
254 258 ip.history_manager.reset()
255 259 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
256 260 "%macro test 2-3"]
257 261 for cmd in cmds:
258 262 ip.run_cell(cmd, store_history=True)
259 263 nt.assert_equal(ip.user_ns["test"].value,
260 264 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
261 265 with tt.AssertPrints("12"):
262 266 ip.run_cell("test")
263 267 with tt.AssertPrints("13"):
264 268 ip.run_cell("test")
265 269
266 270
267 271 def test_magic_magic():
268 272 """Test %magic"""
269 273 ip = get_ipython()
270 274 with capture_output() as captured:
271 275 ip.magic("magic")
272 276
273 277 stdout = captured.stdout
274 278 nt.assert_in('%magic', stdout)
275 279 nt.assert_in('IPython', stdout)
276 280 nt.assert_in('Available', stdout)
277 281
278 282
279 283 @dec.skipif_not_numpy
280 284 def test_numpy_reset_array_undec():
281 285 "Test '%reset array' functionality"
282 286 _ip.ex('import numpy as np')
283 287 _ip.ex('a = np.empty(2)')
284 288 nt.assert_in('a', _ip.user_ns)
285 289 _ip.magic('reset -f array')
286 290 nt.assert_not_in('a', _ip.user_ns)
287 291
288 292 def test_reset_out():
289 293 "Test '%reset out' magic"
290 294 _ip.run_cell("parrot = 'dead'", store_history=True)
291 295 # test '%reset -f out', make an Out prompt
292 296 _ip.run_cell("parrot", store_history=True)
293 297 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
294 298 _ip.magic('reset -f out')
295 299 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
296 300 nt.assert_equal(len(_ip.user_ns['Out']), 0)
297 301
298 302 def test_reset_in():
299 303 "Test '%reset in' magic"
300 304 # test '%reset -f in'
301 305 _ip.run_cell("parrot", store_history=True)
302 306 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
303 307 _ip.magic('%reset -f in')
304 308 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
305 309 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
306 310
307 311 def test_reset_dhist():
308 312 "Test '%reset dhist' magic"
309 313 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
310 314 _ip.magic('cd ' + os.path.dirname(nt.__file__))
311 315 _ip.magic('cd -')
312 316 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
313 317 _ip.magic('reset -f dhist')
314 318 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
315 319 _ip.run_cell("_dh = [d for d in tmp]") #restore
316 320
317 321 def test_reset_in_length():
318 322 "Test that '%reset in' preserves In[] length"
319 323 _ip.run_cell("print 'foo'")
320 324 _ip.run_cell("reset -f in")
321 325 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
322 326
323 327 def test_tb_syntaxerror():
324 328 """test %tb after a SyntaxError"""
325 329 ip = get_ipython()
326 330 ip.run_cell("for")
327 331
328 332 # trap and validate stdout
329 333 save_stdout = sys.stdout
330 334 try:
331 335 sys.stdout = StringIO()
332 336 ip.run_cell("%tb")
333 337 out = sys.stdout.getvalue()
334 338 finally:
335 339 sys.stdout = save_stdout
336 340 # trim output, and only check the last line
337 341 last_line = out.rstrip().splitlines()[-1].strip()
338 342 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
339 343
340 344
341 345 def test_time():
342 346 ip = get_ipython()
343 347
344 348 with tt.AssertPrints("Wall time: "):
345 349 ip.run_cell("%time None")
346 350
347 351 ip.run_cell("def f(kmjy):\n"
348 352 " %time print (2*kmjy)")
349 353
350 354 with tt.AssertPrints("Wall time: "):
351 355 with tt.AssertPrints("hihi", suppress=False):
352 356 ip.run_cell("f('hi')")
353 357
354 358
355 359 @dec.skip_win32
356 360 def test_time2():
357 361 ip = get_ipython()
358 362
359 363 with tt.AssertPrints("CPU times: user "):
360 364 ip.run_cell("%time None")
361 365
362 366 def test_time3():
363 367 """Erroneous magic function calls, issue gh-3334"""
364 368 ip = get_ipython()
365 369 ip.user_ns.pop('run', None)
366 370
367 371 with tt.AssertNotPrints("not found", channel='stderr'):
368 372 ip.run_cell("%%time\n"
369 373 "run = 0\n"
370 374 "run += 1")
371 375
372 376 def test_doctest_mode():
373 377 "Toggle doctest_mode twice, it should be a no-op and run without error"
374 378 _ip.magic('doctest_mode')
375 379 _ip.magic('doctest_mode')
376 380
377 381
378 382 def test_parse_options():
379 383 """Tests for basic options parsing in magics."""
380 384 # These are only the most minimal of tests, more should be added later. At
381 385 # the very least we check that basic text/unicode calls work OK.
382 386 m = DummyMagics(_ip)
383 387 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
384 388 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
385 389
386 390
387 391 def test_dirops():
388 392 """Test various directory handling operations."""
389 393 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
390 394 curpath = os.getcwdu
391 395 startdir = os.getcwdu()
392 396 ipdir = os.path.realpath(_ip.ipython_dir)
393 397 try:
394 398 _ip.magic('cd "%s"' % ipdir)
395 399 nt.assert_equal(curpath(), ipdir)
396 400 _ip.magic('cd -')
397 401 nt.assert_equal(curpath(), startdir)
398 402 _ip.magic('pushd "%s"' % ipdir)
399 403 nt.assert_equal(curpath(), ipdir)
400 404 _ip.magic('popd')
401 405 nt.assert_equal(curpath(), startdir)
402 406 finally:
403 407 os.chdir(startdir)
404 408
405 409
406 410 def test_xmode():
407 411 # Calling xmode three times should be a no-op
408 412 xmode = _ip.InteractiveTB.mode
409 413 for i in range(3):
410 414 _ip.magic("xmode")
411 415 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
412 416
413 417 def test_reset_hard():
414 418 monitor = []
415 419 class A(object):
416 420 def __del__(self):
417 421 monitor.append(1)
418 422 def __repr__(self):
419 423 return "<A instance>"
420 424
421 425 _ip.user_ns["a"] = A()
422 426 _ip.run_cell("a")
423 427
424 428 nt.assert_equal(monitor, [])
425 429 _ip.magic("reset -f")
426 430 nt.assert_equal(monitor, [1])
427 431
428 432 class TestXdel(tt.TempFileMixin):
429 433 def test_xdel(self):
430 434 """Test that references from %run are cleared by xdel."""
431 435 src = ("class A(object):\n"
432 436 " monitor = []\n"
433 437 " def __del__(self):\n"
434 438 " self.monitor.append(1)\n"
435 439 "a = A()\n")
436 440 self.mktmp(src)
437 441 # %run creates some hidden references...
438 442 _ip.magic("run %s" % self.fname)
439 443 # ... as does the displayhook.
440 444 _ip.run_cell("a")
441 445
442 446 monitor = _ip.user_ns["A"].monitor
443 447 nt.assert_equal(monitor, [])
444 448
445 449 _ip.magic("xdel a")
446 450
447 451 # Check that a's __del__ method has been called.
448 452 nt.assert_equal(monitor, [1])
449 453
450 454 def doctest_who():
451 455 """doctest for %who
452 456
453 457 In [1]: %reset -f
454 458
455 459 In [2]: alpha = 123
456 460
457 461 In [3]: beta = 'beta'
458 462
459 463 In [4]: %who int
460 464 alpha
461 465
462 466 In [5]: %who str
463 467 beta
464 468
465 469 In [6]: %whos
466 470 Variable Type Data/Info
467 471 ----------------------------
468 472 alpha int 123
469 473 beta str beta
470 474
471 475 In [7]: %who_ls
472 476 Out[7]: ['alpha', 'beta']
473 477 """
474 478
475 479 def test_whos():
476 480 """Check that whos is protected against objects where repr() fails."""
477 481 class A(object):
478 482 def __repr__(self):
479 483 raise Exception()
480 484 _ip.user_ns['a'] = A()
481 485 _ip.magic("whos")
482 486
483 487 @py3compat.u_format
484 488 def doctest_precision():
485 489 """doctest for %precision
486 490
487 491 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
488 492
489 493 In [2]: %precision 5
490 494 Out[2]: {u}'%.5f'
491 495
492 496 In [3]: f.float_format
493 497 Out[3]: {u}'%.5f'
494 498
495 499 In [4]: %precision %e
496 500 Out[4]: {u}'%e'
497 501
498 502 In [5]: f(3.1415927)
499 503 Out[5]: {u}'3.141593e+00'
500 504 """
501 505
502 506 def test_psearch():
503 507 with tt.AssertPrints("dict.fromkeys"):
504 508 _ip.run_cell("dict.fr*?")
505 509
506 510 def test_timeit_shlex():
507 511 """test shlex issues with timeit (#1109)"""
508 512 _ip.ex("def f(*a,**kw): pass")
509 513 _ip.magic('timeit -n1 "this is a bug".count(" ")')
510 514 _ip.magic('timeit -r1 -n1 f(" ", 1)')
511 515 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
512 516 _ip.magic('timeit -r1 -n1 ("a " + "b")')
513 517 _ip.magic('timeit -r1 -n1 f("a " + "b")')
514 518 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
515 519
516 520
517 521 def test_timeit_arguments():
518 522 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
519 523 _ip.magic("timeit ('#')")
520 524
521 525
522 526 def test_timeit_special_syntax():
523 527 "Test %%timeit with IPython special syntax"
524 528 @register_line_magic
525 529 def lmagic(line):
526 530 ip = get_ipython()
527 531 ip.user_ns['lmagic_out'] = line
528 532
529 533 # line mode test
530 534 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
531 535 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
532 536 # cell mode test
533 537 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
534 538 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
535 539
536 540 def test_timeit_return():
537 541 """
538 542 test wether timeit -o return object
539 543 """
540 544
541 545 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
542 546 assert(res is not None)
543 547
544 548 def test_timeit_quiet():
545 549 """
546 550 test quiet option of timeit magic
547 551 """
548 552 with tt.AssertNotPrints("loops"):
549 553 _ip.run_cell("%timeit -n1 -r1 -q 1")
550 554
551 555 @dec.skipif(execution.profile is None)
552 556 def test_prun_special_syntax():
553 557 "Test %%prun with IPython special syntax"
554 558 @register_line_magic
555 559 def lmagic(line):
556 560 ip = get_ipython()
557 561 ip.user_ns['lmagic_out'] = line
558 562
559 563 # line mode test
560 564 _ip.run_line_magic('prun', '-q %lmagic my line')
561 565 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
562 566 # cell mode test
563 567 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
564 568 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
565 569
566 570 @dec.skipif(execution.profile is None)
567 571 def test_prun_quotes():
568 572 "Test that prun does not clobber string escapes (GH #1302)"
569 573 _ip.magic(r"prun -q x = '\t'")
570 574 nt.assert_equal(_ip.user_ns['x'], '\t')
571 575
572 576 def test_extension():
573 577 tmpdir = TemporaryDirectory()
574 578 orig_ipython_dir = _ip.ipython_dir
575 579 try:
576 580 _ip.ipython_dir = tmpdir.name
577 581 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
578 582 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
579 583 _ip.magic("install_ext %s" % url)
580 584 _ip.user_ns.pop('arq', None)
581 585 invalidate_caches() # Clear import caches
582 586 _ip.magic("load_ext daft_extension")
583 587 nt.assert_equal(_ip.user_ns['arq'], 185)
584 588 _ip.magic("unload_ext daft_extension")
585 589 assert 'arq' not in _ip.user_ns
586 590 finally:
587 591 _ip.ipython_dir = orig_ipython_dir
588 592 tmpdir.cleanup()
589 593
590 594 def test_notebook_export_json():
591 595 with TemporaryDirectory() as td:
592 596 outfile = os.path.join(td, "nb.ipynb")
593 597 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
594 598 _ip.magic("notebook -e %s" % outfile)
595 599
596 600 def test_notebook_export_py():
597 601 with TemporaryDirectory() as td:
598 602 outfile = os.path.join(td, "nb.py")
599 603 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
600 604 _ip.magic("notebook -e %s" % outfile)
601 605
602 606 def test_notebook_reformat_py():
603 607 with TemporaryDirectory() as td:
604 608 infile = os.path.join(td, "nb.ipynb")
605 609 with io.open(infile, 'w', encoding='utf-8') as f:
606 610 current.write(nb0, f, 'json')
607 611
608 612 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
609 613 _ip.magic("notebook -f py %s" % infile)
610 614
611 615 def test_notebook_reformat_json():
612 616 with TemporaryDirectory() as td:
613 617 infile = os.path.join(td, "nb.py")
614 618 with io.open(infile, 'w', encoding='utf-8') as f:
615 619 current.write(nb0, f, 'py')
616 620
617 621 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
618 622 _ip.magic("notebook -f ipynb %s" % infile)
619 623 _ip.magic("notebook -f json %s" % infile)
620 624
621 625 def test_env():
622 626 env = _ip.magic("env")
623 627 assert isinstance(env, dict), type(env)
624 628
625 629
626 630 class CellMagicTestCase(TestCase):
627 631
628 632 def check_ident(self, magic):
629 633 # Manually called, we get the result
630 634 out = _ip.run_cell_magic(magic, 'a', 'b')
631 635 nt.assert_equal(out, ('a','b'))
632 636 # Via run_cell, it goes into the user's namespace via displayhook
633 637 _ip.run_cell('%%' + magic +' c\nd')
634 638 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
635 639
636 640 def test_cell_magic_func_deco(self):
637 641 "Cell magic using simple decorator"
638 642 @register_cell_magic
639 643 def cellm(line, cell):
640 644 return line, cell
641 645
642 646 self.check_ident('cellm')
643 647
644 648 def test_cell_magic_reg(self):
645 649 "Cell magic manually registered"
646 650 def cellm(line, cell):
647 651 return line, cell
648 652
649 653 _ip.register_magic_function(cellm, 'cell', 'cellm2')
650 654 self.check_ident('cellm2')
651 655
652 656 def test_cell_magic_class(self):
653 657 "Cell magics declared via a class"
654 658 @magics_class
655 659 class MyMagics(Magics):
656 660
657 661 @cell_magic
658 662 def cellm3(self, line, cell):
659 663 return line, cell
660 664
661 665 _ip.register_magics(MyMagics)
662 666 self.check_ident('cellm3')
663 667
664 668 def test_cell_magic_class2(self):
665 669 "Cell magics declared via a class, #2"
666 670 @magics_class
667 671 class MyMagics2(Magics):
668 672
669 673 @cell_magic('cellm4')
670 674 def cellm33(self, line, cell):
671 675 return line, cell
672 676
673 677 _ip.register_magics(MyMagics2)
674 678 self.check_ident('cellm4')
675 679 # Check that nothing is registered as 'cellm33'
676 680 c33 = _ip.find_cell_magic('cellm33')
677 681 nt.assert_equal(c33, None)
678 682
679 683 def test_file():
680 684 """Basic %%file"""
681 685 ip = get_ipython()
682 686 with TemporaryDirectory() as td:
683 687 fname = os.path.join(td, 'file1')
684 688 ip.run_cell_magic("file", fname, u'\n'.join([
685 689 'line1',
686 690 'line2',
687 691 ]))
688 692 with open(fname) as f:
689 693 s = f.read()
690 694 nt.assert_in('line1\n', s)
691 695 nt.assert_in('line2', s)
692 696
693 697 def test_file_var_expand():
694 698 """%%file $filename"""
695 699 ip = get_ipython()
696 700 with TemporaryDirectory() as td:
697 701 fname = os.path.join(td, 'file1')
698 702 ip.user_ns['filename'] = fname
699 703 ip.run_cell_magic("file", '$filename', u'\n'.join([
700 704 'line1',
701 705 'line2',
702 706 ]))
703 707 with open(fname) as f:
704 708 s = f.read()
705 709 nt.assert_in('line1\n', s)
706 710 nt.assert_in('line2', s)
707 711
708 712 def test_file_unicode():
709 713 """%%file with unicode cell"""
710 714 ip = get_ipython()
711 715 with TemporaryDirectory() as td:
712 716 fname = os.path.join(td, 'file1')
713 717 ip.run_cell_magic("file", fname, u'\n'.join([
714 718 u'linΓ©1',
715 719 u'linΓ©2',
716 720 ]))
717 721 with io.open(fname, encoding='utf-8') as f:
718 722 s = f.read()
719 723 nt.assert_in(u'linΓ©1\n', s)
720 724 nt.assert_in(u'linΓ©2', s)
721 725
722 726 def test_file_amend():
723 727 """%%file -a amends files"""
724 728 ip = get_ipython()
725 729 with TemporaryDirectory() as td:
726 730 fname = os.path.join(td, 'file2')
727 731 ip.run_cell_magic("file", fname, u'\n'.join([
728 732 'line1',
729 733 'line2',
730 734 ]))
731 735 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
732 736 'line3',
733 737 'line4',
734 738 ]))
735 739 with open(fname) as f:
736 740 s = f.read()
737 741 nt.assert_in('line1\n', s)
738 742 nt.assert_in('line3\n', s)
739 743
740 744
741 745 def test_script_config():
742 746 ip = get_ipython()
743 747 ip.config.ScriptMagics.script_magics = ['whoda']
744 748 sm = script.ScriptMagics(shell=ip)
745 749 nt.assert_in('whoda', sm.magics['cell'])
746 750
747 751 @dec.skip_win32
748 752 def test_script_out():
749 753 ip = get_ipython()
750 754 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
751 755 nt.assert_equal(ip.user_ns['output'], 'hi\n')
752 756
753 757 @dec.skip_win32
754 758 def test_script_err():
755 759 ip = get_ipython()
756 760 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
757 761 nt.assert_equal(ip.user_ns['error'], 'hello\n')
758 762
759 763 @dec.skip_win32
760 764 def test_script_out_err():
761 765 ip = get_ipython()
762 766 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
763 767 nt.assert_equal(ip.user_ns['output'], 'hi\n')
764 768 nt.assert_equal(ip.user_ns['error'], 'hello\n')
765 769
766 770 @dec.skip_win32
767 771 def test_script_bg_out():
768 772 ip = get_ipython()
769 773 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
770 774 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
771 775
772 776 @dec.skip_win32
773 777 def test_script_bg_err():
774 778 ip = get_ipython()
775 779 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
776 780 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
777 781
778 782 @dec.skip_win32
779 783 def test_script_bg_out_err():
780 784 ip = get_ipython()
781 785 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
782 786 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
783 787 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
784 788
785 789 def test_script_defaults():
786 790 ip = get_ipython()
787 791 for cmd in ['sh', 'bash', 'perl', 'ruby']:
788 792 try:
789 793 find_cmd(cmd)
790 794 except Exception:
791 795 pass
792 796 else:
793 797 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
794 798
795 799
796 800 @magics_class
797 801 class FooFoo(Magics):
798 802 """class with both %foo and %%foo magics"""
799 803 @line_magic('foo')
800 804 def line_foo(self, line):
801 805 "I am line foo"
802 806 pass
803 807
804 808 @cell_magic("foo")
805 809 def cell_foo(self, line, cell):
806 810 "I am cell foo, not line foo"
807 811 pass
808 812
809 813 def test_line_cell_info():
810 814 """%%foo and %foo magics are distinguishable to inspect"""
811 815 ip = get_ipython()
812 816 ip.magics_manager.register(FooFoo)
813 817 oinfo = ip.object_inspect('foo')
814 818 nt.assert_true(oinfo['found'])
815 819 nt.assert_true(oinfo['ismagic'])
816 820
817 821 oinfo = ip.object_inspect('%%foo')
818 822 nt.assert_true(oinfo['found'])
819 823 nt.assert_true(oinfo['ismagic'])
820 824 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
821 825
822 826 oinfo = ip.object_inspect('%foo')
823 827 nt.assert_true(oinfo['found'])
824 828 nt.assert_true(oinfo['ismagic'])
825 829 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
826 830
827 831 def test_multiple_magics():
828 832 ip = get_ipython()
829 833 foo1 = FooFoo(ip)
830 834 foo2 = FooFoo(ip)
831 835 mm = ip.magics_manager
832 836 mm.register(foo1)
833 837 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
834 838 mm.register(foo2)
835 839 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
836 840
837 841 def test_alias_magic():
838 842 """Test %alias_magic."""
839 843 ip = get_ipython()
840 844 mm = ip.magics_manager
841 845
842 846 # Basic operation: both cell and line magics are created, if possible.
843 847 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
844 848 nt.assert_in('timeit_alias', mm.magics['line'])
845 849 nt.assert_in('timeit_alias', mm.magics['cell'])
846 850
847 851 # --cell is specified, line magic not created.
848 852 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
849 853 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
850 854 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
851 855
852 856 # Test that line alias is created successfully.
853 857 ip.run_line_magic('alias_magic', '--line env_alias env')
854 858 nt.assert_equal(ip.run_line_magic('env', ''),
855 859 ip.run_line_magic('env_alias', ''))
856 860
857 861 def test_save():
858 862 """Test %save."""
859 863 ip = get_ipython()
860 864 ip.history_manager.reset() # Clear any existing history.
861 865 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
862 866 for i, cmd in enumerate(cmds, start=1):
863 867 ip.history_manager.store_inputs(i, cmd)
864 868 with TemporaryDirectory() as tmpdir:
865 869 file = os.path.join(tmpdir, "testsave.py")
866 870 ip.run_line_magic("save", "%s 1-10" % file)
867 871 with open(file) as f:
868 872 content = f.read()
869 873 nt.assert_equal(content.count(cmds[0]), 1)
870 874 nt.assert_in('coding: utf-8', content)
871 875 ip.run_line_magic("save", "-a %s 1-10" % file)
872 876 with open(file) as f:
873 877 content = f.read()
874 878 nt.assert_equal(content.count(cmds[0]), 2)
875 879 nt.assert_in('coding: utf-8', content)
876 880
877 881
878 882 def test_store():
879 883 """Test %store."""
880 884 ip = get_ipython()
881 885 ip.run_line_magic('load_ext', 'storemagic')
882 886
883 887 # make sure the storage is empty
884 888 ip.run_line_magic('store', '-z')
885 889 ip.user_ns['var'] = 42
886 890 ip.run_line_magic('store', 'var')
887 891 ip.user_ns['var'] = 39
888 892 ip.run_line_magic('store', '-r')
889 893 nt.assert_equal(ip.user_ns['var'], 42)
890 894
891 895 ip.run_line_magic('store', '-d var')
892 896 ip.user_ns['var'] = 39
893 897 ip.run_line_magic('store' , '-r')
894 898 nt.assert_equal(ip.user_ns['var'], 39)
895 899
896 900
897 901 def _run_edit_test(arg_s, exp_filename=None,
898 902 exp_lineno=-1,
899 903 exp_contents=None,
900 904 exp_is_temp=None):
901 905 ip = get_ipython()
902 906 M = code.CodeMagics(ip)
903 907 last_call = ['','']
904 908 opts,args = M.parse_options(arg_s,'prxn:')
905 909 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
906 910
907 911 if exp_filename is not None:
908 912 nt.assert_equal(exp_filename, filename)
909 913 if exp_contents is not None:
910 914 with io.open(filename, 'r') as f:
911 915 contents = f.read()
912 916 nt.assert_equal(exp_contents, contents)
913 917 if exp_lineno != -1:
914 918 nt.assert_equal(exp_lineno, lineno)
915 919 if exp_is_temp is not None:
916 920 nt.assert_equal(exp_is_temp, is_temp)
917 921
918 922
919 923 def test_edit_interactive():
920 924 """%edit on interactively defined objects"""
921 925 ip = get_ipython()
922 926 n = ip.execution_count
923 927 ip.run_cell(u"def foo(): return 1", store_history=True)
924 928
925 929 try:
926 930 _run_edit_test("foo")
927 931 except code.InteractivelyDefined as e:
928 932 nt.assert_equal(e.index, n)
929 933 else:
930 934 raise AssertionError("Should have raised InteractivelyDefined")
931 935
932 936
933 937 def test_edit_cell():
934 938 """%edit [cell id]"""
935 939 ip = get_ipython()
936 940
937 941 ip.run_cell(u"def foo(): return 1", store_history=True)
938 942
939 943 # test
940 944 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
@@ -1,317 +1,322 b''
1 1 """Tests for autoreload extension.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012 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
15 15 import os
16 16 import sys
17 17 import tempfile
18 18 import shutil
19 19 import random
20 20 import time
21 from io import StringIO
22 21
23 22 import nose.tools as nt
24 23 import IPython.testing.tools as tt
25 24
26 25 from IPython.extensions.autoreload import AutoreloadMagics
27 26 from IPython.core.hooks import TryNext
27 from IPython.utils.py3compat import PY3
28
29 if PY3:
30 from io import StringIO
31 else:
32 from StringIO import StringIO
28 33
29 34 #-----------------------------------------------------------------------------
30 35 # Test fixture
31 36 #-----------------------------------------------------------------------------
32 37
33 38 noop = lambda *a, **kw: None
34 39
35 40 class FakeShell(object):
36 41
37 42 def __init__(self):
38 43 self.ns = {}
39 44 self.auto_magics = AutoreloadMagics(shell=self)
40 45
41 46 register_magics = set_hook = noop
42 47
43 48 def run_code(self, code):
44 49 try:
45 50 self.auto_magics.pre_run_code_hook(self)
46 51 except TryNext:
47 52 pass
48 53 exec(code, self.ns)
49 54
50 55 def push(self, items):
51 56 self.ns.update(items)
52 57
53 58 def magic_autoreload(self, parameter):
54 59 self.auto_magics.autoreload(parameter)
55 60
56 61 def magic_aimport(self, parameter, stream=None):
57 62 self.auto_magics.aimport(parameter, stream=stream)
58 63
59 64
60 65 class Fixture(object):
61 66 """Fixture for creating test module files"""
62 67
63 68 test_dir = None
64 69 old_sys_path = None
65 70 filename_chars = "abcdefghijklmopqrstuvwxyz0123456789"
66 71
67 72 def setUp(self):
68 73 self.test_dir = tempfile.mkdtemp()
69 74 self.old_sys_path = list(sys.path)
70 75 sys.path.insert(0, self.test_dir)
71 76 self.shell = FakeShell()
72 77
73 78 def tearDown(self):
74 79 shutil.rmtree(self.test_dir)
75 80 sys.path = self.old_sys_path
76 81
77 82 self.test_dir = None
78 83 self.old_sys_path = None
79 84 self.shell = None
80 85
81 86 def get_module(self):
82 87 module_name = "tmpmod_" + "".join(random.sample(self.filename_chars,20))
83 88 if module_name in sys.modules:
84 89 del sys.modules[module_name]
85 90 file_name = os.path.join(self.test_dir, module_name + ".py")
86 91 return module_name, file_name
87 92
88 93 def write_file(self, filename, content):
89 94 """
90 95 Write a file, and force a timestamp difference of at least one second
91 96
92 97 Notes
93 98 -----
94 99 Python's .pyc files record the timestamp of their compilation
95 100 with a time resolution of one second.
96 101
97 102 Therefore, we need to force a timestamp difference between .py
98 103 and .pyc, without having the .py file be timestamped in the
99 104 future, and without changing the timestamp of the .pyc file
100 105 (because that is stored in the file). The only reliable way
101 106 to achieve this seems to be to sleep.
102 107 """
103 108
104 109 # Sleep one second + eps
105 110 time.sleep(1.05)
106 111
107 112 # Write
108 113 f = open(filename, 'w')
109 114 try:
110 115 f.write(content)
111 116 finally:
112 117 f.close()
113 118
114 119 def new_module(self, code):
115 120 mod_name, mod_fn = self.get_module()
116 121 f = open(mod_fn, 'w')
117 122 try:
118 123 f.write(code)
119 124 finally:
120 125 f.close()
121 126 return mod_name, mod_fn
122 127
123 128 #-----------------------------------------------------------------------------
124 129 # Test automatic reloading
125 130 #-----------------------------------------------------------------------------
126 131
127 132 class TestAutoreload(Fixture):
128 133 def _check_smoketest(self, use_aimport=True):
129 134 """
130 135 Functional test for the automatic reloader using either
131 136 '%autoreload 1' or '%autoreload 2'
132 137 """
133 138
134 139 mod_name, mod_fn = self.new_module("""
135 140 x = 9
136 141
137 142 z = 123 # this item will be deleted
138 143
139 144 def foo(y):
140 145 return y + 3
141 146
142 147 class Baz(object):
143 148 def __init__(self, x):
144 149 self.x = x
145 150 def bar(self, y):
146 151 return self.x + y
147 152 @property
148 153 def quux(self):
149 154 return 42
150 155 def zzz(self):
151 156 '''This method will be deleted below'''
152 157 return 99
153 158
154 159 class Bar: # old-style class: weakref doesn't work for it on Python < 2.7
155 160 def foo(self):
156 161 return 1
157 162 """)
158 163
159 164 #
160 165 # Import module, and mark for reloading
161 166 #
162 167 if use_aimport:
163 168 self.shell.magic_autoreload("1")
164 169 self.shell.magic_aimport(mod_name)
165 170 stream = StringIO()
166 171 self.shell.magic_aimport("", stream=stream)
167 172 nt.assert_true(("Modules to reload:\n%s" % mod_name) in
168 173 stream.getvalue())
169 174
170 175 nt.assert_raises(
171 176 ImportError,
172 177 self.shell.magic_aimport, "tmpmod_as318989e89ds")
173 178 else:
174 179 self.shell.magic_autoreload("2")
175 180 self.shell.run_code("import %s" % mod_name)
176 181 stream = StringIO()
177 182 self.shell.magic_aimport("", stream=stream)
178 183 nt.assert_true("Modules to reload:\nall-except-skipped" in
179 184 stream.getvalue())
180 185 nt.assert_in(mod_name, self.shell.ns)
181 186
182 187 mod = sys.modules[mod_name]
183 188
184 189 #
185 190 # Test module contents
186 191 #
187 192 old_foo = mod.foo
188 193 old_obj = mod.Baz(9)
189 194 old_obj2 = mod.Bar()
190 195
191 196 def check_module_contents():
192 197 nt.assert_equal(mod.x, 9)
193 198 nt.assert_equal(mod.z, 123)
194 199
195 200 nt.assert_equal(old_foo(0), 3)
196 201 nt.assert_equal(mod.foo(0), 3)
197 202
198 203 obj = mod.Baz(9)
199 204 nt.assert_equal(old_obj.bar(1), 10)
200 205 nt.assert_equal(obj.bar(1), 10)
201 206 nt.assert_equal(obj.quux, 42)
202 207 nt.assert_equal(obj.zzz(), 99)
203 208
204 209 obj2 = mod.Bar()
205 210 nt.assert_equal(old_obj2.foo(), 1)
206 211 nt.assert_equal(obj2.foo(), 1)
207 212
208 213 check_module_contents()
209 214
210 215 #
211 216 # Simulate a failed reload: no reload should occur and exactly
212 217 # one error message should be printed
213 218 #
214 219 self.write_file(mod_fn, """
215 220 a syntax error
216 221 """)
217 222
218 223 with tt.AssertPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
219 224 self.shell.run_code("pass") # trigger reload
220 225 with tt.AssertNotPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
221 226 self.shell.run_code("pass") # trigger another reload
222 227 check_module_contents()
223 228
224 229 #
225 230 # Rewrite module (this time reload should succeed)
226 231 #
227 232 self.write_file(mod_fn, """
228 233 x = 10
229 234
230 235 def foo(y):
231 236 return y + 4
232 237
233 238 class Baz(object):
234 239 def __init__(self, x):
235 240 self.x = x
236 241 def bar(self, y):
237 242 return self.x + y + 1
238 243 @property
239 244 def quux(self):
240 245 return 43
241 246
242 247 class Bar: # old-style class
243 248 def foo(self):
244 249 return 2
245 250 """)
246 251
247 252 def check_module_contents():
248 253 nt.assert_equal(mod.x, 10)
249 254 nt.assert_false(hasattr(mod, 'z'))
250 255
251 256 nt.assert_equal(old_foo(0), 4) # superreload magic!
252 257 nt.assert_equal(mod.foo(0), 4)
253 258
254 259 obj = mod.Baz(9)
255 260 nt.assert_equal(old_obj.bar(1), 11) # superreload magic!
256 261 nt.assert_equal(obj.bar(1), 11)
257 262
258 263 nt.assert_equal(old_obj.quux, 43)
259 264 nt.assert_equal(obj.quux, 43)
260 265
261 266 nt.assert_false(hasattr(old_obj, 'zzz'))
262 267 nt.assert_false(hasattr(obj, 'zzz'))
263 268
264 269 obj2 = mod.Bar()
265 270 nt.assert_equal(old_obj2.foo(), 2)
266 271 nt.assert_equal(obj2.foo(), 2)
267 272
268 273 self.shell.run_code("pass") # trigger reload
269 274 check_module_contents()
270 275
271 276 #
272 277 # Another failure case: deleted file (shouldn't reload)
273 278 #
274 279 os.unlink(mod_fn)
275 280
276 281 self.shell.run_code("pass") # trigger reload
277 282 check_module_contents()
278 283
279 284 #
280 285 # Disable autoreload and rewrite module: no reload should occur
281 286 #
282 287 if use_aimport:
283 288 self.shell.magic_aimport("-" + mod_name)
284 289 stream = StringIO()
285 290 self.shell.magic_aimport("", stream=stream)
286 291 nt.assert_true(("Modules to skip:\n%s" % mod_name) in
287 292 stream.getvalue())
288 293
289 294 # This should succeed, although no such module exists
290 295 self.shell.magic_aimport("-tmpmod_as318989e89ds")
291 296 else:
292 297 self.shell.magic_autoreload("0")
293 298
294 299 self.write_file(mod_fn, """
295 300 x = -99
296 301 """)
297 302
298 303 self.shell.run_code("pass") # trigger reload
299 304 self.shell.run_code("pass")
300 305 check_module_contents()
301 306
302 307 #
303 308 # Re-enable autoreload: reload should now occur
304 309 #
305 310 if use_aimport:
306 311 self.shell.magic_aimport(mod_name)
307 312 else:
308 313 self.shell.magic_autoreload("")
309 314
310 315 self.shell.run_code("pass") # trigger reload
311 316 nt.assert_equal(mod.x, -99)
312 317
313 318 def test_smoketest_aimport(self):
314 319 self._check_smoketest(use_aimport=True)
315 320
316 321 def test_smoketest_autoreload(self):
317 322 self._check_smoketest(use_aimport=False)
@@ -1,122 +1,126 b''
1 from io import StringIO
2
3 1 import numpy as np
4 2 from IPython.testing.decorators import skip_without
5 3 from IPython.extensions import rmagic
4 from IPython.utils.py3compat import PY3
6 5 from rpy2 import rinterface
7 6 import nose.tools as nt
8 7
8 if PY3:
9 from io import StringIO
10 else:
11 from StringIO import StringIO
12
9 13 ip = get_ipython()
10 14 ip.magic('load_ext rmagic')
11 15
12 16
13 17 def test_push():
14 18 rm = rmagic.RMagics(ip)
15 19 ip.push({'X':np.arange(5), 'Y':np.array([3,5,4,6,7])})
16 20 ip.run_line_magic('Rpush', 'X Y')
17 21 np.testing.assert_almost_equal(np.asarray(rm.r('X')), ip.user_ns['X'])
18 22 np.testing.assert_almost_equal(np.asarray(rm.r('Y')), ip.user_ns['Y'])
19 23
20 24 def test_push_localscope():
21 25 """Test that Rpush looks for variables in the local scope first."""
22 26 ip.run_cell('''
23 27 def rmagic_addone(u):
24 28 %Rpush u
25 29 %R result = u+1
26 30 %Rpull result
27 31 return result[0]
28 32 u = 0
29 33 result = rmagic_addone(12344)
30 34 ''')
31 35 result = ip.user_ns['result']
32 36 np.testing.assert_equal(result, 12345)
33 37
34 38 @skip_without('pandas')
35 39 def test_push_dataframe():
36 40 from pandas import DataFrame
37 41 rm = rmagic.RMagics(ip)
38 42 df = DataFrame([{'a': 1, 'b': 'bar'}, {'a': 5, 'b': 'foo', 'c': 20}])
39 43 ip.push({'df':df})
40 44 ip.run_line_magic('Rpush', 'df')
41 45
42 46 # This is converted to factors, which are currently converted back to Python
43 47 # as integers, so for now we test its representation in R.
44 48 sio = StringIO()
45 49 rinterface.set_writeconsole(sio.write)
46 50 try:
47 51 rm.r('print(df$b[1])')
48 52 nt.assert_in('[1] bar', sio.getvalue())
49 53 finally:
50 54 rinterface.set_writeconsole(None)
51 55
52 56 # Values come packaged in arrays, so we unbox them to test.
53 57 nt.assert_equal(rm.r('df$a[2]')[0], 5)
54 58 missing = rm.r('df$c[1]')[0]
55 59 assert np.isnan(missing), missing
56 60
57 61 def test_pull():
58 62 rm = rmagic.RMagics(ip)
59 63 rm.r('Z=c(11:20)')
60 64 ip.run_line_magic('Rpull', 'Z')
61 65 np.testing.assert_almost_equal(np.asarray(rm.r('Z')), ip.user_ns['Z'])
62 66 np.testing.assert_almost_equal(ip.user_ns['Z'], np.arange(11,21))
63 67
64 68 def test_Rconverter():
65 69 datapy= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')],
66 70 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
67 71 ip.user_ns['datapy'] = datapy
68 72 ip.run_line_magic('Rpush', 'datapy')
69 73
70 74 # test to see if a copy is being made
71 75 v = ip.run_line_magic('Rget', '-d datapy')
72 76 w = ip.run_line_magic('Rget', '-d datapy')
73 77 np.testing.assert_almost_equal(w['x'], v['x'])
74 78 np.testing.assert_almost_equal(w['y'], v['y'])
75 79 nt.assert_true(np.all(w['z'] == v['z']))
76 80 np.testing.assert_equal(id(w.data), id(v.data))
77 81 nt.assert_equal(w.dtype, v.dtype)
78 82
79 83 ip.run_cell_magic('R', ' -d datar', 'datar=datapy')
80 84
81 85 u = ip.run_line_magic('Rget', ' -d datar')
82 86 np.testing.assert_almost_equal(u['x'], v['x'])
83 87 np.testing.assert_almost_equal(u['y'], v['y'])
84 88 nt.assert_true(np.all(u['z'] == v['z']))
85 89 np.testing.assert_equal(id(u.data), id(v.data))
86 90 nt.assert_equal(u.dtype, v.dtype)
87 91
88 92
89 93 def test_cell_magic():
90 94
91 95 ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
92 96 snippet = '''
93 97 print(summary(a))
94 98 plot(x, y, pch=23, bg='orange', cex=2)
95 99 plot(x, x)
96 100 print(summary(x))
97 101 r = resid(a)
98 102 xc = coef(a)
99 103 '''
100 104 ip.run_cell_magic('R', '-i x,y -o r,xc -w 150 -u mm a=lm(y~x)', snippet)
101 105 np.testing.assert_almost_equal(ip.user_ns['xc'], [3.2, 0.9])
102 106 np.testing.assert_almost_equal(ip.user_ns['r'], np.array([-0.2, 0.9, -1. , 0.1, 0.2]))
103 107
104 108
105 109 def test_rmagic_localscope():
106 110 ip.push({'x':0})
107 111 ip.run_line_magic('R', '-i x -o result result <-x+1')
108 112 result = ip.user_ns['result']
109 113 nt.assert_equal(result[0], 1)
110 114
111 115 ip.run_cell('''def rmagic_addone(u):
112 116 %R -i u -o result result <- u+1
113 117 return result[0]''')
114 118 ip.run_cell('result = rmagic_addone(1)')
115 119 result = ip.user_ns['result']
116 120 nt.assert_equal(result, 2)
117 121
118 122 nt.assert_raises(
119 123 NameError,
120 124 ip.run_line_magic,
121 125 "R",
122 126 "-i var_not_defined 1+1")
@@ -1,91 +1,95 b''
1 1 #-------------------------------------------------------------------------------
2 2 # Copyright (C) 2012 The IPython Development Team
3 3 #
4 4 # Distributed under the terms of the BSD License. The full license is in
5 5 # the file COPYING, distributed as part of this software.
6 6 #-------------------------------------------------------------------------------
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Imports
10 10 #-----------------------------------------------------------------------------
11 11 from __future__ import print_function
12 12
13 13 # Standard library imports
14 from io import StringIO
15 14 import sys
16 15 import unittest
17 16
18 17 # Local imports
19 18 from IPython.kernel.inprocess.blocking import BlockingInProcessKernelClient
20 19 from IPython.kernel.inprocess.manager import InProcessKernelManager
21 20 from IPython.kernel.inprocess.ipkernel import InProcessKernel
22 21 from IPython.testing.decorators import skipif_not_matplotlib
23 22 from IPython.utils.io import capture_output
24 23 from IPython.utils import py3compat
25 24
25 if py3compat.PY3:
26 from io import StringIO
27 else:
28 from StringIO import StringIO
29
26 30 #-----------------------------------------------------------------------------
27 31 # Test case
28 32 #-----------------------------------------------------------------------------
29 33
30 34 class InProcessKernelTestCase(unittest.TestCase):
31 35
32 36 def setUp(self):
33 37 self.km = InProcessKernelManager()
34 38 self.km.start_kernel()
35 39 self.kc = BlockingInProcessKernelClient(kernel=self.km.kernel)
36 40 self.kc.start_channels()
37 41
38 42 @skipif_not_matplotlib
39 43 def test_pylab(self):
40 44 """ Does pylab work in the in-process kernel?
41 45 """
42 46 kc = self.kc
43 47 kc.execute('%pylab')
44 48 msg = get_stream_message(kc)
45 49 self.assert_('matplotlib' in msg['content']['data'])
46 50
47 51 def test_raw_input(self):
48 52 """ Does the in-process kernel handle raw_input correctly?
49 53 """
50 54 io = StringIO('foobar\n')
51 55 sys_stdin = sys.stdin
52 56 sys.stdin = io
53 57 try:
54 58 if py3compat.PY3:
55 59 self.kc.execute('x = input()')
56 60 else:
57 61 self.kc.execute('x = raw_input()')
58 62 finally:
59 63 sys.stdin = sys_stdin
60 64 self.assertEqual(self.km.kernel.shell.user_ns.get('x'), 'foobar')
61 65
62 66 def test_stdout(self):
63 67 """ Does the in-process kernel correctly capture IO?
64 68 """
65 69 kernel = InProcessKernel()
66 70
67 71 with capture_output() as io:
68 72 kernel.shell.run_cell('print("foo")')
69 73 self.assertEqual(io.stdout, 'foo\n')
70 74
71 75 kc = BlockingInProcessKernelClient(kernel=kernel)
72 76 kernel.frontends.append(kc)
73 77 kc.shell_channel.execute('print("bar")')
74 78 msg = get_stream_message(kc)
75 79 self.assertEqual(msg['content']['data'], 'bar\n')
76 80
77 81 #-----------------------------------------------------------------------------
78 82 # Utility functions
79 83 #-----------------------------------------------------------------------------
80 84
81 85 def get_stream_message(kernel_client, timeout=5):
82 86 """ Gets a single stream message synchronously from the sub channel.
83 87 """
84 88 while True:
85 89 msg = kernel_client.get_iopub_msg(timeout=timeout)
86 90 if msg['header']['msg_type'] == 'stream':
87 91 return msg
88 92
89 93
90 94 if __name__ == '__main__':
91 95 unittest.main()
@@ -1,791 +1,797 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Python advanced pretty printer. This pretty printer is intended to
4 4 replace the old `pprint` python module which does not allow developers
5 5 to provide their own pretty print callbacks.
6 6
7 7 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
8 8
9 9
10 10 Example Usage
11 11 -------------
12 12
13 13 To directly print the representation of an object use `pprint`::
14 14
15 15 from pretty import pprint
16 16 pprint(complex_object)
17 17
18 18 To get a string of the output use `pretty`::
19 19
20 20 from pretty import pretty
21 21 string = pretty(complex_object)
22 22
23 23
24 24 Extending
25 25 ---------
26 26
27 27 The pretty library allows developers to add pretty printing rules for their
28 28 own objects. This process is straightforward. All you have to do is to
29 29 add a `_repr_pretty_` method to your object and call the methods on the
30 30 pretty printer passed::
31 31
32 32 class MyObject(object):
33 33
34 34 def _repr_pretty_(self, p, cycle):
35 35 ...
36 36
37 37 Depending on the python version you want to support you have two
38 38 possibilities. The following list shows the python 2.5 version and the
39 39 compatibility one.
40 40
41 41
42 42 Here the example implementation of a `_repr_pretty_` method for a list
43 43 subclass for python 2.5 and higher (python 2.5 requires the with statement
44 44 __future__ import)::
45 45
46 46 class MyList(list):
47 47
48 48 def _repr_pretty_(self, p, cycle):
49 49 if cycle:
50 50 p.text('MyList(...)')
51 51 else:
52 52 with p.group(8, 'MyList([', '])'):
53 53 for idx, item in enumerate(self):
54 54 if idx:
55 55 p.text(',')
56 56 p.breakable()
57 57 p.pretty(item)
58 58
59 59 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
60 60 react to that or the result is an infinite loop. `p.text()` just adds
61 61 non breaking text to the output, `p.breakable()` either adds a whitespace
62 62 or breaks here. If you pass it an argument it's used instead of the
63 63 default space. `p.pretty` prettyprints another object using the pretty print
64 64 method.
65 65
66 66 The first parameter to the `group` function specifies the extra indentation
67 67 of the next line. In this example the next item will either be not
68 68 breaked (if the items are short enough) or aligned with the right edge of
69 69 the opening bracked of `MyList`.
70 70
71 71 If you want to support python 2.4 and lower you can use this code::
72 72
73 73 class MyList(list):
74 74
75 75 def _repr_pretty_(self, p, cycle):
76 76 if cycle:
77 77 p.text('MyList(...)')
78 78 else:
79 79 p.begin_group(8, 'MyList([')
80 80 for idx, item in enumerate(self):
81 81 if idx:
82 82 p.text(',')
83 83 p.breakable()
84 84 p.pretty(item)
85 85 p.end_group(8, '])')
86 86
87 87 If you just want to indent something you can use the group function
88 88 without open / close parameters. Under python 2.5 you can also use this
89 89 code::
90 90
91 91 with p.indent(2):
92 92 ...
93 93
94 94 Or under python2.4 you might want to modify ``p.indentation`` by hand but
95 95 this is rather ugly.
96 96
97 97 Inheritance diagram:
98 98
99 99 .. inheritance-diagram:: IPython.lib.pretty
100 100 :parts: 3
101 101
102 102 :copyright: 2007 by Armin Ronacher.
103 103 Portions (c) 2009 by Robert Kern.
104 104 :license: BSD License.
105 105 """
106 106 from __future__ import print_function
107 107 from contextlib import contextmanager
108 108 import sys
109 109 import types
110 110 import re
111 111 import datetime
112 from io import StringIO
113 112 from collections import deque
114 113
114 from IPython.utils.py3compat import PY3
115
116 if PY3:
117 from io import StringIO
118 else:
119 from StringIO import StringIO
120
115 121
116 122 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
117 123 'for_type', 'for_type_by_name']
118 124
119 125
120 126 _re_pattern_type = type(re.compile(''))
121 127
122 128
123 129 def pretty(obj, verbose=False, max_width=79, newline='\n'):
124 130 """
125 131 Pretty print the object's representation.
126 132 """
127 133 stream = StringIO()
128 134 printer = RepresentationPrinter(stream, verbose, max_width, newline)
129 135 printer.pretty(obj)
130 136 printer.flush()
131 137 return stream.getvalue()
132 138
133 139
134 140 def pprint(obj, verbose=False, max_width=79, newline='\n'):
135 141 """
136 142 Like `pretty` but print to stdout.
137 143 """
138 144 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
139 145 printer.pretty(obj)
140 146 printer.flush()
141 147 sys.stdout.write(newline)
142 148 sys.stdout.flush()
143 149
144 150 class _PrettyPrinterBase(object):
145 151
146 152 @contextmanager
147 153 def indent(self, indent):
148 154 """with statement support for indenting/dedenting."""
149 155 self.indentation += indent
150 156 try:
151 157 yield
152 158 finally:
153 159 self.indentation -= indent
154 160
155 161 @contextmanager
156 162 def group(self, indent=0, open='', close=''):
157 163 """like begin_group / end_group but for the with statement."""
158 164 self.begin_group(indent, open)
159 165 try:
160 166 yield
161 167 finally:
162 168 self.end_group(indent, close)
163 169
164 170 class PrettyPrinter(_PrettyPrinterBase):
165 171 """
166 172 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
167 173 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
168 174 this printer knows nothing about the default pprinters or the `_repr_pretty_`
169 175 callback method.
170 176 """
171 177
172 178 def __init__(self, output, max_width=79, newline='\n'):
173 179 self.output = output
174 180 self.max_width = max_width
175 181 self.newline = newline
176 182 self.output_width = 0
177 183 self.buffer_width = 0
178 184 self.buffer = deque()
179 185
180 186 root_group = Group(0)
181 187 self.group_stack = [root_group]
182 188 self.group_queue = GroupQueue(root_group)
183 189 self.indentation = 0
184 190
185 191 def _break_outer_groups(self):
186 192 while self.max_width < self.output_width + self.buffer_width:
187 193 group = self.group_queue.deq()
188 194 if not group:
189 195 return
190 196 while group.breakables:
191 197 x = self.buffer.popleft()
192 198 self.output_width = x.output(self.output, self.output_width)
193 199 self.buffer_width -= x.width
194 200 while self.buffer and isinstance(self.buffer[0], Text):
195 201 x = self.buffer.popleft()
196 202 self.output_width = x.output(self.output, self.output_width)
197 203 self.buffer_width -= x.width
198 204
199 205 def text(self, obj):
200 206 """Add literal text to the output."""
201 207 width = len(obj)
202 208 if self.buffer:
203 209 text = self.buffer[-1]
204 210 if not isinstance(text, Text):
205 211 text = Text()
206 212 self.buffer.append(text)
207 213 text.add(obj, width)
208 214 self.buffer_width += width
209 215 self._break_outer_groups()
210 216 else:
211 217 self.output.write(obj)
212 218 self.output_width += width
213 219
214 220 def breakable(self, sep=' '):
215 221 """
216 222 Add a breakable separator to the output. This does not mean that it
217 223 will automatically break here. If no breaking on this position takes
218 224 place the `sep` is inserted which default to one space.
219 225 """
220 226 width = len(sep)
221 227 group = self.group_stack[-1]
222 228 if group.want_break:
223 229 self.flush()
224 230 self.output.write(self.newline)
225 231 self.output.write(' ' * self.indentation)
226 232 self.output_width = self.indentation
227 233 self.buffer_width = 0
228 234 else:
229 235 self.buffer.append(Breakable(sep, width, self))
230 236 self.buffer_width += width
231 237 self._break_outer_groups()
232 238
233 239 def break_(self):
234 240 """
235 241 Explicitly insert a newline into the output, maintaining correct indentation.
236 242 """
237 243 self.flush()
238 244 self.output.write(self.newline)
239 245 self.output.write(' ' * self.indentation)
240 246 self.output_width = self.indentation
241 247 self.buffer_width = 0
242 248
243 249
244 250 def begin_group(self, indent=0, open=''):
245 251 """
246 252 Begin a group. If you want support for python < 2.5 which doesn't has
247 253 the with statement this is the preferred way:
248 254
249 255 p.begin_group(1, '{')
250 256 ...
251 257 p.end_group(1, '}')
252 258
253 259 The python 2.5 expression would be this:
254 260
255 261 with p.group(1, '{', '}'):
256 262 ...
257 263
258 264 The first parameter specifies the indentation for the next line (usually
259 265 the width of the opening text), the second the opening text. All
260 266 parameters are optional.
261 267 """
262 268 if open:
263 269 self.text(open)
264 270 group = Group(self.group_stack[-1].depth + 1)
265 271 self.group_stack.append(group)
266 272 self.group_queue.enq(group)
267 273 self.indentation += indent
268 274
269 275 def end_group(self, dedent=0, close=''):
270 276 """End a group. See `begin_group` for more details."""
271 277 self.indentation -= dedent
272 278 group = self.group_stack.pop()
273 279 if not group.breakables:
274 280 self.group_queue.remove(group)
275 281 if close:
276 282 self.text(close)
277 283
278 284 def flush(self):
279 285 """Flush data that is left in the buffer."""
280 286 for data in self.buffer:
281 287 self.output_width += data.output(self.output, self.output_width)
282 288 self.buffer.clear()
283 289 self.buffer_width = 0
284 290
285 291
286 292 def _get_mro(obj_class):
287 293 """ Get a reasonable method resolution order of a class and its superclasses
288 294 for both old-style and new-style classes.
289 295 """
290 296 if not hasattr(obj_class, '__mro__'):
291 297 # Old-style class. Mix in object to make a fake new-style class.
292 298 try:
293 299 obj_class = type(obj_class.__name__, (obj_class, object), {})
294 300 except TypeError:
295 301 # Old-style extension type that does not descend from object.
296 302 # FIXME: try to construct a more thorough MRO.
297 303 mro = [obj_class]
298 304 else:
299 305 mro = obj_class.__mro__[1:-1]
300 306 else:
301 307 mro = obj_class.__mro__
302 308 return mro
303 309
304 310
305 311 class RepresentationPrinter(PrettyPrinter):
306 312 """
307 313 Special pretty printer that has a `pretty` method that calls the pretty
308 314 printer for a python object.
309 315
310 316 This class stores processing data on `self` so you must *never* use
311 317 this class in a threaded environment. Always lock it or reinstanciate
312 318 it.
313 319
314 320 Instances also have a verbose flag callbacks can access to control their
315 321 output. For example the default instance repr prints all attributes and
316 322 methods that are not prefixed by an underscore if the printer is in
317 323 verbose mode.
318 324 """
319 325
320 326 def __init__(self, output, verbose=False, max_width=79, newline='\n',
321 327 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
322 328
323 329 PrettyPrinter.__init__(self, output, max_width, newline)
324 330 self.verbose = verbose
325 331 self.stack = []
326 332 if singleton_pprinters is None:
327 333 singleton_pprinters = _singleton_pprinters.copy()
328 334 self.singleton_pprinters = singleton_pprinters
329 335 if type_pprinters is None:
330 336 type_pprinters = _type_pprinters.copy()
331 337 self.type_pprinters = type_pprinters
332 338 if deferred_pprinters is None:
333 339 deferred_pprinters = _deferred_type_pprinters.copy()
334 340 self.deferred_pprinters = deferred_pprinters
335 341
336 342 def pretty(self, obj):
337 343 """Pretty print the given object."""
338 344 obj_id = id(obj)
339 345 cycle = obj_id in self.stack
340 346 self.stack.append(obj_id)
341 347 self.begin_group()
342 348 try:
343 349 obj_class = getattr(obj, '__class__', None) or type(obj)
344 350 # First try to find registered singleton printers for the type.
345 351 try:
346 352 printer = self.singleton_pprinters[obj_id]
347 353 except (TypeError, KeyError):
348 354 pass
349 355 else:
350 356 return printer(obj, self, cycle)
351 357 # Next walk the mro and check for either:
352 358 # 1) a registered printer
353 359 # 2) a _repr_pretty_ method
354 360 for cls in _get_mro(obj_class):
355 361 if cls in self.type_pprinters:
356 362 # printer registered in self.type_pprinters
357 363 return self.type_pprinters[cls](obj, self, cycle)
358 364 else:
359 365 # deferred printer
360 366 printer = self._in_deferred_types(cls)
361 367 if printer is not None:
362 368 return printer(obj, self, cycle)
363 369 else:
364 370 # Finally look for special method names.
365 371 # Some objects automatically create any requested
366 372 # attribute. Try to ignore most of them by checking for
367 373 # callability.
368 374 if '_repr_pretty_' in cls.__dict__:
369 375 meth = cls._repr_pretty_
370 376 if callable(meth):
371 377 return meth(obj, self, cycle)
372 378 return _default_pprint(obj, self, cycle)
373 379 finally:
374 380 self.end_group()
375 381 self.stack.pop()
376 382
377 383 def _in_deferred_types(self, cls):
378 384 """
379 385 Check if the given class is specified in the deferred type registry.
380 386
381 387 Returns the printer from the registry if it exists, and None if the
382 388 class is not in the registry. Successful matches will be moved to the
383 389 regular type registry for future use.
384 390 """
385 391 mod = getattr(cls, '__module__', None)
386 392 name = getattr(cls, '__name__', None)
387 393 key = (mod, name)
388 394 printer = None
389 395 if key in self.deferred_pprinters:
390 396 # Move the printer over to the regular registry.
391 397 printer = self.deferred_pprinters.pop(key)
392 398 self.type_pprinters[cls] = printer
393 399 return printer
394 400
395 401
396 402 class Printable(object):
397 403
398 404 def output(self, stream, output_width):
399 405 return output_width
400 406
401 407
402 408 class Text(Printable):
403 409
404 410 def __init__(self):
405 411 self.objs = []
406 412 self.width = 0
407 413
408 414 def output(self, stream, output_width):
409 415 for obj in self.objs:
410 416 stream.write(obj)
411 417 return output_width + self.width
412 418
413 419 def add(self, obj, width):
414 420 self.objs.append(obj)
415 421 self.width += width
416 422
417 423
418 424 class Breakable(Printable):
419 425
420 426 def __init__(self, seq, width, pretty):
421 427 self.obj = seq
422 428 self.width = width
423 429 self.pretty = pretty
424 430 self.indentation = pretty.indentation
425 431 self.group = pretty.group_stack[-1]
426 432 self.group.breakables.append(self)
427 433
428 434 def output(self, stream, output_width):
429 435 self.group.breakables.popleft()
430 436 if self.group.want_break:
431 437 stream.write(self.pretty.newline)
432 438 stream.write(' ' * self.indentation)
433 439 return self.indentation
434 440 if not self.group.breakables:
435 441 self.pretty.group_queue.remove(self.group)
436 442 stream.write(self.obj)
437 443 return output_width + self.width
438 444
439 445
440 446 class Group(Printable):
441 447
442 448 def __init__(self, depth):
443 449 self.depth = depth
444 450 self.breakables = deque()
445 451 self.want_break = False
446 452
447 453
448 454 class GroupQueue(object):
449 455
450 456 def __init__(self, *groups):
451 457 self.queue = []
452 458 for group in groups:
453 459 self.enq(group)
454 460
455 461 def enq(self, group):
456 462 depth = group.depth
457 463 while depth > len(self.queue) - 1:
458 464 self.queue.append([])
459 465 self.queue[depth].append(group)
460 466
461 467 def deq(self):
462 468 for stack in self.queue:
463 469 for idx, group in enumerate(reversed(stack)):
464 470 if group.breakables:
465 471 del stack[idx]
466 472 group.want_break = True
467 473 return group
468 474 for group in stack:
469 475 group.want_break = True
470 476 del stack[:]
471 477
472 478 def remove(self, group):
473 479 try:
474 480 self.queue[group.depth].remove(group)
475 481 except ValueError:
476 482 pass
477 483
478 484 try:
479 485 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
480 486 except AttributeError: # Python 3
481 487 _baseclass_reprs = (object.__repr__,)
482 488
483 489
484 490 def _default_pprint(obj, p, cycle):
485 491 """
486 492 The default print function. Used if an object does not provide one and
487 493 it's none of the builtin objects.
488 494 """
489 495 klass = getattr(obj, '__class__', None) or type(obj)
490 496 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
491 497 # A user-provided repr. Find newlines and replace them with p.break_()
492 498 output = repr(obj)
493 499 for idx,output_line in enumerate(output.splitlines()):
494 500 if idx:
495 501 p.break_()
496 502 p.text(output_line)
497 503 return
498 504 p.begin_group(1, '<')
499 505 p.pretty(klass)
500 506 p.text(' at 0x%x' % id(obj))
501 507 if cycle:
502 508 p.text(' ...')
503 509 elif p.verbose:
504 510 first = True
505 511 for key in dir(obj):
506 512 if not key.startswith('_'):
507 513 try:
508 514 value = getattr(obj, key)
509 515 except AttributeError:
510 516 continue
511 517 if isinstance(value, types.MethodType):
512 518 continue
513 519 if not first:
514 520 p.text(',')
515 521 p.breakable()
516 522 p.text(key)
517 523 p.text('=')
518 524 step = len(key) + 1
519 525 p.indentation += step
520 526 p.pretty(value)
521 527 p.indentation -= step
522 528 first = False
523 529 p.end_group(1, '>')
524 530
525 531
526 532 def _seq_pprinter_factory(start, end, basetype):
527 533 """
528 534 Factory that returns a pprint function useful for sequences. Used by
529 535 the default pprint for tuples, dicts, and lists.
530 536 """
531 537 def inner(obj, p, cycle):
532 538 typ = type(obj)
533 539 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
534 540 # If the subclass provides its own repr, use it instead.
535 541 return p.text(typ.__repr__(obj))
536 542
537 543 if cycle:
538 544 return p.text(start + '...' + end)
539 545 step = len(start)
540 546 p.begin_group(step, start)
541 547 for idx, x in enumerate(obj):
542 548 if idx:
543 549 p.text(',')
544 550 p.breakable()
545 551 p.pretty(x)
546 552 if len(obj) == 1 and type(obj) is tuple:
547 553 # Special case for 1-item tuples.
548 554 p.text(',')
549 555 p.end_group(step, end)
550 556 return inner
551 557
552 558
553 559 def _set_pprinter_factory(start, end, basetype):
554 560 """
555 561 Factory that returns a pprint function useful for sets and frozensets.
556 562 """
557 563 def inner(obj, p, cycle):
558 564 typ = type(obj)
559 565 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
560 566 # If the subclass provides its own repr, use it instead.
561 567 return p.text(typ.__repr__(obj))
562 568
563 569 if cycle:
564 570 return p.text(start + '...' + end)
565 571 if len(obj) == 0:
566 572 # Special case.
567 573 p.text(basetype.__name__ + '()')
568 574 else:
569 575 step = len(start)
570 576 p.begin_group(step, start)
571 577 # Like dictionary keys, we will try to sort the items.
572 578 items = list(obj)
573 579 try:
574 580 items.sort()
575 581 except Exception:
576 582 # Sometimes the items don't sort.
577 583 pass
578 584 for idx, x in enumerate(items):
579 585 if idx:
580 586 p.text(',')
581 587 p.breakable()
582 588 p.pretty(x)
583 589 p.end_group(step, end)
584 590 return inner
585 591
586 592
587 593 def _dict_pprinter_factory(start, end, basetype=None):
588 594 """
589 595 Factory that returns a pprint function used by the default pprint of
590 596 dicts and dict proxies.
591 597 """
592 598 def inner(obj, p, cycle):
593 599 typ = type(obj)
594 600 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
595 601 # If the subclass provides its own repr, use it instead.
596 602 return p.text(typ.__repr__(obj))
597 603
598 604 if cycle:
599 605 return p.text('{...}')
600 606 p.begin_group(1, start)
601 607 keys = obj.keys()
602 608 try:
603 609 keys.sort()
604 610 except Exception as e:
605 611 # Sometimes the keys don't sort.
606 612 pass
607 613 for idx, key in enumerate(keys):
608 614 if idx:
609 615 p.text(',')
610 616 p.breakable()
611 617 p.pretty(key)
612 618 p.text(': ')
613 619 p.pretty(obj[key])
614 620 p.end_group(1, end)
615 621 return inner
616 622
617 623
618 624 def _super_pprint(obj, p, cycle):
619 625 """The pprint for the super type."""
620 626 p.begin_group(8, '<super: ')
621 627 p.pretty(obj.__self_class__)
622 628 p.text(',')
623 629 p.breakable()
624 630 p.pretty(obj.__self__)
625 631 p.end_group(8, '>')
626 632
627 633
628 634 def _re_pattern_pprint(obj, p, cycle):
629 635 """The pprint function for regular expression patterns."""
630 636 p.text('re.compile(')
631 637 pattern = repr(obj.pattern)
632 638 if pattern[:1] in 'uU':
633 639 pattern = pattern[1:]
634 640 prefix = 'ur'
635 641 else:
636 642 prefix = 'r'
637 643 pattern = prefix + pattern.replace('\\\\', '\\')
638 644 p.text(pattern)
639 645 if obj.flags:
640 646 p.text(',')
641 647 p.breakable()
642 648 done_one = False
643 649 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
644 650 'UNICODE', 'VERBOSE', 'DEBUG'):
645 651 if obj.flags & getattr(re, flag):
646 652 if done_one:
647 653 p.text('|')
648 654 p.text('re.' + flag)
649 655 done_one = True
650 656 p.text(')')
651 657
652 658
653 659 def _type_pprint(obj, p, cycle):
654 660 """The pprint for classes and types."""
655 661 mod = getattr(obj, '__module__', None)
656 662 if mod is None:
657 663 # Heap allocated types might not have the module attribute,
658 664 # and others may set it to None.
659 665 return p.text(obj.__name__)
660 666
661 667 if mod in ('__builtin__', 'builtins', 'exceptions'):
662 668 name = obj.__name__
663 669 else:
664 670 name = mod + '.' + obj.__name__
665 671 p.text(name)
666 672
667 673
668 674 def _repr_pprint(obj, p, cycle):
669 675 """A pprint that just redirects to the normal repr function."""
670 676 p.text(repr(obj))
671 677
672 678
673 679 def _function_pprint(obj, p, cycle):
674 680 """Base pprint for all functions and builtin functions."""
675 681 if obj.__module__ in ('__builtin__', 'builtins', 'exceptions') or not obj.__module__:
676 682 name = obj.__name__
677 683 else:
678 684 name = obj.__module__ + '.' + obj.__name__
679 685 p.text('<function %s>' % name)
680 686
681 687
682 688 def _exception_pprint(obj, p, cycle):
683 689 """Base pprint for all exceptions."""
684 690 if obj.__class__.__module__ in ('exceptions', 'builtins'):
685 691 name = obj.__class__.__name__
686 692 else:
687 693 name = '%s.%s' % (
688 694 obj.__class__.__module__,
689 695 obj.__class__.__name__
690 696 )
691 697 step = len(name) + 1
692 698 p.begin_group(step, name + '(')
693 699 for idx, arg in enumerate(getattr(obj, 'args', ())):
694 700 if idx:
695 701 p.text(',')
696 702 p.breakable()
697 703 p.pretty(arg)
698 704 p.end_group(step, ')')
699 705
700 706
701 707 #: the exception base
702 708 try:
703 709 _exception_base = BaseException
704 710 except NameError:
705 711 _exception_base = Exception
706 712
707 713
708 714 #: printers for builtin types
709 715 _type_pprinters = {
710 716 int: _repr_pprint,
711 717 float: _repr_pprint,
712 718 str: _repr_pprint,
713 719 tuple: _seq_pprinter_factory('(', ')', tuple),
714 720 list: _seq_pprinter_factory('[', ']', list),
715 721 dict: _dict_pprinter_factory('{', '}', dict),
716 722
717 723 set: _set_pprinter_factory('{', '}', set),
718 724 frozenset: _set_pprinter_factory('frozenset({', '})', frozenset),
719 725 super: _super_pprint,
720 726 _re_pattern_type: _re_pattern_pprint,
721 727 type: _type_pprint,
722 728 types.FunctionType: _function_pprint,
723 729 types.BuiltinFunctionType: _function_pprint,
724 730 types.MethodType: _repr_pprint,
725 731
726 732 datetime.datetime: _repr_pprint,
727 733 datetime.timedelta: _repr_pprint,
728 734 _exception_base: _exception_pprint
729 735 }
730 736
731 737 try:
732 738 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
733 739 _type_pprinters[types.ClassType] = _type_pprint
734 740 _type_pprinters[types.SliceType] = _repr_pprint
735 741 except AttributeError: # Python 3
736 742 _type_pprinters[slice] = _repr_pprint
737 743
738 744 try:
739 745 _type_pprinters[xrange] = _repr_pprint
740 746 _type_pprinters[long] = _repr_pprint
741 747 _type_pprinters[unicode] = _repr_pprint
742 748 except NameError:
743 749 _type_pprinters[range] = _repr_pprint
744 750 _type_pprinters[bytes] = _repr_pprint
745 751
746 752 #: printers for types specified by name
747 753 _deferred_type_pprinters = {
748 754 }
749 755
750 756 def for_type(typ, func):
751 757 """
752 758 Add a pretty printer for a given type.
753 759 """
754 760 oldfunc = _type_pprinters.get(typ, None)
755 761 if func is not None:
756 762 # To support easy restoration of old pprinters, we need to ignore Nones.
757 763 _type_pprinters[typ] = func
758 764 return oldfunc
759 765
760 766 def for_type_by_name(type_module, type_name, func):
761 767 """
762 768 Add a pretty printer for a type specified by the module and name of a type
763 769 rather than the type object itself.
764 770 """
765 771 key = (type_module, type_name)
766 772 oldfunc = _deferred_type_pprinters.get(key, None)
767 773 if func is not None:
768 774 # To support easy restoration of old pprinters, we need to ignore Nones.
769 775 _deferred_type_pprinters[key] = func
770 776 return oldfunc
771 777
772 778
773 779 #: printers for the default singletons
774 780 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
775 781 NotImplemented]), _repr_pprint)
776 782
777 783
778 784 if __name__ == '__main__':
779 785 from random import randrange
780 786 class Foo(object):
781 787 def __init__(self):
782 788 self.foo = 1
783 789 self.bar = re.compile(r'\s+')
784 790 self.blub = dict.fromkeys(range(30), randrange(1, 40))
785 791 self.hehe = 23424.234234
786 792 self.list = ["blub", "blah", self]
787 793
788 794 def get_foo(self):
789 795 print("foo")
790 796
791 797 pprint(Foo(), verbose=True)
@@ -1,180 +1,184 b''
1 1 """Test suite for the irunner module.
2 2
3 3 Not the most elegant or fine-grained, but it does cover at least the bulk
4 4 functionality."""
5 5 from __future__ import print_function
6 6
7 7 # Global to make tests extra verbose and help debugging
8 8 VERBOSE = True
9 9
10 10 # stdlib imports
11 import io
12 11 import sys
13 12 import unittest
14 13
15 14 # IPython imports
16 15 from IPython.lib import irunner
17 from IPython.utils.py3compat import doctest_refactor_print
16 from IPython.utils.py3compat import doctest_refactor_print, PY3
17
18 if PY3:
19 from io import StringIO
20 else:
21 from StringIO import StringIO
18 22
19 23 # Testing code begins
20 24 class RunnerTestCase(unittest.TestCase):
21 25
22 26 def setUp(self):
23 self.out = io.StringIO()
27 self.out = StringIO()
24 28 #self.out = sys.stdout
25 29
26 30 def _test_runner(self,runner,source,output):
27 31 """Test that a given runner's input/output match."""
28 32
29 33 runner.run_source(source)
30 34 out = self.out.getvalue()
31 35 #out = ''
32 36 # this output contains nasty \r\n lineends, and the initial ipython
33 37 # banner. clean it up for comparison, removing lines of whitespace
34 38 output_l = [l for l in output.splitlines() if l and not l.isspace()]
35 39 out_l = [l for l in out.splitlines() if l and not l.isspace()]
36 40 mismatch = 0
37 41 if len(output_l) != len(out_l):
38 42 message = ("Mismatch in number of lines\n\n"
39 43 "Expected:\n"
40 44 "~~~~~~~~~\n"
41 45 "%s\n\n"
42 46 "Got:\n"
43 47 "~~~~~~~~~\n"
44 48 "%s"
45 49 ) % ("\n".join(output_l), "\n".join(out_l))
46 50 self.fail(message)
47 51 for n in range(len(output_l)):
48 52 # Do a line-by-line comparison
49 53 ol1 = output_l[n].strip()
50 54 ol2 = out_l[n].strip()
51 55 if ol1 != ol2:
52 56 mismatch += 1
53 57 if VERBOSE:
54 58 print('<<< line %s does not match:' % n)
55 59 print(repr(ol1))
56 60 print(repr(ol2))
57 61 print('>>>')
58 62 self.assertTrue(mismatch==0,'Number of mismatched lines: %s' %
59 63 mismatch)
60 64
61 65 def testIPython(self):
62 66 """Test the IPython runner."""
63 67 source = doctest_refactor_print("""
64 68 print 'hello, this is python'
65 69 # some more code
66 70 x=1;y=2
67 71 x+y**2
68 72
69 73 # An example of autocall functionality
70 74 from math import *
71 75 autocall 1
72 76 cos pi
73 77 autocall 0
74 78 cos pi
75 79 cos(pi)
76 80
77 81 for i in range(5):
78 82 print i
79 83
80 84 print "that's all folks!"
81 85
82 86 exit
83 87 """)
84 88 output = doctest_refactor_print("""\
85 89 In [1]: print 'hello, this is python'
86 90 hello, this is python
87 91
88 92
89 93 # some more code
90 94 In [2]: x=1;y=2
91 95
92 96 In [3]: x+y**2
93 97 Out[3]: 5
94 98
95 99
96 100 # An example of autocall functionality
97 101 In [4]: from math import *
98 102
99 103 In [5]: autocall 1
100 104 Automatic calling is: Smart
101 105
102 106 In [6]: cos pi
103 107 ------> cos(pi)
104 108 Out[6]: -1.0
105 109
106 110 In [7]: autocall 0
107 111 Automatic calling is: OFF
108 112
109 113 In [8]: cos pi
110 114 File "<ipython-input-8-6bd7313dd9a9>", line 1
111 115 cos pi
112 116 ^
113 117 SyntaxError: invalid syntax
114 118
115 119
116 120 In [9]: cos(pi)
117 121 Out[9]: -1.0
118 122
119 123
120 124 In [10]: for i in range(5):
121 125 ....: print i
122 126 ....:
123 127 0
124 128 1
125 129 2
126 130 3
127 131 4
128 132
129 133 In [11]: print "that's all folks!"
130 134 that's all folks!
131 135
132 136
133 137 In [12]: exit
134 138 """)
135 139 runner = irunner.IPythonRunner(out=self.out)
136 140 self._test_runner(runner,source,output)
137 141
138 142 def testPython(self):
139 143 """Test the Python runner."""
140 144 runner = irunner.PythonRunner(out=self.out, args=['-E'])
141 145 source = doctest_refactor_print("""
142 146 print 'hello, this is python'
143 147
144 148 # some more code
145 149 x=1;y=2
146 150 x+y**2
147 151
148 152 from math import *
149 153 cos(pi)
150 154
151 155 for i in range(5):
152 156 print i
153 157
154 158 print "that's all folks!"
155 159 """)
156 160 output = doctest_refactor_print("""\
157 161 >>> print 'hello, this is python'
158 162 hello, this is python
159 163
160 164 # some more code
161 165 >>> x=1;y=2
162 166 >>> x+y**2
163 167 5
164 168
165 169 >>> from math import *
166 170 >>> cos(pi)
167 171 -1.0
168 172
169 173 >>> for i in range(5):
170 174 ... print i
171 175 ...
172 176 0
173 177 1
174 178 2
175 179 3
176 180 4
177 181 >>> print "that's all folks!"
178 182 that's all folks!
179 183 """)
180 184 self._test_runner(runner,source,output)
@@ -1,121 +1,126 b''
1 1 """Test suite for pylab_import_all magic
2 2 Modified from the irunner module but using regex.
3 3 """
4 4 from __future__ import print_function
5 5
6 6 # Global to make tests extra verbose and help debugging
7 7 VERBOSE = True
8 8
9 9 # stdlib imports
10 import io
11 10 import sys
12 11 import unittest
13 12 import re
14 13
15 14 # IPython imports
16 15 from IPython.lib import irunner
17 16 from IPython.testing import decorators
17 from IPython.utils.py3compat import PY3
18
19 if PY3:
20 from io import StringIO
21 else:
22 from StringIO import StringIO
18 23
19 24 def pylab_not_importable():
20 25 """Test if importing pylab fails. (For example, when having no display)"""
21 26 try:
22 27 import pylab
23 28 return False
24 29 except:
25 30 return True
26 31
27 32 # Testing code begins
28 33 class RunnerTestCase(unittest.TestCase):
29 34
30 35 def setUp(self):
31 self.out = io.StringIO()
36 self.out = StringIO()
32 37 #self.out = sys.stdout
33 38
34 39 def _test_runner(self,runner,source,output):
35 40 """Test that a given runner's input/output match."""
36 41
37 42 runner.run_source(source)
38 43 out = self.out.getvalue()
39 44 #out = ''
40 45 # this output contains nasty \r\n lineends, and the initial ipython
41 46 # banner. clean it up for comparison, removing lines of whitespace
42 47 output_l = [l for l in output.splitlines() if l and not l.isspace()]
43 48 out_l = [l for l in out.splitlines() if l and not l.isspace()]
44 49 mismatch = 0
45 50 if len(output_l) != len(out_l):
46 51 message = ("Mismatch in number of lines\n\n"
47 52 "Expected:\n"
48 53 "~~~~~~~~~\n"
49 54 "%s\n\n"
50 55 "Got:\n"
51 56 "~~~~~~~~~\n"
52 57 "%s"
53 58 ) % ("\n".join(output_l), "\n".join(out_l))
54 59 self.fail(message)
55 60 for n in range(len(output_l)):
56 61 # Do a line-by-line comparison
57 62 ol1 = output_l[n].strip()
58 63 ol2 = out_l[n].strip()
59 64 if not re.match(ol1,ol2):
60 65 mismatch += 1
61 66 if VERBOSE:
62 67 print('<<< line %s does not match:' % n)
63 68 print(repr(ol1))
64 69 print(repr(ol2))
65 70 print('>>>')
66 71 self.assertTrue(mismatch==0,'Number of mismatched lines: %s' %
67 72 mismatch)
68 73
69 74 @decorators.skip_if_no_x11
70 75 @decorators.skipif_not_matplotlib
71 76 @decorators.skipif(pylab_not_importable, "Likely a run without X.")
72 77 def test_pylab_import_all_enabled(self):
73 78 "Verify that plot is available when pylab_import_all = True"
74 79 source = """
75 80 from IPython.config.application import Application
76 81 app = Application.instance()
77 82 app.pylab_import_all = True
78 83 pylab
79 84 ip=get_ipython()
80 85 'plot' in ip.user_ns
81 86 """
82 87 output = """
83 88 In \[1\]: from IPython\.config\.application import Application
84 89 In \[2\]: app = Application\.instance\(\)
85 90 In \[3\]: app\.pylab_import_all = True
86 91 In \[4\]: pylab
87 92 ^Using matplotlib backend:
88 93 Populating the interactive namespace from numpy and matplotlib
89 94 In \[5\]: ip=get_ipython\(\)
90 95 In \[6\]: \'plot\' in ip\.user_ns
91 96 Out\[6\]: True
92 97 """
93 98 runner = irunner.IPythonRunner(out=self.out)
94 99 self._test_runner(runner,source,output)
95 100
96 101 @decorators.skip_if_no_x11
97 102 @decorators.skipif_not_matplotlib
98 103 @decorators.skipif(pylab_not_importable, "Likely a run without X.")
99 104 def test_pylab_import_all_disabled(self):
100 105 "Verify that plot is not available when pylab_import_all = False"
101 106 source = """
102 107 from IPython.config.application import Application
103 108 app = Application.instance()
104 109 app.pylab_import_all = False
105 110 pylab
106 111 ip=get_ipython()
107 112 'plot' in ip.user_ns
108 113 """
109 114 output = """
110 115 In \[1\]: from IPython\.config\.application import Application
111 116 In \[2\]: app = Application\.instance\(\)
112 117 In \[3\]: app\.pylab_import_all = False
113 118 In \[4\]: pylab
114 119 ^Using matplotlib backend:
115 120 Populating the interactive namespace from numpy and matplotlib
116 121 In \[5\]: ip=get_ipython\(\)
117 122 In \[6\]: \'plot\' in ip\.user_ns
118 123 Out\[6\]: False
119 124 """
120 125 runner = irunner.IPythonRunner(out=self.out)
121 126 self._test_runner(runner,source,output)
@@ -1,51 +1,56 b''
1 1 """
2 2 Module with tests for debug
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 from io import StringIO
19 18
20 19 from ...tests.base import TestsBase
21 20 from ..debug import DebugWriter
21 from IPython.utils.py3compat import PY3
22
23 if PY3:
24 from io import StringIO
25 else:
26 from StringIO import StringIO
22 27
23 28
24 29 #-----------------------------------------------------------------------------
25 30 # Class
26 31 #-----------------------------------------------------------------------------
27 32
28 33 class TestDebug(TestsBase):
29 34 """Contains test functions for debug.py"""
30 35
31 36 def test_output(self):
32 37 """Test debug writer output."""
33 38
34 39 # Capture the stdout. Remember original.
35 40 stdout = sys.stdout
36 41 stream = StringIO()
37 42 sys.stdout = stream
38 43
39 44 # Create stdout writer, get output
40 45 writer = DebugWriter()
41 46 writer.write('aaa', {'outputs': {'bbb': 'ccc'}})
42 47 output = stream.getvalue()
43 48
44 49 # Check output. Make sure resources dictionary is dumped, but nothing
45 50 # else.
46 51 assert 'aaa' not in output
47 52 assert 'bbb' in output
48 53 assert 'ccc' in output
49 54
50 55 # Revert stdout
51 56 sys.stdout = stdout No newline at end of file
@@ -1,159 +1,164 b''
1 1 """
2 2 Module with tests for files
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 18 import os
19 from io import StringIO
20 19
21 20 from ...tests.base import TestsBase
22 21 from ..files import FilesWriter
22 from IPython.utils.py3compat import PY3
23
24 if PY3:
25 from io import StringIO
26 else:
27 from StringIO import StringIO
23 28
24 29
25 30 #-----------------------------------------------------------------------------
26 31 # Class
27 32 #-----------------------------------------------------------------------------
28 33
29 34 class Testfiles(TestsBase):
30 35 """Contains test functions for files.py"""
31 36
32 37 def test_basic_output(self):
33 38 """Is FilesWriter basic output correct?"""
34 39
35 40 # Work in a temporary directory.
36 41 with self.create_temp_cwd():
37 42
38 43 # Create the resoruces dictionary
39 44 res = {}
40 45
41 46 # Create files writer, test output
42 47 writer = FilesWriter()
43 48 writer.write(u'y', res, notebook_name="z")
44 49
45 50 # Check the output of the file
46 51 with open('z', 'r') as f:
47 52 output = f.read()
48 53 self.assertEqual(output, u'y')
49 54
50 55 def test_ext(self):
51 56 """Does the FilesWriter add the correct extension to the output?"""
52 57
53 58 # Work in a temporary directory.
54 59 with self.create_temp_cwd():
55 60
56 61 # Create the resoruces dictionary
57 62 res = {'output_extension': 'txt'}
58 63
59 64 # Create files writer, test output
60 65 writer = FilesWriter()
61 66 writer.write(u'y', res, notebook_name="z")
62 67
63 68 # Check the output of the file
64 69 assert os.path.isfile('z.txt')
65 70 with open('z.txt', 'r') as f:
66 71 output = f.read()
67 72 self.assertEqual(output, u'y')
68 73
69 74
70 75 def test_extract(self):
71 76 """Can FilesWriter write extracted figures correctly?"""
72 77
73 78 # Work in a temporary directory.
74 79 with self.create_temp_cwd():
75 80
76 81 # Create the resoruces dictionary
77 82 res = {'outputs': {os.path.join('z_files', 'a'): b'b'}}
78 83
79 84 # Create files writer, test output
80 85 writer = FilesWriter()
81 86 writer.write(u'y', res, notebook_name="z")
82 87
83 88 # Check the output of the file
84 89 with open('z', 'r') as f:
85 90 output = f.read()
86 91 self.assertEqual(output, u'y')
87 92
88 93 # Check the output of the extracted file
89 94 extracted_file_dest = os.path.join('z_files', 'a')
90 95 assert os.path.isfile(extracted_file_dest)
91 96 with open(extracted_file_dest, 'r') as f:
92 97 output = f.read()
93 98 self.assertEqual(output, 'b')
94 99
95 100
96 101 def test_builddir(self):
97 102 """Can FilesWriter write to a build dir correctly?"""
98 103
99 104 # Work in a temporary directory.
100 105 with self.create_temp_cwd():
101 106
102 107 # Create the resoruces dictionary
103 108 res = {'outputs': {os.path.join('z_files', 'a'): b'b'}}
104 109
105 110 # Create files writer, test output
106 111 writer = FilesWriter()
107 112 writer.build_directory = u'build'
108 113 writer.write(u'y', res, notebook_name="z")
109 114
110 115 # Check the output of the file
111 116 assert os.path.isdir(writer.build_directory)
112 117 dest = os.path.join(writer.build_directory, 'z')
113 118 with open(dest, 'r') as f:
114 119 output = f.read()
115 120 self.assertEqual(output, u'y')
116 121
117 122 # Check the output of the extracted file
118 123 extracted_file_dest = os.path.join(writer.build_directory, 'z_files', 'a')
119 124 assert os.path.isfile(extracted_file_dest)
120 125 with open(extracted_file_dest, 'r') as f:
121 126 output = f.read()
122 127 self.assertEqual(output, 'b')
123 128
124 129
125 130 def test_links(self):
126 131 """Can the FilesWriter handle linked files correctly?"""
127 132
128 133 # Work in a temporary directory.
129 134 with self.create_temp_cwd():
130 135
131 136 # Create test file
132 137 os.mkdir('sub')
133 138 with open(os.path.join('sub', 'c'), 'w') as f:
134 139 f.write('d')
135 140
136 141 # Create the resoruces dictionary
137 142 res = {}
138 143
139 144 # Create files writer, test output
140 145 writer = FilesWriter()
141 146 writer.files = [os.path.join('sub', 'c')]
142 147 writer.build_directory = u'build'
143 148 writer.write(u'y', res, notebook_name="z")
144 149
145 150 # Check the output of the file
146 151 assert os.path.isdir(writer.build_directory)
147 152 dest = os.path.join(writer.build_directory, 'z')
148 153 with open(dest, 'r') as f:
149 154 output = f.read()
150 155 self.assertEqual(output, u'y')
151 156
152 157 # Check to make sure the linked file was copied
153 158 path = os.path.join(writer.build_directory, 'sub')
154 159 assert os.path.isdir(path)
155 160 dest = os.path.join(path, 'c')
156 161 assert os.path.isfile(dest)
157 162 with open(dest, 'r') as f:
158 163 output = f.read()
159 164 self.assertEqual(output, 'd')
@@ -1,46 +1,51 b''
1 1 """
2 2 Module with tests for stdout
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 from io import StringIO
19 18
20 19 from ...tests.base import TestsBase
21 20 from ..stdout import StdoutWriter
21 from IPython.utils.py3compat import PY3
22
23 if PY3:
24 from io import StringIO
25 else:
26 from StringIO import StringIO
22 27
23 28
24 29 #-----------------------------------------------------------------------------
25 30 # Class
26 31 #-----------------------------------------------------------------------------
27 32
28 33 class TestStdout(TestsBase):
29 34 """Contains test functions for stdout.py"""
30 35
31 36 def test_output(self):
32 37 """Test stdout writer output."""
33 38
34 39 # Capture the stdout. Remember original.
35 40 stdout = sys.stdout
36 41 stream = StringIO()
37 42 sys.stdout = stream
38 43
39 44 # Create stdout writer, test output
40 45 writer = StdoutWriter()
41 46 writer.write('a', {'b': 'c'})
42 47 output = stream.getvalue()
43 48 self.fuzzy_compare(output, 'a')
44 49
45 50 # Revert stdout
46 51 sys.stdout = stdout No newline at end of file
@@ -1,193 +1,192 b''
1 1 """base class for parallel client tests
2 2
3 3 Authors:
4 4
5 5 * Min RK
6 6 """
7 7
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 import sys
17 17 import tempfile
18 18 import time
19 from io import StringIO
20 19
21 20 from nose import SkipTest
22 21
23 22 import zmq
24 23 from zmq.tests import BaseZMQTestCase
25 24
26 25 from IPython.external.decorator import decorator
27 26
28 27 from IPython.parallel import error
29 28 from IPython.parallel import Client
30 29
31 30 from IPython.parallel.tests import launchers, add_engines
32 31
33 32 # simple tasks for use in apply tests
34 33
35 34 def segfault():
36 35 """this will segfault"""
37 36 import ctypes
38 37 ctypes.memset(-1,0,1)
39 38
40 39 def crash():
41 40 """from stdlib crashers in the test suite"""
42 41 import types
43 42 if sys.platform.startswith('win'):
44 43 import ctypes
45 44 ctypes.windll.kernel32.SetErrorMode(0x0002);
46 45 args = [ 0, 0, 0, 0, b'\x04\x71\x00\x00', (), (), (), '', '', 1, b'']
47 46 if sys.version_info[0] >= 3:
48 47 # Python3 adds 'kwonlyargcount' as the second argument to Code
49 48 args.insert(1, 0)
50 49
51 50 co = types.CodeType(*args)
52 51 exec(co)
53 52
54 53 def wait(n):
55 54 """sleep for a time"""
56 55 import time
57 56 time.sleep(n)
58 57 return n
59 58
60 59 def raiser(eclass):
61 60 """raise an exception"""
62 61 raise eclass()
63 62
64 63 def generate_output():
65 64 """function for testing output
66 65
67 66 publishes two outputs of each type, and returns
68 67 a rich displayable object.
69 68 """
70 69
71 70 import sys
72 71 from IPython.core.display import display, HTML, Math
73 72
74 73 print("stdout")
75 74 print("stderr", file=sys.stderr)
76 75
77 76 display(HTML("<b>HTML</b>"))
78 77
79 78 print("stdout2")
80 79 print("stderr2", file=sys.stderr)
81 80
82 81 display(Math(r"\alpha=\beta"))
83 82
84 83 return Math("42")
85 84
86 85 # test decorator for skipping tests when libraries are unavailable
87 86 def skip_without(*names):
88 87 """skip a test if some names are not importable"""
89 88 @decorator
90 89 def skip_without_names(f, *args, **kwargs):
91 90 """decorator to skip tests in the absence of numpy."""
92 91 for name in names:
93 92 try:
94 93 __import__(name)
95 94 except ImportError:
96 95 raise SkipTest
97 96 return f(*args, **kwargs)
98 97 return skip_without_names
99 98
100 99 #-------------------------------------------------------------------------------
101 100 # Classes
102 101 #-------------------------------------------------------------------------------
103 102
104 103
105 104 class ClusterTestCase(BaseZMQTestCase):
106 105 timeout = 10
107 106
108 107 def add_engines(self, n=1, block=True):
109 108 """add multiple engines to our cluster"""
110 109 self.engines.extend(add_engines(n))
111 110 if block:
112 111 self.wait_on_engines()
113 112
114 113 def minimum_engines(self, n=1, block=True):
115 114 """add engines until there are at least n connected"""
116 115 self.engines.extend(add_engines(n, total=True))
117 116 if block:
118 117 self.wait_on_engines()
119 118
120 119
121 120 def wait_on_engines(self, timeout=5):
122 121 """wait for our engines to connect."""
123 122 n = len(self.engines)+self.base_engine_count
124 123 tic = time.time()
125 124 while time.time()-tic < timeout and len(self.client.ids) < n:
126 125 time.sleep(0.1)
127 126
128 127 assert not len(self.client.ids) < n, "waiting for engines timed out"
129 128
130 129 def client_wait(self, client, jobs=None, timeout=-1):
131 130 """my wait wrapper, sets a default finite timeout to avoid hangs"""
132 131 if timeout < 0:
133 132 timeout = self.timeout
134 133 return Client.wait(client, jobs, timeout)
135 134
136 135 def connect_client(self):
137 136 """connect a client with my Context, and track its sockets for cleanup"""
138 137 c = Client(profile='iptest', context=self.context)
139 138 c.wait = lambda *a, **kw: self.client_wait(c, *a, **kw)
140 139
141 140 for name in filter(lambda n:n.endswith('socket'), dir(c)):
142 141 s = getattr(c, name)
143 142 s.setsockopt(zmq.LINGER, 0)
144 143 self.sockets.append(s)
145 144 return c
146 145
147 146 def assertRaisesRemote(self, etype, f, *args, **kwargs):
148 147 try:
149 148 try:
150 149 f(*args, **kwargs)
151 150 except error.CompositeError as e:
152 151 e.raise_exception()
153 152 except error.RemoteError as e:
154 153 self.assertEqual(etype.__name__, e.ename, "Should have raised %r, but raised %r"%(etype.__name__, e.ename))
155 154 else:
156 155 self.fail("should have raised a RemoteError")
157 156
158 157 def _wait_for(self, f, timeout=10):
159 158 """wait for a condition"""
160 159 tic = time.time()
161 160 while time.time() <= tic + timeout:
162 161 if f():
163 162 return
164 163 time.sleep(0.1)
165 164 self.client.spin()
166 165 if not f():
167 166 print("Warning: Awaited condition never arrived")
168 167
169 168 def setUp(self):
170 169 BaseZMQTestCase.setUp(self)
171 170 self.client = self.connect_client()
172 171 # start every test with clean engine namespaces:
173 172 self.client.clear(block=True)
174 173 self.base_engine_count=len(self.client.ids)
175 174 self.engines=[]
176 175
177 176 def tearDown(self):
178 177 # self.client.clear(block=True)
179 178 # close fds:
180 179 for e in filter(lambda e: e.poll() is not None, launchers):
181 180 launchers.remove(e)
182 181
183 182 # allow flushing of incoming messages to prevent crash on socket close
184 183 self.client.wait(timeout=2)
185 184 # time.sleep(2)
186 185 self.client.spin()
187 186 self.client.close()
188 187 BaseZMQTestCase.tearDown(self)
189 188 # this will be redundant when pyzmq merges PR #88
190 189 # self.context.term()
191 190 # print tempfile.TemporaryFile().fileno(),
192 191 # sys.stdout.flush()
193 192
@@ -1,830 +1,835 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Sphinx directive to support embedded IPython code.
3 3
4 4 This directive allows pasting of entire interactive IPython sessions, prompts
5 5 and all, and their code will actually get re-executed at doc build time, with
6 6 all prompts renumbered sequentially. It also allows you to input code as a pure
7 7 python input by giving the argument python to the directive. The output looks
8 8 like an interactive ipython section.
9 9
10 10 To enable this directive, simply list it in your Sphinx ``conf.py`` file
11 11 (making sure the directory where you placed it is visible to sphinx, as is
12 12 needed for all Sphinx directives).
13 13
14 14 By default this directive assumes that your prompts are unchanged IPython ones,
15 15 but this can be customized. The configurable options that can be placed in
16 16 conf.py are
17 17
18 18 ipython_savefig_dir:
19 19 The directory in which to save the figures. This is relative to the
20 20 Sphinx source directory. The default is `html_static_path`.
21 21 ipython_rgxin:
22 22 The compiled regular expression to denote the start of IPython input
23 23 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
24 24 shouldn't need to change this.
25 25 ipython_rgxout:
26 26 The compiled regular expression to denote the start of IPython output
27 27 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
28 28 shouldn't need to change this.
29 29 ipython_promptin:
30 30 The string to represent the IPython input prompt in the generated ReST.
31 31 The default is 'In [%d]:'. This expects that the line numbers are used
32 32 in the prompt.
33 33 ipython_promptout:
34 34
35 35 The string to represent the IPython prompt in the generated ReST. The
36 36 default is 'Out [%d]:'. This expects that the line numbers are used
37 37 in the prompt.
38 38
39 39 ToDo
40 40 ----
41 41
42 42 - Turn the ad-hoc test() function into a real test suite.
43 43 - Break up ipython-specific functionality from matplotlib stuff into better
44 44 separated code.
45 45
46 46 Authors
47 47 -------
48 48
49 49 - John D Hunter: orignal author.
50 50 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
51 51 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
52 52 - Skipper Seabold, refactoring, cleanups, pure python addition
53 53 """
54 54 from __future__ import print_function
55 55
56 56 #-----------------------------------------------------------------------------
57 57 # Imports
58 58 #-----------------------------------------------------------------------------
59 59
60 60 # Stdlib
61 import io
62 61 import os
63 62 import re
64 63 import sys
65 64 import tempfile
66 65 import ast
67 66
68 67 # To keep compatibility with various python versions
69 68 try:
70 69 from hashlib import md5
71 70 except ImportError:
72 71 from md5 import md5
73 72
74 73 # Third-party
75 74 import matplotlib
76 75 import sphinx
77 76 from docutils.parsers.rst import directives
78 77 from docutils import nodes
79 78 from sphinx.util.compat import Directive
80 79
81 80 matplotlib.use('Agg')
82 81
83 82 # Our own
84 83 from IPython import Config, InteractiveShell
85 84 from IPython.core.profiledir import ProfileDir
86 85 from IPython.utils import io
86 from IPython.utils.py3compat import PY3
87
88 if PY3:
89 from io import StringIO
90 else:
91 from StringIO import StringIO
87 92
88 93 #-----------------------------------------------------------------------------
89 94 # Globals
90 95 #-----------------------------------------------------------------------------
91 96 # for tokenizing blocks
92 97 COMMENT, INPUT, OUTPUT = range(3)
93 98
94 99 #-----------------------------------------------------------------------------
95 100 # Functions and class declarations
96 101 #-----------------------------------------------------------------------------
97 102 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
98 103 """
99 104 part is a string of ipython text, comprised of at most one
100 105 input, one ouput, comments, and blank lines. The block parser
101 106 parses the text into a list of::
102 107
103 108 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
104 109
105 110 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
106 111 data is, depending on the type of token::
107 112
108 113 COMMENT : the comment string
109 114
110 115 INPUT: the (DECORATOR, INPUT_LINE, REST) where
111 116 DECORATOR: the input decorator (or None)
112 117 INPUT_LINE: the input as string (possibly multi-line)
113 118 REST : any stdout generated by the input line (not OUTPUT)
114 119
115 120
116 121 OUTPUT: the output string, possibly multi-line
117 122 """
118 123
119 124 block = []
120 125 lines = part.split('\n')
121 126 N = len(lines)
122 127 i = 0
123 128 decorator = None
124 129 while 1:
125 130
126 131 if i==N:
127 132 # nothing left to parse -- the last line
128 133 break
129 134
130 135 line = lines[i]
131 136 i += 1
132 137 line_stripped = line.strip()
133 138 if line_stripped.startswith('#'):
134 139 block.append((COMMENT, line))
135 140 continue
136 141
137 142 if line_stripped.startswith('@'):
138 143 # we're assuming at most one decorator -- may need to
139 144 # rethink
140 145 decorator = line_stripped
141 146 continue
142 147
143 148 # does this look like an input line?
144 149 matchin = rgxin.match(line)
145 150 if matchin:
146 151 lineno, inputline = int(matchin.group(1)), matchin.group(2)
147 152
148 153 # the ....: continuation string
149 154 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
150 155 Nc = len(continuation)
151 156 # input lines can continue on for more than one line, if
152 157 # we have a '\' line continuation char or a function call
153 158 # echo line 'print'. The input line can only be
154 159 # terminated by the end of the block or an output line, so
155 160 # we parse out the rest of the input line if it is
156 161 # multiline as well as any echo text
157 162
158 163 rest = []
159 164 while i<N:
160 165
161 166 # look ahead; if the next line is blank, or a comment, or
162 167 # an output line, we're done
163 168
164 169 nextline = lines[i]
165 170 matchout = rgxout.match(nextline)
166 171 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
167 172 if matchout or nextline.startswith('#'):
168 173 break
169 174 elif nextline.startswith(continuation):
170 175 inputline += '\n' + nextline[Nc:]
171 176 else:
172 177 rest.append(nextline)
173 178 i+= 1
174 179
175 180 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
176 181 continue
177 182
178 183 # if it looks like an output line grab all the text to the end
179 184 # of the block
180 185 matchout = rgxout.match(line)
181 186 if matchout:
182 187 lineno, output = int(matchout.group(1)), matchout.group(2)
183 188 if i<N-1:
184 189 output = '\n'.join([output] + lines[i:])
185 190
186 191 block.append((OUTPUT, output))
187 192 break
188 193
189 194 return block
190 195
191 196 class EmbeddedSphinxShell(object):
192 197 """An embedded IPython instance to run inside Sphinx"""
193 198
194 199 def __init__(self):
195 200
196 self.cout = io.StringIO()
201 self.cout = StringIO()
197 202
198 203
199 204 # Create config object for IPython
200 205 config = Config()
201 206 config.Global.display_banner = False
202 207 config.Global.exec_lines = ['import numpy as np',
203 208 'from pylab import *'
204 209 ]
205 210 config.InteractiveShell.autocall = False
206 211 config.InteractiveShell.autoindent = False
207 212 config.InteractiveShell.colors = 'NoColor'
208 213
209 214 # create a profile so instance history isn't saved
210 215 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
211 216 profname = 'auto_profile_sphinx_build'
212 217 pdir = os.path.join(tmp_profile_dir,profname)
213 218 profile = ProfileDir.create_profile_dir(pdir)
214 219
215 220 # Create and initialize ipython, but don't start its mainloop
216 221 IP = InteractiveShell.instance(config=config, profile_dir=profile)
217 222 # io.stdout redirect must be done *after* instantiating InteractiveShell
218 223 io.stdout = self.cout
219 224 io.stderr = self.cout
220 225
221 226 # For debugging, so we can see normal output, use this:
222 227 #from IPython.utils.io import Tee
223 228 #io.stdout = Tee(self.cout, channel='stdout') # dbg
224 229 #io.stderr = Tee(self.cout, channel='stderr') # dbg
225 230
226 231 # Store a few parts of IPython we'll need.
227 232 self.IP = IP
228 233 self.user_ns = self.IP.user_ns
229 234 self.user_global_ns = self.IP.user_global_ns
230 235
231 236 self.input = ''
232 237 self.output = ''
233 238
234 239 self.is_verbatim = False
235 240 self.is_doctest = False
236 241 self.is_suppress = False
237 242
238 243 # on the first call to the savefig decorator, we'll import
239 244 # pyplot as plt so we can make a call to the plt.gcf().savefig
240 245 self._pyplot_imported = False
241 246
242 247 def clear_cout(self):
243 248 self.cout.seek(0)
244 249 self.cout.truncate(0)
245 250
246 251 def process_input_line(self, line, store_history=True):
247 252 """process the input, capturing stdout"""
248 253 #print "input='%s'"%self.input
249 254 stdout = sys.stdout
250 255 splitter = self.IP.input_splitter
251 256 try:
252 257 sys.stdout = self.cout
253 258 splitter.push(line)
254 259 more = splitter.push_accepts_more()
255 260 if not more:
256 261 source_raw = splitter.source_raw_reset()[1]
257 262 self.IP.run_cell(source_raw, store_history=store_history)
258 263 finally:
259 264 sys.stdout = stdout
260 265
261 266 def process_image(self, decorator):
262 267 """
263 268 # build out an image directive like
264 269 # .. image:: somefile.png
265 270 # :width 4in
266 271 #
267 272 # from an input like
268 273 # savefig somefile.png width=4in
269 274 """
270 275 savefig_dir = self.savefig_dir
271 276 source_dir = self.source_dir
272 277 saveargs = decorator.split(' ')
273 278 filename = saveargs[1]
274 279 # insert relative path to image file in source
275 280 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
276 281 source_dir)
277 282
278 283 imagerows = ['.. image:: %s'%outfile]
279 284
280 285 for kwarg in saveargs[2:]:
281 286 arg, val = kwarg.split('=')
282 287 arg = arg.strip()
283 288 val = val.strip()
284 289 imagerows.append(' :%s: %s'%(arg, val))
285 290
286 291 image_file = os.path.basename(outfile) # only return file name
287 292 image_directive = '\n'.join(imagerows)
288 293 return image_file, image_directive
289 294
290 295
291 296 # Callbacks for each type of token
292 297 def process_input(self, data, input_prompt, lineno):
293 298 """Process data block for INPUT token."""
294 299 decorator, input, rest = data
295 300 image_file = None
296 301 image_directive = None
297 302 #print 'INPUT:', data # dbg
298 303 is_verbatim = decorator=='@verbatim' or self.is_verbatim
299 304 is_doctest = decorator=='@doctest' or self.is_doctest
300 305 is_suppress = decorator=='@suppress' or self.is_suppress
301 306 is_savefig = decorator is not None and \
302 307 decorator.startswith('@savefig')
303 308
304 309 input_lines = input.split('\n')
305 310 if len(input_lines) > 1:
306 311 if input_lines[-1] != "":
307 312 input_lines.append('') # make sure there's a blank line
308 313 # so splitter buffer gets reset
309 314
310 315 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
311 316 Nc = len(continuation)
312 317
313 318 if is_savefig:
314 319 image_file, image_directive = self.process_image(decorator)
315 320
316 321 ret = []
317 322 is_semicolon = False
318 323
319 324 for i, line in enumerate(input_lines):
320 325 if line.endswith(';'):
321 326 is_semicolon = True
322 327
323 328 if i==0:
324 329 # process the first input line
325 330 if is_verbatim:
326 331 self.process_input_line('')
327 332 self.IP.execution_count += 1 # increment it anyway
328 333 else:
329 334 # only submit the line in non-verbatim mode
330 335 self.process_input_line(line, store_history=True)
331 336 formatted_line = '%s %s'%(input_prompt, line)
332 337 else:
333 338 # process a continuation line
334 339 if not is_verbatim:
335 340 self.process_input_line(line, store_history=True)
336 341
337 342 formatted_line = '%s %s'%(continuation, line)
338 343
339 344 if not is_suppress:
340 345 ret.append(formatted_line)
341 346
342 347 if not is_suppress and len(rest.strip()) and is_verbatim:
343 348 # the "rest" is the standard output of the
344 349 # input, which needs to be added in
345 350 # verbatim mode
346 351 ret.append(rest)
347 352
348 353 self.cout.seek(0)
349 354 output = self.cout.read()
350 355 if not is_suppress and not is_semicolon:
351 356 ret.append(output)
352 357 elif is_semicolon: # get spacing right
353 358 ret.append('')
354 359
355 360 self.cout.truncate(0)
356 361 return (ret, input_lines, output, is_doctest, image_file,
357 362 image_directive)
358 363 #print 'OUTPUT', output # dbg
359 364
360 365 def process_output(self, data, output_prompt,
361 366 input_lines, output, is_doctest, image_file):
362 367 """Process data block for OUTPUT token."""
363 368 if is_doctest:
364 369 submitted = data.strip()
365 370 found = output
366 371 if found is not None:
367 372 found = found.strip()
368 373
369 374 # XXX - fperez: in 0.11, 'output' never comes with the prompt
370 375 # in it, just the actual output text. So I think all this code
371 376 # can be nuked...
372 377
373 378 # the above comment does not appear to be accurate... (minrk)
374 379
375 380 ind = found.find(output_prompt)
376 381 if ind<0:
377 382 e='output prompt="%s" does not match out line=%s' % \
378 383 (output_prompt, found)
379 384 raise RuntimeError(e)
380 385 found = found[len(output_prompt):].strip()
381 386
382 387 if found!=submitted:
383 388 e = ('doctest failure for input_lines="%s" with '
384 389 'found_output="%s" and submitted output="%s"' %
385 390 (input_lines, found, submitted) )
386 391 raise RuntimeError(e)
387 392 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
388 393
389 394 def process_comment(self, data):
390 395 """Process data fPblock for COMMENT token."""
391 396 if not self.is_suppress:
392 397 return [data]
393 398
394 399 def save_image(self, image_file):
395 400 """
396 401 Saves the image file to disk.
397 402 """
398 403 self.ensure_pyplot()
399 404 command = 'plt.gcf().savefig("%s")'%image_file
400 405 #print 'SAVEFIG', command # dbg
401 406 self.process_input_line('bookmark ipy_thisdir', store_history=False)
402 407 self.process_input_line('cd -b ipy_savedir', store_history=False)
403 408 self.process_input_line(command, store_history=False)
404 409 self.process_input_line('cd -b ipy_thisdir', store_history=False)
405 410 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
406 411 self.clear_cout()
407 412
408 413
409 414 def process_block(self, block):
410 415 """
411 416 process block from the block_parser and return a list of processed lines
412 417 """
413 418 ret = []
414 419 output = None
415 420 input_lines = None
416 421 lineno = self.IP.execution_count
417 422
418 423 input_prompt = self.promptin%lineno
419 424 output_prompt = self.promptout%lineno
420 425 image_file = None
421 426 image_directive = None
422 427
423 428 for token, data in block:
424 429 if token==COMMENT:
425 430 out_data = self.process_comment(data)
426 431 elif token==INPUT:
427 432 (out_data, input_lines, output, is_doctest, image_file,
428 433 image_directive) = \
429 434 self.process_input(data, input_prompt, lineno)
430 435 elif token==OUTPUT:
431 436 out_data = \
432 437 self.process_output(data, output_prompt,
433 438 input_lines, output, is_doctest,
434 439 image_file)
435 440 if out_data:
436 441 ret.extend(out_data)
437 442
438 443 # save the image files
439 444 if image_file is not None:
440 445 self.save_image(image_file)
441 446
442 447 return ret, image_directive
443 448
444 449 def ensure_pyplot(self):
445 450 if self._pyplot_imported:
446 451 return
447 452 self.process_input_line('import matplotlib.pyplot as plt',
448 453 store_history=False)
449 454
450 455 def process_pure_python(self, content):
451 456 """
452 457 content is a list of strings. it is unedited directive conent
453 458
454 459 This runs it line by line in the InteractiveShell, prepends
455 460 prompts as needed capturing stderr and stdout, then returns
456 461 the content as a list as if it were ipython code
457 462 """
458 463 output = []
459 464 savefig = False # keep up with this to clear figure
460 465 multiline = False # to handle line continuation
461 466 multiline_start = None
462 467 fmtin = self.promptin
463 468
464 469 ct = 0
465 470
466 471 for lineno, line in enumerate(content):
467 472
468 473 line_stripped = line.strip()
469 474 if not len(line):
470 475 output.append(line)
471 476 continue
472 477
473 478 # handle decorators
474 479 if line_stripped.startswith('@'):
475 480 output.extend([line])
476 481 if 'savefig' in line:
477 482 savefig = True # and need to clear figure
478 483 continue
479 484
480 485 # handle comments
481 486 if line_stripped.startswith('#'):
482 487 output.extend([line])
483 488 continue
484 489
485 490 # deal with lines checking for multiline
486 491 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
487 492 if not multiline:
488 493 modified = u"%s %s" % (fmtin % ct, line_stripped)
489 494 output.append(modified)
490 495 ct += 1
491 496 try:
492 497 ast.parse(line_stripped)
493 498 output.append(u'')
494 499 except Exception: # on a multiline
495 500 multiline = True
496 501 multiline_start = lineno
497 502 else: # still on a multiline
498 503 modified = u'%s %s' % (continuation, line)
499 504 output.append(modified)
500 505
501 506 # if the next line is indented, it should be part of multiline
502 507 if len(content) > lineno + 1:
503 508 nextline = content[lineno + 1]
504 509 if len(nextline) - len(nextline.lstrip()) > 3:
505 510 continue
506 511 try:
507 512 mod = ast.parse(
508 513 '\n'.join(content[multiline_start:lineno+1]))
509 514 if isinstance(mod.body[0], ast.FunctionDef):
510 515 # check to see if we have the whole function
511 516 for element in mod.body[0].body:
512 517 if isinstance(element, ast.Return):
513 518 multiline = False
514 519 else:
515 520 output.append(u'')
516 521 multiline = False
517 522 except Exception:
518 523 pass
519 524
520 525 if savefig: # clear figure if plotted
521 526 self.ensure_pyplot()
522 527 self.process_input_line('plt.clf()', store_history=False)
523 528 self.clear_cout()
524 529 savefig = False
525 530
526 531 return output
527 532
528 533 class IPythonDirective(Directive):
529 534
530 535 has_content = True
531 536 required_arguments = 0
532 537 optional_arguments = 4 # python, suppress, verbatim, doctest
533 538 final_argumuent_whitespace = True
534 539 option_spec = { 'python': directives.unchanged,
535 540 'suppress' : directives.flag,
536 541 'verbatim' : directives.flag,
537 542 'doctest' : directives.flag,
538 543 }
539 544
540 545 shell = None
541 546
542 547 seen_docs = set()
543 548
544 549 def get_config_options(self):
545 550 # contains sphinx configuration variables
546 551 config = self.state.document.settings.env.config
547 552
548 553 # get config variables to set figure output directory
549 554 confdir = self.state.document.settings.env.app.confdir
550 555 savefig_dir = config.ipython_savefig_dir
551 556 source_dir = os.path.dirname(self.state.document.current_source)
552 557 if savefig_dir is None:
553 558 savefig_dir = config.html_static_path
554 559 if isinstance(savefig_dir, list):
555 560 savefig_dir = savefig_dir[0] # safe to assume only one path?
556 561 savefig_dir = os.path.join(confdir, savefig_dir)
557 562
558 563 # get regex and prompt stuff
559 564 rgxin = config.ipython_rgxin
560 565 rgxout = config.ipython_rgxout
561 566 promptin = config.ipython_promptin
562 567 promptout = config.ipython_promptout
563 568
564 569 return savefig_dir, source_dir, rgxin, rgxout, promptin, promptout
565 570
566 571 def setup(self):
567 572 if self.shell is None:
568 573 self.shell = EmbeddedSphinxShell()
569 574 # reset the execution count if we haven't processed this doc
570 575 #NOTE: this may be borked if there are multiple seen_doc tmp files
571 576 #check time stamp?
572 577
573 578 if not self.state.document.current_source in self.seen_docs:
574 579 self.shell.IP.history_manager.reset()
575 580 self.shell.IP.execution_count = 1
576 581 self.seen_docs.add(self.state.document.current_source)
577 582
578 583
579 584
580 585 # get config values
581 586 (savefig_dir, source_dir, rgxin,
582 587 rgxout, promptin, promptout) = self.get_config_options()
583 588
584 589 # and attach to shell so we don't have to pass them around
585 590 self.shell.rgxin = rgxin
586 591 self.shell.rgxout = rgxout
587 592 self.shell.promptin = promptin
588 593 self.shell.promptout = promptout
589 594 self.shell.savefig_dir = savefig_dir
590 595 self.shell.source_dir = source_dir
591 596
592 597 # setup bookmark for saving figures directory
593 598
594 599 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
595 600 store_history=False)
596 601 self.shell.clear_cout()
597 602
598 603 return rgxin, rgxout, promptin, promptout
599 604
600 605
601 606 def teardown(self):
602 607 # delete last bookmark
603 608 self.shell.process_input_line('bookmark -d ipy_savedir',
604 609 store_history=False)
605 610 self.shell.clear_cout()
606 611
607 612 def run(self):
608 613 debug = False
609 614
610 615 #TODO, any reason block_parser can't be a method of embeddable shell
611 616 # then we wouldn't have to carry these around
612 617 rgxin, rgxout, promptin, promptout = self.setup()
613 618
614 619 options = self.options
615 620 self.shell.is_suppress = 'suppress' in options
616 621 self.shell.is_doctest = 'doctest' in options
617 622 self.shell.is_verbatim = 'verbatim' in options
618 623
619 624
620 625 # handle pure python code
621 626 if 'python' in self.arguments:
622 627 content = self.content
623 628 self.content = self.shell.process_pure_python(content)
624 629
625 630 parts = '\n'.join(self.content).split('\n\n')
626 631
627 632 lines = ['.. code-block:: ipython','']
628 633 figures = []
629 634
630 635 for part in parts:
631 636
632 637 block = block_parser(part, rgxin, rgxout, promptin, promptout)
633 638
634 639 if len(block):
635 640 rows, figure = self.shell.process_block(block)
636 641 for row in rows:
637 642 lines.extend([' %s'%line for line in row.split('\n')])
638 643
639 644 if figure is not None:
640 645 figures.append(figure)
641 646
642 647 #text = '\n'.join(lines)
643 648 #figs = '\n'.join(figures)
644 649
645 650 for figure in figures:
646 651 lines.append('')
647 652 lines.extend(figure.split('\n'))
648 653 lines.append('')
649 654
650 655 #print lines
651 656 if len(lines)>2:
652 657 if debug:
653 658 print('\n'.join(lines))
654 659 else: #NOTE: this raises some errors, what's it for?
655 660 #print 'INSERTING %d lines'%len(lines)
656 661 self.state_machine.insert_input(
657 662 lines, self.state_machine.input_lines.source(0))
658 663
659 664 text = '\n'.join(lines)
660 665 txtnode = nodes.literal_block(text, text)
661 666 txtnode['language'] = 'ipython'
662 667 #imgnode = nodes.image(figs)
663 668
664 669 # cleanup
665 670 self.teardown()
666 671
667 672 return []#, imgnode]
668 673
669 674 # Enable as a proper Sphinx directive
670 675 def setup(app):
671 676 setup.app = app
672 677
673 678 app.add_directive('ipython', IPythonDirective)
674 679 app.add_config_value('ipython_savefig_dir', None, True)
675 680 app.add_config_value('ipython_rgxin',
676 681 re.compile('In \[(\d+)\]:\s?(.*)\s*'), True)
677 682 app.add_config_value('ipython_rgxout',
678 683 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), True)
679 684 app.add_config_value('ipython_promptin', 'In [%d]:', True)
680 685 app.add_config_value('ipython_promptout', 'Out[%d]:', True)
681 686
682 687
683 688 # Simple smoke test, needs to be converted to a proper automatic test.
684 689 def test():
685 690
686 691 examples = [
687 692 r"""
688 693 In [9]: pwd
689 694 Out[9]: '/home/jdhunter/py4science/book'
690 695
691 696 In [10]: cd bookdata/
692 697 /home/jdhunter/py4science/book/bookdata
693 698
694 699 In [2]: from pylab import *
695 700
696 701 In [2]: ion()
697 702
698 703 In [3]: im = imread('stinkbug.png')
699 704
700 705 @savefig mystinkbug.png width=4in
701 706 In [4]: imshow(im)
702 707 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
703 708
704 709 """,
705 710 r"""
706 711
707 712 In [1]: x = 'hello world'
708 713
709 714 # string methods can be
710 715 # used to alter the string
711 716 @doctest
712 717 In [2]: x.upper()
713 718 Out[2]: 'HELLO WORLD'
714 719
715 720 @verbatim
716 721 In [3]: x.st<TAB>
717 722 x.startswith x.strip
718 723 """,
719 724 r"""
720 725
721 726 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
722 727 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
723 728
724 729 In [131]: print url.split('&')
725 730 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
726 731
727 732 In [60]: import urllib
728 733
729 734 """,
730 735 r"""\
731 736
732 737 In [133]: import numpy.random
733 738
734 739 @suppress
735 740 In [134]: numpy.random.seed(2358)
736 741
737 742 @doctest
738 743 In [135]: numpy.random.rand(10,2)
739 744 Out[135]:
740 745 array([[ 0.64524308, 0.59943846],
741 746 [ 0.47102322, 0.8715456 ],
742 747 [ 0.29370834, 0.74776844],
743 748 [ 0.99539577, 0.1313423 ],
744 749 [ 0.16250302, 0.21103583],
745 750 [ 0.81626524, 0.1312433 ],
746 751 [ 0.67338089, 0.72302393],
747 752 [ 0.7566368 , 0.07033696],
748 753 [ 0.22591016, 0.77731835],
749 754 [ 0.0072729 , 0.34273127]])
750 755
751 756 """,
752 757
753 758 r"""
754 759 In [106]: print x
755 760 jdh
756 761
757 762 In [109]: for i in range(10):
758 763 .....: print i
759 764 .....:
760 765 .....:
761 766 0
762 767 1
763 768 2
764 769 3
765 770 4
766 771 5
767 772 6
768 773 7
769 774 8
770 775 9
771 776 """,
772 777
773 778 r"""
774 779
775 780 In [144]: from pylab import *
776 781
777 782 In [145]: ion()
778 783
779 784 # use a semicolon to suppress the output
780 785 @savefig test_hist.png width=4in
781 786 In [151]: hist(np.random.randn(10000), 100);
782 787
783 788
784 789 @savefig test_plot.png width=4in
785 790 In [151]: plot(np.random.randn(10000), 'o');
786 791 """,
787 792
788 793 r"""
789 794 # use a semicolon to suppress the output
790 795 In [151]: plt.clf()
791 796
792 797 @savefig plot_simple.png width=4in
793 798 In [151]: plot([1,2,3])
794 799
795 800 @savefig hist_simple.png width=4in
796 801 In [151]: hist(np.random.randn(10000), 100);
797 802
798 803 """,
799 804 r"""
800 805 # update the current fig
801 806 In [151]: ylabel('number')
802 807
803 808 In [152]: title('normal distribution')
804 809
805 810
806 811 @savefig hist_with_text.png
807 812 In [153]: grid(True)
808 813
809 814 """,
810 815 ]
811 816 # skip local-file depending first example:
812 817 examples = examples[1:]
813 818
814 819 #ipython_directive.DEBUG = True # dbg
815 820 #options = dict(suppress=True) # dbg
816 821 options = dict()
817 822 for example in examples:
818 823 content = example.split('\n')
819 824 IPythonDirective('debug', arguments=None, options=options,
820 825 content=content, lineno=0,
821 826 content_offset=None, block_text=None,
822 827 state=None, state_machine=None,
823 828 )
824 829
825 830 # Run test suite as a script
826 831 if __name__=='__main__':
827 832 if not os.path.isdir('_static'):
828 833 os.mkdir('_static')
829 834 test()
830 835 print('All OK? Check figures in _static/')
@@ -1,760 +1,764 b''
1 1 """Nose Plugin that supports IPython doctests.
2 2
3 3 Limitations:
4 4
5 5 - When generating examples for use as doctests, make sure that you have
6 6 pretty-printing OFF. This can be done either by setting the
7 7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 8 by interactively disabling it with %Pprint. This is required so that IPython
9 9 output matches that of normal Python, which is used by doctest for internal
10 10 execution.
11 11
12 12 - Do not rely on specific prompt numbers for results (such as using
13 13 '_34==True', for example). For IPython tests run via an external process the
14 14 prompt numbers may be different, and IPython tests run as normal python code
15 15 won't even have these special _NN variables set at all.
16 16 """
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Module imports
20 20
21 21 # From the standard library
22 22 import doctest
23 23 import inspect
24 24 import logging
25 25 import os
26 26 import re
27 27 import sys
28 28 import traceback
29 29 import unittest
30 30
31 31 from inspect import getmodule
32 from io import StringIO
33 32
34 33 # We are overriding the default doctest runner, so we need to import a few
35 34 # things from doctest directly
36 35 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
37 36 _unittest_reportflags, DocTestRunner,
38 37 _extract_future_flags, pdb, _OutputRedirectingPdb,
39 38 _exception_traceback,
40 39 linecache)
41 40
42 41 # Third-party modules
43 42 import nose.core
44 43
45 44 from nose.plugins import doctests, Plugin
46 45 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
47 46
48 47 # Our own imports
49 from IPython.utils.py3compat import builtin_mod
48 from IPython.utils.py3compat import builtin_mod, PY3
49
50 if PY3:
51 from io import StringIO
52 else:
53 from StringIO import StringIO
50 54
51 55 #-----------------------------------------------------------------------------
52 56 # Module globals and other constants
53 57 #-----------------------------------------------------------------------------
54 58
55 59 log = logging.getLogger(__name__)
56 60
57 61
58 62 #-----------------------------------------------------------------------------
59 63 # Classes and functions
60 64 #-----------------------------------------------------------------------------
61 65
62 66 def is_extension_module(filename):
63 67 """Return whether the given filename is an extension module.
64 68
65 69 This simply checks that the extension is either .so or .pyd.
66 70 """
67 71 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
68 72
69 73
70 74 class DocTestSkip(object):
71 75 """Object wrapper for doctests to be skipped."""
72 76
73 77 ds_skip = """Doctest to skip.
74 78 >>> 1 #doctest: +SKIP
75 79 """
76 80
77 81 def __init__(self,obj):
78 82 self.obj = obj
79 83
80 84 def __getattribute__(self,key):
81 85 if key == '__doc__':
82 86 return DocTestSkip.ds_skip
83 87 else:
84 88 return getattr(object.__getattribute__(self,'obj'),key)
85 89
86 90 # Modified version of the one in the stdlib, that fixes a python bug (doctests
87 91 # not found in extension modules, http://bugs.python.org/issue3158)
88 92 class DocTestFinder(doctest.DocTestFinder):
89 93
90 94 def _from_module(self, module, object):
91 95 """
92 96 Return true if the given object is defined in the given
93 97 module.
94 98 """
95 99 if module is None:
96 100 return True
97 101 elif inspect.isfunction(object):
98 102 return module.__dict__ is object.__globals__
99 103 elif inspect.isbuiltin(object):
100 104 return module.__name__ == object.__module__
101 105 elif inspect.isclass(object):
102 106 return module.__name__ == object.__module__
103 107 elif inspect.ismethod(object):
104 108 # This one may be a bug in cython that fails to correctly set the
105 109 # __module__ attribute of methods, but since the same error is easy
106 110 # to make by extension code writers, having this safety in place
107 111 # isn't such a bad idea
108 112 return module.__name__ == object.im_class.__module__
109 113 elif inspect.getmodule(object) is not None:
110 114 return module is inspect.getmodule(object)
111 115 elif hasattr(object, '__module__'):
112 116 return module.__name__ == object.__module__
113 117 elif isinstance(object, property):
114 118 return True # [XX] no way not be sure.
115 119 else:
116 120 raise ValueError("object must be a class or function")
117 121
118 122 def _find(self, tests, obj, name, module, source_lines, globs, seen):
119 123 """
120 124 Find tests for the given object and any contained objects, and
121 125 add them to `tests`.
122 126 """
123 127 #print '_find for:', obj, name, module # dbg
124 128 if hasattr(obj,"skip_doctest"):
125 129 #print 'SKIPPING DOCTEST FOR:',obj # dbg
126 130 obj = DocTestSkip(obj)
127 131
128 132 doctest.DocTestFinder._find(self,tests, obj, name, module,
129 133 source_lines, globs, seen)
130 134
131 135 # Below we re-run pieces of the above method with manual modifications,
132 136 # because the original code is buggy and fails to correctly identify
133 137 # doctests in extension modules.
134 138
135 139 # Local shorthands
136 140 from inspect import isroutine, isclass, ismodule
137 141
138 142 # Look for tests in a module's contained objects.
139 143 if inspect.ismodule(obj) and self._recurse:
140 144 for valname, val in obj.__dict__.items():
141 145 valname1 = '%s.%s' % (name, valname)
142 146 if ( (isroutine(val) or isclass(val))
143 147 and self._from_module(module, val) ):
144 148
145 149 self._find(tests, val, valname1, module, source_lines,
146 150 globs, seen)
147 151
148 152 # Look for tests in a class's contained objects.
149 153 if inspect.isclass(obj) and self._recurse:
150 154 #print 'RECURSE into class:',obj # dbg
151 155 for valname, val in obj.__dict__.items():
152 156 # Special handling for staticmethod/classmethod.
153 157 if isinstance(val, staticmethod):
154 158 val = getattr(obj, valname)
155 159 if isinstance(val, classmethod):
156 160 val = getattr(obj, valname).im_func
157 161
158 162 # Recurse to methods, properties, and nested classes.
159 163 if ((inspect.isfunction(val) or inspect.isclass(val) or
160 164 inspect.ismethod(val) or
161 165 isinstance(val, property)) and
162 166 self._from_module(module, val)):
163 167 valname = '%s.%s' % (name, valname)
164 168 self._find(tests, val, valname, module, source_lines,
165 169 globs, seen)
166 170
167 171
168 172 class IPDoctestOutputChecker(doctest.OutputChecker):
169 173 """Second-chance checker with support for random tests.
170 174
171 175 If the default comparison doesn't pass, this checker looks in the expected
172 176 output string for flags that tell us to ignore the output.
173 177 """
174 178
175 179 random_re = re.compile(r'#\s*random\s+')
176 180
177 181 def check_output(self, want, got, optionflags):
178 182 """Check output, accepting special markers embedded in the output.
179 183
180 184 If the output didn't pass the default validation but the special string
181 185 '#random' is included, we accept it."""
182 186
183 187 # Let the original tester verify first, in case people have valid tests
184 188 # that happen to have a comment saying '#random' embedded in.
185 189 ret = doctest.OutputChecker.check_output(self, want, got,
186 190 optionflags)
187 191 if not ret and self.random_re.search(want):
188 192 #print >> sys.stderr, 'RANDOM OK:',want # dbg
189 193 return True
190 194
191 195 return ret
192 196
193 197
194 198 class DocTestCase(doctests.DocTestCase):
195 199 """Proxy for DocTestCase: provides an address() method that
196 200 returns the correct address for the doctest case. Otherwise
197 201 acts as a proxy to the test case. To provide hints for address(),
198 202 an obj may also be passed -- this will be used as the test object
199 203 for purposes of determining the test address, if it is provided.
200 204 """
201 205
202 206 # Note: this method was taken from numpy's nosetester module.
203 207
204 208 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
205 209 # its constructor that blocks non-default arguments from being passed
206 210 # down into doctest.DocTestCase
207 211
208 212 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
209 213 checker=None, obj=None, result_var='_'):
210 214 self._result_var = result_var
211 215 doctests.DocTestCase.__init__(self, test,
212 216 optionflags=optionflags,
213 217 setUp=setUp, tearDown=tearDown,
214 218 checker=checker)
215 219 # Now we must actually copy the original constructor from the stdlib
216 220 # doctest class, because we can't call it directly and a bug in nose
217 221 # means it never gets passed the right arguments.
218 222
219 223 self._dt_optionflags = optionflags
220 224 self._dt_checker = checker
221 225 self._dt_test = test
222 226 self._dt_test_globs_ori = test.globs
223 227 self._dt_setUp = setUp
224 228 self._dt_tearDown = tearDown
225 229
226 230 # XXX - store this runner once in the object!
227 231 runner = IPDocTestRunner(optionflags=optionflags,
228 232 checker=checker, verbose=False)
229 233 self._dt_runner = runner
230 234
231 235
232 236 # Each doctest should remember the directory it was loaded from, so
233 237 # things like %run work without too many contortions
234 238 self._ori_dir = os.path.dirname(test.filename)
235 239
236 240 # Modified runTest from the default stdlib
237 241 def runTest(self):
238 242 test = self._dt_test
239 243 runner = self._dt_runner
240 244
241 245 old = sys.stdout
242 246 new = StringIO()
243 247 optionflags = self._dt_optionflags
244 248
245 249 if not (optionflags & REPORTING_FLAGS):
246 250 # The option flags don't include any reporting flags,
247 251 # so add the default reporting flags
248 252 optionflags |= _unittest_reportflags
249 253
250 254 try:
251 255 # Save our current directory and switch out to the one where the
252 256 # test was originally created, in case another doctest did a
253 257 # directory change. We'll restore this in the finally clause.
254 258 curdir = os.getcwdu()
255 259 #print 'runTest in dir:', self._ori_dir # dbg
256 260 os.chdir(self._ori_dir)
257 261
258 262 runner.DIVIDER = "-"*70
259 263 failures, tries = runner.run(test,out=new.write,
260 264 clear_globs=False)
261 265 finally:
262 266 sys.stdout = old
263 267 os.chdir(curdir)
264 268
265 269 if failures:
266 270 raise self.failureException(self.format_failure(new.getvalue()))
267 271
268 272 def setUp(self):
269 273 """Modified test setup that syncs with ipython namespace"""
270 274 #print "setUp test", self._dt_test.examples # dbg
271 275 if isinstance(self._dt_test.examples[0], IPExample):
272 276 # for IPython examples *only*, we swap the globals with the ipython
273 277 # namespace, after updating it with the globals (which doctest
274 278 # fills with the necessary info from the module being tested).
275 279 self.user_ns_orig = {}
276 280 self.user_ns_orig.update(_ip.user_ns)
277 281 _ip.user_ns.update(self._dt_test.globs)
278 282 # We must remove the _ key in the namespace, so that Python's
279 283 # doctest code sets it naturally
280 284 _ip.user_ns.pop('_', None)
281 285 _ip.user_ns['__builtins__'] = builtin_mod
282 286 self._dt_test.globs = _ip.user_ns
283 287
284 288 super(DocTestCase, self).setUp()
285 289
286 290 def tearDown(self):
287 291
288 292 # Undo the test.globs reassignment we made, so that the parent class
289 293 # teardown doesn't destroy the ipython namespace
290 294 if isinstance(self._dt_test.examples[0], IPExample):
291 295 self._dt_test.globs = self._dt_test_globs_ori
292 296 _ip.user_ns.clear()
293 297 _ip.user_ns.update(self.user_ns_orig)
294 298
295 299 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
296 300 # it does look like one to me: its tearDown method tries to run
297 301 #
298 302 # delattr(builtin_mod, self._result_var)
299 303 #
300 304 # without checking that the attribute really is there; it implicitly
301 305 # assumes it should have been set via displayhook. But if the
302 306 # displayhook was never called, this doesn't necessarily happen. I
303 307 # haven't been able to find a little self-contained example outside of
304 308 # ipython that would show the problem so I can report it to the nose
305 309 # team, but it does happen a lot in our code.
306 310 #
307 311 # So here, we just protect as narrowly as possible by trapping an
308 312 # attribute error whose message would be the name of self._result_var,
309 313 # and letting any other error propagate.
310 314 try:
311 315 super(DocTestCase, self).tearDown()
312 316 except AttributeError as exc:
313 317 if exc.args[0] != self._result_var:
314 318 raise
315 319
316 320
317 321 # A simple subclassing of the original with a different class name, so we can
318 322 # distinguish and treat differently IPython examples from pure python ones.
319 323 class IPExample(doctest.Example): pass
320 324
321 325
322 326 class IPExternalExample(doctest.Example):
323 327 """Doctest examples to be run in an external process."""
324 328
325 329 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
326 330 options=None):
327 331 # Parent constructor
328 332 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
329 333
330 334 # An EXTRA newline is needed to prevent pexpect hangs
331 335 self.source += '\n'
332 336
333 337
334 338 class IPDocTestParser(doctest.DocTestParser):
335 339 """
336 340 A class used to parse strings containing doctest examples.
337 341
338 342 Note: This is a version modified to properly recognize IPython input and
339 343 convert any IPython examples into valid Python ones.
340 344 """
341 345 # This regular expression is used to find doctest examples in a
342 346 # string. It defines three groups: `source` is the source code
343 347 # (including leading indentation and prompts); `indent` is the
344 348 # indentation of the first (PS1) line of the source code; and
345 349 # `want` is the expected output (including leading indentation).
346 350
347 351 # Classic Python prompts or default IPython ones
348 352 _PS1_PY = r'>>>'
349 353 _PS2_PY = r'\.\.\.'
350 354
351 355 _PS1_IP = r'In\ \[\d+\]:'
352 356 _PS2_IP = r'\ \ \ \.\.\.+:'
353 357
354 358 _RE_TPL = r'''
355 359 # Source consists of a PS1 line followed by zero or more PS2 lines.
356 360 (?P<source>
357 361 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
358 362 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
359 363 \n? # a newline
360 364 # Want consists of any non-blank lines that do not start with PS1.
361 365 (?P<want> (?:(?![ ]*$) # Not a blank line
362 366 (?![ ]*%s) # Not a line starting with PS1
363 367 (?![ ]*%s) # Not a line starting with PS2
364 368 .*$\n? # But any other line
365 369 )*)
366 370 '''
367 371
368 372 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
369 373 re.MULTILINE | re.VERBOSE)
370 374
371 375 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
372 376 re.MULTILINE | re.VERBOSE)
373 377
374 378 # Mark a test as being fully random. In this case, we simply append the
375 379 # random marker ('#random') to each individual example's output. This way
376 380 # we don't need to modify any other code.
377 381 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
378 382
379 383 # Mark tests to be executed in an external process - currently unsupported.
380 384 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
381 385
382 386 def ip2py(self,source):
383 387 """Convert input IPython source into valid Python."""
384 388 block = _ip.input_transformer_manager.transform_cell(source)
385 389 if len(block.splitlines()) == 1:
386 390 return _ip.prefilter(block)
387 391 else:
388 392 return block
389 393
390 394 def parse(self, string, name='<string>'):
391 395 """
392 396 Divide the given string into examples and intervening text,
393 397 and return them as a list of alternating Examples and strings.
394 398 Line numbers for the Examples are 0-based. The optional
395 399 argument `name` is a name identifying this string, and is only
396 400 used for error messages.
397 401 """
398 402
399 403 #print 'Parse string:\n',string # dbg
400 404
401 405 string = string.expandtabs()
402 406 # If all lines begin with the same indentation, then strip it.
403 407 min_indent = self._min_indent(string)
404 408 if min_indent > 0:
405 409 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
406 410
407 411 output = []
408 412 charno, lineno = 0, 0
409 413
410 414 # We make 'all random' tests by adding the '# random' mark to every
411 415 # block of output in the test.
412 416 if self._RANDOM_TEST.search(string):
413 417 random_marker = '\n# random'
414 418 else:
415 419 random_marker = ''
416 420
417 421 # Whether to convert the input from ipython to python syntax
418 422 ip2py = False
419 423 # Find all doctest examples in the string. First, try them as Python
420 424 # examples, then as IPython ones
421 425 terms = list(self._EXAMPLE_RE_PY.finditer(string))
422 426 if terms:
423 427 # Normal Python example
424 428 #print '-'*70 # dbg
425 429 #print 'PyExample, Source:\n',string # dbg
426 430 #print '-'*70 # dbg
427 431 Example = doctest.Example
428 432 else:
429 433 # It's an ipython example. Note that IPExamples are run
430 434 # in-process, so their syntax must be turned into valid python.
431 435 # IPExternalExamples are run out-of-process (via pexpect) so they
432 436 # don't need any filtering (a real ipython will be executing them).
433 437 terms = list(self._EXAMPLE_RE_IP.finditer(string))
434 438 if self._EXTERNAL_IP.search(string):
435 439 #print '-'*70 # dbg
436 440 #print 'IPExternalExample, Source:\n',string # dbg
437 441 #print '-'*70 # dbg
438 442 Example = IPExternalExample
439 443 else:
440 444 #print '-'*70 # dbg
441 445 #print 'IPExample, Source:\n',string # dbg
442 446 #print '-'*70 # dbg
443 447 Example = IPExample
444 448 ip2py = True
445 449
446 450 for m in terms:
447 451 # Add the pre-example text to `output`.
448 452 output.append(string[charno:m.start()])
449 453 # Update lineno (lines before this example)
450 454 lineno += string.count('\n', charno, m.start())
451 455 # Extract info from the regexp match.
452 456 (source, options, want, exc_msg) = \
453 457 self._parse_example(m, name, lineno,ip2py)
454 458
455 459 # Append the random-output marker (it defaults to empty in most
456 460 # cases, it's only non-empty for 'all-random' tests):
457 461 want += random_marker
458 462
459 463 if Example is IPExternalExample:
460 464 options[doctest.NORMALIZE_WHITESPACE] = True
461 465 want += '\n'
462 466
463 467 # Create an Example, and add it to the list.
464 468 if not self._IS_BLANK_OR_COMMENT(source):
465 469 output.append(Example(source, want, exc_msg,
466 470 lineno=lineno,
467 471 indent=min_indent+len(m.group('indent')),
468 472 options=options))
469 473 # Update lineno (lines inside this example)
470 474 lineno += string.count('\n', m.start(), m.end())
471 475 # Update charno.
472 476 charno = m.end()
473 477 # Add any remaining post-example text to `output`.
474 478 output.append(string[charno:])
475 479 return output
476 480
477 481 def _parse_example(self, m, name, lineno,ip2py=False):
478 482 """
479 483 Given a regular expression match from `_EXAMPLE_RE` (`m`),
480 484 return a pair `(source, want)`, where `source` is the matched
481 485 example's source code (with prompts and indentation stripped);
482 486 and `want` is the example's expected output (with indentation
483 487 stripped).
484 488
485 489 `name` is the string's name, and `lineno` is the line number
486 490 where the example starts; both are used for error messages.
487 491
488 492 Optional:
489 493 `ip2py`: if true, filter the input via IPython to convert the syntax
490 494 into valid python.
491 495 """
492 496
493 497 # Get the example's indentation level.
494 498 indent = len(m.group('indent'))
495 499
496 500 # Divide source into lines; check that they're properly
497 501 # indented; and then strip their indentation & prompts.
498 502 source_lines = m.group('source').split('\n')
499 503
500 504 # We're using variable-length input prompts
501 505 ps1 = m.group('ps1')
502 506 ps2 = m.group('ps2')
503 507 ps1_len = len(ps1)
504 508
505 509 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
506 510 if ps2:
507 511 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
508 512
509 513 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
510 514
511 515 if ip2py:
512 516 # Convert source input from IPython into valid Python syntax
513 517 source = self.ip2py(source)
514 518
515 519 # Divide want into lines; check that it's properly indented; and
516 520 # then strip the indentation. Spaces before the last newline should
517 521 # be preserved, so plain rstrip() isn't good enough.
518 522 want = m.group('want')
519 523 want_lines = want.split('\n')
520 524 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
521 525 del want_lines[-1] # forget final newline & spaces after it
522 526 self._check_prefix(want_lines, ' '*indent, name,
523 527 lineno + len(source_lines))
524 528
525 529 # Remove ipython output prompt that might be present in the first line
526 530 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
527 531
528 532 want = '\n'.join([wl[indent:] for wl in want_lines])
529 533
530 534 # If `want` contains a traceback message, then extract it.
531 535 m = self._EXCEPTION_RE.match(want)
532 536 if m:
533 537 exc_msg = m.group('msg')
534 538 else:
535 539 exc_msg = None
536 540
537 541 # Extract options from the source.
538 542 options = self._find_options(source, name, lineno)
539 543
540 544 return source, options, want, exc_msg
541 545
542 546 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
543 547 """
544 548 Given the lines of a source string (including prompts and
545 549 leading indentation), check to make sure that every prompt is
546 550 followed by a space character. If any line is not followed by
547 551 a space character, then raise ValueError.
548 552
549 553 Note: IPython-modified version which takes the input prompt length as a
550 554 parameter, so that prompts of variable length can be dealt with.
551 555 """
552 556 space_idx = indent+ps1_len
553 557 min_len = space_idx+1
554 558 for i, line in enumerate(lines):
555 559 if len(line) >= min_len and line[space_idx] != ' ':
556 560 raise ValueError('line %r of the docstring for %s '
557 561 'lacks blank after %s: %r' %
558 562 (lineno+i+1, name,
559 563 line[indent:space_idx], line))
560 564
561 565
562 566 SKIP = doctest.register_optionflag('SKIP')
563 567
564 568
565 569 class IPDocTestRunner(doctest.DocTestRunner,object):
566 570 """Test runner that synchronizes the IPython namespace with test globals.
567 571 """
568 572
569 573 def run(self, test, compileflags=None, out=None, clear_globs=True):
570 574
571 575 # Hack: ipython needs access to the execution context of the example,
572 576 # so that it can propagate user variables loaded by %run into
573 577 # test.globs. We put them here into our modified %run as a function
574 578 # attribute. Our new %run will then only make the namespace update
575 579 # when called (rather than unconconditionally updating test.globs here
576 580 # for all examples, most of which won't be calling %run anyway).
577 581 #_ip._ipdoctest_test_globs = test.globs
578 582 #_ip._ipdoctest_test_filename = test.filename
579 583
580 584 test.globs.update(_ip.user_ns)
581 585
582 586 return super(IPDocTestRunner,self).run(test,
583 587 compileflags,out,clear_globs)
584 588
585 589
586 590 class DocFileCase(doctest.DocFileCase):
587 591 """Overrides to provide filename
588 592 """
589 593 def address(self):
590 594 return (self._dt_test.filename, None, None)
591 595
592 596
593 597 class ExtensionDoctest(doctests.Doctest):
594 598 """Nose Plugin that supports doctests in extension modules.
595 599 """
596 600 name = 'extdoctest' # call nosetests with --with-extdoctest
597 601 enabled = True
598 602
599 603 def options(self, parser, env=os.environ):
600 604 Plugin.options(self, parser, env)
601 605 parser.add_option('--doctest-tests', action='store_true',
602 606 dest='doctest_tests',
603 607 default=env.get('NOSE_DOCTEST_TESTS',True),
604 608 help="Also look for doctests in test modules. "
605 609 "Note that classes, methods and functions should "
606 610 "have either doctests or non-doctest tests, "
607 611 "not both. [NOSE_DOCTEST_TESTS]")
608 612 parser.add_option('--doctest-extension', action="append",
609 613 dest="doctestExtension",
610 614 help="Also look for doctests in files with "
611 615 "this extension [NOSE_DOCTEST_EXTENSION]")
612 616 # Set the default as a list, if given in env; otherwise
613 617 # an additional value set on the command line will cause
614 618 # an error.
615 619 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
616 620 if env_setting is not None:
617 621 parser.set_defaults(doctestExtension=tolist(env_setting))
618 622
619 623
620 624 def configure(self, options, config):
621 625 Plugin.configure(self, options, config)
622 626 # Pull standard doctest plugin out of config; we will do doctesting
623 627 config.plugins.plugins = [p for p in config.plugins.plugins
624 628 if p.name != 'doctest']
625 629 self.doctest_tests = options.doctest_tests
626 630 self.extension = tolist(options.doctestExtension)
627 631
628 632 self.parser = doctest.DocTestParser()
629 633 self.finder = DocTestFinder()
630 634 self.checker = IPDoctestOutputChecker()
631 635 self.globs = None
632 636 self.extraglobs = None
633 637
634 638
635 639 def loadTestsFromExtensionModule(self,filename):
636 640 bpath,mod = os.path.split(filename)
637 641 modname = os.path.splitext(mod)[0]
638 642 try:
639 643 sys.path.append(bpath)
640 644 module = __import__(modname)
641 645 tests = list(self.loadTestsFromModule(module))
642 646 finally:
643 647 sys.path.pop()
644 648 return tests
645 649
646 650 # NOTE: the method below is almost a copy of the original one in nose, with
647 651 # a few modifications to control output checking.
648 652
649 653 def loadTestsFromModule(self, module):
650 654 #print '*** ipdoctest - lTM',module # dbg
651 655
652 656 if not self.matches(module.__name__):
653 657 log.debug("Doctest doesn't want module %s", module)
654 658 return
655 659
656 660 tests = self.finder.find(module,globs=self.globs,
657 661 extraglobs=self.extraglobs)
658 662 if not tests:
659 663 return
660 664
661 665 # always use whitespace and ellipsis options
662 666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
663 667
664 668 tests.sort()
665 669 module_file = module.__file__
666 670 if module_file[-4:] in ('.pyc', '.pyo'):
667 671 module_file = module_file[:-1]
668 672 for test in tests:
669 673 if not test.examples:
670 674 continue
671 675 if not test.filename:
672 676 test.filename = module_file
673 677
674 678 yield DocTestCase(test,
675 679 optionflags=optionflags,
676 680 checker=self.checker)
677 681
678 682
679 683 def loadTestsFromFile(self, filename):
680 684 #print "ipdoctest - from file", filename # dbg
681 685 if is_extension_module(filename):
682 686 for t in self.loadTestsFromExtensionModule(filename):
683 687 yield t
684 688 else:
685 689 if self.extension and anyp(filename.endswith, self.extension):
686 690 name = os.path.basename(filename)
687 691 dh = open(filename)
688 692 try:
689 693 doc = dh.read()
690 694 finally:
691 695 dh.close()
692 696 test = self.parser.get_doctest(
693 697 doc, globs={'__file__': filename}, name=name,
694 698 filename=filename, lineno=0)
695 699 if test.examples:
696 700 #print 'FileCase:',test.examples # dbg
697 701 yield DocFileCase(test)
698 702 else:
699 703 yield False # no tests to load
700 704
701 705
702 706 class IPythonDoctest(ExtensionDoctest):
703 707 """Nose Plugin that supports doctests in extension modules.
704 708 """
705 709 name = 'ipdoctest' # call nosetests with --with-ipdoctest
706 710 enabled = True
707 711
708 712 def makeTest(self, obj, parent):
709 713 """Look for doctests in the given object, which will be a
710 714 function, method or class.
711 715 """
712 716 #print 'Plugin analyzing:', obj, parent # dbg
713 717 # always use whitespace and ellipsis options
714 718 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
715 719
716 720 doctests = self.finder.find(obj, module=getmodule(parent))
717 721 if doctests:
718 722 for test in doctests:
719 723 if len(test.examples) == 0:
720 724 continue
721 725
722 726 yield DocTestCase(test, obj=obj,
723 727 optionflags=optionflags,
724 728 checker=self.checker)
725 729
726 730 def options(self, parser, env=os.environ):
727 731 #print "Options for nose plugin:", self.name # dbg
728 732 Plugin.options(self, parser, env)
729 733 parser.add_option('--ipdoctest-tests', action='store_true',
730 734 dest='ipdoctest_tests',
731 735 default=env.get('NOSE_IPDOCTEST_TESTS',True),
732 736 help="Also look for doctests in test modules. "
733 737 "Note that classes, methods and functions should "
734 738 "have either doctests or non-doctest tests, "
735 739 "not both. [NOSE_IPDOCTEST_TESTS]")
736 740 parser.add_option('--ipdoctest-extension', action="append",
737 741 dest="ipdoctest_extension",
738 742 help="Also look for doctests in files with "
739 743 "this extension [NOSE_IPDOCTEST_EXTENSION]")
740 744 # Set the default as a list, if given in env; otherwise
741 745 # an additional value set on the command line will cause
742 746 # an error.
743 747 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
744 748 if env_setting is not None:
745 749 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
746 750
747 751 def configure(self, options, config):
748 752 #print "Configuring nose plugin:", self.name # dbg
749 753 Plugin.configure(self, options, config)
750 754 # Pull standard doctest plugin out of config; we will do doctesting
751 755 config.plugins.plugins = [p for p in config.plugins.plugins
752 756 if p.name != 'doctest']
753 757 self.doctest_tests = options.ipdoctest_tests
754 758 self.extension = tolist(options.ipdoctest_extension)
755 759
756 760 self.parser = IPDocTestParser()
757 761 self.finder = DocTestFinder(parser=self.parser)
758 762 self.checker = IPDoctestOutputChecker()
759 763 self.globs = None
760 764 self.extraglobs = None
@@ -1,310 +1,315 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Class and program to colorize python source code for ANSI terminals.
4 4
5 5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7 7
8 8 Modifications by Fernando Perez (fperez@colorado.edu).
9 9
10 10 Information on the original HTML highlighter follows:
11 11
12 12 MoinMoin - Python Source Parser
13 13
14 14 Title: Colorize Python source using the built-in tokenizer
15 15
16 16 Submitter: Jurgen Hermann
17 17 Last Updated:2001/04/06
18 18
19 19 Version no:1.2
20 20
21 21 Description:
22 22
23 23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 24 Python source code to HTML markup, rendering comments, keywords,
25 25 operators, numeric and string literals in different colors.
26 26
27 27 It shows how to use the built-in keyword, token and tokenize modules to
28 28 scan Python source code and re-emit it with no changes to its original
29 29 formatting (which is the hard part).
30 30 """
31 31 from __future__ import print_function
32 32 from __future__ import absolute_import
33 33 from __future__ import unicode_literals
34 34
35 35 __all__ = ['ANSICodeColors','Parser']
36 36
37 37 _scheme_default = 'Linux'
38 38
39 39
40 40 # Imports
41 import io
42 41 import keyword
43 42 import os
44 43 import sys
45 44 import token
46 45 import tokenize
47 46
48 47 try:
49 48 generate_tokens = tokenize.generate_tokens
50 49 except AttributeError:
51 50 # Python 3. Note that we use the undocumented _tokenize because it expects
52 51 # strings, not bytes. See also Python issue #9969.
53 52 generate_tokens = tokenize._tokenize
54 53
55 54 from IPython.utils.coloransi import *
55 from IPython.utils.py3compat import PY3
56
57 if PY3:
58 from io import StringIO
59 else:
60 from StringIO import StringIO
56 61
57 62 #############################################################################
58 63 ### Python Source Parser (does Hilighting)
59 64 #############################################################################
60 65
61 66 _KEYWORD = token.NT_OFFSET + 1
62 67 _TEXT = token.NT_OFFSET + 2
63 68
64 69 #****************************************************************************
65 70 # Builtin color schemes
66 71
67 72 Colors = TermColors # just a shorthand
68 73
69 74 # Build a few color schemes
70 75 NoColor = ColorScheme(
71 76 'NoColor',{
72 77 token.NUMBER : Colors.NoColor,
73 78 token.OP : Colors.NoColor,
74 79 token.STRING : Colors.NoColor,
75 80 tokenize.COMMENT : Colors.NoColor,
76 81 token.NAME : Colors.NoColor,
77 82 token.ERRORTOKEN : Colors.NoColor,
78 83
79 84 _KEYWORD : Colors.NoColor,
80 85 _TEXT : Colors.NoColor,
81 86
82 87 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
83 88 } )
84 89
85 90 LinuxColors = ColorScheme(
86 91 'Linux',{
87 92 token.NUMBER : Colors.LightCyan,
88 93 token.OP : Colors.Yellow,
89 94 token.STRING : Colors.LightBlue,
90 95 tokenize.COMMENT : Colors.LightRed,
91 96 token.NAME : Colors.Normal,
92 97 token.ERRORTOKEN : Colors.Red,
93 98
94 99 _KEYWORD : Colors.LightGreen,
95 100 _TEXT : Colors.Yellow,
96 101
97 102 'normal' : Colors.Normal # color off (usu. Colors.Normal)
98 103 } )
99 104
100 105 LightBGColors = ColorScheme(
101 106 'LightBG',{
102 107 token.NUMBER : Colors.Cyan,
103 108 token.OP : Colors.Blue,
104 109 token.STRING : Colors.Blue,
105 110 tokenize.COMMENT : Colors.Red,
106 111 token.NAME : Colors.Normal,
107 112 token.ERRORTOKEN : Colors.Red,
108 113
109 114 _KEYWORD : Colors.Green,
110 115 _TEXT : Colors.Blue,
111 116
112 117 'normal' : Colors.Normal # color off (usu. Colors.Normal)
113 118 } )
114 119
115 120 # Build table of color schemes (needed by the parser)
116 121 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
117 122 _scheme_default)
118 123
119 124 class Parser:
120 125 """ Format colored Python source.
121 126 """
122 127
123 128 def __init__(self, color_table=None,out = sys.stdout):
124 129 """ Create a parser with a specified color table and output channel.
125 130
126 131 Call format() to process code.
127 132 """
128 133 self.color_table = color_table and color_table or ANSICodeColors
129 134 self.out = out
130 135
131 136 def format(self, raw, out = None, scheme = ''):
132 137 return self.format2(raw, out, scheme)[0]
133 138
134 139 def format2(self, raw, out = None, scheme = ''):
135 140 """ Parse and send the colored source.
136 141
137 142 If out and scheme are not specified, the defaults (given to
138 143 constructor) are used.
139 144
140 145 out should be a file-type object. Optionally, out can be given as the
141 146 string 'str' and the parser will automatically return the output in a
142 147 string."""
143 148
144 149 string_output = 0
145 150 if out == 'str' or self.out == 'str' or \
146 isinstance(self.out,io.StringIO):
151 isinstance(self.out,StringIO):
147 152 # XXX - I don't really like this state handling logic, but at this
148 153 # point I don't want to make major changes, so adding the
149 154 # isinstance() check is the simplest I can do to ensure correct
150 155 # behavior.
151 156 out_old = self.out
152 self.out = io.StringIO()
157 self.out = StringIO()
153 158 string_output = 1
154 159 elif out is not None:
155 160 self.out = out
156 161
157 162 # Fast return of the unmodified input for NoColor scheme
158 163 if scheme == 'NoColor':
159 164 error = False
160 165 self.out.write(raw)
161 166 if string_output:
162 167 return raw,error
163 168 else:
164 169 return None,error
165 170
166 171 # local shorthands
167 172 colors = self.color_table[scheme].colors
168 173 self.colors = colors # put in object so __call__ sees it
169 174
170 175 # Remove trailing whitespace and normalize tabs
171 176 self.raw = raw.expandtabs().rstrip()
172 177
173 178 # store line offsets in self.lines
174 179 self.lines = [0, 0]
175 180 pos = 0
176 181 raw_find = self.raw.find
177 182 lines_append = self.lines.append
178 183 while 1:
179 184 pos = raw_find('\n', pos) + 1
180 185 if not pos: break
181 186 lines_append(pos)
182 187 lines_append(len(self.raw))
183 188
184 189 # parse the source and write it
185 190 self.pos = 0
186 text = io.StringIO(self.raw)
191 text = StringIO(self.raw)
187 192
188 193 error = False
189 194 try:
190 195 for atoken in generate_tokens(text.readline):
191 196 self(*atoken)
192 197 except tokenize.TokenError as ex:
193 198 msg = ex.args[0]
194 199 line = ex.args[1][0]
195 200 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
196 201 (colors[token.ERRORTOKEN],
197 202 msg, self.raw[self.lines[line]:],
198 203 colors.normal)
199 204 )
200 205 error = True
201 206 self.out.write(colors.normal+'\n')
202 207 if string_output:
203 208 output = self.out.getvalue()
204 209 self.out = out_old
205 210 return (output, error)
206 211 return (None, error)
207 212
208 213 def __call__(self, toktype, toktext, start_pos, end_pos, line):
209 214 """ Token handler, with syntax highlighting."""
210 215 (srow,scol) = start_pos
211 216 (erow,ecol) = end_pos
212 217 colors = self.colors
213 218 owrite = self.out.write
214 219
215 220 # line separator, so this works across platforms
216 221 linesep = os.linesep
217 222
218 223 # calculate new positions
219 224 oldpos = self.pos
220 225 newpos = self.lines[srow] + scol
221 226 self.pos = newpos + len(toktext)
222 227
223 228 # send the original whitespace, if needed
224 229 if newpos > oldpos:
225 230 owrite(self.raw[oldpos:newpos])
226 231
227 232 # skip indenting tokens
228 233 if toktype in [token.INDENT, token.DEDENT]:
229 234 self.pos = newpos
230 235 return
231 236
232 237 # map token type to a color group
233 238 if token.LPAR <= toktype and toktype <= token.OP:
234 239 toktype = token.OP
235 240 elif toktype == token.NAME and keyword.iskeyword(toktext):
236 241 toktype = _KEYWORD
237 242 color = colors.get(toktype, colors[_TEXT])
238 243
239 244 #print '<%s>' % toktext, # dbg
240 245
241 246 # Triple quoted strings must be handled carefully so that backtracking
242 247 # in pagers works correctly. We need color terminators on _each_ line.
243 248 if linesep in toktext:
244 249 toktext = toktext.replace(linesep, '%s%s%s' %
245 250 (colors.normal,linesep,color))
246 251
247 252 # send text
248 253 owrite('%s%s%s' % (color,toktext,colors.normal))
249 254
250 255 def main(argv=None):
251 256 """Run as a command-line script: colorize a python file or stdin using ANSI
252 257 color escapes and print to stdout.
253 258
254 259 Inputs:
255 260
256 261 - argv(None): a list of strings like sys.argv[1:] giving the command-line
257 262 arguments. If None, use sys.argv[1:].
258 263 """
259 264
260 265 usage_msg = """%prog [options] [filename]
261 266
262 267 Colorize a python file or stdin using ANSI color escapes and print to stdout.
263 268 If no filename is given, or if filename is -, read standard input."""
264 269
265 270 import optparse
266 271 parser = optparse.OptionParser(usage=usage_msg)
267 272 newopt = parser.add_option
268 273 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
269 274 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
270 275 help="give the color scheme to use. Currently only 'Linux'\
271 276 (default) and 'LightBG' and 'NoColor' are implemented (give without\
272 277 quotes)")
273 278
274 279 opts,args = parser.parse_args(argv)
275 280
276 281 if len(args) > 1:
277 282 parser.error("you must give at most one filename.")
278 283
279 284 if len(args) == 0:
280 285 fname = '-' # no filename given; setup to read from stdin
281 286 else:
282 287 fname = args[0]
283 288
284 289 if fname == '-':
285 290 stream = sys.stdin
286 291 else:
287 292 try:
288 293 stream = open(fname)
289 294 except IOError as msg:
290 295 print(msg, file=sys.stderr)
291 296 sys.exit(1)
292 297
293 298 parser = Parser()
294 299
295 300 # we need nested try blocks because pre-2.5 python doesn't support unified
296 301 # try-except-finally
297 302 try:
298 303 try:
299 304 # write colorized version to stdout
300 305 parser.format(stream.read(),scheme=opts.scheme_name)
301 306 except IOError as msg:
302 307 # if user reads through a pager and quits, don't print traceback
303 308 if msg.args != (32,'Broken pipe'):
304 309 raise
305 310 finally:
306 311 if stream is not sys.stdin:
307 312 stream.close() # in case a non-handled exception happened above
308 313
309 314 if __name__ == "__main__":
310 315 main()
@@ -1,173 +1,179 b''
1 1 # encoding: utf-8
2 2 """
3 3 IO capturing utilities.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2013 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 from __future__ import print_function, absolute_import
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 import sys
19 from io import StringIO
19
20 from IPython.utils.py3compat import PY3
21
22 if PY3:
23 from io import StringIO
24 else:
25 from StringIO import StringIO
20 26
21 27 #-----------------------------------------------------------------------------
22 28 # Classes and functions
23 29 #-----------------------------------------------------------------------------
24 30
25 31
26 32 class RichOutput(object):
27 33 def __init__(self, source="", data=None, metadata=None):
28 34 self.source = source
29 35 self.data = data or {}
30 36 self.metadata = metadata or {}
31 37
32 38 def display(self):
33 39 from IPython.display import publish_display_data
34 40 publish_display_data(self.source, self.data, self.metadata)
35 41
36 42 def _repr_mime_(self, mime):
37 43 if mime not in self.data:
38 44 return
39 45 data = self.data[mime]
40 46 if mime in self.metadata:
41 47 return data, self.metadata[mime]
42 48 else:
43 49 return data
44 50
45 51 def _repr_html_(self):
46 52 return self._repr_mime_("text/html")
47 53
48 54 def _repr_latex_(self):
49 55 return self._repr_mime_("text/latex")
50 56
51 57 def _repr_json_(self):
52 58 return self._repr_mime_("application/json")
53 59
54 60 def _repr_javascript_(self):
55 61 return self._repr_mime_("application/javascript")
56 62
57 63 def _repr_png_(self):
58 64 return self._repr_mime_("image/png")
59 65
60 66 def _repr_jpeg_(self):
61 67 return self._repr_mime_("image/jpeg")
62 68
63 69 def _repr_svg_(self):
64 70 return self._repr_mime_("image/svg+xml")
65 71
66 72
67 73 class CapturedIO(object):
68 74 """Simple object for containing captured stdout/err and rich display StringIO objects
69 75
70 76 Each instance `c` has three attributes:
71 77
72 78 - ``c.stdout`` : standard output as a string
73 79 - ``c.stderr`` : standard error as a string
74 80 - ``c.outputs``: a list of rich display outputs
75 81
76 82 Additionally, there's a ``c.show()`` method which will print all of the
77 83 above in the same order, and can be invoked simply via ``c()``.
78 84 """
79 85
80 86 def __init__(self, stdout, stderr, outputs=None):
81 87 self._stdout = stdout
82 88 self._stderr = stderr
83 89 if outputs is None:
84 90 outputs = []
85 91 self._outputs = outputs
86 92
87 93 def __str__(self):
88 94 return self.stdout
89 95
90 96 @property
91 97 def stdout(self):
92 98 "Captured standard output"
93 99 if not self._stdout:
94 100 return ''
95 101 return self._stdout.getvalue()
96 102
97 103 @property
98 104 def stderr(self):
99 105 "Captured standard error"
100 106 if not self._stderr:
101 107 return ''
102 108 return self._stderr.getvalue()
103 109
104 110 @property
105 111 def outputs(self):
106 112 """A list of the captured rich display outputs, if any.
107 113
108 114 If you have a CapturedIO object ``c``, these can be displayed in IPython
109 115 using::
110 116
111 117 from IPython.display import display
112 118 for o in c.outputs:
113 119 display(o)
114 120 """
115 121 return [ RichOutput(s, d, md) for s, d, md in self._outputs ]
116 122
117 123 def show(self):
118 124 """write my output to sys.stdout/err as appropriate"""
119 125 sys.stdout.write(self.stdout)
120 126 sys.stderr.write(self.stderr)
121 127 sys.stdout.flush()
122 128 sys.stderr.flush()
123 129 for source, data, metadata in self._outputs:
124 130 RichOutput(source, data, metadata).display()
125 131
126 132 __call__ = show
127 133
128 134
129 135 class capture_output(object):
130 136 """context manager for capturing stdout/err"""
131 137 stdout = True
132 138 stderr = True
133 139 display = True
134 140
135 141 def __init__(self, stdout=True, stderr=True, display=True):
136 142 self.stdout = stdout
137 143 self.stderr = stderr
138 144 self.display = display
139 145 self.shell = None
140 146
141 147 def __enter__(self):
142 148 from IPython.core.getipython import get_ipython
143 149 from IPython.core.displaypub import CapturingDisplayPublisher
144 150
145 151 self.sys_stdout = sys.stdout
146 152 self.sys_stderr = sys.stderr
147 153
148 154 if self.display:
149 155 self.shell = get_ipython()
150 156 if self.shell is None:
151 157 self.save_display_pub = None
152 158 self.display = False
153 159
154 160 stdout = stderr = outputs = None
155 161 if self.stdout:
156 162 stdout = sys.stdout = StringIO()
157 163 if self.stderr:
158 164 stderr = sys.stderr = StringIO()
159 165 if self.display:
160 166 self.save_display_pub = self.shell.display_pub
161 167 self.shell.display_pub = CapturingDisplayPublisher()
162 168 outputs = self.shell.display_pub.outputs
163 169
164 170
165 171 return CapturedIO(stdout, stderr, outputs)
166 172
167 173 def __exit__(self, exc_type, exc_value, traceback):
168 174 sys.stdout = self.sys_stdout
169 175 sys.stderr = self.sys_stderr
170 176 if self.display and self.shell:
171 177 self.shell.display_pub = self.save_display_pub
172 178
173 179
@@ -1,86 +1,90 b''
1 1 # encoding: utf-8
2 2 """Tests for io.py"""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2008-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 import sys
17 17
18 from io import StringIO
19 18 from subprocess import Popen, PIPE
20 19 import unittest
21 20
22 21 import nose.tools as nt
23 22
24 23 from IPython.utils.io import Tee, capture_output
25 from IPython.utils.py3compat import doctest_refactor_print
24 from IPython.utils.py3compat import doctest_refactor_print, PY3
25
26 if PY3:
27 from io import StringIO
28 else:
29 from StringIO import StringIO
26 30
27 31 #-----------------------------------------------------------------------------
28 32 # Tests
29 33 #-----------------------------------------------------------------------------
30 34
31 35
32 36 def test_tee_simple():
33 37 "Very simple check with stdout only"
34 38 chan = StringIO()
35 39 text = 'Hello'
36 40 tee = Tee(chan, channel='stdout')
37 41 print(text, file=chan)
38 42 nt.assert_equal(chan.getvalue(), text+"\n")
39 43
40 44
41 45 class TeeTestCase(unittest.TestCase):
42 46
43 47 def tchan(self, channel, check='close'):
44 48 trap = StringIO()
45 49 chan = StringIO()
46 50 text = 'Hello'
47 51
48 52 std_ori = getattr(sys, channel)
49 53 setattr(sys, channel, trap)
50 54
51 55 tee = Tee(chan, channel=channel)
52 56 print(text, end='', file=chan)
53 57 setattr(sys, channel, std_ori)
54 58 trap_val = trap.getvalue()
55 59 nt.assert_equal(chan.getvalue(), text)
56 60 if check=='close':
57 61 tee.close()
58 62 else:
59 63 del tee
60 64
61 65 def test(self):
62 66 for chan in ['stdout', 'stderr']:
63 67 for check in ['close', 'del']:
64 68 self.tchan(chan, check)
65 69
66 70 def test_io_init():
67 71 """Test that io.stdin/out/err exist at startup"""
68 72 for name in ('stdin', 'stdout', 'stderr'):
69 73 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
70 74 p = Popen([sys.executable, '-c', cmd],
71 75 stdout=PIPE)
72 76 p.wait()
73 77 classname = p.stdout.read().strip().decode('ascii')
74 78 # __class__ is a reference to the class object in Python 3, so we can't
75 79 # just test for string equality.
76 80 assert 'IPython.utils.io.IOStream' in classname, classname
77 81
78 82 def test_capture_output():
79 83 """capture_output() context works"""
80 84
81 85 with capture_output() as io:
82 86 print('hi, stdout')
83 87 print('hi, stderr', file=sys.stderr)
84 88
85 89 nt.assert_equal(io.stdout, 'hi, stdout\n')
86 90 nt.assert_equal(io.stderr, 'hi, stderr\n')
General Comments 0
You need to be logged in to leave comments. Login now