##// END OF EJS Templates
Compatibility with traitlets 5.0....
Matthias Bussonnier -
Show More
@@ -1,126 +1,126 b''
1 1 # http://travis-ci.org/#!/ipython/ipython
2 2 language: python
3 3 os: linux
4 4
5 5 addons:
6 6 apt:
7 7 packages:
8 8 - graphviz
9 9
10 10 python:
11 11 - 3.6
12 12
13 13 env:
14 14 global:
15 15 - PATH=$TRAVIS_BUILD_DIR/pandoc:$PATH
16 16
17 17 group: edge
18 18
19 19 before_install:
20 20 - |
21 21 # install Python on macOS
22 22 if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
23 23 env | sort
24 24 if ! which python$TRAVIS_PYTHON_VERSION; then
25 25 HOMEBREW_NO_AUTO_UPDATE=1 brew tap minrk/homebrew-python-frameworks
26 26 HOMEBREW_NO_AUTO_UPDATE=1 brew cask install python-framework-${TRAVIS_PYTHON_VERSION/./}
27 27 fi
28 28 python3 -m pip install virtualenv
29 29 python3 -m virtualenv -p $(which python$TRAVIS_PYTHON_VERSION) ~/travis-env
30 30 source ~/travis-env/bin/activate
31 31 fi
32 32 - python --version
33 33
34 34 install:
35 35 - pip install pip --upgrade
36 36 - pip install setuptools --upgrade
37 37 - if [[ "$TRAVIS_PYTHON_VERSION" == "3.6" ]]; then
38 38 echo "for the tiem being still test on 3.6";
39 39 sed -ibkp s/7/6/g setup.py;
40 40 git diff;
41 41 fi
42 42 - pip install -e file://$PWD#egg=ipython[test] --upgrade
43 43 - pip install trio curio --upgrade --upgrade-strategy eager
44 - pip install pytest 'matplotlib !=3.2.0' mypy
44 - pip install 'pytest<6' 'matplotlib !=3.2.0' mypy
45 45 - pip install codecov check-manifest --upgrade
46 46 - pip install mypy
47 47 - |
48 48 if [[ "$MASTER_DEPENDENCIES" == "True" ]]; then
49 49 pip install git+https://github.com/ipython/traitlets#egg=traitlets --force
50 50 fi
51 51
52 52
53 53 script:
54 54 - check-manifest
55 55 - |
56 56 if [[ "$TRAVIS_PYTHON_VERSION" == "nightly" ]]; then
57 57 # on nightly fake parso known the grammar
58 58 cp /home/travis/virtualenv/python3.9-dev/lib/python3.9/site-packages/parso/python/grammar38.txt /home/travis/virtualenv/python3.9-dev/lib/python3.9/site-packages/parso/python/grammar39.txt
59 59 fi
60 60 - cd /tmp && iptest --coverage xml && cd -
61 61 - pytest IPython
62 62 - mypy IPython/terminal/ptutils.py
63 63 - mypy IPython/core/c*.py
64 64 # On the latest Python (on Linux) only, make sure that the docs build.
65 65 - |
66 66 if [[ "$TRAVIS_PYTHON_VERSION" == "3.7" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
67 67 pip install -r docs/requirements.txt
68 68 python tools/fixup_whats_new_pr.py
69 69 make -C docs/ html SPHINXOPTS="-W"
70 70 fi
71 71
72 72 after_success:
73 73 - cp /tmp/ipy_coverage.xml ./
74 74 - cp /tmp/.coverage ./
75 75 - codecov
76 76
77 77 matrix:
78 78 include:
79 79 - arch: amd64
80 80 python: "3.6"
81 81 dist: xenial
82 82 - arch: amd64
83 83 python: "3.7"
84 84 dist: xenial
85 85 - arch: amd64
86 86 python: "3.8"
87 87 dist: xenial
88 88 - arch: amd64
89 89 python: "nightly"
90 90 dist: xenial
91 91 - arch: arm64
92 92 python: "nightly"
93 93 dist: bionic
94 94 env: ARM64=True
95 95 - os: osx
96 96 language: generic
97 97 python: 3.6
98 98 env: TRAVIS_PYTHON_VERSION=3.6
99 99 - os: osx
100 100 language: generic
101 101 python: 3.7
102 102 env: TRAVIS_PYTHON_VERSION=3.7
103 103 - arch: amd64
104 104 python: "3.8"
105 105 env: MASTER_DEPENDENCIES=True
106 106 allow_failures:
107 107 - python: nightly
108 108
109 109 before_deploy:
110 110 - rm -rf dist/
111 111 - python setup.py sdist
112 112 - python setup.py bdist_wheel
113 113
114 114 deploy:
115 115 provider: releases
116 116 api_key:
117 117 secure: Y/Ae9tYs5aoBU8bDjN2YrwGG6tCbezj/h3Lcmtx8HQavSbBgXnhnZVRb2snOKD7auqnqjfT/7QMm4ZyKvaOEgyggGktKqEKYHC8KOZ7yp8I5/UMDtk6j9TnXpSqqBxPiud4MDV76SfRYEQiaDoG4tGGvSfPJ9KcNjKrNvSyyxns=
118 118 file: dist/*
119 119 file_glob: true
120 120 cleanup: false
121 121 on:
122 122 repo: ipython/ipython
123 123 all_branches: true # Backports are released from e.g. 5.x branch
124 124 tags: true
125 125 python: 3.6 # Any version should work, but we only need one
126 126 condition: $TRAVIS_OS_NAME = "linux"
@@ -1,1024 +1,1024 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
10 10 # Copyright (c) IPython Development Team.
11 11 # Distributed under the terms of the Modified BSD License.
12 12
13 13 import abc
14 14 import json
15 15 import sys
16 16 import traceback
17 17 import warnings
18 18 from io import StringIO
19 19
20 20 from decorator import decorator
21 21
22 22 from traitlets.config.configurable import Configurable
23 23 from .getipython import get_ipython
24 24 from ..utils.sentinel import Sentinel
25 25 from ..utils.dir2 import get_real_method
26 26 from ..lib import pretty
27 27 from traitlets import (
28 28 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
29 29 ForwardDeclaredInstance,
30 30 default, observe,
31 31 )
32 32
33 33
34 34 class DisplayFormatter(Configurable):
35 35
36 36 active_types = List(Unicode(),
37 37 help="""List of currently active mime-types to display.
38 38 You can use this to set a white-list for formats to display.
39 39
40 40 Most users will not need to change this value.
41 41 """).tag(config=True)
42 42
43 43 @default('active_types')
44 44 def _active_types_default(self):
45 45 return self.format_types
46 46
47 47 @observe('active_types')
48 48 def _active_types_changed(self, change):
49 49 for key, formatter in self.formatters.items():
50 50 if key in change['new']:
51 51 formatter.enabled = True
52 52 else:
53 53 formatter.enabled = False
54 54
55 55 ipython_display_formatter = ForwardDeclaredInstance('FormatterABC')
56 56 @default('ipython_display_formatter')
57 57 def _default_formatter(self):
58 58 return IPythonDisplayFormatter(parent=self)
59 59
60 60 mimebundle_formatter = ForwardDeclaredInstance('FormatterABC')
61 61 @default('mimebundle_formatter')
62 62 def _default_mime_formatter(self):
63 63 return MimeBundleFormatter(parent=self)
64 64
65 65 # A dict of formatter whose keys are format types (MIME types) and whose
66 66 # values are subclasses of BaseFormatter.
67 67 formatters = Dict()
68 68 @default('formatters')
69 69 def _formatters_default(self):
70 70 """Activate the default formatters."""
71 71 formatter_classes = [
72 72 PlainTextFormatter,
73 73 HTMLFormatter,
74 74 MarkdownFormatter,
75 75 SVGFormatter,
76 76 PNGFormatter,
77 77 PDFFormatter,
78 78 JPEGFormatter,
79 79 LatexFormatter,
80 80 JSONFormatter,
81 81 JavascriptFormatter
82 82 ]
83 83 d = {}
84 84 for cls in formatter_classes:
85 85 f = cls(parent=self)
86 86 d[f.format_type] = f
87 87 return d
88 88
89 89 def format(self, obj, include=None, exclude=None):
90 90 """Return a format data dict for an object.
91 91
92 92 By default all format types will be computed.
93 93
94 94 The following MIME types are usually implemented:
95 95
96 96 * text/plain
97 97 * text/html
98 98 * text/markdown
99 99 * text/latex
100 100 * application/json
101 101 * application/javascript
102 102 * application/pdf
103 103 * image/png
104 104 * image/jpeg
105 105 * image/svg+xml
106 106
107 107 Parameters
108 108 ----------
109 109 obj : object
110 110 The Python object whose format data will be computed.
111 111 include : list, tuple or set; optional
112 112 A list of format type strings (MIME types) to include in the
113 113 format data dict. If this is set *only* the format types included
114 114 in this list will be computed.
115 115 exclude : list, tuple or set; optional
116 116 A list of format type string (MIME types) to exclude in the format
117 117 data dict. If this is set all format types will be computed,
118 118 except for those included in this argument.
119 119 Mimetypes present in exclude will take precedence over the ones in include
120 120
121 121 Returns
122 122 -------
123 123 (format_dict, metadata_dict) : tuple of two dicts
124 124
125 125 format_dict is a dictionary of key/value pairs, one of each format that was
126 126 generated for the object. The keys are the format types, which
127 127 will usually be MIME type strings and the values and JSON'able
128 128 data structure containing the raw data for the representation in
129 129 that format.
130 130
131 131 metadata_dict is a dictionary of metadata about each mime-type output.
132 132 Its keys will be a strict subset of the keys in format_dict.
133 133
134 134 Notes
135 135 -----
136 136
137 137 If an object implement `_repr_mimebundle_` as well as various
138 138 `_repr_*_`, the data returned by `_repr_mimebundle_` will take
139 139 precedence and the corresponding `_repr_*_` for this mimetype will
140 140 not be called.
141 141
142 142 """
143 143 format_dict = {}
144 144 md_dict = {}
145 145
146 146 if self.ipython_display_formatter(obj):
147 147 # object handled itself, don't proceed
148 148 return {}, {}
149 149
150 150 format_dict, md_dict = self.mimebundle_formatter(obj, include=include, exclude=exclude)
151 151
152 152 if format_dict or md_dict:
153 153 if include:
154 154 format_dict = {k:v for k,v in format_dict.items() if k in include}
155 155 md_dict = {k:v for k,v in md_dict.items() if k in include}
156 156 if exclude:
157 157 format_dict = {k:v for k,v in format_dict.items() if k not in exclude}
158 158 md_dict = {k:v for k,v in md_dict.items() if k not in exclude}
159 159
160 160 for format_type, formatter in self.formatters.items():
161 161 if format_type in format_dict:
162 162 # already got it from mimebundle, maybe don't render again.
163 163 # exception: manually registered per-mime renderer
164 164 # check priority:
165 165 # 1. user-registered per-mime formatter
166 166 # 2. mime-bundle (user-registered or repr method)
167 167 # 3. default per-mime formatter (e.g. repr method)
168 168 try:
169 169 formatter.lookup(obj)
170 170 except KeyError:
171 171 # no special formatter, use mime-bundle-provided value
172 172 continue
173 173 if include and format_type not in include:
174 174 continue
175 175 if exclude and format_type in exclude:
176 176 continue
177 177
178 178 md = None
179 179 try:
180 180 data = formatter(obj)
181 181 except:
182 182 # FIXME: log the exception
183 183 raise
184 184
185 185 # formatters can return raw data or (data, metadata)
186 186 if isinstance(data, tuple) and len(data) == 2:
187 187 data, md = data
188 188
189 189 if data is not None:
190 190 format_dict[format_type] = data
191 191 if md is not None:
192 192 md_dict[format_type] = md
193 193 return format_dict, md_dict
194 194
195 195 @property
196 196 def format_types(self):
197 197 """Return the format types (MIME types) of the active formatters."""
198 198 return list(self.formatters.keys())
199 199
200 200
201 201 #-----------------------------------------------------------------------------
202 202 # Formatters for specific format types (text, html, svg, etc.)
203 203 #-----------------------------------------------------------------------------
204 204
205 205
206 206 def _safe_repr(obj):
207 207 """Try to return a repr of an object
208 208
209 209 always returns a string, at least.
210 210 """
211 211 try:
212 212 return repr(obj)
213 213 except Exception as e:
214 214 return "un-repr-able object (%r)" % e
215 215
216 216
217 217 class FormatterWarning(UserWarning):
218 218 """Warning class for errors in formatters"""
219 219
220 220 @decorator
221 221 def catch_format_error(method, self, *args, **kwargs):
222 222 """show traceback on failed format call"""
223 223 try:
224 224 r = method(self, *args, **kwargs)
225 225 except NotImplementedError:
226 226 # don't warn on NotImplementedErrors
227 227 return self._check_return(None, args[0])
228 228 except Exception:
229 229 exc_info = sys.exc_info()
230 230 ip = get_ipython()
231 231 if ip is not None:
232 232 ip.showtraceback(exc_info)
233 233 else:
234 234 traceback.print_exception(*exc_info)
235 235 return self._check_return(None, args[0])
236 236 return self._check_return(r, args[0])
237 237
238 238
239 239 class FormatterABC(metaclass=abc.ABCMeta):
240 240 """ Abstract base class for Formatters.
241 241
242 242 A formatter is a callable class that is responsible for computing the
243 243 raw format data for a particular format type (MIME type). For example,
244 244 an HTML formatter would have a format type of `text/html` and would return
245 245 the HTML representation of the object when called.
246 246 """
247 247
248 248 # The format type of the data returned, usually a MIME type.
249 249 format_type = 'text/plain'
250 250
251 251 # Is the formatter enabled...
252 252 enabled = True
253 253
254 254 @abc.abstractmethod
255 255 def __call__(self, obj):
256 256 """Return a JSON'able representation of the object.
257 257
258 258 If the object cannot be formatted by this formatter,
259 259 warn and return None.
260 260 """
261 261 return repr(obj)
262 262
263 263
264 264 def _mod_name_key(typ):
265 265 """Return a (__module__, __name__) tuple for a type.
266 266
267 267 Used as key in Formatter.deferred_printers.
268 268 """
269 269 module = getattr(typ, '__module__', None)
270 270 name = getattr(typ, '__name__', None)
271 271 return (module, name)
272 272
273 273
274 274 def _get_type(obj):
275 275 """Return the type of an instance (old and new-style)"""
276 276 return getattr(obj, '__class__', None) or type(obj)
277 277
278 278
279 279 _raise_key_error = Sentinel('_raise_key_error', __name__,
280 280 """
281 281 Special value to raise a KeyError
282 282
283 283 Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
284 284 """)
285 285
286 286
287 287 class BaseFormatter(Configurable):
288 288 """A base formatter class that is configurable.
289 289
290 290 This formatter should usually be used as the base class of all formatters.
291 291 It is a traited :class:`Configurable` class and includes an extensible
292 292 API for users to determine how their objects are formatted. The following
293 293 logic is used to find a function to format an given object.
294 294
295 295 1. The object is introspected to see if it has a method with the name
296 296 :attr:`print_method`. If is does, that object is passed to that method
297 297 for formatting.
298 298 2. If no print method is found, three internal dictionaries are consulted
299 299 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
300 300 and :attr:`deferred_printers`.
301 301
302 302 Users should use these dictionaries to register functions that will be
303 303 used to compute the format data for their objects (if those objects don't
304 304 have the special print methods). The easiest way of using these
305 305 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
306 306 methods.
307 307
308 308 If no function/callable is found to compute the format data, ``None`` is
309 309 returned and this format type is not used.
310 310 """
311 311
312 312 format_type = Unicode('text/plain')
313 313 _return_type = str
314 314
315 315 enabled = Bool(True).tag(config=True)
316 316
317 317 print_method = ObjectName('__repr__')
318 318
319 319 # The singleton printers.
320 320 # Maps the IDs of the builtin singleton objects to the format functions.
321 321 singleton_printers = Dict().tag(config=True)
322 322
323 323 # The type-specific printers.
324 324 # Map type objects to the format functions.
325 325 type_printers = Dict().tag(config=True)
326 326
327 327 # The deferred-import type-specific printers.
328 328 # Map (modulename, classname) pairs to the format functions.
329 329 deferred_printers = Dict().tag(config=True)
330 330
331 331 @catch_format_error
332 332 def __call__(self, obj):
333 333 """Compute the format for an object."""
334 334 if self.enabled:
335 335 # lookup registered printer
336 336 try:
337 337 printer = self.lookup(obj)
338 338 except KeyError:
339 339 pass
340 340 else:
341 341 return printer(obj)
342 342 # Finally look for special method names
343 343 method = get_real_method(obj, self.print_method)
344 344 if method is not None:
345 345 return method()
346 346 return None
347 347 else:
348 348 return None
349 349
350 350 def __contains__(self, typ):
351 351 """map in to lookup_by_type"""
352 352 try:
353 353 self.lookup_by_type(typ)
354 354 except KeyError:
355 355 return False
356 356 else:
357 357 return True
358 358
359 359 def _check_return(self, r, obj):
360 360 """Check that a return value is appropriate
361 361
362 362 Return the value if so, None otherwise, warning if invalid.
363 363 """
364 364 if r is None or isinstance(r, self._return_type) or \
365 365 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
366 366 return r
367 367 else:
368 368 warnings.warn(
369 369 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
370 370 (self.format_type, type(r), self._return_type, _safe_repr(obj)),
371 371 FormatterWarning
372 372 )
373 373
374 374 def lookup(self, obj):
375 375 """Look up the formatter for a given instance.
376 376
377 377 Parameters
378 378 ----------
379 379 obj : object instance
380 380
381 381 Returns
382 382 -------
383 383 f : callable
384 384 The registered formatting callable for the type.
385 385
386 386 Raises
387 387 ------
388 388 KeyError if the type has not been registered.
389 389 """
390 390 # look for singleton first
391 391 obj_id = id(obj)
392 392 if obj_id in self.singleton_printers:
393 393 return self.singleton_printers[obj_id]
394 394 # then lookup by type
395 395 return self.lookup_by_type(_get_type(obj))
396 396
397 397 def lookup_by_type(self, typ):
398 398 """Look up the registered formatter for a type.
399 399
400 400 Parameters
401 401 ----------
402 402 typ : type or '__module__.__name__' string for a type
403 403
404 404 Returns
405 405 -------
406 406 f : callable
407 407 The registered formatting callable for the type.
408 408
409 409 Raises
410 410 ------
411 411 KeyError if the type has not been registered.
412 412 """
413 413 if isinstance(typ, str):
414 414 typ_key = tuple(typ.rsplit('.',1))
415 415 if typ_key not in self.deferred_printers:
416 416 # We may have it cached in the type map. We will have to
417 417 # iterate over all of the types to check.
418 418 for cls in self.type_printers:
419 419 if _mod_name_key(cls) == typ_key:
420 420 return self.type_printers[cls]
421 421 else:
422 422 return self.deferred_printers[typ_key]
423 423 else:
424 424 for cls in pretty._get_mro(typ):
425 425 if cls in self.type_printers or self._in_deferred_types(cls):
426 426 return self.type_printers[cls]
427 427
428 428 # If we have reached here, the lookup failed.
429 429 raise KeyError("No registered printer for {0!r}".format(typ))
430 430
431 431 def for_type(self, typ, func=None):
432 432 """Add a format function for a given type.
433 433
434 434 Parameters
435 -----------
435 ----------
436 436 typ : type or '__module__.__name__' string for a type
437 437 The class of the object that will be formatted using `func`.
438 438 func : callable
439 439 A callable for computing the format data.
440 440 `func` will be called with the object to be formatted,
441 441 and will return the raw data in this formatter's format.
442 442 Subclasses may use a different call signature for the
443 443 `func` argument.
444 444
445 445 If `func` is None or not specified, there will be no change,
446 446 only returning the current value.
447 447
448 448 Returns
449 449 -------
450 450 oldfunc : callable
451 451 The currently registered callable.
452 452 If you are registering a new formatter,
453 453 this will be the previous value (to enable restoring later).
454 454 """
455 455 # if string given, interpret as 'pkg.module.class_name'
456 456 if isinstance(typ, str):
457 457 type_module, type_name = typ.rsplit('.', 1)
458 458 return self.for_type_by_name(type_module, type_name, func)
459 459
460 460 try:
461 461 oldfunc = self.lookup_by_type(typ)
462 462 except KeyError:
463 463 oldfunc = None
464 464
465 465 if func is not None:
466 466 self.type_printers[typ] = func
467 467
468 468 return oldfunc
469 469
470 470 def for_type_by_name(self, type_module, type_name, func=None):
471 471 """Add a format function for a type specified by the full dotted
472 472 module and name of the type, rather than the type of the object.
473 473
474 474 Parameters
475 475 ----------
476 476 type_module : str
477 477 The full dotted name of the module the type is defined in, like
478 478 ``numpy``.
479 479 type_name : str
480 480 The name of the type (the class name), like ``dtype``
481 481 func : callable
482 482 A callable for computing the format data.
483 483 `func` will be called with the object to be formatted,
484 484 and will return the raw data in this formatter's format.
485 485 Subclasses may use a different call signature for the
486 486 `func` argument.
487 487
488 488 If `func` is None or unspecified, there will be no change,
489 489 only returning the current value.
490 490
491 491 Returns
492 492 -------
493 493 oldfunc : callable
494 494 The currently registered callable.
495 495 If you are registering a new formatter,
496 496 this will be the previous value (to enable restoring later).
497 497 """
498 498 key = (type_module, type_name)
499 499
500 500 try:
501 501 oldfunc = self.lookup_by_type("%s.%s" % key)
502 502 except KeyError:
503 503 oldfunc = None
504 504
505 505 if func is not None:
506 506 self.deferred_printers[key] = func
507 507 return oldfunc
508 508
509 509 def pop(self, typ, default=_raise_key_error):
510 510 """Pop a formatter for the given type.
511 511
512 512 Parameters
513 513 ----------
514 514 typ : type or '__module__.__name__' string for a type
515 515 default : object
516 516 value to be returned if no formatter is registered for typ.
517 517
518 518 Returns
519 519 -------
520 520 obj : object
521 521 The last registered object for the type.
522 522
523 523 Raises
524 524 ------
525 525 KeyError if the type is not registered and default is not specified.
526 526 """
527 527
528 528 if isinstance(typ, str):
529 529 typ_key = tuple(typ.rsplit('.',1))
530 530 if typ_key not in self.deferred_printers:
531 531 # We may have it cached in the type map. We will have to
532 532 # iterate over all of the types to check.
533 533 for cls in self.type_printers:
534 534 if _mod_name_key(cls) == typ_key:
535 535 old = self.type_printers.pop(cls)
536 536 break
537 537 else:
538 538 old = default
539 539 else:
540 540 old = self.deferred_printers.pop(typ_key)
541 541 else:
542 542 if typ in self.type_printers:
543 543 old = self.type_printers.pop(typ)
544 544 else:
545 545 old = self.deferred_printers.pop(_mod_name_key(typ), default)
546 546 if old is _raise_key_error:
547 547 raise KeyError("No registered value for {0!r}".format(typ))
548 548 return old
549 549
550 550 def _in_deferred_types(self, cls):
551 551 """
552 552 Check if the given class is specified in the deferred type registry.
553 553
554 554 Successful matches will be moved to the regular type registry for future use.
555 555 """
556 556 mod = getattr(cls, '__module__', None)
557 557 name = getattr(cls, '__name__', None)
558 558 key = (mod, name)
559 559 if key in self.deferred_printers:
560 560 # Move the printer over to the regular registry.
561 561 printer = self.deferred_printers.pop(key)
562 562 self.type_printers[cls] = printer
563 563 return True
564 564 return False
565 565
566 566
567 567 class PlainTextFormatter(BaseFormatter):
568 568 """The default pretty-printer.
569 569
570 570 This uses :mod:`IPython.lib.pretty` to compute the format data of
571 571 the object. If the object cannot be pretty printed, :func:`repr` is used.
572 572 See the documentation of :mod:`IPython.lib.pretty` for details on
573 573 how to write pretty printers. Here is a simple example::
574 574
575 575 def dtype_pprinter(obj, p, cycle):
576 576 if cycle:
577 577 return p.text('dtype(...)')
578 578 if hasattr(obj, 'fields'):
579 579 if obj.fields is None:
580 580 p.text(repr(obj))
581 581 else:
582 582 p.begin_group(7, 'dtype([')
583 583 for i, field in enumerate(obj.descr):
584 584 if i > 0:
585 585 p.text(',')
586 586 p.breakable()
587 587 p.pretty(field)
588 588 p.end_group(7, '])')
589 589 """
590 590
591 591 # The format type of data returned.
592 592 format_type = Unicode('text/plain')
593 593
594 594 # This subclass ignores this attribute as it always need to return
595 595 # something.
596 596 enabled = Bool(True).tag(config=False)
597 597
598 598 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
599 599 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
600 600
601 601 Set to 0 to disable truncation.
602 602 """
603 603 ).tag(config=True)
604 604
605 605 # Look for a _repr_pretty_ methods to use for pretty printing.
606 606 print_method = ObjectName('_repr_pretty_')
607 607
608 608 # Whether to pretty-print or not.
609 609 pprint = Bool(True).tag(config=True)
610 610
611 611 # Whether to be verbose or not.
612 612 verbose = Bool(False).tag(config=True)
613 613
614 614 # The maximum width.
615 615 max_width = Integer(79).tag(config=True)
616 616
617 617 # The newline character.
618 618 newline = Unicode('\n').tag(config=True)
619 619
620 620 # format-string for pprinting floats
621 621 float_format = Unicode('%r')
622 622 # setter for float precision, either int or direct format-string
623 623 float_precision = CUnicode('').tag(config=True)
624 624
625 625 @observe('float_precision')
626 626 def _float_precision_changed(self, change):
627 627 """float_precision changed, set float_format accordingly.
628 628
629 629 float_precision can be set by int or str.
630 630 This will set float_format, after interpreting input.
631 631 If numpy has been imported, numpy print precision will also be set.
632 632
633 633 integer `n` sets format to '%.nf', otherwise, format set directly.
634 634
635 635 An empty string returns to defaults (repr for float, 8 for numpy).
636 636
637 637 This parameter can be set via the '%precision' magic.
638 638 """
639 639
640 640 new = change['new']
641 641 if '%' in new:
642 642 # got explicit format string
643 643 fmt = new
644 644 try:
645 645 fmt%3.14159
646 646 except Exception as e:
647 647 raise ValueError("Precision must be int or format string, not %r"%new) from e
648 648 elif new:
649 649 # otherwise, should be an int
650 650 try:
651 651 i = int(new)
652 652 assert i >= 0
653 653 except ValueError as e:
654 654 raise ValueError("Precision must be int or format string, not %r"%new) from e
655 655 except AssertionError as e:
656 656 raise ValueError("int precision must be non-negative, not %r"%i) from e
657 657
658 658 fmt = '%%.%if'%i
659 659 if 'numpy' in sys.modules:
660 660 # set numpy precision if it has been imported
661 661 import numpy
662 662 numpy.set_printoptions(precision=i)
663 663 else:
664 664 # default back to repr
665 665 fmt = '%r'
666 666 if 'numpy' in sys.modules:
667 667 import numpy
668 668 # numpy default is 8
669 669 numpy.set_printoptions(precision=8)
670 670 self.float_format = fmt
671 671
672 672 # Use the default pretty printers from IPython.lib.pretty.
673 673 @default('singleton_printers')
674 674 def _singleton_printers_default(self):
675 675 return pretty._singleton_pprinters.copy()
676 676
677 677 @default('type_printers')
678 678 def _type_printers_default(self):
679 679 d = pretty._type_pprinters.copy()
680 680 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
681 681 return d
682 682
683 683 @default('deferred_printers')
684 684 def _deferred_printers_default(self):
685 685 return pretty._deferred_type_pprinters.copy()
686 686
687 687 #### FormatterABC interface ####
688 688
689 689 @catch_format_error
690 690 def __call__(self, obj):
691 691 """Compute the pretty representation of the object."""
692 692 if not self.pprint:
693 693 return repr(obj)
694 694 else:
695 695 stream = StringIO()
696 696 printer = pretty.RepresentationPrinter(stream, self.verbose,
697 697 self.max_width, self.newline,
698 698 max_seq_length=self.max_seq_length,
699 699 singleton_pprinters=self.singleton_printers,
700 700 type_pprinters=self.type_printers,
701 701 deferred_pprinters=self.deferred_printers)
702 702 printer.pretty(obj)
703 703 printer.flush()
704 704 return stream.getvalue()
705 705
706 706
707 707 class HTMLFormatter(BaseFormatter):
708 708 """An HTML formatter.
709 709
710 710 To define the callables that compute the HTML representation of your
711 711 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
712 712 or :meth:`for_type_by_name` methods to register functions that handle
713 713 this.
714 714
715 715 The return value of this formatter should be a valid HTML snippet that
716 716 could be injected into an existing DOM. It should *not* include the
717 717 ```<html>`` or ```<body>`` tags.
718 718 """
719 719 format_type = Unicode('text/html')
720 720
721 721 print_method = ObjectName('_repr_html_')
722 722
723 723
724 724 class MarkdownFormatter(BaseFormatter):
725 725 """A Markdown formatter.
726 726
727 727 To define the callables that compute the Markdown representation of your
728 728 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
729 729 or :meth:`for_type_by_name` methods to register functions that handle
730 730 this.
731 731
732 732 The return value of this formatter should be a valid Markdown.
733 733 """
734 734 format_type = Unicode('text/markdown')
735 735
736 736 print_method = ObjectName('_repr_markdown_')
737 737
738 738 class SVGFormatter(BaseFormatter):
739 739 """An SVG formatter.
740 740
741 741 To define the callables that compute the SVG representation of your
742 742 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
743 743 or :meth:`for_type_by_name` methods to register functions that handle
744 744 this.
745 745
746 746 The return value of this formatter should be valid SVG enclosed in
747 747 ```<svg>``` tags, that could be injected into an existing DOM. It should
748 748 *not* include the ```<html>`` or ```<body>`` tags.
749 749 """
750 750 format_type = Unicode('image/svg+xml')
751 751
752 752 print_method = ObjectName('_repr_svg_')
753 753
754 754
755 755 class PNGFormatter(BaseFormatter):
756 756 """A PNG formatter.
757 757
758 758 To define the callables that compute the PNG representation of your
759 759 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
760 760 or :meth:`for_type_by_name` methods to register functions that handle
761 761 this.
762 762
763 763 The return value of this formatter should be raw PNG data, *not*
764 764 base64 encoded.
765 765 """
766 766 format_type = Unicode('image/png')
767 767
768 768 print_method = ObjectName('_repr_png_')
769 769
770 770 _return_type = (bytes, str)
771 771
772 772
773 773 class JPEGFormatter(BaseFormatter):
774 774 """A JPEG formatter.
775 775
776 776 To define the callables that compute the JPEG representation of your
777 777 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
778 778 or :meth:`for_type_by_name` methods to register functions that handle
779 779 this.
780 780
781 781 The return value of this formatter should be raw JPEG data, *not*
782 782 base64 encoded.
783 783 """
784 784 format_type = Unicode('image/jpeg')
785 785
786 786 print_method = ObjectName('_repr_jpeg_')
787 787
788 788 _return_type = (bytes, str)
789 789
790 790
791 791 class LatexFormatter(BaseFormatter):
792 792 """A LaTeX formatter.
793 793
794 794 To define the callables that compute the LaTeX representation of your
795 795 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
796 796 or :meth:`for_type_by_name` methods to register functions that handle
797 797 this.
798 798
799 799 The return value of this formatter should be a valid LaTeX equation,
800 800 enclosed in either ```$```, ```$$``` or another LaTeX equation
801 801 environment.
802 802 """
803 803 format_type = Unicode('text/latex')
804 804
805 805 print_method = ObjectName('_repr_latex_')
806 806
807 807
808 808 class JSONFormatter(BaseFormatter):
809 809 """A JSON string formatter.
810 810
811 811 To define the callables that compute the JSONable representation of
812 812 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
813 813 or :meth:`for_type_by_name` methods to register functions that handle
814 814 this.
815 815
816 816 The return value of this formatter should be a JSONable list or dict.
817 817 JSON scalars (None, number, string) are not allowed, only dict or list containers.
818 818 """
819 819 format_type = Unicode('application/json')
820 820 _return_type = (list, dict)
821 821
822 822 print_method = ObjectName('_repr_json_')
823 823
824 824 def _check_return(self, r, obj):
825 825 """Check that a return value is appropriate
826 826
827 827 Return the value if so, None otherwise, warning if invalid.
828 828 """
829 829 if r is None:
830 830 return
831 831 md = None
832 832 if isinstance(r, tuple):
833 833 # unpack data, metadata tuple for type checking on first element
834 834 r, md = r
835 835
836 836 # handle deprecated JSON-as-string form from IPython < 3
837 837 if isinstance(r, str):
838 838 warnings.warn("JSON expects JSONable list/dict containers, not JSON strings",
839 839 FormatterWarning)
840 840 r = json.loads(r)
841 841
842 842 if md is not None:
843 843 # put the tuple back together
844 844 r = (r, md)
845 845 return super(JSONFormatter, self)._check_return(r, obj)
846 846
847 847
848 848 class JavascriptFormatter(BaseFormatter):
849 849 """A Javascript formatter.
850 850
851 851 To define the callables that compute the Javascript representation of
852 852 your objects, define a :meth:`_repr_javascript_` method or use the
853 853 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
854 854 that handle this.
855 855
856 856 The return value of this formatter should be valid Javascript code and
857 857 should *not* be enclosed in ```<script>``` tags.
858 858 """
859 859 format_type = Unicode('application/javascript')
860 860
861 861 print_method = ObjectName('_repr_javascript_')
862 862
863 863
864 864 class PDFFormatter(BaseFormatter):
865 865 """A PDF formatter.
866 866
867 867 To define the callables that compute the PDF representation of your
868 868 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
869 869 or :meth:`for_type_by_name` methods to register functions that handle
870 870 this.
871 871
872 872 The return value of this formatter should be raw PDF data, *not*
873 873 base64 encoded.
874 874 """
875 875 format_type = Unicode('application/pdf')
876 876
877 877 print_method = ObjectName('_repr_pdf_')
878 878
879 879 _return_type = (bytes, str)
880 880
881 881 class IPythonDisplayFormatter(BaseFormatter):
882 882 """An escape-hatch Formatter for objects that know how to display themselves.
883 883
884 884 To define the callables that compute the representation of your
885 885 objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
886 886 or :meth:`for_type_by_name` methods to register functions that handle
887 887 this. Unlike mime-type displays, this method should not return anything,
888 888 instead calling any appropriate display methods itself.
889 889
890 890 This display formatter has highest priority.
891 891 If it fires, no other display formatter will be called.
892 892
893 893 Prior to IPython 6.1, `_ipython_display_` was the only way to display custom mime-types
894 894 without registering a new Formatter.
895 895
896 896 IPython 6.1 introduces `_repr_mimebundle_` for displaying custom mime-types,
897 897 so `_ipython_display_` should only be used for objects that require unusual
898 898 display patterns, such as multiple display calls.
899 899 """
900 900 print_method = ObjectName('_ipython_display_')
901 901 _return_type = (type(None), bool)
902 902
903 903 @catch_format_error
904 904 def __call__(self, obj):
905 905 """Compute the format for an object."""
906 906 if self.enabled:
907 907 # lookup registered printer
908 908 try:
909 909 printer = self.lookup(obj)
910 910 except KeyError:
911 911 pass
912 912 else:
913 913 printer(obj)
914 914 return True
915 915 # Finally look for special method names
916 916 method = get_real_method(obj, self.print_method)
917 917 if method is not None:
918 918 method()
919 919 return True
920 920
921 921
922 922 class MimeBundleFormatter(BaseFormatter):
923 923 """A Formatter for arbitrary mime-types.
924 924
925 925 Unlike other `_repr_<mimetype>_` methods,
926 926 `_repr_mimebundle_` should return mime-bundle data,
927 927 either the mime-keyed `data` dictionary or the tuple `(data, metadata)`.
928 928 Any mime-type is valid.
929 929
930 930 To define the callables that compute the mime-bundle representation of your
931 931 objects, define a :meth:`_repr_mimebundle_` method or use the :meth:`for_type`
932 932 or :meth:`for_type_by_name` methods to register functions that handle
933 933 this.
934 934
935 935 .. versionadded:: 6.1
936 936 """
937 937 print_method = ObjectName('_repr_mimebundle_')
938 938 _return_type = dict
939 939
940 940 def _check_return(self, r, obj):
941 941 r = super(MimeBundleFormatter, self)._check_return(r, obj)
942 942 # always return (data, metadata):
943 943 if r is None:
944 944 return {}, {}
945 945 if not isinstance(r, tuple):
946 946 return r, {}
947 947 return r
948 948
949 949 @catch_format_error
950 950 def __call__(self, obj, include=None, exclude=None):
951 951 """Compute the format for an object.
952 952
953 953 Identical to parent's method but we pass extra parameters to the method.
954 954
955 955 Unlike other _repr_*_ `_repr_mimebundle_` should allow extra kwargs, in
956 956 particular `include` and `exclude`.
957 957 """
958 958 if self.enabled:
959 959 # lookup registered printer
960 960 try:
961 961 printer = self.lookup(obj)
962 962 except KeyError:
963 963 pass
964 964 else:
965 965 return printer(obj)
966 966 # Finally look for special method names
967 967 method = get_real_method(obj, self.print_method)
968 968
969 969 if method is not None:
970 970 return method(include=include, exclude=exclude)
971 971 return None
972 972 else:
973 973 return None
974 974
975 975
976 976 FormatterABC.register(BaseFormatter)
977 977 FormatterABC.register(PlainTextFormatter)
978 978 FormatterABC.register(HTMLFormatter)
979 979 FormatterABC.register(MarkdownFormatter)
980 980 FormatterABC.register(SVGFormatter)
981 981 FormatterABC.register(PNGFormatter)
982 982 FormatterABC.register(PDFFormatter)
983 983 FormatterABC.register(JPEGFormatter)
984 984 FormatterABC.register(LatexFormatter)
985 985 FormatterABC.register(JSONFormatter)
986 986 FormatterABC.register(JavascriptFormatter)
987 987 FormatterABC.register(IPythonDisplayFormatter)
988 988 FormatterABC.register(MimeBundleFormatter)
989 989
990 990
991 991 def format_display_data(obj, include=None, exclude=None):
992 992 """Return a format data dict for an object.
993 993
994 994 By default all format types will be computed.
995 995
996 996 Parameters
997 997 ----------
998 998 obj : object
999 999 The Python object whose format data will be computed.
1000 1000
1001 1001 Returns
1002 1002 -------
1003 1003 format_dict : dict
1004 1004 A dictionary of key/value pairs, one or each format that was
1005 1005 generated for the object. The keys are the format types, which
1006 1006 will usually be MIME type strings and the values and JSON'able
1007 1007 data structure containing the raw data for the representation in
1008 1008 that format.
1009 1009 include : list or tuple, optional
1010 1010 A list of format type strings (MIME types) to include in the
1011 1011 format data dict. If this is set *only* the format types included
1012 1012 in this list will be computed.
1013 1013 exclude : list or tuple, optional
1014 1014 A list of format type string (MIME types) to exclude in the format
1015 1015 data dict. If this is set all format types will be computed,
1016 1016 except for those included in this argument.
1017 1017 """
1018 1018 from .interactiveshell import InteractiveShell
1019 1019
1020 1020 return InteractiveShell.instance().display_formatter.format(
1021 1021 obj,
1022 1022 include,
1023 1023 exclude
1024 1024 )
@@ -1,471 +1,471 b''
1 1 """Generic testing tools.
2 2
3 3 Authors
4 4 -------
5 5 - Fernando Perez <Fernando.Perez@berkeley.edu>
6 6 """
7 7
8 8
9 9 # Copyright (c) IPython Development Team.
10 10 # Distributed under the terms of the Modified BSD License.
11 11
12 12 import os
13 13 import re
14 14 import sys
15 15 import tempfile
16 16 import unittest
17 17
18 18 from contextlib import contextmanager
19 19 from io import StringIO
20 20 from subprocess import Popen, PIPE
21 21 from unittest.mock import patch
22 22
23 23 try:
24 24 # These tools are used by parts of the runtime, so we make the nose
25 25 # dependency optional at this point. Nose is a hard dependency to run the
26 26 # test suite, but NOT to use ipython itself.
27 27 import nose.tools as nt
28 28 has_nose = True
29 29 except ImportError:
30 30 has_nose = False
31 31
32 32 from traitlets.config.loader import Config
33 33 from IPython.utils.process import get_output_error_code
34 34 from IPython.utils.text import list_strings
35 35 from IPython.utils.io import temp_pyfile, Tee
36 36 from IPython.utils import py3compat
37 37
38 38 from . import decorators as dec
39 39 from . import skipdoctest
40 40
41 41
42 42 # The docstring for full_path doctests differently on win32 (different path
43 43 # separator) so just skip the doctest there. The example remains informative.
44 44 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
45 45
46 46 @doctest_deco
47 47 def full_path(startPath,files):
48 48 """Make full paths for all the listed files, based on startPath.
49 49
50 50 Only the base part of startPath is kept, since this routine is typically
51 51 used with a script's ``__file__`` variable as startPath. The base of startPath
52 52 is then prepended to all the listed files, forming the output list.
53 53
54 54 Parameters
55 55 ----------
56 56 startPath : string
57 57 Initial path to use as the base for the results. This path is split
58 58 using os.path.split() and only its first component is kept.
59 59
60 60 files : string or list
61 61 One or more files.
62 62
63 63 Examples
64 64 --------
65 65
66 66 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
67 67 ['/foo/a.txt', '/foo/b.txt']
68 68
69 69 >>> full_path('/foo',['a.txt','b.txt'])
70 70 ['/a.txt', '/b.txt']
71 71
72 72 If a single file is given, the output is still a list::
73 73
74 74 >>> full_path('/foo','a.txt')
75 75 ['/a.txt']
76 76 """
77 77
78 78 files = list_strings(files)
79 79 base = os.path.split(startPath)[0]
80 80 return [ os.path.join(base,f) for f in files ]
81 81
82 82
83 83 def parse_test_output(txt):
84 84 """Parse the output of a test run and return errors, failures.
85 85
86 86 Parameters
87 87 ----------
88 88 txt : str
89 89 Text output of a test run, assumed to contain a line of one of the
90 90 following forms::
91 91
92 92 'FAILED (errors=1)'
93 93 'FAILED (failures=1)'
94 94 'FAILED (errors=1, failures=1)'
95 95
96 96 Returns
97 97 -------
98 98 nerr, nfail
99 99 number of errors and failures.
100 100 """
101 101
102 102 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
103 103 if err_m:
104 104 nerr = int(err_m.group(1))
105 105 nfail = 0
106 106 return nerr, nfail
107 107
108 108 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
109 109 if fail_m:
110 110 nerr = 0
111 111 nfail = int(fail_m.group(1))
112 112 return nerr, nfail
113 113
114 114 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
115 115 re.MULTILINE)
116 116 if both_m:
117 117 nerr = int(both_m.group(1))
118 118 nfail = int(both_m.group(2))
119 119 return nerr, nfail
120 120
121 121 # If the input didn't match any of these forms, assume no error/failures
122 122 return 0, 0
123 123
124 124
125 125 # So nose doesn't think this is a test
126 126 parse_test_output.__test__ = False
127 127
128 128
129 129 def default_argv():
130 130 """Return a valid default argv for creating testing instances of ipython"""
131 131
132 132 return ['--quick', # so no config file is loaded
133 133 # Other defaults to minimize side effects on stdout
134 134 '--colors=NoColor', '--no-term-title','--no-banner',
135 135 '--autocall=0']
136 136
137 137
138 138 def default_config():
139 139 """Return a config object with good defaults for testing."""
140 140 config = Config()
141 141 config.TerminalInteractiveShell.colors = 'NoColor'
142 142 config.TerminalTerminalInteractiveShell.term_title = False,
143 143 config.TerminalInteractiveShell.autocall = 0
144 144 f = tempfile.NamedTemporaryFile(suffix=u'test_hist.sqlite', delete=False)
145 145 config.HistoryManager.hist_file = f.name
146 146 f.close()
147 147 config.HistoryManager.db_cache_size = 10000
148 148 return config
149 149
150 150
151 151 def get_ipython_cmd(as_string=False):
152 152 """
153 153 Return appropriate IPython command line name. By default, this will return
154 154 a list that can be used with subprocess.Popen, for example, but passing
155 155 `as_string=True` allows for returning the IPython command as a string.
156 156
157 157 Parameters
158 158 ----------
159 159 as_string: bool
160 160 Flag to allow to return the command as a string.
161 161 """
162 162 ipython_cmd = [sys.executable, "-m", "IPython"]
163 163
164 164 if as_string:
165 165 ipython_cmd = " ".join(ipython_cmd)
166 166
167 167 return ipython_cmd
168 168
169 169 def ipexec(fname, options=None, commands=()):
170 170 """Utility to call 'ipython filename'.
171 171
172 172 Starts IPython with a minimal and safe configuration to make startup as fast
173 173 as possible.
174 174
175 175 Note that this starts IPython in a subprocess!
176 176
177 177 Parameters
178 178 ----------
179 179 fname : str
180 180 Name of file to be executed (should have .py or .ipy extension).
181 181
182 182 options : optional, list
183 183 Extra command-line flags to be passed to IPython.
184 184
185 185 commands : optional, list
186 186 Commands to send in on stdin
187 187
188 188 Returns
189 189 -------
190 190 ``(stdout, stderr)`` of ipython subprocess.
191 191 """
192 192 if options is None: options = []
193 193
194 194 cmdargs = default_argv() + options
195 195
196 196 test_dir = os.path.dirname(__file__)
197 197
198 198 ipython_cmd = get_ipython_cmd()
199 199 # Absolute path for filename
200 200 full_fname = os.path.join(test_dir, fname)
201 full_cmd = ipython_cmd + cmdargs + [full_fname]
201 full_cmd = ipython_cmd + cmdargs + ['--', full_fname]
202 202 env = os.environ.copy()
203 203 # FIXME: ignore all warnings in ipexec while we have shims
204 204 # should we keep suppressing warnings here, even after removing shims?
205 205 env['PYTHONWARNINGS'] = 'ignore'
206 206 # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
207 207 for k, v in env.items():
208 208 # Debug a bizarre failure we've seen on Windows:
209 209 # TypeError: environment can only contain strings
210 210 if not isinstance(v, str):
211 211 print(k, v)
212 212 p = Popen(full_cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, env=env)
213 213 out, err = p.communicate(input=py3compat.encode('\n'.join(commands)) or None)
214 214 out, err = py3compat.decode(out), py3compat.decode(err)
215 215 # `import readline` causes 'ESC[?1034h' to be output sometimes,
216 216 # so strip that out before doing comparisons
217 217 if out:
218 218 out = re.sub(r'\x1b\[[^h]+h', '', out)
219 219 return out, err
220 220
221 221
222 222 def ipexec_validate(fname, expected_out, expected_err='',
223 223 options=None, commands=()):
224 224 """Utility to call 'ipython filename' and validate output/error.
225 225
226 226 This function raises an AssertionError if the validation fails.
227 227
228 228 Note that this starts IPython in a subprocess!
229 229
230 230 Parameters
231 231 ----------
232 232 fname : str
233 233 Name of the file to be executed (should have .py or .ipy extension).
234 234
235 235 expected_out : str
236 236 Expected stdout of the process.
237 237
238 238 expected_err : optional, str
239 239 Expected stderr of the process.
240 240
241 241 options : optional, list
242 242 Extra command-line flags to be passed to IPython.
243 243
244 244 Returns
245 245 -------
246 246 None
247 247 """
248 248
249 249 import nose.tools as nt
250 250
251 251 out, err = ipexec(fname, options, commands)
252 252 #print 'OUT', out # dbg
253 253 #print 'ERR', err # dbg
254 254 # If there are any errors, we must check those before stdout, as they may be
255 255 # more informative than simply having an empty stdout.
256 256 if err:
257 257 if expected_err:
258 258 nt.assert_equal("\n".join(err.strip().splitlines()), "\n".join(expected_err.strip().splitlines()))
259 259 else:
260 260 raise ValueError('Running file %r produced error: %r' %
261 261 (fname, err))
262 262 # If no errors or output on stderr was expected, match stdout
263 263 nt.assert_equal("\n".join(out.strip().splitlines()), "\n".join(expected_out.strip().splitlines()))
264 264
265 265
266 266 class TempFileMixin(unittest.TestCase):
267 267 """Utility class to create temporary Python/IPython files.
268 268
269 269 Meant as a mixin class for test cases."""
270 270
271 271 def mktmp(self, src, ext='.py'):
272 272 """Make a valid python temp file."""
273 273 fname = temp_pyfile(src, ext)
274 274 if not hasattr(self, 'tmps'):
275 275 self.tmps=[]
276 276 self.tmps.append(fname)
277 277 self.fname = fname
278 278
279 279 def tearDown(self):
280 280 # If the tmpfile wasn't made because of skipped tests, like in
281 281 # win32, there's nothing to cleanup.
282 282 if hasattr(self, 'tmps'):
283 283 for fname in self.tmps:
284 284 # If the tmpfile wasn't made because of skipped tests, like in
285 285 # win32, there's nothing to cleanup.
286 286 try:
287 287 os.unlink(fname)
288 288 except:
289 289 # On Windows, even though we close the file, we still can't
290 290 # delete it. I have no clue why
291 291 pass
292 292
293 293 def __enter__(self):
294 294 return self
295 295
296 296 def __exit__(self, exc_type, exc_value, traceback):
297 297 self.tearDown()
298 298
299 299
300 300 pair_fail_msg = ("Testing {0}\n\n"
301 301 "In:\n"
302 302 " {1!r}\n"
303 303 "Expected:\n"
304 304 " {2!r}\n"
305 305 "Got:\n"
306 306 " {3!r}\n")
307 307 def check_pairs(func, pairs):
308 308 """Utility function for the common case of checking a function with a
309 309 sequence of input/output pairs.
310 310
311 311 Parameters
312 312 ----------
313 313 func : callable
314 314 The function to be tested. Should accept a single argument.
315 315 pairs : iterable
316 316 A list of (input, expected_output) tuples.
317 317
318 318 Returns
319 319 -------
320 320 None. Raises an AssertionError if any output does not match the expected
321 321 value.
322 322 """
323 323 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
324 324 for inp, expected in pairs:
325 325 out = func(inp)
326 326 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
327 327
328 328
329 329 MyStringIO = StringIO
330 330
331 331 _re_type = type(re.compile(r''))
332 332
333 333 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
334 334 -------
335 335 {2!s}
336 336 -------
337 337 """
338 338
339 339 class AssertPrints(object):
340 340 """Context manager for testing that code prints certain text.
341 341
342 342 Examples
343 343 --------
344 344 >>> with AssertPrints("abc", suppress=False):
345 345 ... print("abcd")
346 346 ... print("def")
347 347 ...
348 348 abcd
349 349 def
350 350 """
351 351 def __init__(self, s, channel='stdout', suppress=True):
352 352 self.s = s
353 353 if isinstance(self.s, (str, _re_type)):
354 354 self.s = [self.s]
355 355 self.channel = channel
356 356 self.suppress = suppress
357 357
358 358 def __enter__(self):
359 359 self.orig_stream = getattr(sys, self.channel)
360 360 self.buffer = MyStringIO()
361 361 self.tee = Tee(self.buffer, channel=self.channel)
362 362 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
363 363
364 364 def __exit__(self, etype, value, traceback):
365 365 try:
366 366 if value is not None:
367 367 # If an error was raised, don't check anything else
368 368 return False
369 369 self.tee.flush()
370 370 setattr(sys, self.channel, self.orig_stream)
371 371 printed = self.buffer.getvalue()
372 372 for s in self.s:
373 373 if isinstance(s, _re_type):
374 374 assert s.search(printed), notprinted_msg.format(s.pattern, self.channel, printed)
375 375 else:
376 376 assert s in printed, notprinted_msg.format(s, self.channel, printed)
377 377 return False
378 378 finally:
379 379 self.tee.close()
380 380
381 381 printed_msg = """Found {0!r} in printed output (on {1}):
382 382 -------
383 383 {2!s}
384 384 -------
385 385 """
386 386
387 387 class AssertNotPrints(AssertPrints):
388 388 """Context manager for checking that certain output *isn't* produced.
389 389
390 390 Counterpart of AssertPrints"""
391 391 def __exit__(self, etype, value, traceback):
392 392 try:
393 393 if value is not None:
394 394 # If an error was raised, don't check anything else
395 395 self.tee.close()
396 396 return False
397 397 self.tee.flush()
398 398 setattr(sys, self.channel, self.orig_stream)
399 399 printed = self.buffer.getvalue()
400 400 for s in self.s:
401 401 if isinstance(s, _re_type):
402 402 assert not s.search(printed),printed_msg.format(
403 403 s.pattern, self.channel, printed)
404 404 else:
405 405 assert s not in printed, printed_msg.format(
406 406 s, self.channel, printed)
407 407 return False
408 408 finally:
409 409 self.tee.close()
410 410
411 411 @contextmanager
412 412 def mute_warn():
413 413 from IPython.utils import warn
414 414 save_warn = warn.warn
415 415 warn.warn = lambda *a, **kw: None
416 416 try:
417 417 yield
418 418 finally:
419 419 warn.warn = save_warn
420 420
421 421 @contextmanager
422 422 def make_tempfile(name):
423 423 """ Create an empty, named, temporary file for the duration of the context.
424 424 """
425 425 open(name, 'w').close()
426 426 try:
427 427 yield
428 428 finally:
429 429 os.unlink(name)
430 430
431 431 def fake_input(inputs):
432 432 """Temporarily replace the input() function to return the given values
433 433
434 434 Use as a context manager:
435 435
436 436 with fake_input(['result1', 'result2']):
437 437 ...
438 438
439 439 Values are returned in order. If input() is called again after the last value
440 440 was used, EOFError is raised.
441 441 """
442 442 it = iter(inputs)
443 443 def mock_input(prompt=''):
444 444 try:
445 445 return next(it)
446 446 except StopIteration as e:
447 447 raise EOFError('No more inputs given') from e
448 448
449 449 return patch('builtins.input', mock_input)
450 450
451 451 def help_output_test(subcommand=''):
452 452 """test that `ipython [subcommand] -h` works"""
453 453 cmd = get_ipython_cmd() + [subcommand, '-h']
454 454 out, err, rc = get_output_error_code(cmd)
455 455 nt.assert_equal(rc, 0, err)
456 456 nt.assert_not_in("Traceback", err)
457 457 nt.assert_in("Options", out)
458 458 nt.assert_in("--help-all", out)
459 459 return out, err
460 460
461 461
462 462 def help_all_output_test(subcommand=''):
463 463 """test that `ipython [subcommand] --help-all` works"""
464 464 cmd = get_ipython_cmd() + [subcommand, '--help-all']
465 465 out, err, rc = get_output_error_code(cmd)
466 466 nt.assert_equal(rc, 0, err)
467 467 nt.assert_not_in("Traceback", err)
468 468 nt.assert_in("Options", out)
469 469 nt.assert_in("Class", out)
470 470 return out, err
471 471
General Comments 0
You need to be logged in to leave comments. Login now