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