##// END OF EJS Templates
fix some deprecations...
Min RK -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,295 +1,295 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Displayhook for IPython.
2 """Displayhook for IPython.
3
3
4 This defines a callable class that IPython uses for `sys.displayhook`.
4 This defines a callable class that IPython uses for `sys.displayhook`.
5 """
5 """
6
6
7 # Copyright (c) IPython Development Team.
7 # Copyright (c) IPython Development Team.
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9
9
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 import sys
12 import sys
13 import io as _io
13 import io as _io
14 import tokenize
14 import tokenize
15
15
16 from traitlets.config.configurable import Configurable
16 from traitlets.config.configurable import Configurable
17 from IPython.utils.py3compat import builtin_mod, cast_unicode_py2
17 from IPython.utils.py3compat import builtin_mod, cast_unicode_py2
18 from traitlets import Instance, Float
18 from traitlets import Instance, Float
19 from warnings import warn
19 from warnings import warn
20
20
21 # TODO: Move the various attributes (cache_size, [others now moved]). Some
21 # TODO: Move the various attributes (cache_size, [others now moved]). Some
22 # of these are also attributes of InteractiveShell. They should be on ONE object
22 # of these are also attributes of InteractiveShell. They should be on ONE object
23 # only and the other objects should ask that one object for their values.
23 # only and the other objects should ask that one object for their values.
24
24
25 class DisplayHook(Configurable):
25 class DisplayHook(Configurable):
26 """The custom IPython displayhook to replace sys.displayhook.
26 """The custom IPython displayhook to replace sys.displayhook.
27
27
28 This class does many things, but the basic idea is that it is a callable
28 This class does many things, but the basic idea is that it is a callable
29 that gets called anytime user code returns a value.
29 that gets called anytime user code returns a value.
30 """
30 """
31
31
32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
32 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
33 allow_none=True)
33 allow_none=True)
34 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
34 exec_result = Instance('IPython.core.interactiveshell.ExecutionResult',
35 allow_none=True)
35 allow_none=True)
36 cull_fraction = Float(0.2)
36 cull_fraction = Float(0.2)
37
37
38 def __init__(self, shell=None, cache_size=1000, **kwargs):
38 def __init__(self, shell=None, cache_size=1000, **kwargs):
39 super(DisplayHook, self).__init__(shell=shell, **kwargs)
39 super(DisplayHook, self).__init__(shell=shell, **kwargs)
40 cache_size_min = 3
40 cache_size_min = 3
41 if cache_size <= 0:
41 if cache_size <= 0:
42 self.do_full_cache = 0
42 self.do_full_cache = 0
43 cache_size = 0
43 cache_size = 0
44 elif cache_size < cache_size_min:
44 elif cache_size < cache_size_min:
45 self.do_full_cache = 0
45 self.do_full_cache = 0
46 cache_size = 0
46 cache_size = 0
47 warn('caching was disabled (min value for cache size is %s).' %
47 warn('caching was disabled (min value for cache size is %s).' %
48 cache_size_min,level=3)
48 cache_size_min,level=3)
49 else:
49 else:
50 self.do_full_cache = 1
50 self.do_full_cache = 1
51
51
52 self.cache_size = cache_size
52 self.cache_size = cache_size
53
53
54 # we need a reference to the user-level namespace
54 # we need a reference to the user-level namespace
55 self.shell = shell
55 self.shell = shell
56
56
57 self._,self.__,self.___ = '','',''
57 self._,self.__,self.___ = '','',''
58
58
59 # these are deliberately global:
59 # these are deliberately global:
60 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
60 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
61 self.shell.user_ns.update(to_user_ns)
61 self.shell.user_ns.update(to_user_ns)
62
62
63 @property
63 @property
64 def prompt_count(self):
64 def prompt_count(self):
65 return self.shell.execution_count
65 return self.shell.execution_count
66
66
67 #-------------------------------------------------------------------------
67 #-------------------------------------------------------------------------
68 # Methods used in __call__. Override these methods to modify the behavior
68 # Methods used in __call__. Override these methods to modify the behavior
69 # of the displayhook.
69 # of the displayhook.
70 #-------------------------------------------------------------------------
70 #-------------------------------------------------------------------------
71
71
72 def check_for_underscore(self):
72 def check_for_underscore(self):
73 """Check if the user has set the '_' variable by hand."""
73 """Check if the user has set the '_' variable by hand."""
74 # If something injected a '_' variable in __builtin__, delete
74 # If something injected a '_' variable in __builtin__, delete
75 # ipython's automatic one so we don't clobber that. gettext() in
75 # ipython's automatic one so we don't clobber that. gettext() in
76 # particular uses _, so we need to stay away from it.
76 # particular uses _, so we need to stay away from it.
77 if '_' in builtin_mod.__dict__:
77 if '_' in builtin_mod.__dict__:
78 try:
78 try:
79 del self.shell.user_ns['_']
79 del self.shell.user_ns['_']
80 except KeyError:
80 except KeyError:
81 pass
81 pass
82
82
83 def quiet(self):
83 def quiet(self):
84 """Should we silence the display hook because of ';'?"""
84 """Should we silence the display hook because of ';'?"""
85 # do not print output if input ends in ';'
85 # do not print output if input ends in ';'
86
86
87 try:
87 try:
88 cell = cast_unicode_py2(self.shell.history_manager.input_hist_parsed[-1])
88 cell = cast_unicode_py2(self.shell.history_manager.input_hist_parsed[-1])
89 except IndexError:
89 except IndexError:
90 # some uses of ipshellembed may fail here
90 # some uses of ipshellembed may fail here
91 return False
91 return False
92
92
93 sio = _io.StringIO(cell)
93 sio = _io.StringIO(cell)
94 tokens = list(tokenize.generate_tokens(sio.readline))
94 tokens = list(tokenize.generate_tokens(sio.readline))
95
95
96 for token in reversed(tokens):
96 for token in reversed(tokens):
97 if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT):
97 if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT):
98 continue
98 continue
99 if (token[0] == tokenize.OP) and (token[1] == ';'):
99 if (token[0] == tokenize.OP) and (token[1] == ';'):
100 return True
100 return True
101 else:
101 else:
102 return False
102 return False
103
103
104 def start_displayhook(self):
104 def start_displayhook(self):
105 """Start the displayhook, initializing resources."""
105 """Start the displayhook, initializing resources."""
106 pass
106 pass
107
107
108 def write_output_prompt(self):
108 def write_output_prompt(self):
109 """Write the output prompt.
109 """Write the output prompt.
110
110
111 The default implementation simply writes the prompt to
111 The default implementation simply writes the prompt to
112 ``io.stdout``.
112 ``sys.stdout``.
113 """
113 """
114 # Use write, not print which adds an extra space.
114 # Use write, not print which adds an extra space.
115 sys.stdout.write(self.shell.separate_out)
115 sys.stdout.write(self.shell.separate_out)
116 outprompt = 'Out[{}]: '.format(self.shell.execution_count)
116 outprompt = 'Out[{}]: '.format(self.shell.execution_count)
117 if self.do_full_cache:
117 if self.do_full_cache:
118 sys.stdout.write(outprompt)
118 sys.stdout.write(outprompt)
119
119
120 def compute_format_data(self, result):
120 def compute_format_data(self, result):
121 """Compute format data of the object to be displayed.
121 """Compute format data of the object to be displayed.
122
122
123 The format data is a generalization of the :func:`repr` of an object.
123 The format data is a generalization of the :func:`repr` of an object.
124 In the default implementation the format data is a :class:`dict` of
124 In the default implementation the format data is a :class:`dict` of
125 key value pair where the keys are valid MIME types and the values
125 key value pair where the keys are valid MIME types and the values
126 are JSON'able data structure containing the raw data for that MIME
126 are JSON'able data structure containing the raw data for that MIME
127 type. It is up to frontends to determine pick a MIME to to use and
127 type. It is up to frontends to determine pick a MIME to to use and
128 display that data in an appropriate manner.
128 display that data in an appropriate manner.
129
129
130 This method only computes the format data for the object and should
130 This method only computes the format data for the object and should
131 NOT actually print or write that to a stream.
131 NOT actually print or write that to a stream.
132
132
133 Parameters
133 Parameters
134 ----------
134 ----------
135 result : object
135 result : object
136 The Python object passed to the display hook, whose format will be
136 The Python object passed to the display hook, whose format will be
137 computed.
137 computed.
138
138
139 Returns
139 Returns
140 -------
140 -------
141 (format_dict, md_dict) : dict
141 (format_dict, md_dict) : dict
142 format_dict is a :class:`dict` whose keys are valid MIME types and values are
142 format_dict is a :class:`dict` whose keys are valid MIME types and values are
143 JSON'able raw data for that MIME type. It is recommended that
143 JSON'able raw data for that MIME type. It is recommended that
144 all return values of this should always include the "text/plain"
144 all return values of this should always include the "text/plain"
145 MIME type representation of the object.
145 MIME type representation of the object.
146 md_dict is a :class:`dict` with the same MIME type keys
146 md_dict is a :class:`dict` with the same MIME type keys
147 of metadata associated with each output.
147 of metadata associated with each output.
148
148
149 """
149 """
150 return self.shell.display_formatter.format(result)
150 return self.shell.display_formatter.format(result)
151
151
152 # This can be set to True by the write_output_prompt method in a subclass
152 # This can be set to True by the write_output_prompt method in a subclass
153 prompt_end_newline = False
153 prompt_end_newline = False
154
154
155 def write_format_data(self, format_dict, md_dict=None):
155 def write_format_data(self, format_dict, md_dict=None):
156 """Write the format data dict to the frontend.
156 """Write the format data dict to the frontend.
157
157
158 This default version of this method simply writes the plain text
158 This default version of this method simply writes the plain text
159 representation of the object to ``io.stdout``. Subclasses should
159 representation of the object to ``sys.stdout``. Subclasses should
160 override this method to send the entire `format_dict` to the
160 override this method to send the entire `format_dict` to the
161 frontends.
161 frontends.
162
162
163 Parameters
163 Parameters
164 ----------
164 ----------
165 format_dict : dict
165 format_dict : dict
166 The format dict for the object passed to `sys.displayhook`.
166 The format dict for the object passed to `sys.displayhook`.
167 md_dict : dict (optional)
167 md_dict : dict (optional)
168 The metadata dict to be associated with the display data.
168 The metadata dict to be associated with the display data.
169 """
169 """
170 if 'text/plain' not in format_dict:
170 if 'text/plain' not in format_dict:
171 # nothing to do
171 # nothing to do
172 return
172 return
173 # We want to print because we want to always make sure we have a
173 # We want to print because we want to always make sure we have a
174 # newline, even if all the prompt separators are ''. This is the
174 # newline, even if all the prompt separators are ''. This is the
175 # standard IPython behavior.
175 # standard IPython behavior.
176 result_repr = format_dict['text/plain']
176 result_repr = format_dict['text/plain']
177 if '\n' in result_repr:
177 if '\n' in result_repr:
178 # So that multi-line strings line up with the left column of
178 # So that multi-line strings line up with the left column of
179 # the screen, instead of having the output prompt mess up
179 # the screen, instead of having the output prompt mess up
180 # their first line.
180 # their first line.
181 # We use the prompt template instead of the expanded prompt
181 # We use the prompt template instead of the expanded prompt
182 # because the expansion may add ANSI escapes that will interfere
182 # because the expansion may add ANSI escapes that will interfere
183 # with our ability to determine whether or not we should add
183 # with our ability to determine whether or not we should add
184 # a newline.
184 # a newline.
185 if not self.prompt_end_newline:
185 if not self.prompt_end_newline:
186 # But avoid extraneous empty lines.
186 # But avoid extraneous empty lines.
187 result_repr = '\n' + result_repr
187 result_repr = '\n' + result_repr
188
188
189 print(result_repr)
189 print(result_repr)
190
190
191 def update_user_ns(self, result):
191 def update_user_ns(self, result):
192 """Update user_ns with various things like _, __, _1, etc."""
192 """Update user_ns with various things like _, __, _1, etc."""
193
193
194 # Avoid recursive reference when displaying _oh/Out
194 # Avoid recursive reference when displaying _oh/Out
195 if result is not self.shell.user_ns['_oh']:
195 if result is not self.shell.user_ns['_oh']:
196 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
196 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
197 self.cull_cache()
197 self.cull_cache()
198 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
198 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
199 # we cause buggy behavior for things like gettext).
199 # we cause buggy behavior for things like gettext).
200
200
201 if '_' not in builtin_mod.__dict__:
201 if '_' not in builtin_mod.__dict__:
202 self.___ = self.__
202 self.___ = self.__
203 self.__ = self._
203 self.__ = self._
204 self._ = result
204 self._ = result
205 self.shell.push({'_':self._,
205 self.shell.push({'_':self._,
206 '__':self.__,
206 '__':self.__,
207 '___':self.___}, interactive=False)
207 '___':self.___}, interactive=False)
208
208
209 # hackish access to top-level namespace to create _1,_2... dynamically
209 # hackish access to top-level namespace to create _1,_2... dynamically
210 to_main = {}
210 to_main = {}
211 if self.do_full_cache:
211 if self.do_full_cache:
212 new_result = '_'+repr(self.prompt_count)
212 new_result = '_'+repr(self.prompt_count)
213 to_main[new_result] = result
213 to_main[new_result] = result
214 self.shell.push(to_main, interactive=False)
214 self.shell.push(to_main, interactive=False)
215 self.shell.user_ns['_oh'][self.prompt_count] = result
215 self.shell.user_ns['_oh'][self.prompt_count] = result
216
216
217 def fill_exec_result(self, result):
217 def fill_exec_result(self, result):
218 if self.exec_result is not None:
218 if self.exec_result is not None:
219 self.exec_result.result = result
219 self.exec_result.result = result
220
220
221 def log_output(self, format_dict):
221 def log_output(self, format_dict):
222 """Log the output."""
222 """Log the output."""
223 if 'text/plain' not in format_dict:
223 if 'text/plain' not in format_dict:
224 # nothing to do
224 # nothing to do
225 return
225 return
226 if self.shell.logger.log_output:
226 if self.shell.logger.log_output:
227 self.shell.logger.log_write(format_dict['text/plain'], 'output')
227 self.shell.logger.log_write(format_dict['text/plain'], 'output')
228 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
228 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
229 format_dict['text/plain']
229 format_dict['text/plain']
230
230
231 def finish_displayhook(self):
231 def finish_displayhook(self):
232 """Finish up all displayhook activities."""
232 """Finish up all displayhook activities."""
233 sys.stdout.write(self.shell.separate_out2)
233 sys.stdout.write(self.shell.separate_out2)
234 sys.stdout.flush()
234 sys.stdout.flush()
235
235
236 def __call__(self, result=None):
236 def __call__(self, result=None):
237 """Printing with history cache management.
237 """Printing with history cache management.
238
238
239 This is invoked everytime the interpreter needs to print, and is
239 This is invoked everytime the interpreter needs to print, and is
240 activated by setting the variable sys.displayhook to it.
240 activated by setting the variable sys.displayhook to it.
241 """
241 """
242 self.check_for_underscore()
242 self.check_for_underscore()
243 if result is not None and not self.quiet():
243 if result is not None and not self.quiet():
244 self.start_displayhook()
244 self.start_displayhook()
245 self.write_output_prompt()
245 self.write_output_prompt()
246 format_dict, md_dict = self.compute_format_data(result)
246 format_dict, md_dict = self.compute_format_data(result)
247 self.update_user_ns(result)
247 self.update_user_ns(result)
248 self.fill_exec_result(result)
248 self.fill_exec_result(result)
249 if format_dict:
249 if format_dict:
250 self.write_format_data(format_dict, md_dict)
250 self.write_format_data(format_dict, md_dict)
251 self.log_output(format_dict)
251 self.log_output(format_dict)
252 self.finish_displayhook()
252 self.finish_displayhook()
253
253
254 def cull_cache(self):
254 def cull_cache(self):
255 """Output cache is full, cull the oldest entries"""
255 """Output cache is full, cull the oldest entries"""
256 oh = self.shell.user_ns.get('_oh', {})
256 oh = self.shell.user_ns.get('_oh', {})
257 sz = len(oh)
257 sz = len(oh)
258 cull_count = max(int(sz * self.cull_fraction), 2)
258 cull_count = max(int(sz * self.cull_fraction), 2)
259 warn('Output cache limit (currently {sz} entries) hit.\n'
259 warn('Output cache limit (currently {sz} entries) hit.\n'
260 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
260 'Flushing oldest {cull_count} entries.'.format(sz=sz, cull_count=cull_count))
261
261
262 for i, n in enumerate(sorted(oh)):
262 for i, n in enumerate(sorted(oh)):
263 if i >= cull_count:
263 if i >= cull_count:
264 break
264 break
265 self.shell.user_ns.pop('_%i' % n, None)
265 self.shell.user_ns.pop('_%i' % n, None)
266 oh.pop(n, None)
266 oh.pop(n, None)
267
267
268
268
269 def flush(self):
269 def flush(self):
270 if not self.do_full_cache:
270 if not self.do_full_cache:
271 raise ValueError("You shouldn't have reached the cache flush "
271 raise ValueError("You shouldn't have reached the cache flush "
272 "if full caching is not enabled!")
272 "if full caching is not enabled!")
273 # delete auto-generated vars from global namespace
273 # delete auto-generated vars from global namespace
274
274
275 for n in range(1,self.prompt_count + 1):
275 for n in range(1,self.prompt_count + 1):
276 key = '_'+repr(n)
276 key = '_'+repr(n)
277 try:
277 try:
278 del self.shell.user_ns[key]
278 del self.shell.user_ns[key]
279 except: pass
279 except: pass
280 # In some embedded circumstances, the user_ns doesn't have the
280 # In some embedded circumstances, the user_ns doesn't have the
281 # '_oh' key set up.
281 # '_oh' key set up.
282 oh = self.shell.user_ns.get('_oh', None)
282 oh = self.shell.user_ns.get('_oh', None)
283 if oh is not None:
283 if oh is not None:
284 oh.clear()
284 oh.clear()
285
285
286 # Release our own references to objects:
286 # Release our own references to objects:
287 self._, self.__, self.___ = '', '', ''
287 self._, self.__, self.___ = '', '', ''
288
288
289 if '_' not in builtin_mod.__dict__:
289 if '_' not in builtin_mod.__dict__:
290 self.shell.user_ns.update({'_':None,'__':None, '___':None})
290 self.shell.user_ns.update({'_':None,'__':None, '___':None})
291 import gc
291 import gc
292 # TODO: Is this really needed?
292 # TODO: Is this really needed?
293 # IronPython blocks here forever
293 # IronPython blocks here forever
294 if sys.platform != "cli":
294 if sys.platform != "cli":
295 gc.collect()
295 gc.collect()
@@ -1,117 +1,117 b''
1 """An interface for publishing rich data to frontends.
1 """An interface for publishing rich data to frontends.
2
2
3 There are two components of the display system:
3 There are two components of the display system:
4
4
5 * Display formatters, which take a Python object and compute the
5 * Display formatters, which take a Python object and compute the
6 representation of the object in various formats (text, HTML, SVG, etc.).
6 representation of the object in various formats (text, HTML, SVG, etc.).
7 * The display publisher that is used to send the representation data to the
7 * The display publisher that is used to send the representation data to the
8 various frontends.
8 various frontends.
9
9
10 This module defines the logic display publishing. The display publisher uses
10 This module defines the logic display publishing. The display publisher uses
11 the ``display_data`` message type that is defined in the IPython messaging
11 the ``display_data`` message type that is defined in the IPython messaging
12 spec.
12 spec.
13 """
13 """
14
14
15 # Copyright (c) IPython Development Team.
15 # Copyright (c) IPython Development Team.
16 # Distributed under the terms of the Modified BSD License.
16 # Distributed under the terms of the Modified BSD License.
17
17
18 from __future__ import print_function
18 from __future__ import print_function
19
19
20 import sys
20 import sys
21
21
22 from traitlets.config.configurable import Configurable
22 from traitlets.config.configurable import Configurable
23 from traitlets import List
23 from traitlets import List
24
24
25 # This used to be defined here - it is imported for backwards compatibility
25 # This used to be defined here - it is imported for backwards compatibility
26 from .display import publish_display_data
26 from .display import publish_display_data
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Main payload class
29 # Main payload class
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 class DisplayPublisher(Configurable):
32 class DisplayPublisher(Configurable):
33 """A traited class that publishes display data to frontends.
33 """A traited class that publishes display data to frontends.
34
34
35 Instances of this class are created by the main IPython object and should
35 Instances of this class are created by the main IPython object and should
36 be accessed there.
36 be accessed there.
37 """
37 """
38
38
39 def _validate_data(self, data, metadata=None):
39 def _validate_data(self, data, metadata=None):
40 """Validate the display data.
40 """Validate the display data.
41
41
42 Parameters
42 Parameters
43 ----------
43 ----------
44 data : dict
44 data : dict
45 The formata data dictionary.
45 The formata data dictionary.
46 metadata : dict
46 metadata : dict
47 Any metadata for the data.
47 Any metadata for the data.
48 """
48 """
49
49
50 if not isinstance(data, dict):
50 if not isinstance(data, dict):
51 raise TypeError('data must be a dict, got: %r' % data)
51 raise TypeError('data must be a dict, got: %r' % data)
52 if metadata is not None:
52 if metadata is not None:
53 if not isinstance(metadata, dict):
53 if not isinstance(metadata, dict):
54 raise TypeError('metadata must be a dict, got: %r' % data)
54 raise TypeError('metadata must be a dict, got: %r' % data)
55
55
56 def publish(self, data, metadata=None, source=None):
56 def publish(self, data, metadata=None, source=None):
57 """Publish data and metadata to all frontends.
57 """Publish data and metadata to all frontends.
58
58
59 See the ``display_data`` message in the messaging documentation for
59 See the ``display_data`` message in the messaging documentation for
60 more details about this message type.
60 more details about this message type.
61
61
62 The following MIME types are currently implemented:
62 The following MIME types are currently implemented:
63
63
64 * text/plain
64 * text/plain
65 * text/html
65 * text/html
66 * text/markdown
66 * text/markdown
67 * text/latex
67 * text/latex
68 * application/json
68 * application/json
69 * application/javascript
69 * application/javascript
70 * image/png
70 * image/png
71 * image/jpeg
71 * image/jpeg
72 * image/svg+xml
72 * image/svg+xml
73
73
74 Parameters
74 Parameters
75 ----------
75 ----------
76 data : dict
76 data : dict
77 A dictionary having keys that are valid MIME types (like
77 A dictionary having keys that are valid MIME types (like
78 'text/plain' or 'image/svg+xml') and values that are the data for
78 'text/plain' or 'image/svg+xml') and values that are the data for
79 that MIME type. The data itself must be a JSON'able data
79 that MIME type. The data itself must be a JSON'able data
80 structure. Minimally all data should have the 'text/plain' data,
80 structure. Minimally all data should have the 'text/plain' data,
81 which can be displayed by all frontends. If more than the plain
81 which can be displayed by all frontends. If more than the plain
82 text is given, it is up to the frontend to decide which
82 text is given, it is up to the frontend to decide which
83 representation to use.
83 representation to use.
84 metadata : dict
84 metadata : dict
85 A dictionary for metadata related to the data. This can contain
85 A dictionary for metadata related to the data. This can contain
86 arbitrary key, value pairs that frontends can use to interpret
86 arbitrary key, value pairs that frontends can use to interpret
87 the data. Metadata specific to each mime-type can be specified
87 the data. Metadata specific to each mime-type can be specified
88 in the metadata dict with the same mime-type keys as
88 in the metadata dict with the same mime-type keys as
89 the data itself.
89 the data itself.
90 source : str, deprecated
90 source : str, deprecated
91 Unused.
91 Unused.
92 """
92 """
93
93
94 # The default is to simply write the plain text data using io.stdout.
94 # The default is to simply write the plain text data using sys.stdout.
95 if 'text/plain' in data:
95 if 'text/plain' in data:
96 print(data['text/plain'])
96 print(data['text/plain'])
97
97
98 def clear_output(self, wait=False):
98 def clear_output(self, wait=False):
99 """Clear the output of the cell receiving output."""
99 """Clear the output of the cell receiving output."""
100 print('\033[2K\r', end='')
100 print('\033[2K\r', end='')
101 sys.stdout.flush()
101 sys.stdout.flush()
102 print('\033[2K\r', end='')
102 print('\033[2K\r', end='')
103 sys.stderr.flush()
103 sys.stderr.flush()
104
104
105
105
106 class CapturingDisplayPublisher(DisplayPublisher):
106 class CapturingDisplayPublisher(DisplayPublisher):
107 """A DisplayPublisher that stores"""
107 """A DisplayPublisher that stores"""
108 outputs = List()
108 outputs = List()
109
109
110 def publish(self, data, metadata=None, source=None):
110 def publish(self, data, metadata=None, source=None):
111 self.outputs.append((data, metadata))
111 self.outputs.append((data, metadata))
112
112
113 def clear_output(self, wait=False):
113 def clear_output(self, wait=False):
114 super(CapturingDisplayPublisher, self).clear_output(wait)
114 super(CapturingDisplayPublisher, self).clear_output(wait)
115
115
116 # empty the list, *do not* reassign a new list
116 # empty the list, *do not* reassign a new list
117 del self.outputs[:]
117 del self.outputs[:]
@@ -1,945 +1,947 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
18
19 from decorator import decorator
19 from decorator import decorator
20
20
21 from traitlets.config.configurable import Configurable
21 from traitlets.config.configurable import Configurable
22 from IPython.core.getipython import get_ipython
22 from IPython.core.getipython import get_ipython
23 from IPython.utils.sentinel import Sentinel
23 from IPython.utils.sentinel import Sentinel
24 from IPython.utils.dir2 import get_real_method
24 from IPython.utils.dir2 import get_real_method
25 from IPython.lib import pretty
25 from IPython.lib import pretty
26 from traitlets import (
26 from traitlets import (
27 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
27 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
28 ForwardDeclaredInstance,
28 ForwardDeclaredInstance,
29 default, observe,
29 default, observe,
30 )
30 )
31 from IPython.utils.py3compat import (
31 from IPython.utils.py3compat import (
32 with_metaclass, string_types, unicode_type,
32 with_metaclass, string_types, unicode_type,
33 )
33 )
34
34
35
35
36 class DisplayFormatter(Configurable):
36 class DisplayFormatter(Configurable):
37
37
38 active_types = List(Unicode(),
38 active_types = List(Unicode(),
39 help="""List of currently active mime-types to display.
39 help="""List of currently active mime-types to display.
40 You can use this to set a white-list for formats to display.
40 You can use this to set a white-list for formats to display.
41
41
42 Most users will not need to change this value.
42 Most users will not need to change this value.
43 """).tag(config=True)
43 """).tag(config=True)
44
44
45 @default('active_types')
45 @default('active_types')
46 def _active_types_default(self):
46 def _active_types_default(self):
47 return self.format_types
47 return self.format_types
48
48
49 @observe('active_types')
49 @observe('active_types')
50 def _active_types_changed(self, change):
50 def _active_types_changed(self, change):
51 for key, formatter in self.formatters.items():
51 for key, formatter in self.formatters.items():
52 if key in change['new']:
52 if key in change['new']:
53 formatter.enabled = True
53 formatter.enabled = True
54 else:
54 else:
55 formatter.enabled = False
55 formatter.enabled = False
56
56
57 ipython_display_formatter = ForwardDeclaredInstance('FormatterABC')
57 ipython_display_formatter = ForwardDeclaredInstance('FormatterABC')
58 @default('ipython_display_formatter')
58 @default('ipython_display_formatter')
59 def _default_formatter(self):
59 def _default_formatter(self):
60 return IPythonDisplayFormatter(parent=self)
60 return IPythonDisplayFormatter(parent=self)
61
61
62 # A dict of formatter whose keys are format types (MIME types) and whose
62 # A dict of formatter whose keys are format types (MIME types) and whose
63 # values are subclasses of BaseFormatter.
63 # values are subclasses of BaseFormatter.
64 formatters = Dict()
64 formatters = Dict()
65 @default('formatters')
65 @default('formatters')
66 def _formatters_default(self):
66 def _formatters_default(self):
67 """Activate the default formatters."""
67 """Activate the default formatters."""
68 formatter_classes = [
68 formatter_classes = [
69 PlainTextFormatter,
69 PlainTextFormatter,
70 HTMLFormatter,
70 HTMLFormatter,
71 MarkdownFormatter,
71 MarkdownFormatter,
72 SVGFormatter,
72 SVGFormatter,
73 PNGFormatter,
73 PNGFormatter,
74 PDFFormatter,
74 PDFFormatter,
75 JPEGFormatter,
75 JPEGFormatter,
76 LatexFormatter,
76 LatexFormatter,
77 JSONFormatter,
77 JSONFormatter,
78 JavascriptFormatter
78 JavascriptFormatter
79 ]
79 ]
80 d = {}
80 d = {}
81 for cls in formatter_classes:
81 for cls in formatter_classes:
82 f = cls(parent=self)
82 f = cls(parent=self)
83 d[f.format_type] = f
83 d[f.format_type] = f
84 return d
84 return d
85
85
86 def format(self, obj, include=None, exclude=None):
86 def format(self, obj, include=None, exclude=None):
87 """Return a format data dict for an object.
87 """Return a format data dict for an object.
88
88
89 By default all format types will be computed.
89 By default all format types will be computed.
90
90
91 The following MIME types are currently implemented:
91 The following MIME types are currently implemented:
92
92
93 * text/plain
93 * text/plain
94 * text/html
94 * text/html
95 * text/markdown
95 * text/markdown
96 * text/latex
96 * text/latex
97 * application/json
97 * application/json
98 * application/javascript
98 * application/javascript
99 * application/pdf
99 * application/pdf
100 * image/png
100 * image/png
101 * image/jpeg
101 * image/jpeg
102 * image/svg+xml
102 * image/svg+xml
103
103
104 Parameters
104 Parameters
105 ----------
105 ----------
106 obj : object
106 obj : object
107 The Python object whose format data will be computed.
107 The Python object whose format data will be computed.
108 include : list or tuple, optional
108 include : list or tuple, optional
109 A list of format type strings (MIME types) to include in the
109 A list of format type strings (MIME types) to include in the
110 format data dict. If this is set *only* the format types included
110 format data dict. If this is set *only* the format types included
111 in this list will be computed.
111 in this list will be computed.
112 exclude : list or tuple, optional
112 exclude : list or tuple, optional
113 A list of format type string (MIME types) to exclude in the format
113 A list of format type string (MIME types) to exclude in the format
114 data dict. If this is set all format types will be computed,
114 data dict. If this is set all format types will be computed,
115 except for those included in this argument.
115 except for those included in this argument.
116
116
117 Returns
117 Returns
118 -------
118 -------
119 (format_dict, metadata_dict) : tuple of two dicts
119 (format_dict, metadata_dict) : tuple of two dicts
120
120
121 format_dict is a dictionary of key/value pairs, one of each format that was
121 format_dict is a dictionary of key/value pairs, one of each format that was
122 generated for the object. The keys are the format types, which
122 generated for the object. The keys are the format types, which
123 will usually be MIME type strings and the values and JSON'able
123 will usually be MIME type strings and the values and JSON'able
124 data structure containing the raw data for the representation in
124 data structure containing the raw data for the representation in
125 that format.
125 that format.
126
126
127 metadata_dict is a dictionary of metadata about each mime-type output.
127 metadata_dict is a dictionary of metadata about each mime-type output.
128 Its keys will be a strict subset of the keys in format_dict.
128 Its keys will be a strict subset of the keys in format_dict.
129 """
129 """
130 format_dict = {}
130 format_dict = {}
131 md_dict = {}
131 md_dict = {}
132
132
133 if self.ipython_display_formatter(obj):
133 if self.ipython_display_formatter(obj):
134 # object handled itself, don't proceed
134 # object handled itself, don't proceed
135 return {}, {}
135 return {}, {}
136
136
137 for format_type, formatter in self.formatters.items():
137 for format_type, formatter in self.formatters.items():
138 if include and format_type not in include:
138 if include and format_type not in include:
139 continue
139 continue
140 if exclude and format_type in exclude:
140 if exclude and format_type in exclude:
141 continue
141 continue
142
142
143 md = None
143 md = None
144 try:
144 try:
145 data = formatter(obj)
145 data = formatter(obj)
146 except:
146 except:
147 # FIXME: log the exception
147 # FIXME: log the exception
148 raise
148 raise
149
149
150 # formatters can return raw data or (data, metadata)
150 # formatters can return raw data or (data, metadata)
151 if isinstance(data, tuple) and len(data) == 2:
151 if isinstance(data, tuple) and len(data) == 2:
152 data, md = data
152 data, md = data
153
153
154 if data is not None:
154 if data is not None:
155 format_dict[format_type] = data
155 format_dict[format_type] = data
156 if md is not None:
156 if md is not None:
157 md_dict[format_type] = md
157 md_dict[format_type] = md
158
158
159 return format_dict, md_dict
159 return format_dict, md_dict
160
160
161 @property
161 @property
162 def format_types(self):
162 def format_types(self):
163 """Return the format types (MIME types) of the active formatters."""
163 """Return the format types (MIME types) of the active formatters."""
164 return list(self.formatters.keys())
164 return list(self.formatters.keys())
165
165
166
166
167 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
168 # Formatters for specific format types (text, html, svg, etc.)
168 # Formatters for specific format types (text, html, svg, etc.)
169 #-----------------------------------------------------------------------------
169 #-----------------------------------------------------------------------------
170
170
171
171
172 def _safe_repr(obj):
172 def _safe_repr(obj):
173 """Try to return a repr of an object
173 """Try to return a repr of an object
174
174
175 always returns a string, at least.
175 always returns a string, at least.
176 """
176 """
177 try:
177 try:
178 return repr(obj)
178 return repr(obj)
179 except Exception as e:
179 except Exception as e:
180 return "un-repr-able object (%r)" % e
180 return "un-repr-able object (%r)" % e
181
181
182
182
183 class FormatterWarning(UserWarning):
183 class FormatterWarning(UserWarning):
184 """Warning class for errors in formatters"""
184 """Warning class for errors in formatters"""
185
185
186 @decorator
186 @decorator
187 def catch_format_error(method, self, *args, **kwargs):
187 def catch_format_error(method, self, *args, **kwargs):
188 """show traceback on failed format call"""
188 """show traceback on failed format call"""
189 try:
189 try:
190 r = method(self, *args, **kwargs)
190 r = method(self, *args, **kwargs)
191 except NotImplementedError:
191 except NotImplementedError:
192 # don't warn on NotImplementedErrors
192 # don't warn on NotImplementedErrors
193 return None
193 return None
194 except Exception:
194 except Exception:
195 exc_info = sys.exc_info()
195 exc_info = sys.exc_info()
196 ip = get_ipython()
196 ip = get_ipython()
197 if ip is not None:
197 if ip is not None:
198 ip.showtraceback(exc_info)
198 ip.showtraceback(exc_info)
199 else:
199 else:
200 traceback.print_exception(*exc_info)
200 traceback.print_exception(*exc_info)
201 return None
201 return None
202 return self._check_return(r, args[0])
202 return self._check_return(r, args[0])
203
203
204
204
205 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
205 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
206 """ Abstract base class for Formatters.
206 """ Abstract base class for Formatters.
207
207
208 A formatter is a callable class that is responsible for computing the
208 A formatter is a callable class that is responsible for computing the
209 raw format data for a particular format type (MIME type). For example,
209 raw format data for a particular format type (MIME type). For example,
210 an HTML formatter would have a format type of `text/html` and would return
210 an HTML formatter would have a format type of `text/html` and would return
211 the HTML representation of the object when called.
211 the HTML representation of the object when called.
212 """
212 """
213
213
214 # The format type of the data returned, usually a MIME type.
214 # The format type of the data returned, usually a MIME type.
215 format_type = 'text/plain'
215 format_type = 'text/plain'
216
216
217 # Is the formatter enabled...
217 # Is the formatter enabled...
218 enabled = True
218 enabled = True
219
219
220 @abc.abstractmethod
220 @abc.abstractmethod
221 def __call__(self, obj):
221 def __call__(self, obj):
222 """Return a JSON'able representation of the object.
222 """Return a JSON'able representation of the object.
223
223
224 If the object cannot be formatted by this formatter,
224 If the object cannot be formatted by this formatter,
225 warn and return None.
225 warn and return None.
226 """
226 """
227 return repr(obj)
227 return repr(obj)
228
228
229
229
230 def _mod_name_key(typ):
230 def _mod_name_key(typ):
231 """Return a (__module__, __name__) tuple for a type.
231 """Return a (__module__, __name__) tuple for a type.
232
232
233 Used as key in Formatter.deferred_printers.
233 Used as key in Formatter.deferred_printers.
234 """
234 """
235 module = getattr(typ, '__module__', None)
235 module = getattr(typ, '__module__', None)
236 name = getattr(typ, '__name__', None)
236 name = getattr(typ, '__name__', None)
237 return (module, name)
237 return (module, name)
238
238
239
239
240 def _get_type(obj):
240 def _get_type(obj):
241 """Return the type of an instance (old and new-style)"""
241 """Return the type of an instance (old and new-style)"""
242 return getattr(obj, '__class__', None) or type(obj)
242 return getattr(obj, '__class__', None) or type(obj)
243
243
244
244
245 _raise_key_error = Sentinel('_raise_key_error', __name__,
245 _raise_key_error = Sentinel('_raise_key_error', __name__,
246 """
246 """
247 Special value to raise a KeyError
247 Special value to raise a KeyError
248
248
249 Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
249 Raise KeyError in `BaseFormatter.pop` if passed as the default value to `pop`
250 """)
250 """)
251
251
252
252
253 class BaseFormatter(Configurable):
253 class BaseFormatter(Configurable):
254 """A base formatter class that is configurable.
254 """A base formatter class that is configurable.
255
255
256 This formatter should usually be used as the base class of all formatters.
256 This formatter should usually be used as the base class of all formatters.
257 It is a traited :class:`Configurable` class and includes an extensible
257 It is a traited :class:`Configurable` class and includes an extensible
258 API for users to determine how their objects are formatted. The following
258 API for users to determine how their objects are formatted. The following
259 logic is used to find a function to format an given object.
259 logic is used to find a function to format an given object.
260
260
261 1. The object is introspected to see if it has a method with the name
261 1. The object is introspected to see if it has a method with the name
262 :attr:`print_method`. If is does, that object is passed to that method
262 :attr:`print_method`. If is does, that object is passed to that method
263 for formatting.
263 for formatting.
264 2. If no print method is found, three internal dictionaries are consulted
264 2. If no print method is found, three internal dictionaries are consulted
265 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
265 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
266 and :attr:`deferred_printers`.
266 and :attr:`deferred_printers`.
267
267
268 Users should use these dictionaries to register functions that will be
268 Users should use these dictionaries to register functions that will be
269 used to compute the format data for their objects (if those objects don't
269 used to compute the format data for their objects (if those objects don't
270 have the special print methods). The easiest way of using these
270 have the special print methods). The easiest way of using these
271 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
271 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
272 methods.
272 methods.
273
273
274 If no function/callable is found to compute the format data, ``None`` is
274 If no function/callable is found to compute the format data, ``None`` is
275 returned and this format type is not used.
275 returned and this format type is not used.
276 """
276 """
277
277
278 format_type = Unicode('text/plain')
278 format_type = Unicode('text/plain')
279 _return_type = string_types
279 _return_type = string_types
280
280
281 enabled = Bool(True).tag(config=True)
281 enabled = Bool(True).tag(config=True)
282
282
283 print_method = ObjectName('__repr__')
283 print_method = ObjectName('__repr__')
284
284
285 # The singleton printers.
285 # The singleton printers.
286 # Maps the IDs of the builtin singleton objects to the format functions.
286 # Maps the IDs of the builtin singleton objects to the format functions.
287 singleton_printers = Dict().tag(config=True)
287 singleton_printers = Dict().tag(config=True)
288
288
289 # The type-specific printers.
289 # The type-specific printers.
290 # Map type objects to the format functions.
290 # Map type objects to the format functions.
291 type_printers = Dict().tag(config=True)
291 type_printers = Dict().tag(config=True)
292
292
293 # The deferred-import type-specific printers.
293 # The deferred-import type-specific printers.
294 # Map (modulename, classname) pairs to the format functions.
294 # Map (modulename, classname) pairs to the format functions.
295 deferred_printers = Dict().tag(config=True)
295 deferred_printers = Dict().tag(config=True)
296
296
297 @catch_format_error
297 @catch_format_error
298 def __call__(self, obj):
298 def __call__(self, obj):
299 """Compute the format for an object."""
299 """Compute the format for an object."""
300 if self.enabled:
300 if self.enabled:
301 # lookup registered printer
301 # lookup registered printer
302 try:
302 try:
303 printer = self.lookup(obj)
303 printer = self.lookup(obj)
304 except KeyError:
304 except KeyError:
305 pass
305 pass
306 else:
306 else:
307 return printer(obj)
307 return printer(obj)
308 # Finally look for special method names
308 # Finally look for special method names
309 method = get_real_method(obj, self.print_method)
309 method = get_real_method(obj, self.print_method)
310 if method is not None:
310 if method is not None:
311 return method()
311 return method()
312 return None
312 return None
313 else:
313 else:
314 return None
314 return None
315
315
316 def __contains__(self, typ):
316 def __contains__(self, typ):
317 """map in to lookup_by_type"""
317 """map in to lookup_by_type"""
318 try:
318 try:
319 self.lookup_by_type(typ)
319 self.lookup_by_type(typ)
320 except KeyError:
320 except KeyError:
321 return False
321 return False
322 else:
322 else:
323 return True
323 return True
324
324
325 def _check_return(self, r, obj):
325 def _check_return(self, r, obj):
326 """Check that a return value is appropriate
326 """Check that a return value is appropriate
327
327
328 Return the value if so, None otherwise, warning if invalid.
328 Return the value if so, None otherwise, warning if invalid.
329 """
329 """
330 if r is None or isinstance(r, self._return_type) or \
330 if r is None or isinstance(r, self._return_type) or \
331 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
331 (isinstance(r, tuple) and r and isinstance(r[0], self._return_type)):
332 return r
332 return r
333 else:
333 else:
334 warnings.warn(
334 warnings.warn(
335 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
335 "%s formatter returned invalid type %s (expected %s) for object: %s" % \
336 (self.format_type, type(r), self._return_type, _safe_repr(obj)),
336 (self.format_type, type(r), self._return_type, _safe_repr(obj)),
337 FormatterWarning
337 FormatterWarning
338 )
338 )
339
339
340 def lookup(self, obj):
340 def lookup(self, obj):
341 """Look up the formatter for a given instance.
341 """Look up the formatter for a given instance.
342
342
343 Parameters
343 Parameters
344 ----------
344 ----------
345 obj : object instance
345 obj : object instance
346
346
347 Returns
347 Returns
348 -------
348 -------
349 f : callable
349 f : callable
350 The registered formatting callable for the type.
350 The registered formatting callable for the type.
351
351
352 Raises
352 Raises
353 ------
353 ------
354 KeyError if the type has not been registered.
354 KeyError if the type has not been registered.
355 """
355 """
356 # look for singleton first
356 # look for singleton first
357 obj_id = id(obj)
357 obj_id = id(obj)
358 if obj_id in self.singleton_printers:
358 if obj_id in self.singleton_printers:
359 return self.singleton_printers[obj_id]
359 return self.singleton_printers[obj_id]
360 # then lookup by type
360 # then lookup by type
361 return self.lookup_by_type(_get_type(obj))
361 return self.lookup_by_type(_get_type(obj))
362
362
363 def lookup_by_type(self, typ):
363 def lookup_by_type(self, typ):
364 """Look up the registered formatter for a type.
364 """Look up the registered formatter for a type.
365
365
366 Parameters
366 Parameters
367 ----------
367 ----------
368 typ : type or '__module__.__name__' string for a type
368 typ : type or '__module__.__name__' string for a type
369
369
370 Returns
370 Returns
371 -------
371 -------
372 f : callable
372 f : callable
373 The registered formatting callable for the type.
373 The registered formatting callable for the type.
374
374
375 Raises
375 Raises
376 ------
376 ------
377 KeyError if the type has not been registered.
377 KeyError if the type has not been registered.
378 """
378 """
379 if isinstance(typ, string_types):
379 if isinstance(typ, string_types):
380 typ_key = tuple(typ.rsplit('.',1))
380 typ_key = tuple(typ.rsplit('.',1))
381 if typ_key not in self.deferred_printers:
381 if typ_key not in self.deferred_printers:
382 # We may have it cached in the type map. We will have to
382 # We may have it cached in the type map. We will have to
383 # iterate over all of the types to check.
383 # iterate over all of the types to check.
384 for cls in self.type_printers:
384 for cls in self.type_printers:
385 if _mod_name_key(cls) == typ_key:
385 if _mod_name_key(cls) == typ_key:
386 return self.type_printers[cls]
386 return self.type_printers[cls]
387 else:
387 else:
388 return self.deferred_printers[typ_key]
388 return self.deferred_printers[typ_key]
389 else:
389 else:
390 for cls in pretty._get_mro(typ):
390 for cls in pretty._get_mro(typ):
391 if cls in self.type_printers or self._in_deferred_types(cls):
391 if cls in self.type_printers or self._in_deferred_types(cls):
392 return self.type_printers[cls]
392 return self.type_printers[cls]
393
393
394 # If we have reached here, the lookup failed.
394 # If we have reached here, the lookup failed.
395 raise KeyError("No registered printer for {0!r}".format(typ))
395 raise KeyError("No registered printer for {0!r}".format(typ))
396
396
397 def for_type(self, typ, func=None):
397 def for_type(self, typ, func=None):
398 """Add a format function for a given type.
398 """Add a format function for a given 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 The class of the object that will be formatted using `func`.
403 The class of the object that will be formatted using `func`.
404 func : callable
404 func : callable
405 A callable for computing the format data.
405 A callable for computing the format data.
406 `func` will be called with the object to be formatted,
406 `func` will be called with the object to be formatted,
407 and will return the raw data in this formatter's format.
407 and will return the raw data in this formatter's format.
408 Subclasses may use a different call signature for the
408 Subclasses may use a different call signature for the
409 `func` argument.
409 `func` argument.
410
410
411 If `func` is None or not specified, there will be no change,
411 If `func` is None or not specified, there will be no change,
412 only returning the current value.
412 only returning the current value.
413
413
414 Returns
414 Returns
415 -------
415 -------
416 oldfunc : callable
416 oldfunc : callable
417 The currently registered callable.
417 The currently registered callable.
418 If you are registering a new formatter,
418 If you are registering a new formatter,
419 this will be the previous value (to enable restoring later).
419 this will be the previous value (to enable restoring later).
420 """
420 """
421 # if string given, interpret as 'pkg.module.class_name'
421 # if string given, interpret as 'pkg.module.class_name'
422 if isinstance(typ, string_types):
422 if isinstance(typ, string_types):
423 type_module, type_name = typ.rsplit('.', 1)
423 type_module, type_name = typ.rsplit('.', 1)
424 return self.for_type_by_name(type_module, type_name, func)
424 return self.for_type_by_name(type_module, type_name, func)
425
425
426 try:
426 try:
427 oldfunc = self.lookup_by_type(typ)
427 oldfunc = self.lookup_by_type(typ)
428 except KeyError:
428 except KeyError:
429 oldfunc = None
429 oldfunc = None
430
430
431 if func is not None:
431 if func is not None:
432 self.type_printers[typ] = func
432 self.type_printers[typ] = func
433
433
434 return oldfunc
434 return oldfunc
435
435
436 def for_type_by_name(self, type_module, type_name, func=None):
436 def for_type_by_name(self, type_module, type_name, func=None):
437 """Add a format function for a type specified by the full dotted
437 """Add a format function for a type specified by the full dotted
438 module and name of the type, rather than the type of the object.
438 module and name of the type, rather than the type of the object.
439
439
440 Parameters
440 Parameters
441 ----------
441 ----------
442 type_module : str
442 type_module : str
443 The full dotted name of the module the type is defined in, like
443 The full dotted name of the module the type is defined in, like
444 ``numpy``.
444 ``numpy``.
445 type_name : str
445 type_name : str
446 The name of the type (the class name), like ``dtype``
446 The name of the type (the class name), like ``dtype``
447 func : callable
447 func : callable
448 A callable for computing the format data.
448 A callable for computing the format data.
449 `func` will be called with the object to be formatted,
449 `func` will be called with the object to be formatted,
450 and will return the raw data in this formatter's format.
450 and will return the raw data in this formatter's format.
451 Subclasses may use a different call signature for the
451 Subclasses may use a different call signature for the
452 `func` argument.
452 `func` argument.
453
453
454 If `func` is None or unspecified, there will be no change,
454 If `func` is None or unspecified, there will be no change,
455 only returning the current value.
455 only returning the current value.
456
456
457 Returns
457 Returns
458 -------
458 -------
459 oldfunc : callable
459 oldfunc : callable
460 The currently registered callable.
460 The currently registered callable.
461 If you are registering a new formatter,
461 If you are registering a new formatter,
462 this will be the previous value (to enable restoring later).
462 this will be the previous value (to enable restoring later).
463 """
463 """
464 key = (type_module, type_name)
464 key = (type_module, type_name)
465
465
466 try:
466 try:
467 oldfunc = self.lookup_by_type("%s.%s" % key)
467 oldfunc = self.lookup_by_type("%s.%s" % key)
468 except KeyError:
468 except KeyError:
469 oldfunc = None
469 oldfunc = None
470
470
471 if func is not None:
471 if func is not None:
472 self.deferred_printers[key] = func
472 self.deferred_printers[key] = func
473 return oldfunc
473 return oldfunc
474
474
475 def pop(self, typ, default=_raise_key_error):
475 def pop(self, typ, default=_raise_key_error):
476 """Pop a formatter for the given type.
476 """Pop a formatter for the given type.
477
477
478 Parameters
478 Parameters
479 ----------
479 ----------
480 typ : type or '__module__.__name__' string for a type
480 typ : type or '__module__.__name__' string for a type
481 default : object
481 default : object
482 value to be returned if no formatter is registered for typ.
482 value to be returned if no formatter is registered for typ.
483
483
484 Returns
484 Returns
485 -------
485 -------
486 obj : object
486 obj : object
487 The last registered object for the type.
487 The last registered object for the type.
488
488
489 Raises
489 Raises
490 ------
490 ------
491 KeyError if the type is not registered and default is not specified.
491 KeyError if the type is not registered and default is not specified.
492 """
492 """
493
493
494 if isinstance(typ, string_types):
494 if isinstance(typ, string_types):
495 typ_key = tuple(typ.rsplit('.',1))
495 typ_key = tuple(typ.rsplit('.',1))
496 if typ_key not in self.deferred_printers:
496 if typ_key not in self.deferred_printers:
497 # We may have it cached in the type map. We will have to
497 # We may have it cached in the type map. We will have to
498 # iterate over all of the types to check.
498 # iterate over all of the types to check.
499 for cls in self.type_printers:
499 for cls in self.type_printers:
500 if _mod_name_key(cls) == typ_key:
500 if _mod_name_key(cls) == typ_key:
501 old = self.type_printers.pop(cls)
501 old = self.type_printers.pop(cls)
502 break
502 break
503 else:
503 else:
504 old = default
504 old = default
505 else:
505 else:
506 old = self.deferred_printers.pop(typ_key)
506 old = self.deferred_printers.pop(typ_key)
507 else:
507 else:
508 if typ in self.type_printers:
508 if typ in self.type_printers:
509 old = self.type_printers.pop(typ)
509 old = self.type_printers.pop(typ)
510 else:
510 else:
511 old = self.deferred_printers.pop(_mod_name_key(typ), default)
511 old = self.deferred_printers.pop(_mod_name_key(typ), default)
512 if old is _raise_key_error:
512 if old is _raise_key_error:
513 raise KeyError("No registered value for {0!r}".format(typ))
513 raise KeyError("No registered value for {0!r}".format(typ))
514 return old
514 return old
515
515
516 def _in_deferred_types(self, cls):
516 def _in_deferred_types(self, cls):
517 """
517 """
518 Check if the given class is specified in the deferred type registry.
518 Check if the given class is specified in the deferred type registry.
519
519
520 Successful matches will be moved to the regular type registry for future use.
520 Successful matches will be moved to the regular type registry for future use.
521 """
521 """
522 mod = getattr(cls, '__module__', None)
522 mod = getattr(cls, '__module__', None)
523 name = getattr(cls, '__name__', None)
523 name = getattr(cls, '__name__', None)
524 key = (mod, name)
524 key = (mod, name)
525 if key in self.deferred_printers:
525 if key in self.deferred_printers:
526 # Move the printer over to the regular registry.
526 # Move the printer over to the regular registry.
527 printer = self.deferred_printers.pop(key)
527 printer = self.deferred_printers.pop(key)
528 self.type_printers[cls] = printer
528 self.type_printers[cls] = printer
529 return True
529 return True
530 return False
530 return False
531
531
532
532
533 class PlainTextFormatter(BaseFormatter):
533 class PlainTextFormatter(BaseFormatter):
534 """The default pretty-printer.
534 """The default pretty-printer.
535
535
536 This uses :mod:`IPython.lib.pretty` to compute the format data of
536 This uses :mod:`IPython.lib.pretty` to compute the format data of
537 the object. If the object cannot be pretty printed, :func:`repr` is used.
537 the object. If the object cannot be pretty printed, :func:`repr` is used.
538 See the documentation of :mod:`IPython.lib.pretty` for details on
538 See the documentation of :mod:`IPython.lib.pretty` for details on
539 how to write pretty printers. Here is a simple example::
539 how to write pretty printers. Here is a simple example::
540
540
541 def dtype_pprinter(obj, p, cycle):
541 def dtype_pprinter(obj, p, cycle):
542 if cycle:
542 if cycle:
543 return p.text('dtype(...)')
543 return p.text('dtype(...)')
544 if hasattr(obj, 'fields'):
544 if hasattr(obj, 'fields'):
545 if obj.fields is None:
545 if obj.fields is None:
546 p.text(repr(obj))
546 p.text(repr(obj))
547 else:
547 else:
548 p.begin_group(7, 'dtype([')
548 p.begin_group(7, 'dtype([')
549 for i, field in enumerate(obj.descr):
549 for i, field in enumerate(obj.descr):
550 if i > 0:
550 if i > 0:
551 p.text(',')
551 p.text(',')
552 p.breakable()
552 p.breakable()
553 p.pretty(field)
553 p.pretty(field)
554 p.end_group(7, '])')
554 p.end_group(7, '])')
555 """
555 """
556
556
557 # The format type of data returned.
557 # The format type of data returned.
558 format_type = Unicode('text/plain')
558 format_type = Unicode('text/plain')
559
559
560 # This subclass ignores this attribute as it always need to return
560 # This subclass ignores this attribute as it always need to return
561 # something.
561 # something.
562 enabled = Bool(True).tag(config=False)
562 enabled = Bool(True).tag(config=False)
563
563
564 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
564 max_seq_length = Integer(pretty.MAX_SEQ_LENGTH,
565 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
565 help="""Truncate large collections (lists, dicts, tuples, sets) to this size.
566
566
567 Set to 0 to disable truncation.
567 Set to 0 to disable truncation.
568 """
568 """
569 ).tag(config=True)
569 ).tag(config=True)
570
570
571 # Look for a _repr_pretty_ methods to use for pretty printing.
571 # Look for a _repr_pretty_ methods to use for pretty printing.
572 print_method = ObjectName('_repr_pretty_')
572 print_method = ObjectName('_repr_pretty_')
573
573
574 # Whether to pretty-print or not.
574 # Whether to pretty-print or not.
575 pprint = Bool(True).tag(config=True)
575 pprint = Bool(True).tag(config=True)
576
576
577 # Whether to be verbose or not.
577 # Whether to be verbose or not.
578 verbose = Bool(False).tag(config=True)
578 verbose = Bool(False).tag(config=True)
579
579
580 # The maximum width.
580 # The maximum width.
581 max_width = Integer(79).tag(config=True)
581 max_width = Integer(79).tag(config=True)
582
582
583 # The newline character.
583 # The newline character.
584 newline = Unicode('\n').tag(config=True)
584 newline = Unicode('\n').tag(config=True)
585
585
586 # format-string for pprinting floats
586 # format-string for pprinting floats
587 float_format = Unicode('%r')
587 float_format = Unicode('%r')
588 # setter for float precision, either int or direct format-string
588 # setter for float precision, either int or direct format-string
589 float_precision = CUnicode('').tag(config=True)
589 float_precision = CUnicode('').tag(config=True)
590
590
591 def _float_precision_changed(self, name, old, new):
591 @observe('float_precision')
592 def _float_precision_changed(self, change):
592 """float_precision changed, set float_format accordingly.
593 """float_precision changed, set float_format accordingly.
593
594
594 float_precision can be set by int or str.
595 float_precision can be set by int or str.
595 This will set float_format, after interpreting input.
596 This will set float_format, after interpreting input.
596 If numpy has been imported, numpy print precision will also be set.
597 If numpy has been imported, numpy print precision will also be set.
597
598
598 integer `n` sets format to '%.nf', otherwise, format set directly.
599 integer `n` sets format to '%.nf', otherwise, format set directly.
599
600
600 An empty string returns to defaults (repr for float, 8 for numpy).
601 An empty string returns to defaults (repr for float, 8 for numpy).
601
602
602 This parameter can be set via the '%precision' magic.
603 This parameter can be set via the '%precision' magic.
603 """
604 """
604
605
606 new = change['new']
605 if '%' in new:
607 if '%' in new:
606 # got explicit format string
608 # got explicit format string
607 fmt = new
609 fmt = new
608 try:
610 try:
609 fmt%3.14159
611 fmt%3.14159
610 except Exception:
612 except Exception:
611 raise ValueError("Precision must be int or format string, not %r"%new)
613 raise ValueError("Precision must be int or format string, not %r"%new)
612 elif new:
614 elif new:
613 # otherwise, should be an int
615 # otherwise, should be an int
614 try:
616 try:
615 i = int(new)
617 i = int(new)
616 assert i >= 0
618 assert i >= 0
617 except ValueError:
619 except ValueError:
618 raise ValueError("Precision must be int or format string, not %r"%new)
620 raise ValueError("Precision must be int or format string, not %r"%new)
619 except AssertionError:
621 except AssertionError:
620 raise ValueError("int precision must be non-negative, not %r"%i)
622 raise ValueError("int precision must be non-negative, not %r"%i)
621
623
622 fmt = '%%.%if'%i
624 fmt = '%%.%if'%i
623 if 'numpy' in sys.modules:
625 if 'numpy' in sys.modules:
624 # set numpy precision if it has been imported
626 # set numpy precision if it has been imported
625 import numpy
627 import numpy
626 numpy.set_printoptions(precision=i)
628 numpy.set_printoptions(precision=i)
627 else:
629 else:
628 # default back to repr
630 # default back to repr
629 fmt = '%r'
631 fmt = '%r'
630 if 'numpy' in sys.modules:
632 if 'numpy' in sys.modules:
631 import numpy
633 import numpy
632 # numpy default is 8
634 # numpy default is 8
633 numpy.set_printoptions(precision=8)
635 numpy.set_printoptions(precision=8)
634 self.float_format = fmt
636 self.float_format = fmt
635
637
636 # Use the default pretty printers from IPython.lib.pretty.
638 # Use the default pretty printers from IPython.lib.pretty.
637 @default('singleton_printers')
639 @default('singleton_printers')
638 def _singleton_printers_default(self):
640 def _singleton_printers_default(self):
639 return pretty._singleton_pprinters.copy()
641 return pretty._singleton_pprinters.copy()
640
642
641 @default('type_printers')
643 @default('type_printers')
642 def _type_printers_default(self):
644 def _type_printers_default(self):
643 d = pretty._type_pprinters.copy()
645 d = pretty._type_pprinters.copy()
644 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
646 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
645 return d
647 return d
646
648
647 @default('deferred_printers')
649 @default('deferred_printers')
648 def _deferred_printers_default(self):
650 def _deferred_printers_default(self):
649 return pretty._deferred_type_pprinters.copy()
651 return pretty._deferred_type_pprinters.copy()
650
652
651 #### FormatterABC interface ####
653 #### FormatterABC interface ####
652
654
653 @catch_format_error
655 @catch_format_error
654 def __call__(self, obj):
656 def __call__(self, obj):
655 """Compute the pretty representation of the object."""
657 """Compute the pretty representation of the object."""
656 if not self.pprint:
658 if not self.pprint:
657 return repr(obj)
659 return repr(obj)
658 else:
660 else:
659 # handle str and unicode on Python 2
661 # handle str and unicode on Python 2
660 # io.StringIO only accepts unicode,
662 # io.StringIO only accepts unicode,
661 # cStringIO doesn't handle unicode on py2,
663 # cStringIO doesn't handle unicode on py2,
662 # StringIO allows str, unicode but only ascii str
664 # StringIO allows str, unicode but only ascii str
663 stream = pretty.CUnicodeIO()
665 stream = pretty.CUnicodeIO()
664 printer = pretty.RepresentationPrinter(stream, self.verbose,
666 printer = pretty.RepresentationPrinter(stream, self.verbose,
665 self.max_width, self.newline,
667 self.max_width, self.newline,
666 max_seq_length=self.max_seq_length,
668 max_seq_length=self.max_seq_length,
667 singleton_pprinters=self.singleton_printers,
669 singleton_pprinters=self.singleton_printers,
668 type_pprinters=self.type_printers,
670 type_pprinters=self.type_printers,
669 deferred_pprinters=self.deferred_printers)
671 deferred_pprinters=self.deferred_printers)
670 printer.pretty(obj)
672 printer.pretty(obj)
671 printer.flush()
673 printer.flush()
672 return stream.getvalue()
674 return stream.getvalue()
673
675
674
676
675 class HTMLFormatter(BaseFormatter):
677 class HTMLFormatter(BaseFormatter):
676 """An HTML formatter.
678 """An HTML formatter.
677
679
678 To define the callables that compute the HTML representation of your
680 To define the callables that compute the HTML representation of your
679 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
681 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
680 or :meth:`for_type_by_name` methods to register functions that handle
682 or :meth:`for_type_by_name` methods to register functions that handle
681 this.
683 this.
682
684
683 The return value of this formatter should be a valid HTML snippet that
685 The return value of this formatter should be a valid HTML snippet that
684 could be injected into an existing DOM. It should *not* include the
686 could be injected into an existing DOM. It should *not* include the
685 ```<html>`` or ```<body>`` tags.
687 ```<html>`` or ```<body>`` tags.
686 """
688 """
687 format_type = Unicode('text/html')
689 format_type = Unicode('text/html')
688
690
689 print_method = ObjectName('_repr_html_')
691 print_method = ObjectName('_repr_html_')
690
692
691
693
692 class MarkdownFormatter(BaseFormatter):
694 class MarkdownFormatter(BaseFormatter):
693 """A Markdown formatter.
695 """A Markdown formatter.
694
696
695 To define the callables that compute the Markdown representation of your
697 To define the callables that compute the Markdown representation of your
696 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
698 objects, define a :meth:`_repr_markdown_` method or use the :meth:`for_type`
697 or :meth:`for_type_by_name` methods to register functions that handle
699 or :meth:`for_type_by_name` methods to register functions that handle
698 this.
700 this.
699
701
700 The return value of this formatter should be a valid Markdown.
702 The return value of this formatter should be a valid Markdown.
701 """
703 """
702 format_type = Unicode('text/markdown')
704 format_type = Unicode('text/markdown')
703
705
704 print_method = ObjectName('_repr_markdown_')
706 print_method = ObjectName('_repr_markdown_')
705
707
706 class SVGFormatter(BaseFormatter):
708 class SVGFormatter(BaseFormatter):
707 """An SVG formatter.
709 """An SVG formatter.
708
710
709 To define the callables that compute the SVG representation of your
711 To define the callables that compute the SVG representation of your
710 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
712 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
711 or :meth:`for_type_by_name` methods to register functions that handle
713 or :meth:`for_type_by_name` methods to register functions that handle
712 this.
714 this.
713
715
714 The return value of this formatter should be valid SVG enclosed in
716 The return value of this formatter should be valid SVG enclosed in
715 ```<svg>``` tags, that could be injected into an existing DOM. It should
717 ```<svg>``` tags, that could be injected into an existing DOM. It should
716 *not* include the ```<html>`` or ```<body>`` tags.
718 *not* include the ```<html>`` or ```<body>`` tags.
717 """
719 """
718 format_type = Unicode('image/svg+xml')
720 format_type = Unicode('image/svg+xml')
719
721
720 print_method = ObjectName('_repr_svg_')
722 print_method = ObjectName('_repr_svg_')
721
723
722
724
723 class PNGFormatter(BaseFormatter):
725 class PNGFormatter(BaseFormatter):
724 """A PNG formatter.
726 """A PNG formatter.
725
727
726 To define the callables that compute the PNG representation of your
728 To define the callables that compute the PNG representation of your
727 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
729 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
728 or :meth:`for_type_by_name` methods to register functions that handle
730 or :meth:`for_type_by_name` methods to register functions that handle
729 this.
731 this.
730
732
731 The return value of this formatter should be raw PNG data, *not*
733 The return value of this formatter should be raw PNG data, *not*
732 base64 encoded.
734 base64 encoded.
733 """
735 """
734 format_type = Unicode('image/png')
736 format_type = Unicode('image/png')
735
737
736 print_method = ObjectName('_repr_png_')
738 print_method = ObjectName('_repr_png_')
737
739
738 _return_type = (bytes, unicode_type)
740 _return_type = (bytes, unicode_type)
739
741
740
742
741 class JPEGFormatter(BaseFormatter):
743 class JPEGFormatter(BaseFormatter):
742 """A JPEG formatter.
744 """A JPEG formatter.
743
745
744 To define the callables that compute the JPEG representation of your
746 To define the callables that compute the JPEG representation of your
745 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
747 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
746 or :meth:`for_type_by_name` methods to register functions that handle
748 or :meth:`for_type_by_name` methods to register functions that handle
747 this.
749 this.
748
750
749 The return value of this formatter should be raw JPEG data, *not*
751 The return value of this formatter should be raw JPEG data, *not*
750 base64 encoded.
752 base64 encoded.
751 """
753 """
752 format_type = Unicode('image/jpeg')
754 format_type = Unicode('image/jpeg')
753
755
754 print_method = ObjectName('_repr_jpeg_')
756 print_method = ObjectName('_repr_jpeg_')
755
757
756 _return_type = (bytes, unicode_type)
758 _return_type = (bytes, unicode_type)
757
759
758
760
759 class LatexFormatter(BaseFormatter):
761 class LatexFormatter(BaseFormatter):
760 """A LaTeX formatter.
762 """A LaTeX formatter.
761
763
762 To define the callables that compute the LaTeX representation of your
764 To define the callables that compute the LaTeX representation of your
763 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
765 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
764 or :meth:`for_type_by_name` methods to register functions that handle
766 or :meth:`for_type_by_name` methods to register functions that handle
765 this.
767 this.
766
768
767 The return value of this formatter should be a valid LaTeX equation,
769 The return value of this formatter should be a valid LaTeX equation,
768 enclosed in either ```$```, ```$$``` or another LaTeX equation
770 enclosed in either ```$```, ```$$``` or another LaTeX equation
769 environment.
771 environment.
770 """
772 """
771 format_type = Unicode('text/latex')
773 format_type = Unicode('text/latex')
772
774
773 print_method = ObjectName('_repr_latex_')
775 print_method = ObjectName('_repr_latex_')
774
776
775
777
776 class JSONFormatter(BaseFormatter):
778 class JSONFormatter(BaseFormatter):
777 """A JSON string formatter.
779 """A JSON string formatter.
778
780
779 To define the callables that compute the JSONable representation of
781 To define the callables that compute the JSONable representation of
780 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
782 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
781 or :meth:`for_type_by_name` methods to register functions that handle
783 or :meth:`for_type_by_name` methods to register functions that handle
782 this.
784 this.
783
785
784 The return value of this formatter should be a JSONable list or dict.
786 The return value of this formatter should be a JSONable list or dict.
785 JSON scalars (None, number, string) are not allowed, only dict or list containers.
787 JSON scalars (None, number, string) are not allowed, only dict or list containers.
786 """
788 """
787 format_type = Unicode('application/json')
789 format_type = Unicode('application/json')
788 _return_type = (list, dict)
790 _return_type = (list, dict)
789
791
790 print_method = ObjectName('_repr_json_')
792 print_method = ObjectName('_repr_json_')
791
793
792 def _check_return(self, r, obj):
794 def _check_return(self, r, obj):
793 """Check that a return value is appropriate
795 """Check that a return value is appropriate
794
796
795 Return the value if so, None otherwise, warning if invalid.
797 Return the value if so, None otherwise, warning if invalid.
796 """
798 """
797 if r is None:
799 if r is None:
798 return
800 return
799 md = None
801 md = None
800 if isinstance(r, tuple):
802 if isinstance(r, tuple):
801 # unpack data, metadata tuple for type checking on first element
803 # unpack data, metadata tuple for type checking on first element
802 r, md = r
804 r, md = r
803
805
804 # handle deprecated JSON-as-string form from IPython < 3
806 # handle deprecated JSON-as-string form from IPython < 3
805 if isinstance(r, string_types):
807 if isinstance(r, string_types):
806 warnings.warn("JSON expects JSONable list/dict containers, not JSON strings",
808 warnings.warn("JSON expects JSONable list/dict containers, not JSON strings",
807 FormatterWarning)
809 FormatterWarning)
808 r = json.loads(r)
810 r = json.loads(r)
809
811
810 if md is not None:
812 if md is not None:
811 # put the tuple back together
813 # put the tuple back together
812 r = (r, md)
814 r = (r, md)
813 return super(JSONFormatter, self)._check_return(r, obj)
815 return super(JSONFormatter, self)._check_return(r, obj)
814
816
815
817
816 class JavascriptFormatter(BaseFormatter):
818 class JavascriptFormatter(BaseFormatter):
817 """A Javascript formatter.
819 """A Javascript formatter.
818
820
819 To define the callables that compute the Javascript representation of
821 To define the callables that compute the Javascript representation of
820 your objects, define a :meth:`_repr_javascript_` method or use the
822 your objects, define a :meth:`_repr_javascript_` method or use the
821 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
823 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
822 that handle this.
824 that handle this.
823
825
824 The return value of this formatter should be valid Javascript code and
826 The return value of this formatter should be valid Javascript code and
825 should *not* be enclosed in ```<script>``` tags.
827 should *not* be enclosed in ```<script>``` tags.
826 """
828 """
827 format_type = Unicode('application/javascript')
829 format_type = Unicode('application/javascript')
828
830
829 print_method = ObjectName('_repr_javascript_')
831 print_method = ObjectName('_repr_javascript_')
830
832
831
833
832 class PDFFormatter(BaseFormatter):
834 class PDFFormatter(BaseFormatter):
833 """A PDF formatter.
835 """A PDF formatter.
834
836
835 To define the callables that compute the PDF representation of your
837 To define the callables that compute the PDF representation of your
836 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
838 objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type`
837 or :meth:`for_type_by_name` methods to register functions that handle
839 or :meth:`for_type_by_name` methods to register functions that handle
838 this.
840 this.
839
841
840 The return value of this formatter should be raw PDF data, *not*
842 The return value of this formatter should be raw PDF data, *not*
841 base64 encoded.
843 base64 encoded.
842 """
844 """
843 format_type = Unicode('application/pdf')
845 format_type = Unicode('application/pdf')
844
846
845 print_method = ObjectName('_repr_pdf_')
847 print_method = ObjectName('_repr_pdf_')
846
848
847 _return_type = (bytes, unicode_type)
849 _return_type = (bytes, unicode_type)
848
850
849 class IPythonDisplayFormatter(BaseFormatter):
851 class IPythonDisplayFormatter(BaseFormatter):
850 """A Formatter for objects that know how to display themselves.
852 """A Formatter for objects that know how to display themselves.
851
853
852 To define the callables that compute the representation of your
854 To define the callables that compute the representation of your
853 objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
855 objects, define a :meth:`_ipython_display_` method or use the :meth:`for_type`
854 or :meth:`for_type_by_name` methods to register functions that handle
856 or :meth:`for_type_by_name` methods to register functions that handle
855 this. Unlike mime-type displays, this method should not return anything,
857 this. Unlike mime-type displays, this method should not return anything,
856 instead calling any appropriate display methods itself.
858 instead calling any appropriate display methods itself.
857
859
858 This display formatter has highest priority.
860 This display formatter has highest priority.
859 If it fires, no other display formatter will be called.
861 If it fires, no other display formatter will be called.
860 """
862 """
861 print_method = ObjectName('_ipython_display_')
863 print_method = ObjectName('_ipython_display_')
862 _return_type = (type(None), bool)
864 _return_type = (type(None), bool)
863
865
864
866
865 @catch_format_error
867 @catch_format_error
866 def __call__(self, obj):
868 def __call__(self, obj):
867 """Compute the format for an object."""
869 """Compute the format for an object."""
868 if self.enabled:
870 if self.enabled:
869 # lookup registered printer
871 # lookup registered printer
870 try:
872 try:
871 printer = self.lookup(obj)
873 printer = self.lookup(obj)
872 except KeyError:
874 except KeyError:
873 pass
875 pass
874 else:
876 else:
875 printer(obj)
877 printer(obj)
876 return True
878 return True
877 # Finally look for special method names
879 # Finally look for special method names
878 method = get_real_method(obj, self.print_method)
880 method = get_real_method(obj, self.print_method)
879 if method is not None:
881 if method is not None:
880 method()
882 method()
881 return True
883 return True
882
884
883
885
884 FormatterABC.register(BaseFormatter)
886 FormatterABC.register(BaseFormatter)
885 FormatterABC.register(PlainTextFormatter)
887 FormatterABC.register(PlainTextFormatter)
886 FormatterABC.register(HTMLFormatter)
888 FormatterABC.register(HTMLFormatter)
887 FormatterABC.register(MarkdownFormatter)
889 FormatterABC.register(MarkdownFormatter)
888 FormatterABC.register(SVGFormatter)
890 FormatterABC.register(SVGFormatter)
889 FormatterABC.register(PNGFormatter)
891 FormatterABC.register(PNGFormatter)
890 FormatterABC.register(PDFFormatter)
892 FormatterABC.register(PDFFormatter)
891 FormatterABC.register(JPEGFormatter)
893 FormatterABC.register(JPEGFormatter)
892 FormatterABC.register(LatexFormatter)
894 FormatterABC.register(LatexFormatter)
893 FormatterABC.register(JSONFormatter)
895 FormatterABC.register(JSONFormatter)
894 FormatterABC.register(JavascriptFormatter)
896 FormatterABC.register(JavascriptFormatter)
895 FormatterABC.register(IPythonDisplayFormatter)
897 FormatterABC.register(IPythonDisplayFormatter)
896
898
897
899
898 def format_display_data(obj, include=None, exclude=None):
900 def format_display_data(obj, include=None, exclude=None):
899 """Return a format data dict for an object.
901 """Return a format data dict for an object.
900
902
901 By default all format types will be computed.
903 By default all format types will be computed.
902
904
903 The following MIME types are currently implemented:
905 The following MIME types are currently implemented:
904
906
905 * text/plain
907 * text/plain
906 * text/html
908 * text/html
907 * text/markdown
909 * text/markdown
908 * text/latex
910 * text/latex
909 * application/json
911 * application/json
910 * application/javascript
912 * application/javascript
911 * application/pdf
913 * application/pdf
912 * image/png
914 * image/png
913 * image/jpeg
915 * image/jpeg
914 * image/svg+xml
916 * image/svg+xml
915
917
916 Parameters
918 Parameters
917 ----------
919 ----------
918 obj : object
920 obj : object
919 The Python object whose format data will be computed.
921 The Python object whose format data will be computed.
920
922
921 Returns
923 Returns
922 -------
924 -------
923 format_dict : dict
925 format_dict : dict
924 A dictionary of key/value pairs, one or each format that was
926 A dictionary of key/value pairs, one or each format that was
925 generated for the object. The keys are the format types, which
927 generated for the object. The keys are the format types, which
926 will usually be MIME type strings and the values and JSON'able
928 will usually be MIME type strings and the values and JSON'able
927 data structure containing the raw data for the representation in
929 data structure containing the raw data for the representation in
928 that format.
930 that format.
929 include : list or tuple, optional
931 include : list or tuple, optional
930 A list of format type strings (MIME types) to include in the
932 A list of format type strings (MIME types) to include in the
931 format data dict. If this is set *only* the format types included
933 format data dict. If this is set *only* the format types included
932 in this list will be computed.
934 in this list will be computed.
933 exclude : list or tuple, optional
935 exclude : list or tuple, optional
934 A list of format type string (MIME types) to exclue in the format
936 A list of format type string (MIME types) to exclue in the format
935 data dict. If this is set all format types will be computed,
937 data dict. If this is set all format types will be computed,
936 except for those included in this argument.
938 except for those included in this argument.
937 """
939 """
938 from IPython.core.interactiveshell import InteractiveShell
940 from IPython.core.interactiveshell import InteractiveShell
939
941
940 return InteractiveShell.instance().display_formatter.format(
942 return InteractiveShell.instance().display_formatter.format(
941 obj,
943 obj,
942 include,
944 include,
943 exclude
945 exclude
944 )
946 )
945
947
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,411 +1,411 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A mixin for :class:`~IPython.core.application.Application` classes that
3 A mixin for :class:`~IPython.core.application.Application` classes that
4 launch InteractiveShell instances, load extensions, etc.
4 launch InteractiveShell instances, load extensions, etc.
5 """
5 """
6
6
7 # Copyright (c) IPython Development Team.
7 # Copyright (c) IPython Development Team.
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9
9
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 import glob
13 import glob
14 import os
14 import os
15 import sys
15 import sys
16
16
17 from traitlets.config.application import boolean_flag
17 from traitlets.config.application import boolean_flag
18 from traitlets.config.configurable import Configurable
18 from traitlets.config.configurable import Configurable
19 from traitlets.config.loader import Config
19 from traitlets.config.loader import Config
20 from IPython.core import pylabtools
20 from IPython.core import pylabtools
21 from IPython.utils import py3compat
21 from IPython.utils import py3compat
22 from IPython.utils.contexts import preserve_keys
22 from IPython.utils.contexts import preserve_keys
23 from IPython.utils.path import filefind
23 from IPython.utils.path import filefind
24 from traitlets import (
24 from traitlets import (
25 Unicode, Instance, List, Bool, CaselessStrEnum, observe,
25 Unicode, Instance, List, Bool, CaselessStrEnum, observe,
26 )
26 )
27 from IPython.lib.inputhook import guis
27 from IPython.terminal import pt_inputhooks
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Aliases and Flags
30 # Aliases and Flags
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 gui_keys = tuple(sorted([ key for key in guis if key is not None ]))
33 gui_keys = tuple(sorted(pt_inputhooks.backends) + sorted(pt_inputhooks.aliases))
34
34
35 backend_keys = sorted(pylabtools.backends.keys())
35 backend_keys = sorted(pylabtools.backends.keys())
36 backend_keys.insert(0, 'auto')
36 backend_keys.insert(0, 'auto')
37
37
38 shell_flags = {}
38 shell_flags = {}
39
39
40 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
40 addflag = lambda *args: shell_flags.update(boolean_flag(*args))
41 addflag('autoindent', 'InteractiveShell.autoindent',
41 addflag('autoindent', 'InteractiveShell.autoindent',
42 'Turn on autoindenting.', 'Turn off autoindenting.'
42 'Turn on autoindenting.', 'Turn off autoindenting.'
43 )
43 )
44 addflag('automagic', 'InteractiveShell.automagic',
44 addflag('automagic', 'InteractiveShell.automagic',
45 """Turn on the auto calling of magic commands. Type %%magic at the
45 """Turn on the auto calling of magic commands. Type %%magic at the
46 IPython prompt for more information.""",
46 IPython prompt for more information.""",
47 'Turn off the auto calling of magic commands.'
47 'Turn off the auto calling of magic commands.'
48 )
48 )
49 addflag('pdb', 'InteractiveShell.pdb',
49 addflag('pdb', 'InteractiveShell.pdb',
50 "Enable auto calling the pdb debugger after every exception.",
50 "Enable auto calling the pdb debugger after every exception.",
51 "Disable auto calling the pdb debugger after every exception."
51 "Disable auto calling the pdb debugger after every exception."
52 )
52 )
53 addflag('pprint', 'PlainTextFormatter.pprint',
53 addflag('pprint', 'PlainTextFormatter.pprint',
54 "Enable auto pretty printing of results.",
54 "Enable auto pretty printing of results.",
55 "Disable auto pretty printing of results."
55 "Disable auto pretty printing of results."
56 )
56 )
57 addflag('color-info', 'InteractiveShell.color_info',
57 addflag('color-info', 'InteractiveShell.color_info',
58 """IPython can display information about objects via a set of functions,
58 """IPython can display information about objects via a set of functions,
59 and optionally can use colors for this, syntax highlighting
59 and optionally can use colors for this, syntax highlighting
60 source code and various other elements. This is on by default, but can cause
60 source code and various other elements. This is on by default, but can cause
61 problems with some pagers. If you see such problems, you can disable the
61 problems with some pagers. If you see such problems, you can disable the
62 colours.""",
62 colours.""",
63 "Disable using colors for info related things."
63 "Disable using colors for info related things."
64 )
64 )
65 nosep_config = Config()
65 nosep_config = Config()
66 nosep_config.InteractiveShell.separate_in = ''
66 nosep_config.InteractiveShell.separate_in = ''
67 nosep_config.InteractiveShell.separate_out = ''
67 nosep_config.InteractiveShell.separate_out = ''
68 nosep_config.InteractiveShell.separate_out2 = ''
68 nosep_config.InteractiveShell.separate_out2 = ''
69
69
70 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
70 shell_flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.")
71 shell_flags['pylab'] = (
71 shell_flags['pylab'] = (
72 {'InteractiveShellApp' : {'pylab' : 'auto'}},
72 {'InteractiveShellApp' : {'pylab' : 'auto'}},
73 """Pre-load matplotlib and numpy for interactive use with
73 """Pre-load matplotlib and numpy for interactive use with
74 the default matplotlib backend."""
74 the default matplotlib backend."""
75 )
75 )
76 shell_flags['matplotlib'] = (
76 shell_flags['matplotlib'] = (
77 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
77 {'InteractiveShellApp' : {'matplotlib' : 'auto'}},
78 """Configure matplotlib for interactive use with
78 """Configure matplotlib for interactive use with
79 the default matplotlib backend."""
79 the default matplotlib backend."""
80 )
80 )
81
81
82 # it's possible we don't want short aliases for *all* of these:
82 # it's possible we don't want short aliases for *all* of these:
83 shell_aliases = dict(
83 shell_aliases = dict(
84 autocall='InteractiveShell.autocall',
84 autocall='InteractiveShell.autocall',
85 colors='InteractiveShell.colors',
85 colors='InteractiveShell.colors',
86 logfile='InteractiveShell.logfile',
86 logfile='InteractiveShell.logfile',
87 logappend='InteractiveShell.logappend',
87 logappend='InteractiveShell.logappend',
88 c='InteractiveShellApp.code_to_run',
88 c='InteractiveShellApp.code_to_run',
89 m='InteractiveShellApp.module_to_run',
89 m='InteractiveShellApp.module_to_run',
90 ext='InteractiveShellApp.extra_extension',
90 ext='InteractiveShellApp.extra_extension',
91 gui='InteractiveShellApp.gui',
91 gui='InteractiveShellApp.gui',
92 pylab='InteractiveShellApp.pylab',
92 pylab='InteractiveShellApp.pylab',
93 matplotlib='InteractiveShellApp.matplotlib',
93 matplotlib='InteractiveShellApp.matplotlib',
94 )
94 )
95 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
95 shell_aliases['cache-size'] = 'InteractiveShell.cache_size'
96
96
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98 # Main classes and functions
98 # Main classes and functions
99 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
100
100
101 class InteractiveShellApp(Configurable):
101 class InteractiveShellApp(Configurable):
102 """A Mixin for applications that start InteractiveShell instances.
102 """A Mixin for applications that start InteractiveShell instances.
103
103
104 Provides configurables for loading extensions and executing files
104 Provides configurables for loading extensions and executing files
105 as part of configuring a Shell environment.
105 as part of configuring a Shell environment.
106
106
107 The following methods should be called by the :meth:`initialize` method
107 The following methods should be called by the :meth:`initialize` method
108 of the subclass:
108 of the subclass:
109
109
110 - :meth:`init_path`
110 - :meth:`init_path`
111 - :meth:`init_shell` (to be implemented by the subclass)
111 - :meth:`init_shell` (to be implemented by the subclass)
112 - :meth:`init_gui_pylab`
112 - :meth:`init_gui_pylab`
113 - :meth:`init_extensions`
113 - :meth:`init_extensions`
114 - :meth:`init_code`
114 - :meth:`init_code`
115 """
115 """
116 extensions = List(Unicode(),
116 extensions = List(Unicode(),
117 help="A list of dotted module names of IPython extensions to load."
117 help="A list of dotted module names of IPython extensions to load."
118 ).tag(config=True)
118 ).tag(config=True)
119 extra_extension = Unicode('',
119 extra_extension = Unicode('',
120 help="dotted module name of an IPython extension to load."
120 help="dotted module name of an IPython extension to load."
121 ).tag(config=True)
121 ).tag(config=True)
122
122
123 reraise_ipython_extension_failures = Bool(False,
123 reraise_ipython_extension_failures = Bool(False,
124 help="Reraise exceptions encountered loading IPython extensions?",
124 help="Reraise exceptions encountered loading IPython extensions?",
125 ).tag(config=True)
125 ).tag(config=True)
126
126
127 # Extensions that are always loaded (not configurable)
127 # Extensions that are always loaded (not configurable)
128 default_extensions = List(Unicode(), [u'storemagic']).tag(config=False)
128 default_extensions = List(Unicode(), [u'storemagic']).tag(config=False)
129
129
130 hide_initial_ns = Bool(True,
130 hide_initial_ns = Bool(True,
131 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
131 help="""Should variables loaded at startup (by startup files, exec_lines, etc.)
132 be hidden from tools like %who?"""
132 be hidden from tools like %who?"""
133 ).tag(config=True)
133 ).tag(config=True)
134
134
135 exec_files = List(Unicode(),
135 exec_files = List(Unicode(),
136 help="""List of files to run at IPython startup."""
136 help="""List of files to run at IPython startup."""
137 ).tag(config=True)
137 ).tag(config=True)
138 exec_PYTHONSTARTUP = Bool(True,
138 exec_PYTHONSTARTUP = Bool(True,
139 help="""Run the file referenced by the PYTHONSTARTUP environment
139 help="""Run the file referenced by the PYTHONSTARTUP environment
140 variable at IPython startup."""
140 variable at IPython startup."""
141 ).tag(config=True)
141 ).tag(config=True)
142 file_to_run = Unicode('',
142 file_to_run = Unicode('',
143 help="""A file to be run""").tag(config=True)
143 help="""A file to be run""").tag(config=True)
144
144
145 exec_lines = List(Unicode(),
145 exec_lines = List(Unicode(),
146 help="""lines of code to run at IPython startup."""
146 help="""lines of code to run at IPython startup."""
147 ).tag(config=True)
147 ).tag(config=True)
148 code_to_run = Unicode('',
148 code_to_run = Unicode('',
149 help="Execute the given command string."
149 help="Execute the given command string."
150 ).tag(config=True)
150 ).tag(config=True)
151 module_to_run = Unicode('',
151 module_to_run = Unicode('',
152 help="Run the module as a script."
152 help="Run the module as a script."
153 ).tag(config=True)
153 ).tag(config=True)
154 gui = CaselessStrEnum(gui_keys, allow_none=True,
154 gui = CaselessStrEnum(gui_keys, allow_none=True,
155 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
155 help="Enable GUI event loop integration with any of {0}.".format(gui_keys)
156 ).tag(config=True)
156 ).tag(config=True)
157 matplotlib = CaselessStrEnum(backend_keys, allow_none=True,
157 matplotlib = CaselessStrEnum(backend_keys, allow_none=True,
158 help="""Configure matplotlib for interactive use with
158 help="""Configure matplotlib for interactive use with
159 the default matplotlib backend."""
159 the default matplotlib backend."""
160 ).tag(config=True)
160 ).tag(config=True)
161 pylab = CaselessStrEnum(backend_keys, allow_none=True,
161 pylab = CaselessStrEnum(backend_keys, allow_none=True,
162 help="""Pre-load matplotlib and numpy for interactive use,
162 help="""Pre-load matplotlib and numpy for interactive use,
163 selecting a particular matplotlib backend and loop integration.
163 selecting a particular matplotlib backend and loop integration.
164 """
164 """
165 ).tag(config=True)
165 ).tag(config=True)
166 pylab_import_all = Bool(True,
166 pylab_import_all = Bool(True,
167 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
167 help="""If true, IPython will populate the user namespace with numpy, pylab, etc.
168 and an ``import *`` is done from numpy and pylab, when using pylab mode.
168 and an ``import *`` is done from numpy and pylab, when using pylab mode.
169
169
170 When False, pylab mode should not import any names into the user namespace.
170 When False, pylab mode should not import any names into the user namespace.
171 """
171 """
172 ).tag(config=True)
172 ).tag(config=True)
173 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
173 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
174 allow_none=True)
174 allow_none=True)
175 # whether interact-loop should start
175 # whether interact-loop should start
176 interact = Bool(True)
176 interact = Bool(True)
177
177
178 user_ns = Instance(dict, args=None, allow_none=True)
178 user_ns = Instance(dict, args=None, allow_none=True)
179 @observe('user_ns')
179 @observe('user_ns')
180 def _user_ns_changed(self, change):
180 def _user_ns_changed(self, change):
181 if self.shell is not None:
181 if self.shell is not None:
182 self.shell.user_ns = change['new']
182 self.shell.user_ns = change['new']
183 self.shell.init_user_ns()
183 self.shell.init_user_ns()
184
184
185 def init_path(self):
185 def init_path(self):
186 """Add current working directory, '', to sys.path"""
186 """Add current working directory, '', to sys.path"""
187 if sys.path[0] != '':
187 if sys.path[0] != '':
188 sys.path.insert(0, '')
188 sys.path.insert(0, '')
189
189
190 def init_shell(self):
190 def init_shell(self):
191 raise NotImplementedError("Override in subclasses")
191 raise NotImplementedError("Override in subclasses")
192
192
193 def init_gui_pylab(self):
193 def init_gui_pylab(self):
194 """Enable GUI event loop integration, taking pylab into account."""
194 """Enable GUI event loop integration, taking pylab into account."""
195 enable = False
195 enable = False
196 shell = self.shell
196 shell = self.shell
197 if self.pylab:
197 if self.pylab:
198 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
198 enable = lambda key: shell.enable_pylab(key, import_all=self.pylab_import_all)
199 key = self.pylab
199 key = self.pylab
200 elif self.matplotlib:
200 elif self.matplotlib:
201 enable = shell.enable_matplotlib
201 enable = shell.enable_matplotlib
202 key = self.matplotlib
202 key = self.matplotlib
203 elif self.gui:
203 elif self.gui:
204 enable = shell.enable_gui
204 enable = shell.enable_gui
205 key = self.gui
205 key = self.gui
206
206
207 if not enable:
207 if not enable:
208 return
208 return
209
209
210 try:
210 try:
211 r = enable(key)
211 r = enable(key)
212 except ImportError:
212 except ImportError:
213 self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?")
213 self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?")
214 self.shell.showtraceback()
214 self.shell.showtraceback()
215 return
215 return
216 except Exception:
216 except Exception:
217 self.log.warning("GUI event loop or pylab initialization failed")
217 self.log.warning("GUI event loop or pylab initialization failed")
218 self.shell.showtraceback()
218 self.shell.showtraceback()
219 return
219 return
220
220
221 if isinstance(r, tuple):
221 if isinstance(r, tuple):
222 gui, backend = r[:2]
222 gui, backend = r[:2]
223 self.log.info("Enabling GUI event loop integration, "
223 self.log.info("Enabling GUI event loop integration, "
224 "eventloop=%s, matplotlib=%s", gui, backend)
224 "eventloop=%s, matplotlib=%s", gui, backend)
225 if key == "auto":
225 if key == "auto":
226 print("Using matplotlib backend: %s" % backend)
226 print("Using matplotlib backend: %s" % backend)
227 else:
227 else:
228 gui = r
228 gui = r
229 self.log.info("Enabling GUI event loop integration, "
229 self.log.info("Enabling GUI event loop integration, "
230 "eventloop=%s", gui)
230 "eventloop=%s", gui)
231
231
232 def init_extensions(self):
232 def init_extensions(self):
233 """Load all IPython extensions in IPythonApp.extensions.
233 """Load all IPython extensions in IPythonApp.extensions.
234
234
235 This uses the :meth:`ExtensionManager.load_extensions` to load all
235 This uses the :meth:`ExtensionManager.load_extensions` to load all
236 the extensions listed in ``self.extensions``.
236 the extensions listed in ``self.extensions``.
237 """
237 """
238 try:
238 try:
239 self.log.debug("Loading IPython extensions...")
239 self.log.debug("Loading IPython extensions...")
240 extensions = self.default_extensions + self.extensions
240 extensions = self.default_extensions + self.extensions
241 if self.extra_extension:
241 if self.extra_extension:
242 extensions.append(self.extra_extension)
242 extensions.append(self.extra_extension)
243 for ext in extensions:
243 for ext in extensions:
244 try:
244 try:
245 self.log.info("Loading IPython extension: %s" % ext)
245 self.log.info("Loading IPython extension: %s" % ext)
246 self.shell.extension_manager.load_extension(ext)
246 self.shell.extension_manager.load_extension(ext)
247 except:
247 except:
248 if self.reraise_ipython_extension_failures:
248 if self.reraise_ipython_extension_failures:
249 raise
249 raise
250 msg = ("Error in loading extension: {ext}\n"
250 msg = ("Error in loading extension: {ext}\n"
251 "Check your config files in {location}".format(
251 "Check your config files in {location}".format(
252 ext=ext,
252 ext=ext,
253 location=self.profile_dir.location
253 location=self.profile_dir.location
254 ))
254 ))
255 self.log.warning(msg, exc_info=True)
255 self.log.warning(msg, exc_info=True)
256 except:
256 except:
257 if self.reraise_ipython_extension_failures:
257 if self.reraise_ipython_extension_failures:
258 raise
258 raise
259 self.log.warning("Unknown error in loading extensions:", exc_info=True)
259 self.log.warning("Unknown error in loading extensions:", exc_info=True)
260
260
261 def init_code(self):
261 def init_code(self):
262 """run the pre-flight code, specified via exec_lines"""
262 """run the pre-flight code, specified via exec_lines"""
263 self._run_startup_files()
263 self._run_startup_files()
264 self._run_exec_lines()
264 self._run_exec_lines()
265 self._run_exec_files()
265 self._run_exec_files()
266
266
267 # Hide variables defined here from %who etc.
267 # Hide variables defined here from %who etc.
268 if self.hide_initial_ns:
268 if self.hide_initial_ns:
269 self.shell.user_ns_hidden.update(self.shell.user_ns)
269 self.shell.user_ns_hidden.update(self.shell.user_ns)
270
270
271 # command-line execution (ipython -i script.py, ipython -m module)
271 # command-line execution (ipython -i script.py, ipython -m module)
272 # should *not* be excluded from %whos
272 # should *not* be excluded from %whos
273 self._run_cmd_line_code()
273 self._run_cmd_line_code()
274 self._run_module()
274 self._run_module()
275
275
276 # flush output, so itwon't be attached to the first cell
276 # flush output, so itwon't be attached to the first cell
277 sys.stdout.flush()
277 sys.stdout.flush()
278 sys.stderr.flush()
278 sys.stderr.flush()
279
279
280 def _run_exec_lines(self):
280 def _run_exec_lines(self):
281 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
281 """Run lines of code in IPythonApp.exec_lines in the user's namespace."""
282 if not self.exec_lines:
282 if not self.exec_lines:
283 return
283 return
284 try:
284 try:
285 self.log.debug("Running code from IPythonApp.exec_lines...")
285 self.log.debug("Running code from IPythonApp.exec_lines...")
286 for line in self.exec_lines:
286 for line in self.exec_lines:
287 try:
287 try:
288 self.log.info("Running code in user namespace: %s" %
288 self.log.info("Running code in user namespace: %s" %
289 line)
289 line)
290 self.shell.run_cell(line, store_history=False)
290 self.shell.run_cell(line, store_history=False)
291 except:
291 except:
292 self.log.warning("Error in executing line in user "
292 self.log.warning("Error in executing line in user "
293 "namespace: %s" % line)
293 "namespace: %s" % line)
294 self.shell.showtraceback()
294 self.shell.showtraceback()
295 except:
295 except:
296 self.log.warning("Unknown error in handling IPythonApp.exec_lines:")
296 self.log.warning("Unknown error in handling IPythonApp.exec_lines:")
297 self.shell.showtraceback()
297 self.shell.showtraceback()
298
298
299 def _exec_file(self, fname, shell_futures=False):
299 def _exec_file(self, fname, shell_futures=False):
300 try:
300 try:
301 full_filename = filefind(fname, [u'.', self.ipython_dir])
301 full_filename = filefind(fname, [u'.', self.ipython_dir])
302 except IOError:
302 except IOError:
303 self.log.warning("File not found: %r"%fname)
303 self.log.warning("File not found: %r"%fname)
304 return
304 return
305 # Make sure that the running script gets a proper sys.argv as if it
305 # Make sure that the running script gets a proper sys.argv as if it
306 # were run from a system shell.
306 # were run from a system shell.
307 save_argv = sys.argv
307 save_argv = sys.argv
308 sys.argv = [full_filename] + self.extra_args[1:]
308 sys.argv = [full_filename] + self.extra_args[1:]
309 # protect sys.argv from potential unicode strings on Python 2:
309 # protect sys.argv from potential unicode strings on Python 2:
310 if not py3compat.PY3:
310 if not py3compat.PY3:
311 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
311 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
312 try:
312 try:
313 if os.path.isfile(full_filename):
313 if os.path.isfile(full_filename):
314 self.log.info("Running file in user namespace: %s" %
314 self.log.info("Running file in user namespace: %s" %
315 full_filename)
315 full_filename)
316 # Ensure that __file__ is always defined to match Python
316 # Ensure that __file__ is always defined to match Python
317 # behavior.
317 # behavior.
318 with preserve_keys(self.shell.user_ns, '__file__'):
318 with preserve_keys(self.shell.user_ns, '__file__'):
319 self.shell.user_ns['__file__'] = fname
319 self.shell.user_ns['__file__'] = fname
320 if full_filename.endswith('.ipy'):
320 if full_filename.endswith('.ipy'):
321 self.shell.safe_execfile_ipy(full_filename,
321 self.shell.safe_execfile_ipy(full_filename,
322 shell_futures=shell_futures)
322 shell_futures=shell_futures)
323 else:
323 else:
324 # default to python, even without extension
324 # default to python, even without extension
325 self.shell.safe_execfile(full_filename,
325 self.shell.safe_execfile(full_filename,
326 self.shell.user_ns,
326 self.shell.user_ns,
327 shell_futures=shell_futures,
327 shell_futures=shell_futures,
328 raise_exceptions=True)
328 raise_exceptions=True)
329 finally:
329 finally:
330 sys.argv = save_argv
330 sys.argv = save_argv
331
331
332 def _run_startup_files(self):
332 def _run_startup_files(self):
333 """Run files from profile startup directory"""
333 """Run files from profile startup directory"""
334 startup_dir = self.profile_dir.startup_dir
334 startup_dir = self.profile_dir.startup_dir
335 startup_files = []
335 startup_files = []
336
336
337 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
337 if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \
338 not (self.file_to_run or self.code_to_run or self.module_to_run):
338 not (self.file_to_run or self.code_to_run or self.module_to_run):
339 python_startup = os.environ['PYTHONSTARTUP']
339 python_startup = os.environ['PYTHONSTARTUP']
340 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
340 self.log.debug("Running PYTHONSTARTUP file %s...", python_startup)
341 try:
341 try:
342 self._exec_file(python_startup)
342 self._exec_file(python_startup)
343 except:
343 except:
344 self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
344 self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup)
345 self.shell.showtraceback()
345 self.shell.showtraceback()
346
346
347 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
347 startup_files += glob.glob(os.path.join(startup_dir, '*.py'))
348 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
348 startup_files += glob.glob(os.path.join(startup_dir, '*.ipy'))
349 if not startup_files:
349 if not startup_files:
350 return
350 return
351
351
352 self.log.debug("Running startup files from %s...", startup_dir)
352 self.log.debug("Running startup files from %s...", startup_dir)
353 try:
353 try:
354 for fname in sorted(startup_files):
354 for fname in sorted(startup_files):
355 self._exec_file(fname)
355 self._exec_file(fname)
356 except:
356 except:
357 self.log.warning("Unknown error in handling startup files:")
357 self.log.warning("Unknown error in handling startup files:")
358 self.shell.showtraceback()
358 self.shell.showtraceback()
359
359
360 def _run_exec_files(self):
360 def _run_exec_files(self):
361 """Run files from IPythonApp.exec_files"""
361 """Run files from IPythonApp.exec_files"""
362 if not self.exec_files:
362 if not self.exec_files:
363 return
363 return
364
364
365 self.log.debug("Running files in IPythonApp.exec_files...")
365 self.log.debug("Running files in IPythonApp.exec_files...")
366 try:
366 try:
367 for fname in self.exec_files:
367 for fname in self.exec_files:
368 self._exec_file(fname)
368 self._exec_file(fname)
369 except:
369 except:
370 self.log.warning("Unknown error in handling IPythonApp.exec_files:")
370 self.log.warning("Unknown error in handling IPythonApp.exec_files:")
371 self.shell.showtraceback()
371 self.shell.showtraceback()
372
372
373 def _run_cmd_line_code(self):
373 def _run_cmd_line_code(self):
374 """Run code or file specified at the command-line"""
374 """Run code or file specified at the command-line"""
375 if self.code_to_run:
375 if self.code_to_run:
376 line = self.code_to_run
376 line = self.code_to_run
377 try:
377 try:
378 self.log.info("Running code given at command line (c=): %s" %
378 self.log.info("Running code given at command line (c=): %s" %
379 line)
379 line)
380 self.shell.run_cell(line, store_history=False)
380 self.shell.run_cell(line, store_history=False)
381 except:
381 except:
382 self.log.warning("Error in executing line in user namespace: %s" %
382 self.log.warning("Error in executing line in user namespace: %s" %
383 line)
383 line)
384 self.shell.showtraceback()
384 self.shell.showtraceback()
385 if not self.interact:
385 if not self.interact:
386 self.exit(1)
386 self.exit(1)
387
387
388 # Like Python itself, ignore the second if the first of these is present
388 # Like Python itself, ignore the second if the first of these is present
389 elif self.file_to_run:
389 elif self.file_to_run:
390 fname = self.file_to_run
390 fname = self.file_to_run
391 if os.path.isdir(fname):
391 if os.path.isdir(fname):
392 fname = os.path.join(fname, "__main__.py")
392 fname = os.path.join(fname, "__main__.py")
393 try:
393 try:
394 self._exec_file(fname, shell_futures=True)
394 self._exec_file(fname, shell_futures=True)
395 except:
395 except:
396 self.shell.showtraceback(tb_offset=4)
396 self.shell.showtraceback(tb_offset=4)
397 if not self.interact:
397 if not self.interact:
398 self.exit(1)
398 self.exit(1)
399
399
400 def _run_module(self):
400 def _run_module(self):
401 """Run module specified at the command-line."""
401 """Run module specified at the command-line."""
402 if self.module_to_run:
402 if self.module_to_run:
403 # Make sure that the module gets a proper sys.argv as if it were
403 # Make sure that the module gets a proper sys.argv as if it were
404 # run using `python -m`.
404 # run using `python -m`.
405 save_argv = sys.argv
405 save_argv = sys.argv
406 sys.argv = [sys.executable] + self.extra_args
406 sys.argv = [sys.executable] + self.extra_args
407 try:
407 try:
408 self.shell.safe_run_module(self.module_to_run,
408 self.shell.safe_run_module(self.module_to_run,
409 self.shell.user_ns)
409 self.shell.user_ns)
410 finally:
410 finally:
411 sys.argv = save_argv
411 sys.argv = save_argv
@@ -1,233 +1,226 b''
1 """Tests for debugging machinery.
1 """Tests for debugging machinery.
2 """
2 """
3 from __future__ import print_function
3 from __future__ import print_function
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2012, The IPython Development Team.
6 #
7 # Distributed under the terms of the Modified BSD License.
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
11
4
12 #-----------------------------------------------------------------------------
5 # Copyright (c) IPython Development Team.
13 # Imports
6 # Distributed under the terms of the Modified BSD License.
14 #-----------------------------------------------------------------------------
15
7
16 import sys
8 import sys
9 import warnings
17
10
18 # third-party
19 import nose.tools as nt
11 import nose.tools as nt
20
12
21 # Our own
22 from IPython.core import debugger
13 from IPython.core import debugger
23
14
24 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
25 # Helper classes, from CPython's Pdb test suite
16 # Helper classes, from CPython's Pdb test suite
26 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
27
18
28 class _FakeInput(object):
19 class _FakeInput(object):
29 """
20 """
30 A fake input stream for pdb's interactive debugger. Whenever a
21 A fake input stream for pdb's interactive debugger. Whenever a
31 line is read, print it (to simulate the user typing it), and then
22 line is read, print it (to simulate the user typing it), and then
32 return it. The set of lines to return is specified in the
23 return it. The set of lines to return is specified in the
33 constructor; they should not have trailing newlines.
24 constructor; they should not have trailing newlines.
34 """
25 """
35 def __init__(self, lines):
26 def __init__(self, lines):
36 self.lines = iter(lines)
27 self.lines = iter(lines)
37
28
38 def readline(self):
29 def readline(self):
39 line = next(self.lines)
30 line = next(self.lines)
40 print(line)
31 print(line)
41 return line+'\n'
32 return line+'\n'
42
33
43 class PdbTestInput(object):
34 class PdbTestInput(object):
44 """Context manager that makes testing Pdb in doctests easier."""
35 """Context manager that makes testing Pdb in doctests easier."""
45
36
46 def __init__(self, input):
37 def __init__(self, input):
47 self.input = input
38 self.input = input
48
39
49 def __enter__(self):
40 def __enter__(self):
50 self.real_stdin = sys.stdin
41 self.real_stdin = sys.stdin
51 sys.stdin = _FakeInput(self.input)
42 sys.stdin = _FakeInput(self.input)
52
43
53 def __exit__(self, *exc):
44 def __exit__(self, *exc):
54 sys.stdin = self.real_stdin
45 sys.stdin = self.real_stdin
55
46
56 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
57 # Tests
48 # Tests
58 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
59
50
60 def test_longer_repr():
51 def test_longer_repr():
61 try:
52 try:
62 from reprlib import repr as trepr # Py 3
53 from reprlib import repr as trepr # Py 3
63 except ImportError:
54 except ImportError:
64 from repr import repr as trepr # Py 2
55 from repr import repr as trepr # Py 2
65
56
66 a = '1234567890'* 7
57 a = '1234567890'* 7
67 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
58 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
68 a_trunc = "'123456789012...8901234567890'"
59 a_trunc = "'123456789012...8901234567890'"
69 nt.assert_equal(trepr(a), a_trunc)
60 nt.assert_equal(trepr(a), a_trunc)
70 # The creation of our tracer modifies the repr module's repr function
61 # The creation of our tracer modifies the repr module's repr function
71 # in-place, since that global is used directly by the stdlib's pdb module.
62 # in-place, since that global is used directly by the stdlib's pdb module.
72 debugger.Tracer()
63 with warnings.catch_warnings():
64 warnings.simplefilter('ignore', DeprecationWarning)
65 debugger.Tracer()
73 nt.assert_equal(trepr(a), ar)
66 nt.assert_equal(trepr(a), ar)
74
67
75 def test_ipdb_magics():
68 def test_ipdb_magics():
76 '''Test calling some IPython magics from ipdb.
69 '''Test calling some IPython magics from ipdb.
77
70
78 First, set up some test functions and classes which we can inspect.
71 First, set up some test functions and classes which we can inspect.
79
72
80 >>> class ExampleClass(object):
73 >>> class ExampleClass(object):
81 ... """Docstring for ExampleClass."""
74 ... """Docstring for ExampleClass."""
82 ... def __init__(self):
75 ... def __init__(self):
83 ... """Docstring for ExampleClass.__init__"""
76 ... """Docstring for ExampleClass.__init__"""
84 ... pass
77 ... pass
85 ... def __str__(self):
78 ... def __str__(self):
86 ... return "ExampleClass()"
79 ... return "ExampleClass()"
87
80
88 >>> def example_function(x, y, z="hello"):
81 >>> def example_function(x, y, z="hello"):
89 ... """Docstring for example_function."""
82 ... """Docstring for example_function."""
90 ... pass
83 ... pass
91
84
92 >>> old_trace = sys.gettrace()
85 >>> old_trace = sys.gettrace()
93
86
94 Create a function which triggers ipdb.
87 Create a function which triggers ipdb.
95
88
96 >>> def trigger_ipdb():
89 >>> def trigger_ipdb():
97 ... a = ExampleClass()
90 ... a = ExampleClass()
98 ... debugger.Pdb().set_trace()
91 ... debugger.Pdb().set_trace()
99
92
100 >>> with PdbTestInput([
93 >>> with PdbTestInput([
101 ... 'pdef example_function',
94 ... 'pdef example_function',
102 ... 'pdoc ExampleClass',
95 ... 'pdoc ExampleClass',
103 ... 'up',
96 ... 'up',
104 ... 'down',
97 ... 'down',
105 ... 'list',
98 ... 'list',
106 ... 'pinfo a',
99 ... 'pinfo a',
107 ... 'll',
100 ... 'll',
108 ... 'continue',
101 ... 'continue',
109 ... ]):
102 ... ]):
110 ... trigger_ipdb()
103 ... trigger_ipdb()
111 --Return--
104 --Return--
112 None
105 None
113 > <doctest ...>(3)trigger_ipdb()
106 > <doctest ...>(3)trigger_ipdb()
114 1 def trigger_ipdb():
107 1 def trigger_ipdb():
115 2 a = ExampleClass()
108 2 a = ExampleClass()
116 ----> 3 debugger.Pdb().set_trace()
109 ----> 3 debugger.Pdb().set_trace()
117 <BLANKLINE>
110 <BLANKLINE>
118 ipdb> pdef example_function
111 ipdb> pdef example_function
119 example_function(x, y, z='hello')
112 example_function(x, y, z='hello')
120 ipdb> pdoc ExampleClass
113 ipdb> pdoc ExampleClass
121 Class docstring:
114 Class docstring:
122 Docstring for ExampleClass.
115 Docstring for ExampleClass.
123 Init docstring:
116 Init docstring:
124 Docstring for ExampleClass.__init__
117 Docstring for ExampleClass.__init__
125 ipdb> up
118 ipdb> up
126 > <doctest ...>(11)<module>()
119 > <doctest ...>(11)<module>()
127 7 'pinfo a',
120 7 'pinfo a',
128 8 'll',
121 8 'll',
129 9 'continue',
122 9 'continue',
130 10 ]):
123 10 ]):
131 ---> 11 trigger_ipdb()
124 ---> 11 trigger_ipdb()
132 <BLANKLINE>
125 <BLANKLINE>
133 ipdb> down
126 ipdb> down
134 None
127 None
135 > <doctest ...>(3)trigger_ipdb()
128 > <doctest ...>(3)trigger_ipdb()
136 1 def trigger_ipdb():
129 1 def trigger_ipdb():
137 2 a = ExampleClass()
130 2 a = ExampleClass()
138 ----> 3 debugger.Pdb().set_trace()
131 ----> 3 debugger.Pdb().set_trace()
139 <BLANKLINE>
132 <BLANKLINE>
140 ipdb> list
133 ipdb> list
141 1 def trigger_ipdb():
134 1 def trigger_ipdb():
142 2 a = ExampleClass()
135 2 a = ExampleClass()
143 ----> 3 debugger.Pdb().set_trace()
136 ----> 3 debugger.Pdb().set_trace()
144 <BLANKLINE>
137 <BLANKLINE>
145 ipdb> pinfo a
138 ipdb> pinfo a
146 Type: ExampleClass
139 Type: ExampleClass
147 String form: ExampleClass()
140 String form: ExampleClass()
148 Namespace: Local...
141 Namespace: Local...
149 Docstring: Docstring for ExampleClass.
142 Docstring: Docstring for ExampleClass.
150 Init docstring: Docstring for ExampleClass.__init__
143 Init docstring: Docstring for ExampleClass.__init__
151 ipdb> ll
144 ipdb> ll
152 1 def trigger_ipdb():
145 1 def trigger_ipdb():
153 2 a = ExampleClass()
146 2 a = ExampleClass()
154 ----> 3 debugger.Pdb().set_trace()
147 ----> 3 debugger.Pdb().set_trace()
155 <BLANKLINE>
148 <BLANKLINE>
156 ipdb> continue
149 ipdb> continue
157
150
158 Restore previous trace function, e.g. for coverage.py
151 Restore previous trace function, e.g. for coverage.py
159
152
160 >>> sys.settrace(old_trace)
153 >>> sys.settrace(old_trace)
161 '''
154 '''
162
155
163 def test_ipdb_magics2():
156 def test_ipdb_magics2():
164 '''Test ipdb with a very short function.
157 '''Test ipdb with a very short function.
165
158
166 >>> old_trace = sys.gettrace()
159 >>> old_trace = sys.gettrace()
167
160
168 >>> def bar():
161 >>> def bar():
169 ... pass
162 ... pass
170
163
171 Run ipdb.
164 Run ipdb.
172
165
173 >>> with PdbTestInput([
166 >>> with PdbTestInput([
174 ... 'continue',
167 ... 'continue',
175 ... ]):
168 ... ]):
176 ... debugger.Pdb().runcall(bar)
169 ... debugger.Pdb().runcall(bar)
177 > <doctest ...>(2)bar()
170 > <doctest ...>(2)bar()
178 1 def bar():
171 1 def bar():
179 ----> 2 pass
172 ----> 2 pass
180 <BLANKLINE>
173 <BLANKLINE>
181 ipdb> continue
174 ipdb> continue
182
175
183 Restore previous trace function, e.g. for coverage.py
176 Restore previous trace function, e.g. for coverage.py
184
177
185 >>> sys.settrace(old_trace)
178 >>> sys.settrace(old_trace)
186 '''
179 '''
187
180
188 def can_quit():
181 def can_quit():
189 '''Test that quit work in ipydb
182 '''Test that quit work in ipydb
190
183
191 >>> old_trace = sys.gettrace()
184 >>> old_trace = sys.gettrace()
192
185
193 >>> def bar():
186 >>> def bar():
194 ... pass
187 ... pass
195
188
196 >>> with PdbTestInput([
189 >>> with PdbTestInput([
197 ... 'quit',
190 ... 'quit',
198 ... ]):
191 ... ]):
199 ... debugger.Pdb().runcall(bar)
192 ... debugger.Pdb().runcall(bar)
200 > <doctest ...>(2)bar()
193 > <doctest ...>(2)bar()
201 1 def bar():
194 1 def bar():
202 ----> 2 pass
195 ----> 2 pass
203 <BLANKLINE>
196 <BLANKLINE>
204 ipdb> quit
197 ipdb> quit
205
198
206 Restore previous trace function, e.g. for coverage.py
199 Restore previous trace function, e.g. for coverage.py
207
200
208 >>> sys.settrace(old_trace)
201 >>> sys.settrace(old_trace)
209 '''
202 '''
210
203
211
204
212 def can_exit():
205 def can_exit():
213 '''Test that quit work in ipydb
206 '''Test that quit work in ipydb
214
207
215 >>> old_trace = sys.gettrace()
208 >>> old_trace = sys.gettrace()
216
209
217 >>> def bar():
210 >>> def bar():
218 ... pass
211 ... pass
219
212
220 >>> with PdbTestInput([
213 >>> with PdbTestInput([
221 ... 'exit',
214 ... 'exit',
222 ... ]):
215 ... ]):
223 ... debugger.Pdb().runcall(bar)
216 ... debugger.Pdb().runcall(bar)
224 > <doctest ...>(2)bar()
217 > <doctest ...>(2)bar()
225 1 def bar():
218 1 def bar():
226 ----> 2 pass
219 ----> 2 pass
227 <BLANKLINE>
220 <BLANKLINE>
228 ipdb> exit
221 ipdb> exit
229
222
230 Restore previous trace function, e.g. for coverage.py
223 Restore previous trace function, e.g. for coverage.py
231
224
232 >>> sys.settrace(old_trace)
225 >>> sys.settrace(old_trace)
233 '''
226 '''
@@ -1,1494 +1,1494 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Verbose and colourful traceback formatting.
3 Verbose and colourful traceback formatting.
4
4
5 **ColorTB**
5 **ColorTB**
6
6
7 I've always found it a bit hard to visually parse tracebacks in Python. The
7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 ColorTB class is a solution to that problem. It colors the different parts of a
8 ColorTB class is a solution to that problem. It colors the different parts of a
9 traceback in a manner similar to what you would expect from a syntax-highlighting
9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 text editor.
10 text editor.
11
11
12 Installation instructions for ColorTB::
12 Installation instructions for ColorTB::
13
13
14 import sys,ultratb
14 import sys,ultratb
15 sys.excepthook = ultratb.ColorTB()
15 sys.excepthook = ultratb.ColorTB()
16
16
17 **VerboseTB**
17 **VerboseTB**
18
18
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 and intended it for CGI programmers, but why should they have all the fun? I
21 and intended it for CGI programmers, but why should they have all the fun? I
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 but kind of neat, and maybe useful for long-running programs that you believe
23 but kind of neat, and maybe useful for long-running programs that you believe
24 are bug-free. If a crash *does* occur in that type of program you want details.
24 are bug-free. If a crash *does* occur in that type of program you want details.
25 Give it a shot--you'll love it or you'll hate it.
25 Give it a shot--you'll love it or you'll hate it.
26
26
27 .. note::
27 .. note::
28
28
29 The Verbose mode prints the variables currently visible where the exception
29 The Verbose mode prints the variables currently visible where the exception
30 happened (shortening their strings if too long). This can potentially be
30 happened (shortening their strings if too long). This can potentially be
31 very slow, if you happen to have a huge data structure whose string
31 very slow, if you happen to have a huge data structure whose string
32 representation is complex to compute. Your computer may appear to freeze for
32 representation is complex to compute. Your computer may appear to freeze for
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 with Ctrl-C (maybe hitting it more than once).
34 with Ctrl-C (maybe hitting it more than once).
35
35
36 If you encounter this kind of situation often, you may want to use the
36 If you encounter this kind of situation often, you may want to use the
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 variables (but otherwise includes the information and context given by
38 variables (but otherwise includes the information and context given by
39 Verbose).
39 Verbose).
40
40
41 .. note::
41 .. note::
42
42
43 The verbose mode print all variables in the stack, which means it can
43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencryted
44 potentially leak sensitive information like access keys, or unencryted
45 password.
45 password.
46
46
47 Installation instructions for VerboseTB::
47 Installation instructions for VerboseTB::
48
48
49 import sys,ultratb
49 import sys,ultratb
50 sys.excepthook = ultratb.VerboseTB()
50 sys.excepthook = ultratb.VerboseTB()
51
51
52 Note: Much of the code in this module was lifted verbatim from the standard
52 Note: Much of the code in this module was lifted verbatim from the standard
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54
54
55 Color schemes
55 Color schemes
56 -------------
56 -------------
57
57
58 The colors are defined in the class TBTools through the use of the
58 The colors are defined in the class TBTools through the use of the
59 ColorSchemeTable class. Currently the following exist:
59 ColorSchemeTable class. Currently the following exist:
60
60
61 - NoColor: allows all of this module to be used in any terminal (the color
61 - NoColor: allows all of this module to be used in any terminal (the color
62 escapes are just dummy blank strings).
62 escapes are just dummy blank strings).
63
63
64 - Linux: is meant to look good in a terminal like the Linux console (black
64 - Linux: is meant to look good in a terminal like the Linux console (black
65 or very dark background).
65 or very dark background).
66
66
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 in light background terminals.
68 in light background terminals.
69
69
70 - Neutral: a neutral color scheme that should be readable on both light and
70 - Neutral: a neutral color scheme that should be readable on both light and
71 dark background
71 dark background
72
72
73 You can implement other color schemes easily, the syntax is fairly
73 You can implement other color schemes easily, the syntax is fairly
74 self-explanatory. Please send back new schemes you develop to the author for
74 self-explanatory. Please send back new schemes you develop to the author for
75 possible inclusion in future releases.
75 possible inclusion in future releases.
76
76
77 Inheritance diagram:
77 Inheritance diagram:
78
78
79 .. inheritance-diagram:: IPython.core.ultratb
79 .. inheritance-diagram:: IPython.core.ultratb
80 :parts: 3
80 :parts: 3
81 """
81 """
82
82
83 #*****************************************************************************
83 #*****************************************************************************
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 #
86 #
87 # Distributed under the terms of the BSD License. The full license is in
87 # Distributed under the terms of the BSD License. The full license is in
88 # the file COPYING, distributed as part of this software.
88 # the file COPYING, distributed as part of this software.
89 #*****************************************************************************
89 #*****************************************************************************
90
90
91 from __future__ import absolute_import
91 from __future__ import absolute_import
92 from __future__ import unicode_literals
92 from __future__ import unicode_literals
93 from __future__ import print_function
93 from __future__ import print_function
94
94
95 import dis
95 import dis
96 import inspect
96 import inspect
97 import keyword
97 import keyword
98 import linecache
98 import linecache
99 import os
99 import os
100 import pydoc
100 import pydoc
101 import re
101 import re
102 import sys
102 import sys
103 import time
103 import time
104 import tokenize
104 import tokenize
105 import traceback
105 import traceback
106 import types
106 import types
107
107
108 try: # Python 2
108 try: # Python 2
109 generate_tokens = tokenize.generate_tokens
109 generate_tokens = tokenize.generate_tokens
110 except AttributeError: # Python 3
110 except AttributeError: # Python 3
111 generate_tokens = tokenize.tokenize
111 generate_tokens = tokenize.tokenize
112
112
113 # For purposes of monkeypatching inspect to fix a bug in it.
113 # For purposes of monkeypatching inspect to fix a bug in it.
114 from inspect import getsourcefile, getfile, getmodule, \
114 from inspect import getsourcefile, getfile, getmodule, \
115 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
115 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
116
116
117 # IPython's own modules
117 # IPython's own modules
118 from IPython import get_ipython
118 from IPython import get_ipython
119 from IPython.core import debugger
119 from IPython.core import debugger
120 from IPython.core.display_trap import DisplayTrap
120 from IPython.core.display_trap import DisplayTrap
121 from IPython.core.excolors import exception_colors
121 from IPython.core.excolors import exception_colors
122 from IPython.utils import PyColorize
122 from IPython.utils import PyColorize
123 from IPython.utils import openpy
123 from IPython.utils import openpy
124 from IPython.utils import path as util_path
124 from IPython.utils import path as util_path
125 from IPython.utils import py3compat
125 from IPython.utils import py3compat
126 from IPython.utils import ulinecache
126 from IPython.utils import ulinecache
127 from IPython.utils.data import uniq_stable
127 from IPython.utils.data import uniq_stable
128 from IPython.utils.terminal import get_terminal_size
128 from IPython.utils.terminal import get_terminal_size
129 from logging import info, error
129 from logging import info, error
130
130
131 import IPython.utils.colorable as colorable
131 import IPython.utils.colorable as colorable
132
132
133 # Globals
133 # Globals
134 # amount of space to put line numbers before verbose tracebacks
134 # amount of space to put line numbers before verbose tracebacks
135 INDENT_SIZE = 8
135 INDENT_SIZE = 8
136
136
137 # Default color scheme. This is used, for example, by the traceback
137 # Default color scheme. This is used, for example, by the traceback
138 # formatter. When running in an actual IPython instance, the user's rc.colors
138 # formatter. When running in an actual IPython instance, the user's rc.colors
139 # value is used, but having a module global makes this functionality available
139 # value is used, but having a module global makes this functionality available
140 # to users of ultratb who are NOT running inside ipython.
140 # to users of ultratb who are NOT running inside ipython.
141 DEFAULT_SCHEME = 'NoColor'
141 DEFAULT_SCHEME = 'NoColor'
142
142
143 # ---------------------------------------------------------------------------
143 # ---------------------------------------------------------------------------
144 # Code begins
144 # Code begins
145
145
146 # Utility functions
146 # Utility functions
147 def inspect_error():
147 def inspect_error():
148 """Print a message about internal inspect errors.
148 """Print a message about internal inspect errors.
149
149
150 These are unfortunately quite common."""
150 These are unfortunately quite common."""
151
151
152 error('Internal Python error in the inspect module.\n'
152 error('Internal Python error in the inspect module.\n'
153 'Below is the traceback from this internal error.\n')
153 'Below is the traceback from this internal error.\n')
154
154
155
155
156 # This function is a monkeypatch we apply to the Python inspect module. We have
156 # This function is a monkeypatch we apply to the Python inspect module. We have
157 # now found when it's needed (see discussion on issue gh-1456), and we have a
157 # now found when it's needed (see discussion on issue gh-1456), and we have a
158 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
158 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
159 # the monkeypatch is not applied. TK, Aug 2012.
159 # the monkeypatch is not applied. TK, Aug 2012.
160 def findsource(object):
160 def findsource(object):
161 """Return the entire source file and starting line number for an object.
161 """Return the entire source file and starting line number for an object.
162
162
163 The argument may be a module, class, method, function, traceback, frame,
163 The argument may be a module, class, method, function, traceback, frame,
164 or code object. The source code is returned as a list of all the lines
164 or code object. The source code is returned as a list of all the lines
165 in the file and the line number indexes a line in that list. An IOError
165 in the file and the line number indexes a line in that list. An IOError
166 is raised if the source code cannot be retrieved.
166 is raised if the source code cannot be retrieved.
167
167
168 FIXED version with which we monkeypatch the stdlib to work around a bug."""
168 FIXED version with which we monkeypatch the stdlib to work around a bug."""
169
169
170 file = getsourcefile(object) or getfile(object)
170 file = getsourcefile(object) or getfile(object)
171 # If the object is a frame, then trying to get the globals dict from its
171 # If the object is a frame, then trying to get the globals dict from its
172 # module won't work. Instead, the frame object itself has the globals
172 # module won't work. Instead, the frame object itself has the globals
173 # dictionary.
173 # dictionary.
174 globals_dict = None
174 globals_dict = None
175 if inspect.isframe(object):
175 if inspect.isframe(object):
176 # XXX: can this ever be false?
176 # XXX: can this ever be false?
177 globals_dict = object.f_globals
177 globals_dict = object.f_globals
178 else:
178 else:
179 module = getmodule(object, file)
179 module = getmodule(object, file)
180 if module:
180 if module:
181 globals_dict = module.__dict__
181 globals_dict = module.__dict__
182 lines = linecache.getlines(file, globals_dict)
182 lines = linecache.getlines(file, globals_dict)
183 if not lines:
183 if not lines:
184 raise IOError('could not get source code')
184 raise IOError('could not get source code')
185
185
186 if ismodule(object):
186 if ismodule(object):
187 return lines, 0
187 return lines, 0
188
188
189 if isclass(object):
189 if isclass(object):
190 name = object.__name__
190 name = object.__name__
191 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
191 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
192 # make some effort to find the best matching class definition:
192 # make some effort to find the best matching class definition:
193 # use the one with the least indentation, which is the one
193 # use the one with the least indentation, which is the one
194 # that's most probably not inside a function definition.
194 # that's most probably not inside a function definition.
195 candidates = []
195 candidates = []
196 for i in range(len(lines)):
196 for i in range(len(lines)):
197 match = pat.match(lines[i])
197 match = pat.match(lines[i])
198 if match:
198 if match:
199 # if it's at toplevel, it's already the best one
199 # if it's at toplevel, it's already the best one
200 if lines[i][0] == 'c':
200 if lines[i][0] == 'c':
201 return lines, i
201 return lines, i
202 # else add whitespace to candidate list
202 # else add whitespace to candidate list
203 candidates.append((match.group(1), i))
203 candidates.append((match.group(1), i))
204 if candidates:
204 if candidates:
205 # this will sort by whitespace, and by line number,
205 # this will sort by whitespace, and by line number,
206 # less whitespace first
206 # less whitespace first
207 candidates.sort()
207 candidates.sort()
208 return lines, candidates[0][1]
208 return lines, candidates[0][1]
209 else:
209 else:
210 raise IOError('could not find class definition')
210 raise IOError('could not find class definition')
211
211
212 if ismethod(object):
212 if ismethod(object):
213 object = object.__func__
213 object = object.__func__
214 if isfunction(object):
214 if isfunction(object):
215 object = object.__code__
215 object = object.__code__
216 if istraceback(object):
216 if istraceback(object):
217 object = object.tb_frame
217 object = object.tb_frame
218 if isframe(object):
218 if isframe(object):
219 object = object.f_code
219 object = object.f_code
220 if iscode(object):
220 if iscode(object):
221 if not hasattr(object, 'co_firstlineno'):
221 if not hasattr(object, 'co_firstlineno'):
222 raise IOError('could not find function definition')
222 raise IOError('could not find function definition')
223 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
223 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
224 pmatch = pat.match
224 pmatch = pat.match
225 # fperez - fix: sometimes, co_firstlineno can give a number larger than
225 # fperez - fix: sometimes, co_firstlineno can give a number larger than
226 # the length of lines, which causes an error. Safeguard against that.
226 # the length of lines, which causes an error. Safeguard against that.
227 lnum = min(object.co_firstlineno, len(lines)) - 1
227 lnum = min(object.co_firstlineno, len(lines)) - 1
228 while lnum > 0:
228 while lnum > 0:
229 if pmatch(lines[lnum]):
229 if pmatch(lines[lnum]):
230 break
230 break
231 lnum -= 1
231 lnum -= 1
232
232
233 return lines, lnum
233 return lines, lnum
234 raise IOError('could not find code object')
234 raise IOError('could not find code object')
235
235
236
236
237 # This is a patched version of inspect.getargs that applies the (unmerged)
237 # This is a patched version of inspect.getargs that applies the (unmerged)
238 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
238 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
239 # https://github.com/ipython/ipython/issues/8205 and
239 # https://github.com/ipython/ipython/issues/8205 and
240 # https://github.com/ipython/ipython/issues/8293
240 # https://github.com/ipython/ipython/issues/8293
241 def getargs(co):
241 def getargs(co):
242 """Get information about the arguments accepted by a code object.
242 """Get information about the arguments accepted by a code object.
243
243
244 Three things are returned: (args, varargs, varkw), where 'args' is
244 Three things are returned: (args, varargs, varkw), where 'args' is
245 a list of argument names (possibly containing nested lists), and
245 a list of argument names (possibly containing nested lists), and
246 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
246 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
247 if not iscode(co):
247 if not iscode(co):
248 raise TypeError('{!r} is not a code object'.format(co))
248 raise TypeError('{!r} is not a code object'.format(co))
249
249
250 nargs = co.co_argcount
250 nargs = co.co_argcount
251 names = co.co_varnames
251 names = co.co_varnames
252 args = list(names[:nargs])
252 args = list(names[:nargs])
253 step = 0
253 step = 0
254
254
255 # The following acrobatics are for anonymous (tuple) arguments.
255 # The following acrobatics are for anonymous (tuple) arguments.
256 for i in range(nargs):
256 for i in range(nargs):
257 if args[i][:1] in ('', '.'):
257 if args[i][:1] in ('', '.'):
258 stack, remain, count = [], [], []
258 stack, remain, count = [], [], []
259 while step < len(co.co_code):
259 while step < len(co.co_code):
260 op = ord(co.co_code[step])
260 op = ord(co.co_code[step])
261 step = step + 1
261 step = step + 1
262 if op >= dis.HAVE_ARGUMENT:
262 if op >= dis.HAVE_ARGUMENT:
263 opname = dis.opname[op]
263 opname = dis.opname[op]
264 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
264 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
265 step = step + 2
265 step = step + 2
266 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
266 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
267 remain.append(value)
267 remain.append(value)
268 count.append(value)
268 count.append(value)
269 elif opname in ('STORE_FAST', 'STORE_DEREF'):
269 elif opname in ('STORE_FAST', 'STORE_DEREF'):
270 if op in dis.haslocal:
270 if op in dis.haslocal:
271 stack.append(co.co_varnames[value])
271 stack.append(co.co_varnames[value])
272 elif op in dis.hasfree:
272 elif op in dis.hasfree:
273 stack.append((co.co_cellvars + co.co_freevars)[value])
273 stack.append((co.co_cellvars + co.co_freevars)[value])
274 # Special case for sublists of length 1: def foo((bar))
274 # Special case for sublists of length 1: def foo((bar))
275 # doesn't generate the UNPACK_TUPLE bytecode, so if
275 # doesn't generate the UNPACK_TUPLE bytecode, so if
276 # `remain` is empty here, we have such a sublist.
276 # `remain` is empty here, we have such a sublist.
277 if not remain:
277 if not remain:
278 stack[0] = [stack[0]]
278 stack[0] = [stack[0]]
279 break
279 break
280 else:
280 else:
281 remain[-1] = remain[-1] - 1
281 remain[-1] = remain[-1] - 1
282 while remain[-1] == 0:
282 while remain[-1] == 0:
283 remain.pop()
283 remain.pop()
284 size = count.pop()
284 size = count.pop()
285 stack[-size:] = [stack[-size:]]
285 stack[-size:] = [stack[-size:]]
286 if not remain:
286 if not remain:
287 break
287 break
288 remain[-1] = remain[-1] - 1
288 remain[-1] = remain[-1] - 1
289 if not remain:
289 if not remain:
290 break
290 break
291 args[i] = stack[0]
291 args[i] = stack[0]
292
292
293 varargs = None
293 varargs = None
294 if co.co_flags & inspect.CO_VARARGS:
294 if co.co_flags & inspect.CO_VARARGS:
295 varargs = co.co_varnames[nargs]
295 varargs = co.co_varnames[nargs]
296 nargs = nargs + 1
296 nargs = nargs + 1
297 varkw = None
297 varkw = None
298 if co.co_flags & inspect.CO_VARKEYWORDS:
298 if co.co_flags & inspect.CO_VARKEYWORDS:
299 varkw = co.co_varnames[nargs]
299 varkw = co.co_varnames[nargs]
300 return inspect.Arguments(args, varargs, varkw)
300 return inspect.Arguments(args, varargs, varkw)
301
301
302
302
303 # Monkeypatch inspect to apply our bugfix.
303 # Monkeypatch inspect to apply our bugfix.
304 def with_patch_inspect(f):
304 def with_patch_inspect(f):
305 """decorator for monkeypatching inspect.findsource"""
305 """decorator for monkeypatching inspect.findsource"""
306
306
307 def wrapped(*args, **kwargs):
307 def wrapped(*args, **kwargs):
308 save_findsource = inspect.findsource
308 save_findsource = inspect.findsource
309 save_getargs = inspect.getargs
309 save_getargs = inspect.getargs
310 inspect.findsource = findsource
310 inspect.findsource = findsource
311 inspect.getargs = getargs
311 inspect.getargs = getargs
312 try:
312 try:
313 return f(*args, **kwargs)
313 return f(*args, **kwargs)
314 finally:
314 finally:
315 inspect.findsource = save_findsource
315 inspect.findsource = save_findsource
316 inspect.getargs = save_getargs
316 inspect.getargs = save_getargs
317
317
318 return wrapped
318 return wrapped
319
319
320
320
321 if py3compat.PY3:
321 if py3compat.PY3:
322 fixed_getargvalues = inspect.getargvalues
322 fixed_getargvalues = inspect.getargvalues
323 else:
323 else:
324 # Fixes for https://github.com/ipython/ipython/issues/8293
324 # Fixes for https://github.com/ipython/ipython/issues/8293
325 # and https://github.com/ipython/ipython/issues/8205.
325 # and https://github.com/ipython/ipython/issues/8205.
326 # The relevant bug is caused by failure to correctly handle anonymous tuple
326 # The relevant bug is caused by failure to correctly handle anonymous tuple
327 # unpacking, which only exists in Python 2.
327 # unpacking, which only exists in Python 2.
328 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
328 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
329
329
330
330
331 def fix_frame_records_filenames(records):
331 def fix_frame_records_filenames(records):
332 """Try to fix the filenames in each record from inspect.getinnerframes().
332 """Try to fix the filenames in each record from inspect.getinnerframes().
333
333
334 Particularly, modules loaded from within zip files have useless filenames
334 Particularly, modules loaded from within zip files have useless filenames
335 attached to their code object, and inspect.getinnerframes() just uses it.
335 attached to their code object, and inspect.getinnerframes() just uses it.
336 """
336 """
337 fixed_records = []
337 fixed_records = []
338 for frame, filename, line_no, func_name, lines, index in records:
338 for frame, filename, line_no, func_name, lines, index in records:
339 # Look inside the frame's globals dictionary for __file__,
339 # Look inside the frame's globals dictionary for __file__,
340 # which should be better. However, keep Cython filenames since
340 # which should be better. However, keep Cython filenames since
341 # we prefer the source filenames over the compiled .so file.
341 # we prefer the source filenames over the compiled .so file.
342 filename = py3compat.cast_unicode_py2(filename, "utf-8")
342 filename = py3compat.cast_unicode_py2(filename, "utf-8")
343 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
343 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
344 better_fn = frame.f_globals.get('__file__', None)
344 better_fn = frame.f_globals.get('__file__', None)
345 if isinstance(better_fn, str):
345 if isinstance(better_fn, str):
346 # Check the type just in case someone did something weird with
346 # Check the type just in case someone did something weird with
347 # __file__. It might also be None if the error occurred during
347 # __file__. It might also be None if the error occurred during
348 # import.
348 # import.
349 filename = better_fn
349 filename = better_fn
350 fixed_records.append((frame, filename, line_no, func_name, lines, index))
350 fixed_records.append((frame, filename, line_no, func_name, lines, index))
351 return fixed_records
351 return fixed_records
352
352
353
353
354 @with_patch_inspect
354 @with_patch_inspect
355 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
355 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
356 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
356 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
357
357
358 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
358 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
359 # If the error is at the console, don't build any context, since it would
359 # If the error is at the console, don't build any context, since it would
360 # otherwise produce 5 blank lines printed out (there is no file at the
360 # otherwise produce 5 blank lines printed out (there is no file at the
361 # console)
361 # console)
362 rec_check = records[tb_offset:]
362 rec_check = records[tb_offset:]
363 try:
363 try:
364 rname = rec_check[0][1]
364 rname = rec_check[0][1]
365 if rname == '<ipython console>' or rname.endswith('<string>'):
365 if rname == '<ipython console>' or rname.endswith('<string>'):
366 return rec_check
366 return rec_check
367 except IndexError:
367 except IndexError:
368 pass
368 pass
369
369
370 aux = traceback.extract_tb(etb)
370 aux = traceback.extract_tb(etb)
371 assert len(records) == len(aux)
371 assert len(records) == len(aux)
372 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
372 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
373 maybeStart = lnum - 1 - context // 2
373 maybeStart = lnum - 1 - context // 2
374 start = max(maybeStart, 0)
374 start = max(maybeStart, 0)
375 end = start + context
375 end = start + context
376 lines = ulinecache.getlines(file)[start:end]
376 lines = ulinecache.getlines(file)[start:end]
377 buf = list(records[i])
377 buf = list(records[i])
378 buf[LNUM_POS] = lnum
378 buf[LNUM_POS] = lnum
379 buf[INDEX_POS] = lnum - 1 - start
379 buf[INDEX_POS] = lnum - 1 - start
380 buf[LINES_POS] = lines
380 buf[LINES_POS] = lines
381 records[i] = tuple(buf)
381 records[i] = tuple(buf)
382 return records[tb_offset:]
382 return records[tb_offset:]
383
383
384 # Helper function -- largely belongs to VerboseTB, but we need the same
384 # Helper function -- largely belongs to VerboseTB, but we need the same
385 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
385 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
386 # can be recognized properly by ipython.el's py-traceback-line-re
386 # can be recognized properly by ipython.el's py-traceback-line-re
387 # (SyntaxErrors have to be treated specially because they have no traceback)
387 # (SyntaxErrors have to be treated specially because they have no traceback)
388
388
389 _parser = PyColorize.Parser()
389 _parser = PyColorize.Parser()
390
390
391
391
392 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
392 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
393 numbers_width = INDENT_SIZE - 1
393 numbers_width = INDENT_SIZE - 1
394 res = []
394 res = []
395 i = lnum - index
395 i = lnum - index
396
396
397 # This lets us get fully syntax-highlighted tracebacks.
397 # This lets us get fully syntax-highlighted tracebacks.
398 if scheme is None:
398 if scheme is None:
399 ipinst = get_ipython()
399 ipinst = get_ipython()
400 if ipinst is not None:
400 if ipinst is not None:
401 scheme = ipinst.colors
401 scheme = ipinst.colors
402 else:
402 else:
403 scheme = DEFAULT_SCHEME
403 scheme = DEFAULT_SCHEME
404
404
405 _line_format = _parser.format2
405 _line_format = _parser.format2
406
406
407 for line in lines:
407 for line in lines:
408 line = py3compat.cast_unicode(line)
408 line = py3compat.cast_unicode(line)
409
409
410 new_line, err = _line_format(line, 'str', scheme)
410 new_line, err = _line_format(line, 'str', scheme)
411 if not err: line = new_line
411 if not err: line = new_line
412
412
413 if i == lnum:
413 if i == lnum:
414 # This is the line with the error
414 # This is the line with the error
415 pad = numbers_width - len(str(i))
415 pad = numbers_width - len(str(i))
416 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
416 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
417 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
417 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
418 Colors.line, line, Colors.Normal)
418 Colors.line, line, Colors.Normal)
419 else:
419 else:
420 num = '%*s' % (numbers_width, i)
420 num = '%*s' % (numbers_width, i)
421 line = '%s%s%s %s' % (Colors.lineno, num,
421 line = '%s%s%s %s' % (Colors.lineno, num,
422 Colors.Normal, line)
422 Colors.Normal, line)
423
423
424 res.append(line)
424 res.append(line)
425 if lvals and i == lnum:
425 if lvals and i == lnum:
426 res.append(lvals + '\n')
426 res.append(lvals + '\n')
427 i = i + 1
427 i = i + 1
428 return res
428 return res
429
429
430 def is_recursion_error(etype, value, records):
430 def is_recursion_error(etype, value, records):
431 try:
431 try:
432 # RecursionError is new in Python 3.5
432 # RecursionError is new in Python 3.5
433 recursion_error_type = RecursionError
433 recursion_error_type = RecursionError
434 except NameError:
434 except NameError:
435 recursion_error_type = RuntimeError
435 recursion_error_type = RuntimeError
436
436
437 # The default recursion limit is 1000, but some of that will be taken up
437 # The default recursion limit is 1000, but some of that will be taken up
438 # by stack frames in IPython itself. >500 frames probably indicates
438 # by stack frames in IPython itself. >500 frames probably indicates
439 # a recursion error.
439 # a recursion error.
440 return (etype is recursion_error_type) \
440 return (etype is recursion_error_type) \
441 and "recursion" in str(value).lower() \
441 and "recursion" in str(value).lower() \
442 and len(records) > 500
442 and len(records) > 500
443
443
444 def find_recursion(etype, value, records):
444 def find_recursion(etype, value, records):
445 """Identify the repeating stack frames from a RecursionError traceback
445 """Identify the repeating stack frames from a RecursionError traceback
446
446
447 'records' is a list as returned by VerboseTB.get_records()
447 'records' is a list as returned by VerboseTB.get_records()
448
448
449 Returns (last_unique, repeat_length)
449 Returns (last_unique, repeat_length)
450 """
450 """
451 # This involves a bit of guesswork - we want to show enough of the traceback
451 # This involves a bit of guesswork - we want to show enough of the traceback
452 # to indicate where the recursion is occurring. We guess that the innermost
452 # to indicate where the recursion is occurring. We guess that the innermost
453 # quarter of the traceback (250 frames by default) is repeats, and find the
453 # quarter of the traceback (250 frames by default) is repeats, and find the
454 # first frame (from in to out) that looks different.
454 # first frame (from in to out) that looks different.
455 if not is_recursion_error(etype, value, records):
455 if not is_recursion_error(etype, value, records):
456 return len(records), 0
456 return len(records), 0
457
457
458 # Select filename, lineno, func_name to track frames with
458 # Select filename, lineno, func_name to track frames with
459 records = [r[1:4] for r in records]
459 records = [r[1:4] for r in records]
460 inner_frames = records[-(len(records)//4):]
460 inner_frames = records[-(len(records)//4):]
461 frames_repeated = set(inner_frames)
461 frames_repeated = set(inner_frames)
462
462
463 last_seen_at = {}
463 last_seen_at = {}
464 longest_repeat = 0
464 longest_repeat = 0
465 i = len(records)
465 i = len(records)
466 for frame in reversed(records):
466 for frame in reversed(records):
467 i -= 1
467 i -= 1
468 if frame not in frames_repeated:
468 if frame not in frames_repeated:
469 last_unique = i
469 last_unique = i
470 break
470 break
471
471
472 if frame in last_seen_at:
472 if frame in last_seen_at:
473 distance = last_seen_at[frame] - i
473 distance = last_seen_at[frame] - i
474 longest_repeat = max(longest_repeat, distance)
474 longest_repeat = max(longest_repeat, distance)
475
475
476 last_seen_at[frame] = i
476 last_seen_at[frame] = i
477 else:
477 else:
478 last_unique = 0 # The whole traceback was recursion
478 last_unique = 0 # The whole traceback was recursion
479
479
480 return last_unique, longest_repeat
480 return last_unique, longest_repeat
481
481
482 #---------------------------------------------------------------------------
482 #---------------------------------------------------------------------------
483 # Module classes
483 # Module classes
484 class TBTools(colorable.Colorable):
484 class TBTools(colorable.Colorable):
485 """Basic tools used by all traceback printer classes."""
485 """Basic tools used by all traceback printer classes."""
486
486
487 # Number of frames to skip when reporting tracebacks
487 # Number of frames to skip when reporting tracebacks
488 tb_offset = 0
488 tb_offset = 0
489
489
490 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
490 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
491 # Whether to call the interactive pdb debugger after printing
491 # Whether to call the interactive pdb debugger after printing
492 # tracebacks or not
492 # tracebacks or not
493 super(TBTools, self).__init__(parent=parent, config=config)
493 super(TBTools, self).__init__(parent=parent, config=config)
494 self.call_pdb = call_pdb
494 self.call_pdb = call_pdb
495
495
496 # Output stream to write to. Note that we store the original value in
496 # Output stream to write to. Note that we store the original value in
497 # a private attribute and then make the public ostream a property, so
497 # a private attribute and then make the public ostream a property, so
498 # that we can delay accessing io.stdout until runtime. The way
498 # that we can delay accessing sys.stdout until runtime. The way
499 # things are written now, the io.stdout object is dynamically managed
499 # things are written now, the sys.stdout object is dynamically managed
500 # so a reference to it should NEVER be stored statically. This
500 # so a reference to it should NEVER be stored statically. This
501 # property approach confines this detail to a single location, and all
501 # property approach confines this detail to a single location, and all
502 # subclasses can simply access self.ostream for writing.
502 # subclasses can simply access self.ostream for writing.
503 self._ostream = ostream
503 self._ostream = ostream
504
504
505 # Create color table
505 # Create color table
506 self.color_scheme_table = exception_colors()
506 self.color_scheme_table = exception_colors()
507
507
508 self.set_colors(color_scheme)
508 self.set_colors(color_scheme)
509 self.old_scheme = color_scheme # save initial value for toggles
509 self.old_scheme = color_scheme # save initial value for toggles
510
510
511 if call_pdb:
511 if call_pdb:
512 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
512 self.pdb = debugger.Pdb()
513 else:
513 else:
514 self.pdb = None
514 self.pdb = None
515
515
516 def _get_ostream(self):
516 def _get_ostream(self):
517 """Output stream that exceptions are written to.
517 """Output stream that exceptions are written to.
518
518
519 Valid values are:
519 Valid values are:
520
520
521 - None: the default, which means that IPython will dynamically resolve
521 - None: the default, which means that IPython will dynamically resolve
522 to io.stdout. This ensures compatibility with most tools, including
522 to sys.stdout. This ensures compatibility with most tools, including
523 Windows (where plain stdout doesn't recognize ANSI escapes).
523 Windows (where plain stdout doesn't recognize ANSI escapes).
524
524
525 - Any object with 'write' and 'flush' attributes.
525 - Any object with 'write' and 'flush' attributes.
526 """
526 """
527 return sys.stdout if self._ostream is None else self._ostream
527 return sys.stdout if self._ostream is None else self._ostream
528
528
529 def _set_ostream(self, val):
529 def _set_ostream(self, val):
530 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
530 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
531 self._ostream = val
531 self._ostream = val
532
532
533 ostream = property(_get_ostream, _set_ostream)
533 ostream = property(_get_ostream, _set_ostream)
534
534
535 def set_colors(self, *args, **kw):
535 def set_colors(self, *args, **kw):
536 """Shorthand access to the color table scheme selector method."""
536 """Shorthand access to the color table scheme selector method."""
537
537
538 # Set own color table
538 # Set own color table
539 self.color_scheme_table.set_active_scheme(*args, **kw)
539 self.color_scheme_table.set_active_scheme(*args, **kw)
540 # for convenience, set Colors to the active scheme
540 # for convenience, set Colors to the active scheme
541 self.Colors = self.color_scheme_table.active_colors
541 self.Colors = self.color_scheme_table.active_colors
542 # Also set colors of debugger
542 # Also set colors of debugger
543 if hasattr(self, 'pdb') and self.pdb is not None:
543 if hasattr(self, 'pdb') and self.pdb is not None:
544 self.pdb.set_colors(*args, **kw)
544 self.pdb.set_colors(*args, **kw)
545
545
546 def color_toggle(self):
546 def color_toggle(self):
547 """Toggle between the currently active color scheme and NoColor."""
547 """Toggle between the currently active color scheme and NoColor."""
548
548
549 if self.color_scheme_table.active_scheme_name == 'NoColor':
549 if self.color_scheme_table.active_scheme_name == 'NoColor':
550 self.color_scheme_table.set_active_scheme(self.old_scheme)
550 self.color_scheme_table.set_active_scheme(self.old_scheme)
551 self.Colors = self.color_scheme_table.active_colors
551 self.Colors = self.color_scheme_table.active_colors
552 else:
552 else:
553 self.old_scheme = self.color_scheme_table.active_scheme_name
553 self.old_scheme = self.color_scheme_table.active_scheme_name
554 self.color_scheme_table.set_active_scheme('NoColor')
554 self.color_scheme_table.set_active_scheme('NoColor')
555 self.Colors = self.color_scheme_table.active_colors
555 self.Colors = self.color_scheme_table.active_colors
556
556
557 def stb2text(self, stb):
557 def stb2text(self, stb):
558 """Convert a structured traceback (a list) to a string."""
558 """Convert a structured traceback (a list) to a string."""
559 return '\n'.join(stb)
559 return '\n'.join(stb)
560
560
561 def text(self, etype, value, tb, tb_offset=None, context=5):
561 def text(self, etype, value, tb, tb_offset=None, context=5):
562 """Return formatted traceback.
562 """Return formatted traceback.
563
563
564 Subclasses may override this if they add extra arguments.
564 Subclasses may override this if they add extra arguments.
565 """
565 """
566 tb_list = self.structured_traceback(etype, value, tb,
566 tb_list = self.structured_traceback(etype, value, tb,
567 tb_offset, context)
567 tb_offset, context)
568 return self.stb2text(tb_list)
568 return self.stb2text(tb_list)
569
569
570 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
570 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
571 context=5, mode=None):
571 context=5, mode=None):
572 """Return a list of traceback frames.
572 """Return a list of traceback frames.
573
573
574 Must be implemented by each class.
574 Must be implemented by each class.
575 """
575 """
576 raise NotImplementedError()
576 raise NotImplementedError()
577
577
578
578
579 #---------------------------------------------------------------------------
579 #---------------------------------------------------------------------------
580 class ListTB(TBTools):
580 class ListTB(TBTools):
581 """Print traceback information from a traceback list, with optional color.
581 """Print traceback information from a traceback list, with optional color.
582
582
583 Calling requires 3 arguments: (etype, evalue, elist)
583 Calling requires 3 arguments: (etype, evalue, elist)
584 as would be obtained by::
584 as would be obtained by::
585
585
586 etype, evalue, tb = sys.exc_info()
586 etype, evalue, tb = sys.exc_info()
587 if tb:
587 if tb:
588 elist = traceback.extract_tb(tb)
588 elist = traceback.extract_tb(tb)
589 else:
589 else:
590 elist = None
590 elist = None
591
591
592 It can thus be used by programs which need to process the traceback before
592 It can thus be used by programs which need to process the traceback before
593 printing (such as console replacements based on the code module from the
593 printing (such as console replacements based on the code module from the
594 standard library).
594 standard library).
595
595
596 Because they are meant to be called without a full traceback (only a
596 Because they are meant to be called without a full traceback (only a
597 list), instances of this class can't call the interactive pdb debugger."""
597 list), instances of this class can't call the interactive pdb debugger."""
598
598
599 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None):
599 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None):
600 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
600 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
601 ostream=ostream, parent=parent)
601 ostream=ostream, parent=parent)
602
602
603 def __call__(self, etype, value, elist):
603 def __call__(self, etype, value, elist):
604 self.ostream.flush()
604 self.ostream.flush()
605 self.ostream.write(self.text(etype, value, elist))
605 self.ostream.write(self.text(etype, value, elist))
606 self.ostream.write('\n')
606 self.ostream.write('\n')
607
607
608 def structured_traceback(self, etype, value, elist, tb_offset=None,
608 def structured_traceback(self, etype, value, elist, tb_offset=None,
609 context=5):
609 context=5):
610 """Return a color formatted string with the traceback info.
610 """Return a color formatted string with the traceback info.
611
611
612 Parameters
612 Parameters
613 ----------
613 ----------
614 etype : exception type
614 etype : exception type
615 Type of the exception raised.
615 Type of the exception raised.
616
616
617 value : object
617 value : object
618 Data stored in the exception
618 Data stored in the exception
619
619
620 elist : list
620 elist : list
621 List of frames, see class docstring for details.
621 List of frames, see class docstring for details.
622
622
623 tb_offset : int, optional
623 tb_offset : int, optional
624 Number of frames in the traceback to skip. If not given, the
624 Number of frames in the traceback to skip. If not given, the
625 instance value is used (set in constructor).
625 instance value is used (set in constructor).
626
626
627 context : int, optional
627 context : int, optional
628 Number of lines of context information to print.
628 Number of lines of context information to print.
629
629
630 Returns
630 Returns
631 -------
631 -------
632 String with formatted exception.
632 String with formatted exception.
633 """
633 """
634 tb_offset = self.tb_offset if tb_offset is None else tb_offset
634 tb_offset = self.tb_offset if tb_offset is None else tb_offset
635 Colors = self.Colors
635 Colors = self.Colors
636 out_list = []
636 out_list = []
637 if elist:
637 if elist:
638
638
639 if tb_offset and len(elist) > tb_offset:
639 if tb_offset and len(elist) > tb_offset:
640 elist = elist[tb_offset:]
640 elist = elist[tb_offset:]
641
641
642 out_list.append('Traceback %s(most recent call last)%s:' %
642 out_list.append('Traceback %s(most recent call last)%s:' %
643 (Colors.normalEm, Colors.Normal) + '\n')
643 (Colors.normalEm, Colors.Normal) + '\n')
644 out_list.extend(self._format_list(elist))
644 out_list.extend(self._format_list(elist))
645 # The exception info should be a single entry in the list.
645 # The exception info should be a single entry in the list.
646 lines = ''.join(self._format_exception_only(etype, value))
646 lines = ''.join(self._format_exception_only(etype, value))
647 out_list.append(lines)
647 out_list.append(lines)
648
648
649 # Note: this code originally read:
649 # Note: this code originally read:
650
650
651 ## for line in lines[:-1]:
651 ## for line in lines[:-1]:
652 ## out_list.append(" "+line)
652 ## out_list.append(" "+line)
653 ## out_list.append(lines[-1])
653 ## out_list.append(lines[-1])
654
654
655 # This means it was indenting everything but the last line by a little
655 # This means it was indenting everything but the last line by a little
656 # bit. I've disabled this for now, but if we see ugliness somewhere we
656 # bit. I've disabled this for now, but if we see ugliness somewhere we
657 # can restore it.
657 # can restore it.
658
658
659 return out_list
659 return out_list
660
660
661 def _format_list(self, extracted_list):
661 def _format_list(self, extracted_list):
662 """Format a list of traceback entry tuples for printing.
662 """Format a list of traceback entry tuples for printing.
663
663
664 Given a list of tuples as returned by extract_tb() or
664 Given a list of tuples as returned by extract_tb() or
665 extract_stack(), return a list of strings ready for printing.
665 extract_stack(), return a list of strings ready for printing.
666 Each string in the resulting list corresponds to the item with the
666 Each string in the resulting list corresponds to the item with the
667 same index in the argument list. Each string ends in a newline;
667 same index in the argument list. Each string ends in a newline;
668 the strings may contain internal newlines as well, for those items
668 the strings may contain internal newlines as well, for those items
669 whose source text line is not None.
669 whose source text line is not None.
670
670
671 Lifted almost verbatim from traceback.py
671 Lifted almost verbatim from traceback.py
672 """
672 """
673
673
674 Colors = self.Colors
674 Colors = self.Colors
675 list = []
675 list = []
676 for filename, lineno, name, line in extracted_list[:-1]:
676 for filename, lineno, name, line in extracted_list[:-1]:
677 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
677 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
678 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
678 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
679 Colors.lineno, lineno, Colors.Normal,
679 Colors.lineno, lineno, Colors.Normal,
680 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
680 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
681 if line:
681 if line:
682 item += ' %s\n' % line.strip()
682 item += ' %s\n' % line.strip()
683 list.append(item)
683 list.append(item)
684 # Emphasize the last entry
684 # Emphasize the last entry
685 filename, lineno, name, line = extracted_list[-1]
685 filename, lineno, name, line = extracted_list[-1]
686 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
686 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
687 (Colors.normalEm,
687 (Colors.normalEm,
688 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
688 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
689 Colors.linenoEm, lineno, Colors.normalEm,
689 Colors.linenoEm, lineno, Colors.normalEm,
690 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
690 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
691 Colors.Normal)
691 Colors.Normal)
692 if line:
692 if line:
693 item += '%s %s%s\n' % (Colors.line, line.strip(),
693 item += '%s %s%s\n' % (Colors.line, line.strip(),
694 Colors.Normal)
694 Colors.Normal)
695 list.append(item)
695 list.append(item)
696 return list
696 return list
697
697
698 def _format_exception_only(self, etype, value):
698 def _format_exception_only(self, etype, value):
699 """Format the exception part of a traceback.
699 """Format the exception part of a traceback.
700
700
701 The arguments are the exception type and value such as given by
701 The arguments are the exception type and value such as given by
702 sys.exc_info()[:2]. The return value is a list of strings, each ending
702 sys.exc_info()[:2]. The return value is a list of strings, each ending
703 in a newline. Normally, the list contains a single string; however,
703 in a newline. Normally, the list contains a single string; however,
704 for SyntaxError exceptions, it contains several lines that (when
704 for SyntaxError exceptions, it contains several lines that (when
705 printed) display detailed information about where the syntax error
705 printed) display detailed information about where the syntax error
706 occurred. The message indicating which exception occurred is the
706 occurred. The message indicating which exception occurred is the
707 always last string in the list.
707 always last string in the list.
708
708
709 Also lifted nearly verbatim from traceback.py
709 Also lifted nearly verbatim from traceback.py
710 """
710 """
711 have_filedata = False
711 have_filedata = False
712 Colors = self.Colors
712 Colors = self.Colors
713 list = []
713 list = []
714 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
714 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
715 if value is None:
715 if value is None:
716 # Not sure if this can still happen in Python 2.6 and above
716 # Not sure if this can still happen in Python 2.6 and above
717 list.append(stype + '\n')
717 list.append(stype + '\n')
718 else:
718 else:
719 if issubclass(etype, SyntaxError):
719 if issubclass(etype, SyntaxError):
720 have_filedata = True
720 have_filedata = True
721 if not value.filename: value.filename = "<string>"
721 if not value.filename: value.filename = "<string>"
722 if value.lineno:
722 if value.lineno:
723 lineno = value.lineno
723 lineno = value.lineno
724 textline = ulinecache.getline(value.filename, value.lineno)
724 textline = ulinecache.getline(value.filename, value.lineno)
725 else:
725 else:
726 lineno = 'unknown'
726 lineno = 'unknown'
727 textline = ''
727 textline = ''
728 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
728 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
729 (Colors.normalEm,
729 (Colors.normalEm,
730 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
730 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
731 Colors.linenoEm, lineno, Colors.Normal ))
731 Colors.linenoEm, lineno, Colors.Normal ))
732 if textline == '':
732 if textline == '':
733 textline = py3compat.cast_unicode(value.text, "utf-8")
733 textline = py3compat.cast_unicode(value.text, "utf-8")
734
734
735 if textline is not None:
735 if textline is not None:
736 i = 0
736 i = 0
737 while i < len(textline) and textline[i].isspace():
737 while i < len(textline) and textline[i].isspace():
738 i += 1
738 i += 1
739 list.append('%s %s%s\n' % (Colors.line,
739 list.append('%s %s%s\n' % (Colors.line,
740 textline.strip(),
740 textline.strip(),
741 Colors.Normal))
741 Colors.Normal))
742 if value.offset is not None:
742 if value.offset is not None:
743 s = ' '
743 s = ' '
744 for c in textline[i:value.offset - 1]:
744 for c in textline[i:value.offset - 1]:
745 if c.isspace():
745 if c.isspace():
746 s += c
746 s += c
747 else:
747 else:
748 s += ' '
748 s += ' '
749 list.append('%s%s^%s\n' % (Colors.caret, s,
749 list.append('%s%s^%s\n' % (Colors.caret, s,
750 Colors.Normal))
750 Colors.Normal))
751
751
752 try:
752 try:
753 s = value.msg
753 s = value.msg
754 except Exception:
754 except Exception:
755 s = self._some_str(value)
755 s = self._some_str(value)
756 if s:
756 if s:
757 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
757 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
758 Colors.Normal, s))
758 Colors.Normal, s))
759 else:
759 else:
760 list.append('%s\n' % stype)
760 list.append('%s\n' % stype)
761
761
762 # sync with user hooks
762 # sync with user hooks
763 if have_filedata:
763 if have_filedata:
764 ipinst = get_ipython()
764 ipinst = get_ipython()
765 if ipinst is not None:
765 if ipinst is not None:
766 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
766 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
767
767
768 return list
768 return list
769
769
770 def get_exception_only(self, etype, value):
770 def get_exception_only(self, etype, value):
771 """Only print the exception type and message, without a traceback.
771 """Only print the exception type and message, without a traceback.
772
772
773 Parameters
773 Parameters
774 ----------
774 ----------
775 etype : exception type
775 etype : exception type
776 value : exception value
776 value : exception value
777 """
777 """
778 return ListTB.structured_traceback(self, etype, value, [])
778 return ListTB.structured_traceback(self, etype, value, [])
779
779
780 def show_exception_only(self, etype, evalue):
780 def show_exception_only(self, etype, evalue):
781 """Only print the exception type and message, without a traceback.
781 """Only print the exception type and message, without a traceback.
782
782
783 Parameters
783 Parameters
784 ----------
784 ----------
785 etype : exception type
785 etype : exception type
786 value : exception value
786 value : exception value
787 """
787 """
788 # This method needs to use __call__ from *this* class, not the one from
788 # This method needs to use __call__ from *this* class, not the one from
789 # a subclass whose signature or behavior may be different
789 # a subclass whose signature or behavior may be different
790 ostream = self.ostream
790 ostream = self.ostream
791 ostream.flush()
791 ostream.flush()
792 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
792 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
793 ostream.flush()
793 ostream.flush()
794
794
795 def _some_str(self, value):
795 def _some_str(self, value):
796 # Lifted from traceback.py
796 # Lifted from traceback.py
797 try:
797 try:
798 return py3compat.cast_unicode(str(value))
798 return py3compat.cast_unicode(str(value))
799 except:
799 except:
800 return u'<unprintable %s object>' % type(value).__name__
800 return u'<unprintable %s object>' % type(value).__name__
801
801
802
802
803 #----------------------------------------------------------------------------
803 #----------------------------------------------------------------------------
804 class VerboseTB(TBTools):
804 class VerboseTB(TBTools):
805 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
805 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
806 of HTML. Requires inspect and pydoc. Crazy, man.
806 of HTML. Requires inspect and pydoc. Crazy, man.
807
807
808 Modified version which optionally strips the topmost entries from the
808 Modified version which optionally strips the topmost entries from the
809 traceback, to be used with alternate interpreters (because their own code
809 traceback, to be used with alternate interpreters (because their own code
810 would appear in the traceback)."""
810 would appear in the traceback)."""
811
811
812 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
812 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
813 tb_offset=0, long_header=False, include_vars=True,
813 tb_offset=0, long_header=False, include_vars=True,
814 check_cache=None, debugger_cls = None):
814 check_cache=None, debugger_cls = None):
815 """Specify traceback offset, headers and color scheme.
815 """Specify traceback offset, headers and color scheme.
816
816
817 Define how many frames to drop from the tracebacks. Calling it with
817 Define how many frames to drop from the tracebacks. Calling it with
818 tb_offset=1 allows use of this handler in interpreters which will have
818 tb_offset=1 allows use of this handler in interpreters which will have
819 their own code at the top of the traceback (VerboseTB will first
819 their own code at the top of the traceback (VerboseTB will first
820 remove that frame before printing the traceback info)."""
820 remove that frame before printing the traceback info)."""
821 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
821 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
822 ostream=ostream)
822 ostream=ostream)
823 self.tb_offset = tb_offset
823 self.tb_offset = tb_offset
824 self.long_header = long_header
824 self.long_header = long_header
825 self.include_vars = include_vars
825 self.include_vars = include_vars
826 # By default we use linecache.checkcache, but the user can provide a
826 # By default we use linecache.checkcache, but the user can provide a
827 # different check_cache implementation. This is used by the IPython
827 # different check_cache implementation. This is used by the IPython
828 # kernel to provide tracebacks for interactive code that is cached,
828 # kernel to provide tracebacks for interactive code that is cached,
829 # by a compiler instance that flushes the linecache but preserves its
829 # by a compiler instance that flushes the linecache but preserves its
830 # own code cache.
830 # own code cache.
831 if check_cache is None:
831 if check_cache is None:
832 check_cache = linecache.checkcache
832 check_cache = linecache.checkcache
833 self.check_cache = check_cache
833 self.check_cache = check_cache
834
834
835 self.debugger_cls = debugger_cls or debugger.Pdb
835 self.debugger_cls = debugger_cls or debugger.Pdb
836
836
837 def format_records(self, records, last_unique, recursion_repeat):
837 def format_records(self, records, last_unique, recursion_repeat):
838 """Format the stack frames of the traceback"""
838 """Format the stack frames of the traceback"""
839 frames = []
839 frames = []
840 for r in records[:last_unique+recursion_repeat+1]:
840 for r in records[:last_unique+recursion_repeat+1]:
841 #print '*** record:',file,lnum,func,lines,index # dbg
841 #print '*** record:',file,lnum,func,lines,index # dbg
842 frames.append(self.format_record(*r))
842 frames.append(self.format_record(*r))
843
843
844 if recursion_repeat:
844 if recursion_repeat:
845 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
845 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
846 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
846 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
847
847
848 return frames
848 return frames
849
849
850 def format_record(self, frame, file, lnum, func, lines, index):
850 def format_record(self, frame, file, lnum, func, lines, index):
851 """Format a single stack frame"""
851 """Format a single stack frame"""
852 Colors = self.Colors # just a shorthand + quicker name lookup
852 Colors = self.Colors # just a shorthand + quicker name lookup
853 ColorsNormal = Colors.Normal # used a lot
853 ColorsNormal = Colors.Normal # used a lot
854 col_scheme = self.color_scheme_table.active_scheme_name
854 col_scheme = self.color_scheme_table.active_scheme_name
855 indent = ' ' * INDENT_SIZE
855 indent = ' ' * INDENT_SIZE
856 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
856 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
857 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
857 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
858 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
858 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
859 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
859 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
860 ColorsNormal)
860 ColorsNormal)
861 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
861 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
862 (Colors.vName, Colors.valEm, ColorsNormal)
862 (Colors.vName, Colors.valEm, ColorsNormal)
863 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
863 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
864 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
864 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
865 Colors.vName, ColorsNormal)
865 Colors.vName, ColorsNormal)
866 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
866 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
867
867
868 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
868 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
869 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
869 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
870 ColorsNormal)
870 ColorsNormal)
871
871
872 abspath = os.path.abspath
872 abspath = os.path.abspath
873
873
874
874
875 if not file:
875 if not file:
876 file = '?'
876 file = '?'
877 elif file.startswith(str("<")) and file.endswith(str(">")):
877 elif file.startswith(str("<")) and file.endswith(str(">")):
878 # Not a real filename, no problem...
878 # Not a real filename, no problem...
879 pass
879 pass
880 elif not os.path.isabs(file):
880 elif not os.path.isabs(file):
881 # Try to make the filename absolute by trying all
881 # Try to make the filename absolute by trying all
882 # sys.path entries (which is also what linecache does)
882 # sys.path entries (which is also what linecache does)
883 for dirname in sys.path:
883 for dirname in sys.path:
884 try:
884 try:
885 fullname = os.path.join(dirname, file)
885 fullname = os.path.join(dirname, file)
886 if os.path.isfile(fullname):
886 if os.path.isfile(fullname):
887 file = os.path.abspath(fullname)
887 file = os.path.abspath(fullname)
888 break
888 break
889 except Exception:
889 except Exception:
890 # Just in case that sys.path contains very
890 # Just in case that sys.path contains very
891 # strange entries...
891 # strange entries...
892 pass
892 pass
893
893
894 file = py3compat.cast_unicode(file, util_path.fs_encoding)
894 file = py3compat.cast_unicode(file, util_path.fs_encoding)
895 link = tpl_link % file
895 link = tpl_link % file
896 args, varargs, varkw, locals = fixed_getargvalues(frame)
896 args, varargs, varkw, locals = fixed_getargvalues(frame)
897
897
898 if func == '?':
898 if func == '?':
899 call = ''
899 call = ''
900 else:
900 else:
901 # Decide whether to include variable details or not
901 # Decide whether to include variable details or not
902 var_repr = self.include_vars and eqrepr or nullrepr
902 var_repr = self.include_vars and eqrepr or nullrepr
903 try:
903 try:
904 call = tpl_call % (func, inspect.formatargvalues(args,
904 call = tpl_call % (func, inspect.formatargvalues(args,
905 varargs, varkw,
905 varargs, varkw,
906 locals, formatvalue=var_repr))
906 locals, formatvalue=var_repr))
907 except KeyError:
907 except KeyError:
908 # This happens in situations like errors inside generator
908 # This happens in situations like errors inside generator
909 # expressions, where local variables are listed in the
909 # expressions, where local variables are listed in the
910 # line, but can't be extracted from the frame. I'm not
910 # line, but can't be extracted from the frame. I'm not
911 # 100% sure this isn't actually a bug in inspect itself,
911 # 100% sure this isn't actually a bug in inspect itself,
912 # but since there's no info for us to compute with, the
912 # but since there's no info for us to compute with, the
913 # best we can do is report the failure and move on. Here
913 # best we can do is report the failure and move on. Here
914 # we must *not* call any traceback construction again,
914 # we must *not* call any traceback construction again,
915 # because that would mess up use of %debug later on. So we
915 # because that would mess up use of %debug later on. So we
916 # simply report the failure and move on. The only
916 # simply report the failure and move on. The only
917 # limitation will be that this frame won't have locals
917 # limitation will be that this frame won't have locals
918 # listed in the call signature. Quite subtle problem...
918 # listed in the call signature. Quite subtle problem...
919 # I can't think of a good way to validate this in a unit
919 # I can't think of a good way to validate this in a unit
920 # test, but running a script consisting of:
920 # test, but running a script consisting of:
921 # dict( (k,v.strip()) for (k,v) in range(10) )
921 # dict( (k,v.strip()) for (k,v) in range(10) )
922 # will illustrate the error, if this exception catch is
922 # will illustrate the error, if this exception catch is
923 # disabled.
923 # disabled.
924 call = tpl_call_fail % func
924 call = tpl_call_fail % func
925
925
926 # Don't attempt to tokenize binary files.
926 # Don't attempt to tokenize binary files.
927 if file.endswith(('.so', '.pyd', '.dll')):
927 if file.endswith(('.so', '.pyd', '.dll')):
928 return '%s %s\n' % (link, call)
928 return '%s %s\n' % (link, call)
929
929
930 elif file.endswith(('.pyc', '.pyo')):
930 elif file.endswith(('.pyc', '.pyo')):
931 # Look up the corresponding source file.
931 # Look up the corresponding source file.
932 try:
932 try:
933 file = openpy.source_from_cache(file)
933 file = openpy.source_from_cache(file)
934 except ValueError:
934 except ValueError:
935 # Failed to get the source file for some reason
935 # Failed to get the source file for some reason
936 # E.g. https://github.com/ipython/ipython/issues/9486
936 # E.g. https://github.com/ipython/ipython/issues/9486
937 return '%s %s\n' % (link, call)
937 return '%s %s\n' % (link, call)
938
938
939 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
939 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
940 line = getline(file, lnum[0])
940 line = getline(file, lnum[0])
941 lnum[0] += 1
941 lnum[0] += 1
942 return line
942 return line
943
943
944 # Build the list of names on this line of code where the exception
944 # Build the list of names on this line of code where the exception
945 # occurred.
945 # occurred.
946 try:
946 try:
947 names = []
947 names = []
948 name_cont = False
948 name_cont = False
949
949
950 for token_type, token, start, end, line in generate_tokens(linereader):
950 for token_type, token, start, end, line in generate_tokens(linereader):
951 # build composite names
951 # build composite names
952 if token_type == tokenize.NAME and token not in keyword.kwlist:
952 if token_type == tokenize.NAME and token not in keyword.kwlist:
953 if name_cont:
953 if name_cont:
954 # Continuation of a dotted name
954 # Continuation of a dotted name
955 try:
955 try:
956 names[-1].append(token)
956 names[-1].append(token)
957 except IndexError:
957 except IndexError:
958 names.append([token])
958 names.append([token])
959 name_cont = False
959 name_cont = False
960 else:
960 else:
961 # Regular new names. We append everything, the caller
961 # Regular new names. We append everything, the caller
962 # will be responsible for pruning the list later. It's
962 # will be responsible for pruning the list later. It's
963 # very tricky to try to prune as we go, b/c composite
963 # very tricky to try to prune as we go, b/c composite
964 # names can fool us. The pruning at the end is easy
964 # names can fool us. The pruning at the end is easy
965 # to do (or the caller can print a list with repeated
965 # to do (or the caller can print a list with repeated
966 # names if so desired.
966 # names if so desired.
967 names.append([token])
967 names.append([token])
968 elif token == '.':
968 elif token == '.':
969 name_cont = True
969 name_cont = True
970 elif token_type == tokenize.NEWLINE:
970 elif token_type == tokenize.NEWLINE:
971 break
971 break
972
972
973 except (IndexError, UnicodeDecodeError, SyntaxError):
973 except (IndexError, UnicodeDecodeError, SyntaxError):
974 # signals exit of tokenizer
974 # signals exit of tokenizer
975 # SyntaxError can occur if the file is not actually Python
975 # SyntaxError can occur if the file is not actually Python
976 # - see gh-6300
976 # - see gh-6300
977 pass
977 pass
978 except tokenize.TokenError as msg:
978 except tokenize.TokenError as msg:
979 _m = ("An unexpected error occurred while tokenizing input\n"
979 _m = ("An unexpected error occurred while tokenizing input\n"
980 "The following traceback may be corrupted or invalid\n"
980 "The following traceback may be corrupted or invalid\n"
981 "The error message is: %s\n" % msg)
981 "The error message is: %s\n" % msg)
982 error(_m)
982 error(_m)
983
983
984 # Join composite names (e.g. "dict.fromkeys")
984 # Join composite names (e.g. "dict.fromkeys")
985 names = ['.'.join(n) for n in names]
985 names = ['.'.join(n) for n in names]
986 # prune names list of duplicates, but keep the right order
986 # prune names list of duplicates, but keep the right order
987 unique_names = uniq_stable(names)
987 unique_names = uniq_stable(names)
988
988
989 # Start loop over vars
989 # Start loop over vars
990 lvals = []
990 lvals = []
991 if self.include_vars:
991 if self.include_vars:
992 for name_full in unique_names:
992 for name_full in unique_names:
993 name_base = name_full.split('.', 1)[0]
993 name_base = name_full.split('.', 1)[0]
994 if name_base in frame.f_code.co_varnames:
994 if name_base in frame.f_code.co_varnames:
995 if name_base in locals:
995 if name_base in locals:
996 try:
996 try:
997 value = repr(eval(name_full, locals))
997 value = repr(eval(name_full, locals))
998 except:
998 except:
999 value = undefined
999 value = undefined
1000 else:
1000 else:
1001 value = undefined
1001 value = undefined
1002 name = tpl_local_var % name_full
1002 name = tpl_local_var % name_full
1003 else:
1003 else:
1004 if name_base in frame.f_globals:
1004 if name_base in frame.f_globals:
1005 try:
1005 try:
1006 value = repr(eval(name_full, frame.f_globals))
1006 value = repr(eval(name_full, frame.f_globals))
1007 except:
1007 except:
1008 value = undefined
1008 value = undefined
1009 else:
1009 else:
1010 value = undefined
1010 value = undefined
1011 name = tpl_global_var % name_full
1011 name = tpl_global_var % name_full
1012 lvals.append(tpl_name_val % (name, value))
1012 lvals.append(tpl_name_val % (name, value))
1013 if lvals:
1013 if lvals:
1014 lvals = '%s%s' % (indent, em_normal.join(lvals))
1014 lvals = '%s%s' % (indent, em_normal.join(lvals))
1015 else:
1015 else:
1016 lvals = ''
1016 lvals = ''
1017
1017
1018 level = '%s %s\n' % (link, call)
1018 level = '%s %s\n' % (link, call)
1019
1019
1020 if index is None:
1020 if index is None:
1021 return level
1021 return level
1022 else:
1022 else:
1023 return '%s%s' % (level, ''.join(
1023 return '%s%s' % (level, ''.join(
1024 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1024 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1025 col_scheme)))
1025 col_scheme)))
1026
1026
1027 def prepare_chained_exception_message(self, cause):
1027 def prepare_chained_exception_message(self, cause):
1028 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1028 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1029 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1029 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1030
1030
1031 if cause:
1031 if cause:
1032 message = [[direct_cause]]
1032 message = [[direct_cause]]
1033 else:
1033 else:
1034 message = [[exception_during_handling]]
1034 message = [[exception_during_handling]]
1035 return message
1035 return message
1036
1036
1037 def prepare_header(self, etype, long_version=False):
1037 def prepare_header(self, etype, long_version=False):
1038 colors = self.Colors # just a shorthand + quicker name lookup
1038 colors = self.Colors # just a shorthand + quicker name lookup
1039 colorsnormal = colors.Normal # used a lot
1039 colorsnormal = colors.Normal # used a lot
1040 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1040 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1041 width = min(75, get_terminal_size()[0])
1041 width = min(75, get_terminal_size()[0])
1042 if long_version:
1042 if long_version:
1043 # Header with the exception type, python version, and date
1043 # Header with the exception type, python version, and date
1044 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1044 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1045 date = time.ctime(time.time())
1045 date = time.ctime(time.time())
1046
1046
1047 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1047 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1048 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1048 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1049 pyver, date.rjust(width) )
1049 pyver, date.rjust(width) )
1050 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1050 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1051 "\ncalls leading up to the error, with the most recent (innermost) call last."
1051 "\ncalls leading up to the error, with the most recent (innermost) call last."
1052 else:
1052 else:
1053 # Simplified header
1053 # Simplified header
1054 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1054 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1055 rjust(width - len(str(etype))) )
1055 rjust(width - len(str(etype))) )
1056
1056
1057 return head
1057 return head
1058
1058
1059 def format_exception(self, etype, evalue):
1059 def format_exception(self, etype, evalue):
1060 colors = self.Colors # just a shorthand + quicker name lookup
1060 colors = self.Colors # just a shorthand + quicker name lookup
1061 colorsnormal = colors.Normal # used a lot
1061 colorsnormal = colors.Normal # used a lot
1062 indent = ' ' * INDENT_SIZE
1062 indent = ' ' * INDENT_SIZE
1063 # Get (safely) a string form of the exception info
1063 # Get (safely) a string form of the exception info
1064 try:
1064 try:
1065 etype_str, evalue_str = map(str, (etype, evalue))
1065 etype_str, evalue_str = map(str, (etype, evalue))
1066 except:
1066 except:
1067 # User exception is improperly defined.
1067 # User exception is improperly defined.
1068 etype, evalue = str, sys.exc_info()[:2]
1068 etype, evalue = str, sys.exc_info()[:2]
1069 etype_str, evalue_str = map(str, (etype, evalue))
1069 etype_str, evalue_str = map(str, (etype, evalue))
1070 # ... and format it
1070 # ... and format it
1071 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1071 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1072 colorsnormal, py3compat.cast_unicode(evalue_str))]
1072 colorsnormal, py3compat.cast_unicode(evalue_str))]
1073
1073
1074 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1074 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1075 try:
1075 try:
1076 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1076 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1077 except:
1077 except:
1078 # Every now and then, an object with funny internals blows up
1078 # Every now and then, an object with funny internals blows up
1079 # when dir() is called on it. We do the best we can to report
1079 # when dir() is called on it. We do the best we can to report
1080 # the problem and continue
1080 # the problem and continue
1081 _m = '%sException reporting error (object with broken dir())%s:'
1081 _m = '%sException reporting error (object with broken dir())%s:'
1082 exception.append(_m % (colors.excName, colorsnormal))
1082 exception.append(_m % (colors.excName, colorsnormal))
1083 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1083 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1084 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1084 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1085 colorsnormal, py3compat.cast_unicode(evalue_str)))
1085 colorsnormal, py3compat.cast_unicode(evalue_str)))
1086 names = []
1086 names = []
1087 for name in names:
1087 for name in names:
1088 value = text_repr(getattr(evalue, name))
1088 value = text_repr(getattr(evalue, name))
1089 exception.append('\n%s%s = %s' % (indent, name, value))
1089 exception.append('\n%s%s = %s' % (indent, name, value))
1090
1090
1091 return exception
1091 return exception
1092
1092
1093 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1093 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1094 """Formats the header, traceback and exception message for a single exception.
1094 """Formats the header, traceback and exception message for a single exception.
1095
1095
1096 This may be called multiple times by Python 3 exception chaining
1096 This may be called multiple times by Python 3 exception chaining
1097 (PEP 3134).
1097 (PEP 3134).
1098 """
1098 """
1099 # some locals
1099 # some locals
1100 orig_etype = etype
1100 orig_etype = etype
1101 try:
1101 try:
1102 etype = etype.__name__
1102 etype = etype.__name__
1103 except AttributeError:
1103 except AttributeError:
1104 pass
1104 pass
1105
1105
1106 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1106 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1107 head = self.prepare_header(etype, self.long_header)
1107 head = self.prepare_header(etype, self.long_header)
1108 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1108 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1109
1109
1110 if records is None:
1110 if records is None:
1111 return ""
1111 return ""
1112
1112
1113 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1113 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1114
1114
1115 frames = self.format_records(records, last_unique, recursion_repeat)
1115 frames = self.format_records(records, last_unique, recursion_repeat)
1116
1116
1117 formatted_exception = self.format_exception(etype, evalue)
1117 formatted_exception = self.format_exception(etype, evalue)
1118 if records:
1118 if records:
1119 filepath, lnum = records[-1][1:3]
1119 filepath, lnum = records[-1][1:3]
1120 filepath = os.path.abspath(filepath)
1120 filepath = os.path.abspath(filepath)
1121 ipinst = get_ipython()
1121 ipinst = get_ipython()
1122 if ipinst is not None:
1122 if ipinst is not None:
1123 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1123 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1124
1124
1125 return [[head] + frames + [''.join(formatted_exception[0])]]
1125 return [[head] + frames + [''.join(formatted_exception[0])]]
1126
1126
1127 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1127 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1128 try:
1128 try:
1129 # Try the default getinnerframes and Alex's: Alex's fixes some
1129 # Try the default getinnerframes and Alex's: Alex's fixes some
1130 # problems, but it generates empty tracebacks for console errors
1130 # problems, but it generates empty tracebacks for console errors
1131 # (5 blanks lines) where none should be returned.
1131 # (5 blanks lines) where none should be returned.
1132 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1132 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1133 except:
1133 except:
1134 # FIXME: I've been getting many crash reports from python 2.3
1134 # FIXME: I've been getting many crash reports from python 2.3
1135 # users, traceable to inspect.py. If I can find a small test-case
1135 # users, traceable to inspect.py. If I can find a small test-case
1136 # to reproduce this, I should either write a better workaround or
1136 # to reproduce this, I should either write a better workaround or
1137 # file a bug report against inspect (if that's the real problem).
1137 # file a bug report against inspect (if that's the real problem).
1138 # So far, I haven't been able to find an isolated example to
1138 # So far, I haven't been able to find an isolated example to
1139 # reproduce the problem.
1139 # reproduce the problem.
1140 inspect_error()
1140 inspect_error()
1141 traceback.print_exc(file=self.ostream)
1141 traceback.print_exc(file=self.ostream)
1142 info('\nUnfortunately, your original traceback can not be constructed.\n')
1142 info('\nUnfortunately, your original traceback can not be constructed.\n')
1143 return None
1143 return None
1144
1144
1145 def get_parts_of_chained_exception(self, evalue):
1145 def get_parts_of_chained_exception(self, evalue):
1146 def get_chained_exception(exception_value):
1146 def get_chained_exception(exception_value):
1147 cause = getattr(exception_value, '__cause__', None)
1147 cause = getattr(exception_value, '__cause__', None)
1148 if cause:
1148 if cause:
1149 return cause
1149 return cause
1150 if getattr(exception_value, '__suppress_context__', False):
1150 if getattr(exception_value, '__suppress_context__', False):
1151 return None
1151 return None
1152 return getattr(exception_value, '__context__', None)
1152 return getattr(exception_value, '__context__', None)
1153
1153
1154 chained_evalue = get_chained_exception(evalue)
1154 chained_evalue = get_chained_exception(evalue)
1155
1155
1156 if chained_evalue:
1156 if chained_evalue:
1157 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1157 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1158
1158
1159 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1159 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1160 number_of_lines_of_context=5):
1160 number_of_lines_of_context=5):
1161 """Return a nice text document describing the traceback."""
1161 """Return a nice text document describing the traceback."""
1162
1162
1163 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1163 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1164 tb_offset)
1164 tb_offset)
1165
1165
1166 colors = self.Colors # just a shorthand + quicker name lookup
1166 colors = self.Colors # just a shorthand + quicker name lookup
1167 colorsnormal = colors.Normal # used a lot
1167 colorsnormal = colors.Normal # used a lot
1168 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1168 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1169 structured_traceback_parts = [head]
1169 structured_traceback_parts = [head]
1170 if py3compat.PY3:
1170 if py3compat.PY3:
1171 chained_exceptions_tb_offset = 0
1171 chained_exceptions_tb_offset = 0
1172 lines_of_context = 3
1172 lines_of_context = 3
1173 formatted_exceptions = formatted_exception
1173 formatted_exceptions = formatted_exception
1174 exception = self.get_parts_of_chained_exception(evalue)
1174 exception = self.get_parts_of_chained_exception(evalue)
1175 if exception:
1175 if exception:
1176 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1176 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1177 etype, evalue, etb = exception
1177 etype, evalue, etb = exception
1178 else:
1178 else:
1179 evalue = None
1179 evalue = None
1180 chained_exc_ids = set()
1180 chained_exc_ids = set()
1181 while evalue:
1181 while evalue:
1182 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1182 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1183 chained_exceptions_tb_offset)
1183 chained_exceptions_tb_offset)
1184 exception = self.get_parts_of_chained_exception(evalue)
1184 exception = self.get_parts_of_chained_exception(evalue)
1185
1185
1186 if exception and not id(exception[1]) in chained_exc_ids:
1186 if exception and not id(exception[1]) in chained_exc_ids:
1187 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1187 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1188 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1188 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1189 etype, evalue, etb = exception
1189 etype, evalue, etb = exception
1190 else:
1190 else:
1191 evalue = None
1191 evalue = None
1192
1192
1193 # we want to see exceptions in a reversed order:
1193 # we want to see exceptions in a reversed order:
1194 # the first exception should be on top
1194 # the first exception should be on top
1195 for formatted_exception in reversed(formatted_exceptions):
1195 for formatted_exception in reversed(formatted_exceptions):
1196 structured_traceback_parts += formatted_exception
1196 structured_traceback_parts += formatted_exception
1197 else:
1197 else:
1198 structured_traceback_parts += formatted_exception[0]
1198 structured_traceback_parts += formatted_exception[0]
1199
1199
1200 return structured_traceback_parts
1200 return structured_traceback_parts
1201
1201
1202 def debugger(self, force=False):
1202 def debugger(self, force=False):
1203 """Call up the pdb debugger if desired, always clean up the tb
1203 """Call up the pdb debugger if desired, always clean up the tb
1204 reference.
1204 reference.
1205
1205
1206 Keywords:
1206 Keywords:
1207
1207
1208 - force(False): by default, this routine checks the instance call_pdb
1208 - force(False): by default, this routine checks the instance call_pdb
1209 flag and does not actually invoke the debugger if the flag is false.
1209 flag and does not actually invoke the debugger if the flag is false.
1210 The 'force' option forces the debugger to activate even if the flag
1210 The 'force' option forces the debugger to activate even if the flag
1211 is false.
1211 is false.
1212
1212
1213 If the call_pdb flag is set, the pdb interactive debugger is
1213 If the call_pdb flag is set, the pdb interactive debugger is
1214 invoked. In all cases, the self.tb reference to the current traceback
1214 invoked. In all cases, the self.tb reference to the current traceback
1215 is deleted to prevent lingering references which hamper memory
1215 is deleted to prevent lingering references which hamper memory
1216 management.
1216 management.
1217
1217
1218 Note that each call to pdb() does an 'import readline', so if your app
1218 Note that each call to pdb() does an 'import readline', so if your app
1219 requires a special setup for the readline completers, you'll have to
1219 requires a special setup for the readline completers, you'll have to
1220 fix that by hand after invoking the exception handler."""
1220 fix that by hand after invoking the exception handler."""
1221
1221
1222 if force or self.call_pdb:
1222 if force or self.call_pdb:
1223 if self.pdb is None:
1223 if self.pdb is None:
1224 self.pdb = self.debugger_cls(
1224 self.pdb = self.debugger_cls(
1225 self.color_scheme_table.active_scheme_name)
1225 self.color_scheme_table.active_scheme_name)
1226 # the system displayhook may have changed, restore the original
1226 # the system displayhook may have changed, restore the original
1227 # for pdb
1227 # for pdb
1228 display_trap = DisplayTrap(hook=sys.__displayhook__)
1228 display_trap = DisplayTrap(hook=sys.__displayhook__)
1229 with display_trap:
1229 with display_trap:
1230 self.pdb.reset()
1230 self.pdb.reset()
1231 # Find the right frame so we don't pop up inside ipython itself
1231 # Find the right frame so we don't pop up inside ipython itself
1232 if hasattr(self, 'tb') and self.tb is not None:
1232 if hasattr(self, 'tb') and self.tb is not None:
1233 etb = self.tb
1233 etb = self.tb
1234 else:
1234 else:
1235 etb = self.tb = sys.last_traceback
1235 etb = self.tb = sys.last_traceback
1236 while self.tb is not None and self.tb.tb_next is not None:
1236 while self.tb is not None and self.tb.tb_next is not None:
1237 self.tb = self.tb.tb_next
1237 self.tb = self.tb.tb_next
1238 if etb and etb.tb_next:
1238 if etb and etb.tb_next:
1239 etb = etb.tb_next
1239 etb = etb.tb_next
1240 self.pdb.botframe = etb.tb_frame
1240 self.pdb.botframe = etb.tb_frame
1241 self.pdb.interaction(self.tb.tb_frame, self.tb)
1241 self.pdb.interaction(self.tb.tb_frame, self.tb)
1242
1242
1243 if hasattr(self, 'tb'):
1243 if hasattr(self, 'tb'):
1244 del self.tb
1244 del self.tb
1245
1245
1246 def handler(self, info=None):
1246 def handler(self, info=None):
1247 (etype, evalue, etb) = info or sys.exc_info()
1247 (etype, evalue, etb) = info or sys.exc_info()
1248 self.tb = etb
1248 self.tb = etb
1249 ostream = self.ostream
1249 ostream = self.ostream
1250 ostream.flush()
1250 ostream.flush()
1251 ostream.write(self.text(etype, evalue, etb))
1251 ostream.write(self.text(etype, evalue, etb))
1252 ostream.write('\n')
1252 ostream.write('\n')
1253 ostream.flush()
1253 ostream.flush()
1254
1254
1255 # Changed so an instance can just be called as VerboseTB_inst() and print
1255 # Changed so an instance can just be called as VerboseTB_inst() and print
1256 # out the right info on its own.
1256 # out the right info on its own.
1257 def __call__(self, etype=None, evalue=None, etb=None):
1257 def __call__(self, etype=None, evalue=None, etb=None):
1258 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1258 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1259 if etb is None:
1259 if etb is None:
1260 self.handler()
1260 self.handler()
1261 else:
1261 else:
1262 self.handler((etype, evalue, etb))
1262 self.handler((etype, evalue, etb))
1263 try:
1263 try:
1264 self.debugger()
1264 self.debugger()
1265 except KeyboardInterrupt:
1265 except KeyboardInterrupt:
1266 print("\nKeyboardInterrupt")
1266 print("\nKeyboardInterrupt")
1267
1267
1268
1268
1269 #----------------------------------------------------------------------------
1269 #----------------------------------------------------------------------------
1270 class FormattedTB(VerboseTB, ListTB):
1270 class FormattedTB(VerboseTB, ListTB):
1271 """Subclass ListTB but allow calling with a traceback.
1271 """Subclass ListTB but allow calling with a traceback.
1272
1272
1273 It can thus be used as a sys.excepthook for Python > 2.1.
1273 It can thus be used as a sys.excepthook for Python > 2.1.
1274
1274
1275 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1275 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1276
1276
1277 Allows a tb_offset to be specified. This is useful for situations where
1277 Allows a tb_offset to be specified. This is useful for situations where
1278 one needs to remove a number of topmost frames from the traceback (such as
1278 one needs to remove a number of topmost frames from the traceback (such as
1279 occurs with python programs that themselves execute other python code,
1279 occurs with python programs that themselves execute other python code,
1280 like Python shells). """
1280 like Python shells). """
1281
1281
1282 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1282 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1283 ostream=None,
1283 ostream=None,
1284 tb_offset=0, long_header=False, include_vars=False,
1284 tb_offset=0, long_header=False, include_vars=False,
1285 check_cache=None, debugger_cls=None):
1285 check_cache=None, debugger_cls=None):
1286
1286
1287 # NEVER change the order of this list. Put new modes at the end:
1287 # NEVER change the order of this list. Put new modes at the end:
1288 self.valid_modes = ['Plain', 'Context', 'Verbose']
1288 self.valid_modes = ['Plain', 'Context', 'Verbose']
1289 self.verbose_modes = self.valid_modes[1:3]
1289 self.verbose_modes = self.valid_modes[1:3]
1290
1290
1291 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1291 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1292 ostream=ostream, tb_offset=tb_offset,
1292 ostream=ostream, tb_offset=tb_offset,
1293 long_header=long_header, include_vars=include_vars,
1293 long_header=long_header, include_vars=include_vars,
1294 check_cache=check_cache, debugger_cls=debugger_cls)
1294 check_cache=check_cache, debugger_cls=debugger_cls)
1295
1295
1296 # Different types of tracebacks are joined with different separators to
1296 # Different types of tracebacks are joined with different separators to
1297 # form a single string. They are taken from this dict
1297 # form a single string. They are taken from this dict
1298 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1298 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1299 # set_mode also sets the tb_join_char attribute
1299 # set_mode also sets the tb_join_char attribute
1300 self.set_mode(mode)
1300 self.set_mode(mode)
1301
1301
1302 def _extract_tb(self, tb):
1302 def _extract_tb(self, tb):
1303 if tb:
1303 if tb:
1304 return traceback.extract_tb(tb)
1304 return traceback.extract_tb(tb)
1305 else:
1305 else:
1306 return None
1306 return None
1307
1307
1308 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1308 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1309 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1309 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1310 mode = self.mode
1310 mode = self.mode
1311 if mode in self.verbose_modes:
1311 if mode in self.verbose_modes:
1312 # Verbose modes need a full traceback
1312 # Verbose modes need a full traceback
1313 return VerboseTB.structured_traceback(
1313 return VerboseTB.structured_traceback(
1314 self, etype, value, tb, tb_offset, number_of_lines_of_context
1314 self, etype, value, tb, tb_offset, number_of_lines_of_context
1315 )
1315 )
1316 else:
1316 else:
1317 # We must check the source cache because otherwise we can print
1317 # We must check the source cache because otherwise we can print
1318 # out-of-date source code.
1318 # out-of-date source code.
1319 self.check_cache()
1319 self.check_cache()
1320 # Now we can extract and format the exception
1320 # Now we can extract and format the exception
1321 elist = self._extract_tb(tb)
1321 elist = self._extract_tb(tb)
1322 return ListTB.structured_traceback(
1322 return ListTB.structured_traceback(
1323 self, etype, value, elist, tb_offset, number_of_lines_of_context
1323 self, etype, value, elist, tb_offset, number_of_lines_of_context
1324 )
1324 )
1325
1325
1326 def stb2text(self, stb):
1326 def stb2text(self, stb):
1327 """Convert a structured traceback (a list) to a string."""
1327 """Convert a structured traceback (a list) to a string."""
1328 return self.tb_join_char.join(stb)
1328 return self.tb_join_char.join(stb)
1329
1329
1330
1330
1331 def set_mode(self, mode=None):
1331 def set_mode(self, mode=None):
1332 """Switch to the desired mode.
1332 """Switch to the desired mode.
1333
1333
1334 If mode is not specified, cycles through the available modes."""
1334 If mode is not specified, cycles through the available modes."""
1335
1335
1336 if not mode:
1336 if not mode:
1337 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1337 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1338 len(self.valid_modes)
1338 len(self.valid_modes)
1339 self.mode = self.valid_modes[new_idx]
1339 self.mode = self.valid_modes[new_idx]
1340 elif mode not in self.valid_modes:
1340 elif mode not in self.valid_modes:
1341 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1341 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1342 'Valid modes: ' + str(self.valid_modes))
1342 'Valid modes: ' + str(self.valid_modes))
1343 else:
1343 else:
1344 self.mode = mode
1344 self.mode = mode
1345 # include variable details only in 'Verbose' mode
1345 # include variable details only in 'Verbose' mode
1346 self.include_vars = (self.mode == self.valid_modes[2])
1346 self.include_vars = (self.mode == self.valid_modes[2])
1347 # Set the join character for generating text tracebacks
1347 # Set the join character for generating text tracebacks
1348 self.tb_join_char = self._join_chars[self.mode]
1348 self.tb_join_char = self._join_chars[self.mode]
1349
1349
1350 # some convenient shortcuts
1350 # some convenient shortcuts
1351 def plain(self):
1351 def plain(self):
1352 self.set_mode(self.valid_modes[0])
1352 self.set_mode(self.valid_modes[0])
1353
1353
1354 def context(self):
1354 def context(self):
1355 self.set_mode(self.valid_modes[1])
1355 self.set_mode(self.valid_modes[1])
1356
1356
1357 def verbose(self):
1357 def verbose(self):
1358 self.set_mode(self.valid_modes[2])
1358 self.set_mode(self.valid_modes[2])
1359
1359
1360
1360
1361 #----------------------------------------------------------------------------
1361 #----------------------------------------------------------------------------
1362 class AutoFormattedTB(FormattedTB):
1362 class AutoFormattedTB(FormattedTB):
1363 """A traceback printer which can be called on the fly.
1363 """A traceback printer which can be called on the fly.
1364
1364
1365 It will find out about exceptions by itself.
1365 It will find out about exceptions by itself.
1366
1366
1367 A brief example::
1367 A brief example::
1368
1368
1369 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1369 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1370 try:
1370 try:
1371 ...
1371 ...
1372 except:
1372 except:
1373 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1373 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1374 """
1374 """
1375
1375
1376 def __call__(self, etype=None, evalue=None, etb=None,
1376 def __call__(self, etype=None, evalue=None, etb=None,
1377 out=None, tb_offset=None):
1377 out=None, tb_offset=None):
1378 """Print out a formatted exception traceback.
1378 """Print out a formatted exception traceback.
1379
1379
1380 Optional arguments:
1380 Optional arguments:
1381 - out: an open file-like object to direct output to.
1381 - out: an open file-like object to direct output to.
1382
1382
1383 - tb_offset: the number of frames to skip over in the stack, on a
1383 - tb_offset: the number of frames to skip over in the stack, on a
1384 per-call basis (this overrides temporarily the instance's tb_offset
1384 per-call basis (this overrides temporarily the instance's tb_offset
1385 given at initialization time. """
1385 given at initialization time. """
1386
1386
1387 if out is None:
1387 if out is None:
1388 out = self.ostream
1388 out = self.ostream
1389 out.flush()
1389 out.flush()
1390 out.write(self.text(etype, evalue, etb, tb_offset))
1390 out.write(self.text(etype, evalue, etb, tb_offset))
1391 out.write('\n')
1391 out.write('\n')
1392 out.flush()
1392 out.flush()
1393 # FIXME: we should remove the auto pdb behavior from here and leave
1393 # FIXME: we should remove the auto pdb behavior from here and leave
1394 # that to the clients.
1394 # that to the clients.
1395 try:
1395 try:
1396 self.debugger()
1396 self.debugger()
1397 except KeyboardInterrupt:
1397 except KeyboardInterrupt:
1398 print("\nKeyboardInterrupt")
1398 print("\nKeyboardInterrupt")
1399
1399
1400 def structured_traceback(self, etype=None, value=None, tb=None,
1400 def structured_traceback(self, etype=None, value=None, tb=None,
1401 tb_offset=None, number_of_lines_of_context=5):
1401 tb_offset=None, number_of_lines_of_context=5):
1402 if etype is None:
1402 if etype is None:
1403 etype, value, tb = sys.exc_info()
1403 etype, value, tb = sys.exc_info()
1404 self.tb = tb
1404 self.tb = tb
1405 return FormattedTB.structured_traceback(
1405 return FormattedTB.structured_traceback(
1406 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1406 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1407
1407
1408
1408
1409 #---------------------------------------------------------------------------
1409 #---------------------------------------------------------------------------
1410
1410
1411 # A simple class to preserve Nathan's original functionality.
1411 # A simple class to preserve Nathan's original functionality.
1412 class ColorTB(FormattedTB):
1412 class ColorTB(FormattedTB):
1413 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1413 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1414
1414
1415 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1415 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1416 FormattedTB.__init__(self, color_scheme=color_scheme,
1416 FormattedTB.__init__(self, color_scheme=color_scheme,
1417 call_pdb=call_pdb, **kwargs)
1417 call_pdb=call_pdb, **kwargs)
1418
1418
1419
1419
1420 class SyntaxTB(ListTB):
1420 class SyntaxTB(ListTB):
1421 """Extension which holds some state: the last exception value"""
1421 """Extension which holds some state: the last exception value"""
1422
1422
1423 def __init__(self, color_scheme='NoColor'):
1423 def __init__(self, color_scheme='NoColor'):
1424 ListTB.__init__(self, color_scheme)
1424 ListTB.__init__(self, color_scheme)
1425 self.last_syntax_error = None
1425 self.last_syntax_error = None
1426
1426
1427 def __call__(self, etype, value, elist):
1427 def __call__(self, etype, value, elist):
1428 self.last_syntax_error = value
1428 self.last_syntax_error = value
1429
1429
1430 ListTB.__call__(self, etype, value, elist)
1430 ListTB.__call__(self, etype, value, elist)
1431
1431
1432 def structured_traceback(self, etype, value, elist, tb_offset=None,
1432 def structured_traceback(self, etype, value, elist, tb_offset=None,
1433 context=5):
1433 context=5):
1434 # If the source file has been edited, the line in the syntax error can
1434 # If the source file has been edited, the line in the syntax error can
1435 # be wrong (retrieved from an outdated cache). This replaces it with
1435 # be wrong (retrieved from an outdated cache). This replaces it with
1436 # the current value.
1436 # the current value.
1437 if isinstance(value, SyntaxError) \
1437 if isinstance(value, SyntaxError) \
1438 and isinstance(value.filename, py3compat.string_types) \
1438 and isinstance(value.filename, py3compat.string_types) \
1439 and isinstance(value.lineno, int):
1439 and isinstance(value.lineno, int):
1440 linecache.checkcache(value.filename)
1440 linecache.checkcache(value.filename)
1441 newtext = ulinecache.getline(value.filename, value.lineno)
1441 newtext = ulinecache.getline(value.filename, value.lineno)
1442 if newtext:
1442 if newtext:
1443 value.text = newtext
1443 value.text = newtext
1444 self.last_syntax_error = value
1444 self.last_syntax_error = value
1445 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1445 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1446 tb_offset=tb_offset, context=context)
1446 tb_offset=tb_offset, context=context)
1447
1447
1448 def clear_err_state(self):
1448 def clear_err_state(self):
1449 """Return the current error state and clear it"""
1449 """Return the current error state and clear it"""
1450 e = self.last_syntax_error
1450 e = self.last_syntax_error
1451 self.last_syntax_error = None
1451 self.last_syntax_error = None
1452 return e
1452 return e
1453
1453
1454 def stb2text(self, stb):
1454 def stb2text(self, stb):
1455 """Convert a structured traceback (a list) to a string."""
1455 """Convert a structured traceback (a list) to a string."""
1456 return ''.join(stb)
1456 return ''.join(stb)
1457
1457
1458
1458
1459 # some internal-use functions
1459 # some internal-use functions
1460 def text_repr(value):
1460 def text_repr(value):
1461 """Hopefully pretty robust repr equivalent."""
1461 """Hopefully pretty robust repr equivalent."""
1462 # this is pretty horrible but should always return *something*
1462 # this is pretty horrible but should always return *something*
1463 try:
1463 try:
1464 return pydoc.text.repr(value)
1464 return pydoc.text.repr(value)
1465 except KeyboardInterrupt:
1465 except KeyboardInterrupt:
1466 raise
1466 raise
1467 except:
1467 except:
1468 try:
1468 try:
1469 return repr(value)
1469 return repr(value)
1470 except KeyboardInterrupt:
1470 except KeyboardInterrupt:
1471 raise
1471 raise
1472 except:
1472 except:
1473 try:
1473 try:
1474 # all still in an except block so we catch
1474 # all still in an except block so we catch
1475 # getattr raising
1475 # getattr raising
1476 name = getattr(value, '__name__', None)
1476 name = getattr(value, '__name__', None)
1477 if name:
1477 if name:
1478 # ick, recursion
1478 # ick, recursion
1479 return text_repr(name)
1479 return text_repr(name)
1480 klass = getattr(value, '__class__', None)
1480 klass = getattr(value, '__class__', None)
1481 if klass:
1481 if klass:
1482 return '%s instance' % text_repr(klass)
1482 return '%s instance' % text_repr(klass)
1483 except KeyboardInterrupt:
1483 except KeyboardInterrupt:
1484 raise
1484 raise
1485 except:
1485 except:
1486 return 'UNRECOVERABLE REPR FAILURE'
1486 return 'UNRECOVERABLE REPR FAILURE'
1487
1487
1488
1488
1489 def eqrepr(value, repr=text_repr):
1489 def eqrepr(value, repr=text_repr):
1490 return '=%s' % repr(value)
1490 return '=%s' % repr(value)
1491
1491
1492
1492
1493 def nullrepr(value, repr=text_repr):
1493 def nullrepr(value, repr=text_repr):
1494 return ''
1494 return ''
@@ -1,583 +1,583 b''
1 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
2
2
3 This module implements a few classes for running Python scripts interactively
3 This module implements a few classes for running Python scripts interactively
4 in IPython for demonstrations. With very simple markup (a few tags in
4 in IPython for demonstrations. With very simple markup (a few tags in
5 comments), you can control points where the script stops executing and returns
5 comments), you can control points where the script stops executing and returns
6 control to IPython.
6 control to IPython.
7
7
8
8
9 Provided classes
9 Provided classes
10 ----------------
10 ----------------
11
11
12 The classes are (see their docstrings for further details):
12 The classes are (see their docstrings for further details):
13
13
14 - Demo: pure python demos
14 - Demo: pure python demos
15
15
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
17 typed interactively (so magics work, as well as any other special syntax you
17 typed interactively (so magics work, as well as any other special syntax you
18 may have added via input prefilters).
18 may have added via input prefilters).
19
19
20 - LineDemo: single-line version of the Demo class. These demos are executed
20 - LineDemo: single-line version of the Demo class. These demos are executed
21 one line at a time, and require no markup.
21 one line at a time, and require no markup.
22
22
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
24 executed a line at a time, but processed via IPython).
24 executed a line at a time, but processed via IPython).
25
25
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
27 declares an empty marquee and a pre_cmd that clears the screen before each
27 declares an empty marquee and a pre_cmd that clears the screen before each
28 block (see Subclassing below).
28 block (see Subclassing below).
29
29
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
31 classes.
31 classes.
32
32
33 Inheritance diagram:
33 Inheritance diagram:
34
34
35 .. inheritance-diagram:: IPython.lib.demo
35 .. inheritance-diagram:: IPython.lib.demo
36 :parts: 3
36 :parts: 3
37
37
38 Subclassing
38 Subclassing
39 -----------
39 -----------
40
40
41 The classes here all include a few methods meant to make customization by
41 The classes here all include a few methods meant to make customization by
42 subclassing more convenient. Their docstrings below have some more details:
42 subclassing more convenient. Their docstrings below have some more details:
43
43
44 - marquee(): generates a marquee to provide visible on-screen markers at each
44 - marquee(): generates a marquee to provide visible on-screen markers at each
45 block start and end.
45 block start and end.
46
46
47 - pre_cmd(): run right before the execution of each block.
47 - pre_cmd(): run right before the execution of each block.
48
48
49 - post_cmd(): run right after the execution of each block. If the block
49 - post_cmd(): run right after the execution of each block. If the block
50 raises an exception, this is NOT called.
50 raises an exception, this is NOT called.
51
51
52
52
53 Operation
53 Operation
54 ---------
54 ---------
55
55
56 The file is run in its own empty namespace (though you can pass it a string of
56 The file is run in its own empty namespace (though you can pass it a string of
57 arguments as if in a command line environment, and it will see those as
57 arguments as if in a command line environment, and it will see those as
58 sys.argv). But at each stop, the global IPython namespace is updated with the
58 sys.argv). But at each stop, the global IPython namespace is updated with the
59 current internal demo namespace, so you can work interactively with the data
59 current internal demo namespace, so you can work interactively with the data
60 accumulated so far.
60 accumulated so far.
61
61
62 By default, each block of code is printed (with syntax highlighting) before
62 By default, each block of code is printed (with syntax highlighting) before
63 executing it and you have to confirm execution. This is intended to show the
63 executing it and you have to confirm execution. This is intended to show the
64 code to an audience first so you can discuss it, and only proceed with
64 code to an audience first so you can discuss it, and only proceed with
65 execution once you agree. There are a few tags which allow you to modify this
65 execution once you agree. There are a few tags which allow you to modify this
66 behavior.
66 behavior.
67
67
68 The supported tags are:
68 The supported tags are:
69
69
70 # <demo> stop
70 # <demo> stop
71
71
72 Defines block boundaries, the points where IPython stops execution of the
72 Defines block boundaries, the points where IPython stops execution of the
73 file and returns to the interactive prompt.
73 file and returns to the interactive prompt.
74
74
75 You can optionally mark the stop tag with extra dashes before and after the
75 You can optionally mark the stop tag with extra dashes before and after the
76 word 'stop', to help visually distinguish the blocks in a text editor:
76 word 'stop', to help visually distinguish the blocks in a text editor:
77
77
78 # <demo> --- stop ---
78 # <demo> --- stop ---
79
79
80
80
81 # <demo> silent
81 # <demo> silent
82
82
83 Make a block execute silently (and hence automatically). Typically used in
83 Make a block execute silently (and hence automatically). Typically used in
84 cases where you have some boilerplate or initialization code which you need
84 cases where you have some boilerplate or initialization code which you need
85 executed but do not want to be seen in the demo.
85 executed but do not want to be seen in the demo.
86
86
87 # <demo> auto
87 # <demo> auto
88
88
89 Make a block execute automatically, but still being printed. Useful for
89 Make a block execute automatically, but still being printed. Useful for
90 simple code which does not warrant discussion, since it avoids the extra
90 simple code which does not warrant discussion, since it avoids the extra
91 manual confirmation.
91 manual confirmation.
92
92
93 # <demo> auto_all
93 # <demo> auto_all
94
94
95 This tag can _only_ be in the first block, and if given it overrides the
95 This tag can _only_ be in the first block, and if given it overrides the
96 individual auto tags to make the whole demo fully automatic (no block asks
96 individual auto tags to make the whole demo fully automatic (no block asks
97 for confirmation). It can also be given at creation time (or the attribute
97 for confirmation). It can also be given at creation time (or the attribute
98 set later) to override what's in the file.
98 set later) to override what's in the file.
99
99
100 While _any_ python file can be run as a Demo instance, if there are no stop
100 While _any_ python file can be run as a Demo instance, if there are no stop
101 tags the whole file will run in a single block (no different that calling
101 tags the whole file will run in a single block (no different that calling
102 first %pycat and then %run). The minimal markup to make this useful is to
102 first %pycat and then %run). The minimal markup to make this useful is to
103 place a set of stop tags; the other tags are only there to let you fine-tune
103 place a set of stop tags; the other tags are only there to let you fine-tune
104 the execution.
104 the execution.
105
105
106 This is probably best explained with the simple example file below. You can
106 This is probably best explained with the simple example file below. You can
107 copy this into a file named ex_demo.py, and try running it via::
107 copy this into a file named ex_demo.py, and try running it via::
108
108
109 from IPython.demo import Demo
109 from IPython.demo import Demo
110 d = Demo('ex_demo.py')
110 d = Demo('ex_demo.py')
111 d()
111 d()
112
112
113 Each time you call the demo object, it runs the next block. The demo object
113 Each time you call the demo object, it runs the next block. The demo object
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
114 has a few useful methods for navigation, like again(), edit(), jump(), seek()
115 and back(). It can be reset for a new run via reset() or reloaded from disk
115 and back(). It can be reset for a new run via reset() or reloaded from disk
116 (in case you've edited the source) via reload(). See their docstrings below.
116 (in case you've edited the source) via reload(). See their docstrings below.
117
117
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
118 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
119 been added to the "docs/examples/core" directory. Just cd to this directory in
119 been added to the "docs/examples/core" directory. Just cd to this directory in
120 an IPython session, and type::
120 an IPython session, and type::
121
121
122 %run demo-exercizer.py
122 %run demo-exercizer.py
123
123
124 and then follow the directions.
124 and then follow the directions.
125
125
126 Example
126 Example
127 -------
127 -------
128
128
129 The following is a very simple example of a valid demo file.
129 The following is a very simple example of a valid demo file.
130
130
131 ::
131 ::
132
132
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
133 #################### EXAMPLE DEMO <ex_demo.py> ###############################
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
134 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
135
135
136 print 'Hello, welcome to an interactive IPython demo.'
136 print 'Hello, welcome to an interactive IPython demo.'
137
137
138 # The mark below defines a block boundary, which is a point where IPython will
138 # The mark below defines a block boundary, which is a point where IPython will
139 # stop execution and return to the interactive prompt. The dashes are actually
139 # stop execution and return to the interactive prompt. The dashes are actually
140 # optional and used only as a visual aid to clearly separate blocks while
140 # optional and used only as a visual aid to clearly separate blocks while
141 # editing the demo code.
141 # editing the demo code.
142 # <demo> stop
142 # <demo> stop
143
143
144 x = 1
144 x = 1
145 y = 2
145 y = 2
146
146
147 # <demo> stop
147 # <demo> stop
148
148
149 # the mark below makes this block as silent
149 # the mark below makes this block as silent
150 # <demo> silent
150 # <demo> silent
151
151
152 print 'This is a silent block, which gets executed but not printed.'
152 print 'This is a silent block, which gets executed but not printed.'
153
153
154 # <demo> stop
154 # <demo> stop
155 # <demo> auto
155 # <demo> auto
156 print 'This is an automatic block.'
156 print 'This is an automatic block.'
157 print 'It is executed without asking for confirmation, but printed.'
157 print 'It is executed without asking for confirmation, but printed.'
158 z = x+y
158 z = x+y
159
159
160 print 'z=',x
160 print 'z=',x
161
161
162 # <demo> stop
162 # <demo> stop
163 # This is just another normal block.
163 # This is just another normal block.
164 print 'z is now:', z
164 print 'z is now:', z
165
165
166 print 'bye!'
166 print 'bye!'
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
167 ################### END EXAMPLE DEMO <ex_demo.py> ############################
168 """
168 """
169
169
170 from __future__ import unicode_literals
170 from __future__ import unicode_literals
171
171
172 #*****************************************************************************
172 #*****************************************************************************
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
173 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
174 #
174 #
175 # Distributed under the terms of the BSD License. The full license is in
175 # Distributed under the terms of the BSD License. The full license is in
176 # the file COPYING, distributed as part of this software.
176 # the file COPYING, distributed as part of this software.
177 #
177 #
178 #*****************************************************************************
178 #*****************************************************************************
179 from __future__ import print_function
179 from __future__ import print_function
180
180
181 import os
181 import os
182 import re
182 import re
183 import shlex
183 import shlex
184 import sys
184 import sys
185
185
186 from IPython.utils import io
186 from IPython.utils import io
187 from IPython.utils.text import marquee
187 from IPython.utils.text import marquee
188 from IPython.utils import openpy
188 from IPython.utils import openpy
189 from IPython.utils import py3compat
189 from IPython.utils import py3compat
190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
190 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
191
191
192 class DemoError(Exception): pass
192 class DemoError(Exception): pass
193
193
194 def re_mark(mark):
194 def re_mark(mark):
195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
195 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
196
196
197 class Demo(object):
197 class Demo(object):
198
198
199 re_stop = re_mark('-*\s?stop\s?-*')
199 re_stop = re_mark('-*\s?stop\s?-*')
200 re_silent = re_mark('silent')
200 re_silent = re_mark('silent')
201 re_auto = re_mark('auto')
201 re_auto = re_mark('auto')
202 re_auto_all = re_mark('auto_all')
202 re_auto_all = re_mark('auto_all')
203
203
204 def __init__(self,src,title='',arg_str='',auto_all=None):
204 def __init__(self,src,title='',arg_str='',auto_all=None):
205 """Make a new demo object. To run the demo, simply call the object.
205 """Make a new demo object. To run the demo, simply call the object.
206
206
207 See the module docstring for full details and an example (you can use
207 See the module docstring for full details and an example (you can use
208 IPython.Demo? in IPython to see it).
208 IPython.Demo? in IPython to see it).
209
209
210 Inputs:
210 Inputs:
211
211
212 - src is either a file, or file-like object, or a
212 - src is either a file, or file-like object, or a
213 string that can be resolved to a filename.
213 string that can be resolved to a filename.
214
214
215 Optional inputs:
215 Optional inputs:
216
216
217 - title: a string to use as the demo name. Of most use when the demo
217 - title: a string to use as the demo name. Of most use when the demo
218 you are making comes from an object that has no filename, or if you
218 you are making comes from an object that has no filename, or if you
219 want an alternate denotation distinct from the filename.
219 want an alternate denotation distinct from the filename.
220
220
221 - arg_str(''): a string of arguments, internally converted to a list
221 - arg_str(''): a string of arguments, internally converted to a list
222 just like sys.argv, so the demo script can see a similar
222 just like sys.argv, so the demo script can see a similar
223 environment.
223 environment.
224
224
225 - auto_all(None): global flag to run all blocks automatically without
225 - auto_all(None): global flag to run all blocks automatically without
226 confirmation. This attribute overrides the block-level tags and
226 confirmation. This attribute overrides the block-level tags and
227 applies to the whole demo. It is an attribute of the object, and
227 applies to the whole demo. It is an attribute of the object, and
228 can be changed at runtime simply by reassigning it to a boolean
228 can be changed at runtime simply by reassigning it to a boolean
229 value.
229 value.
230 """
230 """
231 if hasattr(src, "read"):
231 if hasattr(src, "read"):
232 # It seems to be a file or a file-like object
232 # It seems to be a file or a file-like object
233 self.fname = "from a file-like object"
233 self.fname = "from a file-like object"
234 if title == '':
234 if title == '':
235 self.title = "from a file-like object"
235 self.title = "from a file-like object"
236 else:
236 else:
237 self.title = title
237 self.title = title
238 else:
238 else:
239 # Assume it's a string or something that can be converted to one
239 # Assume it's a string or something that can be converted to one
240 self.fname = src
240 self.fname = src
241 if title == '':
241 if title == '':
242 (filepath, filename) = os.path.split(src)
242 (filepath, filename) = os.path.split(src)
243 self.title = filename
243 self.title = filename
244 else:
244 else:
245 self.title = title
245 self.title = title
246 self.sys_argv = [src] + shlex.split(arg_str)
246 self.sys_argv = [src] + shlex.split(arg_str)
247 self.auto_all = auto_all
247 self.auto_all = auto_all
248 self.src = src
248 self.src = src
249
249
250 # get a few things from ipython. While it's a bit ugly design-wise,
250 # get a few things from ipython. While it's a bit ugly design-wise,
251 # it ensures that things like color scheme and the like are always in
251 # it ensures that things like color scheme and the like are always in
252 # sync with the ipython mode being used. This class is only meant to
252 # sync with the ipython mode being used. This class is only meant to
253 # be used inside ipython anyways, so it's OK.
253 # be used inside ipython anyways, so it's OK.
254 ip = get_ipython() # this is in builtins whenever IPython is running
254 ip = get_ipython() # this is in builtins whenever IPython is running
255 self.ip_ns = ip.user_ns
255 self.ip_ns = ip.user_ns
256 self.ip_colorize = ip.pycolorize
256 self.ip_colorize = ip.pycolorize
257 self.ip_showtb = ip.showtraceback
257 self.ip_showtb = ip.showtraceback
258 self.ip_run_cell = ip.run_cell
258 self.ip_run_cell = ip.run_cell
259 self.shell = ip
259 self.shell = ip
260
260
261 # load user data and initialize data structures
261 # load user data and initialize data structures
262 self.reload()
262 self.reload()
263
263
264 def fload(self):
264 def fload(self):
265 """Load file object."""
265 """Load file object."""
266 # read data and parse into blocks
266 # read data and parse into blocks
267 if hasattr(self, 'fobj') and self.fobj is not None:
267 if hasattr(self, 'fobj') and self.fobj is not None:
268 self.fobj.close()
268 self.fobj.close()
269 if hasattr(self.src, "read"):
269 if hasattr(self.src, "read"):
270 # It seems to be a file or a file-like object
270 # It seems to be a file or a file-like object
271 self.fobj = self.src
271 self.fobj = self.src
272 else:
272 else:
273 # Assume it's a string or something that can be converted to one
273 # Assume it's a string or something that can be converted to one
274 self.fobj = openpy.open(self.fname)
274 self.fobj = openpy.open(self.fname)
275
275
276 def reload(self):
276 def reload(self):
277 """Reload source from disk and initialize state."""
277 """Reload source from disk and initialize state."""
278 self.fload()
278 self.fload()
279
279
280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
280 self.src = "".join(openpy.strip_encoding_cookie(self.fobj))
281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
281 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
282 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
283 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
284
284
285 # if auto_all is not given (def. None), we read it from the file
285 # if auto_all is not given (def. None), we read it from the file
286 if self.auto_all is None:
286 if self.auto_all is None:
287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
287 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
288 else:
288 else:
289 self.auto_all = bool(self.auto_all)
289 self.auto_all = bool(self.auto_all)
290
290
291 # Clean the sources from all markup so it doesn't get displayed when
291 # Clean the sources from all markup so it doesn't get displayed when
292 # running the demo
292 # running the demo
293 src_blocks = []
293 src_blocks = []
294 auto_strip = lambda s: self.re_auto.sub('',s)
294 auto_strip = lambda s: self.re_auto.sub('',s)
295 for i,b in enumerate(src_b):
295 for i,b in enumerate(src_b):
296 if self._auto[i]:
296 if self._auto[i]:
297 src_blocks.append(auto_strip(b))
297 src_blocks.append(auto_strip(b))
298 else:
298 else:
299 src_blocks.append(b)
299 src_blocks.append(b)
300 # remove the auto_all marker
300 # remove the auto_all marker
301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
301 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
302
302
303 self.nblocks = len(src_blocks)
303 self.nblocks = len(src_blocks)
304 self.src_blocks = src_blocks
304 self.src_blocks = src_blocks
305
305
306 # also build syntax-highlighted source
306 # also build syntax-highlighted source
307 self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks))
307 self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks))
308
308
309 # ensure clean namespace and seek offset
309 # ensure clean namespace and seek offset
310 self.reset()
310 self.reset()
311
311
312 def reset(self):
312 def reset(self):
313 """Reset the namespace and seek pointer to restart the demo"""
313 """Reset the namespace and seek pointer to restart the demo"""
314 self.user_ns = {}
314 self.user_ns = {}
315 self.finished = False
315 self.finished = False
316 self.block_index = 0
316 self.block_index = 0
317
317
318 def _validate_index(self,index):
318 def _validate_index(self,index):
319 if index<0 or index>=self.nblocks:
319 if index<0 or index>=self.nblocks:
320 raise ValueError('invalid block index %s' % index)
320 raise ValueError('invalid block index %s' % index)
321
321
322 def _get_index(self,index):
322 def _get_index(self,index):
323 """Get the current block index, validating and checking status.
323 """Get the current block index, validating and checking status.
324
324
325 Returns None if the demo is finished"""
325 Returns None if the demo is finished"""
326
326
327 if index is None:
327 if index is None:
328 if self.finished:
328 if self.finished:
329 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.')
329 print('Demo finished. Use <demo_name>.reset() if you want to rerun it.')
330 return None
330 return None
331 index = self.block_index
331 index = self.block_index
332 else:
332 else:
333 self._validate_index(index)
333 self._validate_index(index)
334 return index
334 return index
335
335
336 def seek(self,index):
336 def seek(self,index):
337 """Move the current seek pointer to the given block.
337 """Move the current seek pointer to the given block.
338
338
339 You can use negative indices to seek from the end, with identical
339 You can use negative indices to seek from the end, with identical
340 semantics to those of Python lists."""
340 semantics to those of Python lists."""
341 if index<0:
341 if index<0:
342 index = self.nblocks + index
342 index = self.nblocks + index
343 self._validate_index(index)
343 self._validate_index(index)
344 self.block_index = index
344 self.block_index = index
345 self.finished = False
345 self.finished = False
346
346
347 def back(self,num=1):
347 def back(self,num=1):
348 """Move the seek pointer back num blocks (default is 1)."""
348 """Move the seek pointer back num blocks (default is 1)."""
349 self.seek(self.block_index-num)
349 self.seek(self.block_index-num)
350
350
351 def jump(self,num=1):
351 def jump(self,num=1):
352 """Jump a given number of blocks relative to the current one.
352 """Jump a given number of blocks relative to the current one.
353
353
354 The offset can be positive or negative, defaults to 1."""
354 The offset can be positive or negative, defaults to 1."""
355 self.seek(self.block_index+num)
355 self.seek(self.block_index+num)
356
356
357 def again(self):
357 def again(self):
358 """Move the seek pointer back one block and re-execute."""
358 """Move the seek pointer back one block and re-execute."""
359 self.back(1)
359 self.back(1)
360 self()
360 self()
361
361
362 def edit(self,index=None):
362 def edit(self,index=None):
363 """Edit a block.
363 """Edit a block.
364
364
365 If no number is given, use the last block executed.
365 If no number is given, use the last block executed.
366
366
367 This edits the in-memory copy of the demo, it does NOT modify the
367 This edits the in-memory copy of the demo, it does NOT modify the
368 original source file. If you want to do that, simply open the file in
368 original source file. If you want to do that, simply open the file in
369 an editor and use reload() when you make changes to the file. This
369 an editor and use reload() when you make changes to the file. This
370 method is meant to let you change a block during a demonstration for
370 method is meant to let you change a block during a demonstration for
371 explanatory purposes, without damaging your original script."""
371 explanatory purposes, without damaging your original script."""
372
372
373 index = self._get_index(index)
373 index = self._get_index(index)
374 if index is None:
374 if index is None:
375 return
375 return
376 # decrease the index by one (unless we're at the very beginning), so
376 # decrease the index by one (unless we're at the very beginning), so
377 # that the default demo.edit() call opens up the sblock we've last run
377 # that the default demo.edit() call opens up the sblock we've last run
378 if index>0:
378 if index>0:
379 index -= 1
379 index -= 1
380
380
381 filename = self.shell.mktempfile(self.src_blocks[index])
381 filename = self.shell.mktempfile(self.src_blocks[index])
382 self.shell.hooks.editor(filename,1)
382 self.shell.hooks.editor(filename,1)
383 with open(filename, 'r') as f:
383 with open(filename, 'r') as f:
384 new_block = f.read()
384 new_block = f.read()
385 # update the source and colored block
385 # update the source and colored block
386 self.src_blocks[index] = new_block
386 self.src_blocks[index] = new_block
387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
387 self.src_blocks_colored[index] = self.ip_colorize(new_block)
388 self.block_index = index
388 self.block_index = index
389 # call to run with the newly edited index
389 # call to run with the newly edited index
390 self()
390 self()
391
391
392 def show(self,index=None):
392 def show(self,index=None):
393 """Show a single block on screen"""
393 """Show a single block on screen"""
394
394
395 index = self._get_index(index)
395 index = self._get_index(index)
396 if index is None:
396 if index is None:
397 return
397 return
398
398
399 print(self.marquee('<%s> block # %s (%s remaining)' %
399 print(self.marquee('<%s> block # %s (%s remaining)' %
400 (self.title,index,self.nblocks-index-1)))
400 (self.title,index,self.nblocks-index-1)))
401 print(self.src_blocks_colored[index])
401 print(self.src_blocks_colored[index])
402 sys.stdout.flush()
402 sys.stdout.flush()
403
403
404 def show_all(self):
404 def show_all(self):
405 """Show entire demo on screen, block by block"""
405 """Show entire demo on screen, block by block"""
406
406
407 fname = self.title
407 fname = self.title
408 title = self.title
408 title = self.title
409 nblocks = self.nblocks
409 nblocks = self.nblocks
410 silent = self._silent
410 silent = self._silent
411 marquee = self.marquee
411 marquee = self.marquee
412 for index,block in enumerate(self.src_blocks_colored):
412 for index,block in enumerate(self.src_blocks_colored):
413 if silent[index]:
413 if silent[index]:
414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
414 print(marquee('<%s> SILENT block # %s (%s remaining)' %
415 (title,index,nblocks-index-1)))
415 (title,index,nblocks-index-1)))
416 else:
416 else:
417 print(marquee('<%s> block # %s (%s remaining)' %
417 print(marquee('<%s> block # %s (%s remaining)' %
418 (title,index,nblocks-index-1)))
418 (title,index,nblocks-index-1)))
419 print(block, end=' ')
419 print(block, end=' ')
420 sys.stdout.flush()
420 sys.stdout.flush()
421
421
422 def run_cell(self,source):
422 def run_cell(self,source):
423 """Execute a string with one or more lines of code"""
423 """Execute a string with one or more lines of code"""
424
424
425 exec(source, self.user_ns)
425 exec(source, self.user_ns)
426
426
427 def __call__(self,index=None):
427 def __call__(self,index=None):
428 """run a block of the demo.
428 """run a block of the demo.
429
429
430 If index is given, it should be an integer >=1 and <= nblocks. This
430 If index is given, it should be an integer >=1 and <= nblocks. This
431 means that the calling convention is one off from typical Python
431 means that the calling convention is one off from typical Python
432 lists. The reason for the inconsistency is that the demo always
432 lists. The reason for the inconsistency is that the demo always
433 prints 'Block n/N, and N is the total, so it would be very odd to use
433 prints 'Block n/N, and N is the total, so it would be very odd to use
434 zero-indexing here."""
434 zero-indexing here."""
435
435
436 index = self._get_index(index)
436 index = self._get_index(index)
437 if index is None:
437 if index is None:
438 return
438 return
439 try:
439 try:
440 marquee = self.marquee
440 marquee = self.marquee
441 next_block = self.src_blocks[index]
441 next_block = self.src_blocks[index]
442 self.block_index += 1
442 self.block_index += 1
443 if self._silent[index]:
443 if self._silent[index]:
444 print(marquee('Executing silent block # %s (%s remaining)' %
444 print(marquee('Executing silent block # %s (%s remaining)' %
445 (index,self.nblocks-index-1)))
445 (index,self.nblocks-index-1)))
446 else:
446 else:
447 self.pre_cmd()
447 self.pre_cmd()
448 self.show(index)
448 self.show(index)
449 if self.auto_all or self._auto[index]:
449 if self.auto_all or self._auto[index]:
450 print(marquee('output:'))
450 print(marquee('output:'))
451 else:
451 else:
452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ')
452 print(marquee('Press <q> to quit, <Enter> to execute...'), end=' ')
453 ans = py3compat.input().strip()
453 ans = py3compat.input().strip()
454 if ans:
454 if ans:
455 print(marquee('Block NOT executed'))
455 print(marquee('Block NOT executed'))
456 return
456 return
457 try:
457 try:
458 save_argv = sys.argv
458 save_argv = sys.argv
459 sys.argv = self.sys_argv
459 sys.argv = self.sys_argv
460 self.run_cell(next_block)
460 self.run_cell(next_block)
461 self.post_cmd()
461 self.post_cmd()
462 finally:
462 finally:
463 sys.argv = save_argv
463 sys.argv = save_argv
464
464
465 except:
465 except:
466 self.ip_showtb(filename=self.fname)
466 self.ip_showtb(filename=self.fname)
467 else:
467 else:
468 self.ip_ns.update(self.user_ns)
468 self.ip_ns.update(self.user_ns)
469
469
470 if self.block_index == self.nblocks:
470 if self.block_index == self.nblocks:
471 mq1 = self.marquee('END OF DEMO')
471 mq1 = self.marquee('END OF DEMO')
472 if mq1:
472 if mq1:
473 # avoid spurious print >>io.stdout,s if empty marquees are used
473 # avoid spurious print if empty marquees are used
474 print()
474 print()
475 print(mq1)
475 print(mq1)
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'))
476 print(self.marquee('Use <demo_name>.reset() if you want to rerun it.'))
477 self.finished = True
477 self.finished = True
478
478
479 # These methods are meant to be overridden by subclasses who may wish to
479 # These methods are meant to be overridden by subclasses who may wish to
480 # customize the behavior of of their demos.
480 # customize the behavior of of their demos.
481 def marquee(self,txt='',width=78,mark='*'):
481 def marquee(self,txt='',width=78,mark='*'):
482 """Return the input string centered in a 'marquee'."""
482 """Return the input string centered in a 'marquee'."""
483 return marquee(txt,width,mark)
483 return marquee(txt,width,mark)
484
484
485 def pre_cmd(self):
485 def pre_cmd(self):
486 """Method called before executing each block."""
486 """Method called before executing each block."""
487 pass
487 pass
488
488
489 def post_cmd(self):
489 def post_cmd(self):
490 """Method called after executing each block."""
490 """Method called after executing each block."""
491 pass
491 pass
492
492
493
493
494 class IPythonDemo(Demo):
494 class IPythonDemo(Demo):
495 """Class for interactive demos with IPython's input processing applied.
495 """Class for interactive demos with IPython's input processing applied.
496
496
497 This subclasses Demo, but instead of executing each block by the Python
497 This subclasses Demo, but instead of executing each block by the Python
498 interpreter (via exec), it actually calls IPython on it, so that any input
498 interpreter (via exec), it actually calls IPython on it, so that any input
499 filters which may be in place are applied to the input block.
499 filters which may be in place are applied to the input block.
500
500
501 If you have an interactive environment which exposes special input
501 If you have an interactive environment which exposes special input
502 processing, you can use this class instead to write demo scripts which
502 processing, you can use this class instead to write demo scripts which
503 operate exactly as if you had typed them interactively. The default Demo
503 operate exactly as if you had typed them interactively. The default Demo
504 class requires the input to be valid, pure Python code.
504 class requires the input to be valid, pure Python code.
505 """
505 """
506
506
507 def run_cell(self,source):
507 def run_cell(self,source):
508 """Execute a string with one or more lines of code"""
508 """Execute a string with one or more lines of code"""
509
509
510 self.shell.run_cell(source)
510 self.shell.run_cell(source)
511
511
512 class LineDemo(Demo):
512 class LineDemo(Demo):
513 """Demo where each line is executed as a separate block.
513 """Demo where each line is executed as a separate block.
514
514
515 The input script should be valid Python code.
515 The input script should be valid Python code.
516
516
517 This class doesn't require any markup at all, and it's meant for simple
517 This class doesn't require any markup at all, and it's meant for simple
518 scripts (with no nesting or any kind of indentation) which consist of
518 scripts (with no nesting or any kind of indentation) which consist of
519 multiple lines of input to be executed, one at a time, as if they had been
519 multiple lines of input to be executed, one at a time, as if they had been
520 typed in the interactive prompt.
520 typed in the interactive prompt.
521
521
522 Note: the input can not have *any* indentation, which means that only
522 Note: the input can not have *any* indentation, which means that only
523 single-lines of input are accepted, not even function definitions are
523 single-lines of input are accepted, not even function definitions are
524 valid."""
524 valid."""
525
525
526 def reload(self):
526 def reload(self):
527 """Reload source from disk and initialize state."""
527 """Reload source from disk and initialize state."""
528 # read data and parse into blocks
528 # read data and parse into blocks
529 self.fload()
529 self.fload()
530 lines = self.fobj.readlines()
530 lines = self.fobj.readlines()
531 src_b = [l for l in lines if l.strip()]
531 src_b = [l for l in lines if l.strip()]
532 nblocks = len(src_b)
532 nblocks = len(src_b)
533 self.src = ''.join(lines)
533 self.src = ''.join(lines)
534 self._silent = [False]*nblocks
534 self._silent = [False]*nblocks
535 self._auto = [True]*nblocks
535 self._auto = [True]*nblocks
536 self.auto_all = True
536 self.auto_all = True
537 self.nblocks = nblocks
537 self.nblocks = nblocks
538 self.src_blocks = src_b
538 self.src_blocks = src_b
539
539
540 # also build syntax-highlighted source
540 # also build syntax-highlighted source
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
541 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
542
542
543 # ensure clean namespace and seek offset
543 # ensure clean namespace and seek offset
544 self.reset()
544 self.reset()
545
545
546
546
547 class IPythonLineDemo(IPythonDemo,LineDemo):
547 class IPythonLineDemo(IPythonDemo,LineDemo):
548 """Variant of the LineDemo class whose input is processed by IPython."""
548 """Variant of the LineDemo class whose input is processed by IPython."""
549 pass
549 pass
550
550
551
551
552 class ClearMixin(object):
552 class ClearMixin(object):
553 """Use this mixin to make Demo classes with less visual clutter.
553 """Use this mixin to make Demo classes with less visual clutter.
554
554
555 Demos using this mixin will clear the screen before every block and use
555 Demos using this mixin will clear the screen before every block and use
556 blank marquees.
556 blank marquees.
557
557
558 Note that in order for the methods defined here to actually override those
558 Note that in order for the methods defined here to actually override those
559 of the classes it's mixed with, it must go /first/ in the inheritance
559 of the classes it's mixed with, it must go /first/ in the inheritance
560 tree. For example:
560 tree. For example:
561
561
562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
562 class ClearIPDemo(ClearMixin,IPythonDemo): pass
563
563
564 will provide an IPythonDemo class with the mixin's features.
564 will provide an IPythonDemo class with the mixin's features.
565 """
565 """
566
566
567 def marquee(self,txt='',width=78,mark='*'):
567 def marquee(self,txt='',width=78,mark='*'):
568 """Blank marquee that returns '' no matter what the input."""
568 """Blank marquee that returns '' no matter what the input."""
569 return ''
569 return ''
570
570
571 def pre_cmd(self):
571 def pre_cmd(self):
572 """Method called before executing each block.
572 """Method called before executing each block.
573
573
574 This one simply clears the screen."""
574 This one simply clears the screen."""
575 from IPython.utils.terminal import term_clear
575 from IPython.utils.terminal import term_clear
576 term_clear()
576 term_clear()
577
577
578 class ClearDemo(ClearMixin,Demo):
578 class ClearDemo(ClearMixin,Demo):
579 pass
579 pass
580
580
581
581
582 class ClearIPDemo(ClearMixin,IPythonDemo):
582 class ClearIPDemo(ClearMixin,IPythonDemo):
583 pass
583 pass
@@ -1,139 +1,139 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.utils.path.py"""
2 """Tests for IPython.utils.path.py"""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 try:
7 try:
8 from unittest.mock import patch
8 from unittest.mock import patch
9 except ImportError:
9 except ImportError:
10 from mock import patch
10 from mock import patch
11
11
12 import nose.tools as nt
12 import nose.tools as nt
13
13
14 from IPython.lib import latextools
14 from IPython.lib import latextools
15 from IPython.testing.decorators import onlyif_cmds_exist, skipif_not_matplotlib
15 from IPython.testing.decorators import onlyif_cmds_exist, skipif_not_matplotlib
16 from IPython.utils.process import FindCmdError
16 from IPython.utils.process import FindCmdError
17
17
18
18
19 def test_latex_to_png_dvipng_fails_when_no_cmd():
19 def test_latex_to_png_dvipng_fails_when_no_cmd():
20 """
20 """
21 `latex_to_png_dvipng` should return None when there is no required command
21 `latex_to_png_dvipng` should return None when there is no required command
22 """
22 """
23 for command in ['latex', 'dvipng']:
23 for command in ['latex', 'dvipng']:
24 yield (check_latex_to_png_dvipng_fails_when_no_cmd, command)
24 yield (check_latex_to_png_dvipng_fails_when_no_cmd, command)
25
25
26
26
27 def check_latex_to_png_dvipng_fails_when_no_cmd(command):
27 def check_latex_to_png_dvipng_fails_when_no_cmd(command):
28 def mock_find_cmd(arg):
28 def mock_find_cmd(arg):
29 if arg == command:
29 if arg == command:
30 raise FindCmdError
30 raise FindCmdError
31
31
32 with patch.object(latextools, "find_cmd", mock_find_cmd):
32 with patch.object(latextools, "find_cmd", mock_find_cmd):
33 nt.assert_equals(latextools.latex_to_png_dvipng("whatever", True),
33 nt.assert_equal(latextools.latex_to_png_dvipng("whatever", True),
34 None)
34 None)
35
35
36
36
37 @onlyif_cmds_exist('latex', 'dvipng')
37 @onlyif_cmds_exist('latex', 'dvipng')
38 def test_latex_to_png_dvipng_runs():
38 def test_latex_to_png_dvipng_runs():
39 """
39 """
40 Test that latex_to_png_dvipng just runs without error.
40 Test that latex_to_png_dvipng just runs without error.
41 """
41 """
42 def mock_kpsewhich(filename):
42 def mock_kpsewhich(filename):
43 nt.assert_equals(filename, "breqn.sty")
43 nt.assert_equal(filename, "breqn.sty")
44 return None
44 return None
45
45
46 for (s, wrap) in [(u"$$x^2$$", False), (u"x^2", True)]:
46 for (s, wrap) in [(u"$$x^2$$", False), (u"x^2", True)]:
47 yield (latextools.latex_to_png_dvipng, s, wrap)
47 yield (latextools.latex_to_png_dvipng, s, wrap)
48
48
49 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
49 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
50 yield (latextools.latex_to_png_dvipng, s, wrap)
50 yield (latextools.latex_to_png_dvipng, s, wrap)
51
51
52 @skipif_not_matplotlib
52 @skipif_not_matplotlib
53 def test_latex_to_png_mpl_runs():
53 def test_latex_to_png_mpl_runs():
54 """
54 """
55 Test that latex_to_png_mpl just runs without error.
55 Test that latex_to_png_mpl just runs without error.
56 """
56 """
57 def mock_kpsewhich(filename):
57 def mock_kpsewhich(filename):
58 nt.assert_equals(filename, "breqn.sty")
58 nt.assert_equal(filename, "breqn.sty")
59 return None
59 return None
60
60
61 for (s, wrap) in [("$x^2$", False), ("x^2", True)]:
61 for (s, wrap) in [("$x^2$", False), ("x^2", True)]:
62 yield (latextools.latex_to_png_mpl, s, wrap)
62 yield (latextools.latex_to_png_mpl, s, wrap)
63
63
64 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
64 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
65 yield (latextools.latex_to_png_mpl, s, wrap)
65 yield (latextools.latex_to_png_mpl, s, wrap)
66
66
67 @skipif_not_matplotlib
67 @skipif_not_matplotlib
68 def test_latex_to_html():
68 def test_latex_to_html():
69 img = latextools.latex_to_html("$x^2$")
69 img = latextools.latex_to_html("$x^2$")
70 nt.assert_in("data:image/png;base64,iVBOR", img)
70 nt.assert_in("data:image/png;base64,iVBOR", img)
71
71
72
72
73 def test_genelatex_no_wrap():
73 def test_genelatex_no_wrap():
74 """
74 """
75 Test genelatex with wrap=False.
75 Test genelatex with wrap=False.
76 """
76 """
77 def mock_kpsewhich(filename):
77 def mock_kpsewhich(filename):
78 assert False, ("kpsewhich should not be called "
78 assert False, ("kpsewhich should not be called "
79 "(called with {0})".format(filename))
79 "(called with {0})".format(filename))
80
80
81 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
81 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
82 nt.assert_equals(
82 nt.assert_equal(
83 '\n'.join(latextools.genelatex("body text", False)),
83 '\n'.join(latextools.genelatex("body text", False)),
84 r'''\documentclass{article}
84 r'''\documentclass{article}
85 \usepackage{amsmath}
85 \usepackage{amsmath}
86 \usepackage{amsthm}
86 \usepackage{amsthm}
87 \usepackage{amssymb}
87 \usepackage{amssymb}
88 \usepackage{bm}
88 \usepackage{bm}
89 \pagestyle{empty}
89 \pagestyle{empty}
90 \begin{document}
90 \begin{document}
91 body text
91 body text
92 \end{document}''')
92 \end{document}''')
93
93
94
94
95 def test_genelatex_wrap_with_breqn():
95 def test_genelatex_wrap_with_breqn():
96 """
96 """
97 Test genelatex with wrap=True for the case breqn.sty is installed.
97 Test genelatex with wrap=True for the case breqn.sty is installed.
98 """
98 """
99 def mock_kpsewhich(filename):
99 def mock_kpsewhich(filename):
100 nt.assert_equals(filename, "breqn.sty")
100 nt.assert_equal(filename, "breqn.sty")
101 return "path/to/breqn.sty"
101 return "path/to/breqn.sty"
102
102
103 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
103 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
104 nt.assert_equals(
104 nt.assert_equal(
105 '\n'.join(latextools.genelatex("x^2", True)),
105 '\n'.join(latextools.genelatex("x^2", True)),
106 r'''\documentclass{article}
106 r'''\documentclass{article}
107 \usepackage{amsmath}
107 \usepackage{amsmath}
108 \usepackage{amsthm}
108 \usepackage{amsthm}
109 \usepackage{amssymb}
109 \usepackage{amssymb}
110 \usepackage{bm}
110 \usepackage{bm}
111 \usepackage{breqn}
111 \usepackage{breqn}
112 \pagestyle{empty}
112 \pagestyle{empty}
113 \begin{document}
113 \begin{document}
114 \begin{dmath*}
114 \begin{dmath*}
115 x^2
115 x^2
116 \end{dmath*}
116 \end{dmath*}
117 \end{document}''')
117 \end{document}''')
118
118
119
119
120 def test_genelatex_wrap_without_breqn():
120 def test_genelatex_wrap_without_breqn():
121 """
121 """
122 Test genelatex with wrap=True for the case breqn.sty is not installed.
122 Test genelatex with wrap=True for the case breqn.sty is not installed.
123 """
123 """
124 def mock_kpsewhich(filename):
124 def mock_kpsewhich(filename):
125 nt.assert_equals(filename, "breqn.sty")
125 nt.assert_equal(filename, "breqn.sty")
126 return None
126 return None
127
127
128 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
128 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
129 nt.assert_equals(
129 nt.assert_equal(
130 '\n'.join(latextools.genelatex("x^2", True)),
130 '\n'.join(latextools.genelatex("x^2", True)),
131 r'''\documentclass{article}
131 r'''\documentclass{article}
132 \usepackage{amsmath}
132 \usepackage{amsmath}
133 \usepackage{amsthm}
133 \usepackage{amsthm}
134 \usepackage{amssymb}
134 \usepackage{amssymb}
135 \usepackage{bm}
135 \usepackage{bm}
136 \pagestyle{empty}
136 \pagestyle{empty}
137 \begin{document}
137 \begin{document}
138 $$x^2$$
138 $$x^2$$
139 \end{document}''')
139 \end{document}''')
@@ -1,1185 +1,1184 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Sphinx directive to support embedded IPython code.
3 Sphinx directive to support embedded IPython code.
4
4
5 This directive allows pasting of entire interactive IPython sessions, prompts
5 This directive allows pasting of entire interactive IPython sessions, prompts
6 and all, and their code will actually get re-executed at doc build time, with
6 and all, and their code will actually get re-executed at doc build time, with
7 all prompts renumbered sequentially. It also allows you to input code as a pure
7 all prompts renumbered sequentially. It also allows you to input code as a pure
8 python input by giving the argument python to the directive. The output looks
8 python input by giving the argument python to the directive. The output looks
9 like an interactive ipython section.
9 like an interactive ipython section.
10
10
11 To enable this directive, simply list it in your Sphinx ``conf.py`` file
11 To enable this directive, simply list it in your Sphinx ``conf.py`` file
12 (making sure the directory where you placed it is visible to sphinx, as is
12 (making sure the directory where you placed it is visible to sphinx, as is
13 needed for all Sphinx directives). For example, to enable syntax highlighting
13 needed for all Sphinx directives). For example, to enable syntax highlighting
14 and the IPython directive::
14 and the IPython directive::
15
15
16 extensions = ['IPython.sphinxext.ipython_console_highlighting',
16 extensions = ['IPython.sphinxext.ipython_console_highlighting',
17 'IPython.sphinxext.ipython_directive']
17 'IPython.sphinxext.ipython_directive']
18
18
19 The IPython directive outputs code-blocks with the language 'ipython'. So
19 The IPython directive outputs code-blocks with the language 'ipython'. So
20 if you do not have the syntax highlighting extension enabled as well, then
20 if you do not have the syntax highlighting extension enabled as well, then
21 all rendered code-blocks will be uncolored. By default this directive assumes
21 all rendered code-blocks will be uncolored. By default this directive assumes
22 that your prompts are unchanged IPython ones, but this can be customized.
22 that your prompts are unchanged IPython ones, but this can be customized.
23 The configurable options that can be placed in conf.py are:
23 The configurable options that can be placed in conf.py are:
24
24
25 ipython_savefig_dir:
25 ipython_savefig_dir:
26 The directory in which to save the figures. This is relative to the
26 The directory in which to save the figures. This is relative to the
27 Sphinx source directory. The default is `html_static_path`.
27 Sphinx source directory. The default is `html_static_path`.
28 ipython_rgxin:
28 ipython_rgxin:
29 The compiled regular expression to denote the start of IPython input
29 The compiled regular expression to denote the start of IPython input
30 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
30 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
31 shouldn't need to change this.
31 shouldn't need to change this.
32 ipython_rgxout:
32 ipython_rgxout:
33 The compiled regular expression to denote the start of IPython output
33 The compiled regular expression to denote the start of IPython output
34 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
34 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
35 shouldn't need to change this.
35 shouldn't need to change this.
36 ipython_promptin:
36 ipython_promptin:
37 The string to represent the IPython input prompt in the generated ReST.
37 The string to represent the IPython input prompt in the generated ReST.
38 The default is 'In [%d]:'. This expects that the line numbers are used
38 The default is 'In [%d]:'. This expects that the line numbers are used
39 in the prompt.
39 in the prompt.
40 ipython_promptout:
40 ipython_promptout:
41 The string to represent the IPython prompt in the generated ReST. The
41 The string to represent the IPython prompt in the generated ReST. The
42 default is 'Out [%d]:'. This expects that the line numbers are used
42 default is 'Out [%d]:'. This expects that the line numbers are used
43 in the prompt.
43 in the prompt.
44 ipython_mplbackend:
44 ipython_mplbackend:
45 The string which specifies if the embedded Sphinx shell should import
45 The string which specifies if the embedded Sphinx shell should import
46 Matplotlib and set the backend. The value specifies a backend that is
46 Matplotlib and set the backend. The value specifies a backend that is
47 passed to `matplotlib.use()` before any lines in `ipython_execlines` are
47 passed to `matplotlib.use()` before any lines in `ipython_execlines` are
48 executed. If not specified in conf.py, then the default value of 'agg' is
48 executed. If not specified in conf.py, then the default value of 'agg' is
49 used. To use the IPython directive without matplotlib as a dependency, set
49 used. To use the IPython directive without matplotlib as a dependency, set
50 the value to `None`. It may end up that matplotlib is still imported
50 the value to `None`. It may end up that matplotlib is still imported
51 if the user specifies so in `ipython_execlines` or makes use of the
51 if the user specifies so in `ipython_execlines` or makes use of the
52 @savefig pseudo decorator.
52 @savefig pseudo decorator.
53 ipython_execlines:
53 ipython_execlines:
54 A list of strings to be exec'd in the embedded Sphinx shell. Typical
54 A list of strings to be exec'd in the embedded Sphinx shell. Typical
55 usage is to make certain packages always available. Set this to an empty
55 usage is to make certain packages always available. Set this to an empty
56 list if you wish to have no imports always available. If specified in
56 list if you wish to have no imports always available. If specified in
57 conf.py as `None`, then it has the effect of making no imports available.
57 conf.py as `None`, then it has the effect of making no imports available.
58 If omitted from conf.py altogether, then the default value of
58 If omitted from conf.py altogether, then the default value of
59 ['import numpy as np', 'import matplotlib.pyplot as plt'] is used.
59 ['import numpy as np', 'import matplotlib.pyplot as plt'] is used.
60 ipython_holdcount
60 ipython_holdcount
61 When the @suppress pseudo-decorator is used, the execution count can be
61 When the @suppress pseudo-decorator is used, the execution count can be
62 incremented or not. The default behavior is to hold the execution count,
62 incremented or not. The default behavior is to hold the execution count,
63 corresponding to a value of `True`. Set this to `False` to increment
63 corresponding to a value of `True`. Set this to `False` to increment
64 the execution count after each suppressed command.
64 the execution count after each suppressed command.
65
65
66 As an example, to use the IPython directive when `matplotlib` is not available,
66 As an example, to use the IPython directive when `matplotlib` is not available,
67 one sets the backend to `None`::
67 one sets the backend to `None`::
68
68
69 ipython_mplbackend = None
69 ipython_mplbackend = None
70
70
71 An example usage of the directive is:
71 An example usage of the directive is:
72
72
73 .. code-block:: rst
73 .. code-block:: rst
74
74
75 .. ipython::
75 .. ipython::
76
76
77 In [1]: x = 1
77 In [1]: x = 1
78
78
79 In [2]: y = x**2
79 In [2]: y = x**2
80
80
81 In [3]: print(y)
81 In [3]: print(y)
82
82
83 See http://matplotlib.org/sampledoc/ipython_directive.html for additional
83 See http://matplotlib.org/sampledoc/ipython_directive.html for additional
84 documentation.
84 documentation.
85
85
86 Pseudo-Decorators
86 Pseudo-Decorators
87 =================
87 =================
88
88
89 Note: Only one decorator is supported per input. If more than one decorator
89 Note: Only one decorator is supported per input. If more than one decorator
90 is specified, then only the last one is used.
90 is specified, then only the last one is used.
91
91
92 In addition to the Pseudo-Decorators/options described at the above link,
92 In addition to the Pseudo-Decorators/options described at the above link,
93 several enhancements have been made. The directive will emit a message to the
93 several enhancements have been made. The directive will emit a message to the
94 console at build-time if code-execution resulted in an exception or warning.
94 console at build-time if code-execution resulted in an exception or warning.
95 You can suppress these on a per-block basis by specifying the :okexcept:
95 You can suppress these on a per-block basis by specifying the :okexcept:
96 or :okwarning: options:
96 or :okwarning: options:
97
97
98 .. code-block:: rst
98 .. code-block:: rst
99
99
100 .. ipython::
100 .. ipython::
101 :okexcept:
101 :okexcept:
102 :okwarning:
102 :okwarning:
103
103
104 In [1]: 1/0
104 In [1]: 1/0
105 In [2]: # raise warning.
105 In [2]: # raise warning.
106
106
107 ToDo
107 ToDo
108 ----
108 ----
109
109
110 - Turn the ad-hoc test() function into a real test suite.
110 - Turn the ad-hoc test() function into a real test suite.
111 - Break up ipython-specific functionality from matplotlib stuff into better
111 - Break up ipython-specific functionality from matplotlib stuff into better
112 separated code.
112 separated code.
113
113
114 Authors
114 Authors
115 -------
115 -------
116
116
117 - John D Hunter: orignal author.
117 - John D Hunter: orignal author.
118 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
118 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
119 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
119 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
120 - Skipper Seabold, refactoring, cleanups, pure python addition
120 - Skipper Seabold, refactoring, cleanups, pure python addition
121 """
121 """
122 from __future__ import print_function
122 from __future__ import print_function
123
123
124 #-----------------------------------------------------------------------------
124 #-----------------------------------------------------------------------------
125 # Imports
125 # Imports
126 #-----------------------------------------------------------------------------
126 #-----------------------------------------------------------------------------
127
127
128 # Stdlib
128 # Stdlib
129 import atexit
129 import atexit
130 import os
130 import os
131 import re
131 import re
132 import sys
132 import sys
133 import tempfile
133 import tempfile
134 import ast
134 import ast
135 import warnings
135 import warnings
136 import shutil
136 import shutil
137
137
138
138
139 # Third-party
139 # Third-party
140 from docutils.parsers.rst import directives
140 from docutils.parsers.rst import directives
141 from sphinx.util.compat import Directive
141 from sphinx.util.compat import Directive
142
142
143 # Our own
143 # Our own
144 from traitlets.config import Config
144 from traitlets.config import Config
145 from IPython import InteractiveShell
145 from IPython import InteractiveShell
146 from IPython.core.profiledir import ProfileDir
146 from IPython.core.profiledir import ProfileDir
147 from IPython.utils import io
147 from IPython.utils import io
148 from IPython.utils.py3compat import PY3
148 from IPython.utils.py3compat import PY3
149
149
150 if PY3:
150 if PY3:
151 from io import StringIO
151 from io import StringIO
152 else:
152 else:
153 from StringIO import StringIO
153 from StringIO import StringIO
154
154
155 #-----------------------------------------------------------------------------
155 #-----------------------------------------------------------------------------
156 # Globals
156 # Globals
157 #-----------------------------------------------------------------------------
157 #-----------------------------------------------------------------------------
158 # for tokenizing blocks
158 # for tokenizing blocks
159 COMMENT, INPUT, OUTPUT = range(3)
159 COMMENT, INPUT, OUTPUT = range(3)
160
160
161 #-----------------------------------------------------------------------------
161 #-----------------------------------------------------------------------------
162 # Functions and class declarations
162 # Functions and class declarations
163 #-----------------------------------------------------------------------------
163 #-----------------------------------------------------------------------------
164
164
165 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
165 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
166 """
166 """
167 part is a string of ipython text, comprised of at most one
167 part is a string of ipython text, comprised of at most one
168 input, one output, comments, and blank lines. The block parser
168 input, one output, comments, and blank lines. The block parser
169 parses the text into a list of::
169 parses the text into a list of::
170
170
171 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
171 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
172
172
173 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
173 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
174 data is, depending on the type of token::
174 data is, depending on the type of token::
175
175
176 COMMENT : the comment string
176 COMMENT : the comment string
177
177
178 INPUT: the (DECORATOR, INPUT_LINE, REST) where
178 INPUT: the (DECORATOR, INPUT_LINE, REST) where
179 DECORATOR: the input decorator (or None)
179 DECORATOR: the input decorator (or None)
180 INPUT_LINE: the input as string (possibly multi-line)
180 INPUT_LINE: the input as string (possibly multi-line)
181 REST : any stdout generated by the input line (not OUTPUT)
181 REST : any stdout generated by the input line (not OUTPUT)
182
182
183 OUTPUT: the output string, possibly multi-line
183 OUTPUT: the output string, possibly multi-line
184
184
185 """
185 """
186 block = []
186 block = []
187 lines = part.split('\n')
187 lines = part.split('\n')
188 N = len(lines)
188 N = len(lines)
189 i = 0
189 i = 0
190 decorator = None
190 decorator = None
191 while 1:
191 while 1:
192
192
193 if i==N:
193 if i==N:
194 # nothing left to parse -- the last line
194 # nothing left to parse -- the last line
195 break
195 break
196
196
197 line = lines[i]
197 line = lines[i]
198 i += 1
198 i += 1
199 line_stripped = line.strip()
199 line_stripped = line.strip()
200 if line_stripped.startswith('#'):
200 if line_stripped.startswith('#'):
201 block.append((COMMENT, line))
201 block.append((COMMENT, line))
202 continue
202 continue
203
203
204 if line_stripped.startswith('@'):
204 if line_stripped.startswith('@'):
205 # Here is where we assume there is, at most, one decorator.
205 # Here is where we assume there is, at most, one decorator.
206 # Might need to rethink this.
206 # Might need to rethink this.
207 decorator = line_stripped
207 decorator = line_stripped
208 continue
208 continue
209
209
210 # does this look like an input line?
210 # does this look like an input line?
211 matchin = rgxin.match(line)
211 matchin = rgxin.match(line)
212 if matchin:
212 if matchin:
213 lineno, inputline = int(matchin.group(1)), matchin.group(2)
213 lineno, inputline = int(matchin.group(1)), matchin.group(2)
214
214
215 # the ....: continuation string
215 # the ....: continuation string
216 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
216 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
217 Nc = len(continuation)
217 Nc = len(continuation)
218 # input lines can continue on for more than one line, if
218 # input lines can continue on for more than one line, if
219 # we have a '\' line continuation char or a function call
219 # we have a '\' line continuation char or a function call
220 # echo line 'print'. The input line can only be
220 # echo line 'print'. The input line can only be
221 # terminated by the end of the block or an output line, so
221 # terminated by the end of the block or an output line, so
222 # we parse out the rest of the input line if it is
222 # we parse out the rest of the input line if it is
223 # multiline as well as any echo text
223 # multiline as well as any echo text
224
224
225 rest = []
225 rest = []
226 while i<N:
226 while i<N:
227
227
228 # look ahead; if the next line is blank, or a comment, or
228 # look ahead; if the next line is blank, or a comment, or
229 # an output line, we're done
229 # an output line, we're done
230
230
231 nextline = lines[i]
231 nextline = lines[i]
232 matchout = rgxout.match(nextline)
232 matchout = rgxout.match(nextline)
233 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
233 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
234 if matchout or nextline.startswith('#'):
234 if matchout or nextline.startswith('#'):
235 break
235 break
236 elif nextline.startswith(continuation):
236 elif nextline.startswith(continuation):
237 # The default ipython_rgx* treat the space following the colon as optional.
237 # The default ipython_rgx* treat the space following the colon as optional.
238 # However, If the space is there we must consume it or code
238 # However, If the space is there we must consume it or code
239 # employing the cython_magic extension will fail to execute.
239 # employing the cython_magic extension will fail to execute.
240 #
240 #
241 # This works with the default ipython_rgx* patterns,
241 # This works with the default ipython_rgx* patterns,
242 # If you modify them, YMMV.
242 # If you modify them, YMMV.
243 nextline = nextline[Nc:]
243 nextline = nextline[Nc:]
244 if nextline and nextline[0] == ' ':
244 if nextline and nextline[0] == ' ':
245 nextline = nextline[1:]
245 nextline = nextline[1:]
246
246
247 inputline += '\n' + nextline
247 inputline += '\n' + nextline
248 else:
248 else:
249 rest.append(nextline)
249 rest.append(nextline)
250 i+= 1
250 i+= 1
251
251
252 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
252 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
253 continue
253 continue
254
254
255 # if it looks like an output line grab all the text to the end
255 # if it looks like an output line grab all the text to the end
256 # of the block
256 # of the block
257 matchout = rgxout.match(line)
257 matchout = rgxout.match(line)
258 if matchout:
258 if matchout:
259 lineno, output = int(matchout.group(1)), matchout.group(2)
259 lineno, output = int(matchout.group(1)), matchout.group(2)
260 if i<N-1:
260 if i<N-1:
261 output = '\n'.join([output] + lines[i:])
261 output = '\n'.join([output] + lines[i:])
262
262
263 block.append((OUTPUT, output))
263 block.append((OUTPUT, output))
264 break
264 break
265
265
266 return block
266 return block
267
267
268
268
269 class EmbeddedSphinxShell(object):
269 class EmbeddedSphinxShell(object):
270 """An embedded IPython instance to run inside Sphinx"""
270 """An embedded IPython instance to run inside Sphinx"""
271
271
272 def __init__(self, exec_lines=None):
272 def __init__(self, exec_lines=None):
273
273
274 self.cout = StringIO()
274 self.cout = StringIO()
275
275
276 if exec_lines is None:
276 if exec_lines is None:
277 exec_lines = []
277 exec_lines = []
278
278
279 # Create config object for IPython
279 # Create config object for IPython
280 config = Config()
280 config = Config()
281 config.HistoryManager.hist_file = ':memory:'
281 config.HistoryManager.hist_file = ':memory:'
282 config.InteractiveShell.autocall = False
282 config.InteractiveShell.autocall = False
283 config.InteractiveShell.autoindent = False
283 config.InteractiveShell.autoindent = False
284 config.InteractiveShell.colors = 'NoColor'
284 config.InteractiveShell.colors = 'NoColor'
285
285
286 # create a profile so instance history isn't saved
286 # create a profile so instance history isn't saved
287 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
287 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
288 profname = 'auto_profile_sphinx_build'
288 profname = 'auto_profile_sphinx_build'
289 pdir = os.path.join(tmp_profile_dir,profname)
289 pdir = os.path.join(tmp_profile_dir,profname)
290 profile = ProfileDir.create_profile_dir(pdir)
290 profile = ProfileDir.create_profile_dir(pdir)
291
291
292 # Create and initialize global ipython, but don't start its mainloop.
292 # Create and initialize global ipython, but don't start its mainloop.
293 # This will persist across different EmbededSphinxShell instances.
293 # This will persist across different EmbededSphinxShell instances.
294 IP = InteractiveShell.instance(config=config, profile_dir=profile)
294 IP = InteractiveShell.instance(config=config, profile_dir=profile)
295 atexit.register(self.cleanup)
295 atexit.register(self.cleanup)
296
296
297 # io.stdout redirect must be done after instantiating InteractiveShell
297 sys.stdout = self.cout
298 io.stdout = self.cout
298 sys.stderr = self.cout
299 io.stderr = self.cout
300
299
301 # For debugging, so we can see normal output, use this:
300 # For debugging, so we can see normal output, use this:
302 #from IPython.utils.io import Tee
301 #from IPython.utils.io import Tee
303 #io.stdout = Tee(self.cout, channel='stdout') # dbg
302 #sys.stdout = Tee(self.cout, channel='stdout') # dbg
304 #io.stderr = Tee(self.cout, channel='stderr') # dbg
303 #sys.stderr = Tee(self.cout, channel='stderr') # dbg
305
304
306 # Store a few parts of IPython we'll need.
305 # Store a few parts of IPython we'll need.
307 self.IP = IP
306 self.IP = IP
308 self.user_ns = self.IP.user_ns
307 self.user_ns = self.IP.user_ns
309 self.user_global_ns = self.IP.user_global_ns
308 self.user_global_ns = self.IP.user_global_ns
310
309
311 self.input = ''
310 self.input = ''
312 self.output = ''
311 self.output = ''
313 self.tmp_profile_dir = tmp_profile_dir
312 self.tmp_profile_dir = tmp_profile_dir
314
313
315 self.is_verbatim = False
314 self.is_verbatim = False
316 self.is_doctest = False
315 self.is_doctest = False
317 self.is_suppress = False
316 self.is_suppress = False
318
317
319 # Optionally, provide more detailed information to shell.
318 # Optionally, provide more detailed information to shell.
320 # this is assigned by the SetUp method of IPythonDirective
319 # this is assigned by the SetUp method of IPythonDirective
321 # to point at itself.
320 # to point at itself.
322 #
321 #
323 # So, you can access handy things at self.directive.state
322 # So, you can access handy things at self.directive.state
324 self.directive = None
323 self.directive = None
325
324
326 # on the first call to the savefig decorator, we'll import
325 # on the first call to the savefig decorator, we'll import
327 # pyplot as plt so we can make a call to the plt.gcf().savefig
326 # pyplot as plt so we can make a call to the plt.gcf().savefig
328 self._pyplot_imported = False
327 self._pyplot_imported = False
329
328
330 # Prepopulate the namespace.
329 # Prepopulate the namespace.
331 for line in exec_lines:
330 for line in exec_lines:
332 self.process_input_line(line, store_history=False)
331 self.process_input_line(line, store_history=False)
333
332
334 def cleanup(self):
333 def cleanup(self):
335 shutil.rmtree(self.tmp_profile_dir, ignore_errors=True)
334 shutil.rmtree(self.tmp_profile_dir, ignore_errors=True)
336
335
337 def clear_cout(self):
336 def clear_cout(self):
338 self.cout.seek(0)
337 self.cout.seek(0)
339 self.cout.truncate(0)
338 self.cout.truncate(0)
340
339
341 def process_input_line(self, line, store_history=True):
340 def process_input_line(self, line, store_history=True):
342 """process the input, capturing stdout"""
341 """process the input, capturing stdout"""
343
342
344 stdout = sys.stdout
343 stdout = sys.stdout
345 splitter = self.IP.input_splitter
344 splitter = self.IP.input_splitter
346 try:
345 try:
347 sys.stdout = self.cout
346 sys.stdout = self.cout
348 splitter.push(line)
347 splitter.push(line)
349 more = splitter.push_accepts_more()
348 more = splitter.push_accepts_more()
350 if not more:
349 if not more:
351 source_raw = splitter.raw_reset()
350 source_raw = splitter.raw_reset()
352 self.IP.run_cell(source_raw, store_history=store_history)
351 self.IP.run_cell(source_raw, store_history=store_history)
353 finally:
352 finally:
354 sys.stdout = stdout
353 sys.stdout = stdout
355
354
356 def process_image(self, decorator):
355 def process_image(self, decorator):
357 """
356 """
358 # build out an image directive like
357 # build out an image directive like
359 # .. image:: somefile.png
358 # .. image:: somefile.png
360 # :width 4in
359 # :width 4in
361 #
360 #
362 # from an input like
361 # from an input like
363 # savefig somefile.png width=4in
362 # savefig somefile.png width=4in
364 """
363 """
365 savefig_dir = self.savefig_dir
364 savefig_dir = self.savefig_dir
366 source_dir = self.source_dir
365 source_dir = self.source_dir
367 saveargs = decorator.split(' ')
366 saveargs = decorator.split(' ')
368 filename = saveargs[1]
367 filename = saveargs[1]
369 # insert relative path to image file in source
368 # insert relative path to image file in source
370 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
369 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
371 source_dir)
370 source_dir)
372
371
373 imagerows = ['.. image:: %s'%outfile]
372 imagerows = ['.. image:: %s'%outfile]
374
373
375 for kwarg in saveargs[2:]:
374 for kwarg in saveargs[2:]:
376 arg, val = kwarg.split('=')
375 arg, val = kwarg.split('=')
377 arg = arg.strip()
376 arg = arg.strip()
378 val = val.strip()
377 val = val.strip()
379 imagerows.append(' :%s: %s'%(arg, val))
378 imagerows.append(' :%s: %s'%(arg, val))
380
379
381 image_file = os.path.basename(outfile) # only return file name
380 image_file = os.path.basename(outfile) # only return file name
382 image_directive = '\n'.join(imagerows)
381 image_directive = '\n'.join(imagerows)
383 return image_file, image_directive
382 return image_file, image_directive
384
383
385 # Callbacks for each type of token
384 # Callbacks for each type of token
386 def process_input(self, data, input_prompt, lineno):
385 def process_input(self, data, input_prompt, lineno):
387 """
386 """
388 Process data block for INPUT token.
387 Process data block for INPUT token.
389
388
390 """
389 """
391 decorator, input, rest = data
390 decorator, input, rest = data
392 image_file = None
391 image_file = None
393 image_directive = None
392 image_directive = None
394
393
395 is_verbatim = decorator=='@verbatim' or self.is_verbatim
394 is_verbatim = decorator=='@verbatim' or self.is_verbatim
396 is_doctest = (decorator is not None and \
395 is_doctest = (decorator is not None and \
397 decorator.startswith('@doctest')) or self.is_doctest
396 decorator.startswith('@doctest')) or self.is_doctest
398 is_suppress = decorator=='@suppress' or self.is_suppress
397 is_suppress = decorator=='@suppress' or self.is_suppress
399 is_okexcept = decorator=='@okexcept' or self.is_okexcept
398 is_okexcept = decorator=='@okexcept' or self.is_okexcept
400 is_okwarning = decorator=='@okwarning' or self.is_okwarning
399 is_okwarning = decorator=='@okwarning' or self.is_okwarning
401 is_savefig = decorator is not None and \
400 is_savefig = decorator is not None and \
402 decorator.startswith('@savefig')
401 decorator.startswith('@savefig')
403
402
404 input_lines = input.split('\n')
403 input_lines = input.split('\n')
405 if len(input_lines) > 1:
404 if len(input_lines) > 1:
406 if input_lines[-1] != "":
405 if input_lines[-1] != "":
407 input_lines.append('') # make sure there's a blank line
406 input_lines.append('') # make sure there's a blank line
408 # so splitter buffer gets reset
407 # so splitter buffer gets reset
409
408
410 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
409 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
411
410
412 if is_savefig:
411 if is_savefig:
413 image_file, image_directive = self.process_image(decorator)
412 image_file, image_directive = self.process_image(decorator)
414
413
415 ret = []
414 ret = []
416 is_semicolon = False
415 is_semicolon = False
417
416
418 # Hold the execution count, if requested to do so.
417 # Hold the execution count, if requested to do so.
419 if is_suppress and self.hold_count:
418 if is_suppress and self.hold_count:
420 store_history = False
419 store_history = False
421 else:
420 else:
422 store_history = True
421 store_history = True
423
422
424 # Note: catch_warnings is not thread safe
423 # Note: catch_warnings is not thread safe
425 with warnings.catch_warnings(record=True) as ws:
424 with warnings.catch_warnings(record=True) as ws:
426 for i, line in enumerate(input_lines):
425 for i, line in enumerate(input_lines):
427 if line.endswith(';'):
426 if line.endswith(';'):
428 is_semicolon = True
427 is_semicolon = True
429
428
430 if i == 0:
429 if i == 0:
431 # process the first input line
430 # process the first input line
432 if is_verbatim:
431 if is_verbatim:
433 self.process_input_line('')
432 self.process_input_line('')
434 self.IP.execution_count += 1 # increment it anyway
433 self.IP.execution_count += 1 # increment it anyway
435 else:
434 else:
436 # only submit the line in non-verbatim mode
435 # only submit the line in non-verbatim mode
437 self.process_input_line(line, store_history=store_history)
436 self.process_input_line(line, store_history=store_history)
438 formatted_line = '%s %s'%(input_prompt, line)
437 formatted_line = '%s %s'%(input_prompt, line)
439 else:
438 else:
440 # process a continuation line
439 # process a continuation line
441 if not is_verbatim:
440 if not is_verbatim:
442 self.process_input_line(line, store_history=store_history)
441 self.process_input_line(line, store_history=store_history)
443
442
444 formatted_line = '%s %s'%(continuation, line)
443 formatted_line = '%s %s'%(continuation, line)
445
444
446 if not is_suppress:
445 if not is_suppress:
447 ret.append(formatted_line)
446 ret.append(formatted_line)
448
447
449 if not is_suppress and len(rest.strip()) and is_verbatim:
448 if not is_suppress and len(rest.strip()) and is_verbatim:
450 # The "rest" is the standard output of the input. This needs to be
449 # The "rest" is the standard output of the input. This needs to be
451 # added when in verbatim mode. If there is no "rest", then we don't
450 # added when in verbatim mode. If there is no "rest", then we don't
452 # add it, as the new line will be added by the processed output.
451 # add it, as the new line will be added by the processed output.
453 ret.append(rest)
452 ret.append(rest)
454
453
455 # Fetch the processed output. (This is not the submitted output.)
454 # Fetch the processed output. (This is not the submitted output.)
456 self.cout.seek(0)
455 self.cout.seek(0)
457 processed_output = self.cout.read()
456 processed_output = self.cout.read()
458 if not is_suppress and not is_semicolon:
457 if not is_suppress and not is_semicolon:
459 #
458 #
460 # In IPythonDirective.run, the elements of `ret` are eventually
459 # In IPythonDirective.run, the elements of `ret` are eventually
461 # combined such that '' entries correspond to newlines. So if
460 # combined such that '' entries correspond to newlines. So if
462 # `processed_output` is equal to '', then the adding it to `ret`
461 # `processed_output` is equal to '', then the adding it to `ret`
463 # ensures that there is a blank line between consecutive inputs
462 # ensures that there is a blank line between consecutive inputs
464 # that have no outputs, as in:
463 # that have no outputs, as in:
465 #
464 #
466 # In [1]: x = 4
465 # In [1]: x = 4
467 #
466 #
468 # In [2]: x = 5
467 # In [2]: x = 5
469 #
468 #
470 # When there is processed output, it has a '\n' at the tail end. So
469 # When there is processed output, it has a '\n' at the tail end. So
471 # adding the output to `ret` will provide the necessary spacing
470 # adding the output to `ret` will provide the necessary spacing
472 # between consecutive input/output blocks, as in:
471 # between consecutive input/output blocks, as in:
473 #
472 #
474 # In [1]: x
473 # In [1]: x
475 # Out[1]: 5
474 # Out[1]: 5
476 #
475 #
477 # In [2]: x
476 # In [2]: x
478 # Out[2]: 5
477 # Out[2]: 5
479 #
478 #
480 # When there is stdout from the input, it also has a '\n' at the
479 # When there is stdout from the input, it also has a '\n' at the
481 # tail end, and so this ensures proper spacing as well. E.g.:
480 # tail end, and so this ensures proper spacing as well. E.g.:
482 #
481 #
483 # In [1]: print x
482 # In [1]: print x
484 # 5
483 # 5
485 #
484 #
486 # In [2]: x = 5
485 # In [2]: x = 5
487 #
486 #
488 # When in verbatim mode, `processed_output` is empty (because
487 # When in verbatim mode, `processed_output` is empty (because
489 # nothing was passed to IP. Sometimes the submitted code block has
488 # nothing was passed to IP. Sometimes the submitted code block has
490 # an Out[] portion and sometimes it does not. When it does not, we
489 # an Out[] portion and sometimes it does not. When it does not, we
491 # need to ensure proper spacing, so we have to add '' to `ret`.
490 # need to ensure proper spacing, so we have to add '' to `ret`.
492 # However, if there is an Out[] in the submitted code, then we do
491 # However, if there is an Out[] in the submitted code, then we do
493 # not want to add a newline as `process_output` has stuff to add.
492 # not want to add a newline as `process_output` has stuff to add.
494 # The difficulty is that `process_input` doesn't know if
493 # The difficulty is that `process_input` doesn't know if
495 # `process_output` will be called---so it doesn't know if there is
494 # `process_output` will be called---so it doesn't know if there is
496 # Out[] in the code block. The requires that we include a hack in
495 # Out[] in the code block. The requires that we include a hack in
497 # `process_block`. See the comments there.
496 # `process_block`. See the comments there.
498 #
497 #
499 ret.append(processed_output)
498 ret.append(processed_output)
500 elif is_semicolon:
499 elif is_semicolon:
501 # Make sure there is a newline after the semicolon.
500 # Make sure there is a newline after the semicolon.
502 ret.append('')
501 ret.append('')
503
502
504 # context information
503 # context information
505 filename = "Unknown"
504 filename = "Unknown"
506 lineno = 0
505 lineno = 0
507 if self.directive.state:
506 if self.directive.state:
508 filename = self.directive.state.document.current_source
507 filename = self.directive.state.document.current_source
509 lineno = self.directive.state.document.current_line
508 lineno = self.directive.state.document.current_line
510
509
511 # output any exceptions raised during execution to stdout
510 # output any exceptions raised during execution to stdout
512 # unless :okexcept: has been specified.
511 # unless :okexcept: has been specified.
513 if not is_okexcept and "Traceback" in processed_output:
512 if not is_okexcept and "Traceback" in processed_output:
514 s = "\nException in %s at block ending on line %s\n" % (filename, lineno)
513 s = "\nException in %s at block ending on line %s\n" % (filename, lineno)
515 s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n"
514 s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n"
516 sys.stdout.write('\n\n>>>' + ('-' * 73))
515 sys.stdout.write('\n\n>>>' + ('-' * 73))
517 sys.stdout.write(s)
516 sys.stdout.write(s)
518 sys.stdout.write(processed_output)
517 sys.stdout.write(processed_output)
519 sys.stdout.write('<<<' + ('-' * 73) + '\n\n')
518 sys.stdout.write('<<<' + ('-' * 73) + '\n\n')
520
519
521 # output any warning raised during execution to stdout
520 # output any warning raised during execution to stdout
522 # unless :okwarning: has been specified.
521 # unless :okwarning: has been specified.
523 if not is_okwarning:
522 if not is_okwarning:
524 for w in ws:
523 for w in ws:
525 s = "\nWarning in %s at block ending on line %s\n" % (filename, lineno)
524 s = "\nWarning in %s at block ending on line %s\n" % (filename, lineno)
526 s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n"
525 s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n"
527 sys.stdout.write('\n\n>>>' + ('-' * 73))
526 sys.stdout.write('\n\n>>>' + ('-' * 73))
528 sys.stdout.write(s)
527 sys.stdout.write(s)
529 sys.stdout.write(('-' * 76) + '\n')
528 sys.stdout.write(('-' * 76) + '\n')
530 s=warnings.formatwarning(w.message, w.category,
529 s=warnings.formatwarning(w.message, w.category,
531 w.filename, w.lineno, w.line)
530 w.filename, w.lineno, w.line)
532 sys.stdout.write(s)
531 sys.stdout.write(s)
533 sys.stdout.write('<<<' + ('-' * 73) + '\n')
532 sys.stdout.write('<<<' + ('-' * 73) + '\n')
534
533
535 self.cout.truncate(0)
534 self.cout.truncate(0)
536
535
537 return (ret, input_lines, processed_output,
536 return (ret, input_lines, processed_output,
538 is_doctest, decorator, image_file, image_directive)
537 is_doctest, decorator, image_file, image_directive)
539
538
540
539
541 def process_output(self, data, output_prompt, input_lines, output,
540 def process_output(self, data, output_prompt, input_lines, output,
542 is_doctest, decorator, image_file):
541 is_doctest, decorator, image_file):
543 """
542 """
544 Process data block for OUTPUT token.
543 Process data block for OUTPUT token.
545
544
546 """
545 """
547 # Recall: `data` is the submitted output, and `output` is the processed
546 # Recall: `data` is the submitted output, and `output` is the processed
548 # output from `input_lines`.
547 # output from `input_lines`.
549
548
550 TAB = ' ' * 4
549 TAB = ' ' * 4
551
550
552 if is_doctest and output is not None:
551 if is_doctest and output is not None:
553
552
554 found = output # This is the processed output
553 found = output # This is the processed output
555 found = found.strip()
554 found = found.strip()
556 submitted = data.strip()
555 submitted = data.strip()
557
556
558 if self.directive is None:
557 if self.directive is None:
559 source = 'Unavailable'
558 source = 'Unavailable'
560 content = 'Unavailable'
559 content = 'Unavailable'
561 else:
560 else:
562 source = self.directive.state.document.current_source
561 source = self.directive.state.document.current_source
563 content = self.directive.content
562 content = self.directive.content
564 # Add tabs and join into a single string.
563 # Add tabs and join into a single string.
565 content = '\n'.join([TAB + line for line in content])
564 content = '\n'.join([TAB + line for line in content])
566
565
567 # Make sure the output contains the output prompt.
566 # Make sure the output contains the output prompt.
568 ind = found.find(output_prompt)
567 ind = found.find(output_prompt)
569 if ind < 0:
568 if ind < 0:
570 e = ('output does not contain output prompt\n\n'
569 e = ('output does not contain output prompt\n\n'
571 'Document source: {0}\n\n'
570 'Document source: {0}\n\n'
572 'Raw content: \n{1}\n\n'
571 'Raw content: \n{1}\n\n'
573 'Input line(s):\n{TAB}{2}\n\n'
572 'Input line(s):\n{TAB}{2}\n\n'
574 'Output line(s):\n{TAB}{3}\n\n')
573 'Output line(s):\n{TAB}{3}\n\n')
575 e = e.format(source, content, '\n'.join(input_lines),
574 e = e.format(source, content, '\n'.join(input_lines),
576 repr(found), TAB=TAB)
575 repr(found), TAB=TAB)
577 raise RuntimeError(e)
576 raise RuntimeError(e)
578 found = found[len(output_prompt):].strip()
577 found = found[len(output_prompt):].strip()
579
578
580 # Handle the actual doctest comparison.
579 # Handle the actual doctest comparison.
581 if decorator.strip() == '@doctest':
580 if decorator.strip() == '@doctest':
582 # Standard doctest
581 # Standard doctest
583 if found != submitted:
582 if found != submitted:
584 e = ('doctest failure\n\n'
583 e = ('doctest failure\n\n'
585 'Document source: {0}\n\n'
584 'Document source: {0}\n\n'
586 'Raw content: \n{1}\n\n'
585 'Raw content: \n{1}\n\n'
587 'On input line(s):\n{TAB}{2}\n\n'
586 'On input line(s):\n{TAB}{2}\n\n'
588 'we found output:\n{TAB}{3}\n\n'
587 'we found output:\n{TAB}{3}\n\n'
589 'instead of the expected:\n{TAB}{4}\n\n')
588 'instead of the expected:\n{TAB}{4}\n\n')
590 e = e.format(source, content, '\n'.join(input_lines),
589 e = e.format(source, content, '\n'.join(input_lines),
591 repr(found), repr(submitted), TAB=TAB)
590 repr(found), repr(submitted), TAB=TAB)
592 raise RuntimeError(e)
591 raise RuntimeError(e)
593 else:
592 else:
594 self.custom_doctest(decorator, input_lines, found, submitted)
593 self.custom_doctest(decorator, input_lines, found, submitted)
595
594
596 # When in verbatim mode, this holds additional submitted output
595 # When in verbatim mode, this holds additional submitted output
597 # to be written in the final Sphinx output.
596 # to be written in the final Sphinx output.
598 # https://github.com/ipython/ipython/issues/5776
597 # https://github.com/ipython/ipython/issues/5776
599 out_data = []
598 out_data = []
600
599
601 is_verbatim = decorator=='@verbatim' or self.is_verbatim
600 is_verbatim = decorator=='@verbatim' or self.is_verbatim
602 if is_verbatim and data.strip():
601 if is_verbatim and data.strip():
603 # Note that `ret` in `process_block` has '' as its last element if
602 # Note that `ret` in `process_block` has '' as its last element if
604 # the code block was in verbatim mode. So if there is no submitted
603 # the code block was in verbatim mode. So if there is no submitted
605 # output, then we will have proper spacing only if we do not add
604 # output, then we will have proper spacing only if we do not add
606 # an additional '' to `out_data`. This is why we condition on
605 # an additional '' to `out_data`. This is why we condition on
607 # `and data.strip()`.
606 # `and data.strip()`.
608
607
609 # The submitted output has no output prompt. If we want the
608 # The submitted output has no output prompt. If we want the
610 # prompt and the code to appear, we need to join them now
609 # prompt and the code to appear, we need to join them now
611 # instead of adding them separately---as this would create an
610 # instead of adding them separately---as this would create an
612 # undesired newline. How we do this ultimately depends on the
611 # undesired newline. How we do this ultimately depends on the
613 # format of the output regex. I'll do what works for the default
612 # format of the output regex. I'll do what works for the default
614 # prompt for now, and we might have to adjust if it doesn't work
613 # prompt for now, and we might have to adjust if it doesn't work
615 # in other cases. Finally, the submitted output does not have
614 # in other cases. Finally, the submitted output does not have
616 # a trailing newline, so we must add it manually.
615 # a trailing newline, so we must add it manually.
617 out_data.append("{0} {1}\n".format(output_prompt, data))
616 out_data.append("{0} {1}\n".format(output_prompt, data))
618
617
619 return out_data
618 return out_data
620
619
621 def process_comment(self, data):
620 def process_comment(self, data):
622 """Process data fPblock for COMMENT token."""
621 """Process data fPblock for COMMENT token."""
623 if not self.is_suppress:
622 if not self.is_suppress:
624 return [data]
623 return [data]
625
624
626 def save_image(self, image_file):
625 def save_image(self, image_file):
627 """
626 """
628 Saves the image file to disk.
627 Saves the image file to disk.
629 """
628 """
630 self.ensure_pyplot()
629 self.ensure_pyplot()
631 command = 'plt.gcf().savefig("%s")'%image_file
630 command = 'plt.gcf().savefig("%s")'%image_file
632 #print 'SAVEFIG', command # dbg
631 #print 'SAVEFIG', command # dbg
633 self.process_input_line('bookmark ipy_thisdir', store_history=False)
632 self.process_input_line('bookmark ipy_thisdir', store_history=False)
634 self.process_input_line('cd -b ipy_savedir', store_history=False)
633 self.process_input_line('cd -b ipy_savedir', store_history=False)
635 self.process_input_line(command, store_history=False)
634 self.process_input_line(command, store_history=False)
636 self.process_input_line('cd -b ipy_thisdir', store_history=False)
635 self.process_input_line('cd -b ipy_thisdir', store_history=False)
637 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
636 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
638 self.clear_cout()
637 self.clear_cout()
639
638
640 def process_block(self, block):
639 def process_block(self, block):
641 """
640 """
642 process block from the block_parser and return a list of processed lines
641 process block from the block_parser and return a list of processed lines
643 """
642 """
644 ret = []
643 ret = []
645 output = None
644 output = None
646 input_lines = None
645 input_lines = None
647 lineno = self.IP.execution_count
646 lineno = self.IP.execution_count
648
647
649 input_prompt = self.promptin % lineno
648 input_prompt = self.promptin % lineno
650 output_prompt = self.promptout % lineno
649 output_prompt = self.promptout % lineno
651 image_file = None
650 image_file = None
652 image_directive = None
651 image_directive = None
653
652
654 found_input = False
653 found_input = False
655 for token, data in block:
654 for token, data in block:
656 if token == COMMENT:
655 if token == COMMENT:
657 out_data = self.process_comment(data)
656 out_data = self.process_comment(data)
658 elif token == INPUT:
657 elif token == INPUT:
659 found_input = True
658 found_input = True
660 (out_data, input_lines, output, is_doctest,
659 (out_data, input_lines, output, is_doctest,
661 decorator, image_file, image_directive) = \
660 decorator, image_file, image_directive) = \
662 self.process_input(data, input_prompt, lineno)
661 self.process_input(data, input_prompt, lineno)
663 elif token == OUTPUT:
662 elif token == OUTPUT:
664 if not found_input:
663 if not found_input:
665
664
666 TAB = ' ' * 4
665 TAB = ' ' * 4
667 linenumber = 0
666 linenumber = 0
668 source = 'Unavailable'
667 source = 'Unavailable'
669 content = 'Unavailable'
668 content = 'Unavailable'
670 if self.directive:
669 if self.directive:
671 linenumber = self.directive.state.document.current_line
670 linenumber = self.directive.state.document.current_line
672 source = self.directive.state.document.current_source
671 source = self.directive.state.document.current_source
673 content = self.directive.content
672 content = self.directive.content
674 # Add tabs and join into a single string.
673 # Add tabs and join into a single string.
675 content = '\n'.join([TAB + line for line in content])
674 content = '\n'.join([TAB + line for line in content])
676
675
677 e = ('\n\nInvalid block: Block contains an output prompt '
676 e = ('\n\nInvalid block: Block contains an output prompt '
678 'without an input prompt.\n\n'
677 'without an input prompt.\n\n'
679 'Document source: {0}\n\n'
678 'Document source: {0}\n\n'
680 'Content begins at line {1}: \n\n{2}\n\n'
679 'Content begins at line {1}: \n\n{2}\n\n'
681 'Problematic block within content: \n\n{TAB}{3}\n\n')
680 'Problematic block within content: \n\n{TAB}{3}\n\n')
682 e = e.format(source, linenumber, content, block, TAB=TAB)
681 e = e.format(source, linenumber, content, block, TAB=TAB)
683
682
684 # Write, rather than include in exception, since Sphinx
683 # Write, rather than include in exception, since Sphinx
685 # will truncate tracebacks.
684 # will truncate tracebacks.
686 sys.stdout.write(e)
685 sys.stdout.write(e)
687 raise RuntimeError('An invalid block was detected.')
686 raise RuntimeError('An invalid block was detected.')
688
687
689 out_data = \
688 out_data = \
690 self.process_output(data, output_prompt, input_lines,
689 self.process_output(data, output_prompt, input_lines,
691 output, is_doctest, decorator,
690 output, is_doctest, decorator,
692 image_file)
691 image_file)
693 if out_data:
692 if out_data:
694 # Then there was user submitted output in verbatim mode.
693 # Then there was user submitted output in verbatim mode.
695 # We need to remove the last element of `ret` that was
694 # We need to remove the last element of `ret` that was
696 # added in `process_input`, as it is '' and would introduce
695 # added in `process_input`, as it is '' and would introduce
697 # an undesirable newline.
696 # an undesirable newline.
698 assert(ret[-1] == '')
697 assert(ret[-1] == '')
699 del ret[-1]
698 del ret[-1]
700
699
701 if out_data:
700 if out_data:
702 ret.extend(out_data)
701 ret.extend(out_data)
703
702
704 # save the image files
703 # save the image files
705 if image_file is not None:
704 if image_file is not None:
706 self.save_image(image_file)
705 self.save_image(image_file)
707
706
708 return ret, image_directive
707 return ret, image_directive
709
708
710 def ensure_pyplot(self):
709 def ensure_pyplot(self):
711 """
710 """
712 Ensures that pyplot has been imported into the embedded IPython shell.
711 Ensures that pyplot has been imported into the embedded IPython shell.
713
712
714 Also, makes sure to set the backend appropriately if not set already.
713 Also, makes sure to set the backend appropriately if not set already.
715
714
716 """
715 """
717 # We are here if the @figure pseudo decorator was used. Thus, it's
716 # We are here if the @figure pseudo decorator was used. Thus, it's
718 # possible that we could be here even if python_mplbackend were set to
717 # possible that we could be here even if python_mplbackend were set to
719 # `None`. That's also strange and perhaps worthy of raising an
718 # `None`. That's also strange and perhaps worthy of raising an
720 # exception, but for now, we just set the backend to 'agg'.
719 # exception, but for now, we just set the backend to 'agg'.
721
720
722 if not self._pyplot_imported:
721 if not self._pyplot_imported:
723 if 'matplotlib.backends' not in sys.modules:
722 if 'matplotlib.backends' not in sys.modules:
724 # Then ipython_matplotlib was set to None but there was a
723 # Then ipython_matplotlib was set to None but there was a
725 # call to the @figure decorator (and ipython_execlines did
724 # call to the @figure decorator (and ipython_execlines did
726 # not set a backend).
725 # not set a backend).
727 #raise Exception("No backend was set, but @figure was used!")
726 #raise Exception("No backend was set, but @figure was used!")
728 import matplotlib
727 import matplotlib
729 matplotlib.use('agg')
728 matplotlib.use('agg')
730
729
731 # Always import pyplot into embedded shell.
730 # Always import pyplot into embedded shell.
732 self.process_input_line('import matplotlib.pyplot as plt',
731 self.process_input_line('import matplotlib.pyplot as plt',
733 store_history=False)
732 store_history=False)
734 self._pyplot_imported = True
733 self._pyplot_imported = True
735
734
736 def process_pure_python(self, content):
735 def process_pure_python(self, content):
737 """
736 """
738 content is a list of strings. it is unedited directive content
737 content is a list of strings. it is unedited directive content
739
738
740 This runs it line by line in the InteractiveShell, prepends
739 This runs it line by line in the InteractiveShell, prepends
741 prompts as needed capturing stderr and stdout, then returns
740 prompts as needed capturing stderr and stdout, then returns
742 the content as a list as if it were ipython code
741 the content as a list as if it were ipython code
743 """
742 """
744 output = []
743 output = []
745 savefig = False # keep up with this to clear figure
744 savefig = False # keep up with this to clear figure
746 multiline = False # to handle line continuation
745 multiline = False # to handle line continuation
747 multiline_start = None
746 multiline_start = None
748 fmtin = self.promptin
747 fmtin = self.promptin
749
748
750 ct = 0
749 ct = 0
751
750
752 for lineno, line in enumerate(content):
751 for lineno, line in enumerate(content):
753
752
754 line_stripped = line.strip()
753 line_stripped = line.strip()
755 if not len(line):
754 if not len(line):
756 output.append(line)
755 output.append(line)
757 continue
756 continue
758
757
759 # handle decorators
758 # handle decorators
760 if line_stripped.startswith('@'):
759 if line_stripped.startswith('@'):
761 output.extend([line])
760 output.extend([line])
762 if 'savefig' in line:
761 if 'savefig' in line:
763 savefig = True # and need to clear figure
762 savefig = True # and need to clear figure
764 continue
763 continue
765
764
766 # handle comments
765 # handle comments
767 if line_stripped.startswith('#'):
766 if line_stripped.startswith('#'):
768 output.extend([line])
767 output.extend([line])
769 continue
768 continue
770
769
771 # deal with lines checking for multiline
770 # deal with lines checking for multiline
772 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
771 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
773 if not multiline:
772 if not multiline:
774 modified = u"%s %s" % (fmtin % ct, line_stripped)
773 modified = u"%s %s" % (fmtin % ct, line_stripped)
775 output.append(modified)
774 output.append(modified)
776 ct += 1
775 ct += 1
777 try:
776 try:
778 ast.parse(line_stripped)
777 ast.parse(line_stripped)
779 output.append(u'')
778 output.append(u'')
780 except Exception: # on a multiline
779 except Exception: # on a multiline
781 multiline = True
780 multiline = True
782 multiline_start = lineno
781 multiline_start = lineno
783 else: # still on a multiline
782 else: # still on a multiline
784 modified = u'%s %s' % (continuation, line)
783 modified = u'%s %s' % (continuation, line)
785 output.append(modified)
784 output.append(modified)
786
785
787 # if the next line is indented, it should be part of multiline
786 # if the next line is indented, it should be part of multiline
788 if len(content) > lineno + 1:
787 if len(content) > lineno + 1:
789 nextline = content[lineno + 1]
788 nextline = content[lineno + 1]
790 if len(nextline) - len(nextline.lstrip()) > 3:
789 if len(nextline) - len(nextline.lstrip()) > 3:
791 continue
790 continue
792 try:
791 try:
793 mod = ast.parse(
792 mod = ast.parse(
794 '\n'.join(content[multiline_start:lineno+1]))
793 '\n'.join(content[multiline_start:lineno+1]))
795 if isinstance(mod.body[0], ast.FunctionDef):
794 if isinstance(mod.body[0], ast.FunctionDef):
796 # check to see if we have the whole function
795 # check to see if we have the whole function
797 for element in mod.body[0].body:
796 for element in mod.body[0].body:
798 if isinstance(element, ast.Return):
797 if isinstance(element, ast.Return):
799 multiline = False
798 multiline = False
800 else:
799 else:
801 output.append(u'')
800 output.append(u'')
802 multiline = False
801 multiline = False
803 except Exception:
802 except Exception:
804 pass
803 pass
805
804
806 if savefig: # clear figure if plotted
805 if savefig: # clear figure if plotted
807 self.ensure_pyplot()
806 self.ensure_pyplot()
808 self.process_input_line('plt.clf()', store_history=False)
807 self.process_input_line('plt.clf()', store_history=False)
809 self.clear_cout()
808 self.clear_cout()
810 savefig = False
809 savefig = False
811
810
812 return output
811 return output
813
812
814 def custom_doctest(self, decorator, input_lines, found, submitted):
813 def custom_doctest(self, decorator, input_lines, found, submitted):
815 """
814 """
816 Perform a specialized doctest.
815 Perform a specialized doctest.
817
816
818 """
817 """
819 from .custom_doctests import doctests
818 from .custom_doctests import doctests
820
819
821 args = decorator.split()
820 args = decorator.split()
822 doctest_type = args[1]
821 doctest_type = args[1]
823 if doctest_type in doctests:
822 if doctest_type in doctests:
824 doctests[doctest_type](self, args, input_lines, found, submitted)
823 doctests[doctest_type](self, args, input_lines, found, submitted)
825 else:
824 else:
826 e = "Invalid option to @doctest: {0}".format(doctest_type)
825 e = "Invalid option to @doctest: {0}".format(doctest_type)
827 raise Exception(e)
826 raise Exception(e)
828
827
829
828
830 class IPythonDirective(Directive):
829 class IPythonDirective(Directive):
831
830
832 has_content = True
831 has_content = True
833 required_arguments = 0
832 required_arguments = 0
834 optional_arguments = 4 # python, suppress, verbatim, doctest
833 optional_arguments = 4 # python, suppress, verbatim, doctest
835 final_argumuent_whitespace = True
834 final_argumuent_whitespace = True
836 option_spec = { 'python': directives.unchanged,
835 option_spec = { 'python': directives.unchanged,
837 'suppress' : directives.flag,
836 'suppress' : directives.flag,
838 'verbatim' : directives.flag,
837 'verbatim' : directives.flag,
839 'doctest' : directives.flag,
838 'doctest' : directives.flag,
840 'okexcept': directives.flag,
839 'okexcept': directives.flag,
841 'okwarning': directives.flag
840 'okwarning': directives.flag
842 }
841 }
843
842
844 shell = None
843 shell = None
845
844
846 seen_docs = set()
845 seen_docs = set()
847
846
848 def get_config_options(self):
847 def get_config_options(self):
849 # contains sphinx configuration variables
848 # contains sphinx configuration variables
850 config = self.state.document.settings.env.config
849 config = self.state.document.settings.env.config
851
850
852 # get config variables to set figure output directory
851 # get config variables to set figure output directory
853 outdir = self.state.document.settings.env.app.outdir
852 outdir = self.state.document.settings.env.app.outdir
854 savefig_dir = config.ipython_savefig_dir
853 savefig_dir = config.ipython_savefig_dir
855 source_dir = os.path.dirname(self.state.document.current_source)
854 source_dir = os.path.dirname(self.state.document.current_source)
856 if savefig_dir is None:
855 if savefig_dir is None:
857 savefig_dir = config.html_static_path or '_static'
856 savefig_dir = config.html_static_path or '_static'
858 if isinstance(savefig_dir, list):
857 if isinstance(savefig_dir, list):
859 savefig_dir = os.path.join(*savefig_dir)
858 savefig_dir = os.path.join(*savefig_dir)
860 savefig_dir = os.path.join(outdir, savefig_dir)
859 savefig_dir = os.path.join(outdir, savefig_dir)
861
860
862 # get regex and prompt stuff
861 # get regex and prompt stuff
863 rgxin = config.ipython_rgxin
862 rgxin = config.ipython_rgxin
864 rgxout = config.ipython_rgxout
863 rgxout = config.ipython_rgxout
865 promptin = config.ipython_promptin
864 promptin = config.ipython_promptin
866 promptout = config.ipython_promptout
865 promptout = config.ipython_promptout
867 mplbackend = config.ipython_mplbackend
866 mplbackend = config.ipython_mplbackend
868 exec_lines = config.ipython_execlines
867 exec_lines = config.ipython_execlines
869 hold_count = config.ipython_holdcount
868 hold_count = config.ipython_holdcount
870
869
871 return (savefig_dir, source_dir, rgxin, rgxout,
870 return (savefig_dir, source_dir, rgxin, rgxout,
872 promptin, promptout, mplbackend, exec_lines, hold_count)
871 promptin, promptout, mplbackend, exec_lines, hold_count)
873
872
874 def setup(self):
873 def setup(self):
875 # Get configuration values.
874 # Get configuration values.
876 (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout,
875 (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout,
877 mplbackend, exec_lines, hold_count) = self.get_config_options()
876 mplbackend, exec_lines, hold_count) = self.get_config_options()
878
877
879 if self.shell is None:
878 if self.shell is None:
880 # We will be here many times. However, when the
879 # We will be here many times. However, when the
881 # EmbeddedSphinxShell is created, its interactive shell member
880 # EmbeddedSphinxShell is created, its interactive shell member
882 # is the same for each instance.
881 # is the same for each instance.
883
882
884 if mplbackend and 'matplotlib.backends' not in sys.modules:
883 if mplbackend and 'matplotlib.backends' not in sys.modules:
885 import matplotlib
884 import matplotlib
886 matplotlib.use(mplbackend)
885 matplotlib.use(mplbackend)
887
886
888 # Must be called after (potentially) importing matplotlib and
887 # Must be called after (potentially) importing matplotlib and
889 # setting its backend since exec_lines might import pylab.
888 # setting its backend since exec_lines might import pylab.
890 self.shell = EmbeddedSphinxShell(exec_lines)
889 self.shell = EmbeddedSphinxShell(exec_lines)
891
890
892 # Store IPython directive to enable better error messages
891 # Store IPython directive to enable better error messages
893 self.shell.directive = self
892 self.shell.directive = self
894
893
895 # reset the execution count if we haven't processed this doc
894 # reset the execution count if we haven't processed this doc
896 #NOTE: this may be borked if there are multiple seen_doc tmp files
895 #NOTE: this may be borked if there are multiple seen_doc tmp files
897 #check time stamp?
896 #check time stamp?
898 if not self.state.document.current_source in self.seen_docs:
897 if not self.state.document.current_source in self.seen_docs:
899 self.shell.IP.history_manager.reset()
898 self.shell.IP.history_manager.reset()
900 self.shell.IP.execution_count = 1
899 self.shell.IP.execution_count = 1
901 self.seen_docs.add(self.state.document.current_source)
900 self.seen_docs.add(self.state.document.current_source)
902
901
903 # and attach to shell so we don't have to pass them around
902 # and attach to shell so we don't have to pass them around
904 self.shell.rgxin = rgxin
903 self.shell.rgxin = rgxin
905 self.shell.rgxout = rgxout
904 self.shell.rgxout = rgxout
906 self.shell.promptin = promptin
905 self.shell.promptin = promptin
907 self.shell.promptout = promptout
906 self.shell.promptout = promptout
908 self.shell.savefig_dir = savefig_dir
907 self.shell.savefig_dir = savefig_dir
909 self.shell.source_dir = source_dir
908 self.shell.source_dir = source_dir
910 self.shell.hold_count = hold_count
909 self.shell.hold_count = hold_count
911
910
912 # setup bookmark for saving figures directory
911 # setup bookmark for saving figures directory
913 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
912 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
914 store_history=False)
913 store_history=False)
915 self.shell.clear_cout()
914 self.shell.clear_cout()
916
915
917 return rgxin, rgxout, promptin, promptout
916 return rgxin, rgxout, promptin, promptout
918
917
919 def teardown(self):
918 def teardown(self):
920 # delete last bookmark
919 # delete last bookmark
921 self.shell.process_input_line('bookmark -d ipy_savedir',
920 self.shell.process_input_line('bookmark -d ipy_savedir',
922 store_history=False)
921 store_history=False)
923 self.shell.clear_cout()
922 self.shell.clear_cout()
924
923
925 def run(self):
924 def run(self):
926 debug = False
925 debug = False
927
926
928 #TODO, any reason block_parser can't be a method of embeddable shell
927 #TODO, any reason block_parser can't be a method of embeddable shell
929 # then we wouldn't have to carry these around
928 # then we wouldn't have to carry these around
930 rgxin, rgxout, promptin, promptout = self.setup()
929 rgxin, rgxout, promptin, promptout = self.setup()
931
930
932 options = self.options
931 options = self.options
933 self.shell.is_suppress = 'suppress' in options
932 self.shell.is_suppress = 'suppress' in options
934 self.shell.is_doctest = 'doctest' in options
933 self.shell.is_doctest = 'doctest' in options
935 self.shell.is_verbatim = 'verbatim' in options
934 self.shell.is_verbatim = 'verbatim' in options
936 self.shell.is_okexcept = 'okexcept' in options
935 self.shell.is_okexcept = 'okexcept' in options
937 self.shell.is_okwarning = 'okwarning' in options
936 self.shell.is_okwarning = 'okwarning' in options
938
937
939 # handle pure python code
938 # handle pure python code
940 if 'python' in self.arguments:
939 if 'python' in self.arguments:
941 content = self.content
940 content = self.content
942 self.content = self.shell.process_pure_python(content)
941 self.content = self.shell.process_pure_python(content)
943
942
944 # parts consists of all text within the ipython-block.
943 # parts consists of all text within the ipython-block.
945 # Each part is an input/output block.
944 # Each part is an input/output block.
946 parts = '\n'.join(self.content).split('\n\n')
945 parts = '\n'.join(self.content).split('\n\n')
947
946
948 lines = ['.. code-block:: ipython', '']
947 lines = ['.. code-block:: ipython', '']
949 figures = []
948 figures = []
950
949
951 for part in parts:
950 for part in parts:
952 block = block_parser(part, rgxin, rgxout, promptin, promptout)
951 block = block_parser(part, rgxin, rgxout, promptin, promptout)
953 if len(block):
952 if len(block):
954 rows, figure = self.shell.process_block(block)
953 rows, figure = self.shell.process_block(block)
955 for row in rows:
954 for row in rows:
956 lines.extend([' {0}'.format(line)
955 lines.extend([' {0}'.format(line)
957 for line in row.split('\n')])
956 for line in row.split('\n')])
958
957
959 if figure is not None:
958 if figure is not None:
960 figures.append(figure)
959 figures.append(figure)
961
960
962 for figure in figures:
961 for figure in figures:
963 lines.append('')
962 lines.append('')
964 lines.extend(figure.split('\n'))
963 lines.extend(figure.split('\n'))
965 lines.append('')
964 lines.append('')
966
965
967 if len(lines) > 2:
966 if len(lines) > 2:
968 if debug:
967 if debug:
969 print('\n'.join(lines))
968 print('\n'.join(lines))
970 else:
969 else:
971 # This has to do with input, not output. But if we comment
970 # This has to do with input, not output. But if we comment
972 # these lines out, then no IPython code will appear in the
971 # these lines out, then no IPython code will appear in the
973 # final output.
972 # final output.
974 self.state_machine.insert_input(
973 self.state_machine.insert_input(
975 lines, self.state_machine.input_lines.source(0))
974 lines, self.state_machine.input_lines.source(0))
976
975
977 # cleanup
976 # cleanup
978 self.teardown()
977 self.teardown()
979
978
980 return []
979 return []
981
980
982 # Enable as a proper Sphinx directive
981 # Enable as a proper Sphinx directive
983 def setup(app):
982 def setup(app):
984 setup.app = app
983 setup.app = app
985
984
986 app.add_directive('ipython', IPythonDirective)
985 app.add_directive('ipython', IPythonDirective)
987 app.add_config_value('ipython_savefig_dir', None, 'env')
986 app.add_config_value('ipython_savefig_dir', None, 'env')
988 app.add_config_value('ipython_rgxin',
987 app.add_config_value('ipython_rgxin',
989 re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env')
988 re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env')
990 app.add_config_value('ipython_rgxout',
989 app.add_config_value('ipython_rgxout',
991 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env')
990 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env')
992 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
991 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
993 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
992 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
994
993
995 # We could just let matplotlib pick whatever is specified as the default
994 # We could just let matplotlib pick whatever is specified as the default
996 # backend in the matplotlibrc file, but this would cause issues if the
995 # backend in the matplotlibrc file, but this would cause issues if the
997 # backend didn't work in headless environments. For this reason, 'agg'
996 # backend didn't work in headless environments. For this reason, 'agg'
998 # is a good default backend choice.
997 # is a good default backend choice.
999 app.add_config_value('ipython_mplbackend', 'agg', 'env')
998 app.add_config_value('ipython_mplbackend', 'agg', 'env')
1000
999
1001 # If the user sets this config value to `None`, then EmbeddedSphinxShell's
1000 # If the user sets this config value to `None`, then EmbeddedSphinxShell's
1002 # __init__ method will treat it as [].
1001 # __init__ method will treat it as [].
1003 execlines = ['import numpy as np', 'import matplotlib.pyplot as plt']
1002 execlines = ['import numpy as np', 'import matplotlib.pyplot as plt']
1004 app.add_config_value('ipython_execlines', execlines, 'env')
1003 app.add_config_value('ipython_execlines', execlines, 'env')
1005
1004
1006 app.add_config_value('ipython_holdcount', True, 'env')
1005 app.add_config_value('ipython_holdcount', True, 'env')
1007
1006
1008 metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
1007 metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
1009 return metadata
1008 return metadata
1010
1009
1011 # Simple smoke test, needs to be converted to a proper automatic test.
1010 # Simple smoke test, needs to be converted to a proper automatic test.
1012 def test():
1011 def test():
1013
1012
1014 examples = [
1013 examples = [
1015 r"""
1014 r"""
1016 In [9]: pwd
1015 In [9]: pwd
1017 Out[9]: '/home/jdhunter/py4science/book'
1016 Out[9]: '/home/jdhunter/py4science/book'
1018
1017
1019 In [10]: cd bookdata/
1018 In [10]: cd bookdata/
1020 /home/jdhunter/py4science/book/bookdata
1019 /home/jdhunter/py4science/book/bookdata
1021
1020
1022 In [2]: from pylab import *
1021 In [2]: from pylab import *
1023
1022
1024 In [2]: ion()
1023 In [2]: ion()
1025
1024
1026 In [3]: im = imread('stinkbug.png')
1025 In [3]: im = imread('stinkbug.png')
1027
1026
1028 @savefig mystinkbug.png width=4in
1027 @savefig mystinkbug.png width=4in
1029 In [4]: imshow(im)
1028 In [4]: imshow(im)
1030 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
1029 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
1031
1030
1032 """,
1031 """,
1033 r"""
1032 r"""
1034
1033
1035 In [1]: x = 'hello world'
1034 In [1]: x = 'hello world'
1036
1035
1037 # string methods can be
1036 # string methods can be
1038 # used to alter the string
1037 # used to alter the string
1039 @doctest
1038 @doctest
1040 In [2]: x.upper()
1039 In [2]: x.upper()
1041 Out[2]: 'HELLO WORLD'
1040 Out[2]: 'HELLO WORLD'
1042
1041
1043 @verbatim
1042 @verbatim
1044 In [3]: x.st<TAB>
1043 In [3]: x.st<TAB>
1045 x.startswith x.strip
1044 x.startswith x.strip
1046 """,
1045 """,
1047 r"""
1046 r"""
1048
1047
1049 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
1048 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
1050 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
1049 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
1051
1050
1052 In [131]: print url.split('&')
1051 In [131]: print url.split('&')
1053 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
1052 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
1054
1053
1055 In [60]: import urllib
1054 In [60]: import urllib
1056
1055
1057 """,
1056 """,
1058 r"""\
1057 r"""\
1059
1058
1060 In [133]: import numpy.random
1059 In [133]: import numpy.random
1061
1060
1062 @suppress
1061 @suppress
1063 In [134]: numpy.random.seed(2358)
1062 In [134]: numpy.random.seed(2358)
1064
1063
1065 @doctest
1064 @doctest
1066 In [135]: numpy.random.rand(10,2)
1065 In [135]: numpy.random.rand(10,2)
1067 Out[135]:
1066 Out[135]:
1068 array([[ 0.64524308, 0.59943846],
1067 array([[ 0.64524308, 0.59943846],
1069 [ 0.47102322, 0.8715456 ],
1068 [ 0.47102322, 0.8715456 ],
1070 [ 0.29370834, 0.74776844],
1069 [ 0.29370834, 0.74776844],
1071 [ 0.99539577, 0.1313423 ],
1070 [ 0.99539577, 0.1313423 ],
1072 [ 0.16250302, 0.21103583],
1071 [ 0.16250302, 0.21103583],
1073 [ 0.81626524, 0.1312433 ],
1072 [ 0.81626524, 0.1312433 ],
1074 [ 0.67338089, 0.72302393],
1073 [ 0.67338089, 0.72302393],
1075 [ 0.7566368 , 0.07033696],
1074 [ 0.7566368 , 0.07033696],
1076 [ 0.22591016, 0.77731835],
1075 [ 0.22591016, 0.77731835],
1077 [ 0.0072729 , 0.34273127]])
1076 [ 0.0072729 , 0.34273127]])
1078
1077
1079 """,
1078 """,
1080
1079
1081 r"""
1080 r"""
1082 In [106]: print x
1081 In [106]: print x
1083 jdh
1082 jdh
1084
1083
1085 In [109]: for i in range(10):
1084 In [109]: for i in range(10):
1086 .....: print i
1085 .....: print i
1087 .....:
1086 .....:
1088 .....:
1087 .....:
1089 0
1088 0
1090 1
1089 1
1091 2
1090 2
1092 3
1091 3
1093 4
1092 4
1094 5
1093 5
1095 6
1094 6
1096 7
1095 7
1097 8
1096 8
1098 9
1097 9
1099 """,
1098 """,
1100
1099
1101 r"""
1100 r"""
1102
1101
1103 In [144]: from pylab import *
1102 In [144]: from pylab import *
1104
1103
1105 In [145]: ion()
1104 In [145]: ion()
1106
1105
1107 # use a semicolon to suppress the output
1106 # use a semicolon to suppress the output
1108 @savefig test_hist.png width=4in
1107 @savefig test_hist.png width=4in
1109 In [151]: hist(np.random.randn(10000), 100);
1108 In [151]: hist(np.random.randn(10000), 100);
1110
1109
1111
1110
1112 @savefig test_plot.png width=4in
1111 @savefig test_plot.png width=4in
1113 In [151]: plot(np.random.randn(10000), 'o');
1112 In [151]: plot(np.random.randn(10000), 'o');
1114 """,
1113 """,
1115
1114
1116 r"""
1115 r"""
1117 # use a semicolon to suppress the output
1116 # use a semicolon to suppress the output
1118 In [151]: plt.clf()
1117 In [151]: plt.clf()
1119
1118
1120 @savefig plot_simple.png width=4in
1119 @savefig plot_simple.png width=4in
1121 In [151]: plot([1,2,3])
1120 In [151]: plot([1,2,3])
1122
1121
1123 @savefig hist_simple.png width=4in
1122 @savefig hist_simple.png width=4in
1124 In [151]: hist(np.random.randn(10000), 100);
1123 In [151]: hist(np.random.randn(10000), 100);
1125
1124
1126 """,
1125 """,
1127 r"""
1126 r"""
1128 # update the current fig
1127 # update the current fig
1129 In [151]: ylabel('number')
1128 In [151]: ylabel('number')
1130
1129
1131 In [152]: title('normal distribution')
1130 In [152]: title('normal distribution')
1132
1131
1133
1132
1134 @savefig hist_with_text.png
1133 @savefig hist_with_text.png
1135 In [153]: grid(True)
1134 In [153]: grid(True)
1136
1135
1137 @doctest float
1136 @doctest float
1138 In [154]: 0.1 + 0.2
1137 In [154]: 0.1 + 0.2
1139 Out[154]: 0.3
1138 Out[154]: 0.3
1140
1139
1141 @doctest float
1140 @doctest float
1142 In [155]: np.arange(16).reshape(4,4)
1141 In [155]: np.arange(16).reshape(4,4)
1143 Out[155]:
1142 Out[155]:
1144 array([[ 0, 1, 2, 3],
1143 array([[ 0, 1, 2, 3],
1145 [ 4, 5, 6, 7],
1144 [ 4, 5, 6, 7],
1146 [ 8, 9, 10, 11],
1145 [ 8, 9, 10, 11],
1147 [12, 13, 14, 15]])
1146 [12, 13, 14, 15]])
1148
1147
1149 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
1148 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
1150
1149
1151 In [2]: x[0,0] = np.inf
1150 In [2]: x[0,0] = np.inf
1152
1151
1153 In [3]: x[0,1] = np.nan
1152 In [3]: x[0,1] = np.nan
1154
1153
1155 @doctest float
1154 @doctest float
1156 In [4]: x
1155 In [4]: x
1157 Out[4]:
1156 Out[4]:
1158 array([[ inf, nan, 2., 3.],
1157 array([[ inf, nan, 2., 3.],
1159 [ 4., 5., 6., 7.],
1158 [ 4., 5., 6., 7.],
1160 [ 8., 9., 10., 11.],
1159 [ 8., 9., 10., 11.],
1161 [ 12., 13., 14., 15.]])
1160 [ 12., 13., 14., 15.]])
1162
1161
1163
1162
1164 """,
1163 """,
1165 ]
1164 ]
1166 # skip local-file depending first example:
1165 # skip local-file depending first example:
1167 examples = examples[1:]
1166 examples = examples[1:]
1168
1167
1169 #ipython_directive.DEBUG = True # dbg
1168 #ipython_directive.DEBUG = True # dbg
1170 #options = dict(suppress=True) # dbg
1169 #options = dict(suppress=True) # dbg
1171 options = dict()
1170 options = dict()
1172 for example in examples:
1171 for example in examples:
1173 content = example.split('\n')
1172 content = example.split('\n')
1174 IPythonDirective('debug', arguments=None, options=options,
1173 IPythonDirective('debug', arguments=None, options=options,
1175 content=content, lineno=0,
1174 content=content, lineno=0,
1176 content_offset=None, block_text=None,
1175 content_offset=None, block_text=None,
1177 state=None, state_machine=None,
1176 state=None, state_machine=None,
1178 )
1177 )
1179
1178
1180 # Run test suite as a script
1179 # Run test suite as a script
1181 if __name__=='__main__':
1180 if __name__=='__main__':
1182 if not os.path.isdir('_static'):
1181 if not os.path.isdir('_static'):
1183 os.mkdir('_static')
1182 os.mkdir('_static')
1184 test()
1183 test()
1185 print('All OK? Check figures in _static/')
1184 print('All OK? Check figures in _static/')
@@ -1,479 +1,484 b''
1 """IPython terminal interface using prompt_toolkit"""
1 """IPython terminal interface using prompt_toolkit"""
2 from __future__ import print_function
2 from __future__ import print_function
3
3
4 import os
4 import os
5 import sys
5 import sys
6 import warnings
6 from warnings import warn
7 from warnings import warn
7
8
8 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
9 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
10 from IPython.utils import io
9 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
11 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
10 from IPython.utils.terminal import toggle_set_term_title, set_term_title
12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
11 from IPython.utils.process import abbrev_cwd
13 from IPython.utils.process import abbrev_cwd
12 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum
14 from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum
13
15
14 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
16 from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
15 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
17 from prompt_toolkit.filters import (HasFocus, Condition, IsDone)
16 from prompt_toolkit.history import InMemoryHistory
18 from prompt_toolkit.history import InMemoryHistory
17 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
19 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output
18 from prompt_toolkit.interface import CommandLineInterface
20 from prompt_toolkit.interface import CommandLineInterface
19 from prompt_toolkit.key_binding.manager import KeyBindingManager
21 from prompt_toolkit.key_binding.manager import KeyBindingManager
20 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
22 from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
21 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
23 from prompt_toolkit.styles import PygmentsStyle, DynamicStyle
22
24
23 from pygments.styles import get_style_by_name, get_all_styles
25 from pygments.styles import get_style_by_name, get_all_styles
24 from pygments.token import Token
26 from pygments.token import Token
25
27
26 from .debugger import TerminalPdb, Pdb
28 from .debugger import TerminalPdb, Pdb
27 from .magics import TerminalMagics
29 from .magics import TerminalMagics
28 from .pt_inputhooks import get_inputhook_func
30 from .pt_inputhooks import get_inputhook_func
29 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
31 from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook
30 from .ptutils import IPythonPTCompleter, IPythonPTLexer
32 from .ptutils import IPythonPTCompleter, IPythonPTLexer
31 from .shortcuts import register_ipython_shortcuts
33 from .shortcuts import register_ipython_shortcuts
32
34
33 DISPLAY_BANNER_DEPRECATED = object()
35 DISPLAY_BANNER_DEPRECATED = object()
34
36
35
37
36 from pygments.style import Style
38 from pygments.style import Style
37
39
38 class _NoStyle(Style): pass
40 class _NoStyle(Style): pass
39
41
40
42
41
43
42 _style_overrides_light_bg = {
44 _style_overrides_light_bg = {
43 Token.Prompt: '#0000ff',
45 Token.Prompt: '#0000ff',
44 Token.PromptNum: '#0000ee bold',
46 Token.PromptNum: '#0000ee bold',
45 Token.OutPrompt: '#cc0000',
47 Token.OutPrompt: '#cc0000',
46 Token.OutPromptNum: '#bb0000 bold',
48 Token.OutPromptNum: '#bb0000 bold',
47 }
49 }
48
50
49 _style_overrides_linux = {
51 _style_overrides_linux = {
50 Token.Prompt: '#00cc00',
52 Token.Prompt: '#00cc00',
51 Token.PromptNum: '#00bb00 bold',
53 Token.PromptNum: '#00bb00 bold',
52 Token.OutPrompt: '#cc0000',
54 Token.OutPrompt: '#cc0000',
53 Token.OutPromptNum: '#bb0000 bold',
55 Token.OutPromptNum: '#bb0000 bold',
54 }
56 }
55
57
56
58
57
59
58 def get_default_editor():
60 def get_default_editor():
59 try:
61 try:
60 ed = os.environ['EDITOR']
62 ed = os.environ['EDITOR']
61 if not PY3:
63 if not PY3:
62 ed = ed.decode()
64 ed = ed.decode()
63 return ed
65 return ed
64 except KeyError:
66 except KeyError:
65 pass
67 pass
66 except UnicodeError:
68 except UnicodeError:
67 warn("$EDITOR environment variable is not pure ASCII. Using platform "
69 warn("$EDITOR environment variable is not pure ASCII. Using platform "
68 "default editor.")
70 "default editor.")
69
71
70 if os.name == 'posix':
72 if os.name == 'posix':
71 return 'vi' # the only one guaranteed to be there!
73 return 'vi' # the only one guaranteed to be there!
72 else:
74 else:
73 return 'notepad' # same in Windows!
75 return 'notepad' # same in Windows!
74
76
75
77
76 if sys.stdin and sys.stdout and sys.stderr:
78 if sys.stdin and sys.stdout and sys.stderr:
77 _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty())
79 _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty())
78 else:
80 else:
79 _is_tty = False
81 _is_tty = False
80
82
81
83
82 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
84 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
83
85
84 class TerminalInteractiveShell(InteractiveShell):
86 class TerminalInteractiveShell(InteractiveShell):
85 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
87 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
86 'to reserve for the completion menu'
88 'to reserve for the completion menu'
87 ).tag(config=True)
89 ).tag(config=True)
88
90
89 def _space_for_menu_changed(self, old, new):
91 def _space_for_menu_changed(self, old, new):
90 self._update_layout()
92 self._update_layout()
91
93
92 pt_cli = None
94 pt_cli = None
93 debugger_history = None
95 debugger_history = None
94 _pt_app = None
96 _pt_app = None
95
97
96 simple_prompt = Bool(_use_simple_prompt,
98 simple_prompt = Bool(_use_simple_prompt,
97 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
99 help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors.
98
100
99 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
101 Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are:
100 IPython own testing machinery, and emacs inferior-shell integration through elpy.
102 IPython own testing machinery, and emacs inferior-shell integration through elpy.
101
103
102 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
104 This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT`
103 environment variable is set, or the current terminal is not a tty.
105 environment variable is set, or the current terminal is not a tty.
104
106
105 """
107 """
106 ).tag(config=True)
108 ).tag(config=True)
107
109
108 @property
110 @property
109 def debugger_cls(self):
111 def debugger_cls(self):
110 return Pdb if self.simple_prompt else TerminalPdb
112 return Pdb if self.simple_prompt else TerminalPdb
111
113
112 confirm_exit = Bool(True,
114 confirm_exit = Bool(True,
113 help="""
115 help="""
114 Set to confirm when you try to exit IPython with an EOF (Control-D
116 Set to confirm when you try to exit IPython with an EOF (Control-D
115 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
117 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
116 you can force a direct exit without any confirmation.""",
118 you can force a direct exit without any confirmation.""",
117 ).tag(config=True)
119 ).tag(config=True)
118
120
119 editing_mode = Unicode('emacs',
121 editing_mode = Unicode('emacs',
120 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
122 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
121 ).tag(config=True)
123 ).tag(config=True)
122
124
123 mouse_support = Bool(False,
125 mouse_support = Bool(False,
124 help="Enable mouse support in the prompt"
126 help="Enable mouse support in the prompt"
125 ).tag(config=True)
127 ).tag(config=True)
126
128
127 highlighting_style = Unicode('legacy',
129 highlighting_style = Unicode('legacy',
128 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
130 help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles())
129 ).tag(config=True)
131 ).tag(config=True)
130
132
131
133
132 @observe('highlighting_style')
134 @observe('highlighting_style')
133 @observe('colors')
135 @observe('colors')
134 def _highlighting_style_changed(self, change):
136 def _highlighting_style_changed(self, change):
135 self.refresh_style()
137 self.refresh_style()
136
138
137 def refresh_style(self):
139 def refresh_style(self):
138 self._style = self._make_style_from_name(self.highlighting_style)
140 self._style = self._make_style_from_name(self.highlighting_style)
139
141
140
142
141 highlighting_style_overrides = Dict(
143 highlighting_style_overrides = Dict(
142 help="Override highlighting format for specific tokens"
144 help="Override highlighting format for specific tokens"
143 ).tag(config=True)
145 ).tag(config=True)
144
146
145 true_color = Bool(False,
147 true_color = Bool(False,
146 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
148 help=("Use 24bit colors instead of 256 colors in prompt highlighting. "
147 "If your terminal supports true color, the following command "
149 "If your terminal supports true color, the following command "
148 "should print 'TRUECOLOR' in orange: "
150 "should print 'TRUECOLOR' in orange: "
149 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
151 "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"")
150 ).tag(config=True)
152 ).tag(config=True)
151
153
152 editor = Unicode(get_default_editor(),
154 editor = Unicode(get_default_editor(),
153 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
155 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
154 ).tag(config=True)
156 ).tag(config=True)
155
157
156 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
158 prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True)
157
159
158 prompts = Instance(Prompts)
160 prompts = Instance(Prompts)
159
161
160 @default('prompts')
162 @default('prompts')
161 def _prompts_default(self):
163 def _prompts_default(self):
162 return self.prompts_class(self)
164 return self.prompts_class(self)
163
165
164 @observe('prompts')
166 @observe('prompts')
165 def _(self, change):
167 def _(self, change):
166 self._update_layout()
168 self._update_layout()
167
169
168 @default('displayhook_class')
170 @default('displayhook_class')
169 def _displayhook_class_default(self):
171 def _displayhook_class_default(self):
170 return RichPromptDisplayHook
172 return RichPromptDisplayHook
171
173
172 term_title = Bool(True,
174 term_title = Bool(True,
173 help="Automatically set the terminal title"
175 help="Automatically set the terminal title"
174 ).tag(config=True)
176 ).tag(config=True)
175
177
176 display_completions = Enum(('column', 'multicolumn','readlinelike'),
178 display_completions = Enum(('column', 'multicolumn','readlinelike'),
177 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
179 help= ( "Options for displaying tab completions, 'column', 'multicolumn', and "
178 "'readlinelike'. These options are for `prompt_toolkit`, see "
180 "'readlinelike'. These options are for `prompt_toolkit`, see "
179 "`prompt_toolkit` documentation for more information."
181 "`prompt_toolkit` documentation for more information."
180 ),
182 ),
181 default_value='multicolumn').tag(config=True)
183 default_value='multicolumn').tag(config=True)
182
184
183 highlight_matching_brackets = Bool(True,
185 highlight_matching_brackets = Bool(True,
184 help="Highlight matching brackets .",
186 help="Highlight matching brackets .",
185 ).tag(config=True)
187 ).tag(config=True)
186
188
187 @observe('term_title')
189 @observe('term_title')
188 def init_term_title(self, change=None):
190 def init_term_title(self, change=None):
189 # Enable or disable the terminal title.
191 # Enable or disable the terminal title.
190 if self.term_title:
192 if self.term_title:
191 toggle_set_term_title(True)
193 toggle_set_term_title(True)
192 set_term_title('IPython: ' + abbrev_cwd())
194 set_term_title('IPython: ' + abbrev_cwd())
193 else:
195 else:
194 toggle_set_term_title(False)
196 toggle_set_term_title(False)
195
197
196 def init_display_formatter(self):
198 def init_display_formatter(self):
197 super(TerminalInteractiveShell, self).init_display_formatter()
199 super(TerminalInteractiveShell, self).init_display_formatter()
198 # terminal only supports plain text
200 # terminal only supports plain text
199 self.display_formatter.active_types = ['text/plain']
201 self.display_formatter.active_types = ['text/plain']
200
202
201 def init_prompt_toolkit_cli(self):
203 def init_prompt_toolkit_cli(self):
202 if self.simple_prompt:
204 if self.simple_prompt:
203 # Fall back to plain non-interactive output for tests.
205 # Fall back to plain non-interactive output for tests.
204 # This is very limited, and only accepts a single line.
206 # This is very limited, and only accepts a single line.
205 def prompt():
207 def prompt():
206 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
208 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
207 self.prompt_for_code = prompt
209 self.prompt_for_code = prompt
208 return
210 return
209
211
210 # Set up keyboard shortcuts
212 # Set up keyboard shortcuts
211 kbmanager = KeyBindingManager.for_prompt()
213 kbmanager = KeyBindingManager.for_prompt()
212 register_ipython_shortcuts(kbmanager.registry, self)
214 register_ipython_shortcuts(kbmanager.registry, self)
213
215
214 # Pre-populate history from IPython's history database
216 # Pre-populate history from IPython's history database
215 history = InMemoryHistory()
217 history = InMemoryHistory()
216 last_cell = u""
218 last_cell = u""
217 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
219 for __, ___, cell in self.history_manager.get_tail(self.history_load_length,
218 include_latest=True):
220 include_latest=True):
219 # Ignore blank lines and consecutive duplicates
221 # Ignore blank lines and consecutive duplicates
220 cell = cell.rstrip()
222 cell = cell.rstrip()
221 if cell and (cell != last_cell):
223 if cell and (cell != last_cell):
222 history.append(cell)
224 history.append(cell)
223
225
224 self._style = self._make_style_from_name(self.highlighting_style)
226 self._style = self._make_style_from_name(self.highlighting_style)
225 style = DynamicStyle(lambda: self._style)
227 style = DynamicStyle(lambda: self._style)
226
228
227 editing_mode = getattr(EditingMode, self.editing_mode.upper())
229 editing_mode = getattr(EditingMode, self.editing_mode.upper())
228
230
229 self._pt_app = create_prompt_application(
231 self._pt_app = create_prompt_application(
230 editing_mode=editing_mode,
232 editing_mode=editing_mode,
231 key_bindings_registry=kbmanager.registry,
233 key_bindings_registry=kbmanager.registry,
232 history=history,
234 history=history,
233 completer=IPythonPTCompleter(self.Completer),
235 completer=IPythonPTCompleter(self.Completer),
234 enable_history_search=True,
236 enable_history_search=True,
235 style=style,
237 style=style,
236 mouse_support=self.mouse_support,
238 mouse_support=self.mouse_support,
237 **self._layout_options()
239 **self._layout_options()
238 )
240 )
239 self._eventloop = create_eventloop(self.inputhook)
241 self._eventloop = create_eventloop(self.inputhook)
240 self.pt_cli = CommandLineInterface(
242 self.pt_cli = CommandLineInterface(
241 self._pt_app, eventloop=self._eventloop,
243 self._pt_app, eventloop=self._eventloop,
242 output=create_output(true_color=self.true_color))
244 output=create_output(true_color=self.true_color))
243
245
244 def _make_style_from_name(self, name):
246 def _make_style_from_name(self, name):
245 """
247 """
246 Small wrapper that make an IPython compatible style from a style name
248 Small wrapper that make an IPython compatible style from a style name
247
249
248 We need that to add style for prompt ... etc.
250 We need that to add style for prompt ... etc.
249 """
251 """
250 style_overrides = {}
252 style_overrides = {}
251 if name == 'legacy':
253 if name == 'legacy':
252 legacy = self.colors.lower()
254 legacy = self.colors.lower()
253 if legacy == 'linux':
255 if legacy == 'linux':
254 style_cls = get_style_by_name('monokai')
256 style_cls = get_style_by_name('monokai')
255 style_overrides = _style_overrides_linux
257 style_overrides = _style_overrides_linux
256 elif legacy == 'lightbg':
258 elif legacy == 'lightbg':
257 style_overrides = _style_overrides_light_bg
259 style_overrides = _style_overrides_light_bg
258 style_cls = get_style_by_name('pastie')
260 style_cls = get_style_by_name('pastie')
259 elif legacy == 'neutral':
261 elif legacy == 'neutral':
260 # The default theme needs to be visible on both a dark background
262 # The default theme needs to be visible on both a dark background
261 # and a light background, because we can't tell what the terminal
263 # and a light background, because we can't tell what the terminal
262 # looks like. These tweaks to the default theme help with that.
264 # looks like. These tweaks to the default theme help with that.
263 style_cls = get_style_by_name('default')
265 style_cls = get_style_by_name('default')
264 style_overrides.update({
266 style_overrides.update({
265 Token.Number: '#007700',
267 Token.Number: '#007700',
266 Token.Operator: 'noinherit',
268 Token.Operator: 'noinherit',
267 Token.String: '#BB6622',
269 Token.String: '#BB6622',
268 Token.Name.Function: '#2080D0',
270 Token.Name.Function: '#2080D0',
269 Token.Name.Class: 'bold #2080D0',
271 Token.Name.Class: 'bold #2080D0',
270 Token.Name.Namespace: 'bold #2080D0',
272 Token.Name.Namespace: 'bold #2080D0',
271 Token.Prompt: '#009900',
273 Token.Prompt: '#009900',
272 Token.PromptNum: '#00ff00 bold',
274 Token.PromptNum: '#00ff00 bold',
273 Token.OutPrompt: '#990000',
275 Token.OutPrompt: '#990000',
274 Token.OutPromptNum: '#ff0000 bold',
276 Token.OutPromptNum: '#ff0000 bold',
275 })
277 })
276 elif legacy =='nocolor':
278 elif legacy =='nocolor':
277 style_cls=_NoStyle
279 style_cls=_NoStyle
278 style_overrides = {}
280 style_overrides = {}
279 else :
281 else :
280 raise ValueError('Got unknown colors: ', legacy)
282 raise ValueError('Got unknown colors: ', legacy)
281 else :
283 else :
282 style_cls = get_style_by_name(name)
284 style_cls = get_style_by_name(name)
283 style_overrides = {
285 style_overrides = {
284 Token.Prompt: '#009900',
286 Token.Prompt: '#009900',
285 Token.PromptNum: '#00ff00 bold',
287 Token.PromptNum: '#00ff00 bold',
286 Token.OutPrompt: '#990000',
288 Token.OutPrompt: '#990000',
287 Token.OutPromptNum: '#ff0000 bold',
289 Token.OutPromptNum: '#ff0000 bold',
288 }
290 }
289 style_overrides.update(self.highlighting_style_overrides)
291 style_overrides.update(self.highlighting_style_overrides)
290 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
292 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
291 style_dict=style_overrides)
293 style_dict=style_overrides)
292
294
293 return style
295 return style
294
296
295 def _layout_options(self):
297 def _layout_options(self):
296 """
298 """
297 Return the current layout option for the current Terminal InteractiveShell
299 Return the current layout option for the current Terminal InteractiveShell
298 """
300 """
299 return {
301 return {
300 'lexer':IPythonPTLexer(),
302 'lexer':IPythonPTLexer(),
301 'reserve_space_for_menu':self.space_for_menu,
303 'reserve_space_for_menu':self.space_for_menu,
302 'get_prompt_tokens':self.prompts.in_prompt_tokens,
304 'get_prompt_tokens':self.prompts.in_prompt_tokens,
303 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
305 'get_continuation_tokens':self.prompts.continuation_prompt_tokens,
304 'multiline':True,
306 'multiline':True,
305 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
307 'display_completions_in_columns': (self.display_completions == 'multicolumn'),
306
308
307 # Highlight matching brackets, but only when this setting is
309 # Highlight matching brackets, but only when this setting is
308 # enabled, and only when the DEFAULT_BUFFER has the focus.
310 # enabled, and only when the DEFAULT_BUFFER has the focus.
309 'extra_input_processors': [ConditionalProcessor(
311 'extra_input_processors': [ConditionalProcessor(
310 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
312 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
311 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
313 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
312 Condition(lambda cli: self.highlight_matching_brackets))],
314 Condition(lambda cli: self.highlight_matching_brackets))],
313 }
315 }
314
316
315 def _update_layout(self):
317 def _update_layout(self):
316 """
318 """
317 Ask for a re computation of the application layout, if for example ,
319 Ask for a re computation of the application layout, if for example ,
318 some configuration options have changed.
320 some configuration options have changed.
319 """
321 """
320 if self._pt_app:
322 if self._pt_app:
321 self._pt_app.layout = create_prompt_layout(**self._layout_options())
323 self._pt_app.layout = create_prompt_layout(**self._layout_options())
322
324
323 def prompt_for_code(self):
325 def prompt_for_code(self):
324 document = self.pt_cli.run(
326 document = self.pt_cli.run(
325 pre_run=self.pre_prompt, reset_current_buffer=True)
327 pre_run=self.pre_prompt, reset_current_buffer=True)
326 return document.text
328 return document.text
327
329
328 def enable_win_unicode_console(self):
330 def enable_win_unicode_console(self):
329 import win_unicode_console
331 import win_unicode_console
330
332
331 if PY3:
333 if PY3:
332 win_unicode_console.enable()
334 win_unicode_console.enable()
333 else:
335 else:
334 # https://github.com/ipython/ipython/issues/9768
336 # https://github.com/ipython/ipython/issues/9768
335 from win_unicode_console.streams import (TextStreamWrapper,
337 from win_unicode_console.streams import (TextStreamWrapper,
336 stdout_text_transcoded, stderr_text_transcoded)
338 stdout_text_transcoded, stderr_text_transcoded)
337
339
338 class LenientStrStreamWrapper(TextStreamWrapper):
340 class LenientStrStreamWrapper(TextStreamWrapper):
339 def write(self, s):
341 def write(self, s):
340 if isinstance(s, bytes):
342 if isinstance(s, bytes):
341 s = s.decode(self.encoding, 'replace')
343 s = s.decode(self.encoding, 'replace')
342
344
343 self.base.write(s)
345 self.base.write(s)
344
346
345 stdout_text_str = LenientStrStreamWrapper(stdout_text_transcoded)
347 stdout_text_str = LenientStrStreamWrapper(stdout_text_transcoded)
346 stderr_text_str = LenientStrStreamWrapper(stderr_text_transcoded)
348 stderr_text_str = LenientStrStreamWrapper(stderr_text_transcoded)
347
349
348 win_unicode_console.enable(stdout=stdout_text_str,
350 win_unicode_console.enable(stdout=stdout_text_str,
349 stderr=stderr_text_str)
351 stderr=stderr_text_str)
350
352
351 def init_io(self):
353 def init_io(self):
352 if sys.platform not in {'win32', 'cli'}:
354 if sys.platform not in {'win32', 'cli'}:
353 return
355 return
354
356
355 self.enable_win_unicode_console()
357 self.enable_win_unicode_console()
356
358
357 import colorama
359 import colorama
358 colorama.init()
360 colorama.init()
359
361
360 # For some reason we make these wrappers around stdout/stderr.
362 # For some reason we make these wrappers around stdout/stderr.
361 # For now, we need to reset them so all output gets coloured.
363 # For now, we need to reset them so all output gets coloured.
362 # https://github.com/ipython/ipython/issues/8669
364 # https://github.com/ipython/ipython/issues/8669
363 from IPython.utils import io
365 # io.std* are deprecated, but don't show our own deprecation warnings
364 io.stdout = io.IOStream(sys.stdout)
366 # during initialization of the deprecated API.
365 io.stderr = io.IOStream(sys.stderr)
367 with warnings.catch_warnings():
368 warnings.simplefilter('ignore', DeprecationWarning)
369 io.stdout = io.IOStream(sys.stdout)
370 io.stderr = io.IOStream(sys.stderr)
366
371
367 def init_magics(self):
372 def init_magics(self):
368 super(TerminalInteractiveShell, self).init_magics()
373 super(TerminalInteractiveShell, self).init_magics()
369 self.register_magics(TerminalMagics)
374 self.register_magics(TerminalMagics)
370
375
371 def init_alias(self):
376 def init_alias(self):
372 # The parent class defines aliases that can be safely used with any
377 # The parent class defines aliases that can be safely used with any
373 # frontend.
378 # frontend.
374 super(TerminalInteractiveShell, self).init_alias()
379 super(TerminalInteractiveShell, self).init_alias()
375
380
376 # Now define aliases that only make sense on the terminal, because they
381 # Now define aliases that only make sense on the terminal, because they
377 # need direct access to the console in a way that we can't emulate in
382 # need direct access to the console in a way that we can't emulate in
378 # GUI or web frontend
383 # GUI or web frontend
379 if os.name == 'posix':
384 if os.name == 'posix':
380 for cmd in ['clear', 'more', 'less', 'man']:
385 for cmd in ['clear', 'more', 'less', 'man']:
381 self.alias_manager.soft_define_alias(cmd, cmd)
386 self.alias_manager.soft_define_alias(cmd, cmd)
382
387
383
388
384 def __init__(self, *args, **kwargs):
389 def __init__(self, *args, **kwargs):
385 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
390 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
386 self.init_prompt_toolkit_cli()
391 self.init_prompt_toolkit_cli()
387 self.init_term_title()
392 self.init_term_title()
388 self.keep_running = True
393 self.keep_running = True
389
394
390 self.debugger_history = InMemoryHistory()
395 self.debugger_history = InMemoryHistory()
391
396
392 def ask_exit(self):
397 def ask_exit(self):
393 self.keep_running = False
398 self.keep_running = False
394
399
395 rl_next_input = None
400 rl_next_input = None
396
401
397 def pre_prompt(self):
402 def pre_prompt(self):
398 if self.rl_next_input:
403 if self.rl_next_input:
399 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
404 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
400 self.rl_next_input = None
405 self.rl_next_input = None
401
406
402 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
407 def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED):
403
408
404 if display_banner is not DISPLAY_BANNER_DEPRECATED:
409 if display_banner is not DISPLAY_BANNER_DEPRECATED:
405 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
410 warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
406
411
407 while self.keep_running:
412 while self.keep_running:
408 print(self.separate_in, end='')
413 print(self.separate_in, end='')
409
414
410 try:
415 try:
411 code = self.prompt_for_code()
416 code = self.prompt_for_code()
412 except EOFError:
417 except EOFError:
413 if (not self.confirm_exit) \
418 if (not self.confirm_exit) \
414 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
419 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
415 self.ask_exit()
420 self.ask_exit()
416
421
417 else:
422 else:
418 if code:
423 if code:
419 self.run_cell(code, store_history=True)
424 self.run_cell(code, store_history=True)
420
425
421 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
426 def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED):
422 # An extra layer of protection in case someone mashing Ctrl-C breaks
427 # An extra layer of protection in case someone mashing Ctrl-C breaks
423 # out of our internal code.
428 # out of our internal code.
424 if display_banner is not DISPLAY_BANNER_DEPRECATED:
429 if display_banner is not DISPLAY_BANNER_DEPRECATED:
425 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
430 warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2)
426 while True:
431 while True:
427 try:
432 try:
428 self.interact()
433 self.interact()
429 break
434 break
430 except KeyboardInterrupt:
435 except KeyboardInterrupt:
431 print("\nKeyboardInterrupt escaped interact()\n")
436 print("\nKeyboardInterrupt escaped interact()\n")
432
437
433 if hasattr(self, '_eventloop'):
438 if hasattr(self, '_eventloop'):
434 self._eventloop.close()
439 self._eventloop.close()
435
440
436 _inputhook = None
441 _inputhook = None
437 def inputhook(self, context):
442 def inputhook(self, context):
438 if self._inputhook is not None:
443 if self._inputhook is not None:
439 self._inputhook(context)
444 self._inputhook(context)
440
445
441 def enable_gui(self, gui=None):
446 def enable_gui(self, gui=None):
442 if gui:
447 if gui:
443 self._inputhook = get_inputhook_func(gui)
448 self._inputhook = get_inputhook_func(gui)
444 else:
449 else:
445 self._inputhook = None
450 self._inputhook = None
446
451
447 # Run !system commands directly, not through pipes, so terminal programs
452 # Run !system commands directly, not through pipes, so terminal programs
448 # work correctly.
453 # work correctly.
449 system = InteractiveShell.system_raw
454 system = InteractiveShell.system_raw
450
455
451 def auto_rewrite_input(self, cmd):
456 def auto_rewrite_input(self, cmd):
452 """Overridden from the parent class to use fancy rewriting prompt"""
457 """Overridden from the parent class to use fancy rewriting prompt"""
453 if not self.show_rewritten_input:
458 if not self.show_rewritten_input:
454 return
459 return
455
460
456 tokens = self.prompts.rewrite_prompt_tokens()
461 tokens = self.prompts.rewrite_prompt_tokens()
457 if self.pt_cli:
462 if self.pt_cli:
458 self.pt_cli.print_tokens(tokens)
463 self.pt_cli.print_tokens(tokens)
459 print(cmd)
464 print(cmd)
460 else:
465 else:
461 prompt = ''.join(s for t, s in tokens)
466 prompt = ''.join(s for t, s in tokens)
462 print(prompt, cmd, sep='')
467 print(prompt, cmd, sep='')
463
468
464 _prompts_before = None
469 _prompts_before = None
465 def switch_doctest_mode(self, mode):
470 def switch_doctest_mode(self, mode):
466 """Switch prompts to classic for %doctest_mode"""
471 """Switch prompts to classic for %doctest_mode"""
467 if mode:
472 if mode:
468 self._prompts_before = self.prompts
473 self._prompts_before = self.prompts
469 self.prompts = ClassicPrompts(self)
474 self.prompts = ClassicPrompts(self)
470 elif self._prompts_before:
475 elif self._prompts_before:
471 self.prompts = self._prompts_before
476 self.prompts = self._prompts_before
472 self._prompts_before = None
477 self._prompts_before = None
473 self._update_layout()
478 self._update_layout()
474
479
475
480
476 InteractiveShellABC.register(TerminalInteractiveShell)
481 InteractiveShellABC.register(TerminalInteractiveShell)
477
482
478 if __name__ == '__main__':
483 if __name__ == '__main__':
479 TerminalInteractiveShell.instance().interact()
484 TerminalInteractiveShell.instance().interact()
@@ -1,151 +1,138 b''
1 """Global IPython app to support test running.
1 """Global IPython app to support test running.
2
2
3 We must start our own ipython object and heavily muck with it so that all the
3 We must start our own ipython object and heavily muck with it so that all the
4 modifications IPython makes to system behavior don't send the doctest machinery
4 modifications IPython makes to system behavior don't send the doctest machinery
5 into a fit. This code should be considered a gross hack, but it gets the job
5 into a fit. This code should be considered a gross hack, but it gets the job
6 done.
6 done.
7 """
7 """
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9 from __future__ import print_function
9 from __future__ import print_function
10
10
11 #-----------------------------------------------------------------------------
11 # Copyright (c) IPython Development Team.
12 # Copyright (C) 2009-2011 The IPython Development Team
12 # Distributed under the terms of the Modified BSD License.
13 #
13
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
21
22 # stdlib
23 import sys
14 import sys
15 import warnings
24
16
25 # our own
26 from . import tools
17 from . import tools
27
18
28 from IPython.core import page
19 from IPython.core import page
29 from IPython.utils import io
20 from IPython.utils import io
30 from IPython.utils import py3compat
21 from IPython.utils import py3compat
31 from IPython.utils.py3compat import builtin_mod
22 from IPython.utils.py3compat import builtin_mod
32 from IPython.terminal.interactiveshell import TerminalInteractiveShell
23 from IPython.terminal.interactiveshell import TerminalInteractiveShell
33
24
34 #-----------------------------------------------------------------------------
35 # Functions
36 #-----------------------------------------------------------------------------
37
25
38 class StreamProxy(io.IOStream):
26 class StreamProxy(io.IOStream):
39 """Proxy for sys.stdout/err. This will request the stream *at call time*
27 """Proxy for sys.stdout/err. This will request the stream *at call time*
40 allowing for nose's Capture plugin's redirection of sys.stdout/err.
28 allowing for nose's Capture plugin's redirection of sys.stdout/err.
41
29
42 Parameters
30 Parameters
43 ----------
31 ----------
44 name : str
32 name : str
45 The name of the stream. This will be requested anew at every call
33 The name of the stream. This will be requested anew at every call
46 """
34 """
47
35
48 def __init__(self, name):
36 def __init__(self, name):
37 warnings.warn("StreamProxy is deprecated and unused as of IPython 5", DeprecationWarning,
38 stacklevel=2,
39 )
49 self.name=name
40 self.name=name
50
41
51 @property
42 @property
52 def stream(self):
43 def stream(self):
53 return getattr(sys, self.name)
44 return getattr(sys, self.name)
54
45
55 def flush(self):
46 def flush(self):
56 self.stream.flush()
47 self.stream.flush()
57
48
58
49
59 def get_ipython():
50 def get_ipython():
60 # This will get replaced by the real thing once we start IPython below
51 # This will get replaced by the real thing once we start IPython below
61 return start_ipython()
52 return start_ipython()
62
53
63
54
64 # A couple of methods to override those in the running IPython to interact
55 # A couple of methods to override those in the running IPython to interact
65 # better with doctest (doctest captures on raw stdout, so we need to direct
56 # better with doctest (doctest captures on raw stdout, so we need to direct
66 # various types of output there otherwise it will miss them).
57 # various types of output there otherwise it will miss them).
67
58
68 def xsys(self, cmd):
59 def xsys(self, cmd):
69 """Replace the default system call with a capturing one for doctest.
60 """Replace the default system call with a capturing one for doctest.
70 """
61 """
71 # We use getoutput, but we need to strip it because pexpect captures
62 # We use getoutput, but we need to strip it because pexpect captures
72 # the trailing newline differently from commands.getoutput
63 # the trailing newline differently from commands.getoutput
73 print(self.getoutput(cmd, split=False, depth=1).rstrip(), end='', file=sys.stdout)
64 print(self.getoutput(cmd, split=False, depth=1).rstrip(), end='', file=sys.stdout)
74 sys.stdout.flush()
65 sys.stdout.flush()
75
66
76
67
77 def _showtraceback(self, etype, evalue, stb):
68 def _showtraceback(self, etype, evalue, stb):
78 """Print the traceback purely on stdout for doctest to capture it.
69 """Print the traceback purely on stdout for doctest to capture it.
79 """
70 """
80 print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
71 print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
81
72
82
73
83 def start_ipython():
74 def start_ipython():
84 """Start a global IPython shell, which we need for IPython-specific syntax.
75 """Start a global IPython shell, which we need for IPython-specific syntax.
85 """
76 """
86 global get_ipython
77 global get_ipython
87
78
88 # This function should only ever run once!
79 # This function should only ever run once!
89 if hasattr(start_ipython, 'already_called'):
80 if hasattr(start_ipython, 'already_called'):
90 return
81 return
91 start_ipython.already_called = True
82 start_ipython.already_called = True
92
83
93 # Store certain global objects that IPython modifies
84 # Store certain global objects that IPython modifies
94 _displayhook = sys.displayhook
85 _displayhook = sys.displayhook
95 _excepthook = sys.excepthook
86 _excepthook = sys.excepthook
96 _main = sys.modules.get('__main__')
87 _main = sys.modules.get('__main__')
97
88
98 # Create custom argv and namespaces for our IPython to be test-friendly
89 # Create custom argv and namespaces for our IPython to be test-friendly
99 config = tools.default_config()
90 config = tools.default_config()
100 config.TerminalInteractiveShell.simple_prompt = True
91 config.TerminalInteractiveShell.simple_prompt = True
101
92
102 # Create and initialize our test-friendly IPython instance.
93 # Create and initialize our test-friendly IPython instance.
103 shell = TerminalInteractiveShell.instance(config=config,
94 shell = TerminalInteractiveShell.instance(config=config,
104 )
95 )
105
96
106 # A few more tweaks needed for playing nicely with doctests...
97 # A few more tweaks needed for playing nicely with doctests...
107
98
108 # remove history file
99 # remove history file
109 shell.tempfiles.append(config.HistoryManager.hist_file)
100 shell.tempfiles.append(config.HistoryManager.hist_file)
110
101
111 # These traps are normally only active for interactive use, set them
102 # These traps are normally only active for interactive use, set them
112 # permanently since we'll be mocking interactive sessions.
103 # permanently since we'll be mocking interactive sessions.
113 shell.builtin_trap.activate()
104 shell.builtin_trap.activate()
114
105
115 # Modify the IPython system call with one that uses getoutput, so that we
106 # Modify the IPython system call with one that uses getoutput, so that we
116 # can capture subcommands and print them to Python's stdout, otherwise the
107 # can capture subcommands and print them to Python's stdout, otherwise the
117 # doctest machinery would miss them.
108 # doctest machinery would miss them.
118 shell.system = py3compat.MethodType(xsys, shell)
109 shell.system = py3compat.MethodType(xsys, shell)
119
110
120 shell._showtraceback = py3compat.MethodType(_showtraceback, shell)
111 shell._showtraceback = py3compat.MethodType(_showtraceback, shell)
121
112
122 # IPython is ready, now clean up some global state...
113 # IPython is ready, now clean up some global state...
123
114
124 # Deactivate the various python system hooks added by ipython for
115 # Deactivate the various python system hooks added by ipython for
125 # interactive convenience so we don't confuse the doctest system
116 # interactive convenience so we don't confuse the doctest system
126 sys.modules['__main__'] = _main
117 sys.modules['__main__'] = _main
127 sys.displayhook = _displayhook
118 sys.displayhook = _displayhook
128 sys.excepthook = _excepthook
119 sys.excepthook = _excepthook
129
120
130 # So that ipython magics and aliases can be doctested (they work by making
121 # So that ipython magics and aliases can be doctested (they work by making
131 # a call into a global _ip object). Also make the top-level get_ipython
122 # a call into a global _ip object). Also make the top-level get_ipython
132 # now return this without recursively calling here again.
123 # now return this without recursively calling here again.
133 _ip = shell
124 _ip = shell
134 get_ipython = _ip.get_ipython
125 get_ipython = _ip.get_ipython
135 builtin_mod._ip = _ip
126 builtin_mod._ip = _ip
136 builtin_mod.get_ipython = get_ipython
127 builtin_mod.get_ipython = get_ipython
137
128
138 # To avoid extra IPython messages during testing, suppress io.stdout/stderr
139 io.stdout = StreamProxy('stdout')
140 io.stderr = StreamProxy('stderr')
141
142 # Override paging, so we don't require user interaction during the tests.
129 # Override paging, so we don't require user interaction during the tests.
143 def nopage(strng, start=0, screen_lines=0, pager_cmd=None):
130 def nopage(strng, start=0, screen_lines=0, pager_cmd=None):
144 if isinstance(strng, dict):
131 if isinstance(strng, dict):
145 strng = strng.get('text/plain', '')
132 strng = strng.get('text/plain', '')
146 print(strng)
133 print(strng)
147
134
148 page.orig_page = page.pager_page
135 page.orig_page = page.pager_page
149 page.pager_page = nopage
136 page.pager_page = nopage
150
137
151 return _ip
138 return _ip
@@ -1,235 +1,241 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 from __future__ import print_function
9 from __future__ import print_function
10 from __future__ import absolute_import
10 from __future__ import absolute_import
11
11
12
12
13 import atexit
13 import atexit
14 import os
14 import os
15 import sys
15 import sys
16 import tempfile
16 import tempfile
17 import warnings
17 from warnings import warn
18 from warnings import warn
18
19
19 from IPython.utils.decorators import undoc
20 from IPython.utils.decorators import undoc
20 from .capture import CapturedIO, capture_output
21 from .capture import CapturedIO, capture_output
21 from .py3compat import string_types, input, PY3
22 from .py3compat import string_types, input, PY3
22
23
23 @undoc
24 @undoc
24 class IOStream:
25 class IOStream:
25
26
26 def __init__(self, stream, fallback=None):
27 def __init__(self, stream, fallback=None):
27 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
28 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
28 DeprecationWarning, stacklevel=2)
29 DeprecationWarning, stacklevel=2)
29 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
30 if fallback is not None:
31 if fallback is not None:
31 stream = fallback
32 stream = fallback
32 else:
33 else:
33 raise ValueError("fallback required, but not specified")
34 raise ValueError("fallback required, but not specified")
34 self.stream = stream
35 self.stream = stream
35 self._swrite = stream.write
36 self._swrite = stream.write
36
37
37 # clone all methods not overridden:
38 # clone all methods not overridden:
38 def clone(meth):
39 def clone(meth):
39 return not hasattr(self, meth) and not meth.startswith('_')
40 return not hasattr(self, meth) and not meth.startswith('_')
40 for meth in filter(clone, dir(stream)):
41 for meth in filter(clone, dir(stream)):
41 setattr(self, meth, getattr(stream, meth))
42 setattr(self, meth, getattr(stream, meth))
42
43
43 def __repr__(self):
44 def __repr__(self):
44 cls = self.__class__
45 cls = self.__class__
45 tpl = '{mod}.{cls}({args})'
46 tpl = '{mod}.{cls}({args})'
46 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
47 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
47
48
48 def write(self,data):
49 def write(self,data):
49 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
50 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
50 DeprecationWarning, stacklevel=2)
51 DeprecationWarning, stacklevel=2)
51 try:
52 try:
52 self._swrite(data)
53 self._swrite(data)
53 except:
54 except:
54 try:
55 try:
55 # print handles some unicode issues which may trip a plain
56 # print handles some unicode issues which may trip a plain
56 # write() call. Emulate write() by using an empty end
57 # write() call. Emulate write() by using an empty end
57 # argument.
58 # argument.
58 print(data, end='', file=self.stream)
59 print(data, end='', file=self.stream)
59 except:
60 except:
60 # if we get here, something is seriously broken.
61 # if we get here, something is seriously broken.
61 print('ERROR - failed to write data to stream:', self.stream,
62 print('ERROR - failed to write data to stream:', self.stream,
62 file=sys.stderr)
63 file=sys.stderr)
63
64
64 def writelines(self, lines):
65 def writelines(self, lines):
65 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
66 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
66 DeprecationWarning, stacklevel=2)
67 DeprecationWarning, stacklevel=2)
67 if isinstance(lines, string_types):
68 if isinstance(lines, string_types):
68 lines = [lines]
69 lines = [lines]
69 for line in lines:
70 for line in lines:
70 self.write(line)
71 self.write(line)
71
72
72 # This class used to have a writeln method, but regular files and streams
73 # This class used to have a writeln method, but regular files and streams
73 # in Python don't have this method. We need to keep this completely
74 # in Python don't have this method. We need to keep this completely
74 # compatible so we removed it.
75 # compatible so we removed it.
75
76
76 @property
77 @property
77 def closed(self):
78 def closed(self):
78 return self.stream.closed
79 return self.stream.closed
79
80
80 def close(self):
81 def close(self):
81 pass
82 pass
82
83
83 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
84 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
84 devnull = open(os.devnull, 'w')
85 devnull = open(os.devnull, 'w')
85 atexit.register(devnull.close)
86 atexit.register(devnull.close)
86 stdin = IOStream(sys.stdin, fallback=devnull)
87
87 stdout = IOStream(sys.stdout, fallback=devnull)
88 # io.std* are deprecated, but don't show our own deprecation warnings
88 stderr = IOStream(sys.stderr, fallback=devnull)
89 # during initialization of the deprecated API.
90 with warnings.catch_warnings():
91 warnings.simplefilter('ignore', DeprecationWarning)
92 stdin = IOStream(sys.stdin, fallback=devnull)
93 stdout = IOStream(sys.stdout, fallback=devnull)
94 stderr = IOStream(sys.stderr, fallback=devnull)
89
95
90 class Tee(object):
96 class Tee(object):
91 """A class to duplicate an output stream to stdout/err.
97 """A class to duplicate an output stream to stdout/err.
92
98
93 This works in a manner very similar to the Unix 'tee' command.
99 This works in a manner very similar to the Unix 'tee' command.
94
100
95 When the object is closed or deleted, it closes the original file given to
101 When the object is closed or deleted, it closes the original file given to
96 it for duplication.
102 it for duplication.
97 """
103 """
98 # Inspired by:
104 # Inspired by:
99 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
105 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
100
106
101 def __init__(self, file_or_name, mode="w", channel='stdout'):
107 def __init__(self, file_or_name, mode="w", channel='stdout'):
102 """Construct a new Tee object.
108 """Construct a new Tee object.
103
109
104 Parameters
110 Parameters
105 ----------
111 ----------
106 file_or_name : filename or open filehandle (writable)
112 file_or_name : filename or open filehandle (writable)
107 File that will be duplicated
113 File that will be duplicated
108
114
109 mode : optional, valid mode for open().
115 mode : optional, valid mode for open().
110 If a filename was give, open with this mode.
116 If a filename was give, open with this mode.
111
117
112 channel : str, one of ['stdout', 'stderr']
118 channel : str, one of ['stdout', 'stderr']
113 """
119 """
114 if channel not in ['stdout', 'stderr']:
120 if channel not in ['stdout', 'stderr']:
115 raise ValueError('Invalid channel spec %s' % channel)
121 raise ValueError('Invalid channel spec %s' % channel)
116
122
117 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
123 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
118 self.file = file_or_name
124 self.file = file_or_name
119 else:
125 else:
120 self.file = open(file_or_name, mode)
126 self.file = open(file_or_name, mode)
121 self.channel = channel
127 self.channel = channel
122 self.ostream = getattr(sys, channel)
128 self.ostream = getattr(sys, channel)
123 setattr(sys, channel, self)
129 setattr(sys, channel, self)
124 self._closed = False
130 self._closed = False
125
131
126 def close(self):
132 def close(self):
127 """Close the file and restore the channel."""
133 """Close the file and restore the channel."""
128 self.flush()
134 self.flush()
129 setattr(sys, self.channel, self.ostream)
135 setattr(sys, self.channel, self.ostream)
130 self.file.close()
136 self.file.close()
131 self._closed = True
137 self._closed = True
132
138
133 def write(self, data):
139 def write(self, data):
134 """Write data to both channels."""
140 """Write data to both channels."""
135 self.file.write(data)
141 self.file.write(data)
136 self.ostream.write(data)
142 self.ostream.write(data)
137 self.ostream.flush()
143 self.ostream.flush()
138
144
139 def flush(self):
145 def flush(self):
140 """Flush both channels."""
146 """Flush both channels."""
141 self.file.flush()
147 self.file.flush()
142 self.ostream.flush()
148 self.ostream.flush()
143
149
144 def __del__(self):
150 def __del__(self):
145 if not self._closed:
151 if not self._closed:
146 self.close()
152 self.close()
147
153
148
154
149 def ask_yes_no(prompt, default=None, interrupt=None):
155 def ask_yes_no(prompt, default=None, interrupt=None):
150 """Asks a question and returns a boolean (y/n) answer.
156 """Asks a question and returns a boolean (y/n) answer.
151
157
152 If default is given (one of 'y','n'), it is used if the user input is
158 If default is given (one of 'y','n'), it is used if the user input is
153 empty. If interrupt is given (one of 'y','n'), it is used if the user
159 empty. If interrupt is given (one of 'y','n'), it is used if the user
154 presses Ctrl-C. Otherwise the question is repeated until an answer is
160 presses Ctrl-C. Otherwise the question is repeated until an answer is
155 given.
161 given.
156
162
157 An EOF is treated as the default answer. If there is no default, an
163 An EOF is treated as the default answer. If there is no default, an
158 exception is raised to prevent infinite loops.
164 exception is raised to prevent infinite loops.
159
165
160 Valid answers are: y/yes/n/no (match is not case sensitive)."""
166 Valid answers are: y/yes/n/no (match is not case sensitive)."""
161
167
162 answers = {'y':True,'n':False,'yes':True,'no':False}
168 answers = {'y':True,'n':False,'yes':True,'no':False}
163 ans = None
169 ans = None
164 while ans not in answers.keys():
170 while ans not in answers.keys():
165 try:
171 try:
166 ans = input(prompt+' ').lower()
172 ans = input(prompt+' ').lower()
167 if not ans: # response was an empty string
173 if not ans: # response was an empty string
168 ans = default
174 ans = default
169 except KeyboardInterrupt:
175 except KeyboardInterrupt:
170 if interrupt:
176 if interrupt:
171 ans = interrupt
177 ans = interrupt
172 except EOFError:
178 except EOFError:
173 if default in answers.keys():
179 if default in answers.keys():
174 ans = default
180 ans = default
175 print()
181 print()
176 else:
182 else:
177 raise
183 raise
178
184
179 return answers[ans]
185 return answers[ans]
180
186
181
187
182 def temp_pyfile(src, ext='.py'):
188 def temp_pyfile(src, ext='.py'):
183 """Make a temporary python file, return filename and filehandle.
189 """Make a temporary python file, return filename and filehandle.
184
190
185 Parameters
191 Parameters
186 ----------
192 ----------
187 src : string or list of strings (no need for ending newlines if list)
193 src : string or list of strings (no need for ending newlines if list)
188 Source code to be written to the file.
194 Source code to be written to the file.
189
195
190 ext : optional, string
196 ext : optional, string
191 Extension for the generated file.
197 Extension for the generated file.
192
198
193 Returns
199 Returns
194 -------
200 -------
195 (filename, open filehandle)
201 (filename, open filehandle)
196 It is the caller's responsibility to close the open file and unlink it.
202 It is the caller's responsibility to close the open file and unlink it.
197 """
203 """
198 fname = tempfile.mkstemp(ext)[1]
204 fname = tempfile.mkstemp(ext)[1]
199 f = open(fname,'w')
205 f = open(fname,'w')
200 f.write(src)
206 f.write(src)
201 f.flush()
207 f.flush()
202 return fname, f
208 return fname, f
203
209
204 def atomic_writing(*args, **kwargs):
210 def atomic_writing(*args, **kwargs):
205 """DEPRECATED: moved to notebook.services.contents.fileio"""
211 """DEPRECATED: moved to notebook.services.contents.fileio"""
206 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio")
212 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio")
207 from notebook.services.contents.fileio import atomic_writing
213 from notebook.services.contents.fileio import atomic_writing
208 return atomic_writing(*args, **kwargs)
214 return atomic_writing(*args, **kwargs)
209
215
210 def raw_print(*args, **kw):
216 def raw_print(*args, **kw):
211 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
217 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
212
218
213 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
219 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
214 file=sys.__stdout__)
220 file=sys.__stdout__)
215 sys.__stdout__.flush()
221 sys.__stdout__.flush()
216
222
217
223
218 def raw_print_err(*args, **kw):
224 def raw_print_err(*args, **kw):
219 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
225 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
220
226
221 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
227 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
222 file=sys.__stderr__)
228 file=sys.__stderr__)
223 sys.__stderr__.flush()
229 sys.__stderr__.flush()
224
230
225
231
226 # Short aliases for quick debugging, do NOT use these in production code.
232 # Short aliases for quick debugging, do NOT use these in production code.
227 rprint = raw_print
233 rprint = raw_print
228 rprinte = raw_print_err
234 rprinte = raw_print_err
229
235
230
236
231 def unicode_std_stream(stream='stdout'):
237 def unicode_std_stream(stream='stdout'):
232 """DEPRECATED, moved to nbconvert.utils.io"""
238 """DEPRECATED, moved to nbconvert.utils.io"""
233 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io")
239 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io")
234 from nbconvert.utils.io import unicode_std_stream
240 from nbconvert.utils.io import unicode_std_stream
235 return unicode_std_stream(stream)
241 return unicode_std_stream(stream)
@@ -1,65 +1,65 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for warnings. Shoudn't we just use the built in warnings module.
3 Utilities for warnings. Shoudn't we just use the built in warnings module.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 from __future__ import print_function
9 from __future__ import print_function
10
10
11 import sys
11 import sys
12 import warnings
12 import warnings
13
13
14 warnings.warn("The module IPython.utils.warn is deprecated since IPython 4.0, use the standard warnings module instead", DeprecationWarning)
14 warnings.warn("The module IPython.utils.warn is deprecated since IPython 4.0, use the standard warnings module instead", DeprecationWarning)
15
15
16 def warn(msg,level=2,exit_val=1):
16 def warn(msg,level=2,exit_val=1):
17 """Deprecated
17 """Deprecated
18
18
19 Standard warning printer. Gives formatting consistency.
19 Standard warning printer. Gives formatting consistency.
20
20
21 Output is sent to io.stderr (sys.stderr by default).
21 Output is sent to sys.stderr.
22
22
23 Options:
23 Options:
24
24
25 -level(2): allows finer control:
25 -level(2): allows finer control:
26 0 -> Do nothing, dummy function.
26 0 -> Do nothing, dummy function.
27 1 -> Print message.
27 1 -> Print message.
28 2 -> Print 'WARNING:' + message. (Default level).
28 2 -> Print 'WARNING:' + message. (Default level).
29 3 -> Print 'ERROR:' + message.
29 3 -> Print 'ERROR:' + message.
30 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
30 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
31
31
32 -exit_val (1): exit value returned by sys.exit() for a level 4
32 -exit_val (1): exit value returned by sys.exit() for a level 4
33 warning. Ignored for all other levels."""
33 warning. Ignored for all other levels."""
34
34
35 warnings.warn("The module IPython.utils.warn is deprecated since IPython 4.0, use the standard warnings module instead", DeprecationWarning)
35 warnings.warn("The module IPython.utils.warn is deprecated since IPython 4.0, use the standard warnings module instead", DeprecationWarning)
36 if level>0:
36 if level>0:
37 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
37 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
38 print(header[level], msg, sep='', file=sys.stderr)
38 print(header[level], msg, sep='', file=sys.stderr)
39 if level == 4:
39 if level == 4:
40 print('Exiting.\n', file=sys.stderr)
40 print('Exiting.\n', file=sys.stderr)
41 sys.exit(exit_val)
41 sys.exit(exit_val)
42
42
43
43
44 def info(msg):
44 def info(msg):
45 """Deprecated
45 """Deprecated
46
46
47 Equivalent to warn(msg,level=1)."""
47 Equivalent to warn(msg,level=1)."""
48
48
49 warn(msg,level=1)
49 warn(msg,level=1)
50
50
51
51
52 def error(msg):
52 def error(msg):
53 """Deprecated
53 """Deprecated
54
54
55 Equivalent to warn(msg,level=3)."""
55 Equivalent to warn(msg,level=3)."""
56
56
57 warn(msg,level=3)
57 warn(msg,level=3)
58
58
59
59
60 def fatal(msg,exit_val=1):
60 def fatal(msg,exit_val=1):
61 """Deprecated
61 """Deprecated
62
62
63 Equivalent to warn(msg,exit_val=exit_val,level=4)."""
63 Equivalent to warn(msg,exit_val=exit_val,level=4)."""
64
64
65 warn(msg,exit_val=exit_val,level=4)
65 warn(msg,exit_val=exit_val,level=4)
General Comments 0
You need to be logged in to leave comments. Login now