##// END OF EJS Templates
Use StringIO.StringIO on Python 2....
Thomas Kluyver -
Show More
@@ -1,654 +1,657 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 Authors:
9 Authors:
10
10
11 * Robert Kern
11 * Robert Kern
12 * Brian Granger
12 * Brian Granger
13 """
13 """
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2010-2011, IPython Development Team.
15 # Copyright (C) 2010-2011, IPython Development Team.
16 #
16 #
17 # Distributed under the terms of the Modified BSD License.
17 # Distributed under the terms of the Modified BSD License.
18 #
18 #
19 # The full license is in the file COPYING.txt, distributed with this software.
19 # The full license is in the file COPYING.txt, distributed with this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 # Stdlib imports
26 # Stdlib imports
27 import abc
27 import abc
28 import sys
28 import sys
29 import warnings
29 import warnings
30 # We must use StringIO, as cStringIO doesn't handle unicode properly.
31 from io import StringIO
32
30
33 # Our own imports
31 # Our own imports
34 from IPython.config.configurable import Configurable
32 from IPython.config.configurable import Configurable
35 from IPython.lib import pretty
33 from IPython.lib import pretty
36 from IPython.utils.traitlets import (
34 from IPython.utils.traitlets import (
37 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
35 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
38 )
36 )
39 from IPython.utils.py3compat import unicode_to_str, with_metaclass
37 from IPython.utils.py3compat import unicode_to_str, with_metaclass, PY3
38
39 if PY3:
40 from io import StringIO
41 else:
42 from StringIO import StringIO
40
43
41
44
42 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
43 # The main DisplayFormatter class
46 # The main DisplayFormatter class
44 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
45
48
46
49
47 class DisplayFormatter(Configurable):
50 class DisplayFormatter(Configurable):
48
51
49 # When set to true only the default plain text formatter will be used.
52 # When set to true only the default plain text formatter will be used.
50 plain_text_only = Bool(False, config=True)
53 plain_text_only = Bool(False, config=True)
51 def _plain_text_only_changed(self, name, old, new):
54 def _plain_text_only_changed(self, name, old, new):
52 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
55 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
53
56
54 Use DisplayFormatter.active_types = ['text/plain']
57 Use DisplayFormatter.active_types = ['text/plain']
55 for the same effect.
58 for the same effect.
56 """, DeprecationWarning)
59 """, DeprecationWarning)
57 if new:
60 if new:
58 self.active_types = ['text/plain']
61 self.active_types = ['text/plain']
59 else:
62 else:
60 self.active_types = self.format_types
63 self.active_types = self.format_types
61
64
62 active_types = List(Unicode, config=True,
65 active_types = List(Unicode, config=True,
63 help="""List of currently active mime-types to display.
66 help="""List of currently active mime-types to display.
64 You can use this to set a white-list for formats to display.
67 You can use this to set a white-list for formats to display.
65
68
66 Most users will not need to change this value.
69 Most users will not need to change this value.
67 """)
70 """)
68 def _active_types_default(self):
71 def _active_types_default(self):
69 return self.format_types
72 return self.format_types
70
73
71 def _active_types_changed(self, name, old, new):
74 def _active_types_changed(self, name, old, new):
72 for key, formatter in self.formatters.items():
75 for key, formatter in self.formatters.items():
73 if key in new:
76 if key in new:
74 formatter.enabled = True
77 formatter.enabled = True
75 else:
78 else:
76 formatter.enabled = False
79 formatter.enabled = False
77
80
78 # A dict of formatter whose keys are format types (MIME types) and whose
81 # A dict of formatter whose keys are format types (MIME types) and whose
79 # values are subclasses of BaseFormatter.
82 # values are subclasses of BaseFormatter.
80 formatters = Dict()
83 formatters = Dict()
81 def _formatters_default(self):
84 def _formatters_default(self):
82 """Activate the default formatters."""
85 """Activate the default formatters."""
83 formatter_classes = [
86 formatter_classes = [
84 PlainTextFormatter,
87 PlainTextFormatter,
85 HTMLFormatter,
88 HTMLFormatter,
86 SVGFormatter,
89 SVGFormatter,
87 PNGFormatter,
90 PNGFormatter,
88 JPEGFormatter,
91 JPEGFormatter,
89 LatexFormatter,
92 LatexFormatter,
90 JSONFormatter,
93 JSONFormatter,
91 JavascriptFormatter
94 JavascriptFormatter
92 ]
95 ]
93 d = {}
96 d = {}
94 for cls in formatter_classes:
97 for cls in formatter_classes:
95 f = cls(parent=self)
98 f = cls(parent=self)
96 d[f.format_type] = f
99 d[f.format_type] = f
97 return d
100 return d
98
101
99 def format(self, obj, include=None, exclude=None):
102 def format(self, obj, include=None, exclude=None):
100 """Return a format data dict for an object.
103 """Return a format data dict for an object.
101
104
102 By default all format types will be computed.
105 By default all format types will be computed.
103
106
104 The following MIME types are currently implemented:
107 The following MIME types are currently implemented:
105
108
106 * text/plain
109 * text/plain
107 * text/html
110 * text/html
108 * text/latex
111 * text/latex
109 * application/json
112 * application/json
110 * application/javascript
113 * application/javascript
111 * image/png
114 * image/png
112 * image/jpeg
115 * image/jpeg
113 * image/svg+xml
116 * image/svg+xml
114
117
115 Parameters
118 Parameters
116 ----------
119 ----------
117 obj : object
120 obj : object
118 The Python object whose format data will be computed.
121 The Python object whose format data will be computed.
119 include : list or tuple, optional
122 include : list or tuple, optional
120 A list of format type strings (MIME types) to include in the
123 A list of format type strings (MIME types) to include in the
121 format data dict. If this is set *only* the format types included
124 format data dict. If this is set *only* the format types included
122 in this list will be computed.
125 in this list will be computed.
123 exclude : list or tuple, optional
126 exclude : list or tuple, optional
124 A list of format type string (MIME types) to exclude in the format
127 A list of format type string (MIME types) to exclude in the format
125 data dict. If this is set all format types will be computed,
128 data dict. If this is set all format types will be computed,
126 except for those included in this argument.
129 except for those included in this argument.
127
130
128 Returns
131 Returns
129 -------
132 -------
130 (format_dict, metadata_dict) : tuple of two dicts
133 (format_dict, metadata_dict) : tuple of two dicts
131
134
132 format_dict is a dictionary of key/value pairs, one of each format that was
135 format_dict is a dictionary of key/value pairs, one of each format that was
133 generated for the object. The keys are the format types, which
136 generated for the object. The keys are the format types, which
134 will usually be MIME type strings and the values and JSON'able
137 will usually be MIME type strings and the values and JSON'able
135 data structure containing the raw data for the representation in
138 data structure containing the raw data for the representation in
136 that format.
139 that format.
137
140
138 metadata_dict is a dictionary of metadata about each mime-type output.
141 metadata_dict is a dictionary of metadata about each mime-type output.
139 Its keys will be a strict subset of the keys in format_dict.
142 Its keys will be a strict subset of the keys in format_dict.
140 """
143 """
141 format_dict = {}
144 format_dict = {}
142 md_dict = {}
145 md_dict = {}
143
146
144 for format_type, formatter in self.formatters.items():
147 for format_type, formatter in self.formatters.items():
145 if include and format_type not in include:
148 if include and format_type not in include:
146 continue
149 continue
147 if exclude and format_type in exclude:
150 if exclude and format_type in exclude:
148 continue
151 continue
149
152
150 md = None
153 md = None
151 try:
154 try:
152 data = formatter(obj)
155 data = formatter(obj)
153 except:
156 except:
154 # FIXME: log the exception
157 # FIXME: log the exception
155 raise
158 raise
156
159
157 # formatters can return raw data or (data, metadata)
160 # formatters can return raw data or (data, metadata)
158 if isinstance(data, tuple) and len(data) == 2:
161 if isinstance(data, tuple) and len(data) == 2:
159 data, md = data
162 data, md = data
160
163
161 if data is not None:
164 if data is not None:
162 format_dict[format_type] = data
165 format_dict[format_type] = data
163 if md is not None:
166 if md is not None:
164 md_dict[format_type] = md
167 md_dict[format_type] = md
165
168
166 return format_dict, md_dict
169 return format_dict, md_dict
167
170
168 @property
171 @property
169 def format_types(self):
172 def format_types(self):
170 """Return the format types (MIME types) of the active formatters."""
173 """Return the format types (MIME types) of the active formatters."""
171 return list(self.formatters.keys())
174 return list(self.formatters.keys())
172
175
173
176
174 #-----------------------------------------------------------------------------
177 #-----------------------------------------------------------------------------
175 # Formatters for specific format types (text, html, svg, etc.)
178 # Formatters for specific format types (text, html, svg, etc.)
176 #-----------------------------------------------------------------------------
179 #-----------------------------------------------------------------------------
177
180
178
181
179 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
182 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
180 """ Abstract base class for Formatters.
183 """ Abstract base class for Formatters.
181
184
182 A formatter is a callable class that is responsible for computing the
185 A formatter is a callable class that is responsible for computing the
183 raw format data for a particular format type (MIME type). For example,
186 raw format data for a particular format type (MIME type). For example,
184 an HTML formatter would have a format type of `text/html` and would return
187 an HTML formatter would have a format type of `text/html` and would return
185 the HTML representation of the object when called.
188 the HTML representation of the object when called.
186 """
189 """
187
190
188 # The format type of the data returned, usually a MIME type.
191 # The format type of the data returned, usually a MIME type.
189 format_type = 'text/plain'
192 format_type = 'text/plain'
190
193
191 # Is the formatter enabled...
194 # Is the formatter enabled...
192 enabled = True
195 enabled = True
193
196
194 @abc.abstractmethod
197 @abc.abstractmethod
195 def __call__(self, obj):
198 def __call__(self, obj):
196 """Return a JSON'able representation of the object.
199 """Return a JSON'able representation of the object.
197
200
198 If the object cannot be formatted by this formatter, then return None
201 If the object cannot be formatted by this formatter, then return None
199 """
202 """
200 try:
203 try:
201 return repr(obj)
204 return repr(obj)
202 except TypeError:
205 except TypeError:
203 return None
206 return None
204
207
205
208
206 class BaseFormatter(Configurable):
209 class BaseFormatter(Configurable):
207 """A base formatter class that is configurable.
210 """A base formatter class that is configurable.
208
211
209 This formatter should usually be used as the base class of all formatters.
212 This formatter should usually be used as the base class of all formatters.
210 It is a traited :class:`Configurable` class and includes an extensible
213 It is a traited :class:`Configurable` class and includes an extensible
211 API for users to determine how their objects are formatted. The following
214 API for users to determine how their objects are formatted. The following
212 logic is used to find a function to format an given object.
215 logic is used to find a function to format an given object.
213
216
214 1. The object is introspected to see if it has a method with the name
217 1. The object is introspected to see if it has a method with the name
215 :attr:`print_method`. If is does, that object is passed to that method
218 :attr:`print_method`. If is does, that object is passed to that method
216 for formatting.
219 for formatting.
217 2. If no print method is found, three internal dictionaries are consulted
220 2. If no print method is found, three internal dictionaries are consulted
218 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
221 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
219 and :attr:`deferred_printers`.
222 and :attr:`deferred_printers`.
220
223
221 Users should use these dictionaries to register functions that will be
224 Users should use these dictionaries to register functions that will be
222 used to compute the format data for their objects (if those objects don't
225 used to compute the format data for their objects (if those objects don't
223 have the special print methods). The easiest way of using these
226 have the special print methods). The easiest way of using these
224 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
227 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
225 methods.
228 methods.
226
229
227 If no function/callable is found to compute the format data, ``None`` is
230 If no function/callable is found to compute the format data, ``None`` is
228 returned and this format type is not used.
231 returned and this format type is not used.
229 """
232 """
230
233
231 format_type = Unicode('text/plain')
234 format_type = Unicode('text/plain')
232
235
233 enabled = Bool(True, config=True)
236 enabled = Bool(True, config=True)
234
237
235 print_method = ObjectName('__repr__')
238 print_method = ObjectName('__repr__')
236
239
237 # The singleton printers.
240 # The singleton printers.
238 # Maps the IDs of the builtin singleton objects to the format functions.
241 # Maps the IDs of the builtin singleton objects to the format functions.
239 singleton_printers = Dict(config=True)
242 singleton_printers = Dict(config=True)
240 def _singleton_printers_default(self):
243 def _singleton_printers_default(self):
241 return {}
244 return {}
242
245
243 # The type-specific printers.
246 # The type-specific printers.
244 # Map type objects to the format functions.
247 # Map type objects to the format functions.
245 type_printers = Dict(config=True)
248 type_printers = Dict(config=True)
246 def _type_printers_default(self):
249 def _type_printers_default(self):
247 return {}
250 return {}
248
251
249 # The deferred-import type-specific printers.
252 # The deferred-import type-specific printers.
250 # Map (modulename, classname) pairs to the format functions.
253 # Map (modulename, classname) pairs to the format functions.
251 deferred_printers = Dict(config=True)
254 deferred_printers = Dict(config=True)
252 def _deferred_printers_default(self):
255 def _deferred_printers_default(self):
253 return {}
256 return {}
254
257
255 def __call__(self, obj):
258 def __call__(self, obj):
256 """Compute the format for an object."""
259 """Compute the format for an object."""
257 if self.enabled:
260 if self.enabled:
258 obj_id = id(obj)
261 obj_id = id(obj)
259 try:
262 try:
260 obj_class = getattr(obj, '__class__', None) or type(obj)
263 obj_class = getattr(obj, '__class__', None) or type(obj)
261 # First try to find registered singleton printers for the type.
264 # First try to find registered singleton printers for the type.
262 try:
265 try:
263 printer = self.singleton_printers[obj_id]
266 printer = self.singleton_printers[obj_id]
264 except (TypeError, KeyError):
267 except (TypeError, KeyError):
265 pass
268 pass
266 else:
269 else:
267 return printer(obj)
270 return printer(obj)
268 # Next look for type_printers.
271 # Next look for type_printers.
269 for cls in pretty._get_mro(obj_class):
272 for cls in pretty._get_mro(obj_class):
270 if cls in self.type_printers:
273 if cls in self.type_printers:
271 return self.type_printers[cls](obj)
274 return self.type_printers[cls](obj)
272 else:
275 else:
273 printer = self._in_deferred_types(cls)
276 printer = self._in_deferred_types(cls)
274 if printer is not None:
277 if printer is not None:
275 return printer(obj)
278 return printer(obj)
276 # Finally look for special method names.
279 # Finally look for special method names.
277 if hasattr(obj_class, self.print_method):
280 if hasattr(obj_class, self.print_method):
278 printer = getattr(obj_class, self.print_method)
281 printer = getattr(obj_class, self.print_method)
279 return printer(obj)
282 return printer(obj)
280 return None
283 return None
281 except Exception:
284 except Exception:
282 pass
285 pass
283 else:
286 else:
284 return None
287 return None
285
288
286 def for_type(self, typ, func):
289 def for_type(self, typ, func):
287 """Add a format function for a given type.
290 """Add a format function for a given type.
288
291
289 Parameters
292 Parameters
290 -----------
293 -----------
291 typ : class
294 typ : class
292 The class of the object that will be formatted using `func`.
295 The class of the object that will be formatted using `func`.
293 func : callable
296 func : callable
294 The callable that will be called to compute the format data. The
297 The callable that will be called to compute the format data. The
295 call signature of this function is simple, it must take the
298 call signature of this function is simple, it must take the
296 object to be formatted and return the raw data for the given
299 object to be formatted and return the raw data for the given
297 format. Subclasses may use a different call signature for the
300 format. Subclasses may use a different call signature for the
298 `func` argument.
301 `func` argument.
299 """
302 """
300 oldfunc = self.type_printers.get(typ, None)
303 oldfunc = self.type_printers.get(typ, None)
301 if func is not None:
304 if func is not None:
302 # To support easy restoration of old printers, we need to ignore
305 # To support easy restoration of old printers, we need to ignore
303 # Nones.
306 # Nones.
304 self.type_printers[typ] = func
307 self.type_printers[typ] = func
305 return oldfunc
308 return oldfunc
306
309
307 def for_type_by_name(self, type_module, type_name, func):
310 def for_type_by_name(self, type_module, type_name, func):
308 """Add a format function for a type specified by the full dotted
311 """Add a format function for a type specified by the full dotted
309 module and name of the type, rather than the type of the object.
312 module and name of the type, rather than the type of the object.
310
313
311 Parameters
314 Parameters
312 ----------
315 ----------
313 type_module : str
316 type_module : str
314 The full dotted name of the module the type is defined in, like
317 The full dotted name of the module the type is defined in, like
315 ``numpy``.
318 ``numpy``.
316 type_name : str
319 type_name : str
317 The name of the type (the class name), like ``dtype``
320 The name of the type (the class name), like ``dtype``
318 func : callable
321 func : callable
319 The callable that will be called to compute the format data. The
322 The callable that will be called to compute the format data. The
320 call signature of this function is simple, it must take the
323 call signature of this function is simple, it must take the
321 object to be formatted and return the raw data for the given
324 object to be formatted and return the raw data for the given
322 format. Subclasses may use a different call signature for the
325 format. Subclasses may use a different call signature for the
323 `func` argument.
326 `func` argument.
324 """
327 """
325 key = (type_module, type_name)
328 key = (type_module, type_name)
326 oldfunc = self.deferred_printers.get(key, None)
329 oldfunc = self.deferred_printers.get(key, None)
327 if func is not None:
330 if func is not None:
328 # To support easy restoration of old printers, we need to ignore
331 # To support easy restoration of old printers, we need to ignore
329 # Nones.
332 # Nones.
330 self.deferred_printers[key] = func
333 self.deferred_printers[key] = func
331 return oldfunc
334 return oldfunc
332
335
333 def _in_deferred_types(self, cls):
336 def _in_deferred_types(self, cls):
334 """
337 """
335 Check if the given class is specified in the deferred type registry.
338 Check if the given class is specified in the deferred type registry.
336
339
337 Returns the printer from the registry if it exists, and None if the
340 Returns the printer from the registry if it exists, and None if the
338 class is not in the registry. Successful matches will be moved to the
341 class is not in the registry. Successful matches will be moved to the
339 regular type registry for future use.
342 regular type registry for future use.
340 """
343 """
341 mod = getattr(cls, '__module__', None)
344 mod = getattr(cls, '__module__', None)
342 name = getattr(cls, '__name__', None)
345 name = getattr(cls, '__name__', None)
343 key = (mod, name)
346 key = (mod, name)
344 printer = None
347 printer = None
345 if key in self.deferred_printers:
348 if key in self.deferred_printers:
346 # Move the printer over to the regular registry.
349 # Move the printer over to the regular registry.
347 printer = self.deferred_printers.pop(key)
350 printer = self.deferred_printers.pop(key)
348 self.type_printers[cls] = printer
351 self.type_printers[cls] = printer
349 return printer
352 return printer
350
353
351
354
352 class PlainTextFormatter(BaseFormatter):
355 class PlainTextFormatter(BaseFormatter):
353 """The default pretty-printer.
356 """The default pretty-printer.
354
357
355 This uses :mod:`IPython.lib.pretty` to compute the format data of
358 This uses :mod:`IPython.lib.pretty` to compute the format data of
356 the object. If the object cannot be pretty printed, :func:`repr` is used.
359 the object. If the object cannot be pretty printed, :func:`repr` is used.
357 See the documentation of :mod:`IPython.lib.pretty` for details on
360 See the documentation of :mod:`IPython.lib.pretty` for details on
358 how to write pretty printers. Here is a simple example::
361 how to write pretty printers. Here is a simple example::
359
362
360 def dtype_pprinter(obj, p, cycle):
363 def dtype_pprinter(obj, p, cycle):
361 if cycle:
364 if cycle:
362 return p.text('dtype(...)')
365 return p.text('dtype(...)')
363 if hasattr(obj, 'fields'):
366 if hasattr(obj, 'fields'):
364 if obj.fields is None:
367 if obj.fields is None:
365 p.text(repr(obj))
368 p.text(repr(obj))
366 else:
369 else:
367 p.begin_group(7, 'dtype([')
370 p.begin_group(7, 'dtype([')
368 for i, field in enumerate(obj.descr):
371 for i, field in enumerate(obj.descr):
369 if i > 0:
372 if i > 0:
370 p.text(',')
373 p.text(',')
371 p.breakable()
374 p.breakable()
372 p.pretty(field)
375 p.pretty(field)
373 p.end_group(7, '])')
376 p.end_group(7, '])')
374 """
377 """
375
378
376 # The format type of data returned.
379 # The format type of data returned.
377 format_type = Unicode('text/plain')
380 format_type = Unicode('text/plain')
378
381
379 # This subclass ignores this attribute as it always need to return
382 # This subclass ignores this attribute as it always need to return
380 # something.
383 # something.
381 enabled = Bool(True, config=False)
384 enabled = Bool(True, config=False)
382
385
383 # Look for a _repr_pretty_ methods to use for pretty printing.
386 # Look for a _repr_pretty_ methods to use for pretty printing.
384 print_method = ObjectName('_repr_pretty_')
387 print_method = ObjectName('_repr_pretty_')
385
388
386 # Whether to pretty-print or not.
389 # Whether to pretty-print or not.
387 pprint = Bool(True, config=True)
390 pprint = Bool(True, config=True)
388
391
389 # Whether to be verbose or not.
392 # Whether to be verbose or not.
390 verbose = Bool(False, config=True)
393 verbose = Bool(False, config=True)
391
394
392 # The maximum width.
395 # The maximum width.
393 max_width = Integer(79, config=True)
396 max_width = Integer(79, config=True)
394
397
395 # The newline character.
398 # The newline character.
396 newline = Unicode('\n', config=True)
399 newline = Unicode('\n', config=True)
397
400
398 # format-string for pprinting floats
401 # format-string for pprinting floats
399 float_format = Unicode('%r')
402 float_format = Unicode('%r')
400 # setter for float precision, either int or direct format-string
403 # setter for float precision, either int or direct format-string
401 float_precision = CUnicode('', config=True)
404 float_precision = CUnicode('', config=True)
402
405
403 def _float_precision_changed(self, name, old, new):
406 def _float_precision_changed(self, name, old, new):
404 """float_precision changed, set float_format accordingly.
407 """float_precision changed, set float_format accordingly.
405
408
406 float_precision can be set by int or str.
409 float_precision can be set by int or str.
407 This will set float_format, after interpreting input.
410 This will set float_format, after interpreting input.
408 If numpy has been imported, numpy print precision will also be set.
411 If numpy has been imported, numpy print precision will also be set.
409
412
410 integer `n` sets format to '%.nf', otherwise, format set directly.
413 integer `n` sets format to '%.nf', otherwise, format set directly.
411
414
412 An empty string returns to defaults (repr for float, 8 for numpy).
415 An empty string returns to defaults (repr for float, 8 for numpy).
413
416
414 This parameter can be set via the '%precision' magic.
417 This parameter can be set via the '%precision' magic.
415 """
418 """
416
419
417 if '%' in new:
420 if '%' in new:
418 # got explicit format string
421 # got explicit format string
419 fmt = new
422 fmt = new
420 try:
423 try:
421 fmt%3.14159
424 fmt%3.14159
422 except Exception:
425 except Exception:
423 raise ValueError("Precision must be int or format string, not %r"%new)
426 raise ValueError("Precision must be int or format string, not %r"%new)
424 elif new:
427 elif new:
425 # otherwise, should be an int
428 # otherwise, should be an int
426 try:
429 try:
427 i = int(new)
430 i = int(new)
428 assert i >= 0
431 assert i >= 0
429 except ValueError:
432 except ValueError:
430 raise ValueError("Precision must be int or format string, not %r"%new)
433 raise ValueError("Precision must be int or format string, not %r"%new)
431 except AssertionError:
434 except AssertionError:
432 raise ValueError("int precision must be non-negative, not %r"%i)
435 raise ValueError("int precision must be non-negative, not %r"%i)
433
436
434 fmt = '%%.%if'%i
437 fmt = '%%.%if'%i
435 if 'numpy' in sys.modules:
438 if 'numpy' in sys.modules:
436 # set numpy precision if it has been imported
439 # set numpy precision if it has been imported
437 import numpy
440 import numpy
438 numpy.set_printoptions(precision=i)
441 numpy.set_printoptions(precision=i)
439 else:
442 else:
440 # default back to repr
443 # default back to repr
441 fmt = '%r'
444 fmt = '%r'
442 if 'numpy' in sys.modules:
445 if 'numpy' in sys.modules:
443 import numpy
446 import numpy
444 # numpy default is 8
447 # numpy default is 8
445 numpy.set_printoptions(precision=8)
448 numpy.set_printoptions(precision=8)
446 self.float_format = fmt
449 self.float_format = fmt
447
450
448 # Use the default pretty printers from IPython.lib.pretty.
451 # Use the default pretty printers from IPython.lib.pretty.
449 def _singleton_printers_default(self):
452 def _singleton_printers_default(self):
450 return pretty._singleton_pprinters.copy()
453 return pretty._singleton_pprinters.copy()
451
454
452 def _type_printers_default(self):
455 def _type_printers_default(self):
453 d = pretty._type_pprinters.copy()
456 d = pretty._type_pprinters.copy()
454 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
457 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
455 return d
458 return d
456
459
457 def _deferred_printers_default(self):
460 def _deferred_printers_default(self):
458 return pretty._deferred_type_pprinters.copy()
461 return pretty._deferred_type_pprinters.copy()
459
462
460 #### FormatterABC interface ####
463 #### FormatterABC interface ####
461
464
462 def __call__(self, obj):
465 def __call__(self, obj):
463 """Compute the pretty representation of the object."""
466 """Compute the pretty representation of the object."""
464 if not self.pprint:
467 if not self.pprint:
465 try:
468 try:
466 return repr(obj)
469 return repr(obj)
467 except TypeError:
470 except TypeError:
468 return ''
471 return ''
469 else:
472 else:
470 # This uses use StringIO, as cStringIO doesn't handle unicode.
473 # This uses use StringIO, as cStringIO doesn't handle unicode.
471 stream = StringIO()
474 stream = StringIO()
472 # self.newline.encode() is a quick fix for issue gh-597. We need to
475 # self.newline.encode() is a quick fix for issue gh-597. We need to
473 # ensure that stream does not get a mix of unicode and bytestrings,
476 # ensure that stream does not get a mix of unicode and bytestrings,
474 # or it will cause trouble.
477 # or it will cause trouble.
475 printer = pretty.RepresentationPrinter(stream, self.verbose,
478 printer = pretty.RepresentationPrinter(stream, self.verbose,
476 self.max_width, unicode_to_str(self.newline),
479 self.max_width, unicode_to_str(self.newline),
477 singleton_pprinters=self.singleton_printers,
480 singleton_pprinters=self.singleton_printers,
478 type_pprinters=self.type_printers,
481 type_pprinters=self.type_printers,
479 deferred_pprinters=self.deferred_printers)
482 deferred_pprinters=self.deferred_printers)
480 printer.pretty(obj)
483 printer.pretty(obj)
481 printer.flush()
484 printer.flush()
482 return stream.getvalue()
485 return stream.getvalue()
483
486
484
487
485 class HTMLFormatter(BaseFormatter):
488 class HTMLFormatter(BaseFormatter):
486 """An HTML formatter.
489 """An HTML formatter.
487
490
488 To define the callables that compute the HTML representation of your
491 To define the callables that compute the HTML representation of your
489 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
492 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
490 or :meth:`for_type_by_name` methods to register functions that handle
493 or :meth:`for_type_by_name` methods to register functions that handle
491 this.
494 this.
492
495
493 The return value of this formatter should be a valid HTML snippet that
496 The return value of this formatter should be a valid HTML snippet that
494 could be injected into an existing DOM. It should *not* include the
497 could be injected into an existing DOM. It should *not* include the
495 ```<html>`` or ```<body>`` tags.
498 ```<html>`` or ```<body>`` tags.
496 """
499 """
497 format_type = Unicode('text/html')
500 format_type = Unicode('text/html')
498
501
499 print_method = ObjectName('_repr_html_')
502 print_method = ObjectName('_repr_html_')
500
503
501
504
502 class SVGFormatter(BaseFormatter):
505 class SVGFormatter(BaseFormatter):
503 """An SVG formatter.
506 """An SVG formatter.
504
507
505 To define the callables that compute the SVG representation of your
508 To define the callables that compute the SVG representation of your
506 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
509 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
507 or :meth:`for_type_by_name` methods to register functions that handle
510 or :meth:`for_type_by_name` methods to register functions that handle
508 this.
511 this.
509
512
510 The return value of this formatter should be valid SVG enclosed in
513 The return value of this formatter should be valid SVG enclosed in
511 ```<svg>``` tags, that could be injected into an existing DOM. It should
514 ```<svg>``` tags, that could be injected into an existing DOM. It should
512 *not* include the ```<html>`` or ```<body>`` tags.
515 *not* include the ```<html>`` or ```<body>`` tags.
513 """
516 """
514 format_type = Unicode('image/svg+xml')
517 format_type = Unicode('image/svg+xml')
515
518
516 print_method = ObjectName('_repr_svg_')
519 print_method = ObjectName('_repr_svg_')
517
520
518
521
519 class PNGFormatter(BaseFormatter):
522 class PNGFormatter(BaseFormatter):
520 """A PNG formatter.
523 """A PNG formatter.
521
524
522 To define the callables that compute the PNG representation of your
525 To define the callables that compute the PNG representation of your
523 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
526 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
524 or :meth:`for_type_by_name` methods to register functions that handle
527 or :meth:`for_type_by_name` methods to register functions that handle
525 this.
528 this.
526
529
527 The return value of this formatter should be raw PNG data, *not*
530 The return value of this formatter should be raw PNG data, *not*
528 base64 encoded.
531 base64 encoded.
529 """
532 """
530 format_type = Unicode('image/png')
533 format_type = Unicode('image/png')
531
534
532 print_method = ObjectName('_repr_png_')
535 print_method = ObjectName('_repr_png_')
533
536
534
537
535 class JPEGFormatter(BaseFormatter):
538 class JPEGFormatter(BaseFormatter):
536 """A JPEG formatter.
539 """A JPEG formatter.
537
540
538 To define the callables that compute the JPEG representation of your
541 To define the callables that compute the JPEG representation of your
539 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
542 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
540 or :meth:`for_type_by_name` methods to register functions that handle
543 or :meth:`for_type_by_name` methods to register functions that handle
541 this.
544 this.
542
545
543 The return value of this formatter should be raw JPEG data, *not*
546 The return value of this formatter should be raw JPEG data, *not*
544 base64 encoded.
547 base64 encoded.
545 """
548 """
546 format_type = Unicode('image/jpeg')
549 format_type = Unicode('image/jpeg')
547
550
548 print_method = ObjectName('_repr_jpeg_')
551 print_method = ObjectName('_repr_jpeg_')
549
552
550
553
551 class LatexFormatter(BaseFormatter):
554 class LatexFormatter(BaseFormatter):
552 """A LaTeX formatter.
555 """A LaTeX formatter.
553
556
554 To define the callables that compute the LaTeX representation of your
557 To define the callables that compute the LaTeX representation of your
555 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
558 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
556 or :meth:`for_type_by_name` methods to register functions that handle
559 or :meth:`for_type_by_name` methods to register functions that handle
557 this.
560 this.
558
561
559 The return value of this formatter should be a valid LaTeX equation,
562 The return value of this formatter should be a valid LaTeX equation,
560 enclosed in either ```$```, ```$$``` or another LaTeX equation
563 enclosed in either ```$```, ```$$``` or another LaTeX equation
561 environment.
564 environment.
562 """
565 """
563 format_type = Unicode('text/latex')
566 format_type = Unicode('text/latex')
564
567
565 print_method = ObjectName('_repr_latex_')
568 print_method = ObjectName('_repr_latex_')
566
569
567
570
568 class JSONFormatter(BaseFormatter):
571 class JSONFormatter(BaseFormatter):
569 """A JSON string formatter.
572 """A JSON string formatter.
570
573
571 To define the callables that compute the JSON string representation of
574 To define the callables that compute the JSON string representation of
572 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
575 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
573 or :meth:`for_type_by_name` methods to register functions that handle
576 or :meth:`for_type_by_name` methods to register functions that handle
574 this.
577 this.
575
578
576 The return value of this formatter should be a valid JSON string.
579 The return value of this formatter should be a valid JSON string.
577 """
580 """
578 format_type = Unicode('application/json')
581 format_type = Unicode('application/json')
579
582
580 print_method = ObjectName('_repr_json_')
583 print_method = ObjectName('_repr_json_')
581
584
582
585
583 class JavascriptFormatter(BaseFormatter):
586 class JavascriptFormatter(BaseFormatter):
584 """A Javascript formatter.
587 """A Javascript formatter.
585
588
586 To define the callables that compute the Javascript representation of
589 To define the callables that compute the Javascript representation of
587 your objects, define a :meth:`_repr_javascript_` method or use the
590 your objects, define a :meth:`_repr_javascript_` method or use the
588 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
591 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
589 that handle this.
592 that handle this.
590
593
591 The return value of this formatter should be valid Javascript code and
594 The return value of this formatter should be valid Javascript code and
592 should *not* be enclosed in ```<script>``` tags.
595 should *not* be enclosed in ```<script>``` tags.
593 """
596 """
594 format_type = Unicode('application/javascript')
597 format_type = Unicode('application/javascript')
595
598
596 print_method = ObjectName('_repr_javascript_')
599 print_method = ObjectName('_repr_javascript_')
597
600
598 FormatterABC.register(BaseFormatter)
601 FormatterABC.register(BaseFormatter)
599 FormatterABC.register(PlainTextFormatter)
602 FormatterABC.register(PlainTextFormatter)
600 FormatterABC.register(HTMLFormatter)
603 FormatterABC.register(HTMLFormatter)
601 FormatterABC.register(SVGFormatter)
604 FormatterABC.register(SVGFormatter)
602 FormatterABC.register(PNGFormatter)
605 FormatterABC.register(PNGFormatter)
603 FormatterABC.register(JPEGFormatter)
606 FormatterABC.register(JPEGFormatter)
604 FormatterABC.register(LatexFormatter)
607 FormatterABC.register(LatexFormatter)
605 FormatterABC.register(JSONFormatter)
608 FormatterABC.register(JSONFormatter)
606 FormatterABC.register(JavascriptFormatter)
609 FormatterABC.register(JavascriptFormatter)
607
610
608
611
609 def format_display_data(obj, include=None, exclude=None):
612 def format_display_data(obj, include=None, exclude=None):
610 """Return a format data dict for an object.
613 """Return a format data dict for an object.
611
614
612 By default all format types will be computed.
615 By default all format types will be computed.
613
616
614 The following MIME types are currently implemented:
617 The following MIME types are currently implemented:
615
618
616 * text/plain
619 * text/plain
617 * text/html
620 * text/html
618 * text/latex
621 * text/latex
619 * application/json
622 * application/json
620 * application/javascript
623 * application/javascript
621 * image/png
624 * image/png
622 * image/jpeg
625 * image/jpeg
623 * image/svg+xml
626 * image/svg+xml
624
627
625 Parameters
628 Parameters
626 ----------
629 ----------
627 obj : object
630 obj : object
628 The Python object whose format data will be computed.
631 The Python object whose format data will be computed.
629
632
630 Returns
633 Returns
631 -------
634 -------
632 format_dict : dict
635 format_dict : dict
633 A dictionary of key/value pairs, one or each format that was
636 A dictionary of key/value pairs, one or each format that was
634 generated for the object. The keys are the format types, which
637 generated for the object. The keys are the format types, which
635 will usually be MIME type strings and the values and JSON'able
638 will usually be MIME type strings and the values and JSON'able
636 data structure containing the raw data for the representation in
639 data structure containing the raw data for the representation in
637 that format.
640 that format.
638 include : list or tuple, optional
641 include : list or tuple, optional
639 A list of format type strings (MIME types) to include in the
642 A list of format type strings (MIME types) to include in the
640 format data dict. If this is set *only* the format types included
643 format data dict. If this is set *only* the format types included
641 in this list will be computed.
644 in this list will be computed.
642 exclude : list or tuple, optional
645 exclude : list or tuple, optional
643 A list of format type string (MIME types) to exclue in the format
646 A list of format type string (MIME types) to exclue in the format
644 data dict. If this is set all format types will be computed,
647 data dict. If this is set all format types will be computed,
645 except for those included in this argument.
648 except for those included in this argument.
646 """
649 """
647 from IPython.core.interactiveshell import InteractiveShell
650 from IPython.core.interactiveshell import InteractiveShell
648
651
649 InteractiveShell.instance().display_formatter.format(
652 InteractiveShell.instance().display_formatter.format(
650 obj,
653 obj,
651 include,
654 include,
652 exclude
655 exclude
653 )
656 )
654
657
@@ -1,531 +1,535 b''
1 import abc
1 import abc
2 import functools
2 import functools
3 import re
3 import re
4 from io import StringIO
5
4
6 from IPython.core.splitinput import LineInfo
5 from IPython.core.splitinput import LineInfo
7 from IPython.utils import tokenize2
6 from IPython.utils import tokenize2
8 from IPython.utils.openpy import cookie_comment_re
7 from IPython.utils.openpy import cookie_comment_re
9 from IPython.utils.py3compat import with_metaclass
8 from IPython.utils.py3compat import with_metaclass, PY3
10 from IPython.utils.tokenize2 import generate_tokens, untokenize, TokenError
9 from IPython.utils.tokenize2 import generate_tokens, untokenize, TokenError
11
10
11 if PY3:
12 from io import StringIO
13 else:
14 from StringIO import StringIO
15
12 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
13 # Globals
17 # Globals
14 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
15
19
16 # The escape sequences that define the syntax transformations IPython will
20 # The escape sequences that define the syntax transformations IPython will
17 # apply to user input. These can NOT be just changed here: many regular
21 # apply to user input. These can NOT be just changed here: many regular
18 # expressions and other parts of the code may use their hardcoded values, and
22 # expressions and other parts of the code may use their hardcoded values, and
19 # for all intents and purposes they constitute the 'IPython syntax', so they
23 # for all intents and purposes they constitute the 'IPython syntax', so they
20 # should be considered fixed.
24 # should be considered fixed.
21
25
22 ESC_SHELL = '!' # Send line to underlying system shell
26 ESC_SHELL = '!' # Send line to underlying system shell
23 ESC_SH_CAP = '!!' # Send line to system shell and capture output
27 ESC_SH_CAP = '!!' # Send line to system shell and capture output
24 ESC_HELP = '?' # Find information about object
28 ESC_HELP = '?' # Find information about object
25 ESC_HELP2 = '??' # Find extra-detailed information about object
29 ESC_HELP2 = '??' # Find extra-detailed information about object
26 ESC_MAGIC = '%' # Call magic function
30 ESC_MAGIC = '%' # Call magic function
27 ESC_MAGIC2 = '%%' # Call cell-magic function
31 ESC_MAGIC2 = '%%' # Call cell-magic function
28 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
32 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
29 ESC_QUOTE2 = ';' # Quote all args as a single string, call
33 ESC_QUOTE2 = ';' # Quote all args as a single string, call
30 ESC_PAREN = '/' # Call first argument with rest of line as arguments
34 ESC_PAREN = '/' # Call first argument with rest of line as arguments
31
35
32 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
36 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
33 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
37 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
34 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
38 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
35
39
36
40
37 class InputTransformer(with_metaclass(abc.ABCMeta, object)):
41 class InputTransformer(with_metaclass(abc.ABCMeta, object)):
38 """Abstract base class for line-based input transformers."""
42 """Abstract base class for line-based input transformers."""
39
43
40 @abc.abstractmethod
44 @abc.abstractmethod
41 def push(self, line):
45 def push(self, line):
42 """Send a line of input to the transformer, returning the transformed
46 """Send a line of input to the transformer, returning the transformed
43 input or None if the transformer is waiting for more input.
47 input or None if the transformer is waiting for more input.
44
48
45 Must be overridden by subclasses.
49 Must be overridden by subclasses.
46 """
50 """
47 pass
51 pass
48
52
49 @abc.abstractmethod
53 @abc.abstractmethod
50 def reset(self):
54 def reset(self):
51 """Return, transformed any lines that the transformer has accumulated,
55 """Return, transformed any lines that the transformer has accumulated,
52 and reset its internal state.
56 and reset its internal state.
53
57
54 Must be overridden by subclasses.
58 Must be overridden by subclasses.
55 """
59 """
56 pass
60 pass
57
61
58 @classmethod
62 @classmethod
59 def wrap(cls, func):
63 def wrap(cls, func):
60 """Can be used by subclasses as a decorator, to return a factory that
64 """Can be used by subclasses as a decorator, to return a factory that
61 will allow instantiation with the decorated object.
65 will allow instantiation with the decorated object.
62 """
66 """
63 @functools.wraps(func)
67 @functools.wraps(func)
64 def transformer_factory(**kwargs):
68 def transformer_factory(**kwargs):
65 return cls(func, **kwargs)
69 return cls(func, **kwargs)
66
70
67 return transformer_factory
71 return transformer_factory
68
72
69 class StatelessInputTransformer(InputTransformer):
73 class StatelessInputTransformer(InputTransformer):
70 """Wrapper for a stateless input transformer implemented as a function."""
74 """Wrapper for a stateless input transformer implemented as a function."""
71 def __init__(self, func):
75 def __init__(self, func):
72 self.func = func
76 self.func = func
73
77
74 def __repr__(self):
78 def __repr__(self):
75 return "StatelessInputTransformer(func={0!r})".format(self.func)
79 return "StatelessInputTransformer(func={0!r})".format(self.func)
76
80
77 def push(self, line):
81 def push(self, line):
78 """Send a line of input to the transformer, returning the
82 """Send a line of input to the transformer, returning the
79 transformed input."""
83 transformed input."""
80 return self.func(line)
84 return self.func(line)
81
85
82 def reset(self):
86 def reset(self):
83 """No-op - exists for compatibility."""
87 """No-op - exists for compatibility."""
84 pass
88 pass
85
89
86 class CoroutineInputTransformer(InputTransformer):
90 class CoroutineInputTransformer(InputTransformer):
87 """Wrapper for an input transformer implemented as a coroutine."""
91 """Wrapper for an input transformer implemented as a coroutine."""
88 def __init__(self, coro, **kwargs):
92 def __init__(self, coro, **kwargs):
89 # Prime it
93 # Prime it
90 self.coro = coro(**kwargs)
94 self.coro = coro(**kwargs)
91 next(self.coro)
95 next(self.coro)
92
96
93 def __repr__(self):
97 def __repr__(self):
94 return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
98 return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
95
99
96 def push(self, line):
100 def push(self, line):
97 """Send a line of input to the transformer, returning the
101 """Send a line of input to the transformer, returning the
98 transformed input or None if the transformer is waiting for more
102 transformed input or None if the transformer is waiting for more
99 input.
103 input.
100 """
104 """
101 return self.coro.send(line)
105 return self.coro.send(line)
102
106
103 def reset(self):
107 def reset(self):
104 """Return, transformed any lines that the transformer has
108 """Return, transformed any lines that the transformer has
105 accumulated, and reset its internal state.
109 accumulated, and reset its internal state.
106 """
110 """
107 return self.coro.send(None)
111 return self.coro.send(None)
108
112
109 class TokenInputTransformer(InputTransformer):
113 class TokenInputTransformer(InputTransformer):
110 """Wrapper for a token-based input transformer.
114 """Wrapper for a token-based input transformer.
111
115
112 func should accept a list of tokens (5-tuples, see tokenize docs), and
116 func should accept a list of tokens (5-tuples, see tokenize docs), and
113 return an iterable which can be passed to tokenize.untokenize().
117 return an iterable which can be passed to tokenize.untokenize().
114 """
118 """
115 def __init__(self, func):
119 def __init__(self, func):
116 self.func = func
120 self.func = func
117 self.current_line = ""
121 self.current_line = ""
118 self.line_used = False
122 self.line_used = False
119 self.reset_tokenizer()
123 self.reset_tokenizer()
120
124
121 def reset_tokenizer(self):
125 def reset_tokenizer(self):
122 self.tokenizer = generate_tokens(self.get_line)
126 self.tokenizer = generate_tokens(self.get_line)
123
127
124 def get_line(self):
128 def get_line(self):
125 if self.line_used:
129 if self.line_used:
126 raise TokenError
130 raise TokenError
127 self.line_used = True
131 self.line_used = True
128 return self.current_line
132 return self.current_line
129
133
130 def push(self, line):
134 def push(self, line):
131 self.current_line += line + "\n"
135 self.current_line += line + "\n"
132 if self.current_line.isspace():
136 if self.current_line.isspace():
133 return self.reset()
137 return self.reset()
134
138
135 self.line_used = False
139 self.line_used = False
136 tokens = []
140 tokens = []
137 stop_at_NL = False
141 stop_at_NL = False
138 try:
142 try:
139 for intok in self.tokenizer:
143 for intok in self.tokenizer:
140 tokens.append(intok)
144 tokens.append(intok)
141 t = intok[0]
145 t = intok[0]
142 if t == tokenize2.NEWLINE or (stop_at_NL and t == tokenize2.NL):
146 if t == tokenize2.NEWLINE or (stop_at_NL and t == tokenize2.NL):
143 # Stop before we try to pull a line we don't have yet
147 # Stop before we try to pull a line we don't have yet
144 break
148 break
145 elif t == tokenize2.ERRORTOKEN:
149 elif t == tokenize2.ERRORTOKEN:
146 stop_at_NL = True
150 stop_at_NL = True
147 except TokenError:
151 except TokenError:
148 # Multi-line statement - stop and try again with the next line
152 # Multi-line statement - stop and try again with the next line
149 self.reset_tokenizer()
153 self.reset_tokenizer()
150 return None
154 return None
151
155
152 return self.output(tokens)
156 return self.output(tokens)
153
157
154 def output(self, tokens):
158 def output(self, tokens):
155 self.current_line = ""
159 self.current_line = ""
156 self.reset_tokenizer()
160 self.reset_tokenizer()
157 return untokenize(self.func(tokens)).rstrip('\n')
161 return untokenize(self.func(tokens)).rstrip('\n')
158
162
159 def reset(self):
163 def reset(self):
160 l = self.current_line
164 l = self.current_line
161 self.current_line = ""
165 self.current_line = ""
162 self.reset_tokenizer()
166 self.reset_tokenizer()
163 if l:
167 if l:
164 return l.rstrip('\n')
168 return l.rstrip('\n')
165
169
166 class assemble_python_lines(TokenInputTransformer):
170 class assemble_python_lines(TokenInputTransformer):
167 def __init__(self):
171 def __init__(self):
168 super(assemble_python_lines, self).__init__(None)
172 super(assemble_python_lines, self).__init__(None)
169
173
170 def output(self, tokens):
174 def output(self, tokens):
171 return self.reset()
175 return self.reset()
172
176
173 @CoroutineInputTransformer.wrap
177 @CoroutineInputTransformer.wrap
174 def assemble_logical_lines():
178 def assemble_logical_lines():
175 """Join lines following explicit line continuations (\)"""
179 """Join lines following explicit line continuations (\)"""
176 line = ''
180 line = ''
177 while True:
181 while True:
178 line = (yield line)
182 line = (yield line)
179 if not line or line.isspace():
183 if not line or line.isspace():
180 continue
184 continue
181
185
182 parts = []
186 parts = []
183 while line is not None:
187 while line is not None:
184 if line.endswith('\\') and (not has_comment(line)):
188 if line.endswith('\\') and (not has_comment(line)):
185 parts.append(line[:-1])
189 parts.append(line[:-1])
186 line = (yield None) # Get another line
190 line = (yield None) # Get another line
187 else:
191 else:
188 parts.append(line)
192 parts.append(line)
189 break
193 break
190
194
191 # Output
195 # Output
192 line = ''.join(parts)
196 line = ''.join(parts)
193
197
194 # Utilities
198 # Utilities
195 def _make_help_call(target, esc, lspace, next_input=None):
199 def _make_help_call(target, esc, lspace, next_input=None):
196 """Prepares a pinfo(2)/psearch call from a target name and the escape
200 """Prepares a pinfo(2)/psearch call from a target name and the escape
197 (i.e. ? or ??)"""
201 (i.e. ? or ??)"""
198 method = 'pinfo2' if esc == '??' \
202 method = 'pinfo2' if esc == '??' \
199 else 'psearch' if '*' in target \
203 else 'psearch' if '*' in target \
200 else 'pinfo'
204 else 'pinfo'
201 arg = " ".join([method, target])
205 arg = " ".join([method, target])
202 if next_input is None:
206 if next_input is None:
203 return '%sget_ipython().magic(%r)' % (lspace, arg)
207 return '%sget_ipython().magic(%r)' % (lspace, arg)
204 else:
208 else:
205 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
209 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
206 (lspace, next_input, arg)
210 (lspace, next_input, arg)
207
211
208 # These define the transformations for the different escape characters.
212 # These define the transformations for the different escape characters.
209 def _tr_system(line_info):
213 def _tr_system(line_info):
210 "Translate lines escaped with: !"
214 "Translate lines escaped with: !"
211 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
215 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
212 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
216 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
213
217
214 def _tr_system2(line_info):
218 def _tr_system2(line_info):
215 "Translate lines escaped with: !!"
219 "Translate lines escaped with: !!"
216 cmd = line_info.line.lstrip()[2:]
220 cmd = line_info.line.lstrip()[2:]
217 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
221 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
218
222
219 def _tr_help(line_info):
223 def _tr_help(line_info):
220 "Translate lines escaped with: ?/??"
224 "Translate lines escaped with: ?/??"
221 # A naked help line should just fire the intro help screen
225 # A naked help line should just fire the intro help screen
222 if not line_info.line[1:]:
226 if not line_info.line[1:]:
223 return 'get_ipython().show_usage()'
227 return 'get_ipython().show_usage()'
224
228
225 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
229 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
226
230
227 def _tr_magic(line_info):
231 def _tr_magic(line_info):
228 "Translate lines escaped with: %"
232 "Translate lines escaped with: %"
229 tpl = '%sget_ipython().magic(%r)'
233 tpl = '%sget_ipython().magic(%r)'
230 if line_info.line.startswith(ESC_MAGIC2):
234 if line_info.line.startswith(ESC_MAGIC2):
231 return line_info.line
235 return line_info.line
232 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
236 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
233 return tpl % (line_info.pre, cmd)
237 return tpl % (line_info.pre, cmd)
234
238
235 def _tr_quote(line_info):
239 def _tr_quote(line_info):
236 "Translate lines escaped with: ,"
240 "Translate lines escaped with: ,"
237 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
241 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
238 '", "'.join(line_info.the_rest.split()) )
242 '", "'.join(line_info.the_rest.split()) )
239
243
240 def _tr_quote2(line_info):
244 def _tr_quote2(line_info):
241 "Translate lines escaped with: ;"
245 "Translate lines escaped with: ;"
242 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
246 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
243 line_info.the_rest)
247 line_info.the_rest)
244
248
245 def _tr_paren(line_info):
249 def _tr_paren(line_info):
246 "Translate lines escaped with: /"
250 "Translate lines escaped with: /"
247 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
251 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
248 ", ".join(line_info.the_rest.split()))
252 ", ".join(line_info.the_rest.split()))
249
253
250 tr = { ESC_SHELL : _tr_system,
254 tr = { ESC_SHELL : _tr_system,
251 ESC_SH_CAP : _tr_system2,
255 ESC_SH_CAP : _tr_system2,
252 ESC_HELP : _tr_help,
256 ESC_HELP : _tr_help,
253 ESC_HELP2 : _tr_help,
257 ESC_HELP2 : _tr_help,
254 ESC_MAGIC : _tr_magic,
258 ESC_MAGIC : _tr_magic,
255 ESC_QUOTE : _tr_quote,
259 ESC_QUOTE : _tr_quote,
256 ESC_QUOTE2 : _tr_quote2,
260 ESC_QUOTE2 : _tr_quote2,
257 ESC_PAREN : _tr_paren }
261 ESC_PAREN : _tr_paren }
258
262
259 @StatelessInputTransformer.wrap
263 @StatelessInputTransformer.wrap
260 def escaped_commands(line):
264 def escaped_commands(line):
261 """Transform escaped commands - %magic, !system, ?help + various autocalls.
265 """Transform escaped commands - %magic, !system, ?help + various autocalls.
262 """
266 """
263 if not line or line.isspace():
267 if not line or line.isspace():
264 return line
268 return line
265 lineinf = LineInfo(line)
269 lineinf = LineInfo(line)
266 if lineinf.esc not in tr:
270 if lineinf.esc not in tr:
267 return line
271 return line
268
272
269 return tr[lineinf.esc](lineinf)
273 return tr[lineinf.esc](lineinf)
270
274
271 _initial_space_re = re.compile(r'\s*')
275 _initial_space_re = re.compile(r'\s*')
272
276
273 _help_end_re = re.compile(r"""(%{0,2}
277 _help_end_re = re.compile(r"""(%{0,2}
274 [a-zA-Z_*][\w*]* # Variable name
278 [a-zA-Z_*][\w*]* # Variable name
275 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
279 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
276 )
280 )
277 (\?\??)$ # ? or ??
281 (\?\??)$ # ? or ??
278 """,
282 """,
279 re.VERBOSE)
283 re.VERBOSE)
280
284
281 # Extra pseudotokens for multiline strings and data structures
285 # Extra pseudotokens for multiline strings and data structures
282 _MULTILINE_STRING = object()
286 _MULTILINE_STRING = object()
283 _MULTILINE_STRUCTURE = object()
287 _MULTILINE_STRUCTURE = object()
284
288
285 def _line_tokens(line):
289 def _line_tokens(line):
286 """Helper for has_comment and ends_in_comment_or_string."""
290 """Helper for has_comment and ends_in_comment_or_string."""
287 readline = StringIO(line).readline
291 readline = StringIO(line).readline
288 toktypes = set()
292 toktypes = set()
289 try:
293 try:
290 for t in generate_tokens(readline):
294 for t in generate_tokens(readline):
291 toktypes.add(t[0])
295 toktypes.add(t[0])
292 except TokenError as e:
296 except TokenError as e:
293 # There are only two cases where a TokenError is raised.
297 # There are only two cases where a TokenError is raised.
294 if 'multi-line string' in e.args[0]:
298 if 'multi-line string' in e.args[0]:
295 toktypes.add(_MULTILINE_STRING)
299 toktypes.add(_MULTILINE_STRING)
296 else:
300 else:
297 toktypes.add(_MULTILINE_STRUCTURE)
301 toktypes.add(_MULTILINE_STRUCTURE)
298 return toktypes
302 return toktypes
299
303
300 def has_comment(src):
304 def has_comment(src):
301 """Indicate whether an input line has (i.e. ends in, or is) a comment.
305 """Indicate whether an input line has (i.e. ends in, or is) a comment.
302
306
303 This uses tokenize, so it can distinguish comments from # inside strings.
307 This uses tokenize, so it can distinguish comments from # inside strings.
304
308
305 Parameters
309 Parameters
306 ----------
310 ----------
307 src : string
311 src : string
308 A single line input string.
312 A single line input string.
309
313
310 Returns
314 Returns
311 -------
315 -------
312 comment : bool
316 comment : bool
313 True if source has a comment.
317 True if source has a comment.
314 """
318 """
315 return (tokenize2.COMMENT in _line_tokens(src))
319 return (tokenize2.COMMENT in _line_tokens(src))
316
320
317 def ends_in_comment_or_string(src):
321 def ends_in_comment_or_string(src):
318 """Indicates whether or not an input line ends in a comment or within
322 """Indicates whether or not an input line ends in a comment or within
319 a multiline string.
323 a multiline string.
320
324
321 Parameters
325 Parameters
322 ----------
326 ----------
323 src : string
327 src : string
324 A single line input string.
328 A single line input string.
325
329
326 Returns
330 Returns
327 -------
331 -------
328 comment : bool
332 comment : bool
329 True if source ends in a comment or multiline string.
333 True if source ends in a comment or multiline string.
330 """
334 """
331 toktypes = _line_tokens(src)
335 toktypes = _line_tokens(src)
332 return (tokenize2.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
336 return (tokenize2.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
333
337
334
338
335 @StatelessInputTransformer.wrap
339 @StatelessInputTransformer.wrap
336 def help_end(line):
340 def help_end(line):
337 """Translate lines with ?/?? at the end"""
341 """Translate lines with ?/?? at the end"""
338 m = _help_end_re.search(line)
342 m = _help_end_re.search(line)
339 if m is None or ends_in_comment_or_string(line):
343 if m is None or ends_in_comment_or_string(line):
340 return line
344 return line
341 target = m.group(1)
345 target = m.group(1)
342 esc = m.group(3)
346 esc = m.group(3)
343 lspace = _initial_space_re.match(line).group(0)
347 lspace = _initial_space_re.match(line).group(0)
344
348
345 # If we're mid-command, put it back on the next prompt for the user.
349 # If we're mid-command, put it back on the next prompt for the user.
346 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
350 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
347
351
348 return _make_help_call(target, esc, lspace, next_input)
352 return _make_help_call(target, esc, lspace, next_input)
349
353
350
354
351 @CoroutineInputTransformer.wrap
355 @CoroutineInputTransformer.wrap
352 def cellmagic(end_on_blank_line=False):
356 def cellmagic(end_on_blank_line=False):
353 """Captures & transforms cell magics.
357 """Captures & transforms cell magics.
354
358
355 After a cell magic is started, this stores up any lines it gets until it is
359 After a cell magic is started, this stores up any lines it gets until it is
356 reset (sent None).
360 reset (sent None).
357 """
361 """
358 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
362 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
359 cellmagic_help_re = re.compile('%%\w+\?')
363 cellmagic_help_re = re.compile('%%\w+\?')
360 line = ''
364 line = ''
361 while True:
365 while True:
362 line = (yield line)
366 line = (yield line)
363 # consume leading empty lines
367 # consume leading empty lines
364 while not line:
368 while not line:
365 line = (yield line)
369 line = (yield line)
366
370
367 if not line.startswith(ESC_MAGIC2):
371 if not line.startswith(ESC_MAGIC2):
368 # This isn't a cell magic, idle waiting for reset then start over
372 # This isn't a cell magic, idle waiting for reset then start over
369 while line is not None:
373 while line is not None:
370 line = (yield line)
374 line = (yield line)
371 continue
375 continue
372
376
373 if cellmagic_help_re.match(line):
377 if cellmagic_help_re.match(line):
374 # This case will be handled by help_end
378 # This case will be handled by help_end
375 continue
379 continue
376
380
377 first = line
381 first = line
378 body = []
382 body = []
379 line = (yield None)
383 line = (yield None)
380 while (line is not None) and \
384 while (line is not None) and \
381 ((line.strip() != '') or not end_on_blank_line):
385 ((line.strip() != '') or not end_on_blank_line):
382 body.append(line)
386 body.append(line)
383 line = (yield None)
387 line = (yield None)
384
388
385 # Output
389 # Output
386 magic_name, _, first = first.partition(' ')
390 magic_name, _, first = first.partition(' ')
387 magic_name = magic_name.lstrip(ESC_MAGIC2)
391 magic_name = magic_name.lstrip(ESC_MAGIC2)
388 line = tpl % (magic_name, first, u'\n'.join(body))
392 line = tpl % (magic_name, first, u'\n'.join(body))
389
393
390
394
391 def _strip_prompts(prompt_re, initial_re=None):
395 def _strip_prompts(prompt_re, initial_re=None):
392 """Remove matching input prompts from a block of input.
396 """Remove matching input prompts from a block of input.
393
397
394 Parameters
398 Parameters
395 ----------
399 ----------
396 prompt_re : regular expression
400 prompt_re : regular expression
397 A regular expression matching any input prompt (including continuation)
401 A regular expression matching any input prompt (including continuation)
398 initial_re : regular expression, optional
402 initial_re : regular expression, optional
399 A regular expression matching only the initial prompt, but not continuation.
403 A regular expression matching only the initial prompt, but not continuation.
400 If no initial expression is given, prompt_re will be used everywhere.
404 If no initial expression is given, prompt_re will be used everywhere.
401 Used mainly for plain Python prompts, where the continuation prompt
405 Used mainly for plain Python prompts, where the continuation prompt
402 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
406 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
403
407
404 If initial_re and prompt_re differ,
408 If initial_re and prompt_re differ,
405 only initial_re will be tested against the first line.
409 only initial_re will be tested against the first line.
406 If any prompt is found on the first two lines,
410 If any prompt is found on the first two lines,
407 prompts will be stripped from the rest of the block.
411 prompts will be stripped from the rest of the block.
408 """
412 """
409 if initial_re is None:
413 if initial_re is None:
410 initial_re = prompt_re
414 initial_re = prompt_re
411 line = ''
415 line = ''
412 while True:
416 while True:
413 line = (yield line)
417 line = (yield line)
414
418
415 # First line of cell
419 # First line of cell
416 if line is None:
420 if line is None:
417 continue
421 continue
418 out, n1 = initial_re.subn('', line, count=1)
422 out, n1 = initial_re.subn('', line, count=1)
419 line = (yield out)
423 line = (yield out)
420
424
421 if line is None:
425 if line is None:
422 continue
426 continue
423 # check for any prompt on the second line of the cell,
427 # check for any prompt on the second line of the cell,
424 # because people often copy from just after the first prompt,
428 # because people often copy from just after the first prompt,
425 # so we might not see it in the first line.
429 # so we might not see it in the first line.
426 out, n2 = prompt_re.subn('', line, count=1)
430 out, n2 = prompt_re.subn('', line, count=1)
427 line = (yield out)
431 line = (yield out)
428
432
429 if n1 or n2:
433 if n1 or n2:
430 # Found a prompt in the first two lines - check for it in
434 # Found a prompt in the first two lines - check for it in
431 # the rest of the cell as well.
435 # the rest of the cell as well.
432 while line is not None:
436 while line is not None:
433 line = (yield prompt_re.sub('', line, count=1))
437 line = (yield prompt_re.sub('', line, count=1))
434
438
435 else:
439 else:
436 # Prompts not in input - wait for reset
440 # Prompts not in input - wait for reset
437 while line is not None:
441 while line is not None:
438 line = (yield line)
442 line = (yield line)
439
443
440 @CoroutineInputTransformer.wrap
444 @CoroutineInputTransformer.wrap
441 def classic_prompt():
445 def classic_prompt():
442 """Strip the >>>/... prompts of the Python interactive shell."""
446 """Strip the >>>/... prompts of the Python interactive shell."""
443 # FIXME: non-capturing version (?:...) usable?
447 # FIXME: non-capturing version (?:...) usable?
444 prompt_re = re.compile(r'^(>>> ?|\.\.\. ?)')
448 prompt_re = re.compile(r'^(>>> ?|\.\.\. ?)')
445 initial_re = re.compile(r'^(>>> ?)')
449 initial_re = re.compile(r'^(>>> ?)')
446 return _strip_prompts(prompt_re, initial_re)
450 return _strip_prompts(prompt_re, initial_re)
447
451
448 @CoroutineInputTransformer.wrap
452 @CoroutineInputTransformer.wrap
449 def ipy_prompt():
453 def ipy_prompt():
450 """Strip IPython's In [1]:/...: prompts."""
454 """Strip IPython's In [1]:/...: prompts."""
451 # FIXME: non-capturing version (?:...) usable?
455 # FIXME: non-capturing version (?:...) usable?
452 # FIXME: r'^(In \[\d+\]: | {3}\.{3,}: )' clearer?
456 # FIXME: r'^(In \[\d+\]: | {3}\.{3,}: )' clearer?
453 prompt_re = re.compile(r'^(In \[\d+\]: |\ \ \ \.\.\.+: )')
457 prompt_re = re.compile(r'^(In \[\d+\]: |\ \ \ \.\.\.+: )')
454 return _strip_prompts(prompt_re)
458 return _strip_prompts(prompt_re)
455
459
456
460
457 @CoroutineInputTransformer.wrap
461 @CoroutineInputTransformer.wrap
458 def leading_indent():
462 def leading_indent():
459 """Remove leading indentation.
463 """Remove leading indentation.
460
464
461 If the first line starts with a spaces or tabs, the same whitespace will be
465 If the first line starts with a spaces or tabs, the same whitespace will be
462 removed from each following line until it is reset.
466 removed from each following line until it is reset.
463 """
467 """
464 space_re = re.compile(r'^[ \t]+')
468 space_re = re.compile(r'^[ \t]+')
465 line = ''
469 line = ''
466 while True:
470 while True:
467 line = (yield line)
471 line = (yield line)
468
472
469 if line is None:
473 if line is None:
470 continue
474 continue
471
475
472 m = space_re.match(line)
476 m = space_re.match(line)
473 if m:
477 if m:
474 space = m.group(0)
478 space = m.group(0)
475 while line is not None:
479 while line is not None:
476 if line.startswith(space):
480 if line.startswith(space):
477 line = line[len(space):]
481 line = line[len(space):]
478 line = (yield line)
482 line = (yield line)
479 else:
483 else:
480 # No leading spaces - wait for reset
484 # No leading spaces - wait for reset
481 while line is not None:
485 while line is not None:
482 line = (yield line)
486 line = (yield line)
483
487
484
488
485 @CoroutineInputTransformer.wrap
489 @CoroutineInputTransformer.wrap
486 def strip_encoding_cookie():
490 def strip_encoding_cookie():
487 """Remove encoding comment if found in first two lines
491 """Remove encoding comment if found in first two lines
488
492
489 If the first or second line has the `# coding: utf-8` comment,
493 If the first or second line has the `# coding: utf-8` comment,
490 it will be removed.
494 it will be removed.
491 """
495 """
492 line = ''
496 line = ''
493 while True:
497 while True:
494 line = (yield line)
498 line = (yield line)
495 # check comment on first two lines
499 # check comment on first two lines
496 for i in range(2):
500 for i in range(2):
497 if line is None:
501 if line is None:
498 break
502 break
499 if cookie_comment_re.match(line):
503 if cookie_comment_re.match(line):
500 line = (yield "")
504 line = (yield "")
501 else:
505 else:
502 line = (yield line)
506 line = (yield line)
503
507
504 # no-op on the rest of the cell
508 # no-op on the rest of the cell
505 while line is not None:
509 while line is not None:
506 line = (yield line)
510 line = (yield line)
507
511
508
512
509 assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
513 assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
510 r'\s*=\s*!\s*(?P<cmd>.*)')
514 r'\s*=\s*!\s*(?P<cmd>.*)')
511 assign_system_template = '%s = get_ipython().getoutput(%r)'
515 assign_system_template = '%s = get_ipython().getoutput(%r)'
512 @StatelessInputTransformer.wrap
516 @StatelessInputTransformer.wrap
513 def assign_from_system(line):
517 def assign_from_system(line):
514 """Transform assignment from system commands (e.g. files = !ls)"""
518 """Transform assignment from system commands (e.g. files = !ls)"""
515 m = assign_system_re.match(line)
519 m = assign_system_re.match(line)
516 if m is None:
520 if m is None:
517 return line
521 return line
518
522
519 return assign_system_template % m.group('lhs', 'cmd')
523 return assign_system_template % m.group('lhs', 'cmd')
520
524
521 assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
525 assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
522 r'\s*=\s*%\s*(?P<cmd>.*)')
526 r'\s*=\s*%\s*(?P<cmd>.*)')
523 assign_magic_template = '%s = get_ipython().magic(%r)'
527 assign_magic_template = '%s = get_ipython().magic(%r)'
524 @StatelessInputTransformer.wrap
528 @StatelessInputTransformer.wrap
525 def assign_from_magic(line):
529 def assign_from_magic(line):
526 """Transform assignment from magic commands (e.g. a = %who_ls)"""
530 """Transform assignment from magic commands (e.g. a = %who_ls)"""
527 m = assign_magic_re.match(line)
531 m = assign_magic_re.match(line)
528 if m is None:
532 if m is None:
529 return line
533 return line
530
534
531 return assign_magic_template % m.group('lhs', 'cmd')
535 return assign_magic_template % m.group('lhs', 'cmd')
@@ -1,1291 +1,1294 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Implementation of execution-related magic functions.
2 """Implementation of execution-related magic functions.
3 """
3 """
4 from __future__ import print_function
4 from __future__ import print_function
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2012 The IPython Development Team.
6 # Copyright (c) 2012 The IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 # Stdlib
17 # Stdlib
18 import ast
18 import ast
19 import bdb
19 import bdb
20 import os
20 import os
21 import sys
21 import sys
22 import time
22 import time
23 from io import StringIO
24
23
25 # cProfile was added in Python2.5
24 # cProfile was added in Python2.5
26 try:
25 try:
27 import cProfile as profile
26 import cProfile as profile
28 import pstats
27 import pstats
29 except ImportError:
28 except ImportError:
30 # profile isn't bundled by default in Debian for license reasons
29 # profile isn't bundled by default in Debian for license reasons
31 try:
30 try:
32 import profile, pstats
31 import profile, pstats
33 except ImportError:
32 except ImportError:
34 profile = pstats = None
33 profile = pstats = None
35
34
36 # Our own packages
35 # Our own packages
37 from IPython.core import debugger, oinspect
36 from IPython.core import debugger, oinspect
38 from IPython.core import magic_arguments
37 from IPython.core import magic_arguments
39 from IPython.core import page
38 from IPython.core import page
40 from IPython.core.error import UsageError
39 from IPython.core.error import UsageError
41 from IPython.core.macro import Macro
40 from IPython.core.macro import Macro
42 from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,
41 from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic,
43 line_cell_magic, on_off, needs_local_scope)
42 line_cell_magic, on_off, needs_local_scope)
44 from IPython.testing.skipdoctest import skip_doctest
43 from IPython.testing.skipdoctest import skip_doctest
45 from IPython.utils import py3compat
44 from IPython.utils import py3compat
46 from IPython.utils.py3compat import builtin_mod, iteritems
45 from IPython.utils.py3compat import builtin_mod, iteritems, PY3
47 from IPython.utils.contexts import preserve_keys
46 from IPython.utils.contexts import preserve_keys
48 from IPython.utils.io import capture_output
47 from IPython.utils.io import capture_output
49 from IPython.utils.ipstruct import Struct
48 from IPython.utils.ipstruct import Struct
50 from IPython.utils.module_paths import find_mod
49 from IPython.utils.module_paths import find_mod
51 from IPython.utils.path import get_py_filename, unquote_filename, shellglob
50 from IPython.utils.path import get_py_filename, unquote_filename, shellglob
52 from IPython.utils.timing import clock, clock2
51 from IPython.utils.timing import clock, clock2
53 from IPython.utils.warn import warn, error
52 from IPython.utils.warn import warn, error
54
53
54 if PY3:
55 from io import StringIO
56 else:
57 from StringIO import StringIO
55
58
56 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
57 # Magic implementation classes
60 # Magic implementation classes
58 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
59
62
60
63
61 class TimeitResult(object):
64 class TimeitResult(object):
62 """
65 """
63 Object returned by the timeit magic with info about the run.
66 Object returned by the timeit magic with info about the run.
64
67
65 Contain the following attributes :
68 Contain the following attributes :
66
69
67 loops: (int) number of loop done per measurement
70 loops: (int) number of loop done per measurement
68 repeat: (int) number of time the mesurement has been repeated
71 repeat: (int) number of time the mesurement has been repeated
69 best: (float) best execusion time / number
72 best: (float) best execusion time / number
70 all_runs: (list of float) execusion time of each run (in s)
73 all_runs: (list of float) execusion time of each run (in s)
71 compile_time: (float) time of statement compilation (s)
74 compile_time: (float) time of statement compilation (s)
72
75
73 """
76 """
74
77
75 def __init__(self, loops, repeat, best, all_runs, compile_time, precision):
78 def __init__(self, loops, repeat, best, all_runs, compile_time, precision):
76 self.loops = loops
79 self.loops = loops
77 self.repeat = repeat
80 self.repeat = repeat
78 self.best = best
81 self.best = best
79 self.all_runs = all_runs
82 self.all_runs = all_runs
80 self.compile_time = compile_time
83 self.compile_time = compile_time
81 self._precision = precision
84 self._precision = precision
82
85
83 def _repr_pretty_(self, p , cycle):
86 def _repr_pretty_(self, p , cycle):
84 unic = u"%d loops, best of %d: %s per loop" % (self.loops, self.repeat,
87 unic = u"%d loops, best of %d: %s per loop" % (self.loops, self.repeat,
85 _format_time(self.best, self._precision))
88 _format_time(self.best, self._precision))
86 p.text(u'<TimeitResult : '+unic+u'>')
89 p.text(u'<TimeitResult : '+unic+u'>')
87
90
88
91
89 class TimeitTemplateFiller(ast.NodeTransformer):
92 class TimeitTemplateFiller(ast.NodeTransformer):
90 "This is quite tightly tied to the template definition above."
93 "This is quite tightly tied to the template definition above."
91 def __init__(self, ast_setup, ast_stmt):
94 def __init__(self, ast_setup, ast_stmt):
92 self.ast_setup = ast_setup
95 self.ast_setup = ast_setup
93 self.ast_stmt = ast_stmt
96 self.ast_stmt = ast_stmt
94
97
95 def visit_FunctionDef(self, node):
98 def visit_FunctionDef(self, node):
96 "Fill in the setup statement"
99 "Fill in the setup statement"
97 self.generic_visit(node)
100 self.generic_visit(node)
98 if node.name == "inner":
101 if node.name == "inner":
99 node.body[:1] = self.ast_setup.body
102 node.body[:1] = self.ast_setup.body
100
103
101 return node
104 return node
102
105
103 def visit_For(self, node):
106 def visit_For(self, node):
104 "Fill in the statement to be timed"
107 "Fill in the statement to be timed"
105 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
108 if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
106 node.body = self.ast_stmt.body
109 node.body = self.ast_stmt.body
107 return node
110 return node
108
111
109
112
110 @magics_class
113 @magics_class
111 class ExecutionMagics(Magics):
114 class ExecutionMagics(Magics):
112 """Magics related to code execution, debugging, profiling, etc.
115 """Magics related to code execution, debugging, profiling, etc.
113
116
114 """
117 """
115
118
116 def __init__(self, shell):
119 def __init__(self, shell):
117 super(ExecutionMagics, self).__init__(shell)
120 super(ExecutionMagics, self).__init__(shell)
118 if profile is None:
121 if profile is None:
119 self.prun = self.profile_missing_notice
122 self.prun = self.profile_missing_notice
120 # Default execution function used to actually run user code.
123 # Default execution function used to actually run user code.
121 self.default_runner = None
124 self.default_runner = None
122
125
123 def profile_missing_notice(self, *args, **kwargs):
126 def profile_missing_notice(self, *args, **kwargs):
124 error("""\
127 error("""\
125 The profile module could not be found. It has been removed from the standard
128 The profile module could not be found. It has been removed from the standard
126 python packages because of its non-free license. To use profiling, install the
129 python packages because of its non-free license. To use profiling, install the
127 python-profiler package from non-free.""")
130 python-profiler package from non-free.""")
128
131
129 @skip_doctest
132 @skip_doctest
130 @line_cell_magic
133 @line_cell_magic
131 def prun(self, parameter_s='', cell=None):
134 def prun(self, parameter_s='', cell=None):
132
135
133 """Run a statement through the python code profiler.
136 """Run a statement through the python code profiler.
134
137
135 Usage, in line mode:
138 Usage, in line mode:
136 %prun [options] statement
139 %prun [options] statement
137
140
138 Usage, in cell mode:
141 Usage, in cell mode:
139 %%prun [options] [statement]
142 %%prun [options] [statement]
140 code...
143 code...
141 code...
144 code...
142
145
143 In cell mode, the additional code lines are appended to the (possibly
146 In cell mode, the additional code lines are appended to the (possibly
144 empty) statement in the first line. Cell mode allows you to easily
147 empty) statement in the first line. Cell mode allows you to easily
145 profile multiline blocks without having to put them in a separate
148 profile multiline blocks without having to put them in a separate
146 function.
149 function.
147
150
148 The given statement (which doesn't require quote marks) is run via the
151 The given statement (which doesn't require quote marks) is run via the
149 python profiler in a manner similar to the profile.run() function.
152 python profiler in a manner similar to the profile.run() function.
150 Namespaces are internally managed to work correctly; profile.run
153 Namespaces are internally managed to work correctly; profile.run
151 cannot be used in IPython because it makes certain assumptions about
154 cannot be used in IPython because it makes certain assumptions about
152 namespaces which do not hold under IPython.
155 namespaces which do not hold under IPython.
153
156
154 Options:
157 Options:
155
158
156 -l <limit>
159 -l <limit>
157 you can place restrictions on what or how much of the
160 you can place restrictions on what or how much of the
158 profile gets printed. The limit value can be:
161 profile gets printed. The limit value can be:
159
162
160 * A string: only information for function names containing this string
163 * A string: only information for function names containing this string
161 is printed.
164 is printed.
162
165
163 * An integer: only these many lines are printed.
166 * An integer: only these many lines are printed.
164
167
165 * A float (between 0 and 1): this fraction of the report is printed
168 * A float (between 0 and 1): this fraction of the report is printed
166 (for example, use a limit of 0.4 to see the topmost 40% only).
169 (for example, use a limit of 0.4 to see the topmost 40% only).
167
170
168 You can combine several limits with repeated use of the option. For
171 You can combine several limits with repeated use of the option. For
169 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
172 example, ``-l __init__ -l 5`` will print only the topmost 5 lines of
170 information about class constructors.
173 information about class constructors.
171
174
172 -r
175 -r
173 return the pstats.Stats object generated by the profiling. This
176 return the pstats.Stats object generated by the profiling. This
174 object has all the information about the profile in it, and you can
177 object has all the information about the profile in it, and you can
175 later use it for further analysis or in other functions.
178 later use it for further analysis or in other functions.
176
179
177 -s <key>
180 -s <key>
178 sort profile by given key. You can provide more than one key
181 sort profile by given key. You can provide more than one key
179 by using the option several times: '-s key1 -s key2 -s key3...'. The
182 by using the option several times: '-s key1 -s key2 -s key3...'. The
180 default sorting key is 'time'.
183 default sorting key is 'time'.
181
184
182 The following is copied verbatim from the profile documentation
185 The following is copied verbatim from the profile documentation
183 referenced below:
186 referenced below:
184
187
185 When more than one key is provided, additional keys are used as
188 When more than one key is provided, additional keys are used as
186 secondary criteria when the there is equality in all keys selected
189 secondary criteria when the there is equality in all keys selected
187 before them.
190 before them.
188
191
189 Abbreviations can be used for any key names, as long as the
192 Abbreviations can be used for any key names, as long as the
190 abbreviation is unambiguous. The following are the keys currently
193 abbreviation is unambiguous. The following are the keys currently
191 defined:
194 defined:
192
195
193 ============ =====================
196 ============ =====================
194 Valid Arg Meaning
197 Valid Arg Meaning
195 ============ =====================
198 ============ =====================
196 "calls" call count
199 "calls" call count
197 "cumulative" cumulative time
200 "cumulative" cumulative time
198 "file" file name
201 "file" file name
199 "module" file name
202 "module" file name
200 "pcalls" primitive call count
203 "pcalls" primitive call count
201 "line" line number
204 "line" line number
202 "name" function name
205 "name" function name
203 "nfl" name/file/line
206 "nfl" name/file/line
204 "stdname" standard name
207 "stdname" standard name
205 "time" internal time
208 "time" internal time
206 ============ =====================
209 ============ =====================
207
210
208 Note that all sorts on statistics are in descending order (placing
211 Note that all sorts on statistics are in descending order (placing
209 most time consuming items first), where as name, file, and line number
212 most time consuming items first), where as name, file, and line number
210 searches are in ascending order (i.e., alphabetical). The subtle
213 searches are in ascending order (i.e., alphabetical). The subtle
211 distinction between "nfl" and "stdname" is that the standard name is a
214 distinction between "nfl" and "stdname" is that the standard name is a
212 sort of the name as printed, which means that the embedded line
215 sort of the name as printed, which means that the embedded line
213 numbers get compared in an odd way. For example, lines 3, 20, and 40
216 numbers get compared in an odd way. For example, lines 3, 20, and 40
214 would (if the file names were the same) appear in the string order
217 would (if the file names were the same) appear in the string order
215 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
218 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
216 line numbers. In fact, sort_stats("nfl") is the same as
219 line numbers. In fact, sort_stats("nfl") is the same as
217 sort_stats("name", "file", "line").
220 sort_stats("name", "file", "line").
218
221
219 -T <filename>
222 -T <filename>
220 save profile results as shown on screen to a text
223 save profile results as shown on screen to a text
221 file. The profile is still shown on screen.
224 file. The profile is still shown on screen.
222
225
223 -D <filename>
226 -D <filename>
224 save (via dump_stats) profile statistics to given
227 save (via dump_stats) profile statistics to given
225 filename. This data is in a format understood by the pstats module, and
228 filename. This data is in a format understood by the pstats module, and
226 is generated by a call to the dump_stats() method of profile
229 is generated by a call to the dump_stats() method of profile
227 objects. The profile is still shown on screen.
230 objects. The profile is still shown on screen.
228
231
229 -q
232 -q
230 suppress output to the pager. Best used with -T and/or -D above.
233 suppress output to the pager. Best used with -T and/or -D above.
231
234
232 If you want to run complete programs under the profiler's control, use
235 If you want to run complete programs under the profiler's control, use
233 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
236 ``%run -p [prof_opts] filename.py [args to program]`` where prof_opts
234 contains profiler specific options as described here.
237 contains profiler specific options as described here.
235
238
236 You can read the complete documentation for the profile module with::
239 You can read the complete documentation for the profile module with::
237
240
238 In [1]: import profile; profile.help()
241 In [1]: import profile; profile.help()
239 """
242 """
240 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
243 opts, arg_str = self.parse_options(parameter_s, 'D:l:rs:T:q',
241 list_all=True, posix=False)
244 list_all=True, posix=False)
242 if cell is not None:
245 if cell is not None:
243 arg_str += '\n' + cell
246 arg_str += '\n' + cell
244 arg_str = self.shell.input_splitter.transform_cell(arg_str)
247 arg_str = self.shell.input_splitter.transform_cell(arg_str)
245 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
248 return self._run_with_profiler(arg_str, opts, self.shell.user_ns)
246
249
247 def _run_with_profiler(self, code, opts, namespace):
250 def _run_with_profiler(self, code, opts, namespace):
248 """
251 """
249 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
252 Run `code` with profiler. Used by ``%prun`` and ``%run -p``.
250
253
251 Parameters
254 Parameters
252 ----------
255 ----------
253 code : str
256 code : str
254 Code to be executed.
257 Code to be executed.
255 opts : Struct
258 opts : Struct
256 Options parsed by `self.parse_options`.
259 Options parsed by `self.parse_options`.
257 namespace : dict
260 namespace : dict
258 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
261 A dictionary for Python namespace (e.g., `self.shell.user_ns`).
259
262
260 """
263 """
261
264
262 # Fill default values for unspecified options:
265 # Fill default values for unspecified options:
263 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
266 opts.merge(Struct(D=[''], l=[], s=['time'], T=['']))
264
267
265 prof = profile.Profile()
268 prof = profile.Profile()
266 try:
269 try:
267 prof = prof.runctx(code, namespace, namespace)
270 prof = prof.runctx(code, namespace, namespace)
268 sys_exit = ''
271 sys_exit = ''
269 except SystemExit:
272 except SystemExit:
270 sys_exit = """*** SystemExit exception caught in code being profiled."""
273 sys_exit = """*** SystemExit exception caught in code being profiled."""
271
274
272 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
275 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
273
276
274 lims = opts.l
277 lims = opts.l
275 if lims:
278 if lims:
276 lims = [] # rebuild lims with ints/floats/strings
279 lims = [] # rebuild lims with ints/floats/strings
277 for lim in opts.l:
280 for lim in opts.l:
278 try:
281 try:
279 lims.append(int(lim))
282 lims.append(int(lim))
280 except ValueError:
283 except ValueError:
281 try:
284 try:
282 lims.append(float(lim))
285 lims.append(float(lim))
283 except ValueError:
286 except ValueError:
284 lims.append(lim)
287 lims.append(lim)
285
288
286 # Trap output.
289 # Trap output.
287 stdout_trap = StringIO()
290 stdout_trap = StringIO()
288 stats_stream = stats.stream
291 stats_stream = stats.stream
289 try:
292 try:
290 stats.stream = stdout_trap
293 stats.stream = stdout_trap
291 stats.print_stats(*lims)
294 stats.print_stats(*lims)
292 finally:
295 finally:
293 stats.stream = stats_stream
296 stats.stream = stats_stream
294
297
295 output = stdout_trap.getvalue()
298 output = stdout_trap.getvalue()
296 output = output.rstrip()
299 output = output.rstrip()
297
300
298 if 'q' not in opts:
301 if 'q' not in opts:
299 page.page(output)
302 page.page(output)
300 print(sys_exit, end=' ')
303 print(sys_exit, end=' ')
301
304
302 dump_file = opts.D[0]
305 dump_file = opts.D[0]
303 text_file = opts.T[0]
306 text_file = opts.T[0]
304 if dump_file:
307 if dump_file:
305 dump_file = unquote_filename(dump_file)
308 dump_file = unquote_filename(dump_file)
306 prof.dump_stats(dump_file)
309 prof.dump_stats(dump_file)
307 print('\n*** Profile stats marshalled to file',\
310 print('\n*** Profile stats marshalled to file',\
308 repr(dump_file)+'.',sys_exit)
311 repr(dump_file)+'.',sys_exit)
309 if text_file:
312 if text_file:
310 text_file = unquote_filename(text_file)
313 text_file = unquote_filename(text_file)
311 pfile = open(text_file,'w')
314 pfile = open(text_file,'w')
312 pfile.write(output)
315 pfile.write(output)
313 pfile.close()
316 pfile.close()
314 print('\n*** Profile printout saved to text file',\
317 print('\n*** Profile printout saved to text file',\
315 repr(text_file)+'.',sys_exit)
318 repr(text_file)+'.',sys_exit)
316
319
317 if 'r' in opts:
320 if 'r' in opts:
318 return stats
321 return stats
319 else:
322 else:
320 return None
323 return None
321
324
322 @line_magic
325 @line_magic
323 def pdb(self, parameter_s=''):
326 def pdb(self, parameter_s=''):
324 """Control the automatic calling of the pdb interactive debugger.
327 """Control the automatic calling of the pdb interactive debugger.
325
328
326 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
329 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
327 argument it works as a toggle.
330 argument it works as a toggle.
328
331
329 When an exception is triggered, IPython can optionally call the
332 When an exception is triggered, IPython can optionally call the
330 interactive pdb debugger after the traceback printout. %pdb toggles
333 interactive pdb debugger after the traceback printout. %pdb toggles
331 this feature on and off.
334 this feature on and off.
332
335
333 The initial state of this feature is set in your configuration
336 The initial state of this feature is set in your configuration
334 file (the option is ``InteractiveShell.pdb``).
337 file (the option is ``InteractiveShell.pdb``).
335
338
336 If you want to just activate the debugger AFTER an exception has fired,
339 If you want to just activate the debugger AFTER an exception has fired,
337 without having to type '%pdb on' and rerunning your code, you can use
340 without having to type '%pdb on' and rerunning your code, you can use
338 the %debug magic."""
341 the %debug magic."""
339
342
340 par = parameter_s.strip().lower()
343 par = parameter_s.strip().lower()
341
344
342 if par:
345 if par:
343 try:
346 try:
344 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
347 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
345 except KeyError:
348 except KeyError:
346 print ('Incorrect argument. Use on/1, off/0, '
349 print ('Incorrect argument. Use on/1, off/0, '
347 'or nothing for a toggle.')
350 'or nothing for a toggle.')
348 return
351 return
349 else:
352 else:
350 # toggle
353 # toggle
351 new_pdb = not self.shell.call_pdb
354 new_pdb = not self.shell.call_pdb
352
355
353 # set on the shell
356 # set on the shell
354 self.shell.call_pdb = new_pdb
357 self.shell.call_pdb = new_pdb
355 print('Automatic pdb calling has been turned',on_off(new_pdb))
358 print('Automatic pdb calling has been turned',on_off(new_pdb))
356
359
357 @skip_doctest
360 @skip_doctest
358 @magic_arguments.magic_arguments()
361 @magic_arguments.magic_arguments()
359 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
362 @magic_arguments.argument('--breakpoint', '-b', metavar='FILE:LINE',
360 help="""
363 help="""
361 Set break point at LINE in FILE.
364 Set break point at LINE in FILE.
362 """
365 """
363 )
366 )
364 @magic_arguments.argument('statement', nargs='*',
367 @magic_arguments.argument('statement', nargs='*',
365 help="""
368 help="""
366 Code to run in debugger.
369 Code to run in debugger.
367 You can omit this in cell magic mode.
370 You can omit this in cell magic mode.
368 """
371 """
369 )
372 )
370 @line_cell_magic
373 @line_cell_magic
371 def debug(self, line='', cell=None):
374 def debug(self, line='', cell=None):
372 """Activate the interactive debugger.
375 """Activate the interactive debugger.
373
376
374 This magic command support two ways of activating debugger.
377 This magic command support two ways of activating debugger.
375 One is to activate debugger before executing code. This way, you
378 One is to activate debugger before executing code. This way, you
376 can set a break point, to step through the code from the point.
379 can set a break point, to step through the code from the point.
377 You can use this mode by giving statements to execute and optionally
380 You can use this mode by giving statements to execute and optionally
378 a breakpoint.
381 a breakpoint.
379
382
380 The other one is to activate debugger in post-mortem mode. You can
383 The other one is to activate debugger in post-mortem mode. You can
381 activate this mode simply running %debug without any argument.
384 activate this mode simply running %debug without any argument.
382 If an exception has just occurred, this lets you inspect its stack
385 If an exception has just occurred, this lets you inspect its stack
383 frames interactively. Note that this will always work only on the last
386 frames interactively. Note that this will always work only on the last
384 traceback that occurred, so you must call this quickly after an
387 traceback that occurred, so you must call this quickly after an
385 exception that you wish to inspect has fired, because if another one
388 exception that you wish to inspect has fired, because if another one
386 occurs, it clobbers the previous one.
389 occurs, it clobbers the previous one.
387
390
388 If you want IPython to automatically do this on every exception, see
391 If you want IPython to automatically do this on every exception, see
389 the %pdb magic for more details.
392 the %pdb magic for more details.
390 """
393 """
391 args = magic_arguments.parse_argstring(self.debug, line)
394 args = magic_arguments.parse_argstring(self.debug, line)
392
395
393 if not (args.breakpoint or args.statement or cell):
396 if not (args.breakpoint or args.statement or cell):
394 self._debug_post_mortem()
397 self._debug_post_mortem()
395 else:
398 else:
396 code = "\n".join(args.statement)
399 code = "\n".join(args.statement)
397 if cell:
400 if cell:
398 code += "\n" + cell
401 code += "\n" + cell
399 self._debug_exec(code, args.breakpoint)
402 self._debug_exec(code, args.breakpoint)
400
403
401 def _debug_post_mortem(self):
404 def _debug_post_mortem(self):
402 self.shell.debugger(force=True)
405 self.shell.debugger(force=True)
403
406
404 def _debug_exec(self, code, breakpoint):
407 def _debug_exec(self, code, breakpoint):
405 if breakpoint:
408 if breakpoint:
406 (filename, bp_line) = breakpoint.split(':', 1)
409 (filename, bp_line) = breakpoint.split(':', 1)
407 bp_line = int(bp_line)
410 bp_line = int(bp_line)
408 else:
411 else:
409 (filename, bp_line) = (None, None)
412 (filename, bp_line) = (None, None)
410 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
413 self._run_with_debugger(code, self.shell.user_ns, filename, bp_line)
411
414
412 @line_magic
415 @line_magic
413 def tb(self, s):
416 def tb(self, s):
414 """Print the last traceback with the currently active exception mode.
417 """Print the last traceback with the currently active exception mode.
415
418
416 See %xmode for changing exception reporting modes."""
419 See %xmode for changing exception reporting modes."""
417 self.shell.showtraceback()
420 self.shell.showtraceback()
418
421
419 @skip_doctest
422 @skip_doctest
420 @line_magic
423 @line_magic
421 def run(self, parameter_s='', runner=None,
424 def run(self, parameter_s='', runner=None,
422 file_finder=get_py_filename):
425 file_finder=get_py_filename):
423 """Run the named file inside IPython as a program.
426 """Run the named file inside IPython as a program.
424
427
425 Usage::
428 Usage::
426
429
427 %run [-n -i -e -G]
430 %run [-n -i -e -G]
428 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
431 [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )]
429 ( -m mod | file ) [args]
432 ( -m mod | file ) [args]
430
433
431 Parameters after the filename are passed as command-line arguments to
434 Parameters after the filename are passed as command-line arguments to
432 the program (put in sys.argv). Then, control returns to IPython's
435 the program (put in sys.argv). Then, control returns to IPython's
433 prompt.
436 prompt.
434
437
435 This is similar to running at a system prompt ``python file args``,
438 This is similar to running at a system prompt ``python file args``,
436 but with the advantage of giving you IPython's tracebacks, and of
439 but with the advantage of giving you IPython's tracebacks, and of
437 loading all variables into your interactive namespace for further use
440 loading all variables into your interactive namespace for further use
438 (unless -p is used, see below).
441 (unless -p is used, see below).
439
442
440 The file is executed in a namespace initially consisting only of
443 The file is executed in a namespace initially consisting only of
441 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
444 ``__name__=='__main__'`` and sys.argv constructed as indicated. It thus
442 sees its environment as if it were being run as a stand-alone program
445 sees its environment as if it were being run as a stand-alone program
443 (except for sharing global objects such as previously imported
446 (except for sharing global objects such as previously imported
444 modules). But after execution, the IPython interactive namespace gets
447 modules). But after execution, the IPython interactive namespace gets
445 updated with all variables defined in the program (except for __name__
448 updated with all variables defined in the program (except for __name__
446 and sys.argv). This allows for very convenient loading of code for
449 and sys.argv). This allows for very convenient loading of code for
447 interactive work, while giving each program a 'clean sheet' to run in.
450 interactive work, while giving each program a 'clean sheet' to run in.
448
451
449 Arguments are expanded using shell-like glob match. Patterns
452 Arguments are expanded using shell-like glob match. Patterns
450 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
453 '*', '?', '[seq]' and '[!seq]' can be used. Additionally,
451 tilde '~' will be expanded into user's home directory. Unlike
454 tilde '~' will be expanded into user's home directory. Unlike
452 real shells, quotation does not suppress expansions. Use
455 real shells, quotation does not suppress expansions. Use
453 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
456 *two* back slashes (e.g. ``\\\\*``) to suppress expansions.
454 To completely disable these expansions, you can use -G flag.
457 To completely disable these expansions, you can use -G flag.
455
458
456 Options:
459 Options:
457
460
458 -n
461 -n
459 __name__ is NOT set to '__main__', but to the running file's name
462 __name__ is NOT set to '__main__', but to the running file's name
460 without extension (as python does under import). This allows running
463 without extension (as python does under import). This allows running
461 scripts and reloading the definitions in them without calling code
464 scripts and reloading the definitions in them without calling code
462 protected by an ``if __name__ == "__main__"`` clause.
465 protected by an ``if __name__ == "__main__"`` clause.
463
466
464 -i
467 -i
465 run the file in IPython's namespace instead of an empty one. This
468 run the file in IPython's namespace instead of an empty one. This
466 is useful if you are experimenting with code written in a text editor
469 is useful if you are experimenting with code written in a text editor
467 which depends on variables defined interactively.
470 which depends on variables defined interactively.
468
471
469 -e
472 -e
470 ignore sys.exit() calls or SystemExit exceptions in the script
473 ignore sys.exit() calls or SystemExit exceptions in the script
471 being run. This is particularly useful if IPython is being used to
474 being run. This is particularly useful if IPython is being used to
472 run unittests, which always exit with a sys.exit() call. In such
475 run unittests, which always exit with a sys.exit() call. In such
473 cases you are interested in the output of the test results, not in
476 cases you are interested in the output of the test results, not in
474 seeing a traceback of the unittest module.
477 seeing a traceback of the unittest module.
475
478
476 -t
479 -t
477 print timing information at the end of the run. IPython will give
480 print timing information at the end of the run. IPython will give
478 you an estimated CPU time consumption for your script, which under
481 you an estimated CPU time consumption for your script, which under
479 Unix uses the resource module to avoid the wraparound problems of
482 Unix uses the resource module to avoid the wraparound problems of
480 time.clock(). Under Unix, an estimate of time spent on system tasks
483 time.clock(). Under Unix, an estimate of time spent on system tasks
481 is also given (for Windows platforms this is reported as 0.0).
484 is also given (for Windows platforms this is reported as 0.0).
482
485
483 If -t is given, an additional ``-N<N>`` option can be given, where <N>
486 If -t is given, an additional ``-N<N>`` option can be given, where <N>
484 must be an integer indicating how many times you want the script to
487 must be an integer indicating how many times you want the script to
485 run. The final timing report will include total and per run results.
488 run. The final timing report will include total and per run results.
486
489
487 For example (testing the script uniq_stable.py)::
490 For example (testing the script uniq_stable.py)::
488
491
489 In [1]: run -t uniq_stable
492 In [1]: run -t uniq_stable
490
493
491 IPython CPU timings (estimated):
494 IPython CPU timings (estimated):
492 User : 0.19597 s.
495 User : 0.19597 s.
493 System: 0.0 s.
496 System: 0.0 s.
494
497
495 In [2]: run -t -N5 uniq_stable
498 In [2]: run -t -N5 uniq_stable
496
499
497 IPython CPU timings (estimated):
500 IPython CPU timings (estimated):
498 Total runs performed: 5
501 Total runs performed: 5
499 Times : Total Per run
502 Times : Total Per run
500 User : 0.910862 s, 0.1821724 s.
503 User : 0.910862 s, 0.1821724 s.
501 System: 0.0 s, 0.0 s.
504 System: 0.0 s, 0.0 s.
502
505
503 -d
506 -d
504 run your program under the control of pdb, the Python debugger.
507 run your program under the control of pdb, the Python debugger.
505 This allows you to execute your program step by step, watch variables,
508 This allows you to execute your program step by step, watch variables,
506 etc. Internally, what IPython does is similar to calling::
509 etc. Internally, what IPython does is similar to calling::
507
510
508 pdb.run('execfile("YOURFILENAME")')
511 pdb.run('execfile("YOURFILENAME")')
509
512
510 with a breakpoint set on line 1 of your file. You can change the line
513 with a breakpoint set on line 1 of your file. You can change the line
511 number for this automatic breakpoint to be <N> by using the -bN option
514 number for this automatic breakpoint to be <N> by using the -bN option
512 (where N must be an integer). For example::
515 (where N must be an integer). For example::
513
516
514 %run -d -b40 myscript
517 %run -d -b40 myscript
515
518
516 will set the first breakpoint at line 40 in myscript.py. Note that
519 will set the first breakpoint at line 40 in myscript.py. Note that
517 the first breakpoint must be set on a line which actually does
520 the first breakpoint must be set on a line which actually does
518 something (not a comment or docstring) for it to stop execution.
521 something (not a comment or docstring) for it to stop execution.
519
522
520 Or you can specify a breakpoint in a different file::
523 Or you can specify a breakpoint in a different file::
521
524
522 %run -d -b myotherfile.py:20 myscript
525 %run -d -b myotherfile.py:20 myscript
523
526
524 When the pdb debugger starts, you will see a (Pdb) prompt. You must
527 When the pdb debugger starts, you will see a (Pdb) prompt. You must
525 first enter 'c' (without quotes) to start execution up to the first
528 first enter 'c' (without quotes) to start execution up to the first
526 breakpoint.
529 breakpoint.
527
530
528 Entering 'help' gives information about the use of the debugger. You
531 Entering 'help' gives information about the use of the debugger. You
529 can easily see pdb's full documentation with "import pdb;pdb.help()"
532 can easily see pdb's full documentation with "import pdb;pdb.help()"
530 at a prompt.
533 at a prompt.
531
534
532 -p
535 -p
533 run program under the control of the Python profiler module (which
536 run program under the control of the Python profiler module (which
534 prints a detailed report of execution times, function calls, etc).
537 prints a detailed report of execution times, function calls, etc).
535
538
536 You can pass other options after -p which affect the behavior of the
539 You can pass other options after -p which affect the behavior of the
537 profiler itself. See the docs for %prun for details.
540 profiler itself. See the docs for %prun for details.
538
541
539 In this mode, the program's variables do NOT propagate back to the
542 In this mode, the program's variables do NOT propagate back to the
540 IPython interactive namespace (because they remain in the namespace
543 IPython interactive namespace (because they remain in the namespace
541 where the profiler executes them).
544 where the profiler executes them).
542
545
543 Internally this triggers a call to %prun, see its documentation for
546 Internally this triggers a call to %prun, see its documentation for
544 details on the options available specifically for profiling.
547 details on the options available specifically for profiling.
545
548
546 There is one special usage for which the text above doesn't apply:
549 There is one special usage for which the text above doesn't apply:
547 if the filename ends with .ipy, the file is run as ipython script,
550 if the filename ends with .ipy, the file is run as ipython script,
548 just as if the commands were written on IPython prompt.
551 just as if the commands were written on IPython prompt.
549
552
550 -m
553 -m
551 specify module name to load instead of script path. Similar to
554 specify module name to load instead of script path. Similar to
552 the -m option for the python interpreter. Use this option last if you
555 the -m option for the python interpreter. Use this option last if you
553 want to combine with other %run options. Unlike the python interpreter
556 want to combine with other %run options. Unlike the python interpreter
554 only source modules are allowed no .pyc or .pyo files.
557 only source modules are allowed no .pyc or .pyo files.
555 For example::
558 For example::
556
559
557 %run -m example
560 %run -m example
558
561
559 will run the example module.
562 will run the example module.
560
563
561 -G
564 -G
562 disable shell-like glob expansion of arguments.
565 disable shell-like glob expansion of arguments.
563
566
564 """
567 """
565
568
566 # get arguments and set sys.argv for program to be run.
569 # get arguments and set sys.argv for program to be run.
567 opts, arg_lst = self.parse_options(parameter_s,
570 opts, arg_lst = self.parse_options(parameter_s,
568 'nidtN:b:pD:l:rs:T:em:G',
571 'nidtN:b:pD:l:rs:T:em:G',
569 mode='list', list_all=1)
572 mode='list', list_all=1)
570 if "m" in opts:
573 if "m" in opts:
571 modulename = opts["m"][0]
574 modulename = opts["m"][0]
572 modpath = find_mod(modulename)
575 modpath = find_mod(modulename)
573 if modpath is None:
576 if modpath is None:
574 warn('%r is not a valid modulename on sys.path'%modulename)
577 warn('%r is not a valid modulename on sys.path'%modulename)
575 return
578 return
576 arg_lst = [modpath] + arg_lst
579 arg_lst = [modpath] + arg_lst
577 try:
580 try:
578 filename = file_finder(arg_lst[0])
581 filename = file_finder(arg_lst[0])
579 except IndexError:
582 except IndexError:
580 warn('you must provide at least a filename.')
583 warn('you must provide at least a filename.')
581 print('\n%run:\n', oinspect.getdoc(self.run))
584 print('\n%run:\n', oinspect.getdoc(self.run))
582 return
585 return
583 except IOError as e:
586 except IOError as e:
584 try:
587 try:
585 msg = str(e)
588 msg = str(e)
586 except UnicodeError:
589 except UnicodeError:
587 msg = e.message
590 msg = e.message
588 error(msg)
591 error(msg)
589 return
592 return
590
593
591 if filename.lower().endswith('.ipy'):
594 if filename.lower().endswith('.ipy'):
592 with preserve_keys(self.shell.user_ns, '__file__'):
595 with preserve_keys(self.shell.user_ns, '__file__'):
593 self.shell.user_ns['__file__'] = filename
596 self.shell.user_ns['__file__'] = filename
594 self.shell.safe_execfile_ipy(filename)
597 self.shell.safe_execfile_ipy(filename)
595 return
598 return
596
599
597 # Control the response to exit() calls made by the script being run
600 # Control the response to exit() calls made by the script being run
598 exit_ignore = 'e' in opts
601 exit_ignore = 'e' in opts
599
602
600 # Make sure that the running script gets a proper sys.argv as if it
603 # Make sure that the running script gets a proper sys.argv as if it
601 # were run from a system shell.
604 # were run from a system shell.
602 save_argv = sys.argv # save it for later restoring
605 save_argv = sys.argv # save it for later restoring
603
606
604 if 'G' in opts:
607 if 'G' in opts:
605 args = arg_lst[1:]
608 args = arg_lst[1:]
606 else:
609 else:
607 # tilde and glob expansion
610 # tilde and glob expansion
608 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
611 args = shellglob(map(os.path.expanduser, arg_lst[1:]))
609
612
610 sys.argv = [filename] + args # put in the proper filename
613 sys.argv = [filename] + args # put in the proper filename
611 # protect sys.argv from potential unicode strings on Python 2:
614 # protect sys.argv from potential unicode strings on Python 2:
612 if not py3compat.PY3:
615 if not py3compat.PY3:
613 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
616 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
614
617
615 if 'i' in opts:
618 if 'i' in opts:
616 # Run in user's interactive namespace
619 # Run in user's interactive namespace
617 prog_ns = self.shell.user_ns
620 prog_ns = self.shell.user_ns
618 __name__save = self.shell.user_ns['__name__']
621 __name__save = self.shell.user_ns['__name__']
619 prog_ns['__name__'] = '__main__'
622 prog_ns['__name__'] = '__main__'
620 main_mod = self.shell.user_module
623 main_mod = self.shell.user_module
621
624
622 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
625 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
623 # set the __file__ global in the script's namespace
626 # set the __file__ global in the script's namespace
624 # TK: Is this necessary in interactive mode?
627 # TK: Is this necessary in interactive mode?
625 prog_ns['__file__'] = filename
628 prog_ns['__file__'] = filename
626 else:
629 else:
627 # Run in a fresh, empty namespace
630 # Run in a fresh, empty namespace
628 if 'n' in opts:
631 if 'n' in opts:
629 name = os.path.splitext(os.path.basename(filename))[0]
632 name = os.path.splitext(os.path.basename(filename))[0]
630 else:
633 else:
631 name = '__main__'
634 name = '__main__'
632
635
633 # The shell MUST hold a reference to prog_ns so after %run
636 # The shell MUST hold a reference to prog_ns so after %run
634 # exits, the python deletion mechanism doesn't zero it out
637 # exits, the python deletion mechanism doesn't zero it out
635 # (leaving dangling references). See interactiveshell for details
638 # (leaving dangling references). See interactiveshell for details
636 main_mod = self.shell.new_main_mod(filename, name)
639 main_mod = self.shell.new_main_mod(filename, name)
637 prog_ns = main_mod.__dict__
640 prog_ns = main_mod.__dict__
638
641
639 # pickle fix. See interactiveshell for an explanation. But we need to
642 # pickle fix. See interactiveshell for an explanation. But we need to
640 # make sure that, if we overwrite __main__, we replace it at the end
643 # make sure that, if we overwrite __main__, we replace it at the end
641 main_mod_name = prog_ns['__name__']
644 main_mod_name = prog_ns['__name__']
642
645
643 if main_mod_name == '__main__':
646 if main_mod_name == '__main__':
644 restore_main = sys.modules['__main__']
647 restore_main = sys.modules['__main__']
645 else:
648 else:
646 restore_main = False
649 restore_main = False
647
650
648 # This needs to be undone at the end to prevent holding references to
651 # This needs to be undone at the end to prevent holding references to
649 # every single object ever created.
652 # every single object ever created.
650 sys.modules[main_mod_name] = main_mod
653 sys.modules[main_mod_name] = main_mod
651
654
652 if 'p' in opts or 'd' in opts:
655 if 'p' in opts or 'd' in opts:
653 if 'm' in opts:
656 if 'm' in opts:
654 code = 'run_module(modulename, prog_ns)'
657 code = 'run_module(modulename, prog_ns)'
655 code_ns = {
658 code_ns = {
656 'run_module': self.shell.safe_run_module,
659 'run_module': self.shell.safe_run_module,
657 'prog_ns': prog_ns,
660 'prog_ns': prog_ns,
658 'modulename': modulename,
661 'modulename': modulename,
659 }
662 }
660 else:
663 else:
661 code = 'execfile(filename, prog_ns)'
664 code = 'execfile(filename, prog_ns)'
662 code_ns = {
665 code_ns = {
663 'execfile': self.shell.safe_execfile,
666 'execfile': self.shell.safe_execfile,
664 'prog_ns': prog_ns,
667 'prog_ns': prog_ns,
665 'filename': get_py_filename(filename),
668 'filename': get_py_filename(filename),
666 }
669 }
667
670
668 try:
671 try:
669 stats = None
672 stats = None
670 with self.shell.readline_no_record:
673 with self.shell.readline_no_record:
671 if 'p' in opts:
674 if 'p' in opts:
672 stats = self._run_with_profiler(code, opts, code_ns)
675 stats = self._run_with_profiler(code, opts, code_ns)
673 else:
676 else:
674 if 'd' in opts:
677 if 'd' in opts:
675 bp_file, bp_line = parse_breakpoint(
678 bp_file, bp_line = parse_breakpoint(
676 opts.get('b', ['1'])[0], filename)
679 opts.get('b', ['1'])[0], filename)
677 self._run_with_debugger(
680 self._run_with_debugger(
678 code, code_ns, filename, bp_line, bp_file)
681 code, code_ns, filename, bp_line, bp_file)
679 else:
682 else:
680 if 'm' in opts:
683 if 'm' in opts:
681 def run():
684 def run():
682 self.shell.safe_run_module(modulename, prog_ns)
685 self.shell.safe_run_module(modulename, prog_ns)
683 else:
686 else:
684 if runner is None:
687 if runner is None:
685 runner = self.default_runner
688 runner = self.default_runner
686 if runner is None:
689 if runner is None:
687 runner = self.shell.safe_execfile
690 runner = self.shell.safe_execfile
688
691
689 def run():
692 def run():
690 runner(filename, prog_ns, prog_ns,
693 runner(filename, prog_ns, prog_ns,
691 exit_ignore=exit_ignore)
694 exit_ignore=exit_ignore)
692
695
693 if 't' in opts:
696 if 't' in opts:
694 # timed execution
697 # timed execution
695 try:
698 try:
696 nruns = int(opts['N'][0])
699 nruns = int(opts['N'][0])
697 if nruns < 1:
700 if nruns < 1:
698 error('Number of runs must be >=1')
701 error('Number of runs must be >=1')
699 return
702 return
700 except (KeyError):
703 except (KeyError):
701 nruns = 1
704 nruns = 1
702 self._run_with_timing(run, nruns)
705 self._run_with_timing(run, nruns)
703 else:
706 else:
704 # regular execution
707 # regular execution
705 run()
708 run()
706
709
707 if 'i' in opts:
710 if 'i' in opts:
708 self.shell.user_ns['__name__'] = __name__save
711 self.shell.user_ns['__name__'] = __name__save
709 else:
712 else:
710 # update IPython interactive namespace
713 # update IPython interactive namespace
711
714
712 # Some forms of read errors on the file may mean the
715 # Some forms of read errors on the file may mean the
713 # __name__ key was never set; using pop we don't have to
716 # __name__ key was never set; using pop we don't have to
714 # worry about a possible KeyError.
717 # worry about a possible KeyError.
715 prog_ns.pop('__name__', None)
718 prog_ns.pop('__name__', None)
716
719
717 with preserve_keys(self.shell.user_ns, '__file__'):
720 with preserve_keys(self.shell.user_ns, '__file__'):
718 self.shell.user_ns.update(prog_ns)
721 self.shell.user_ns.update(prog_ns)
719 finally:
722 finally:
720 # It's a bit of a mystery why, but __builtins__ can change from
723 # It's a bit of a mystery why, but __builtins__ can change from
721 # being a module to becoming a dict missing some key data after
724 # being a module to becoming a dict missing some key data after
722 # %run. As best I can see, this is NOT something IPython is doing
725 # %run. As best I can see, this is NOT something IPython is doing
723 # at all, and similar problems have been reported before:
726 # at all, and similar problems have been reported before:
724 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
727 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
725 # Since this seems to be done by the interpreter itself, the best
728 # Since this seems to be done by the interpreter itself, the best
726 # we can do is to at least restore __builtins__ for the user on
729 # we can do is to at least restore __builtins__ for the user on
727 # exit.
730 # exit.
728 self.shell.user_ns['__builtins__'] = builtin_mod
731 self.shell.user_ns['__builtins__'] = builtin_mod
729
732
730 # Ensure key global structures are restored
733 # Ensure key global structures are restored
731 sys.argv = save_argv
734 sys.argv = save_argv
732 if restore_main:
735 if restore_main:
733 sys.modules['__main__'] = restore_main
736 sys.modules['__main__'] = restore_main
734 else:
737 else:
735 # Remove from sys.modules the reference to main_mod we'd
738 # Remove from sys.modules the reference to main_mod we'd
736 # added. Otherwise it will trap references to objects
739 # added. Otherwise it will trap references to objects
737 # contained therein.
740 # contained therein.
738 del sys.modules[main_mod_name]
741 del sys.modules[main_mod_name]
739
742
740 return stats
743 return stats
741
744
742 def _run_with_debugger(self, code, code_ns, filename=None,
745 def _run_with_debugger(self, code, code_ns, filename=None,
743 bp_line=None, bp_file=None):
746 bp_line=None, bp_file=None):
744 """
747 """
745 Run `code` in debugger with a break point.
748 Run `code` in debugger with a break point.
746
749
747 Parameters
750 Parameters
748 ----------
751 ----------
749 code : str
752 code : str
750 Code to execute.
753 Code to execute.
751 code_ns : dict
754 code_ns : dict
752 A namespace in which `code` is executed.
755 A namespace in which `code` is executed.
753 filename : str
756 filename : str
754 `code` is ran as if it is in `filename`.
757 `code` is ran as if it is in `filename`.
755 bp_line : int, optional
758 bp_line : int, optional
756 Line number of the break point.
759 Line number of the break point.
757 bp_file : str, optional
760 bp_file : str, optional
758 Path to the file in which break point is specified.
761 Path to the file in which break point is specified.
759 `filename` is used if not given.
762 `filename` is used if not given.
760
763
761 Raises
764 Raises
762 ------
765 ------
763 UsageError
766 UsageError
764 If the break point given by `bp_line` is not valid.
767 If the break point given by `bp_line` is not valid.
765
768
766 """
769 """
767 deb = debugger.Pdb(self.shell.colors)
770 deb = debugger.Pdb(self.shell.colors)
768 # reset Breakpoint state, which is moronically kept
771 # reset Breakpoint state, which is moronically kept
769 # in a class
772 # in a class
770 bdb.Breakpoint.next = 1
773 bdb.Breakpoint.next = 1
771 bdb.Breakpoint.bplist = {}
774 bdb.Breakpoint.bplist = {}
772 bdb.Breakpoint.bpbynumber = [None]
775 bdb.Breakpoint.bpbynumber = [None]
773 if bp_line is not None:
776 if bp_line is not None:
774 # Set an initial breakpoint to stop execution
777 # Set an initial breakpoint to stop execution
775 maxtries = 10
778 maxtries = 10
776 bp_file = bp_file or filename
779 bp_file = bp_file or filename
777 checkline = deb.checkline(bp_file, bp_line)
780 checkline = deb.checkline(bp_file, bp_line)
778 if not checkline:
781 if not checkline:
779 for bp in range(bp_line + 1, bp_line + maxtries + 1):
782 for bp in range(bp_line + 1, bp_line + maxtries + 1):
780 if deb.checkline(bp_file, bp):
783 if deb.checkline(bp_file, bp):
781 break
784 break
782 else:
785 else:
783 msg = ("\nI failed to find a valid line to set "
786 msg = ("\nI failed to find a valid line to set "
784 "a breakpoint\n"
787 "a breakpoint\n"
785 "after trying up to line: %s.\n"
788 "after trying up to line: %s.\n"
786 "Please set a valid breakpoint manually "
789 "Please set a valid breakpoint manually "
787 "with the -b option." % bp)
790 "with the -b option." % bp)
788 raise UsageError(msg)
791 raise UsageError(msg)
789 # if we find a good linenumber, set the breakpoint
792 # if we find a good linenumber, set the breakpoint
790 deb.do_break('%s:%s' % (bp_file, bp_line))
793 deb.do_break('%s:%s' % (bp_file, bp_line))
791
794
792 if filename:
795 if filename:
793 # Mimic Pdb._runscript(...)
796 # Mimic Pdb._runscript(...)
794 deb._wait_for_mainpyfile = True
797 deb._wait_for_mainpyfile = True
795 deb.mainpyfile = deb.canonic(filename)
798 deb.mainpyfile = deb.canonic(filename)
796
799
797 # Start file run
800 # Start file run
798 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
801 print("NOTE: Enter 'c' at the %s prompt to continue execution." % deb.prompt)
799 try:
802 try:
800 if filename:
803 if filename:
801 # save filename so it can be used by methods on the deb object
804 # save filename so it can be used by methods on the deb object
802 deb._exec_filename = filename
805 deb._exec_filename = filename
803 deb.run(code, code_ns)
806 deb.run(code, code_ns)
804
807
805 except:
808 except:
806 etype, value, tb = sys.exc_info()
809 etype, value, tb = sys.exc_info()
807 # Skip three frames in the traceback: the %run one,
810 # Skip three frames in the traceback: the %run one,
808 # one inside bdb.py, and the command-line typed by the
811 # one inside bdb.py, and the command-line typed by the
809 # user (run by exec in pdb itself).
812 # user (run by exec in pdb itself).
810 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
813 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
811
814
812 @staticmethod
815 @staticmethod
813 def _run_with_timing(run, nruns):
816 def _run_with_timing(run, nruns):
814 """
817 """
815 Run function `run` and print timing information.
818 Run function `run` and print timing information.
816
819
817 Parameters
820 Parameters
818 ----------
821 ----------
819 run : callable
822 run : callable
820 Any callable object which takes no argument.
823 Any callable object which takes no argument.
821 nruns : int
824 nruns : int
822 Number of times to execute `run`.
825 Number of times to execute `run`.
823
826
824 """
827 """
825 twall0 = time.time()
828 twall0 = time.time()
826 if nruns == 1:
829 if nruns == 1:
827 t0 = clock2()
830 t0 = clock2()
828 run()
831 run()
829 t1 = clock2()
832 t1 = clock2()
830 t_usr = t1[0] - t0[0]
833 t_usr = t1[0] - t0[0]
831 t_sys = t1[1] - t0[1]
834 t_sys = t1[1] - t0[1]
832 print("\nIPython CPU timings (estimated):")
835 print("\nIPython CPU timings (estimated):")
833 print(" User : %10.2f s." % t_usr)
836 print(" User : %10.2f s." % t_usr)
834 print(" System : %10.2f s." % t_sys)
837 print(" System : %10.2f s." % t_sys)
835 else:
838 else:
836 runs = range(nruns)
839 runs = range(nruns)
837 t0 = clock2()
840 t0 = clock2()
838 for nr in runs:
841 for nr in runs:
839 run()
842 run()
840 t1 = clock2()
843 t1 = clock2()
841 t_usr = t1[0] - t0[0]
844 t_usr = t1[0] - t0[0]
842 t_sys = t1[1] - t0[1]
845 t_sys = t1[1] - t0[1]
843 print("\nIPython CPU timings (estimated):")
846 print("\nIPython CPU timings (estimated):")
844 print("Total runs performed:", nruns)
847 print("Total runs performed:", nruns)
845 print(" Times : %10s %10s" % ('Total', 'Per run'))
848 print(" Times : %10s %10s" % ('Total', 'Per run'))
846 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
849 print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns))
847 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
850 print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns))
848 twall1 = time.time()
851 twall1 = time.time()
849 print("Wall time: %10.2f s." % (twall1 - twall0))
852 print("Wall time: %10.2f s." % (twall1 - twall0))
850
853
851 @skip_doctest
854 @skip_doctest
852 @line_cell_magic
855 @line_cell_magic
853 def timeit(self, line='', cell=None):
856 def timeit(self, line='', cell=None):
854 """Time execution of a Python statement or expression
857 """Time execution of a Python statement or expression
855
858
856 Usage, in line mode:
859 Usage, in line mode:
857 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
860 %timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
858 or in cell mode:
861 or in cell mode:
859 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
862 %%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code
860 code
863 code
861 code...
864 code...
862
865
863 Time execution of a Python statement or expression using the timeit
866 Time execution of a Python statement or expression using the timeit
864 module. This function can be used both as a line and cell magic:
867 module. This function can be used both as a line and cell magic:
865
868
866 - In line mode you can time a single-line statement (though multiple
869 - In line mode you can time a single-line statement (though multiple
867 ones can be chained with using semicolons).
870 ones can be chained with using semicolons).
868
871
869 - In cell mode, the statement in the first line is used as setup code
872 - In cell mode, the statement in the first line is used as setup code
870 (executed but not timed) and the body of the cell is timed. The cell
873 (executed but not timed) and the body of the cell is timed. The cell
871 body has access to any variables created in the setup code.
874 body has access to any variables created in the setup code.
872
875
873 Options:
876 Options:
874 -n<N>: execute the given statement <N> times in a loop. If this value
877 -n<N>: execute the given statement <N> times in a loop. If this value
875 is not given, a fitting value is chosen.
878 is not given, a fitting value is chosen.
876
879
877 -r<R>: repeat the loop iteration <R> times and take the best result.
880 -r<R>: repeat the loop iteration <R> times and take the best result.
878 Default: 3
881 Default: 3
879
882
880 -t: use time.time to measure the time, which is the default on Unix.
883 -t: use time.time to measure the time, which is the default on Unix.
881 This function measures wall time.
884 This function measures wall time.
882
885
883 -c: use time.clock to measure the time, which is the default on
886 -c: use time.clock to measure the time, which is the default on
884 Windows and measures wall time. On Unix, resource.getrusage is used
887 Windows and measures wall time. On Unix, resource.getrusage is used
885 instead and returns the CPU user time.
888 instead and returns the CPU user time.
886
889
887 -p<P>: use a precision of <P> digits to display the timing result.
890 -p<P>: use a precision of <P> digits to display the timing result.
888 Default: 3
891 Default: 3
889
892
890 -q: Quiet, do not print result.
893 -q: Quiet, do not print result.
891
894
892 -o: return a TimeitResult that can be stored in a variable to inspect
895 -o: return a TimeitResult that can be stored in a variable to inspect
893 the result in more details.
896 the result in more details.
894
897
895
898
896 Examples
899 Examples
897 --------
900 --------
898 ::
901 ::
899
902
900 In [1]: %timeit pass
903 In [1]: %timeit pass
901 10000000 loops, best of 3: 53.3 ns per loop
904 10000000 loops, best of 3: 53.3 ns per loop
902
905
903 In [2]: u = None
906 In [2]: u = None
904
907
905 In [3]: %timeit u is None
908 In [3]: %timeit u is None
906 10000000 loops, best of 3: 184 ns per loop
909 10000000 loops, best of 3: 184 ns per loop
907
910
908 In [4]: %timeit -r 4 u == None
911 In [4]: %timeit -r 4 u == None
909 1000000 loops, best of 4: 242 ns per loop
912 1000000 loops, best of 4: 242 ns per loop
910
913
911 In [5]: import time
914 In [5]: import time
912
915
913 In [6]: %timeit -n1 time.sleep(2)
916 In [6]: %timeit -n1 time.sleep(2)
914 1 loops, best of 3: 2 s per loop
917 1 loops, best of 3: 2 s per loop
915
918
916
919
917 The times reported by %timeit will be slightly higher than those
920 The times reported by %timeit will be slightly higher than those
918 reported by the timeit.py script when variables are accessed. This is
921 reported by the timeit.py script when variables are accessed. This is
919 due to the fact that %timeit executes the statement in the namespace
922 due to the fact that %timeit executes the statement in the namespace
920 of the shell, compared with timeit.py, which uses a single setup
923 of the shell, compared with timeit.py, which uses a single setup
921 statement to import function or create variables. Generally, the bias
924 statement to import function or create variables. Generally, the bias
922 does not matter as long as results from timeit.py are not mixed with
925 does not matter as long as results from timeit.py are not mixed with
923 those from %timeit."""
926 those from %timeit."""
924
927
925 import timeit
928 import timeit
926
929
927 opts, stmt = self.parse_options(line,'n:r:tcp:qo',
930 opts, stmt = self.parse_options(line,'n:r:tcp:qo',
928 posix=False, strict=False)
931 posix=False, strict=False)
929 if stmt == "" and cell is None:
932 if stmt == "" and cell is None:
930 return
933 return
931
934
932 timefunc = timeit.default_timer
935 timefunc = timeit.default_timer
933 number = int(getattr(opts, "n", 0))
936 number = int(getattr(opts, "n", 0))
934 repeat = int(getattr(opts, "r", timeit.default_repeat))
937 repeat = int(getattr(opts, "r", timeit.default_repeat))
935 precision = int(getattr(opts, "p", 3))
938 precision = int(getattr(opts, "p", 3))
936 quiet = 'q' in opts
939 quiet = 'q' in opts
937 return_result = 'o' in opts
940 return_result = 'o' in opts
938 if hasattr(opts, "t"):
941 if hasattr(opts, "t"):
939 timefunc = time.time
942 timefunc = time.time
940 if hasattr(opts, "c"):
943 if hasattr(opts, "c"):
941 timefunc = clock
944 timefunc = clock
942
945
943 timer = timeit.Timer(timer=timefunc)
946 timer = timeit.Timer(timer=timefunc)
944 # this code has tight coupling to the inner workings of timeit.Timer,
947 # this code has tight coupling to the inner workings of timeit.Timer,
945 # but is there a better way to achieve that the code stmt has access
948 # but is there a better way to achieve that the code stmt has access
946 # to the shell namespace?
949 # to the shell namespace?
947 transform = self.shell.input_splitter.transform_cell
950 transform = self.shell.input_splitter.transform_cell
948
951
949 if cell is None:
952 if cell is None:
950 # called as line magic
953 # called as line magic
951 ast_setup = ast.parse("pass")
954 ast_setup = ast.parse("pass")
952 ast_stmt = ast.parse(transform(stmt))
955 ast_stmt = ast.parse(transform(stmt))
953 else:
956 else:
954 ast_setup = ast.parse(transform(stmt))
957 ast_setup = ast.parse(transform(stmt))
955 ast_stmt = ast.parse(transform(cell))
958 ast_stmt = ast.parse(transform(cell))
956
959
957 ast_setup = self.shell.transform_ast(ast_setup)
960 ast_setup = self.shell.transform_ast(ast_setup)
958 ast_stmt = self.shell.transform_ast(ast_stmt)
961 ast_stmt = self.shell.transform_ast(ast_stmt)
959
962
960 # This codestring is taken from timeit.template - we fill it in as an
963 # This codestring is taken from timeit.template - we fill it in as an
961 # AST, so that we can apply our AST transformations to the user code
964 # AST, so that we can apply our AST transformations to the user code
962 # without affecting the timing code.
965 # without affecting the timing code.
963 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
966 timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
964 ' setup\n'
967 ' setup\n'
965 ' _t0 = _timer()\n'
968 ' _t0 = _timer()\n'
966 ' for _i in _it:\n'
969 ' for _i in _it:\n'
967 ' stmt\n'
970 ' stmt\n'
968 ' _t1 = _timer()\n'
971 ' _t1 = _timer()\n'
969 ' return _t1 - _t0\n')
972 ' return _t1 - _t0\n')
970
973
971 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
974 timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
972 timeit_ast = ast.fix_missing_locations(timeit_ast)
975 timeit_ast = ast.fix_missing_locations(timeit_ast)
973
976
974 # Track compilation time so it can be reported if too long
977 # Track compilation time so it can be reported if too long
975 # Minimum time above which compilation time will be reported
978 # Minimum time above which compilation time will be reported
976 tc_min = 0.1
979 tc_min = 0.1
977
980
978 t0 = clock()
981 t0 = clock()
979 code = compile(timeit_ast, "<magic-timeit>", "exec")
982 code = compile(timeit_ast, "<magic-timeit>", "exec")
980 tc = clock()-t0
983 tc = clock()-t0
981
984
982 ns = {}
985 ns = {}
983 exec(code, self.shell.user_ns, ns)
986 exec(code, self.shell.user_ns, ns)
984 timer.inner = ns["inner"]
987 timer.inner = ns["inner"]
985
988
986 if number == 0:
989 if number == 0:
987 # determine number so that 0.2 <= total time < 2.0
990 # determine number so that 0.2 <= total time < 2.0
988 number = 1
991 number = 1
989 for _ in range(1, 10):
992 for _ in range(1, 10):
990 if timer.timeit(number) >= 0.2:
993 if timer.timeit(number) >= 0.2:
991 break
994 break
992 number *= 10
995 number *= 10
993 all_runs = timer.repeat(repeat, number)
996 all_runs = timer.repeat(repeat, number)
994 best = min(all_runs) / number
997 best = min(all_runs) / number
995 if not quiet :
998 if not quiet :
996 print(u"%d loops, best of %d: %s per loop" % (number, repeat,
999 print(u"%d loops, best of %d: %s per loop" % (number, repeat,
997 _format_time(best, precision)))
1000 _format_time(best, precision)))
998 if tc > tc_min:
1001 if tc > tc_min:
999 print("Compiler time: %.2f s" % tc)
1002 print("Compiler time: %.2f s" % tc)
1000 if return_result:
1003 if return_result:
1001 return TimeitResult(number, repeat, best, all_runs, tc, precision)
1004 return TimeitResult(number, repeat, best, all_runs, tc, precision)
1002
1005
1003 @skip_doctest
1006 @skip_doctest
1004 @needs_local_scope
1007 @needs_local_scope
1005 @line_cell_magic
1008 @line_cell_magic
1006 def time(self,line='', cell=None, local_ns=None):
1009 def time(self,line='', cell=None, local_ns=None):
1007 """Time execution of a Python statement or expression.
1010 """Time execution of a Python statement or expression.
1008
1011
1009 The CPU and wall clock times are printed, and the value of the
1012 The CPU and wall clock times are printed, and the value of the
1010 expression (if any) is returned. Note that under Win32, system time
1013 expression (if any) is returned. Note that under Win32, system time
1011 is always reported as 0, since it can not be measured.
1014 is always reported as 0, since it can not be measured.
1012
1015
1013 This function can be used both as a line and cell magic:
1016 This function can be used both as a line and cell magic:
1014
1017
1015 - In line mode you can time a single-line statement (though multiple
1018 - In line mode you can time a single-line statement (though multiple
1016 ones can be chained with using semicolons).
1019 ones can be chained with using semicolons).
1017
1020
1018 - In cell mode, you can time the cell body (a directly
1021 - In cell mode, you can time the cell body (a directly
1019 following statement raises an error).
1022 following statement raises an error).
1020
1023
1021 This function provides very basic timing functionality. Use the timeit
1024 This function provides very basic timing functionality. Use the timeit
1022 magic for more controll over the measurement.
1025 magic for more controll over the measurement.
1023
1026
1024 Examples
1027 Examples
1025 --------
1028 --------
1026 ::
1029 ::
1027
1030
1028 In [1]: %time 2**128
1031 In [1]: %time 2**128
1029 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1032 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1030 Wall time: 0.00
1033 Wall time: 0.00
1031 Out[1]: 340282366920938463463374607431768211456L
1034 Out[1]: 340282366920938463463374607431768211456L
1032
1035
1033 In [2]: n = 1000000
1036 In [2]: n = 1000000
1034
1037
1035 In [3]: %time sum(range(n))
1038 In [3]: %time sum(range(n))
1036 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1039 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1037 Wall time: 1.37
1040 Wall time: 1.37
1038 Out[3]: 499999500000L
1041 Out[3]: 499999500000L
1039
1042
1040 In [4]: %time print 'hello world'
1043 In [4]: %time print 'hello world'
1041 hello world
1044 hello world
1042 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1045 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1043 Wall time: 0.00
1046 Wall time: 0.00
1044
1047
1045 Note that the time needed by Python to compile the given expression
1048 Note that the time needed by Python to compile the given expression
1046 will be reported if it is more than 0.1s. In this example, the
1049 will be reported if it is more than 0.1s. In this example, the
1047 actual exponentiation is done by Python at compilation time, so while
1050 actual exponentiation is done by Python at compilation time, so while
1048 the expression can take a noticeable amount of time to compute, that
1051 the expression can take a noticeable amount of time to compute, that
1049 time is purely due to the compilation:
1052 time is purely due to the compilation:
1050
1053
1051 In [5]: %time 3**9999;
1054 In [5]: %time 3**9999;
1052 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1055 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1053 Wall time: 0.00 s
1056 Wall time: 0.00 s
1054
1057
1055 In [6]: %time 3**999999;
1058 In [6]: %time 3**999999;
1056 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1059 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1057 Wall time: 0.00 s
1060 Wall time: 0.00 s
1058 Compiler : 0.78 s
1061 Compiler : 0.78 s
1059 """
1062 """
1060
1063
1061 # fail immediately if the given expression can't be compiled
1064 # fail immediately if the given expression can't be compiled
1062
1065
1063 if line and cell:
1066 if line and cell:
1064 raise UsageError("Can't use statement directly after '%%time'!")
1067 raise UsageError("Can't use statement directly after '%%time'!")
1065
1068
1066 if cell:
1069 if cell:
1067 expr = self.shell.input_transformer_manager.transform_cell(cell)
1070 expr = self.shell.input_transformer_manager.transform_cell(cell)
1068 else:
1071 else:
1069 expr = self.shell.input_transformer_manager.transform_cell(line)
1072 expr = self.shell.input_transformer_manager.transform_cell(line)
1070
1073
1071 # Minimum time above which parse time will be reported
1074 # Minimum time above which parse time will be reported
1072 tp_min = 0.1
1075 tp_min = 0.1
1073
1076
1074 t0 = clock()
1077 t0 = clock()
1075 expr_ast = ast.parse(expr)
1078 expr_ast = ast.parse(expr)
1076 tp = clock()-t0
1079 tp = clock()-t0
1077
1080
1078 # Apply AST transformations
1081 # Apply AST transformations
1079 expr_ast = self.shell.transform_ast(expr_ast)
1082 expr_ast = self.shell.transform_ast(expr_ast)
1080
1083
1081 # Minimum time above which compilation time will be reported
1084 # Minimum time above which compilation time will be reported
1082 tc_min = 0.1
1085 tc_min = 0.1
1083
1086
1084 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1087 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr):
1085 mode = 'eval'
1088 mode = 'eval'
1086 source = '<timed eval>'
1089 source = '<timed eval>'
1087 expr_ast = ast.Expression(expr_ast.body[0].value)
1090 expr_ast = ast.Expression(expr_ast.body[0].value)
1088 else:
1091 else:
1089 mode = 'exec'
1092 mode = 'exec'
1090 source = '<timed exec>'
1093 source = '<timed exec>'
1091 t0 = clock()
1094 t0 = clock()
1092 code = compile(expr_ast, source, mode)
1095 code = compile(expr_ast, source, mode)
1093 tc = clock()-t0
1096 tc = clock()-t0
1094
1097
1095 # skew measurement as little as possible
1098 # skew measurement as little as possible
1096 glob = self.shell.user_ns
1099 glob = self.shell.user_ns
1097 wtime = time.time
1100 wtime = time.time
1098 # time execution
1101 # time execution
1099 wall_st = wtime()
1102 wall_st = wtime()
1100 if mode=='eval':
1103 if mode=='eval':
1101 st = clock2()
1104 st = clock2()
1102 out = eval(code, glob, local_ns)
1105 out = eval(code, glob, local_ns)
1103 end = clock2()
1106 end = clock2()
1104 else:
1107 else:
1105 st = clock2()
1108 st = clock2()
1106 exec(code, glob, local_ns)
1109 exec(code, glob, local_ns)
1107 end = clock2()
1110 end = clock2()
1108 out = None
1111 out = None
1109 wall_end = wtime()
1112 wall_end = wtime()
1110 # Compute actual times and report
1113 # Compute actual times and report
1111 wall_time = wall_end-wall_st
1114 wall_time = wall_end-wall_st
1112 cpu_user = end[0]-st[0]
1115 cpu_user = end[0]-st[0]
1113 cpu_sys = end[1]-st[1]
1116 cpu_sys = end[1]-st[1]
1114 cpu_tot = cpu_user+cpu_sys
1117 cpu_tot = cpu_user+cpu_sys
1115 # On windows cpu_sys is always zero, so no new information to the next print
1118 # On windows cpu_sys is always zero, so no new information to the next print
1116 if sys.platform != 'win32':
1119 if sys.platform != 'win32':
1117 print("CPU times: user %s, sys: %s, total: %s" % \
1120 print("CPU times: user %s, sys: %s, total: %s" % \
1118 (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot)))
1121 (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot)))
1119 print("Wall time: %s" % _format_time(wall_time))
1122 print("Wall time: %s" % _format_time(wall_time))
1120 if tc > tc_min:
1123 if tc > tc_min:
1121 print("Compiler : %s" % _format_time(tc))
1124 print("Compiler : %s" % _format_time(tc))
1122 if tp > tp_min:
1125 if tp > tp_min:
1123 print("Parser : %s" % _format_time(tp))
1126 print("Parser : %s" % _format_time(tp))
1124 return out
1127 return out
1125
1128
1126 @skip_doctest
1129 @skip_doctest
1127 @line_magic
1130 @line_magic
1128 def macro(self, parameter_s=''):
1131 def macro(self, parameter_s=''):
1129 """Define a macro for future re-execution. It accepts ranges of history,
1132 """Define a macro for future re-execution. It accepts ranges of history,
1130 filenames or string objects.
1133 filenames or string objects.
1131
1134
1132 Usage:\\
1135 Usage:\\
1133 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1136 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1134
1137
1135 Options:
1138 Options:
1136
1139
1137 -r: use 'raw' input. By default, the 'processed' history is used,
1140 -r: use 'raw' input. By default, the 'processed' history is used,
1138 so that magics are loaded in their transformed version to valid
1141 so that magics are loaded in their transformed version to valid
1139 Python. If this option is given, the raw input as typed at the
1142 Python. If this option is given, the raw input as typed at the
1140 command line is used instead.
1143 command line is used instead.
1141
1144
1142 -q: quiet macro definition. By default, a tag line is printed
1145 -q: quiet macro definition. By default, a tag line is printed
1143 to indicate the macro has been created, and then the contents of
1146 to indicate the macro has been created, and then the contents of
1144 the macro are printed. If this option is given, then no printout
1147 the macro are printed. If this option is given, then no printout
1145 is produced once the macro is created.
1148 is produced once the macro is created.
1146
1149
1147 This will define a global variable called `name` which is a string
1150 This will define a global variable called `name` which is a string
1148 made of joining the slices and lines you specify (n1,n2,... numbers
1151 made of joining the slices and lines you specify (n1,n2,... numbers
1149 above) from your input history into a single string. This variable
1152 above) from your input history into a single string. This variable
1150 acts like an automatic function which re-executes those lines as if
1153 acts like an automatic function which re-executes those lines as if
1151 you had typed them. You just type 'name' at the prompt and the code
1154 you had typed them. You just type 'name' at the prompt and the code
1152 executes.
1155 executes.
1153
1156
1154 The syntax for indicating input ranges is described in %history.
1157 The syntax for indicating input ranges is described in %history.
1155
1158
1156 Note: as a 'hidden' feature, you can also use traditional python slice
1159 Note: as a 'hidden' feature, you can also use traditional python slice
1157 notation, where N:M means numbers N through M-1.
1160 notation, where N:M means numbers N through M-1.
1158
1161
1159 For example, if your history contains (print using %hist -n )::
1162 For example, if your history contains (print using %hist -n )::
1160
1163
1161 44: x=1
1164 44: x=1
1162 45: y=3
1165 45: y=3
1163 46: z=x+y
1166 46: z=x+y
1164 47: print x
1167 47: print x
1165 48: a=5
1168 48: a=5
1166 49: print 'x',x,'y',y
1169 49: print 'x',x,'y',y
1167
1170
1168 you can create a macro with lines 44 through 47 (included) and line 49
1171 you can create a macro with lines 44 through 47 (included) and line 49
1169 called my_macro with::
1172 called my_macro with::
1170
1173
1171 In [55]: %macro my_macro 44-47 49
1174 In [55]: %macro my_macro 44-47 49
1172
1175
1173 Now, typing `my_macro` (without quotes) will re-execute all this code
1176 Now, typing `my_macro` (without quotes) will re-execute all this code
1174 in one pass.
1177 in one pass.
1175
1178
1176 You don't need to give the line-numbers in order, and any given line
1179 You don't need to give the line-numbers in order, and any given line
1177 number can appear multiple times. You can assemble macros with any
1180 number can appear multiple times. You can assemble macros with any
1178 lines from your input history in any order.
1181 lines from your input history in any order.
1179
1182
1180 The macro is a simple object which holds its value in an attribute,
1183 The macro is a simple object which holds its value in an attribute,
1181 but IPython's display system checks for macros and executes them as
1184 but IPython's display system checks for macros and executes them as
1182 code instead of printing them when you type their name.
1185 code instead of printing them when you type their name.
1183
1186
1184 You can view a macro's contents by explicitly printing it with::
1187 You can view a macro's contents by explicitly printing it with::
1185
1188
1186 print macro_name
1189 print macro_name
1187
1190
1188 """
1191 """
1189 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1192 opts,args = self.parse_options(parameter_s,'rq',mode='list')
1190 if not args: # List existing macros
1193 if not args: # List existing macros
1191 return sorted(k for k,v in iteritems(self.shell.user_ns) if\
1194 return sorted(k for k,v in iteritems(self.shell.user_ns) if\
1192 isinstance(v, Macro))
1195 isinstance(v, Macro))
1193 if len(args) == 1:
1196 if len(args) == 1:
1194 raise UsageError(
1197 raise UsageError(
1195 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1198 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
1196 name, codefrom = args[0], " ".join(args[1:])
1199 name, codefrom = args[0], " ".join(args[1:])
1197
1200
1198 #print 'rng',ranges # dbg
1201 #print 'rng',ranges # dbg
1199 try:
1202 try:
1200 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1203 lines = self.shell.find_user_code(codefrom, 'r' in opts)
1201 except (ValueError, TypeError) as e:
1204 except (ValueError, TypeError) as e:
1202 print(e.args[0])
1205 print(e.args[0])
1203 return
1206 return
1204 macro = Macro(lines)
1207 macro = Macro(lines)
1205 self.shell.define_macro(name, macro)
1208 self.shell.define_macro(name, macro)
1206 if not ( 'q' in opts) :
1209 if not ( 'q' in opts) :
1207 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1210 print('Macro `%s` created. To execute, type its name (without quotes).' % name)
1208 print('=== Macro contents: ===')
1211 print('=== Macro contents: ===')
1209 print(macro, end=' ')
1212 print(macro, end=' ')
1210
1213
1211 @magic_arguments.magic_arguments()
1214 @magic_arguments.magic_arguments()
1212 @magic_arguments.argument('output', type=str, default='', nargs='?',
1215 @magic_arguments.argument('output', type=str, default='', nargs='?',
1213 help="""The name of the variable in which to store output.
1216 help="""The name of the variable in which to store output.
1214 This is a utils.io.CapturedIO object with stdout/err attributes
1217 This is a utils.io.CapturedIO object with stdout/err attributes
1215 for the text of the captured output.
1218 for the text of the captured output.
1216
1219
1217 CapturedOutput also has a show() method for displaying the output,
1220 CapturedOutput also has a show() method for displaying the output,
1218 and __call__ as well, so you can use that to quickly display the
1221 and __call__ as well, so you can use that to quickly display the
1219 output.
1222 output.
1220
1223
1221 If unspecified, captured output is discarded.
1224 If unspecified, captured output is discarded.
1222 """
1225 """
1223 )
1226 )
1224 @magic_arguments.argument('--no-stderr', action="store_true",
1227 @magic_arguments.argument('--no-stderr', action="store_true",
1225 help="""Don't capture stderr."""
1228 help="""Don't capture stderr."""
1226 )
1229 )
1227 @magic_arguments.argument('--no-stdout', action="store_true",
1230 @magic_arguments.argument('--no-stdout', action="store_true",
1228 help="""Don't capture stdout."""
1231 help="""Don't capture stdout."""
1229 )
1232 )
1230 @magic_arguments.argument('--no-display', action="store_true",
1233 @magic_arguments.argument('--no-display', action="store_true",
1231 help="""Don't capture IPython's rich display."""
1234 help="""Don't capture IPython's rich display."""
1232 )
1235 )
1233 @cell_magic
1236 @cell_magic
1234 def capture(self, line, cell):
1237 def capture(self, line, cell):
1235 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1238 """run the cell, capturing stdout, stderr, and IPython's rich display() calls."""
1236 args = magic_arguments.parse_argstring(self.capture, line)
1239 args = magic_arguments.parse_argstring(self.capture, line)
1237 out = not args.no_stdout
1240 out = not args.no_stdout
1238 err = not args.no_stderr
1241 err = not args.no_stderr
1239 disp = not args.no_display
1242 disp = not args.no_display
1240 with capture_output(out, err, disp) as io:
1243 with capture_output(out, err, disp) as io:
1241 self.shell.run_cell(cell)
1244 self.shell.run_cell(cell)
1242 if args.output:
1245 if args.output:
1243 self.shell.user_ns[args.output] = io
1246 self.shell.user_ns[args.output] = io
1244
1247
1245 def parse_breakpoint(text, current_file):
1248 def parse_breakpoint(text, current_file):
1246 '''Returns (file, line) for file:line and (current_file, line) for line'''
1249 '''Returns (file, line) for file:line and (current_file, line) for line'''
1247 colon = text.find(':')
1250 colon = text.find(':')
1248 if colon == -1:
1251 if colon == -1:
1249 return current_file, int(text)
1252 return current_file, int(text)
1250 else:
1253 else:
1251 return text[:colon], int(text[colon+1:])
1254 return text[:colon], int(text[colon+1:])
1252
1255
1253 def _format_time(timespan, precision=3):
1256 def _format_time(timespan, precision=3):
1254 """Formats the timespan in a human readable form"""
1257 """Formats the timespan in a human readable form"""
1255 import math
1258 import math
1256
1259
1257 if timespan >= 60.0:
1260 if timespan >= 60.0:
1258 # we have more than a minute, format that in a human readable form
1261 # we have more than a minute, format that in a human readable form
1259 # Idea from http://snipplr.com/view/5713/
1262 # Idea from http://snipplr.com/view/5713/
1260 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1263 parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
1261 time = []
1264 time = []
1262 leftover = timespan
1265 leftover = timespan
1263 for suffix, length in parts:
1266 for suffix, length in parts:
1264 value = int(leftover / length)
1267 value = int(leftover / length)
1265 if value > 0:
1268 if value > 0:
1266 leftover = leftover % length
1269 leftover = leftover % length
1267 time.append(u'%s%s' % (str(value), suffix))
1270 time.append(u'%s%s' % (str(value), suffix))
1268 if leftover < 1:
1271 if leftover < 1:
1269 break
1272 break
1270 return " ".join(time)
1273 return " ".join(time)
1271
1274
1272
1275
1273 # Unfortunately the unicode 'micro' symbol can cause problems in
1276 # Unfortunately the unicode 'micro' symbol can cause problems in
1274 # certain terminals.
1277 # certain terminals.
1275 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1278 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1276 # Try to prevent crashes by being more secure than it needs to
1279 # Try to prevent crashes by being more secure than it needs to
1277 # E.g. eclipse is able to print a Β΅, but has no sys.stdout.encoding set.
1280 # E.g. eclipse is able to print a Β΅, but has no sys.stdout.encoding set.
1278 units = [u"s", u"ms",u'us',"ns"] # the save value
1281 units = [u"s", u"ms",u'us',"ns"] # the save value
1279 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1282 if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
1280 try:
1283 try:
1281 u'\xb5'.encode(sys.stdout.encoding)
1284 u'\xb5'.encode(sys.stdout.encoding)
1282 units = [u"s", u"ms",u'\xb5s',"ns"]
1285 units = [u"s", u"ms",u'\xb5s',"ns"]
1283 except:
1286 except:
1284 pass
1287 pass
1285 scaling = [1, 1e3, 1e6, 1e9]
1288 scaling = [1, 1e3, 1e6, 1e9]
1286
1289
1287 if timespan > 0.0:
1290 if timespan > 0.0:
1288 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1291 order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
1289 else:
1292 else:
1290 order = 3
1293 order = 3
1291 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
1294 return u"%.*g %s" % (precision, timespan * scaling[order], units[order])
@@ -1,672 +1,676 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7
7
8 Authors
8 Authors
9 -------
9 -------
10 * Fernando Perez
10 * Fernando Perez
11 """
11 """
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2011 The IPython Development Team
13 # Copyright (C) 2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # stdlib
22 # stdlib
23 import ast
23 import ast
24 import os
24 import os
25 import signal
25 import signal
26 import shutil
26 import shutil
27 import sys
27 import sys
28 import tempfile
28 import tempfile
29 import unittest
29 import unittest
30 from os.path import join
30 from os.path import join
31 from io import StringIO
32
31
33 # third-party
32 # third-party
34 import nose.tools as nt
33 import nose.tools as nt
35
34
36 # Our own
35 # Our own
37 from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths
36 from IPython.testing.decorators import skipif, skip_win32, onlyif_unicode_paths
38 from IPython.testing import tools as tt
37 from IPython.testing import tools as tt
39 from IPython.utils import io
38 from IPython.utils import io
40 from IPython.utils.py3compat import unicode_type
39 from IPython.utils.py3compat import unicode_type, PY3
40
41 if PY3:
42 from io import StringIO
43 else:
44 from StringIO import StringIO
41
45
42 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
43 # Globals
47 # Globals
44 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
45 # This is used by every single test, no point repeating it ad nauseam
49 # This is used by every single test, no point repeating it ad nauseam
46 ip = get_ipython()
50 ip = get_ipython()
47
51
48 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
49 # Tests
53 # Tests
50 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
51
55
52 class InteractiveShellTestCase(unittest.TestCase):
56 class InteractiveShellTestCase(unittest.TestCase):
53 def test_naked_string_cells(self):
57 def test_naked_string_cells(self):
54 """Test that cells with only naked strings are fully executed"""
58 """Test that cells with only naked strings are fully executed"""
55 # First, single-line inputs
59 # First, single-line inputs
56 ip.run_cell('"a"\n')
60 ip.run_cell('"a"\n')
57 self.assertEqual(ip.user_ns['_'], 'a')
61 self.assertEqual(ip.user_ns['_'], 'a')
58 # And also multi-line cells
62 # And also multi-line cells
59 ip.run_cell('"""a\nb"""\n')
63 ip.run_cell('"""a\nb"""\n')
60 self.assertEqual(ip.user_ns['_'], 'a\nb')
64 self.assertEqual(ip.user_ns['_'], 'a\nb')
61
65
62 def test_run_empty_cell(self):
66 def test_run_empty_cell(self):
63 """Just make sure we don't get a horrible error with a blank
67 """Just make sure we don't get a horrible error with a blank
64 cell of input. Yes, I did overlook that."""
68 cell of input. Yes, I did overlook that."""
65 old_xc = ip.execution_count
69 old_xc = ip.execution_count
66 ip.run_cell('')
70 ip.run_cell('')
67 self.assertEqual(ip.execution_count, old_xc)
71 self.assertEqual(ip.execution_count, old_xc)
68
72
69 def test_run_cell_multiline(self):
73 def test_run_cell_multiline(self):
70 """Multi-block, multi-line cells must execute correctly.
74 """Multi-block, multi-line cells must execute correctly.
71 """
75 """
72 src = '\n'.join(["x=1",
76 src = '\n'.join(["x=1",
73 "y=2",
77 "y=2",
74 "if 1:",
78 "if 1:",
75 " x += 1",
79 " x += 1",
76 " y += 1",])
80 " y += 1",])
77 ip.run_cell(src)
81 ip.run_cell(src)
78 self.assertEqual(ip.user_ns['x'], 2)
82 self.assertEqual(ip.user_ns['x'], 2)
79 self.assertEqual(ip.user_ns['y'], 3)
83 self.assertEqual(ip.user_ns['y'], 3)
80
84
81 def test_multiline_string_cells(self):
85 def test_multiline_string_cells(self):
82 "Code sprinkled with multiline strings should execute (GH-306)"
86 "Code sprinkled with multiline strings should execute (GH-306)"
83 ip.run_cell('tmp=0')
87 ip.run_cell('tmp=0')
84 self.assertEqual(ip.user_ns['tmp'], 0)
88 self.assertEqual(ip.user_ns['tmp'], 0)
85 ip.run_cell('tmp=1;"""a\nb"""\n')
89 ip.run_cell('tmp=1;"""a\nb"""\n')
86 self.assertEqual(ip.user_ns['tmp'], 1)
90 self.assertEqual(ip.user_ns['tmp'], 1)
87
91
88 def test_dont_cache_with_semicolon(self):
92 def test_dont_cache_with_semicolon(self):
89 "Ending a line with semicolon should not cache the returned object (GH-307)"
93 "Ending a line with semicolon should not cache the returned object (GH-307)"
90 oldlen = len(ip.user_ns['Out'])
94 oldlen = len(ip.user_ns['Out'])
91 a = ip.run_cell('1;', store_history=True)
95 a = ip.run_cell('1;', store_history=True)
92 newlen = len(ip.user_ns['Out'])
96 newlen = len(ip.user_ns['Out'])
93 self.assertEqual(oldlen, newlen)
97 self.assertEqual(oldlen, newlen)
94 #also test the default caching behavior
98 #also test the default caching behavior
95 ip.run_cell('1', store_history=True)
99 ip.run_cell('1', store_history=True)
96 newlen = len(ip.user_ns['Out'])
100 newlen = len(ip.user_ns['Out'])
97 self.assertEqual(oldlen+1, newlen)
101 self.assertEqual(oldlen+1, newlen)
98
102
99 def test_In_variable(self):
103 def test_In_variable(self):
100 "Verify that In variable grows with user input (GH-284)"
104 "Verify that In variable grows with user input (GH-284)"
101 oldlen = len(ip.user_ns['In'])
105 oldlen = len(ip.user_ns['In'])
102 ip.run_cell('1;', store_history=True)
106 ip.run_cell('1;', store_history=True)
103 newlen = len(ip.user_ns['In'])
107 newlen = len(ip.user_ns['In'])
104 self.assertEqual(oldlen+1, newlen)
108 self.assertEqual(oldlen+1, newlen)
105 self.assertEqual(ip.user_ns['In'][-1],'1;')
109 self.assertEqual(ip.user_ns['In'][-1],'1;')
106
110
107 def test_magic_names_in_string(self):
111 def test_magic_names_in_string(self):
108 ip.run_cell('a = """\n%exit\n"""')
112 ip.run_cell('a = """\n%exit\n"""')
109 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
113 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
110
114
111 def test_trailing_newline(self):
115 def test_trailing_newline(self):
112 """test that running !(command) does not raise a SyntaxError"""
116 """test that running !(command) does not raise a SyntaxError"""
113 ip.run_cell('!(true)\n', False)
117 ip.run_cell('!(true)\n', False)
114 ip.run_cell('!(true)\n\n\n', False)
118 ip.run_cell('!(true)\n\n\n', False)
115
119
116 def test_gh_597(self):
120 def test_gh_597(self):
117 """Pretty-printing lists of objects with non-ascii reprs may cause
121 """Pretty-printing lists of objects with non-ascii reprs may cause
118 problems."""
122 problems."""
119 class Spam(object):
123 class Spam(object):
120 def __repr__(self):
124 def __repr__(self):
121 return "\xe9"*50
125 return "\xe9"*50
122 import IPython.core.formatters
126 import IPython.core.formatters
123 f = IPython.core.formatters.PlainTextFormatter()
127 f = IPython.core.formatters.PlainTextFormatter()
124 f([Spam(),Spam()])
128 f([Spam(),Spam()])
125
129
126
130
127 def test_future_flags(self):
131 def test_future_flags(self):
128 """Check that future flags are used for parsing code (gh-777)"""
132 """Check that future flags are used for parsing code (gh-777)"""
129 ip.run_cell('from __future__ import print_function')
133 ip.run_cell('from __future__ import print_function')
130 try:
134 try:
131 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
135 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
132 assert 'prfunc_return_val' in ip.user_ns
136 assert 'prfunc_return_val' in ip.user_ns
133 finally:
137 finally:
134 # Reset compiler flags so we don't mess up other tests.
138 # Reset compiler flags so we don't mess up other tests.
135 ip.compile.reset_compiler_flags()
139 ip.compile.reset_compiler_flags()
136
140
137 def test_future_unicode(self):
141 def test_future_unicode(self):
138 """Check that unicode_literals is imported from __future__ (gh #786)"""
142 """Check that unicode_literals is imported from __future__ (gh #786)"""
139 try:
143 try:
140 ip.run_cell(u'byte_str = "a"')
144 ip.run_cell(u'byte_str = "a"')
141 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
145 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
142 ip.run_cell('from __future__ import unicode_literals')
146 ip.run_cell('from __future__ import unicode_literals')
143 ip.run_cell(u'unicode_str = "a"')
147 ip.run_cell(u'unicode_str = "a"')
144 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
148 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
145 finally:
149 finally:
146 # Reset compiler flags so we don't mess up other tests.
150 # Reset compiler flags so we don't mess up other tests.
147 ip.compile.reset_compiler_flags()
151 ip.compile.reset_compiler_flags()
148
152
149 def test_can_pickle(self):
153 def test_can_pickle(self):
150 "Can we pickle objects defined interactively (GH-29)"
154 "Can we pickle objects defined interactively (GH-29)"
151 ip = get_ipython()
155 ip = get_ipython()
152 ip.reset()
156 ip.reset()
153 ip.run_cell(("class Mylist(list):\n"
157 ip.run_cell(("class Mylist(list):\n"
154 " def __init__(self,x=[]):\n"
158 " def __init__(self,x=[]):\n"
155 " list.__init__(self,x)"))
159 " list.__init__(self,x)"))
156 ip.run_cell("w=Mylist([1,2,3])")
160 ip.run_cell("w=Mylist([1,2,3])")
157
161
158 from pickle import dumps
162 from pickle import dumps
159
163
160 # We need to swap in our main module - this is only necessary
164 # We need to swap in our main module - this is only necessary
161 # inside the test framework, because IPython puts the interactive module
165 # inside the test framework, because IPython puts the interactive module
162 # in place (but the test framework undoes this).
166 # in place (but the test framework undoes this).
163 _main = sys.modules['__main__']
167 _main = sys.modules['__main__']
164 sys.modules['__main__'] = ip.user_module
168 sys.modules['__main__'] = ip.user_module
165 try:
169 try:
166 res = dumps(ip.user_ns["w"])
170 res = dumps(ip.user_ns["w"])
167 finally:
171 finally:
168 sys.modules['__main__'] = _main
172 sys.modules['__main__'] = _main
169 self.assertTrue(isinstance(res, bytes))
173 self.assertTrue(isinstance(res, bytes))
170
174
171 def test_global_ns(self):
175 def test_global_ns(self):
172 "Code in functions must be able to access variables outside them."
176 "Code in functions must be able to access variables outside them."
173 ip = get_ipython()
177 ip = get_ipython()
174 ip.run_cell("a = 10")
178 ip.run_cell("a = 10")
175 ip.run_cell(("def f(x):\n"
179 ip.run_cell(("def f(x):\n"
176 " return x + a"))
180 " return x + a"))
177 ip.run_cell("b = f(12)")
181 ip.run_cell("b = f(12)")
178 self.assertEqual(ip.user_ns["b"], 22)
182 self.assertEqual(ip.user_ns["b"], 22)
179
183
180 def test_bad_custom_tb(self):
184 def test_bad_custom_tb(self):
181 """Check that InteractiveShell is protected from bad custom exception handlers"""
185 """Check that InteractiveShell is protected from bad custom exception handlers"""
182 from IPython.utils import io
186 from IPython.utils import io
183 save_stderr = io.stderr
187 save_stderr = io.stderr
184 try:
188 try:
185 # capture stderr
189 # capture stderr
186 io.stderr = StringIO()
190 io.stderr = StringIO()
187 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
191 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
188 self.assertEqual(ip.custom_exceptions, (IOError,))
192 self.assertEqual(ip.custom_exceptions, (IOError,))
189 ip.run_cell(u'raise IOError("foo")')
193 ip.run_cell(u'raise IOError("foo")')
190 self.assertEqual(ip.custom_exceptions, ())
194 self.assertEqual(ip.custom_exceptions, ())
191 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
195 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
192 finally:
196 finally:
193 io.stderr = save_stderr
197 io.stderr = save_stderr
194
198
195 def test_bad_custom_tb_return(self):
199 def test_bad_custom_tb_return(self):
196 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
200 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
197 from IPython.utils import io
201 from IPython.utils import io
198 save_stderr = io.stderr
202 save_stderr = io.stderr
199 try:
203 try:
200 # capture stderr
204 # capture stderr
201 io.stderr = StringIO()
205 io.stderr = StringIO()
202 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
206 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
203 self.assertEqual(ip.custom_exceptions, (NameError,))
207 self.assertEqual(ip.custom_exceptions, (NameError,))
204 ip.run_cell(u'a=abracadabra')
208 ip.run_cell(u'a=abracadabra')
205 self.assertEqual(ip.custom_exceptions, ())
209 self.assertEqual(ip.custom_exceptions, ())
206 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
210 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
207 finally:
211 finally:
208 io.stderr = save_stderr
212 io.stderr = save_stderr
209
213
210 def test_drop_by_id(self):
214 def test_drop_by_id(self):
211 myvars = {"a":object(), "b":object(), "c": object()}
215 myvars = {"a":object(), "b":object(), "c": object()}
212 ip.push(myvars, interactive=False)
216 ip.push(myvars, interactive=False)
213 for name in myvars:
217 for name in myvars:
214 assert name in ip.user_ns, name
218 assert name in ip.user_ns, name
215 assert name in ip.user_ns_hidden, name
219 assert name in ip.user_ns_hidden, name
216 ip.user_ns['b'] = 12
220 ip.user_ns['b'] = 12
217 ip.drop_by_id(myvars)
221 ip.drop_by_id(myvars)
218 for name in ["a", "c"]:
222 for name in ["a", "c"]:
219 assert name not in ip.user_ns, name
223 assert name not in ip.user_ns, name
220 assert name not in ip.user_ns_hidden, name
224 assert name not in ip.user_ns_hidden, name
221 assert ip.user_ns['b'] == 12
225 assert ip.user_ns['b'] == 12
222 ip.reset()
226 ip.reset()
223
227
224 def test_var_expand(self):
228 def test_var_expand(self):
225 ip.user_ns['f'] = u'Ca\xf1o'
229 ip.user_ns['f'] = u'Ca\xf1o'
226 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
230 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
227 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
231 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
228 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
232 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
229 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
233 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
230
234
231 ip.user_ns['f'] = b'Ca\xc3\xb1o'
235 ip.user_ns['f'] = b'Ca\xc3\xb1o'
232 # This should not raise any exception:
236 # This should not raise any exception:
233 ip.var_expand(u'echo $f')
237 ip.var_expand(u'echo $f')
234
238
235 def test_var_expand_local(self):
239 def test_var_expand_local(self):
236 """Test local variable expansion in !system and %magic calls"""
240 """Test local variable expansion in !system and %magic calls"""
237 # !system
241 # !system
238 ip.run_cell('def test():\n'
242 ip.run_cell('def test():\n'
239 ' lvar = "ttt"\n'
243 ' lvar = "ttt"\n'
240 ' ret = !echo {lvar}\n'
244 ' ret = !echo {lvar}\n'
241 ' return ret[0]\n')
245 ' return ret[0]\n')
242 res = ip.user_ns['test']()
246 res = ip.user_ns['test']()
243 nt.assert_in('ttt', res)
247 nt.assert_in('ttt', res)
244
248
245 # %magic
249 # %magic
246 ip.run_cell('def makemacro():\n'
250 ip.run_cell('def makemacro():\n'
247 ' macroname = "macro_var_expand_locals"\n'
251 ' macroname = "macro_var_expand_locals"\n'
248 ' %macro {macroname} codestr\n')
252 ' %macro {macroname} codestr\n')
249 ip.user_ns['codestr'] = "str(12)"
253 ip.user_ns['codestr'] = "str(12)"
250 ip.run_cell('makemacro()')
254 ip.run_cell('makemacro()')
251 nt.assert_in('macro_var_expand_locals', ip.user_ns)
255 nt.assert_in('macro_var_expand_locals', ip.user_ns)
252
256
253 def test_var_expand_self(self):
257 def test_var_expand_self(self):
254 """Test variable expansion with the name 'self', which was failing.
258 """Test variable expansion with the name 'self', which was failing.
255
259
256 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
260 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
257 """
261 """
258 ip.run_cell('class cTest:\n'
262 ip.run_cell('class cTest:\n'
259 ' classvar="see me"\n'
263 ' classvar="see me"\n'
260 ' def test(self):\n'
264 ' def test(self):\n'
261 ' res = !echo Variable: {self.classvar}\n'
265 ' res = !echo Variable: {self.classvar}\n'
262 ' return res[0]\n')
266 ' return res[0]\n')
263 nt.assert_in('see me', ip.user_ns['cTest']().test())
267 nt.assert_in('see me', ip.user_ns['cTest']().test())
264
268
265 def test_bad_var_expand(self):
269 def test_bad_var_expand(self):
266 """var_expand on invalid formats shouldn't raise"""
270 """var_expand on invalid formats shouldn't raise"""
267 # SyntaxError
271 # SyntaxError
268 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
272 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
269 # NameError
273 # NameError
270 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
274 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
271 # ZeroDivisionError
275 # ZeroDivisionError
272 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
276 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
273
277
274 def test_silent_nopostexec(self):
278 def test_silent_nopostexec(self):
275 """run_cell(silent=True) doesn't invoke post-exec funcs"""
279 """run_cell(silent=True) doesn't invoke post-exec funcs"""
276 d = dict(called=False)
280 d = dict(called=False)
277 def set_called():
281 def set_called():
278 d['called'] = True
282 d['called'] = True
279
283
280 ip.register_post_execute(set_called)
284 ip.register_post_execute(set_called)
281 ip.run_cell("1", silent=True)
285 ip.run_cell("1", silent=True)
282 self.assertFalse(d['called'])
286 self.assertFalse(d['called'])
283 # double-check that non-silent exec did what we expected
287 # double-check that non-silent exec did what we expected
284 # silent to avoid
288 # silent to avoid
285 ip.run_cell("1")
289 ip.run_cell("1")
286 self.assertTrue(d['called'])
290 self.assertTrue(d['called'])
287 # remove post-exec
291 # remove post-exec
288 ip._post_execute.pop(set_called)
292 ip._post_execute.pop(set_called)
289
293
290 def test_silent_noadvance(self):
294 def test_silent_noadvance(self):
291 """run_cell(silent=True) doesn't advance execution_count"""
295 """run_cell(silent=True) doesn't advance execution_count"""
292 ec = ip.execution_count
296 ec = ip.execution_count
293 # silent should force store_history=False
297 # silent should force store_history=False
294 ip.run_cell("1", store_history=True, silent=True)
298 ip.run_cell("1", store_history=True, silent=True)
295
299
296 self.assertEqual(ec, ip.execution_count)
300 self.assertEqual(ec, ip.execution_count)
297 # double-check that non-silent exec did what we expected
301 # double-check that non-silent exec did what we expected
298 # silent to avoid
302 # silent to avoid
299 ip.run_cell("1", store_history=True)
303 ip.run_cell("1", store_history=True)
300 self.assertEqual(ec+1, ip.execution_count)
304 self.assertEqual(ec+1, ip.execution_count)
301
305
302 def test_silent_nodisplayhook(self):
306 def test_silent_nodisplayhook(self):
303 """run_cell(silent=True) doesn't trigger displayhook"""
307 """run_cell(silent=True) doesn't trigger displayhook"""
304 d = dict(called=False)
308 d = dict(called=False)
305
309
306 trap = ip.display_trap
310 trap = ip.display_trap
307 save_hook = trap.hook
311 save_hook = trap.hook
308
312
309 def failing_hook(*args, **kwargs):
313 def failing_hook(*args, **kwargs):
310 d['called'] = True
314 d['called'] = True
311
315
312 try:
316 try:
313 trap.hook = failing_hook
317 trap.hook = failing_hook
314 ip.run_cell("1", silent=True)
318 ip.run_cell("1", silent=True)
315 self.assertFalse(d['called'])
319 self.assertFalse(d['called'])
316 # double-check that non-silent exec did what we expected
320 # double-check that non-silent exec did what we expected
317 # silent to avoid
321 # silent to avoid
318 ip.run_cell("1")
322 ip.run_cell("1")
319 self.assertTrue(d['called'])
323 self.assertTrue(d['called'])
320 finally:
324 finally:
321 trap.hook = save_hook
325 trap.hook = save_hook
322
326
323 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
327 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
324 def test_print_softspace(self):
328 def test_print_softspace(self):
325 """Verify that softspace is handled correctly when executing multiple
329 """Verify that softspace is handled correctly when executing multiple
326 statements.
330 statements.
327
331
328 In [1]: print 1; print 2
332 In [1]: print 1; print 2
329 1
333 1
330 2
334 2
331
335
332 In [2]: print 1,; print 2
336 In [2]: print 1,; print 2
333 1 2
337 1 2
334 """
338 """
335
339
336 def test_ofind_line_magic(self):
340 def test_ofind_line_magic(self):
337 from IPython.core.magic import register_line_magic
341 from IPython.core.magic import register_line_magic
338
342
339 @register_line_magic
343 @register_line_magic
340 def lmagic(line):
344 def lmagic(line):
341 "A line magic"
345 "A line magic"
342
346
343 # Get info on line magic
347 # Get info on line magic
344 lfind = ip._ofind('lmagic')
348 lfind = ip._ofind('lmagic')
345 info = dict(found=True, isalias=False, ismagic=True,
349 info = dict(found=True, isalias=False, ismagic=True,
346 namespace = 'IPython internal', obj= lmagic.__wrapped__,
350 namespace = 'IPython internal', obj= lmagic.__wrapped__,
347 parent = None)
351 parent = None)
348 nt.assert_equal(lfind, info)
352 nt.assert_equal(lfind, info)
349
353
350 def test_ofind_cell_magic(self):
354 def test_ofind_cell_magic(self):
351 from IPython.core.magic import register_cell_magic
355 from IPython.core.magic import register_cell_magic
352
356
353 @register_cell_magic
357 @register_cell_magic
354 def cmagic(line, cell):
358 def cmagic(line, cell):
355 "A cell magic"
359 "A cell magic"
356
360
357 # Get info on cell magic
361 # Get info on cell magic
358 find = ip._ofind('cmagic')
362 find = ip._ofind('cmagic')
359 info = dict(found=True, isalias=False, ismagic=True,
363 info = dict(found=True, isalias=False, ismagic=True,
360 namespace = 'IPython internal', obj= cmagic.__wrapped__,
364 namespace = 'IPython internal', obj= cmagic.__wrapped__,
361 parent = None)
365 parent = None)
362 nt.assert_equal(find, info)
366 nt.assert_equal(find, info)
363
367
364 def test_custom_exception(self):
368 def test_custom_exception(self):
365 called = []
369 called = []
366 def my_handler(shell, etype, value, tb, tb_offset=None):
370 def my_handler(shell, etype, value, tb, tb_offset=None):
367 called.append(etype)
371 called.append(etype)
368 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
372 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
369
373
370 ip.set_custom_exc((ValueError,), my_handler)
374 ip.set_custom_exc((ValueError,), my_handler)
371 try:
375 try:
372 ip.run_cell("raise ValueError('test')")
376 ip.run_cell("raise ValueError('test')")
373 # Check that this was called, and only once.
377 # Check that this was called, and only once.
374 self.assertEqual(called, [ValueError])
378 self.assertEqual(called, [ValueError])
375 finally:
379 finally:
376 # Reset the custom exception hook
380 # Reset the custom exception hook
377 ip.set_custom_exc((), None)
381 ip.set_custom_exc((), None)
378
382
379 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
383 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
380 def test_future_environment(self):
384 def test_future_environment(self):
381 "Can we run code with & without the shell's __future__ imports?"
385 "Can we run code with & without the shell's __future__ imports?"
382 ip.run_cell("from __future__ import division")
386 ip.run_cell("from __future__ import division")
383 ip.run_cell("a = 1/2", shell_futures=True)
387 ip.run_cell("a = 1/2", shell_futures=True)
384 self.assertEqual(ip.user_ns['a'], 0.5)
388 self.assertEqual(ip.user_ns['a'], 0.5)
385 ip.run_cell("b = 1/2", shell_futures=False)
389 ip.run_cell("b = 1/2", shell_futures=False)
386 self.assertEqual(ip.user_ns['b'], 0)
390 self.assertEqual(ip.user_ns['b'], 0)
387
391
388 ip.compile.reset_compiler_flags()
392 ip.compile.reset_compiler_flags()
389 # This shouldn't leak to the shell's compiler
393 # This shouldn't leak to the shell's compiler
390 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
394 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
391 self.assertEqual(ip.user_ns['c'], 0.5)
395 self.assertEqual(ip.user_ns['c'], 0.5)
392 ip.run_cell("d = 1/2", shell_futures=True)
396 ip.run_cell("d = 1/2", shell_futures=True)
393 self.assertEqual(ip.user_ns['d'], 0)
397 self.assertEqual(ip.user_ns['d'], 0)
394
398
395
399
396 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
400 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
397
401
398 @onlyif_unicode_paths
402 @onlyif_unicode_paths
399 def setUp(self):
403 def setUp(self):
400 self.BASETESTDIR = tempfile.mkdtemp()
404 self.BASETESTDIR = tempfile.mkdtemp()
401 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
405 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
402 os.mkdir(self.TESTDIR)
406 os.mkdir(self.TESTDIR)
403 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
407 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
404 sfile.write("pass\n")
408 sfile.write("pass\n")
405 self.oldpath = os.getcwdu()
409 self.oldpath = os.getcwdu()
406 os.chdir(self.TESTDIR)
410 os.chdir(self.TESTDIR)
407 self.fname = u"Γ₯Àâtestscript.py"
411 self.fname = u"Γ₯Àâtestscript.py"
408
412
409 def tearDown(self):
413 def tearDown(self):
410 os.chdir(self.oldpath)
414 os.chdir(self.oldpath)
411 shutil.rmtree(self.BASETESTDIR)
415 shutil.rmtree(self.BASETESTDIR)
412
416
413 @onlyif_unicode_paths
417 @onlyif_unicode_paths
414 def test_1(self):
418 def test_1(self):
415 """Test safe_execfile with non-ascii path
419 """Test safe_execfile with non-ascii path
416 """
420 """
417 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
421 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
418
422
419 class ExitCodeChecks(tt.TempFileMixin):
423 class ExitCodeChecks(tt.TempFileMixin):
420 def test_exit_code_ok(self):
424 def test_exit_code_ok(self):
421 self.system('exit 0')
425 self.system('exit 0')
422 self.assertEqual(ip.user_ns['_exit_code'], 0)
426 self.assertEqual(ip.user_ns['_exit_code'], 0)
423
427
424 def test_exit_code_error(self):
428 def test_exit_code_error(self):
425 self.system('exit 1')
429 self.system('exit 1')
426 self.assertEqual(ip.user_ns['_exit_code'], 1)
430 self.assertEqual(ip.user_ns['_exit_code'], 1)
427
431
428 @skipif(not hasattr(signal, 'SIGALRM'))
432 @skipif(not hasattr(signal, 'SIGALRM'))
429 def test_exit_code_signal(self):
433 def test_exit_code_signal(self):
430 self.mktmp("import signal, time\n"
434 self.mktmp("import signal, time\n"
431 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
435 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
432 "time.sleep(1)\n")
436 "time.sleep(1)\n")
433 self.system("%s %s" % (sys.executable, self.fname))
437 self.system("%s %s" % (sys.executable, self.fname))
434 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
438 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
435
439
436 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
440 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
437 system = ip.system_raw
441 system = ip.system_raw
438
442
439 @onlyif_unicode_paths
443 @onlyif_unicode_paths
440 def test_1(self):
444 def test_1(self):
441 """Test system_raw with non-ascii cmd
445 """Test system_raw with non-ascii cmd
442 """
446 """
443 cmd = u'''python -c "'Γ₯Àâ'" '''
447 cmd = u'''python -c "'Γ₯Àâ'" '''
444 ip.system_raw(cmd)
448 ip.system_raw(cmd)
445
449
446 # TODO: Exit codes are currently ignored on Windows.
450 # TODO: Exit codes are currently ignored on Windows.
447 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
451 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
448 system = ip.system_piped
452 system = ip.system_piped
449
453
450 @skip_win32
454 @skip_win32
451 def test_exit_code_ok(self):
455 def test_exit_code_ok(self):
452 ExitCodeChecks.test_exit_code_ok(self)
456 ExitCodeChecks.test_exit_code_ok(self)
453
457
454 @skip_win32
458 @skip_win32
455 def test_exit_code_error(self):
459 def test_exit_code_error(self):
456 ExitCodeChecks.test_exit_code_error(self)
460 ExitCodeChecks.test_exit_code_error(self)
457
461
458 @skip_win32
462 @skip_win32
459 def test_exit_code_signal(self):
463 def test_exit_code_signal(self):
460 ExitCodeChecks.test_exit_code_signal(self)
464 ExitCodeChecks.test_exit_code_signal(self)
461
465
462 class TestModules(unittest.TestCase, tt.TempFileMixin):
466 class TestModules(unittest.TestCase, tt.TempFileMixin):
463 def test_extraneous_loads(self):
467 def test_extraneous_loads(self):
464 """Test we're not loading modules on startup that we shouldn't.
468 """Test we're not loading modules on startup that we shouldn't.
465 """
469 """
466 self.mktmp("import sys\n"
470 self.mktmp("import sys\n"
467 "print('numpy' in sys.modules)\n"
471 "print('numpy' in sys.modules)\n"
468 "print('IPython.parallel' in sys.modules)\n"
472 "print('IPython.parallel' in sys.modules)\n"
469 "print('IPython.kernel.zmq' in sys.modules)\n"
473 "print('IPython.kernel.zmq' in sys.modules)\n"
470 )
474 )
471 out = "False\nFalse\nFalse\n"
475 out = "False\nFalse\nFalse\n"
472 tt.ipexec_validate(self.fname, out)
476 tt.ipexec_validate(self.fname, out)
473
477
474 class Negator(ast.NodeTransformer):
478 class Negator(ast.NodeTransformer):
475 """Negates all number literals in an AST."""
479 """Negates all number literals in an AST."""
476 def visit_Num(self, node):
480 def visit_Num(self, node):
477 node.n = -node.n
481 node.n = -node.n
478 return node
482 return node
479
483
480 class TestAstTransform(unittest.TestCase):
484 class TestAstTransform(unittest.TestCase):
481 def setUp(self):
485 def setUp(self):
482 self.negator = Negator()
486 self.negator = Negator()
483 ip.ast_transformers.append(self.negator)
487 ip.ast_transformers.append(self.negator)
484
488
485 def tearDown(self):
489 def tearDown(self):
486 ip.ast_transformers.remove(self.negator)
490 ip.ast_transformers.remove(self.negator)
487
491
488 def test_run_cell(self):
492 def test_run_cell(self):
489 with tt.AssertPrints('-34'):
493 with tt.AssertPrints('-34'):
490 ip.run_cell('print (12 + 22)')
494 ip.run_cell('print (12 + 22)')
491
495
492 # A named reference to a number shouldn't be transformed.
496 # A named reference to a number shouldn't be transformed.
493 ip.user_ns['n'] = 55
497 ip.user_ns['n'] = 55
494 with tt.AssertNotPrints('-55'):
498 with tt.AssertNotPrints('-55'):
495 ip.run_cell('print (n)')
499 ip.run_cell('print (n)')
496
500
497 def test_timeit(self):
501 def test_timeit(self):
498 called = set()
502 called = set()
499 def f(x):
503 def f(x):
500 called.add(x)
504 called.add(x)
501 ip.push({'f':f})
505 ip.push({'f':f})
502
506
503 with tt.AssertPrints("best of "):
507 with tt.AssertPrints("best of "):
504 ip.run_line_magic("timeit", "-n1 f(1)")
508 ip.run_line_magic("timeit", "-n1 f(1)")
505 self.assertEqual(called, set([-1]))
509 self.assertEqual(called, set([-1]))
506 called.clear()
510 called.clear()
507
511
508 with tt.AssertPrints("best of "):
512 with tt.AssertPrints("best of "):
509 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
513 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
510 self.assertEqual(called, set([-2, -3]))
514 self.assertEqual(called, set([-2, -3]))
511
515
512 def test_time(self):
516 def test_time(self):
513 called = []
517 called = []
514 def f(x):
518 def f(x):
515 called.append(x)
519 called.append(x)
516 ip.push({'f':f})
520 ip.push({'f':f})
517
521
518 # Test with an expression
522 # Test with an expression
519 with tt.AssertPrints("Wall time: "):
523 with tt.AssertPrints("Wall time: "):
520 ip.run_line_magic("time", "f(5+9)")
524 ip.run_line_magic("time", "f(5+9)")
521 self.assertEqual(called, [-14])
525 self.assertEqual(called, [-14])
522 called[:] = []
526 called[:] = []
523
527
524 # Test with a statement (different code path)
528 # Test with a statement (different code path)
525 with tt.AssertPrints("Wall time: "):
529 with tt.AssertPrints("Wall time: "):
526 ip.run_line_magic("time", "a = f(-3 + -2)")
530 ip.run_line_magic("time", "a = f(-3 + -2)")
527 self.assertEqual(called, [5])
531 self.assertEqual(called, [5])
528
532
529 def test_macro(self):
533 def test_macro(self):
530 ip.push({'a':10})
534 ip.push({'a':10})
531 # The AST transformation makes this do a+=-1
535 # The AST transformation makes this do a+=-1
532 ip.define_macro("amacro", "a+=1\nprint(a)")
536 ip.define_macro("amacro", "a+=1\nprint(a)")
533
537
534 with tt.AssertPrints("9"):
538 with tt.AssertPrints("9"):
535 ip.run_cell("amacro")
539 ip.run_cell("amacro")
536 with tt.AssertPrints("8"):
540 with tt.AssertPrints("8"):
537 ip.run_cell("amacro")
541 ip.run_cell("amacro")
538
542
539 class IntegerWrapper(ast.NodeTransformer):
543 class IntegerWrapper(ast.NodeTransformer):
540 """Wraps all integers in a call to Integer()"""
544 """Wraps all integers in a call to Integer()"""
541 def visit_Num(self, node):
545 def visit_Num(self, node):
542 if isinstance(node.n, int):
546 if isinstance(node.n, int):
543 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
547 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
544 args=[node], keywords=[])
548 args=[node], keywords=[])
545 return node
549 return node
546
550
547 class TestAstTransform2(unittest.TestCase):
551 class TestAstTransform2(unittest.TestCase):
548 def setUp(self):
552 def setUp(self):
549 self.intwrapper = IntegerWrapper()
553 self.intwrapper = IntegerWrapper()
550 ip.ast_transformers.append(self.intwrapper)
554 ip.ast_transformers.append(self.intwrapper)
551
555
552 self.calls = []
556 self.calls = []
553 def Integer(*args):
557 def Integer(*args):
554 self.calls.append(args)
558 self.calls.append(args)
555 return args
559 return args
556 ip.push({"Integer": Integer})
560 ip.push({"Integer": Integer})
557
561
558 def tearDown(self):
562 def tearDown(self):
559 ip.ast_transformers.remove(self.intwrapper)
563 ip.ast_transformers.remove(self.intwrapper)
560 del ip.user_ns['Integer']
564 del ip.user_ns['Integer']
561
565
562 def test_run_cell(self):
566 def test_run_cell(self):
563 ip.run_cell("n = 2")
567 ip.run_cell("n = 2")
564 self.assertEqual(self.calls, [(2,)])
568 self.assertEqual(self.calls, [(2,)])
565
569
566 # This shouldn't throw an error
570 # This shouldn't throw an error
567 ip.run_cell("o = 2.0")
571 ip.run_cell("o = 2.0")
568 self.assertEqual(ip.user_ns['o'], 2.0)
572 self.assertEqual(ip.user_ns['o'], 2.0)
569
573
570 def test_timeit(self):
574 def test_timeit(self):
571 called = set()
575 called = set()
572 def f(x):
576 def f(x):
573 called.add(x)
577 called.add(x)
574 ip.push({'f':f})
578 ip.push({'f':f})
575
579
576 with tt.AssertPrints("best of "):
580 with tt.AssertPrints("best of "):
577 ip.run_line_magic("timeit", "-n1 f(1)")
581 ip.run_line_magic("timeit", "-n1 f(1)")
578 self.assertEqual(called, set([(1,)]))
582 self.assertEqual(called, set([(1,)]))
579 called.clear()
583 called.clear()
580
584
581 with tt.AssertPrints("best of "):
585 with tt.AssertPrints("best of "):
582 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
586 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
583 self.assertEqual(called, set([(2,), (3,)]))
587 self.assertEqual(called, set([(2,), (3,)]))
584
588
585 class ErrorTransformer(ast.NodeTransformer):
589 class ErrorTransformer(ast.NodeTransformer):
586 """Throws an error when it sees a number."""
590 """Throws an error when it sees a number."""
587 def visit_Num(self):
591 def visit_Num(self):
588 raise ValueError("test")
592 raise ValueError("test")
589
593
590 class TestAstTransformError(unittest.TestCase):
594 class TestAstTransformError(unittest.TestCase):
591 def test_unregistering(self):
595 def test_unregistering(self):
592 err_transformer = ErrorTransformer()
596 err_transformer = ErrorTransformer()
593 ip.ast_transformers.append(err_transformer)
597 ip.ast_transformers.append(err_transformer)
594
598
595 with tt.AssertPrints("unregister", channel='stderr'):
599 with tt.AssertPrints("unregister", channel='stderr'):
596 ip.run_cell("1 + 2")
600 ip.run_cell("1 + 2")
597
601
598 # This should have been removed.
602 # This should have been removed.
599 nt.assert_not_in(err_transformer, ip.ast_transformers)
603 nt.assert_not_in(err_transformer, ip.ast_transformers)
600
604
601 def test__IPYTHON__():
605 def test__IPYTHON__():
602 # This shouldn't raise a NameError, that's all
606 # This shouldn't raise a NameError, that's all
603 __IPYTHON__
607 __IPYTHON__
604
608
605
609
606 class DummyRepr(object):
610 class DummyRepr(object):
607 def __repr__(self):
611 def __repr__(self):
608 return "DummyRepr"
612 return "DummyRepr"
609
613
610 def _repr_html_(self):
614 def _repr_html_(self):
611 return "<b>dummy</b>"
615 return "<b>dummy</b>"
612
616
613 def _repr_javascript_(self):
617 def _repr_javascript_(self):
614 return "console.log('hi');", {'key': 'value'}
618 return "console.log('hi');", {'key': 'value'}
615
619
616
620
617 def test_user_variables():
621 def test_user_variables():
618 # enable all formatters
622 # enable all formatters
619 ip.display_formatter.active_types = ip.display_formatter.format_types
623 ip.display_formatter.active_types = ip.display_formatter.format_types
620
624
621 ip.user_ns['dummy'] = d = DummyRepr()
625 ip.user_ns['dummy'] = d = DummyRepr()
622 keys = set(['dummy', 'doesnotexist'])
626 keys = set(['dummy', 'doesnotexist'])
623 r = ip.user_variables(keys)
627 r = ip.user_variables(keys)
624
628
625 nt.assert_equal(keys, set(r.keys()))
629 nt.assert_equal(keys, set(r.keys()))
626 dummy = r['dummy']
630 dummy = r['dummy']
627 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
631 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
628 nt.assert_equal(dummy['status'], 'ok')
632 nt.assert_equal(dummy['status'], 'ok')
629 data = dummy['data']
633 data = dummy['data']
630 metadata = dummy['metadata']
634 metadata = dummy['metadata']
631 nt.assert_equal(data.get('text/html'), d._repr_html_())
635 nt.assert_equal(data.get('text/html'), d._repr_html_())
632 js, jsmd = d._repr_javascript_()
636 js, jsmd = d._repr_javascript_()
633 nt.assert_equal(data.get('application/javascript'), js)
637 nt.assert_equal(data.get('application/javascript'), js)
634 nt.assert_equal(metadata.get('application/javascript'), jsmd)
638 nt.assert_equal(metadata.get('application/javascript'), jsmd)
635
639
636 dne = r['doesnotexist']
640 dne = r['doesnotexist']
637 nt.assert_equal(dne['status'], 'error')
641 nt.assert_equal(dne['status'], 'error')
638 nt.assert_equal(dne['ename'], 'KeyError')
642 nt.assert_equal(dne['ename'], 'KeyError')
639
643
640 # back to text only
644 # back to text only
641 ip.display_formatter.active_types = ['text/plain']
645 ip.display_formatter.active_types = ['text/plain']
642
646
643 def test_user_expression():
647 def test_user_expression():
644 # enable all formatters
648 # enable all formatters
645 ip.display_formatter.active_types = ip.display_formatter.format_types
649 ip.display_formatter.active_types = ip.display_formatter.format_types
646 query = {
650 query = {
647 'a' : '1 + 2',
651 'a' : '1 + 2',
648 'b' : '1/0',
652 'b' : '1/0',
649 }
653 }
650 r = ip.user_expressions(query)
654 r = ip.user_expressions(query)
651 import pprint
655 import pprint
652 pprint.pprint(r)
656 pprint.pprint(r)
653 nt.assert_equal(r.keys(), query.keys())
657 nt.assert_equal(r.keys(), query.keys())
654 a = r['a']
658 a = r['a']
655 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
659 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
656 nt.assert_equal(a['status'], 'ok')
660 nt.assert_equal(a['status'], 'ok')
657 data = a['data']
661 data = a['data']
658 metadata = a['metadata']
662 metadata = a['metadata']
659 nt.assert_equal(data.get('text/plain'), '3')
663 nt.assert_equal(data.get('text/plain'), '3')
660
664
661 b = r['b']
665 b = r['b']
662 nt.assert_equal(b['status'], 'error')
666 nt.assert_equal(b['status'], 'error')
663 nt.assert_equal(b['ename'], 'ZeroDivisionError')
667 nt.assert_equal(b['ename'], 'ZeroDivisionError')
664
668
665 # back to text only
669 # back to text only
666 ip.display_formatter.active_types = ['text/plain']
670 ip.display_formatter.active_types = ['text/plain']
667
671
668
672
669
673
670
674
671
675
672
676
@@ -1,940 +1,944 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 import io
12 import io
13 import os
13 import os
14 import sys
14 import sys
15 from io import StringIO
16 from unittest import TestCase
15 from unittest import TestCase
17
16
18 try:
17 try:
19 from importlib import invalidate_caches # Required from Python 3.3
18 from importlib import invalidate_caches # Required from Python 3.3
20 except ImportError:
19 except ImportError:
21 def invalidate_caches():
20 def invalidate_caches():
22 pass
21 pass
23
22
24 import nose.tools as nt
23 import nose.tools as nt
25
24
26 from IPython.core import magic
25 from IPython.core import magic
27 from IPython.core.magic import (Magics, magics_class, line_magic,
26 from IPython.core.magic import (Magics, magics_class, line_magic,
28 cell_magic, line_cell_magic,
27 cell_magic, line_cell_magic,
29 register_line_magic, register_cell_magic,
28 register_line_magic, register_cell_magic,
30 register_line_cell_magic)
29 register_line_cell_magic)
31 from IPython.core.magics import execution, script, code
30 from IPython.core.magics import execution, script, code
32 from IPython.nbformat.v3.tests.nbexamples import nb0
31 from IPython.nbformat.v3.tests.nbexamples import nb0
33 from IPython.nbformat import current
32 from IPython.nbformat import current
34 from IPython.testing import decorators as dec
33 from IPython.testing import decorators as dec
35 from IPython.testing import tools as tt
34 from IPython.testing import tools as tt
36 from IPython.utils import py3compat
35 from IPython.utils import py3compat
37 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
38 from IPython.utils.tempdir import TemporaryDirectory
37 from IPython.utils.tempdir import TemporaryDirectory
39 from IPython.utils.process import find_cmd
38 from IPython.utils.process import find_cmd
40
39
40 if py3compat.PY3:
41 from io import StringIO
42 else:
43 from StringIO import StringIO
44
41 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
42 # Test functions begin
46 # Test functions begin
43 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
44
48
45 @magic.magics_class
49 @magic.magics_class
46 class DummyMagics(magic.Magics): pass
50 class DummyMagics(magic.Magics): pass
47
51
48 def test_extract_code_ranges():
52 def test_extract_code_ranges():
49 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
53 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
50 expected = [(0, 1),
54 expected = [(0, 1),
51 (2, 3),
55 (2, 3),
52 (4, 6),
56 (4, 6),
53 (6, 9),
57 (6, 9),
54 (9, 14),
58 (9, 14),
55 (16, None),
59 (16, None),
56 (None, 9),
60 (None, 9),
57 (9, None),
61 (9, None),
58 (None, 13),
62 (None, 13),
59 (None, None)]
63 (None, None)]
60 actual = list(code.extract_code_ranges(instr))
64 actual = list(code.extract_code_ranges(instr))
61 nt.assert_equal(actual, expected)
65 nt.assert_equal(actual, expected)
62
66
63 def test_extract_symbols():
67 def test_extract_symbols():
64 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
68 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
65 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
69 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
66 expected = [([], ['a']),
70 expected = [([], ['a']),
67 (["def b():\n return 42\n"], []),
71 (["def b():\n return 42\n"], []),
68 (["class A: pass\n"], []),
72 (["class A: pass\n"], []),
69 (["class A: pass\n", "def b():\n return 42\n"], []),
73 (["class A: pass\n", "def b():\n return 42\n"], []),
70 (["class A: pass\n"], ['a']),
74 (["class A: pass\n"], ['a']),
71 ([], ['z'])]
75 ([], ['z'])]
72 for symbols, exp in zip(symbols_args, expected):
76 for symbols, exp in zip(symbols_args, expected):
73 nt.assert_equal(code.extract_symbols(source, symbols), exp)
77 nt.assert_equal(code.extract_symbols(source, symbols), exp)
74
78
75
79
76 def test_extract_symbols_raises_exception_with_non_python_code():
80 def test_extract_symbols_raises_exception_with_non_python_code():
77 source = ("=begin A Ruby program :)=end\n"
81 source = ("=begin A Ruby program :)=end\n"
78 "def hello\n"
82 "def hello\n"
79 "puts 'Hello world'\n"
83 "puts 'Hello world'\n"
80 "end")
84 "end")
81 with nt.assert_raises(SyntaxError):
85 with nt.assert_raises(SyntaxError):
82 code.extract_symbols(source, "hello")
86 code.extract_symbols(source, "hello")
83
87
84 def test_config():
88 def test_config():
85 """ test that config magic does not raise
89 """ test that config magic does not raise
86 can happen if Configurable init is moved too early into
90 can happen if Configurable init is moved too early into
87 Magics.__init__ as then a Config object will be registerd as a
91 Magics.__init__ as then a Config object will be registerd as a
88 magic.
92 magic.
89 """
93 """
90 ## should not raise.
94 ## should not raise.
91 _ip.magic('config')
95 _ip.magic('config')
92
96
93 def test_rehashx():
97 def test_rehashx():
94 # clear up everything
98 # clear up everything
95 _ip = get_ipython()
99 _ip = get_ipython()
96 _ip.alias_manager.clear_aliases()
100 _ip.alias_manager.clear_aliases()
97 del _ip.db['syscmdlist']
101 del _ip.db['syscmdlist']
98
102
99 _ip.magic('rehashx')
103 _ip.magic('rehashx')
100 # Practically ALL ipython development systems will have more than 10 aliases
104 # Practically ALL ipython development systems will have more than 10 aliases
101
105
102 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
106 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
103 for name, cmd in _ip.alias_manager.aliases:
107 for name, cmd in _ip.alias_manager.aliases:
104 # we must strip dots from alias names
108 # we must strip dots from alias names
105 nt.assert_not_in('.', name)
109 nt.assert_not_in('.', name)
106
110
107 # rehashx must fill up syscmdlist
111 # rehashx must fill up syscmdlist
108 scoms = _ip.db['syscmdlist']
112 scoms = _ip.db['syscmdlist']
109 nt.assert_true(len(scoms) > 10)
113 nt.assert_true(len(scoms) > 10)
110
114
111
115
112 def test_magic_parse_options():
116 def test_magic_parse_options():
113 """Test that we don't mangle paths when parsing magic options."""
117 """Test that we don't mangle paths when parsing magic options."""
114 ip = get_ipython()
118 ip = get_ipython()
115 path = 'c:\\x'
119 path = 'c:\\x'
116 m = DummyMagics(ip)
120 m = DummyMagics(ip)
117 opts = m.parse_options('-f %s' % path,'f:')[0]
121 opts = m.parse_options('-f %s' % path,'f:')[0]
118 # argv splitting is os-dependent
122 # argv splitting is os-dependent
119 if os.name == 'posix':
123 if os.name == 'posix':
120 expected = 'c:x'
124 expected = 'c:x'
121 else:
125 else:
122 expected = path
126 expected = path
123 nt.assert_equal(opts['f'], expected)
127 nt.assert_equal(opts['f'], expected)
124
128
125 def test_magic_parse_long_options():
129 def test_magic_parse_long_options():
126 """Magic.parse_options can handle --foo=bar long options"""
130 """Magic.parse_options can handle --foo=bar long options"""
127 ip = get_ipython()
131 ip = get_ipython()
128 m = DummyMagics(ip)
132 m = DummyMagics(ip)
129 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
133 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
130 nt.assert_in('foo', opts)
134 nt.assert_in('foo', opts)
131 nt.assert_in('bar', opts)
135 nt.assert_in('bar', opts)
132 nt.assert_equal(opts['bar'], "bubble")
136 nt.assert_equal(opts['bar'], "bubble")
133
137
134
138
135 @dec.skip_without('sqlite3')
139 @dec.skip_without('sqlite3')
136 def doctest_hist_f():
140 def doctest_hist_f():
137 """Test %hist -f with temporary filename.
141 """Test %hist -f with temporary filename.
138
142
139 In [9]: import tempfile
143 In [9]: import tempfile
140
144
141 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
145 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
142
146
143 In [11]: %hist -nl -f $tfile 3
147 In [11]: %hist -nl -f $tfile 3
144
148
145 In [13]: import os; os.unlink(tfile)
149 In [13]: import os; os.unlink(tfile)
146 """
150 """
147
151
148
152
149 @dec.skip_without('sqlite3')
153 @dec.skip_without('sqlite3')
150 def doctest_hist_r():
154 def doctest_hist_r():
151 """Test %hist -r
155 """Test %hist -r
152
156
153 XXX - This test is not recording the output correctly. For some reason, in
157 XXX - This test is not recording the output correctly. For some reason, in
154 testing mode the raw history isn't getting populated. No idea why.
158 testing mode the raw history isn't getting populated. No idea why.
155 Disabling the output checking for now, though at least we do run it.
159 Disabling the output checking for now, though at least we do run it.
156
160
157 In [1]: 'hist' in _ip.lsmagic()
161 In [1]: 'hist' in _ip.lsmagic()
158 Out[1]: True
162 Out[1]: True
159
163
160 In [2]: x=1
164 In [2]: x=1
161
165
162 In [3]: %hist -rl 2
166 In [3]: %hist -rl 2
163 x=1 # random
167 x=1 # random
164 %hist -r 2
168 %hist -r 2
165 """
169 """
166
170
167
171
168 @dec.skip_without('sqlite3')
172 @dec.skip_without('sqlite3')
169 def doctest_hist_op():
173 def doctest_hist_op():
170 """Test %hist -op
174 """Test %hist -op
171
175
172 In [1]: class b(float):
176 In [1]: class b(float):
173 ...: pass
177 ...: pass
174 ...:
178 ...:
175
179
176 In [2]: class s(object):
180 In [2]: class s(object):
177 ...: def __str__(self):
181 ...: def __str__(self):
178 ...: return 's'
182 ...: return 's'
179 ...:
183 ...:
180
184
181 In [3]:
185 In [3]:
182
186
183 In [4]: class r(b):
187 In [4]: class r(b):
184 ...: def __repr__(self):
188 ...: def __repr__(self):
185 ...: return 'r'
189 ...: return 'r'
186 ...:
190 ...:
187
191
188 In [5]: class sr(s,r): pass
192 In [5]: class sr(s,r): pass
189 ...:
193 ...:
190
194
191 In [6]:
195 In [6]:
192
196
193 In [7]: bb=b()
197 In [7]: bb=b()
194
198
195 In [8]: ss=s()
199 In [8]: ss=s()
196
200
197 In [9]: rr=r()
201 In [9]: rr=r()
198
202
199 In [10]: ssrr=sr()
203 In [10]: ssrr=sr()
200
204
201 In [11]: 4.5
205 In [11]: 4.5
202 Out[11]: 4.5
206 Out[11]: 4.5
203
207
204 In [12]: str(ss)
208 In [12]: str(ss)
205 Out[12]: 's'
209 Out[12]: 's'
206
210
207 In [13]:
211 In [13]:
208
212
209 In [14]: %hist -op
213 In [14]: %hist -op
210 >>> class b:
214 >>> class b:
211 ... pass
215 ... pass
212 ...
216 ...
213 >>> class s(b):
217 >>> class s(b):
214 ... def __str__(self):
218 ... def __str__(self):
215 ... return 's'
219 ... return 's'
216 ...
220 ...
217 >>>
221 >>>
218 >>> class r(b):
222 >>> class r(b):
219 ... def __repr__(self):
223 ... def __repr__(self):
220 ... return 'r'
224 ... return 'r'
221 ...
225 ...
222 >>> class sr(s,r): pass
226 >>> class sr(s,r): pass
223 >>>
227 >>>
224 >>> bb=b()
228 >>> bb=b()
225 >>> ss=s()
229 >>> ss=s()
226 >>> rr=r()
230 >>> rr=r()
227 >>> ssrr=sr()
231 >>> ssrr=sr()
228 >>> 4.5
232 >>> 4.5
229 4.5
233 4.5
230 >>> str(ss)
234 >>> str(ss)
231 's'
235 's'
232 >>>
236 >>>
233 """
237 """
234
238
235
239
236 @dec.skip_without('sqlite3')
240 @dec.skip_without('sqlite3')
237 def test_macro():
241 def test_macro():
238 ip = get_ipython()
242 ip = get_ipython()
239 ip.history_manager.reset() # Clear any existing history.
243 ip.history_manager.reset() # Clear any existing history.
240 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
244 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
241 for i, cmd in enumerate(cmds, start=1):
245 for i, cmd in enumerate(cmds, start=1):
242 ip.history_manager.store_inputs(i, cmd)
246 ip.history_manager.store_inputs(i, cmd)
243 ip.magic("macro test 1-3")
247 ip.magic("macro test 1-3")
244 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
248 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
245
249
246 # List macros
250 # List macros
247 nt.assert_in("test", ip.magic("macro"))
251 nt.assert_in("test", ip.magic("macro"))
248
252
249
253
250 @dec.skip_without('sqlite3')
254 @dec.skip_without('sqlite3')
251 def test_macro_run():
255 def test_macro_run():
252 """Test that we can run a multi-line macro successfully."""
256 """Test that we can run a multi-line macro successfully."""
253 ip = get_ipython()
257 ip = get_ipython()
254 ip.history_manager.reset()
258 ip.history_manager.reset()
255 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
259 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
256 "%macro test 2-3"]
260 "%macro test 2-3"]
257 for cmd in cmds:
261 for cmd in cmds:
258 ip.run_cell(cmd, store_history=True)
262 ip.run_cell(cmd, store_history=True)
259 nt.assert_equal(ip.user_ns["test"].value,
263 nt.assert_equal(ip.user_ns["test"].value,
260 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
264 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
261 with tt.AssertPrints("12"):
265 with tt.AssertPrints("12"):
262 ip.run_cell("test")
266 ip.run_cell("test")
263 with tt.AssertPrints("13"):
267 with tt.AssertPrints("13"):
264 ip.run_cell("test")
268 ip.run_cell("test")
265
269
266
270
267 def test_magic_magic():
271 def test_magic_magic():
268 """Test %magic"""
272 """Test %magic"""
269 ip = get_ipython()
273 ip = get_ipython()
270 with capture_output() as captured:
274 with capture_output() as captured:
271 ip.magic("magic")
275 ip.magic("magic")
272
276
273 stdout = captured.stdout
277 stdout = captured.stdout
274 nt.assert_in('%magic', stdout)
278 nt.assert_in('%magic', stdout)
275 nt.assert_in('IPython', stdout)
279 nt.assert_in('IPython', stdout)
276 nt.assert_in('Available', stdout)
280 nt.assert_in('Available', stdout)
277
281
278
282
279 @dec.skipif_not_numpy
283 @dec.skipif_not_numpy
280 def test_numpy_reset_array_undec():
284 def test_numpy_reset_array_undec():
281 "Test '%reset array' functionality"
285 "Test '%reset array' functionality"
282 _ip.ex('import numpy as np')
286 _ip.ex('import numpy as np')
283 _ip.ex('a = np.empty(2)')
287 _ip.ex('a = np.empty(2)')
284 nt.assert_in('a', _ip.user_ns)
288 nt.assert_in('a', _ip.user_ns)
285 _ip.magic('reset -f array')
289 _ip.magic('reset -f array')
286 nt.assert_not_in('a', _ip.user_ns)
290 nt.assert_not_in('a', _ip.user_ns)
287
291
288 def test_reset_out():
292 def test_reset_out():
289 "Test '%reset out' magic"
293 "Test '%reset out' magic"
290 _ip.run_cell("parrot = 'dead'", store_history=True)
294 _ip.run_cell("parrot = 'dead'", store_history=True)
291 # test '%reset -f out', make an Out prompt
295 # test '%reset -f out', make an Out prompt
292 _ip.run_cell("parrot", store_history=True)
296 _ip.run_cell("parrot", store_history=True)
293 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
297 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
294 _ip.magic('reset -f out')
298 _ip.magic('reset -f out')
295 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
299 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
296 nt.assert_equal(len(_ip.user_ns['Out']), 0)
300 nt.assert_equal(len(_ip.user_ns['Out']), 0)
297
301
298 def test_reset_in():
302 def test_reset_in():
299 "Test '%reset in' magic"
303 "Test '%reset in' magic"
300 # test '%reset -f in'
304 # test '%reset -f in'
301 _ip.run_cell("parrot", store_history=True)
305 _ip.run_cell("parrot", store_history=True)
302 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
306 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
303 _ip.magic('%reset -f in')
307 _ip.magic('%reset -f in')
304 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
308 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
305 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
309 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
306
310
307 def test_reset_dhist():
311 def test_reset_dhist():
308 "Test '%reset dhist' magic"
312 "Test '%reset dhist' magic"
309 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
313 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
310 _ip.magic('cd ' + os.path.dirname(nt.__file__))
314 _ip.magic('cd ' + os.path.dirname(nt.__file__))
311 _ip.magic('cd -')
315 _ip.magic('cd -')
312 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
316 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
313 _ip.magic('reset -f dhist')
317 _ip.magic('reset -f dhist')
314 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
318 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
315 _ip.run_cell("_dh = [d for d in tmp]") #restore
319 _ip.run_cell("_dh = [d for d in tmp]") #restore
316
320
317 def test_reset_in_length():
321 def test_reset_in_length():
318 "Test that '%reset in' preserves In[] length"
322 "Test that '%reset in' preserves In[] length"
319 _ip.run_cell("print 'foo'")
323 _ip.run_cell("print 'foo'")
320 _ip.run_cell("reset -f in")
324 _ip.run_cell("reset -f in")
321 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
325 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
322
326
323 def test_tb_syntaxerror():
327 def test_tb_syntaxerror():
324 """test %tb after a SyntaxError"""
328 """test %tb after a SyntaxError"""
325 ip = get_ipython()
329 ip = get_ipython()
326 ip.run_cell("for")
330 ip.run_cell("for")
327
331
328 # trap and validate stdout
332 # trap and validate stdout
329 save_stdout = sys.stdout
333 save_stdout = sys.stdout
330 try:
334 try:
331 sys.stdout = StringIO()
335 sys.stdout = StringIO()
332 ip.run_cell("%tb")
336 ip.run_cell("%tb")
333 out = sys.stdout.getvalue()
337 out = sys.stdout.getvalue()
334 finally:
338 finally:
335 sys.stdout = save_stdout
339 sys.stdout = save_stdout
336 # trim output, and only check the last line
340 # trim output, and only check the last line
337 last_line = out.rstrip().splitlines()[-1].strip()
341 last_line = out.rstrip().splitlines()[-1].strip()
338 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
342 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
339
343
340
344
341 def test_time():
345 def test_time():
342 ip = get_ipython()
346 ip = get_ipython()
343
347
344 with tt.AssertPrints("Wall time: "):
348 with tt.AssertPrints("Wall time: "):
345 ip.run_cell("%time None")
349 ip.run_cell("%time None")
346
350
347 ip.run_cell("def f(kmjy):\n"
351 ip.run_cell("def f(kmjy):\n"
348 " %time print (2*kmjy)")
352 " %time print (2*kmjy)")
349
353
350 with tt.AssertPrints("Wall time: "):
354 with tt.AssertPrints("Wall time: "):
351 with tt.AssertPrints("hihi", suppress=False):
355 with tt.AssertPrints("hihi", suppress=False):
352 ip.run_cell("f('hi')")
356 ip.run_cell("f('hi')")
353
357
354
358
355 @dec.skip_win32
359 @dec.skip_win32
356 def test_time2():
360 def test_time2():
357 ip = get_ipython()
361 ip = get_ipython()
358
362
359 with tt.AssertPrints("CPU times: user "):
363 with tt.AssertPrints("CPU times: user "):
360 ip.run_cell("%time None")
364 ip.run_cell("%time None")
361
365
362 def test_time3():
366 def test_time3():
363 """Erroneous magic function calls, issue gh-3334"""
367 """Erroneous magic function calls, issue gh-3334"""
364 ip = get_ipython()
368 ip = get_ipython()
365 ip.user_ns.pop('run', None)
369 ip.user_ns.pop('run', None)
366
370
367 with tt.AssertNotPrints("not found", channel='stderr'):
371 with tt.AssertNotPrints("not found", channel='stderr'):
368 ip.run_cell("%%time\n"
372 ip.run_cell("%%time\n"
369 "run = 0\n"
373 "run = 0\n"
370 "run += 1")
374 "run += 1")
371
375
372 def test_doctest_mode():
376 def test_doctest_mode():
373 "Toggle doctest_mode twice, it should be a no-op and run without error"
377 "Toggle doctest_mode twice, it should be a no-op and run without error"
374 _ip.magic('doctest_mode')
378 _ip.magic('doctest_mode')
375 _ip.magic('doctest_mode')
379 _ip.magic('doctest_mode')
376
380
377
381
378 def test_parse_options():
382 def test_parse_options():
379 """Tests for basic options parsing in magics."""
383 """Tests for basic options parsing in magics."""
380 # These are only the most minimal of tests, more should be added later. At
384 # These are only the most minimal of tests, more should be added later. At
381 # the very least we check that basic text/unicode calls work OK.
385 # the very least we check that basic text/unicode calls work OK.
382 m = DummyMagics(_ip)
386 m = DummyMagics(_ip)
383 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
387 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
384 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
388 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
385
389
386
390
387 def test_dirops():
391 def test_dirops():
388 """Test various directory handling operations."""
392 """Test various directory handling operations."""
389 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
393 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
390 curpath = os.getcwdu
394 curpath = os.getcwdu
391 startdir = os.getcwdu()
395 startdir = os.getcwdu()
392 ipdir = os.path.realpath(_ip.ipython_dir)
396 ipdir = os.path.realpath(_ip.ipython_dir)
393 try:
397 try:
394 _ip.magic('cd "%s"' % ipdir)
398 _ip.magic('cd "%s"' % ipdir)
395 nt.assert_equal(curpath(), ipdir)
399 nt.assert_equal(curpath(), ipdir)
396 _ip.magic('cd -')
400 _ip.magic('cd -')
397 nt.assert_equal(curpath(), startdir)
401 nt.assert_equal(curpath(), startdir)
398 _ip.magic('pushd "%s"' % ipdir)
402 _ip.magic('pushd "%s"' % ipdir)
399 nt.assert_equal(curpath(), ipdir)
403 nt.assert_equal(curpath(), ipdir)
400 _ip.magic('popd')
404 _ip.magic('popd')
401 nt.assert_equal(curpath(), startdir)
405 nt.assert_equal(curpath(), startdir)
402 finally:
406 finally:
403 os.chdir(startdir)
407 os.chdir(startdir)
404
408
405
409
406 def test_xmode():
410 def test_xmode():
407 # Calling xmode three times should be a no-op
411 # Calling xmode three times should be a no-op
408 xmode = _ip.InteractiveTB.mode
412 xmode = _ip.InteractiveTB.mode
409 for i in range(3):
413 for i in range(3):
410 _ip.magic("xmode")
414 _ip.magic("xmode")
411 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
415 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
412
416
413 def test_reset_hard():
417 def test_reset_hard():
414 monitor = []
418 monitor = []
415 class A(object):
419 class A(object):
416 def __del__(self):
420 def __del__(self):
417 monitor.append(1)
421 monitor.append(1)
418 def __repr__(self):
422 def __repr__(self):
419 return "<A instance>"
423 return "<A instance>"
420
424
421 _ip.user_ns["a"] = A()
425 _ip.user_ns["a"] = A()
422 _ip.run_cell("a")
426 _ip.run_cell("a")
423
427
424 nt.assert_equal(monitor, [])
428 nt.assert_equal(monitor, [])
425 _ip.magic("reset -f")
429 _ip.magic("reset -f")
426 nt.assert_equal(monitor, [1])
430 nt.assert_equal(monitor, [1])
427
431
428 class TestXdel(tt.TempFileMixin):
432 class TestXdel(tt.TempFileMixin):
429 def test_xdel(self):
433 def test_xdel(self):
430 """Test that references from %run are cleared by xdel."""
434 """Test that references from %run are cleared by xdel."""
431 src = ("class A(object):\n"
435 src = ("class A(object):\n"
432 " monitor = []\n"
436 " monitor = []\n"
433 " def __del__(self):\n"
437 " def __del__(self):\n"
434 " self.monitor.append(1)\n"
438 " self.monitor.append(1)\n"
435 "a = A()\n")
439 "a = A()\n")
436 self.mktmp(src)
440 self.mktmp(src)
437 # %run creates some hidden references...
441 # %run creates some hidden references...
438 _ip.magic("run %s" % self.fname)
442 _ip.magic("run %s" % self.fname)
439 # ... as does the displayhook.
443 # ... as does the displayhook.
440 _ip.run_cell("a")
444 _ip.run_cell("a")
441
445
442 monitor = _ip.user_ns["A"].monitor
446 monitor = _ip.user_ns["A"].monitor
443 nt.assert_equal(monitor, [])
447 nt.assert_equal(monitor, [])
444
448
445 _ip.magic("xdel a")
449 _ip.magic("xdel a")
446
450
447 # Check that a's __del__ method has been called.
451 # Check that a's __del__ method has been called.
448 nt.assert_equal(monitor, [1])
452 nt.assert_equal(monitor, [1])
449
453
450 def doctest_who():
454 def doctest_who():
451 """doctest for %who
455 """doctest for %who
452
456
453 In [1]: %reset -f
457 In [1]: %reset -f
454
458
455 In [2]: alpha = 123
459 In [2]: alpha = 123
456
460
457 In [3]: beta = 'beta'
461 In [3]: beta = 'beta'
458
462
459 In [4]: %who int
463 In [4]: %who int
460 alpha
464 alpha
461
465
462 In [5]: %who str
466 In [5]: %who str
463 beta
467 beta
464
468
465 In [6]: %whos
469 In [6]: %whos
466 Variable Type Data/Info
470 Variable Type Data/Info
467 ----------------------------
471 ----------------------------
468 alpha int 123
472 alpha int 123
469 beta str beta
473 beta str beta
470
474
471 In [7]: %who_ls
475 In [7]: %who_ls
472 Out[7]: ['alpha', 'beta']
476 Out[7]: ['alpha', 'beta']
473 """
477 """
474
478
475 def test_whos():
479 def test_whos():
476 """Check that whos is protected against objects where repr() fails."""
480 """Check that whos is protected against objects where repr() fails."""
477 class A(object):
481 class A(object):
478 def __repr__(self):
482 def __repr__(self):
479 raise Exception()
483 raise Exception()
480 _ip.user_ns['a'] = A()
484 _ip.user_ns['a'] = A()
481 _ip.magic("whos")
485 _ip.magic("whos")
482
486
483 @py3compat.u_format
487 @py3compat.u_format
484 def doctest_precision():
488 def doctest_precision():
485 """doctest for %precision
489 """doctest for %precision
486
490
487 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
491 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
488
492
489 In [2]: %precision 5
493 In [2]: %precision 5
490 Out[2]: {u}'%.5f'
494 Out[2]: {u}'%.5f'
491
495
492 In [3]: f.float_format
496 In [3]: f.float_format
493 Out[3]: {u}'%.5f'
497 Out[3]: {u}'%.5f'
494
498
495 In [4]: %precision %e
499 In [4]: %precision %e
496 Out[4]: {u}'%e'
500 Out[4]: {u}'%e'
497
501
498 In [5]: f(3.1415927)
502 In [5]: f(3.1415927)
499 Out[5]: {u}'3.141593e+00'
503 Out[5]: {u}'3.141593e+00'
500 """
504 """
501
505
502 def test_psearch():
506 def test_psearch():
503 with tt.AssertPrints("dict.fromkeys"):
507 with tt.AssertPrints("dict.fromkeys"):
504 _ip.run_cell("dict.fr*?")
508 _ip.run_cell("dict.fr*?")
505
509
506 def test_timeit_shlex():
510 def test_timeit_shlex():
507 """test shlex issues with timeit (#1109)"""
511 """test shlex issues with timeit (#1109)"""
508 _ip.ex("def f(*a,**kw): pass")
512 _ip.ex("def f(*a,**kw): pass")
509 _ip.magic('timeit -n1 "this is a bug".count(" ")')
513 _ip.magic('timeit -n1 "this is a bug".count(" ")')
510 _ip.magic('timeit -r1 -n1 f(" ", 1)')
514 _ip.magic('timeit -r1 -n1 f(" ", 1)')
511 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
515 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
512 _ip.magic('timeit -r1 -n1 ("a " + "b")')
516 _ip.magic('timeit -r1 -n1 ("a " + "b")')
513 _ip.magic('timeit -r1 -n1 f("a " + "b")')
517 _ip.magic('timeit -r1 -n1 f("a " + "b")')
514 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
518 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
515
519
516
520
517 def test_timeit_arguments():
521 def test_timeit_arguments():
518 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
522 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
519 _ip.magic("timeit ('#')")
523 _ip.magic("timeit ('#')")
520
524
521
525
522 def test_timeit_special_syntax():
526 def test_timeit_special_syntax():
523 "Test %%timeit with IPython special syntax"
527 "Test %%timeit with IPython special syntax"
524 @register_line_magic
528 @register_line_magic
525 def lmagic(line):
529 def lmagic(line):
526 ip = get_ipython()
530 ip = get_ipython()
527 ip.user_ns['lmagic_out'] = line
531 ip.user_ns['lmagic_out'] = line
528
532
529 # line mode test
533 # line mode test
530 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
534 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
531 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
535 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
532 # cell mode test
536 # cell mode test
533 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
537 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
534 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
538 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
535
539
536 def test_timeit_return():
540 def test_timeit_return():
537 """
541 """
538 test wether timeit -o return object
542 test wether timeit -o return object
539 """
543 """
540
544
541 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
545 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
542 assert(res is not None)
546 assert(res is not None)
543
547
544 def test_timeit_quiet():
548 def test_timeit_quiet():
545 """
549 """
546 test quiet option of timeit magic
550 test quiet option of timeit magic
547 """
551 """
548 with tt.AssertNotPrints("loops"):
552 with tt.AssertNotPrints("loops"):
549 _ip.run_cell("%timeit -n1 -r1 -q 1")
553 _ip.run_cell("%timeit -n1 -r1 -q 1")
550
554
551 @dec.skipif(execution.profile is None)
555 @dec.skipif(execution.profile is None)
552 def test_prun_special_syntax():
556 def test_prun_special_syntax():
553 "Test %%prun with IPython special syntax"
557 "Test %%prun with IPython special syntax"
554 @register_line_magic
558 @register_line_magic
555 def lmagic(line):
559 def lmagic(line):
556 ip = get_ipython()
560 ip = get_ipython()
557 ip.user_ns['lmagic_out'] = line
561 ip.user_ns['lmagic_out'] = line
558
562
559 # line mode test
563 # line mode test
560 _ip.run_line_magic('prun', '-q %lmagic my line')
564 _ip.run_line_magic('prun', '-q %lmagic my line')
561 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
565 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
562 # cell mode test
566 # cell mode test
563 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
567 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
564 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
568 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
565
569
566 @dec.skipif(execution.profile is None)
570 @dec.skipif(execution.profile is None)
567 def test_prun_quotes():
571 def test_prun_quotes():
568 "Test that prun does not clobber string escapes (GH #1302)"
572 "Test that prun does not clobber string escapes (GH #1302)"
569 _ip.magic(r"prun -q x = '\t'")
573 _ip.magic(r"prun -q x = '\t'")
570 nt.assert_equal(_ip.user_ns['x'], '\t')
574 nt.assert_equal(_ip.user_ns['x'], '\t')
571
575
572 def test_extension():
576 def test_extension():
573 tmpdir = TemporaryDirectory()
577 tmpdir = TemporaryDirectory()
574 orig_ipython_dir = _ip.ipython_dir
578 orig_ipython_dir = _ip.ipython_dir
575 try:
579 try:
576 _ip.ipython_dir = tmpdir.name
580 _ip.ipython_dir = tmpdir.name
577 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
581 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
578 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
582 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
579 _ip.magic("install_ext %s" % url)
583 _ip.magic("install_ext %s" % url)
580 _ip.user_ns.pop('arq', None)
584 _ip.user_ns.pop('arq', None)
581 invalidate_caches() # Clear import caches
585 invalidate_caches() # Clear import caches
582 _ip.magic("load_ext daft_extension")
586 _ip.magic("load_ext daft_extension")
583 nt.assert_equal(_ip.user_ns['arq'], 185)
587 nt.assert_equal(_ip.user_ns['arq'], 185)
584 _ip.magic("unload_ext daft_extension")
588 _ip.magic("unload_ext daft_extension")
585 assert 'arq' not in _ip.user_ns
589 assert 'arq' not in _ip.user_ns
586 finally:
590 finally:
587 _ip.ipython_dir = orig_ipython_dir
591 _ip.ipython_dir = orig_ipython_dir
588 tmpdir.cleanup()
592 tmpdir.cleanup()
589
593
590 def test_notebook_export_json():
594 def test_notebook_export_json():
591 with TemporaryDirectory() as td:
595 with TemporaryDirectory() as td:
592 outfile = os.path.join(td, "nb.ipynb")
596 outfile = os.path.join(td, "nb.ipynb")
593 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
597 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
594 _ip.magic("notebook -e %s" % outfile)
598 _ip.magic("notebook -e %s" % outfile)
595
599
596 def test_notebook_export_py():
600 def test_notebook_export_py():
597 with TemporaryDirectory() as td:
601 with TemporaryDirectory() as td:
598 outfile = os.path.join(td, "nb.py")
602 outfile = os.path.join(td, "nb.py")
599 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
603 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
600 _ip.magic("notebook -e %s" % outfile)
604 _ip.magic("notebook -e %s" % outfile)
601
605
602 def test_notebook_reformat_py():
606 def test_notebook_reformat_py():
603 with TemporaryDirectory() as td:
607 with TemporaryDirectory() as td:
604 infile = os.path.join(td, "nb.ipynb")
608 infile = os.path.join(td, "nb.ipynb")
605 with io.open(infile, 'w', encoding='utf-8') as f:
609 with io.open(infile, 'w', encoding='utf-8') as f:
606 current.write(nb0, f, 'json')
610 current.write(nb0, f, 'json')
607
611
608 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
612 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
609 _ip.magic("notebook -f py %s" % infile)
613 _ip.magic("notebook -f py %s" % infile)
610
614
611 def test_notebook_reformat_json():
615 def test_notebook_reformat_json():
612 with TemporaryDirectory() as td:
616 with TemporaryDirectory() as td:
613 infile = os.path.join(td, "nb.py")
617 infile = os.path.join(td, "nb.py")
614 with io.open(infile, 'w', encoding='utf-8') as f:
618 with io.open(infile, 'w', encoding='utf-8') as f:
615 current.write(nb0, f, 'py')
619 current.write(nb0, f, 'py')
616
620
617 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
621 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
618 _ip.magic("notebook -f ipynb %s" % infile)
622 _ip.magic("notebook -f ipynb %s" % infile)
619 _ip.magic("notebook -f json %s" % infile)
623 _ip.magic("notebook -f json %s" % infile)
620
624
621 def test_env():
625 def test_env():
622 env = _ip.magic("env")
626 env = _ip.magic("env")
623 assert isinstance(env, dict), type(env)
627 assert isinstance(env, dict), type(env)
624
628
625
629
626 class CellMagicTestCase(TestCase):
630 class CellMagicTestCase(TestCase):
627
631
628 def check_ident(self, magic):
632 def check_ident(self, magic):
629 # Manually called, we get the result
633 # Manually called, we get the result
630 out = _ip.run_cell_magic(magic, 'a', 'b')
634 out = _ip.run_cell_magic(magic, 'a', 'b')
631 nt.assert_equal(out, ('a','b'))
635 nt.assert_equal(out, ('a','b'))
632 # Via run_cell, it goes into the user's namespace via displayhook
636 # Via run_cell, it goes into the user's namespace via displayhook
633 _ip.run_cell('%%' + magic +' c\nd')
637 _ip.run_cell('%%' + magic +' c\nd')
634 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
638 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
635
639
636 def test_cell_magic_func_deco(self):
640 def test_cell_magic_func_deco(self):
637 "Cell magic using simple decorator"
641 "Cell magic using simple decorator"
638 @register_cell_magic
642 @register_cell_magic
639 def cellm(line, cell):
643 def cellm(line, cell):
640 return line, cell
644 return line, cell
641
645
642 self.check_ident('cellm')
646 self.check_ident('cellm')
643
647
644 def test_cell_magic_reg(self):
648 def test_cell_magic_reg(self):
645 "Cell magic manually registered"
649 "Cell magic manually registered"
646 def cellm(line, cell):
650 def cellm(line, cell):
647 return line, cell
651 return line, cell
648
652
649 _ip.register_magic_function(cellm, 'cell', 'cellm2')
653 _ip.register_magic_function(cellm, 'cell', 'cellm2')
650 self.check_ident('cellm2')
654 self.check_ident('cellm2')
651
655
652 def test_cell_magic_class(self):
656 def test_cell_magic_class(self):
653 "Cell magics declared via a class"
657 "Cell magics declared via a class"
654 @magics_class
658 @magics_class
655 class MyMagics(Magics):
659 class MyMagics(Magics):
656
660
657 @cell_magic
661 @cell_magic
658 def cellm3(self, line, cell):
662 def cellm3(self, line, cell):
659 return line, cell
663 return line, cell
660
664
661 _ip.register_magics(MyMagics)
665 _ip.register_magics(MyMagics)
662 self.check_ident('cellm3')
666 self.check_ident('cellm3')
663
667
664 def test_cell_magic_class2(self):
668 def test_cell_magic_class2(self):
665 "Cell magics declared via a class, #2"
669 "Cell magics declared via a class, #2"
666 @magics_class
670 @magics_class
667 class MyMagics2(Magics):
671 class MyMagics2(Magics):
668
672
669 @cell_magic('cellm4')
673 @cell_magic('cellm4')
670 def cellm33(self, line, cell):
674 def cellm33(self, line, cell):
671 return line, cell
675 return line, cell
672
676
673 _ip.register_magics(MyMagics2)
677 _ip.register_magics(MyMagics2)
674 self.check_ident('cellm4')
678 self.check_ident('cellm4')
675 # Check that nothing is registered as 'cellm33'
679 # Check that nothing is registered as 'cellm33'
676 c33 = _ip.find_cell_magic('cellm33')
680 c33 = _ip.find_cell_magic('cellm33')
677 nt.assert_equal(c33, None)
681 nt.assert_equal(c33, None)
678
682
679 def test_file():
683 def test_file():
680 """Basic %%file"""
684 """Basic %%file"""
681 ip = get_ipython()
685 ip = get_ipython()
682 with TemporaryDirectory() as td:
686 with TemporaryDirectory() as td:
683 fname = os.path.join(td, 'file1')
687 fname = os.path.join(td, 'file1')
684 ip.run_cell_magic("file", fname, u'\n'.join([
688 ip.run_cell_magic("file", fname, u'\n'.join([
685 'line1',
689 'line1',
686 'line2',
690 'line2',
687 ]))
691 ]))
688 with open(fname) as f:
692 with open(fname) as f:
689 s = f.read()
693 s = f.read()
690 nt.assert_in('line1\n', s)
694 nt.assert_in('line1\n', s)
691 nt.assert_in('line2', s)
695 nt.assert_in('line2', s)
692
696
693 def test_file_var_expand():
697 def test_file_var_expand():
694 """%%file $filename"""
698 """%%file $filename"""
695 ip = get_ipython()
699 ip = get_ipython()
696 with TemporaryDirectory() as td:
700 with TemporaryDirectory() as td:
697 fname = os.path.join(td, 'file1')
701 fname = os.path.join(td, 'file1')
698 ip.user_ns['filename'] = fname
702 ip.user_ns['filename'] = fname
699 ip.run_cell_magic("file", '$filename', u'\n'.join([
703 ip.run_cell_magic("file", '$filename', u'\n'.join([
700 'line1',
704 'line1',
701 'line2',
705 'line2',
702 ]))
706 ]))
703 with open(fname) as f:
707 with open(fname) as f:
704 s = f.read()
708 s = f.read()
705 nt.assert_in('line1\n', s)
709 nt.assert_in('line1\n', s)
706 nt.assert_in('line2', s)
710 nt.assert_in('line2', s)
707
711
708 def test_file_unicode():
712 def test_file_unicode():
709 """%%file with unicode cell"""
713 """%%file with unicode cell"""
710 ip = get_ipython()
714 ip = get_ipython()
711 with TemporaryDirectory() as td:
715 with TemporaryDirectory() as td:
712 fname = os.path.join(td, 'file1')
716 fname = os.path.join(td, 'file1')
713 ip.run_cell_magic("file", fname, u'\n'.join([
717 ip.run_cell_magic("file", fname, u'\n'.join([
714 u'linΓ©1',
718 u'linΓ©1',
715 u'linΓ©2',
719 u'linΓ©2',
716 ]))
720 ]))
717 with io.open(fname, encoding='utf-8') as f:
721 with io.open(fname, encoding='utf-8') as f:
718 s = f.read()
722 s = f.read()
719 nt.assert_in(u'linΓ©1\n', s)
723 nt.assert_in(u'linΓ©1\n', s)
720 nt.assert_in(u'linΓ©2', s)
724 nt.assert_in(u'linΓ©2', s)
721
725
722 def test_file_amend():
726 def test_file_amend():
723 """%%file -a amends files"""
727 """%%file -a amends files"""
724 ip = get_ipython()
728 ip = get_ipython()
725 with TemporaryDirectory() as td:
729 with TemporaryDirectory() as td:
726 fname = os.path.join(td, 'file2')
730 fname = os.path.join(td, 'file2')
727 ip.run_cell_magic("file", fname, u'\n'.join([
731 ip.run_cell_magic("file", fname, u'\n'.join([
728 'line1',
732 'line1',
729 'line2',
733 'line2',
730 ]))
734 ]))
731 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
735 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
732 'line3',
736 'line3',
733 'line4',
737 'line4',
734 ]))
738 ]))
735 with open(fname) as f:
739 with open(fname) as f:
736 s = f.read()
740 s = f.read()
737 nt.assert_in('line1\n', s)
741 nt.assert_in('line1\n', s)
738 nt.assert_in('line3\n', s)
742 nt.assert_in('line3\n', s)
739
743
740
744
741 def test_script_config():
745 def test_script_config():
742 ip = get_ipython()
746 ip = get_ipython()
743 ip.config.ScriptMagics.script_magics = ['whoda']
747 ip.config.ScriptMagics.script_magics = ['whoda']
744 sm = script.ScriptMagics(shell=ip)
748 sm = script.ScriptMagics(shell=ip)
745 nt.assert_in('whoda', sm.magics['cell'])
749 nt.assert_in('whoda', sm.magics['cell'])
746
750
747 @dec.skip_win32
751 @dec.skip_win32
748 def test_script_out():
752 def test_script_out():
749 ip = get_ipython()
753 ip = get_ipython()
750 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
754 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
751 nt.assert_equal(ip.user_ns['output'], 'hi\n')
755 nt.assert_equal(ip.user_ns['output'], 'hi\n')
752
756
753 @dec.skip_win32
757 @dec.skip_win32
754 def test_script_err():
758 def test_script_err():
755 ip = get_ipython()
759 ip = get_ipython()
756 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
760 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
757 nt.assert_equal(ip.user_ns['error'], 'hello\n')
761 nt.assert_equal(ip.user_ns['error'], 'hello\n')
758
762
759 @dec.skip_win32
763 @dec.skip_win32
760 def test_script_out_err():
764 def test_script_out_err():
761 ip = get_ipython()
765 ip = get_ipython()
762 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
766 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
763 nt.assert_equal(ip.user_ns['output'], 'hi\n')
767 nt.assert_equal(ip.user_ns['output'], 'hi\n')
764 nt.assert_equal(ip.user_ns['error'], 'hello\n')
768 nt.assert_equal(ip.user_ns['error'], 'hello\n')
765
769
766 @dec.skip_win32
770 @dec.skip_win32
767 def test_script_bg_out():
771 def test_script_bg_out():
768 ip = get_ipython()
772 ip = get_ipython()
769 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
773 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
770 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
774 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
771
775
772 @dec.skip_win32
776 @dec.skip_win32
773 def test_script_bg_err():
777 def test_script_bg_err():
774 ip = get_ipython()
778 ip = get_ipython()
775 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
779 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
776 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
780 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
777
781
778 @dec.skip_win32
782 @dec.skip_win32
779 def test_script_bg_out_err():
783 def test_script_bg_out_err():
780 ip = get_ipython()
784 ip = get_ipython()
781 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
785 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
782 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
786 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
783 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
787 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
784
788
785 def test_script_defaults():
789 def test_script_defaults():
786 ip = get_ipython()
790 ip = get_ipython()
787 for cmd in ['sh', 'bash', 'perl', 'ruby']:
791 for cmd in ['sh', 'bash', 'perl', 'ruby']:
788 try:
792 try:
789 find_cmd(cmd)
793 find_cmd(cmd)
790 except Exception:
794 except Exception:
791 pass
795 pass
792 else:
796 else:
793 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
797 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
794
798
795
799
796 @magics_class
800 @magics_class
797 class FooFoo(Magics):
801 class FooFoo(Magics):
798 """class with both %foo and %%foo magics"""
802 """class with both %foo and %%foo magics"""
799 @line_magic('foo')
803 @line_magic('foo')
800 def line_foo(self, line):
804 def line_foo(self, line):
801 "I am line foo"
805 "I am line foo"
802 pass
806 pass
803
807
804 @cell_magic("foo")
808 @cell_magic("foo")
805 def cell_foo(self, line, cell):
809 def cell_foo(self, line, cell):
806 "I am cell foo, not line foo"
810 "I am cell foo, not line foo"
807 pass
811 pass
808
812
809 def test_line_cell_info():
813 def test_line_cell_info():
810 """%%foo and %foo magics are distinguishable to inspect"""
814 """%%foo and %foo magics are distinguishable to inspect"""
811 ip = get_ipython()
815 ip = get_ipython()
812 ip.magics_manager.register(FooFoo)
816 ip.magics_manager.register(FooFoo)
813 oinfo = ip.object_inspect('foo')
817 oinfo = ip.object_inspect('foo')
814 nt.assert_true(oinfo['found'])
818 nt.assert_true(oinfo['found'])
815 nt.assert_true(oinfo['ismagic'])
819 nt.assert_true(oinfo['ismagic'])
816
820
817 oinfo = ip.object_inspect('%%foo')
821 oinfo = ip.object_inspect('%%foo')
818 nt.assert_true(oinfo['found'])
822 nt.assert_true(oinfo['found'])
819 nt.assert_true(oinfo['ismagic'])
823 nt.assert_true(oinfo['ismagic'])
820 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
824 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
821
825
822 oinfo = ip.object_inspect('%foo')
826 oinfo = ip.object_inspect('%foo')
823 nt.assert_true(oinfo['found'])
827 nt.assert_true(oinfo['found'])
824 nt.assert_true(oinfo['ismagic'])
828 nt.assert_true(oinfo['ismagic'])
825 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
829 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
826
830
827 def test_multiple_magics():
831 def test_multiple_magics():
828 ip = get_ipython()
832 ip = get_ipython()
829 foo1 = FooFoo(ip)
833 foo1 = FooFoo(ip)
830 foo2 = FooFoo(ip)
834 foo2 = FooFoo(ip)
831 mm = ip.magics_manager
835 mm = ip.magics_manager
832 mm.register(foo1)
836 mm.register(foo1)
833 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
837 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
834 mm.register(foo2)
838 mm.register(foo2)
835 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
839 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
836
840
837 def test_alias_magic():
841 def test_alias_magic():
838 """Test %alias_magic."""
842 """Test %alias_magic."""
839 ip = get_ipython()
843 ip = get_ipython()
840 mm = ip.magics_manager
844 mm = ip.magics_manager
841
845
842 # Basic operation: both cell and line magics are created, if possible.
846 # Basic operation: both cell and line magics are created, if possible.
843 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
847 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
844 nt.assert_in('timeit_alias', mm.magics['line'])
848 nt.assert_in('timeit_alias', mm.magics['line'])
845 nt.assert_in('timeit_alias', mm.magics['cell'])
849 nt.assert_in('timeit_alias', mm.magics['cell'])
846
850
847 # --cell is specified, line magic not created.
851 # --cell is specified, line magic not created.
848 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
852 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
849 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
853 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
850 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
854 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
851
855
852 # Test that line alias is created successfully.
856 # Test that line alias is created successfully.
853 ip.run_line_magic('alias_magic', '--line env_alias env')
857 ip.run_line_magic('alias_magic', '--line env_alias env')
854 nt.assert_equal(ip.run_line_magic('env', ''),
858 nt.assert_equal(ip.run_line_magic('env', ''),
855 ip.run_line_magic('env_alias', ''))
859 ip.run_line_magic('env_alias', ''))
856
860
857 def test_save():
861 def test_save():
858 """Test %save."""
862 """Test %save."""
859 ip = get_ipython()
863 ip = get_ipython()
860 ip.history_manager.reset() # Clear any existing history.
864 ip.history_manager.reset() # Clear any existing history.
861 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
865 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
862 for i, cmd in enumerate(cmds, start=1):
866 for i, cmd in enumerate(cmds, start=1):
863 ip.history_manager.store_inputs(i, cmd)
867 ip.history_manager.store_inputs(i, cmd)
864 with TemporaryDirectory() as tmpdir:
868 with TemporaryDirectory() as tmpdir:
865 file = os.path.join(tmpdir, "testsave.py")
869 file = os.path.join(tmpdir, "testsave.py")
866 ip.run_line_magic("save", "%s 1-10" % file)
870 ip.run_line_magic("save", "%s 1-10" % file)
867 with open(file) as f:
871 with open(file) as f:
868 content = f.read()
872 content = f.read()
869 nt.assert_equal(content.count(cmds[0]), 1)
873 nt.assert_equal(content.count(cmds[0]), 1)
870 nt.assert_in('coding: utf-8', content)
874 nt.assert_in('coding: utf-8', content)
871 ip.run_line_magic("save", "-a %s 1-10" % file)
875 ip.run_line_magic("save", "-a %s 1-10" % file)
872 with open(file) as f:
876 with open(file) as f:
873 content = f.read()
877 content = f.read()
874 nt.assert_equal(content.count(cmds[0]), 2)
878 nt.assert_equal(content.count(cmds[0]), 2)
875 nt.assert_in('coding: utf-8', content)
879 nt.assert_in('coding: utf-8', content)
876
880
877
881
878 def test_store():
882 def test_store():
879 """Test %store."""
883 """Test %store."""
880 ip = get_ipython()
884 ip = get_ipython()
881 ip.run_line_magic('load_ext', 'storemagic')
885 ip.run_line_magic('load_ext', 'storemagic')
882
886
883 # make sure the storage is empty
887 # make sure the storage is empty
884 ip.run_line_magic('store', '-z')
888 ip.run_line_magic('store', '-z')
885 ip.user_ns['var'] = 42
889 ip.user_ns['var'] = 42
886 ip.run_line_magic('store', 'var')
890 ip.run_line_magic('store', 'var')
887 ip.user_ns['var'] = 39
891 ip.user_ns['var'] = 39
888 ip.run_line_magic('store', '-r')
892 ip.run_line_magic('store', '-r')
889 nt.assert_equal(ip.user_ns['var'], 42)
893 nt.assert_equal(ip.user_ns['var'], 42)
890
894
891 ip.run_line_magic('store', '-d var')
895 ip.run_line_magic('store', '-d var')
892 ip.user_ns['var'] = 39
896 ip.user_ns['var'] = 39
893 ip.run_line_magic('store' , '-r')
897 ip.run_line_magic('store' , '-r')
894 nt.assert_equal(ip.user_ns['var'], 39)
898 nt.assert_equal(ip.user_ns['var'], 39)
895
899
896
900
897 def _run_edit_test(arg_s, exp_filename=None,
901 def _run_edit_test(arg_s, exp_filename=None,
898 exp_lineno=-1,
902 exp_lineno=-1,
899 exp_contents=None,
903 exp_contents=None,
900 exp_is_temp=None):
904 exp_is_temp=None):
901 ip = get_ipython()
905 ip = get_ipython()
902 M = code.CodeMagics(ip)
906 M = code.CodeMagics(ip)
903 last_call = ['','']
907 last_call = ['','']
904 opts,args = M.parse_options(arg_s,'prxn:')
908 opts,args = M.parse_options(arg_s,'prxn:')
905 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
909 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
906
910
907 if exp_filename is not None:
911 if exp_filename is not None:
908 nt.assert_equal(exp_filename, filename)
912 nt.assert_equal(exp_filename, filename)
909 if exp_contents is not None:
913 if exp_contents is not None:
910 with io.open(filename, 'r') as f:
914 with io.open(filename, 'r') as f:
911 contents = f.read()
915 contents = f.read()
912 nt.assert_equal(exp_contents, contents)
916 nt.assert_equal(exp_contents, contents)
913 if exp_lineno != -1:
917 if exp_lineno != -1:
914 nt.assert_equal(exp_lineno, lineno)
918 nt.assert_equal(exp_lineno, lineno)
915 if exp_is_temp is not None:
919 if exp_is_temp is not None:
916 nt.assert_equal(exp_is_temp, is_temp)
920 nt.assert_equal(exp_is_temp, is_temp)
917
921
918
922
919 def test_edit_interactive():
923 def test_edit_interactive():
920 """%edit on interactively defined objects"""
924 """%edit on interactively defined objects"""
921 ip = get_ipython()
925 ip = get_ipython()
922 n = ip.execution_count
926 n = ip.execution_count
923 ip.run_cell(u"def foo(): return 1", store_history=True)
927 ip.run_cell(u"def foo(): return 1", store_history=True)
924
928
925 try:
929 try:
926 _run_edit_test("foo")
930 _run_edit_test("foo")
927 except code.InteractivelyDefined as e:
931 except code.InteractivelyDefined as e:
928 nt.assert_equal(e.index, n)
932 nt.assert_equal(e.index, n)
929 else:
933 else:
930 raise AssertionError("Should have raised InteractivelyDefined")
934 raise AssertionError("Should have raised InteractivelyDefined")
931
935
932
936
933 def test_edit_cell():
937 def test_edit_cell():
934 """%edit [cell id]"""
938 """%edit [cell id]"""
935 ip = get_ipython()
939 ip = get_ipython()
936
940
937 ip.run_cell(u"def foo(): return 1", store_history=True)
941 ip.run_cell(u"def foo(): return 1", store_history=True)
938
942
939 # test
943 # test
940 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
944 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
@@ -1,317 +1,322 b''
1 """Tests for autoreload extension.
1 """Tests for autoreload extension.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 IPython Development Team.
4 # Copyright (c) 2012 IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18 import shutil
18 import shutil
19 import random
19 import random
20 import time
20 import time
21 from io import StringIO
22
21
23 import nose.tools as nt
22 import nose.tools as nt
24 import IPython.testing.tools as tt
23 import IPython.testing.tools as tt
25
24
26 from IPython.extensions.autoreload import AutoreloadMagics
25 from IPython.extensions.autoreload import AutoreloadMagics
27 from IPython.core.hooks import TryNext
26 from IPython.core.hooks import TryNext
27 from IPython.utils.py3compat import PY3
28
29 if PY3:
30 from io import StringIO
31 else:
32 from StringIO import StringIO
28
33
29 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
30 # Test fixture
35 # Test fixture
31 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
32
37
33 noop = lambda *a, **kw: None
38 noop = lambda *a, **kw: None
34
39
35 class FakeShell(object):
40 class FakeShell(object):
36
41
37 def __init__(self):
42 def __init__(self):
38 self.ns = {}
43 self.ns = {}
39 self.auto_magics = AutoreloadMagics(shell=self)
44 self.auto_magics = AutoreloadMagics(shell=self)
40
45
41 register_magics = set_hook = noop
46 register_magics = set_hook = noop
42
47
43 def run_code(self, code):
48 def run_code(self, code):
44 try:
49 try:
45 self.auto_magics.pre_run_code_hook(self)
50 self.auto_magics.pre_run_code_hook(self)
46 except TryNext:
51 except TryNext:
47 pass
52 pass
48 exec(code, self.ns)
53 exec(code, self.ns)
49
54
50 def push(self, items):
55 def push(self, items):
51 self.ns.update(items)
56 self.ns.update(items)
52
57
53 def magic_autoreload(self, parameter):
58 def magic_autoreload(self, parameter):
54 self.auto_magics.autoreload(parameter)
59 self.auto_magics.autoreload(parameter)
55
60
56 def magic_aimport(self, parameter, stream=None):
61 def magic_aimport(self, parameter, stream=None):
57 self.auto_magics.aimport(parameter, stream=stream)
62 self.auto_magics.aimport(parameter, stream=stream)
58
63
59
64
60 class Fixture(object):
65 class Fixture(object):
61 """Fixture for creating test module files"""
66 """Fixture for creating test module files"""
62
67
63 test_dir = None
68 test_dir = None
64 old_sys_path = None
69 old_sys_path = None
65 filename_chars = "abcdefghijklmopqrstuvwxyz0123456789"
70 filename_chars = "abcdefghijklmopqrstuvwxyz0123456789"
66
71
67 def setUp(self):
72 def setUp(self):
68 self.test_dir = tempfile.mkdtemp()
73 self.test_dir = tempfile.mkdtemp()
69 self.old_sys_path = list(sys.path)
74 self.old_sys_path = list(sys.path)
70 sys.path.insert(0, self.test_dir)
75 sys.path.insert(0, self.test_dir)
71 self.shell = FakeShell()
76 self.shell = FakeShell()
72
77
73 def tearDown(self):
78 def tearDown(self):
74 shutil.rmtree(self.test_dir)
79 shutil.rmtree(self.test_dir)
75 sys.path = self.old_sys_path
80 sys.path = self.old_sys_path
76
81
77 self.test_dir = None
82 self.test_dir = None
78 self.old_sys_path = None
83 self.old_sys_path = None
79 self.shell = None
84 self.shell = None
80
85
81 def get_module(self):
86 def get_module(self):
82 module_name = "tmpmod_" + "".join(random.sample(self.filename_chars,20))
87 module_name = "tmpmod_" + "".join(random.sample(self.filename_chars,20))
83 if module_name in sys.modules:
88 if module_name in sys.modules:
84 del sys.modules[module_name]
89 del sys.modules[module_name]
85 file_name = os.path.join(self.test_dir, module_name + ".py")
90 file_name = os.path.join(self.test_dir, module_name + ".py")
86 return module_name, file_name
91 return module_name, file_name
87
92
88 def write_file(self, filename, content):
93 def write_file(self, filename, content):
89 """
94 """
90 Write a file, and force a timestamp difference of at least one second
95 Write a file, and force a timestamp difference of at least one second
91
96
92 Notes
97 Notes
93 -----
98 -----
94 Python's .pyc files record the timestamp of their compilation
99 Python's .pyc files record the timestamp of their compilation
95 with a time resolution of one second.
100 with a time resolution of one second.
96
101
97 Therefore, we need to force a timestamp difference between .py
102 Therefore, we need to force a timestamp difference between .py
98 and .pyc, without having the .py file be timestamped in the
103 and .pyc, without having the .py file be timestamped in the
99 future, and without changing the timestamp of the .pyc file
104 future, and without changing the timestamp of the .pyc file
100 (because that is stored in the file). The only reliable way
105 (because that is stored in the file). The only reliable way
101 to achieve this seems to be to sleep.
106 to achieve this seems to be to sleep.
102 """
107 """
103
108
104 # Sleep one second + eps
109 # Sleep one second + eps
105 time.sleep(1.05)
110 time.sleep(1.05)
106
111
107 # Write
112 # Write
108 f = open(filename, 'w')
113 f = open(filename, 'w')
109 try:
114 try:
110 f.write(content)
115 f.write(content)
111 finally:
116 finally:
112 f.close()
117 f.close()
113
118
114 def new_module(self, code):
119 def new_module(self, code):
115 mod_name, mod_fn = self.get_module()
120 mod_name, mod_fn = self.get_module()
116 f = open(mod_fn, 'w')
121 f = open(mod_fn, 'w')
117 try:
122 try:
118 f.write(code)
123 f.write(code)
119 finally:
124 finally:
120 f.close()
125 f.close()
121 return mod_name, mod_fn
126 return mod_name, mod_fn
122
127
123 #-----------------------------------------------------------------------------
128 #-----------------------------------------------------------------------------
124 # Test automatic reloading
129 # Test automatic reloading
125 #-----------------------------------------------------------------------------
130 #-----------------------------------------------------------------------------
126
131
127 class TestAutoreload(Fixture):
132 class TestAutoreload(Fixture):
128 def _check_smoketest(self, use_aimport=True):
133 def _check_smoketest(self, use_aimport=True):
129 """
134 """
130 Functional test for the automatic reloader using either
135 Functional test for the automatic reloader using either
131 '%autoreload 1' or '%autoreload 2'
136 '%autoreload 1' or '%autoreload 2'
132 """
137 """
133
138
134 mod_name, mod_fn = self.new_module("""
139 mod_name, mod_fn = self.new_module("""
135 x = 9
140 x = 9
136
141
137 z = 123 # this item will be deleted
142 z = 123 # this item will be deleted
138
143
139 def foo(y):
144 def foo(y):
140 return y + 3
145 return y + 3
141
146
142 class Baz(object):
147 class Baz(object):
143 def __init__(self, x):
148 def __init__(self, x):
144 self.x = x
149 self.x = x
145 def bar(self, y):
150 def bar(self, y):
146 return self.x + y
151 return self.x + y
147 @property
152 @property
148 def quux(self):
153 def quux(self):
149 return 42
154 return 42
150 def zzz(self):
155 def zzz(self):
151 '''This method will be deleted below'''
156 '''This method will be deleted below'''
152 return 99
157 return 99
153
158
154 class Bar: # old-style class: weakref doesn't work for it on Python < 2.7
159 class Bar: # old-style class: weakref doesn't work for it on Python < 2.7
155 def foo(self):
160 def foo(self):
156 return 1
161 return 1
157 """)
162 """)
158
163
159 #
164 #
160 # Import module, and mark for reloading
165 # Import module, and mark for reloading
161 #
166 #
162 if use_aimport:
167 if use_aimport:
163 self.shell.magic_autoreload("1")
168 self.shell.magic_autoreload("1")
164 self.shell.magic_aimport(mod_name)
169 self.shell.magic_aimport(mod_name)
165 stream = StringIO()
170 stream = StringIO()
166 self.shell.magic_aimport("", stream=stream)
171 self.shell.magic_aimport("", stream=stream)
167 nt.assert_true(("Modules to reload:\n%s" % mod_name) in
172 nt.assert_true(("Modules to reload:\n%s" % mod_name) in
168 stream.getvalue())
173 stream.getvalue())
169
174
170 nt.assert_raises(
175 nt.assert_raises(
171 ImportError,
176 ImportError,
172 self.shell.magic_aimport, "tmpmod_as318989e89ds")
177 self.shell.magic_aimport, "tmpmod_as318989e89ds")
173 else:
178 else:
174 self.shell.magic_autoreload("2")
179 self.shell.magic_autoreload("2")
175 self.shell.run_code("import %s" % mod_name)
180 self.shell.run_code("import %s" % mod_name)
176 stream = StringIO()
181 stream = StringIO()
177 self.shell.magic_aimport("", stream=stream)
182 self.shell.magic_aimport("", stream=stream)
178 nt.assert_true("Modules to reload:\nall-except-skipped" in
183 nt.assert_true("Modules to reload:\nall-except-skipped" in
179 stream.getvalue())
184 stream.getvalue())
180 nt.assert_in(mod_name, self.shell.ns)
185 nt.assert_in(mod_name, self.shell.ns)
181
186
182 mod = sys.modules[mod_name]
187 mod = sys.modules[mod_name]
183
188
184 #
189 #
185 # Test module contents
190 # Test module contents
186 #
191 #
187 old_foo = mod.foo
192 old_foo = mod.foo
188 old_obj = mod.Baz(9)
193 old_obj = mod.Baz(9)
189 old_obj2 = mod.Bar()
194 old_obj2 = mod.Bar()
190
195
191 def check_module_contents():
196 def check_module_contents():
192 nt.assert_equal(mod.x, 9)
197 nt.assert_equal(mod.x, 9)
193 nt.assert_equal(mod.z, 123)
198 nt.assert_equal(mod.z, 123)
194
199
195 nt.assert_equal(old_foo(0), 3)
200 nt.assert_equal(old_foo(0), 3)
196 nt.assert_equal(mod.foo(0), 3)
201 nt.assert_equal(mod.foo(0), 3)
197
202
198 obj = mod.Baz(9)
203 obj = mod.Baz(9)
199 nt.assert_equal(old_obj.bar(1), 10)
204 nt.assert_equal(old_obj.bar(1), 10)
200 nt.assert_equal(obj.bar(1), 10)
205 nt.assert_equal(obj.bar(1), 10)
201 nt.assert_equal(obj.quux, 42)
206 nt.assert_equal(obj.quux, 42)
202 nt.assert_equal(obj.zzz(), 99)
207 nt.assert_equal(obj.zzz(), 99)
203
208
204 obj2 = mod.Bar()
209 obj2 = mod.Bar()
205 nt.assert_equal(old_obj2.foo(), 1)
210 nt.assert_equal(old_obj2.foo(), 1)
206 nt.assert_equal(obj2.foo(), 1)
211 nt.assert_equal(obj2.foo(), 1)
207
212
208 check_module_contents()
213 check_module_contents()
209
214
210 #
215 #
211 # Simulate a failed reload: no reload should occur and exactly
216 # Simulate a failed reload: no reload should occur and exactly
212 # one error message should be printed
217 # one error message should be printed
213 #
218 #
214 self.write_file(mod_fn, """
219 self.write_file(mod_fn, """
215 a syntax error
220 a syntax error
216 """)
221 """)
217
222
218 with tt.AssertPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
223 with tt.AssertPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
219 self.shell.run_code("pass") # trigger reload
224 self.shell.run_code("pass") # trigger reload
220 with tt.AssertNotPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
225 with tt.AssertNotPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
221 self.shell.run_code("pass") # trigger another reload
226 self.shell.run_code("pass") # trigger another reload
222 check_module_contents()
227 check_module_contents()
223
228
224 #
229 #
225 # Rewrite module (this time reload should succeed)
230 # Rewrite module (this time reload should succeed)
226 #
231 #
227 self.write_file(mod_fn, """
232 self.write_file(mod_fn, """
228 x = 10
233 x = 10
229
234
230 def foo(y):
235 def foo(y):
231 return y + 4
236 return y + 4
232
237
233 class Baz(object):
238 class Baz(object):
234 def __init__(self, x):
239 def __init__(self, x):
235 self.x = x
240 self.x = x
236 def bar(self, y):
241 def bar(self, y):
237 return self.x + y + 1
242 return self.x + y + 1
238 @property
243 @property
239 def quux(self):
244 def quux(self):
240 return 43
245 return 43
241
246
242 class Bar: # old-style class
247 class Bar: # old-style class
243 def foo(self):
248 def foo(self):
244 return 2
249 return 2
245 """)
250 """)
246
251
247 def check_module_contents():
252 def check_module_contents():
248 nt.assert_equal(mod.x, 10)
253 nt.assert_equal(mod.x, 10)
249 nt.assert_false(hasattr(mod, 'z'))
254 nt.assert_false(hasattr(mod, 'z'))
250
255
251 nt.assert_equal(old_foo(0), 4) # superreload magic!
256 nt.assert_equal(old_foo(0), 4) # superreload magic!
252 nt.assert_equal(mod.foo(0), 4)
257 nt.assert_equal(mod.foo(0), 4)
253
258
254 obj = mod.Baz(9)
259 obj = mod.Baz(9)
255 nt.assert_equal(old_obj.bar(1), 11) # superreload magic!
260 nt.assert_equal(old_obj.bar(1), 11) # superreload magic!
256 nt.assert_equal(obj.bar(1), 11)
261 nt.assert_equal(obj.bar(1), 11)
257
262
258 nt.assert_equal(old_obj.quux, 43)
263 nt.assert_equal(old_obj.quux, 43)
259 nt.assert_equal(obj.quux, 43)
264 nt.assert_equal(obj.quux, 43)
260
265
261 nt.assert_false(hasattr(old_obj, 'zzz'))
266 nt.assert_false(hasattr(old_obj, 'zzz'))
262 nt.assert_false(hasattr(obj, 'zzz'))
267 nt.assert_false(hasattr(obj, 'zzz'))
263
268
264 obj2 = mod.Bar()
269 obj2 = mod.Bar()
265 nt.assert_equal(old_obj2.foo(), 2)
270 nt.assert_equal(old_obj2.foo(), 2)
266 nt.assert_equal(obj2.foo(), 2)
271 nt.assert_equal(obj2.foo(), 2)
267
272
268 self.shell.run_code("pass") # trigger reload
273 self.shell.run_code("pass") # trigger reload
269 check_module_contents()
274 check_module_contents()
270
275
271 #
276 #
272 # Another failure case: deleted file (shouldn't reload)
277 # Another failure case: deleted file (shouldn't reload)
273 #
278 #
274 os.unlink(mod_fn)
279 os.unlink(mod_fn)
275
280
276 self.shell.run_code("pass") # trigger reload
281 self.shell.run_code("pass") # trigger reload
277 check_module_contents()
282 check_module_contents()
278
283
279 #
284 #
280 # Disable autoreload and rewrite module: no reload should occur
285 # Disable autoreload and rewrite module: no reload should occur
281 #
286 #
282 if use_aimport:
287 if use_aimport:
283 self.shell.magic_aimport("-" + mod_name)
288 self.shell.magic_aimport("-" + mod_name)
284 stream = StringIO()
289 stream = StringIO()
285 self.shell.magic_aimport("", stream=stream)
290 self.shell.magic_aimport("", stream=stream)
286 nt.assert_true(("Modules to skip:\n%s" % mod_name) in
291 nt.assert_true(("Modules to skip:\n%s" % mod_name) in
287 stream.getvalue())
292 stream.getvalue())
288
293
289 # This should succeed, although no such module exists
294 # This should succeed, although no such module exists
290 self.shell.magic_aimport("-tmpmod_as318989e89ds")
295 self.shell.magic_aimport("-tmpmod_as318989e89ds")
291 else:
296 else:
292 self.shell.magic_autoreload("0")
297 self.shell.magic_autoreload("0")
293
298
294 self.write_file(mod_fn, """
299 self.write_file(mod_fn, """
295 x = -99
300 x = -99
296 """)
301 """)
297
302
298 self.shell.run_code("pass") # trigger reload
303 self.shell.run_code("pass") # trigger reload
299 self.shell.run_code("pass")
304 self.shell.run_code("pass")
300 check_module_contents()
305 check_module_contents()
301
306
302 #
307 #
303 # Re-enable autoreload: reload should now occur
308 # Re-enable autoreload: reload should now occur
304 #
309 #
305 if use_aimport:
310 if use_aimport:
306 self.shell.magic_aimport(mod_name)
311 self.shell.magic_aimport(mod_name)
307 else:
312 else:
308 self.shell.magic_autoreload("")
313 self.shell.magic_autoreload("")
309
314
310 self.shell.run_code("pass") # trigger reload
315 self.shell.run_code("pass") # trigger reload
311 nt.assert_equal(mod.x, -99)
316 nt.assert_equal(mod.x, -99)
312
317
313 def test_smoketest_aimport(self):
318 def test_smoketest_aimport(self):
314 self._check_smoketest(use_aimport=True)
319 self._check_smoketest(use_aimport=True)
315
320
316 def test_smoketest_autoreload(self):
321 def test_smoketest_autoreload(self):
317 self._check_smoketest(use_aimport=False)
322 self._check_smoketest(use_aimport=False)
@@ -1,122 +1,126 b''
1 from io import StringIO
2
3 import numpy as np
1 import numpy as np
4 from IPython.testing.decorators import skip_without
2 from IPython.testing.decorators import skip_without
5 from IPython.extensions import rmagic
3 from IPython.extensions import rmagic
4 from IPython.utils.py3compat import PY3
6 from rpy2 import rinterface
5 from rpy2 import rinterface
7 import nose.tools as nt
6 import nose.tools as nt
8
7
8 if PY3:
9 from io import StringIO
10 else:
11 from StringIO import StringIO
12
9 ip = get_ipython()
13 ip = get_ipython()
10 ip.magic('load_ext rmagic')
14 ip.magic('load_ext rmagic')
11
15
12
16
13 def test_push():
17 def test_push():
14 rm = rmagic.RMagics(ip)
18 rm = rmagic.RMagics(ip)
15 ip.push({'X':np.arange(5), 'Y':np.array([3,5,4,6,7])})
19 ip.push({'X':np.arange(5), 'Y':np.array([3,5,4,6,7])})
16 ip.run_line_magic('Rpush', 'X Y')
20 ip.run_line_magic('Rpush', 'X Y')
17 np.testing.assert_almost_equal(np.asarray(rm.r('X')), ip.user_ns['X'])
21 np.testing.assert_almost_equal(np.asarray(rm.r('X')), ip.user_ns['X'])
18 np.testing.assert_almost_equal(np.asarray(rm.r('Y')), ip.user_ns['Y'])
22 np.testing.assert_almost_equal(np.asarray(rm.r('Y')), ip.user_ns['Y'])
19
23
20 def test_push_localscope():
24 def test_push_localscope():
21 """Test that Rpush looks for variables in the local scope first."""
25 """Test that Rpush looks for variables in the local scope first."""
22 ip.run_cell('''
26 ip.run_cell('''
23 def rmagic_addone(u):
27 def rmagic_addone(u):
24 %Rpush u
28 %Rpush u
25 %R result = u+1
29 %R result = u+1
26 %Rpull result
30 %Rpull result
27 return result[0]
31 return result[0]
28 u = 0
32 u = 0
29 result = rmagic_addone(12344)
33 result = rmagic_addone(12344)
30 ''')
34 ''')
31 result = ip.user_ns['result']
35 result = ip.user_ns['result']
32 np.testing.assert_equal(result, 12345)
36 np.testing.assert_equal(result, 12345)
33
37
34 @skip_without('pandas')
38 @skip_without('pandas')
35 def test_push_dataframe():
39 def test_push_dataframe():
36 from pandas import DataFrame
40 from pandas import DataFrame
37 rm = rmagic.RMagics(ip)
41 rm = rmagic.RMagics(ip)
38 df = DataFrame([{'a': 1, 'b': 'bar'}, {'a': 5, 'b': 'foo', 'c': 20}])
42 df = DataFrame([{'a': 1, 'b': 'bar'}, {'a': 5, 'b': 'foo', 'c': 20}])
39 ip.push({'df':df})
43 ip.push({'df':df})
40 ip.run_line_magic('Rpush', 'df')
44 ip.run_line_magic('Rpush', 'df')
41
45
42 # This is converted to factors, which are currently converted back to Python
46 # This is converted to factors, which are currently converted back to Python
43 # as integers, so for now we test its representation in R.
47 # as integers, so for now we test its representation in R.
44 sio = StringIO()
48 sio = StringIO()
45 rinterface.set_writeconsole(sio.write)
49 rinterface.set_writeconsole(sio.write)
46 try:
50 try:
47 rm.r('print(df$b[1])')
51 rm.r('print(df$b[1])')
48 nt.assert_in('[1] bar', sio.getvalue())
52 nt.assert_in('[1] bar', sio.getvalue())
49 finally:
53 finally:
50 rinterface.set_writeconsole(None)
54 rinterface.set_writeconsole(None)
51
55
52 # Values come packaged in arrays, so we unbox them to test.
56 # Values come packaged in arrays, so we unbox them to test.
53 nt.assert_equal(rm.r('df$a[2]')[0], 5)
57 nt.assert_equal(rm.r('df$a[2]')[0], 5)
54 missing = rm.r('df$c[1]')[0]
58 missing = rm.r('df$c[1]')[0]
55 assert np.isnan(missing), missing
59 assert np.isnan(missing), missing
56
60
57 def test_pull():
61 def test_pull():
58 rm = rmagic.RMagics(ip)
62 rm = rmagic.RMagics(ip)
59 rm.r('Z=c(11:20)')
63 rm.r('Z=c(11:20)')
60 ip.run_line_magic('Rpull', 'Z')
64 ip.run_line_magic('Rpull', 'Z')
61 np.testing.assert_almost_equal(np.asarray(rm.r('Z')), ip.user_ns['Z'])
65 np.testing.assert_almost_equal(np.asarray(rm.r('Z')), ip.user_ns['Z'])
62 np.testing.assert_almost_equal(ip.user_ns['Z'], np.arange(11,21))
66 np.testing.assert_almost_equal(ip.user_ns['Z'], np.arange(11,21))
63
67
64 def test_Rconverter():
68 def test_Rconverter():
65 datapy= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')],
69 datapy= np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c')],
66 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
70 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
67 ip.user_ns['datapy'] = datapy
71 ip.user_ns['datapy'] = datapy
68 ip.run_line_magic('Rpush', 'datapy')
72 ip.run_line_magic('Rpush', 'datapy')
69
73
70 # test to see if a copy is being made
74 # test to see if a copy is being made
71 v = ip.run_line_magic('Rget', '-d datapy')
75 v = ip.run_line_magic('Rget', '-d datapy')
72 w = ip.run_line_magic('Rget', '-d datapy')
76 w = ip.run_line_magic('Rget', '-d datapy')
73 np.testing.assert_almost_equal(w['x'], v['x'])
77 np.testing.assert_almost_equal(w['x'], v['x'])
74 np.testing.assert_almost_equal(w['y'], v['y'])
78 np.testing.assert_almost_equal(w['y'], v['y'])
75 nt.assert_true(np.all(w['z'] == v['z']))
79 nt.assert_true(np.all(w['z'] == v['z']))
76 np.testing.assert_equal(id(w.data), id(v.data))
80 np.testing.assert_equal(id(w.data), id(v.data))
77 nt.assert_equal(w.dtype, v.dtype)
81 nt.assert_equal(w.dtype, v.dtype)
78
82
79 ip.run_cell_magic('R', ' -d datar', 'datar=datapy')
83 ip.run_cell_magic('R', ' -d datar', 'datar=datapy')
80
84
81 u = ip.run_line_magic('Rget', ' -d datar')
85 u = ip.run_line_magic('Rget', ' -d datar')
82 np.testing.assert_almost_equal(u['x'], v['x'])
86 np.testing.assert_almost_equal(u['x'], v['x'])
83 np.testing.assert_almost_equal(u['y'], v['y'])
87 np.testing.assert_almost_equal(u['y'], v['y'])
84 nt.assert_true(np.all(u['z'] == v['z']))
88 nt.assert_true(np.all(u['z'] == v['z']))
85 np.testing.assert_equal(id(u.data), id(v.data))
89 np.testing.assert_equal(id(u.data), id(v.data))
86 nt.assert_equal(u.dtype, v.dtype)
90 nt.assert_equal(u.dtype, v.dtype)
87
91
88
92
89 def test_cell_magic():
93 def test_cell_magic():
90
94
91 ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
95 ip.push({'x':np.arange(5), 'y':np.array([3,5,4,6,7])})
92 snippet = '''
96 snippet = '''
93 print(summary(a))
97 print(summary(a))
94 plot(x, y, pch=23, bg='orange', cex=2)
98 plot(x, y, pch=23, bg='orange', cex=2)
95 plot(x, x)
99 plot(x, x)
96 print(summary(x))
100 print(summary(x))
97 r = resid(a)
101 r = resid(a)
98 xc = coef(a)
102 xc = coef(a)
99 '''
103 '''
100 ip.run_cell_magic('R', '-i x,y -o r,xc -w 150 -u mm a=lm(y~x)', snippet)
104 ip.run_cell_magic('R', '-i x,y -o r,xc -w 150 -u mm a=lm(y~x)', snippet)
101 np.testing.assert_almost_equal(ip.user_ns['xc'], [3.2, 0.9])
105 np.testing.assert_almost_equal(ip.user_ns['xc'], [3.2, 0.9])
102 np.testing.assert_almost_equal(ip.user_ns['r'], np.array([-0.2, 0.9, -1. , 0.1, 0.2]))
106 np.testing.assert_almost_equal(ip.user_ns['r'], np.array([-0.2, 0.9, -1. , 0.1, 0.2]))
103
107
104
108
105 def test_rmagic_localscope():
109 def test_rmagic_localscope():
106 ip.push({'x':0})
110 ip.push({'x':0})
107 ip.run_line_magic('R', '-i x -o result result <-x+1')
111 ip.run_line_magic('R', '-i x -o result result <-x+1')
108 result = ip.user_ns['result']
112 result = ip.user_ns['result']
109 nt.assert_equal(result[0], 1)
113 nt.assert_equal(result[0], 1)
110
114
111 ip.run_cell('''def rmagic_addone(u):
115 ip.run_cell('''def rmagic_addone(u):
112 %R -i u -o result result <- u+1
116 %R -i u -o result result <- u+1
113 return result[0]''')
117 return result[0]''')
114 ip.run_cell('result = rmagic_addone(1)')
118 ip.run_cell('result = rmagic_addone(1)')
115 result = ip.user_ns['result']
119 result = ip.user_ns['result']
116 nt.assert_equal(result, 2)
120 nt.assert_equal(result, 2)
117
121
118 nt.assert_raises(
122 nt.assert_raises(
119 NameError,
123 NameError,
120 ip.run_line_magic,
124 ip.run_line_magic,
121 "R",
125 "R",
122 "-i var_not_defined 1+1")
126 "-i var_not_defined 1+1")
@@ -1,91 +1,95 b''
1 #-------------------------------------------------------------------------------
1 #-------------------------------------------------------------------------------
2 # Copyright (C) 2012 The IPython Development Team
2 # Copyright (C) 2012 The IPython Development Team
3 #
3 #
4 # Distributed under the terms of the BSD License. The full license is in
4 # Distributed under the terms of the BSD License. The full license is in
5 # the file COPYING, distributed as part of this software.
5 # the file COPYING, distributed as part of this software.
6 #-------------------------------------------------------------------------------
6 #-------------------------------------------------------------------------------
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 # Standard library imports
13 # Standard library imports
14 from io import StringIO
15 import sys
14 import sys
16 import unittest
15 import unittest
17
16
18 # Local imports
17 # Local imports
19 from IPython.kernel.inprocess.blocking import BlockingInProcessKernelClient
18 from IPython.kernel.inprocess.blocking import BlockingInProcessKernelClient
20 from IPython.kernel.inprocess.manager import InProcessKernelManager
19 from IPython.kernel.inprocess.manager import InProcessKernelManager
21 from IPython.kernel.inprocess.ipkernel import InProcessKernel
20 from IPython.kernel.inprocess.ipkernel import InProcessKernel
22 from IPython.testing.decorators import skipif_not_matplotlib
21 from IPython.testing.decorators import skipif_not_matplotlib
23 from IPython.utils.io import capture_output
22 from IPython.utils.io import capture_output
24 from IPython.utils import py3compat
23 from IPython.utils import py3compat
25
24
25 if py3compat.PY3:
26 from io import StringIO
27 else:
28 from StringIO import StringIO
29
26 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
27 # Test case
31 # Test case
28 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
29
33
30 class InProcessKernelTestCase(unittest.TestCase):
34 class InProcessKernelTestCase(unittest.TestCase):
31
35
32 def setUp(self):
36 def setUp(self):
33 self.km = InProcessKernelManager()
37 self.km = InProcessKernelManager()
34 self.km.start_kernel()
38 self.km.start_kernel()
35 self.kc = BlockingInProcessKernelClient(kernel=self.km.kernel)
39 self.kc = BlockingInProcessKernelClient(kernel=self.km.kernel)
36 self.kc.start_channels()
40 self.kc.start_channels()
37
41
38 @skipif_not_matplotlib
42 @skipif_not_matplotlib
39 def test_pylab(self):
43 def test_pylab(self):
40 """ Does pylab work in the in-process kernel?
44 """ Does pylab work in the in-process kernel?
41 """
45 """
42 kc = self.kc
46 kc = self.kc
43 kc.execute('%pylab')
47 kc.execute('%pylab')
44 msg = get_stream_message(kc)
48 msg = get_stream_message(kc)
45 self.assert_('matplotlib' in msg['content']['data'])
49 self.assert_('matplotlib' in msg['content']['data'])
46
50
47 def test_raw_input(self):
51 def test_raw_input(self):
48 """ Does the in-process kernel handle raw_input correctly?
52 """ Does the in-process kernel handle raw_input correctly?
49 """
53 """
50 io = StringIO('foobar\n')
54 io = StringIO('foobar\n')
51 sys_stdin = sys.stdin
55 sys_stdin = sys.stdin
52 sys.stdin = io
56 sys.stdin = io
53 try:
57 try:
54 if py3compat.PY3:
58 if py3compat.PY3:
55 self.kc.execute('x = input()')
59 self.kc.execute('x = input()')
56 else:
60 else:
57 self.kc.execute('x = raw_input()')
61 self.kc.execute('x = raw_input()')
58 finally:
62 finally:
59 sys.stdin = sys_stdin
63 sys.stdin = sys_stdin
60 self.assertEqual(self.km.kernel.shell.user_ns.get('x'), 'foobar')
64 self.assertEqual(self.km.kernel.shell.user_ns.get('x'), 'foobar')
61
65
62 def test_stdout(self):
66 def test_stdout(self):
63 """ Does the in-process kernel correctly capture IO?
67 """ Does the in-process kernel correctly capture IO?
64 """
68 """
65 kernel = InProcessKernel()
69 kernel = InProcessKernel()
66
70
67 with capture_output() as io:
71 with capture_output() as io:
68 kernel.shell.run_cell('print("foo")')
72 kernel.shell.run_cell('print("foo")')
69 self.assertEqual(io.stdout, 'foo\n')
73 self.assertEqual(io.stdout, 'foo\n')
70
74
71 kc = BlockingInProcessKernelClient(kernel=kernel)
75 kc = BlockingInProcessKernelClient(kernel=kernel)
72 kernel.frontends.append(kc)
76 kernel.frontends.append(kc)
73 kc.shell_channel.execute('print("bar")')
77 kc.shell_channel.execute('print("bar")')
74 msg = get_stream_message(kc)
78 msg = get_stream_message(kc)
75 self.assertEqual(msg['content']['data'], 'bar\n')
79 self.assertEqual(msg['content']['data'], 'bar\n')
76
80
77 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
78 # Utility functions
82 # Utility functions
79 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
80
84
81 def get_stream_message(kernel_client, timeout=5):
85 def get_stream_message(kernel_client, timeout=5):
82 """ Gets a single stream message synchronously from the sub channel.
86 """ Gets a single stream message synchronously from the sub channel.
83 """
87 """
84 while True:
88 while True:
85 msg = kernel_client.get_iopub_msg(timeout=timeout)
89 msg = kernel_client.get_iopub_msg(timeout=timeout)
86 if msg['header']['msg_type'] == 'stream':
90 if msg['header']['msg_type'] == 'stream':
87 return msg
91 return msg
88
92
89
93
90 if __name__ == '__main__':
94 if __name__ == '__main__':
91 unittest.main()
95 unittest.main()
@@ -1,791 +1,797 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Python advanced pretty printer. This pretty printer is intended to
3 Python advanced pretty printer. This pretty printer is intended to
4 replace the old `pprint` python module which does not allow developers
4 replace the old `pprint` python module which does not allow developers
5 to provide their own pretty print callbacks.
5 to provide their own pretty print callbacks.
6
6
7 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
7 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
8
8
9
9
10 Example Usage
10 Example Usage
11 -------------
11 -------------
12
12
13 To directly print the representation of an object use `pprint`::
13 To directly print the representation of an object use `pprint`::
14
14
15 from pretty import pprint
15 from pretty import pprint
16 pprint(complex_object)
16 pprint(complex_object)
17
17
18 To get a string of the output use `pretty`::
18 To get a string of the output use `pretty`::
19
19
20 from pretty import pretty
20 from pretty import pretty
21 string = pretty(complex_object)
21 string = pretty(complex_object)
22
22
23
23
24 Extending
24 Extending
25 ---------
25 ---------
26
26
27 The pretty library allows developers to add pretty printing rules for their
27 The pretty library allows developers to add pretty printing rules for their
28 own objects. This process is straightforward. All you have to do is to
28 own objects. This process is straightforward. All you have to do is to
29 add a `_repr_pretty_` method to your object and call the methods on the
29 add a `_repr_pretty_` method to your object and call the methods on the
30 pretty printer passed::
30 pretty printer passed::
31
31
32 class MyObject(object):
32 class MyObject(object):
33
33
34 def _repr_pretty_(self, p, cycle):
34 def _repr_pretty_(self, p, cycle):
35 ...
35 ...
36
36
37 Depending on the python version you want to support you have two
37 Depending on the python version you want to support you have two
38 possibilities. The following list shows the python 2.5 version and the
38 possibilities. The following list shows the python 2.5 version and the
39 compatibility one.
39 compatibility one.
40
40
41
41
42 Here the example implementation of a `_repr_pretty_` method for a list
42 Here the example implementation of a `_repr_pretty_` method for a list
43 subclass for python 2.5 and higher (python 2.5 requires the with statement
43 subclass for python 2.5 and higher (python 2.5 requires the with statement
44 __future__ import)::
44 __future__ import)::
45
45
46 class MyList(list):
46 class MyList(list):
47
47
48 def _repr_pretty_(self, p, cycle):
48 def _repr_pretty_(self, p, cycle):
49 if cycle:
49 if cycle:
50 p.text('MyList(...)')
50 p.text('MyList(...)')
51 else:
51 else:
52 with p.group(8, 'MyList([', '])'):
52 with p.group(8, 'MyList([', '])'):
53 for idx, item in enumerate(self):
53 for idx, item in enumerate(self):
54 if idx:
54 if idx:
55 p.text(',')
55 p.text(',')
56 p.breakable()
56 p.breakable()
57 p.pretty(item)
57 p.pretty(item)
58
58
59 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
59 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
60 react to that or the result is an infinite loop. `p.text()` just adds
60 react to that or the result is an infinite loop. `p.text()` just adds
61 non breaking text to the output, `p.breakable()` either adds a whitespace
61 non breaking text to the output, `p.breakable()` either adds a whitespace
62 or breaks here. If you pass it an argument it's used instead of the
62 or breaks here. If you pass it an argument it's used instead of the
63 default space. `p.pretty` prettyprints another object using the pretty print
63 default space. `p.pretty` prettyprints another object using the pretty print
64 method.
64 method.
65
65
66 The first parameter to the `group` function specifies the extra indentation
66 The first parameter to the `group` function specifies the extra indentation
67 of the next line. In this example the next item will either be not
67 of the next line. In this example the next item will either be not
68 breaked (if the items are short enough) or aligned with the right edge of
68 breaked (if the items are short enough) or aligned with the right edge of
69 the opening bracked of `MyList`.
69 the opening bracked of `MyList`.
70
70
71 If you want to support python 2.4 and lower you can use this code::
71 If you want to support python 2.4 and lower you can use this code::
72
72
73 class MyList(list):
73 class MyList(list):
74
74
75 def _repr_pretty_(self, p, cycle):
75 def _repr_pretty_(self, p, cycle):
76 if cycle:
76 if cycle:
77 p.text('MyList(...)')
77 p.text('MyList(...)')
78 else:
78 else:
79 p.begin_group(8, 'MyList([')
79 p.begin_group(8, 'MyList([')
80 for idx, item in enumerate(self):
80 for idx, item in enumerate(self):
81 if idx:
81 if idx:
82 p.text(',')
82 p.text(',')
83 p.breakable()
83 p.breakable()
84 p.pretty(item)
84 p.pretty(item)
85 p.end_group(8, '])')
85 p.end_group(8, '])')
86
86
87 If you just want to indent something you can use the group function
87 If you just want to indent something you can use the group function
88 without open / close parameters. Under python 2.5 you can also use this
88 without open / close parameters. Under python 2.5 you can also use this
89 code::
89 code::
90
90
91 with p.indent(2):
91 with p.indent(2):
92 ...
92 ...
93
93
94 Or under python2.4 you might want to modify ``p.indentation`` by hand but
94 Or under python2.4 you might want to modify ``p.indentation`` by hand but
95 this is rather ugly.
95 this is rather ugly.
96
96
97 Inheritance diagram:
97 Inheritance diagram:
98
98
99 .. inheritance-diagram:: IPython.lib.pretty
99 .. inheritance-diagram:: IPython.lib.pretty
100 :parts: 3
100 :parts: 3
101
101
102 :copyright: 2007 by Armin Ronacher.
102 :copyright: 2007 by Armin Ronacher.
103 Portions (c) 2009 by Robert Kern.
103 Portions (c) 2009 by Robert Kern.
104 :license: BSD License.
104 :license: BSD License.
105 """
105 """
106 from __future__ import print_function
106 from __future__ import print_function
107 from contextlib import contextmanager
107 from contextlib import contextmanager
108 import sys
108 import sys
109 import types
109 import types
110 import re
110 import re
111 import datetime
111 import datetime
112 from io import StringIO
113 from collections import deque
112 from collections import deque
114
113
114 from IPython.utils.py3compat import PY3
115
116 if PY3:
117 from io import StringIO
118 else:
119 from StringIO import StringIO
120
115
121
116 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
122 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
117 'for_type', 'for_type_by_name']
123 'for_type', 'for_type_by_name']
118
124
119
125
120 _re_pattern_type = type(re.compile(''))
126 _re_pattern_type = type(re.compile(''))
121
127
122
128
123 def pretty(obj, verbose=False, max_width=79, newline='\n'):
129 def pretty(obj, verbose=False, max_width=79, newline='\n'):
124 """
130 """
125 Pretty print the object's representation.
131 Pretty print the object's representation.
126 """
132 """
127 stream = StringIO()
133 stream = StringIO()
128 printer = RepresentationPrinter(stream, verbose, max_width, newline)
134 printer = RepresentationPrinter(stream, verbose, max_width, newline)
129 printer.pretty(obj)
135 printer.pretty(obj)
130 printer.flush()
136 printer.flush()
131 return stream.getvalue()
137 return stream.getvalue()
132
138
133
139
134 def pprint(obj, verbose=False, max_width=79, newline='\n'):
140 def pprint(obj, verbose=False, max_width=79, newline='\n'):
135 """
141 """
136 Like `pretty` but print to stdout.
142 Like `pretty` but print to stdout.
137 """
143 """
138 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
144 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
139 printer.pretty(obj)
145 printer.pretty(obj)
140 printer.flush()
146 printer.flush()
141 sys.stdout.write(newline)
147 sys.stdout.write(newline)
142 sys.stdout.flush()
148 sys.stdout.flush()
143
149
144 class _PrettyPrinterBase(object):
150 class _PrettyPrinterBase(object):
145
151
146 @contextmanager
152 @contextmanager
147 def indent(self, indent):
153 def indent(self, indent):
148 """with statement support for indenting/dedenting."""
154 """with statement support for indenting/dedenting."""
149 self.indentation += indent
155 self.indentation += indent
150 try:
156 try:
151 yield
157 yield
152 finally:
158 finally:
153 self.indentation -= indent
159 self.indentation -= indent
154
160
155 @contextmanager
161 @contextmanager
156 def group(self, indent=0, open='', close=''):
162 def group(self, indent=0, open='', close=''):
157 """like begin_group / end_group but for the with statement."""
163 """like begin_group / end_group but for the with statement."""
158 self.begin_group(indent, open)
164 self.begin_group(indent, open)
159 try:
165 try:
160 yield
166 yield
161 finally:
167 finally:
162 self.end_group(indent, close)
168 self.end_group(indent, close)
163
169
164 class PrettyPrinter(_PrettyPrinterBase):
170 class PrettyPrinter(_PrettyPrinterBase):
165 """
171 """
166 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
172 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
167 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
173 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
168 this printer knows nothing about the default pprinters or the `_repr_pretty_`
174 this printer knows nothing about the default pprinters or the `_repr_pretty_`
169 callback method.
175 callback method.
170 """
176 """
171
177
172 def __init__(self, output, max_width=79, newline='\n'):
178 def __init__(self, output, max_width=79, newline='\n'):
173 self.output = output
179 self.output = output
174 self.max_width = max_width
180 self.max_width = max_width
175 self.newline = newline
181 self.newline = newline
176 self.output_width = 0
182 self.output_width = 0
177 self.buffer_width = 0
183 self.buffer_width = 0
178 self.buffer = deque()
184 self.buffer = deque()
179
185
180 root_group = Group(0)
186 root_group = Group(0)
181 self.group_stack = [root_group]
187 self.group_stack = [root_group]
182 self.group_queue = GroupQueue(root_group)
188 self.group_queue = GroupQueue(root_group)
183 self.indentation = 0
189 self.indentation = 0
184
190
185 def _break_outer_groups(self):
191 def _break_outer_groups(self):
186 while self.max_width < self.output_width + self.buffer_width:
192 while self.max_width < self.output_width + self.buffer_width:
187 group = self.group_queue.deq()
193 group = self.group_queue.deq()
188 if not group:
194 if not group:
189 return
195 return
190 while group.breakables:
196 while group.breakables:
191 x = self.buffer.popleft()
197 x = self.buffer.popleft()
192 self.output_width = x.output(self.output, self.output_width)
198 self.output_width = x.output(self.output, self.output_width)
193 self.buffer_width -= x.width
199 self.buffer_width -= x.width
194 while self.buffer and isinstance(self.buffer[0], Text):
200 while self.buffer and isinstance(self.buffer[0], Text):
195 x = self.buffer.popleft()
201 x = self.buffer.popleft()
196 self.output_width = x.output(self.output, self.output_width)
202 self.output_width = x.output(self.output, self.output_width)
197 self.buffer_width -= x.width
203 self.buffer_width -= x.width
198
204
199 def text(self, obj):
205 def text(self, obj):
200 """Add literal text to the output."""
206 """Add literal text to the output."""
201 width = len(obj)
207 width = len(obj)
202 if self.buffer:
208 if self.buffer:
203 text = self.buffer[-1]
209 text = self.buffer[-1]
204 if not isinstance(text, Text):
210 if not isinstance(text, Text):
205 text = Text()
211 text = Text()
206 self.buffer.append(text)
212 self.buffer.append(text)
207 text.add(obj, width)
213 text.add(obj, width)
208 self.buffer_width += width
214 self.buffer_width += width
209 self._break_outer_groups()
215 self._break_outer_groups()
210 else:
216 else:
211 self.output.write(obj)
217 self.output.write(obj)
212 self.output_width += width
218 self.output_width += width
213
219
214 def breakable(self, sep=' '):
220 def breakable(self, sep=' '):
215 """
221 """
216 Add a breakable separator to the output. This does not mean that it
222 Add a breakable separator to the output. This does not mean that it
217 will automatically break here. If no breaking on this position takes
223 will automatically break here. If no breaking on this position takes
218 place the `sep` is inserted which default to one space.
224 place the `sep` is inserted which default to one space.
219 """
225 """
220 width = len(sep)
226 width = len(sep)
221 group = self.group_stack[-1]
227 group = self.group_stack[-1]
222 if group.want_break:
228 if group.want_break:
223 self.flush()
229 self.flush()
224 self.output.write(self.newline)
230 self.output.write(self.newline)
225 self.output.write(' ' * self.indentation)
231 self.output.write(' ' * self.indentation)
226 self.output_width = self.indentation
232 self.output_width = self.indentation
227 self.buffer_width = 0
233 self.buffer_width = 0
228 else:
234 else:
229 self.buffer.append(Breakable(sep, width, self))
235 self.buffer.append(Breakable(sep, width, self))
230 self.buffer_width += width
236 self.buffer_width += width
231 self._break_outer_groups()
237 self._break_outer_groups()
232
238
233 def break_(self):
239 def break_(self):
234 """
240 """
235 Explicitly insert a newline into the output, maintaining correct indentation.
241 Explicitly insert a newline into the output, maintaining correct indentation.
236 """
242 """
237 self.flush()
243 self.flush()
238 self.output.write(self.newline)
244 self.output.write(self.newline)
239 self.output.write(' ' * self.indentation)
245 self.output.write(' ' * self.indentation)
240 self.output_width = self.indentation
246 self.output_width = self.indentation
241 self.buffer_width = 0
247 self.buffer_width = 0
242
248
243
249
244 def begin_group(self, indent=0, open=''):
250 def begin_group(self, indent=0, open=''):
245 """
251 """
246 Begin a group. If you want support for python < 2.5 which doesn't has
252 Begin a group. If you want support for python < 2.5 which doesn't has
247 the with statement this is the preferred way:
253 the with statement this is the preferred way:
248
254
249 p.begin_group(1, '{')
255 p.begin_group(1, '{')
250 ...
256 ...
251 p.end_group(1, '}')
257 p.end_group(1, '}')
252
258
253 The python 2.5 expression would be this:
259 The python 2.5 expression would be this:
254
260
255 with p.group(1, '{', '}'):
261 with p.group(1, '{', '}'):
256 ...
262 ...
257
263
258 The first parameter specifies the indentation for the next line (usually
264 The first parameter specifies the indentation for the next line (usually
259 the width of the opening text), the second the opening text. All
265 the width of the opening text), the second the opening text. All
260 parameters are optional.
266 parameters are optional.
261 """
267 """
262 if open:
268 if open:
263 self.text(open)
269 self.text(open)
264 group = Group(self.group_stack[-1].depth + 1)
270 group = Group(self.group_stack[-1].depth + 1)
265 self.group_stack.append(group)
271 self.group_stack.append(group)
266 self.group_queue.enq(group)
272 self.group_queue.enq(group)
267 self.indentation += indent
273 self.indentation += indent
268
274
269 def end_group(self, dedent=0, close=''):
275 def end_group(self, dedent=0, close=''):
270 """End a group. See `begin_group` for more details."""
276 """End a group. See `begin_group` for more details."""
271 self.indentation -= dedent
277 self.indentation -= dedent
272 group = self.group_stack.pop()
278 group = self.group_stack.pop()
273 if not group.breakables:
279 if not group.breakables:
274 self.group_queue.remove(group)
280 self.group_queue.remove(group)
275 if close:
281 if close:
276 self.text(close)
282 self.text(close)
277
283
278 def flush(self):
284 def flush(self):
279 """Flush data that is left in the buffer."""
285 """Flush data that is left in the buffer."""
280 for data in self.buffer:
286 for data in self.buffer:
281 self.output_width += data.output(self.output, self.output_width)
287 self.output_width += data.output(self.output, self.output_width)
282 self.buffer.clear()
288 self.buffer.clear()
283 self.buffer_width = 0
289 self.buffer_width = 0
284
290
285
291
286 def _get_mro(obj_class):
292 def _get_mro(obj_class):
287 """ Get a reasonable method resolution order of a class and its superclasses
293 """ Get a reasonable method resolution order of a class and its superclasses
288 for both old-style and new-style classes.
294 for both old-style and new-style classes.
289 """
295 """
290 if not hasattr(obj_class, '__mro__'):
296 if not hasattr(obj_class, '__mro__'):
291 # Old-style class. Mix in object to make a fake new-style class.
297 # Old-style class. Mix in object to make a fake new-style class.
292 try:
298 try:
293 obj_class = type(obj_class.__name__, (obj_class, object), {})
299 obj_class = type(obj_class.__name__, (obj_class, object), {})
294 except TypeError:
300 except TypeError:
295 # Old-style extension type that does not descend from object.
301 # Old-style extension type that does not descend from object.
296 # FIXME: try to construct a more thorough MRO.
302 # FIXME: try to construct a more thorough MRO.
297 mro = [obj_class]
303 mro = [obj_class]
298 else:
304 else:
299 mro = obj_class.__mro__[1:-1]
305 mro = obj_class.__mro__[1:-1]
300 else:
306 else:
301 mro = obj_class.__mro__
307 mro = obj_class.__mro__
302 return mro
308 return mro
303
309
304
310
305 class RepresentationPrinter(PrettyPrinter):
311 class RepresentationPrinter(PrettyPrinter):
306 """
312 """
307 Special pretty printer that has a `pretty` method that calls the pretty
313 Special pretty printer that has a `pretty` method that calls the pretty
308 printer for a python object.
314 printer for a python object.
309
315
310 This class stores processing data on `self` so you must *never* use
316 This class stores processing data on `self` so you must *never* use
311 this class in a threaded environment. Always lock it or reinstanciate
317 this class in a threaded environment. Always lock it or reinstanciate
312 it.
318 it.
313
319
314 Instances also have a verbose flag callbacks can access to control their
320 Instances also have a verbose flag callbacks can access to control their
315 output. For example the default instance repr prints all attributes and
321 output. For example the default instance repr prints all attributes and
316 methods that are not prefixed by an underscore if the printer is in
322 methods that are not prefixed by an underscore if the printer is in
317 verbose mode.
323 verbose mode.
318 """
324 """
319
325
320 def __init__(self, output, verbose=False, max_width=79, newline='\n',
326 def __init__(self, output, verbose=False, max_width=79, newline='\n',
321 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
327 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
322
328
323 PrettyPrinter.__init__(self, output, max_width, newline)
329 PrettyPrinter.__init__(self, output, max_width, newline)
324 self.verbose = verbose
330 self.verbose = verbose
325 self.stack = []
331 self.stack = []
326 if singleton_pprinters is None:
332 if singleton_pprinters is None:
327 singleton_pprinters = _singleton_pprinters.copy()
333 singleton_pprinters = _singleton_pprinters.copy()
328 self.singleton_pprinters = singleton_pprinters
334 self.singleton_pprinters = singleton_pprinters
329 if type_pprinters is None:
335 if type_pprinters is None:
330 type_pprinters = _type_pprinters.copy()
336 type_pprinters = _type_pprinters.copy()
331 self.type_pprinters = type_pprinters
337 self.type_pprinters = type_pprinters
332 if deferred_pprinters is None:
338 if deferred_pprinters is None:
333 deferred_pprinters = _deferred_type_pprinters.copy()
339 deferred_pprinters = _deferred_type_pprinters.copy()
334 self.deferred_pprinters = deferred_pprinters
340 self.deferred_pprinters = deferred_pprinters
335
341
336 def pretty(self, obj):
342 def pretty(self, obj):
337 """Pretty print the given object."""
343 """Pretty print the given object."""
338 obj_id = id(obj)
344 obj_id = id(obj)
339 cycle = obj_id in self.stack
345 cycle = obj_id in self.stack
340 self.stack.append(obj_id)
346 self.stack.append(obj_id)
341 self.begin_group()
347 self.begin_group()
342 try:
348 try:
343 obj_class = getattr(obj, '__class__', None) or type(obj)
349 obj_class = getattr(obj, '__class__', None) or type(obj)
344 # First try to find registered singleton printers for the type.
350 # First try to find registered singleton printers for the type.
345 try:
351 try:
346 printer = self.singleton_pprinters[obj_id]
352 printer = self.singleton_pprinters[obj_id]
347 except (TypeError, KeyError):
353 except (TypeError, KeyError):
348 pass
354 pass
349 else:
355 else:
350 return printer(obj, self, cycle)
356 return printer(obj, self, cycle)
351 # Next walk the mro and check for either:
357 # Next walk the mro and check for either:
352 # 1) a registered printer
358 # 1) a registered printer
353 # 2) a _repr_pretty_ method
359 # 2) a _repr_pretty_ method
354 for cls in _get_mro(obj_class):
360 for cls in _get_mro(obj_class):
355 if cls in self.type_pprinters:
361 if cls in self.type_pprinters:
356 # printer registered in self.type_pprinters
362 # printer registered in self.type_pprinters
357 return self.type_pprinters[cls](obj, self, cycle)
363 return self.type_pprinters[cls](obj, self, cycle)
358 else:
364 else:
359 # deferred printer
365 # deferred printer
360 printer = self._in_deferred_types(cls)
366 printer = self._in_deferred_types(cls)
361 if printer is not None:
367 if printer is not None:
362 return printer(obj, self, cycle)
368 return printer(obj, self, cycle)
363 else:
369 else:
364 # Finally look for special method names.
370 # Finally look for special method names.
365 # Some objects automatically create any requested
371 # Some objects automatically create any requested
366 # attribute. Try to ignore most of them by checking for
372 # attribute. Try to ignore most of them by checking for
367 # callability.
373 # callability.
368 if '_repr_pretty_' in cls.__dict__:
374 if '_repr_pretty_' in cls.__dict__:
369 meth = cls._repr_pretty_
375 meth = cls._repr_pretty_
370 if callable(meth):
376 if callable(meth):
371 return meth(obj, self, cycle)
377 return meth(obj, self, cycle)
372 return _default_pprint(obj, self, cycle)
378 return _default_pprint(obj, self, cycle)
373 finally:
379 finally:
374 self.end_group()
380 self.end_group()
375 self.stack.pop()
381 self.stack.pop()
376
382
377 def _in_deferred_types(self, cls):
383 def _in_deferred_types(self, cls):
378 """
384 """
379 Check if the given class is specified in the deferred type registry.
385 Check if the given class is specified in the deferred type registry.
380
386
381 Returns the printer from the registry if it exists, and None if the
387 Returns the printer from the registry if it exists, and None if the
382 class is not in the registry. Successful matches will be moved to the
388 class is not in the registry. Successful matches will be moved to the
383 regular type registry for future use.
389 regular type registry for future use.
384 """
390 """
385 mod = getattr(cls, '__module__', None)
391 mod = getattr(cls, '__module__', None)
386 name = getattr(cls, '__name__', None)
392 name = getattr(cls, '__name__', None)
387 key = (mod, name)
393 key = (mod, name)
388 printer = None
394 printer = None
389 if key in self.deferred_pprinters:
395 if key in self.deferred_pprinters:
390 # Move the printer over to the regular registry.
396 # Move the printer over to the regular registry.
391 printer = self.deferred_pprinters.pop(key)
397 printer = self.deferred_pprinters.pop(key)
392 self.type_pprinters[cls] = printer
398 self.type_pprinters[cls] = printer
393 return printer
399 return printer
394
400
395
401
396 class Printable(object):
402 class Printable(object):
397
403
398 def output(self, stream, output_width):
404 def output(self, stream, output_width):
399 return output_width
405 return output_width
400
406
401
407
402 class Text(Printable):
408 class Text(Printable):
403
409
404 def __init__(self):
410 def __init__(self):
405 self.objs = []
411 self.objs = []
406 self.width = 0
412 self.width = 0
407
413
408 def output(self, stream, output_width):
414 def output(self, stream, output_width):
409 for obj in self.objs:
415 for obj in self.objs:
410 stream.write(obj)
416 stream.write(obj)
411 return output_width + self.width
417 return output_width + self.width
412
418
413 def add(self, obj, width):
419 def add(self, obj, width):
414 self.objs.append(obj)
420 self.objs.append(obj)
415 self.width += width
421 self.width += width
416
422
417
423
418 class Breakable(Printable):
424 class Breakable(Printable):
419
425
420 def __init__(self, seq, width, pretty):
426 def __init__(self, seq, width, pretty):
421 self.obj = seq
427 self.obj = seq
422 self.width = width
428 self.width = width
423 self.pretty = pretty
429 self.pretty = pretty
424 self.indentation = pretty.indentation
430 self.indentation = pretty.indentation
425 self.group = pretty.group_stack[-1]
431 self.group = pretty.group_stack[-1]
426 self.group.breakables.append(self)
432 self.group.breakables.append(self)
427
433
428 def output(self, stream, output_width):
434 def output(self, stream, output_width):
429 self.group.breakables.popleft()
435 self.group.breakables.popleft()
430 if self.group.want_break:
436 if self.group.want_break:
431 stream.write(self.pretty.newline)
437 stream.write(self.pretty.newline)
432 stream.write(' ' * self.indentation)
438 stream.write(' ' * self.indentation)
433 return self.indentation
439 return self.indentation
434 if not self.group.breakables:
440 if not self.group.breakables:
435 self.pretty.group_queue.remove(self.group)
441 self.pretty.group_queue.remove(self.group)
436 stream.write(self.obj)
442 stream.write(self.obj)
437 return output_width + self.width
443 return output_width + self.width
438
444
439
445
440 class Group(Printable):
446 class Group(Printable):
441
447
442 def __init__(self, depth):
448 def __init__(self, depth):
443 self.depth = depth
449 self.depth = depth
444 self.breakables = deque()
450 self.breakables = deque()
445 self.want_break = False
451 self.want_break = False
446
452
447
453
448 class GroupQueue(object):
454 class GroupQueue(object):
449
455
450 def __init__(self, *groups):
456 def __init__(self, *groups):
451 self.queue = []
457 self.queue = []
452 for group in groups:
458 for group in groups:
453 self.enq(group)
459 self.enq(group)
454
460
455 def enq(self, group):
461 def enq(self, group):
456 depth = group.depth
462 depth = group.depth
457 while depth > len(self.queue) - 1:
463 while depth > len(self.queue) - 1:
458 self.queue.append([])
464 self.queue.append([])
459 self.queue[depth].append(group)
465 self.queue[depth].append(group)
460
466
461 def deq(self):
467 def deq(self):
462 for stack in self.queue:
468 for stack in self.queue:
463 for idx, group in enumerate(reversed(stack)):
469 for idx, group in enumerate(reversed(stack)):
464 if group.breakables:
470 if group.breakables:
465 del stack[idx]
471 del stack[idx]
466 group.want_break = True
472 group.want_break = True
467 return group
473 return group
468 for group in stack:
474 for group in stack:
469 group.want_break = True
475 group.want_break = True
470 del stack[:]
476 del stack[:]
471
477
472 def remove(self, group):
478 def remove(self, group):
473 try:
479 try:
474 self.queue[group.depth].remove(group)
480 self.queue[group.depth].remove(group)
475 except ValueError:
481 except ValueError:
476 pass
482 pass
477
483
478 try:
484 try:
479 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
485 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
480 except AttributeError: # Python 3
486 except AttributeError: # Python 3
481 _baseclass_reprs = (object.__repr__,)
487 _baseclass_reprs = (object.__repr__,)
482
488
483
489
484 def _default_pprint(obj, p, cycle):
490 def _default_pprint(obj, p, cycle):
485 """
491 """
486 The default print function. Used if an object does not provide one and
492 The default print function. Used if an object does not provide one and
487 it's none of the builtin objects.
493 it's none of the builtin objects.
488 """
494 """
489 klass = getattr(obj, '__class__', None) or type(obj)
495 klass = getattr(obj, '__class__', None) or type(obj)
490 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
496 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
491 # A user-provided repr. Find newlines and replace them with p.break_()
497 # A user-provided repr. Find newlines and replace them with p.break_()
492 output = repr(obj)
498 output = repr(obj)
493 for idx,output_line in enumerate(output.splitlines()):
499 for idx,output_line in enumerate(output.splitlines()):
494 if idx:
500 if idx:
495 p.break_()
501 p.break_()
496 p.text(output_line)
502 p.text(output_line)
497 return
503 return
498 p.begin_group(1, '<')
504 p.begin_group(1, '<')
499 p.pretty(klass)
505 p.pretty(klass)
500 p.text(' at 0x%x' % id(obj))
506 p.text(' at 0x%x' % id(obj))
501 if cycle:
507 if cycle:
502 p.text(' ...')
508 p.text(' ...')
503 elif p.verbose:
509 elif p.verbose:
504 first = True
510 first = True
505 for key in dir(obj):
511 for key in dir(obj):
506 if not key.startswith('_'):
512 if not key.startswith('_'):
507 try:
513 try:
508 value = getattr(obj, key)
514 value = getattr(obj, key)
509 except AttributeError:
515 except AttributeError:
510 continue
516 continue
511 if isinstance(value, types.MethodType):
517 if isinstance(value, types.MethodType):
512 continue
518 continue
513 if not first:
519 if not first:
514 p.text(',')
520 p.text(',')
515 p.breakable()
521 p.breakable()
516 p.text(key)
522 p.text(key)
517 p.text('=')
523 p.text('=')
518 step = len(key) + 1
524 step = len(key) + 1
519 p.indentation += step
525 p.indentation += step
520 p.pretty(value)
526 p.pretty(value)
521 p.indentation -= step
527 p.indentation -= step
522 first = False
528 first = False
523 p.end_group(1, '>')
529 p.end_group(1, '>')
524
530
525
531
526 def _seq_pprinter_factory(start, end, basetype):
532 def _seq_pprinter_factory(start, end, basetype):
527 """
533 """
528 Factory that returns a pprint function useful for sequences. Used by
534 Factory that returns a pprint function useful for sequences. Used by
529 the default pprint for tuples, dicts, and lists.
535 the default pprint for tuples, dicts, and lists.
530 """
536 """
531 def inner(obj, p, cycle):
537 def inner(obj, p, cycle):
532 typ = type(obj)
538 typ = type(obj)
533 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
539 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
534 # If the subclass provides its own repr, use it instead.
540 # If the subclass provides its own repr, use it instead.
535 return p.text(typ.__repr__(obj))
541 return p.text(typ.__repr__(obj))
536
542
537 if cycle:
543 if cycle:
538 return p.text(start + '...' + end)
544 return p.text(start + '...' + end)
539 step = len(start)
545 step = len(start)
540 p.begin_group(step, start)
546 p.begin_group(step, start)
541 for idx, x in enumerate(obj):
547 for idx, x in enumerate(obj):
542 if idx:
548 if idx:
543 p.text(',')
549 p.text(',')
544 p.breakable()
550 p.breakable()
545 p.pretty(x)
551 p.pretty(x)
546 if len(obj) == 1 and type(obj) is tuple:
552 if len(obj) == 1 and type(obj) is tuple:
547 # Special case for 1-item tuples.
553 # Special case for 1-item tuples.
548 p.text(',')
554 p.text(',')
549 p.end_group(step, end)
555 p.end_group(step, end)
550 return inner
556 return inner
551
557
552
558
553 def _set_pprinter_factory(start, end, basetype):
559 def _set_pprinter_factory(start, end, basetype):
554 """
560 """
555 Factory that returns a pprint function useful for sets and frozensets.
561 Factory that returns a pprint function useful for sets and frozensets.
556 """
562 """
557 def inner(obj, p, cycle):
563 def inner(obj, p, cycle):
558 typ = type(obj)
564 typ = type(obj)
559 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
565 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
560 # If the subclass provides its own repr, use it instead.
566 # If the subclass provides its own repr, use it instead.
561 return p.text(typ.__repr__(obj))
567 return p.text(typ.__repr__(obj))
562
568
563 if cycle:
569 if cycle:
564 return p.text(start + '...' + end)
570 return p.text(start + '...' + end)
565 if len(obj) == 0:
571 if len(obj) == 0:
566 # Special case.
572 # Special case.
567 p.text(basetype.__name__ + '()')
573 p.text(basetype.__name__ + '()')
568 else:
574 else:
569 step = len(start)
575 step = len(start)
570 p.begin_group(step, start)
576 p.begin_group(step, start)
571 # Like dictionary keys, we will try to sort the items.
577 # Like dictionary keys, we will try to sort the items.
572 items = list(obj)
578 items = list(obj)
573 try:
579 try:
574 items.sort()
580 items.sort()
575 except Exception:
581 except Exception:
576 # Sometimes the items don't sort.
582 # Sometimes the items don't sort.
577 pass
583 pass
578 for idx, x in enumerate(items):
584 for idx, x in enumerate(items):
579 if idx:
585 if idx:
580 p.text(',')
586 p.text(',')
581 p.breakable()
587 p.breakable()
582 p.pretty(x)
588 p.pretty(x)
583 p.end_group(step, end)
589 p.end_group(step, end)
584 return inner
590 return inner
585
591
586
592
587 def _dict_pprinter_factory(start, end, basetype=None):
593 def _dict_pprinter_factory(start, end, basetype=None):
588 """
594 """
589 Factory that returns a pprint function used by the default pprint of
595 Factory that returns a pprint function used by the default pprint of
590 dicts and dict proxies.
596 dicts and dict proxies.
591 """
597 """
592 def inner(obj, p, cycle):
598 def inner(obj, p, cycle):
593 typ = type(obj)
599 typ = type(obj)
594 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
600 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
595 # If the subclass provides its own repr, use it instead.
601 # If the subclass provides its own repr, use it instead.
596 return p.text(typ.__repr__(obj))
602 return p.text(typ.__repr__(obj))
597
603
598 if cycle:
604 if cycle:
599 return p.text('{...}')
605 return p.text('{...}')
600 p.begin_group(1, start)
606 p.begin_group(1, start)
601 keys = obj.keys()
607 keys = obj.keys()
602 try:
608 try:
603 keys.sort()
609 keys.sort()
604 except Exception as e:
610 except Exception as e:
605 # Sometimes the keys don't sort.
611 # Sometimes the keys don't sort.
606 pass
612 pass
607 for idx, key in enumerate(keys):
613 for idx, key in enumerate(keys):
608 if idx:
614 if idx:
609 p.text(',')
615 p.text(',')
610 p.breakable()
616 p.breakable()
611 p.pretty(key)
617 p.pretty(key)
612 p.text(': ')
618 p.text(': ')
613 p.pretty(obj[key])
619 p.pretty(obj[key])
614 p.end_group(1, end)
620 p.end_group(1, end)
615 return inner
621 return inner
616
622
617
623
618 def _super_pprint(obj, p, cycle):
624 def _super_pprint(obj, p, cycle):
619 """The pprint for the super type."""
625 """The pprint for the super type."""
620 p.begin_group(8, '<super: ')
626 p.begin_group(8, '<super: ')
621 p.pretty(obj.__self_class__)
627 p.pretty(obj.__self_class__)
622 p.text(',')
628 p.text(',')
623 p.breakable()
629 p.breakable()
624 p.pretty(obj.__self__)
630 p.pretty(obj.__self__)
625 p.end_group(8, '>')
631 p.end_group(8, '>')
626
632
627
633
628 def _re_pattern_pprint(obj, p, cycle):
634 def _re_pattern_pprint(obj, p, cycle):
629 """The pprint function for regular expression patterns."""
635 """The pprint function for regular expression patterns."""
630 p.text('re.compile(')
636 p.text('re.compile(')
631 pattern = repr(obj.pattern)
637 pattern = repr(obj.pattern)
632 if pattern[:1] in 'uU':
638 if pattern[:1] in 'uU':
633 pattern = pattern[1:]
639 pattern = pattern[1:]
634 prefix = 'ur'
640 prefix = 'ur'
635 else:
641 else:
636 prefix = 'r'
642 prefix = 'r'
637 pattern = prefix + pattern.replace('\\\\', '\\')
643 pattern = prefix + pattern.replace('\\\\', '\\')
638 p.text(pattern)
644 p.text(pattern)
639 if obj.flags:
645 if obj.flags:
640 p.text(',')
646 p.text(',')
641 p.breakable()
647 p.breakable()
642 done_one = False
648 done_one = False
643 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
649 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
644 'UNICODE', 'VERBOSE', 'DEBUG'):
650 'UNICODE', 'VERBOSE', 'DEBUG'):
645 if obj.flags & getattr(re, flag):
651 if obj.flags & getattr(re, flag):
646 if done_one:
652 if done_one:
647 p.text('|')
653 p.text('|')
648 p.text('re.' + flag)
654 p.text('re.' + flag)
649 done_one = True
655 done_one = True
650 p.text(')')
656 p.text(')')
651
657
652
658
653 def _type_pprint(obj, p, cycle):
659 def _type_pprint(obj, p, cycle):
654 """The pprint for classes and types."""
660 """The pprint for classes and types."""
655 mod = getattr(obj, '__module__', None)
661 mod = getattr(obj, '__module__', None)
656 if mod is None:
662 if mod is None:
657 # Heap allocated types might not have the module attribute,
663 # Heap allocated types might not have the module attribute,
658 # and others may set it to None.
664 # and others may set it to None.
659 return p.text(obj.__name__)
665 return p.text(obj.__name__)
660
666
661 if mod in ('__builtin__', 'builtins', 'exceptions'):
667 if mod in ('__builtin__', 'builtins', 'exceptions'):
662 name = obj.__name__
668 name = obj.__name__
663 else:
669 else:
664 name = mod + '.' + obj.__name__
670 name = mod + '.' + obj.__name__
665 p.text(name)
671 p.text(name)
666
672
667
673
668 def _repr_pprint(obj, p, cycle):
674 def _repr_pprint(obj, p, cycle):
669 """A pprint that just redirects to the normal repr function."""
675 """A pprint that just redirects to the normal repr function."""
670 p.text(repr(obj))
676 p.text(repr(obj))
671
677
672
678
673 def _function_pprint(obj, p, cycle):
679 def _function_pprint(obj, p, cycle):
674 """Base pprint for all functions and builtin functions."""
680 """Base pprint for all functions and builtin functions."""
675 if obj.__module__ in ('__builtin__', 'builtins', 'exceptions') or not obj.__module__:
681 if obj.__module__ in ('__builtin__', 'builtins', 'exceptions') or not obj.__module__:
676 name = obj.__name__
682 name = obj.__name__
677 else:
683 else:
678 name = obj.__module__ + '.' + obj.__name__
684 name = obj.__module__ + '.' + obj.__name__
679 p.text('<function %s>' % name)
685 p.text('<function %s>' % name)
680
686
681
687
682 def _exception_pprint(obj, p, cycle):
688 def _exception_pprint(obj, p, cycle):
683 """Base pprint for all exceptions."""
689 """Base pprint for all exceptions."""
684 if obj.__class__.__module__ in ('exceptions', 'builtins'):
690 if obj.__class__.__module__ in ('exceptions', 'builtins'):
685 name = obj.__class__.__name__
691 name = obj.__class__.__name__
686 else:
692 else:
687 name = '%s.%s' % (
693 name = '%s.%s' % (
688 obj.__class__.__module__,
694 obj.__class__.__module__,
689 obj.__class__.__name__
695 obj.__class__.__name__
690 )
696 )
691 step = len(name) + 1
697 step = len(name) + 1
692 p.begin_group(step, name + '(')
698 p.begin_group(step, name + '(')
693 for idx, arg in enumerate(getattr(obj, 'args', ())):
699 for idx, arg in enumerate(getattr(obj, 'args', ())):
694 if idx:
700 if idx:
695 p.text(',')
701 p.text(',')
696 p.breakable()
702 p.breakable()
697 p.pretty(arg)
703 p.pretty(arg)
698 p.end_group(step, ')')
704 p.end_group(step, ')')
699
705
700
706
701 #: the exception base
707 #: the exception base
702 try:
708 try:
703 _exception_base = BaseException
709 _exception_base = BaseException
704 except NameError:
710 except NameError:
705 _exception_base = Exception
711 _exception_base = Exception
706
712
707
713
708 #: printers for builtin types
714 #: printers for builtin types
709 _type_pprinters = {
715 _type_pprinters = {
710 int: _repr_pprint,
716 int: _repr_pprint,
711 float: _repr_pprint,
717 float: _repr_pprint,
712 str: _repr_pprint,
718 str: _repr_pprint,
713 tuple: _seq_pprinter_factory('(', ')', tuple),
719 tuple: _seq_pprinter_factory('(', ')', tuple),
714 list: _seq_pprinter_factory('[', ']', list),
720 list: _seq_pprinter_factory('[', ']', list),
715 dict: _dict_pprinter_factory('{', '}', dict),
721 dict: _dict_pprinter_factory('{', '}', dict),
716
722
717 set: _set_pprinter_factory('{', '}', set),
723 set: _set_pprinter_factory('{', '}', set),
718 frozenset: _set_pprinter_factory('frozenset({', '})', frozenset),
724 frozenset: _set_pprinter_factory('frozenset({', '})', frozenset),
719 super: _super_pprint,
725 super: _super_pprint,
720 _re_pattern_type: _re_pattern_pprint,
726 _re_pattern_type: _re_pattern_pprint,
721 type: _type_pprint,
727 type: _type_pprint,
722 types.FunctionType: _function_pprint,
728 types.FunctionType: _function_pprint,
723 types.BuiltinFunctionType: _function_pprint,
729 types.BuiltinFunctionType: _function_pprint,
724 types.MethodType: _repr_pprint,
730 types.MethodType: _repr_pprint,
725
731
726 datetime.datetime: _repr_pprint,
732 datetime.datetime: _repr_pprint,
727 datetime.timedelta: _repr_pprint,
733 datetime.timedelta: _repr_pprint,
728 _exception_base: _exception_pprint
734 _exception_base: _exception_pprint
729 }
735 }
730
736
731 try:
737 try:
732 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
738 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
733 _type_pprinters[types.ClassType] = _type_pprint
739 _type_pprinters[types.ClassType] = _type_pprint
734 _type_pprinters[types.SliceType] = _repr_pprint
740 _type_pprinters[types.SliceType] = _repr_pprint
735 except AttributeError: # Python 3
741 except AttributeError: # Python 3
736 _type_pprinters[slice] = _repr_pprint
742 _type_pprinters[slice] = _repr_pprint
737
743
738 try:
744 try:
739 _type_pprinters[xrange] = _repr_pprint
745 _type_pprinters[xrange] = _repr_pprint
740 _type_pprinters[long] = _repr_pprint
746 _type_pprinters[long] = _repr_pprint
741 _type_pprinters[unicode] = _repr_pprint
747 _type_pprinters[unicode] = _repr_pprint
742 except NameError:
748 except NameError:
743 _type_pprinters[range] = _repr_pprint
749 _type_pprinters[range] = _repr_pprint
744 _type_pprinters[bytes] = _repr_pprint
750 _type_pprinters[bytes] = _repr_pprint
745
751
746 #: printers for types specified by name
752 #: printers for types specified by name
747 _deferred_type_pprinters = {
753 _deferred_type_pprinters = {
748 }
754 }
749
755
750 def for_type(typ, func):
756 def for_type(typ, func):
751 """
757 """
752 Add a pretty printer for a given type.
758 Add a pretty printer for a given type.
753 """
759 """
754 oldfunc = _type_pprinters.get(typ, None)
760 oldfunc = _type_pprinters.get(typ, None)
755 if func is not None:
761 if func is not None:
756 # To support easy restoration of old pprinters, we need to ignore Nones.
762 # To support easy restoration of old pprinters, we need to ignore Nones.
757 _type_pprinters[typ] = func
763 _type_pprinters[typ] = func
758 return oldfunc
764 return oldfunc
759
765
760 def for_type_by_name(type_module, type_name, func):
766 def for_type_by_name(type_module, type_name, func):
761 """
767 """
762 Add a pretty printer for a type specified by the module and name of a type
768 Add a pretty printer for a type specified by the module and name of a type
763 rather than the type object itself.
769 rather than the type object itself.
764 """
770 """
765 key = (type_module, type_name)
771 key = (type_module, type_name)
766 oldfunc = _deferred_type_pprinters.get(key, None)
772 oldfunc = _deferred_type_pprinters.get(key, None)
767 if func is not None:
773 if func is not None:
768 # To support easy restoration of old pprinters, we need to ignore Nones.
774 # To support easy restoration of old pprinters, we need to ignore Nones.
769 _deferred_type_pprinters[key] = func
775 _deferred_type_pprinters[key] = func
770 return oldfunc
776 return oldfunc
771
777
772
778
773 #: printers for the default singletons
779 #: printers for the default singletons
774 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
780 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
775 NotImplemented]), _repr_pprint)
781 NotImplemented]), _repr_pprint)
776
782
777
783
778 if __name__ == '__main__':
784 if __name__ == '__main__':
779 from random import randrange
785 from random import randrange
780 class Foo(object):
786 class Foo(object):
781 def __init__(self):
787 def __init__(self):
782 self.foo = 1
788 self.foo = 1
783 self.bar = re.compile(r'\s+')
789 self.bar = re.compile(r'\s+')
784 self.blub = dict.fromkeys(range(30), randrange(1, 40))
790 self.blub = dict.fromkeys(range(30), randrange(1, 40))
785 self.hehe = 23424.234234
791 self.hehe = 23424.234234
786 self.list = ["blub", "blah", self]
792 self.list = ["blub", "blah", self]
787
793
788 def get_foo(self):
794 def get_foo(self):
789 print("foo")
795 print("foo")
790
796
791 pprint(Foo(), verbose=True)
797 pprint(Foo(), verbose=True)
@@ -1,180 +1,184 b''
1 """Test suite for the irunner module.
1 """Test suite for the irunner module.
2
2
3 Not the most elegant or fine-grained, but it does cover at least the bulk
3 Not the most elegant or fine-grained, but it does cover at least the bulk
4 functionality."""
4 functionality."""
5 from __future__ import print_function
5 from __future__ import print_function
6
6
7 # Global to make tests extra verbose and help debugging
7 # Global to make tests extra verbose and help debugging
8 VERBOSE = True
8 VERBOSE = True
9
9
10 # stdlib imports
10 # stdlib imports
11 import io
12 import sys
11 import sys
13 import unittest
12 import unittest
14
13
15 # IPython imports
14 # IPython imports
16 from IPython.lib import irunner
15 from IPython.lib import irunner
17 from IPython.utils.py3compat import doctest_refactor_print
16 from IPython.utils.py3compat import doctest_refactor_print, PY3
17
18 if PY3:
19 from io import StringIO
20 else:
21 from StringIO import StringIO
18
22
19 # Testing code begins
23 # Testing code begins
20 class RunnerTestCase(unittest.TestCase):
24 class RunnerTestCase(unittest.TestCase):
21
25
22 def setUp(self):
26 def setUp(self):
23 self.out = io.StringIO()
27 self.out = StringIO()
24 #self.out = sys.stdout
28 #self.out = sys.stdout
25
29
26 def _test_runner(self,runner,source,output):
30 def _test_runner(self,runner,source,output):
27 """Test that a given runner's input/output match."""
31 """Test that a given runner's input/output match."""
28
32
29 runner.run_source(source)
33 runner.run_source(source)
30 out = self.out.getvalue()
34 out = self.out.getvalue()
31 #out = ''
35 #out = ''
32 # this output contains nasty \r\n lineends, and the initial ipython
36 # this output contains nasty \r\n lineends, and the initial ipython
33 # banner. clean it up for comparison, removing lines of whitespace
37 # banner. clean it up for comparison, removing lines of whitespace
34 output_l = [l for l in output.splitlines() if l and not l.isspace()]
38 output_l = [l for l in output.splitlines() if l and not l.isspace()]
35 out_l = [l for l in out.splitlines() if l and not l.isspace()]
39 out_l = [l for l in out.splitlines() if l and not l.isspace()]
36 mismatch = 0
40 mismatch = 0
37 if len(output_l) != len(out_l):
41 if len(output_l) != len(out_l):
38 message = ("Mismatch in number of lines\n\n"
42 message = ("Mismatch in number of lines\n\n"
39 "Expected:\n"
43 "Expected:\n"
40 "~~~~~~~~~\n"
44 "~~~~~~~~~\n"
41 "%s\n\n"
45 "%s\n\n"
42 "Got:\n"
46 "Got:\n"
43 "~~~~~~~~~\n"
47 "~~~~~~~~~\n"
44 "%s"
48 "%s"
45 ) % ("\n".join(output_l), "\n".join(out_l))
49 ) % ("\n".join(output_l), "\n".join(out_l))
46 self.fail(message)
50 self.fail(message)
47 for n in range(len(output_l)):
51 for n in range(len(output_l)):
48 # Do a line-by-line comparison
52 # Do a line-by-line comparison
49 ol1 = output_l[n].strip()
53 ol1 = output_l[n].strip()
50 ol2 = out_l[n].strip()
54 ol2 = out_l[n].strip()
51 if ol1 != ol2:
55 if ol1 != ol2:
52 mismatch += 1
56 mismatch += 1
53 if VERBOSE:
57 if VERBOSE:
54 print('<<< line %s does not match:' % n)
58 print('<<< line %s does not match:' % n)
55 print(repr(ol1))
59 print(repr(ol1))
56 print(repr(ol2))
60 print(repr(ol2))
57 print('>>>')
61 print('>>>')
58 self.assertTrue(mismatch==0,'Number of mismatched lines: %s' %
62 self.assertTrue(mismatch==0,'Number of mismatched lines: %s' %
59 mismatch)
63 mismatch)
60
64
61 def testIPython(self):
65 def testIPython(self):
62 """Test the IPython runner."""
66 """Test the IPython runner."""
63 source = doctest_refactor_print("""
67 source = doctest_refactor_print("""
64 print 'hello, this is python'
68 print 'hello, this is python'
65 # some more code
69 # some more code
66 x=1;y=2
70 x=1;y=2
67 x+y**2
71 x+y**2
68
72
69 # An example of autocall functionality
73 # An example of autocall functionality
70 from math import *
74 from math import *
71 autocall 1
75 autocall 1
72 cos pi
76 cos pi
73 autocall 0
77 autocall 0
74 cos pi
78 cos pi
75 cos(pi)
79 cos(pi)
76
80
77 for i in range(5):
81 for i in range(5):
78 print i
82 print i
79
83
80 print "that's all folks!"
84 print "that's all folks!"
81
85
82 exit
86 exit
83 """)
87 """)
84 output = doctest_refactor_print("""\
88 output = doctest_refactor_print("""\
85 In [1]: print 'hello, this is python'
89 In [1]: print 'hello, this is python'
86 hello, this is python
90 hello, this is python
87
91
88
92
89 # some more code
93 # some more code
90 In [2]: x=1;y=2
94 In [2]: x=1;y=2
91
95
92 In [3]: x+y**2
96 In [3]: x+y**2
93 Out[3]: 5
97 Out[3]: 5
94
98
95
99
96 # An example of autocall functionality
100 # An example of autocall functionality
97 In [4]: from math import *
101 In [4]: from math import *
98
102
99 In [5]: autocall 1
103 In [5]: autocall 1
100 Automatic calling is: Smart
104 Automatic calling is: Smart
101
105
102 In [6]: cos pi
106 In [6]: cos pi
103 ------> cos(pi)
107 ------> cos(pi)
104 Out[6]: -1.0
108 Out[6]: -1.0
105
109
106 In [7]: autocall 0
110 In [7]: autocall 0
107 Automatic calling is: OFF
111 Automatic calling is: OFF
108
112
109 In [8]: cos pi
113 In [8]: cos pi
110 File "<ipython-input-8-6bd7313dd9a9>", line 1
114 File "<ipython-input-8-6bd7313dd9a9>", line 1
111 cos pi
115 cos pi
112 ^
116 ^
113 SyntaxError: invalid syntax
117 SyntaxError: invalid syntax
114
118
115
119
116 In [9]: cos(pi)
120 In [9]: cos(pi)
117 Out[9]: -1.0
121 Out[9]: -1.0
118
122
119
123
120 In [10]: for i in range(5):
124 In [10]: for i in range(5):
121 ....: print i
125 ....: print i
122 ....:
126 ....:
123 0
127 0
124 1
128 1
125 2
129 2
126 3
130 3
127 4
131 4
128
132
129 In [11]: print "that's all folks!"
133 In [11]: print "that's all folks!"
130 that's all folks!
134 that's all folks!
131
135
132
136
133 In [12]: exit
137 In [12]: exit
134 """)
138 """)
135 runner = irunner.IPythonRunner(out=self.out)
139 runner = irunner.IPythonRunner(out=self.out)
136 self._test_runner(runner,source,output)
140 self._test_runner(runner,source,output)
137
141
138 def testPython(self):
142 def testPython(self):
139 """Test the Python runner."""
143 """Test the Python runner."""
140 runner = irunner.PythonRunner(out=self.out, args=['-E'])
144 runner = irunner.PythonRunner(out=self.out, args=['-E'])
141 source = doctest_refactor_print("""
145 source = doctest_refactor_print("""
142 print 'hello, this is python'
146 print 'hello, this is python'
143
147
144 # some more code
148 # some more code
145 x=1;y=2
149 x=1;y=2
146 x+y**2
150 x+y**2
147
151
148 from math import *
152 from math import *
149 cos(pi)
153 cos(pi)
150
154
151 for i in range(5):
155 for i in range(5):
152 print i
156 print i
153
157
154 print "that's all folks!"
158 print "that's all folks!"
155 """)
159 """)
156 output = doctest_refactor_print("""\
160 output = doctest_refactor_print("""\
157 >>> print 'hello, this is python'
161 >>> print 'hello, this is python'
158 hello, this is python
162 hello, this is python
159
163
160 # some more code
164 # some more code
161 >>> x=1;y=2
165 >>> x=1;y=2
162 >>> x+y**2
166 >>> x+y**2
163 5
167 5
164
168
165 >>> from math import *
169 >>> from math import *
166 >>> cos(pi)
170 >>> cos(pi)
167 -1.0
171 -1.0
168
172
169 >>> for i in range(5):
173 >>> for i in range(5):
170 ... print i
174 ... print i
171 ...
175 ...
172 0
176 0
173 1
177 1
174 2
178 2
175 3
179 3
176 4
180 4
177 >>> print "that's all folks!"
181 >>> print "that's all folks!"
178 that's all folks!
182 that's all folks!
179 """)
183 """)
180 self._test_runner(runner,source,output)
184 self._test_runner(runner,source,output)
@@ -1,121 +1,126 b''
1 """Test suite for pylab_import_all magic
1 """Test suite for pylab_import_all magic
2 Modified from the irunner module but using regex.
2 Modified from the irunner module but using regex.
3 """
3 """
4 from __future__ import print_function
4 from __future__ import print_function
5
5
6 # Global to make tests extra verbose and help debugging
6 # Global to make tests extra verbose and help debugging
7 VERBOSE = True
7 VERBOSE = True
8
8
9 # stdlib imports
9 # stdlib imports
10 import io
11 import sys
10 import sys
12 import unittest
11 import unittest
13 import re
12 import re
14
13
15 # IPython imports
14 # IPython imports
16 from IPython.lib import irunner
15 from IPython.lib import irunner
17 from IPython.testing import decorators
16 from IPython.testing import decorators
17 from IPython.utils.py3compat import PY3
18
19 if PY3:
20 from io import StringIO
21 else:
22 from StringIO import StringIO
18
23
19 def pylab_not_importable():
24 def pylab_not_importable():
20 """Test if importing pylab fails. (For example, when having no display)"""
25 """Test if importing pylab fails. (For example, when having no display)"""
21 try:
26 try:
22 import pylab
27 import pylab
23 return False
28 return False
24 except:
29 except:
25 return True
30 return True
26
31
27 # Testing code begins
32 # Testing code begins
28 class RunnerTestCase(unittest.TestCase):
33 class RunnerTestCase(unittest.TestCase):
29
34
30 def setUp(self):
35 def setUp(self):
31 self.out = io.StringIO()
36 self.out = StringIO()
32 #self.out = sys.stdout
37 #self.out = sys.stdout
33
38
34 def _test_runner(self,runner,source,output):
39 def _test_runner(self,runner,source,output):
35 """Test that a given runner's input/output match."""
40 """Test that a given runner's input/output match."""
36
41
37 runner.run_source(source)
42 runner.run_source(source)
38 out = self.out.getvalue()
43 out = self.out.getvalue()
39 #out = ''
44 #out = ''
40 # this output contains nasty \r\n lineends, and the initial ipython
45 # this output contains nasty \r\n lineends, and the initial ipython
41 # banner. clean it up for comparison, removing lines of whitespace
46 # banner. clean it up for comparison, removing lines of whitespace
42 output_l = [l for l in output.splitlines() if l and not l.isspace()]
47 output_l = [l for l in output.splitlines() if l and not l.isspace()]
43 out_l = [l for l in out.splitlines() if l and not l.isspace()]
48 out_l = [l for l in out.splitlines() if l and not l.isspace()]
44 mismatch = 0
49 mismatch = 0
45 if len(output_l) != len(out_l):
50 if len(output_l) != len(out_l):
46 message = ("Mismatch in number of lines\n\n"
51 message = ("Mismatch in number of lines\n\n"
47 "Expected:\n"
52 "Expected:\n"
48 "~~~~~~~~~\n"
53 "~~~~~~~~~\n"
49 "%s\n\n"
54 "%s\n\n"
50 "Got:\n"
55 "Got:\n"
51 "~~~~~~~~~\n"
56 "~~~~~~~~~\n"
52 "%s"
57 "%s"
53 ) % ("\n".join(output_l), "\n".join(out_l))
58 ) % ("\n".join(output_l), "\n".join(out_l))
54 self.fail(message)
59 self.fail(message)
55 for n in range(len(output_l)):
60 for n in range(len(output_l)):
56 # Do a line-by-line comparison
61 # Do a line-by-line comparison
57 ol1 = output_l[n].strip()
62 ol1 = output_l[n].strip()
58 ol2 = out_l[n].strip()
63 ol2 = out_l[n].strip()
59 if not re.match(ol1,ol2):
64 if not re.match(ol1,ol2):
60 mismatch += 1
65 mismatch += 1
61 if VERBOSE:
66 if VERBOSE:
62 print('<<< line %s does not match:' % n)
67 print('<<< line %s does not match:' % n)
63 print(repr(ol1))
68 print(repr(ol1))
64 print(repr(ol2))
69 print(repr(ol2))
65 print('>>>')
70 print('>>>')
66 self.assertTrue(mismatch==0,'Number of mismatched lines: %s' %
71 self.assertTrue(mismatch==0,'Number of mismatched lines: %s' %
67 mismatch)
72 mismatch)
68
73
69 @decorators.skip_if_no_x11
74 @decorators.skip_if_no_x11
70 @decorators.skipif_not_matplotlib
75 @decorators.skipif_not_matplotlib
71 @decorators.skipif(pylab_not_importable, "Likely a run without X.")
76 @decorators.skipif(pylab_not_importable, "Likely a run without X.")
72 def test_pylab_import_all_enabled(self):
77 def test_pylab_import_all_enabled(self):
73 "Verify that plot is available when pylab_import_all = True"
78 "Verify that plot is available when pylab_import_all = True"
74 source = """
79 source = """
75 from IPython.config.application import Application
80 from IPython.config.application import Application
76 app = Application.instance()
81 app = Application.instance()
77 app.pylab_import_all = True
82 app.pylab_import_all = True
78 pylab
83 pylab
79 ip=get_ipython()
84 ip=get_ipython()
80 'plot' in ip.user_ns
85 'plot' in ip.user_ns
81 """
86 """
82 output = """
87 output = """
83 In \[1\]: from IPython\.config\.application import Application
88 In \[1\]: from IPython\.config\.application import Application
84 In \[2\]: app = Application\.instance\(\)
89 In \[2\]: app = Application\.instance\(\)
85 In \[3\]: app\.pylab_import_all = True
90 In \[3\]: app\.pylab_import_all = True
86 In \[4\]: pylab
91 In \[4\]: pylab
87 ^Using matplotlib backend:
92 ^Using matplotlib backend:
88 Populating the interactive namespace from numpy and matplotlib
93 Populating the interactive namespace from numpy and matplotlib
89 In \[5\]: ip=get_ipython\(\)
94 In \[5\]: ip=get_ipython\(\)
90 In \[6\]: \'plot\' in ip\.user_ns
95 In \[6\]: \'plot\' in ip\.user_ns
91 Out\[6\]: True
96 Out\[6\]: True
92 """
97 """
93 runner = irunner.IPythonRunner(out=self.out)
98 runner = irunner.IPythonRunner(out=self.out)
94 self._test_runner(runner,source,output)
99 self._test_runner(runner,source,output)
95
100
96 @decorators.skip_if_no_x11
101 @decorators.skip_if_no_x11
97 @decorators.skipif_not_matplotlib
102 @decorators.skipif_not_matplotlib
98 @decorators.skipif(pylab_not_importable, "Likely a run without X.")
103 @decorators.skipif(pylab_not_importable, "Likely a run without X.")
99 def test_pylab_import_all_disabled(self):
104 def test_pylab_import_all_disabled(self):
100 "Verify that plot is not available when pylab_import_all = False"
105 "Verify that plot is not available when pylab_import_all = False"
101 source = """
106 source = """
102 from IPython.config.application import Application
107 from IPython.config.application import Application
103 app = Application.instance()
108 app = Application.instance()
104 app.pylab_import_all = False
109 app.pylab_import_all = False
105 pylab
110 pylab
106 ip=get_ipython()
111 ip=get_ipython()
107 'plot' in ip.user_ns
112 'plot' in ip.user_ns
108 """
113 """
109 output = """
114 output = """
110 In \[1\]: from IPython\.config\.application import Application
115 In \[1\]: from IPython\.config\.application import Application
111 In \[2\]: app = Application\.instance\(\)
116 In \[2\]: app = Application\.instance\(\)
112 In \[3\]: app\.pylab_import_all = False
117 In \[3\]: app\.pylab_import_all = False
113 In \[4\]: pylab
118 In \[4\]: pylab
114 ^Using matplotlib backend:
119 ^Using matplotlib backend:
115 Populating the interactive namespace from numpy and matplotlib
120 Populating the interactive namespace from numpy and matplotlib
116 In \[5\]: ip=get_ipython\(\)
121 In \[5\]: ip=get_ipython\(\)
117 In \[6\]: \'plot\' in ip\.user_ns
122 In \[6\]: \'plot\' in ip\.user_ns
118 Out\[6\]: False
123 Out\[6\]: False
119 """
124 """
120 runner = irunner.IPythonRunner(out=self.out)
125 runner = irunner.IPythonRunner(out=self.out)
121 self._test_runner(runner,source,output)
126 self._test_runner(runner,source,output)
@@ -1,51 +1,56 b''
1 """
1 """
2 Module with tests for debug
2 Module with tests for debug
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import sys
17 import sys
18 from io import StringIO
19
18
20 from ...tests.base import TestsBase
19 from ...tests.base import TestsBase
21 from ..debug import DebugWriter
20 from ..debug import DebugWriter
21 from IPython.utils.py3compat import PY3
22
23 if PY3:
24 from io import StringIO
25 else:
26 from StringIO import StringIO
22
27
23
28
24 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
25 # Class
30 # Class
26 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
27
32
28 class TestDebug(TestsBase):
33 class TestDebug(TestsBase):
29 """Contains test functions for debug.py"""
34 """Contains test functions for debug.py"""
30
35
31 def test_output(self):
36 def test_output(self):
32 """Test debug writer output."""
37 """Test debug writer output."""
33
38
34 # Capture the stdout. Remember original.
39 # Capture the stdout. Remember original.
35 stdout = sys.stdout
40 stdout = sys.stdout
36 stream = StringIO()
41 stream = StringIO()
37 sys.stdout = stream
42 sys.stdout = stream
38
43
39 # Create stdout writer, get output
44 # Create stdout writer, get output
40 writer = DebugWriter()
45 writer = DebugWriter()
41 writer.write('aaa', {'outputs': {'bbb': 'ccc'}})
46 writer.write('aaa', {'outputs': {'bbb': 'ccc'}})
42 output = stream.getvalue()
47 output = stream.getvalue()
43
48
44 # Check output. Make sure resources dictionary is dumped, but nothing
49 # Check output. Make sure resources dictionary is dumped, but nothing
45 # else.
50 # else.
46 assert 'aaa' not in output
51 assert 'aaa' not in output
47 assert 'bbb' in output
52 assert 'bbb' in output
48 assert 'ccc' in output
53 assert 'ccc' in output
49
54
50 # Revert stdout
55 # Revert stdout
51 sys.stdout = stdout No newline at end of file
56 sys.stdout = stdout
@@ -1,159 +1,164 b''
1 """
1 """
2 Module with tests for files
2 Module with tests for files
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import sys
17 import sys
18 import os
18 import os
19 from io import StringIO
20
19
21 from ...tests.base import TestsBase
20 from ...tests.base import TestsBase
22 from ..files import FilesWriter
21 from ..files import FilesWriter
22 from IPython.utils.py3compat import PY3
23
24 if PY3:
25 from io import StringIO
26 else:
27 from StringIO import StringIO
23
28
24
29
25 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
26 # Class
31 # Class
27 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
28
33
29 class Testfiles(TestsBase):
34 class Testfiles(TestsBase):
30 """Contains test functions for files.py"""
35 """Contains test functions for files.py"""
31
36
32 def test_basic_output(self):
37 def test_basic_output(self):
33 """Is FilesWriter basic output correct?"""
38 """Is FilesWriter basic output correct?"""
34
39
35 # Work in a temporary directory.
40 # Work in a temporary directory.
36 with self.create_temp_cwd():
41 with self.create_temp_cwd():
37
42
38 # Create the resoruces dictionary
43 # Create the resoruces dictionary
39 res = {}
44 res = {}
40
45
41 # Create files writer, test output
46 # Create files writer, test output
42 writer = FilesWriter()
47 writer = FilesWriter()
43 writer.write(u'y', res, notebook_name="z")
48 writer.write(u'y', res, notebook_name="z")
44
49
45 # Check the output of the file
50 # Check the output of the file
46 with open('z', 'r') as f:
51 with open('z', 'r') as f:
47 output = f.read()
52 output = f.read()
48 self.assertEqual(output, u'y')
53 self.assertEqual(output, u'y')
49
54
50 def test_ext(self):
55 def test_ext(self):
51 """Does the FilesWriter add the correct extension to the output?"""
56 """Does the FilesWriter add the correct extension to the output?"""
52
57
53 # Work in a temporary directory.
58 # Work in a temporary directory.
54 with self.create_temp_cwd():
59 with self.create_temp_cwd():
55
60
56 # Create the resoruces dictionary
61 # Create the resoruces dictionary
57 res = {'output_extension': 'txt'}
62 res = {'output_extension': 'txt'}
58
63
59 # Create files writer, test output
64 # Create files writer, test output
60 writer = FilesWriter()
65 writer = FilesWriter()
61 writer.write(u'y', res, notebook_name="z")
66 writer.write(u'y', res, notebook_name="z")
62
67
63 # Check the output of the file
68 # Check the output of the file
64 assert os.path.isfile('z.txt')
69 assert os.path.isfile('z.txt')
65 with open('z.txt', 'r') as f:
70 with open('z.txt', 'r') as f:
66 output = f.read()
71 output = f.read()
67 self.assertEqual(output, u'y')
72 self.assertEqual(output, u'y')
68
73
69
74
70 def test_extract(self):
75 def test_extract(self):
71 """Can FilesWriter write extracted figures correctly?"""
76 """Can FilesWriter write extracted figures correctly?"""
72
77
73 # Work in a temporary directory.
78 # Work in a temporary directory.
74 with self.create_temp_cwd():
79 with self.create_temp_cwd():
75
80
76 # Create the resoruces dictionary
81 # Create the resoruces dictionary
77 res = {'outputs': {os.path.join('z_files', 'a'): b'b'}}
82 res = {'outputs': {os.path.join('z_files', 'a'): b'b'}}
78
83
79 # Create files writer, test output
84 # Create files writer, test output
80 writer = FilesWriter()
85 writer = FilesWriter()
81 writer.write(u'y', res, notebook_name="z")
86 writer.write(u'y', res, notebook_name="z")
82
87
83 # Check the output of the file
88 # Check the output of the file
84 with open('z', 'r') as f:
89 with open('z', 'r') as f:
85 output = f.read()
90 output = f.read()
86 self.assertEqual(output, u'y')
91 self.assertEqual(output, u'y')
87
92
88 # Check the output of the extracted file
93 # Check the output of the extracted file
89 extracted_file_dest = os.path.join('z_files', 'a')
94 extracted_file_dest = os.path.join('z_files', 'a')
90 assert os.path.isfile(extracted_file_dest)
95 assert os.path.isfile(extracted_file_dest)
91 with open(extracted_file_dest, 'r') as f:
96 with open(extracted_file_dest, 'r') as f:
92 output = f.read()
97 output = f.read()
93 self.assertEqual(output, 'b')
98 self.assertEqual(output, 'b')
94
99
95
100
96 def test_builddir(self):
101 def test_builddir(self):
97 """Can FilesWriter write to a build dir correctly?"""
102 """Can FilesWriter write to a build dir correctly?"""
98
103
99 # Work in a temporary directory.
104 # Work in a temporary directory.
100 with self.create_temp_cwd():
105 with self.create_temp_cwd():
101
106
102 # Create the resoruces dictionary
107 # Create the resoruces dictionary
103 res = {'outputs': {os.path.join('z_files', 'a'): b'b'}}
108 res = {'outputs': {os.path.join('z_files', 'a'): b'b'}}
104
109
105 # Create files writer, test output
110 # Create files writer, test output
106 writer = FilesWriter()
111 writer = FilesWriter()
107 writer.build_directory = u'build'
112 writer.build_directory = u'build'
108 writer.write(u'y', res, notebook_name="z")
113 writer.write(u'y', res, notebook_name="z")
109
114
110 # Check the output of the file
115 # Check the output of the file
111 assert os.path.isdir(writer.build_directory)
116 assert os.path.isdir(writer.build_directory)
112 dest = os.path.join(writer.build_directory, 'z')
117 dest = os.path.join(writer.build_directory, 'z')
113 with open(dest, 'r') as f:
118 with open(dest, 'r') as f:
114 output = f.read()
119 output = f.read()
115 self.assertEqual(output, u'y')
120 self.assertEqual(output, u'y')
116
121
117 # Check the output of the extracted file
122 # Check the output of the extracted file
118 extracted_file_dest = os.path.join(writer.build_directory, 'z_files', 'a')
123 extracted_file_dest = os.path.join(writer.build_directory, 'z_files', 'a')
119 assert os.path.isfile(extracted_file_dest)
124 assert os.path.isfile(extracted_file_dest)
120 with open(extracted_file_dest, 'r') as f:
125 with open(extracted_file_dest, 'r') as f:
121 output = f.read()
126 output = f.read()
122 self.assertEqual(output, 'b')
127 self.assertEqual(output, 'b')
123
128
124
129
125 def test_links(self):
130 def test_links(self):
126 """Can the FilesWriter handle linked files correctly?"""
131 """Can the FilesWriter handle linked files correctly?"""
127
132
128 # Work in a temporary directory.
133 # Work in a temporary directory.
129 with self.create_temp_cwd():
134 with self.create_temp_cwd():
130
135
131 # Create test file
136 # Create test file
132 os.mkdir('sub')
137 os.mkdir('sub')
133 with open(os.path.join('sub', 'c'), 'w') as f:
138 with open(os.path.join('sub', 'c'), 'w') as f:
134 f.write('d')
139 f.write('d')
135
140
136 # Create the resoruces dictionary
141 # Create the resoruces dictionary
137 res = {}
142 res = {}
138
143
139 # Create files writer, test output
144 # Create files writer, test output
140 writer = FilesWriter()
145 writer = FilesWriter()
141 writer.files = [os.path.join('sub', 'c')]
146 writer.files = [os.path.join('sub', 'c')]
142 writer.build_directory = u'build'
147 writer.build_directory = u'build'
143 writer.write(u'y', res, notebook_name="z")
148 writer.write(u'y', res, notebook_name="z")
144
149
145 # Check the output of the file
150 # Check the output of the file
146 assert os.path.isdir(writer.build_directory)
151 assert os.path.isdir(writer.build_directory)
147 dest = os.path.join(writer.build_directory, 'z')
152 dest = os.path.join(writer.build_directory, 'z')
148 with open(dest, 'r') as f:
153 with open(dest, 'r') as f:
149 output = f.read()
154 output = f.read()
150 self.assertEqual(output, u'y')
155 self.assertEqual(output, u'y')
151
156
152 # Check to make sure the linked file was copied
157 # Check to make sure the linked file was copied
153 path = os.path.join(writer.build_directory, 'sub')
158 path = os.path.join(writer.build_directory, 'sub')
154 assert os.path.isdir(path)
159 assert os.path.isdir(path)
155 dest = os.path.join(path, 'c')
160 dest = os.path.join(path, 'c')
156 assert os.path.isfile(dest)
161 assert os.path.isfile(dest)
157 with open(dest, 'r') as f:
162 with open(dest, 'r') as f:
158 output = f.read()
163 output = f.read()
159 self.assertEqual(output, 'd')
164 self.assertEqual(output, 'd')
@@ -1,46 +1,51 b''
1 """
1 """
2 Module with tests for stdout
2 Module with tests for stdout
3 """
3 """
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import sys
17 import sys
18 from io import StringIO
19
18
20 from ...tests.base import TestsBase
19 from ...tests.base import TestsBase
21 from ..stdout import StdoutWriter
20 from ..stdout import StdoutWriter
21 from IPython.utils.py3compat import PY3
22
23 if PY3:
24 from io import StringIO
25 else:
26 from StringIO import StringIO
22
27
23
28
24 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
25 # Class
30 # Class
26 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
27
32
28 class TestStdout(TestsBase):
33 class TestStdout(TestsBase):
29 """Contains test functions for stdout.py"""
34 """Contains test functions for stdout.py"""
30
35
31 def test_output(self):
36 def test_output(self):
32 """Test stdout writer output."""
37 """Test stdout writer output."""
33
38
34 # Capture the stdout. Remember original.
39 # Capture the stdout. Remember original.
35 stdout = sys.stdout
40 stdout = sys.stdout
36 stream = StringIO()
41 stream = StringIO()
37 sys.stdout = stream
42 sys.stdout = stream
38
43
39 # Create stdout writer, test output
44 # Create stdout writer, test output
40 writer = StdoutWriter()
45 writer = StdoutWriter()
41 writer.write('a', {'b': 'c'})
46 writer.write('a', {'b': 'c'})
42 output = stream.getvalue()
47 output = stream.getvalue()
43 self.fuzzy_compare(output, 'a')
48 self.fuzzy_compare(output, 'a')
44
49
45 # Revert stdout
50 # Revert stdout
46 sys.stdout = stdout No newline at end of file
51 sys.stdout = stdout
@@ -1,193 +1,192 b''
1 """base class for parallel client tests
1 """base class for parallel client tests
2
2
3 Authors:
3 Authors:
4
4
5 * Min RK
5 * Min RK
6 """
6 """
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2011 The IPython Development Team
9 # Copyright (C) 2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18 import time
18 import time
19 from io import StringIO
20
19
21 from nose import SkipTest
20 from nose import SkipTest
22
21
23 import zmq
22 import zmq
24 from zmq.tests import BaseZMQTestCase
23 from zmq.tests import BaseZMQTestCase
25
24
26 from IPython.external.decorator import decorator
25 from IPython.external.decorator import decorator
27
26
28 from IPython.parallel import error
27 from IPython.parallel import error
29 from IPython.parallel import Client
28 from IPython.parallel import Client
30
29
31 from IPython.parallel.tests import launchers, add_engines
30 from IPython.parallel.tests import launchers, add_engines
32
31
33 # simple tasks for use in apply tests
32 # simple tasks for use in apply tests
34
33
35 def segfault():
34 def segfault():
36 """this will segfault"""
35 """this will segfault"""
37 import ctypes
36 import ctypes
38 ctypes.memset(-1,0,1)
37 ctypes.memset(-1,0,1)
39
38
40 def crash():
39 def crash():
41 """from stdlib crashers in the test suite"""
40 """from stdlib crashers in the test suite"""
42 import types
41 import types
43 if sys.platform.startswith('win'):
42 if sys.platform.startswith('win'):
44 import ctypes
43 import ctypes
45 ctypes.windll.kernel32.SetErrorMode(0x0002);
44 ctypes.windll.kernel32.SetErrorMode(0x0002);
46 args = [ 0, 0, 0, 0, b'\x04\x71\x00\x00', (), (), (), '', '', 1, b'']
45 args = [ 0, 0, 0, 0, b'\x04\x71\x00\x00', (), (), (), '', '', 1, b'']
47 if sys.version_info[0] >= 3:
46 if sys.version_info[0] >= 3:
48 # Python3 adds 'kwonlyargcount' as the second argument to Code
47 # Python3 adds 'kwonlyargcount' as the second argument to Code
49 args.insert(1, 0)
48 args.insert(1, 0)
50
49
51 co = types.CodeType(*args)
50 co = types.CodeType(*args)
52 exec(co)
51 exec(co)
53
52
54 def wait(n):
53 def wait(n):
55 """sleep for a time"""
54 """sleep for a time"""
56 import time
55 import time
57 time.sleep(n)
56 time.sleep(n)
58 return n
57 return n
59
58
60 def raiser(eclass):
59 def raiser(eclass):
61 """raise an exception"""
60 """raise an exception"""
62 raise eclass()
61 raise eclass()
63
62
64 def generate_output():
63 def generate_output():
65 """function for testing output
64 """function for testing output
66
65
67 publishes two outputs of each type, and returns
66 publishes two outputs of each type, and returns
68 a rich displayable object.
67 a rich displayable object.
69 """
68 """
70
69
71 import sys
70 import sys
72 from IPython.core.display import display, HTML, Math
71 from IPython.core.display import display, HTML, Math
73
72
74 print("stdout")
73 print("stdout")
75 print("stderr", file=sys.stderr)
74 print("stderr", file=sys.stderr)
76
75
77 display(HTML("<b>HTML</b>"))
76 display(HTML("<b>HTML</b>"))
78
77
79 print("stdout2")
78 print("stdout2")
80 print("stderr2", file=sys.stderr)
79 print("stderr2", file=sys.stderr)
81
80
82 display(Math(r"\alpha=\beta"))
81 display(Math(r"\alpha=\beta"))
83
82
84 return Math("42")
83 return Math("42")
85
84
86 # test decorator for skipping tests when libraries are unavailable
85 # test decorator for skipping tests when libraries are unavailable
87 def skip_without(*names):
86 def skip_without(*names):
88 """skip a test if some names are not importable"""
87 """skip a test if some names are not importable"""
89 @decorator
88 @decorator
90 def skip_without_names(f, *args, **kwargs):
89 def skip_without_names(f, *args, **kwargs):
91 """decorator to skip tests in the absence of numpy."""
90 """decorator to skip tests in the absence of numpy."""
92 for name in names:
91 for name in names:
93 try:
92 try:
94 __import__(name)
93 __import__(name)
95 except ImportError:
94 except ImportError:
96 raise SkipTest
95 raise SkipTest
97 return f(*args, **kwargs)
96 return f(*args, **kwargs)
98 return skip_without_names
97 return skip_without_names
99
98
100 #-------------------------------------------------------------------------------
99 #-------------------------------------------------------------------------------
101 # Classes
100 # Classes
102 #-------------------------------------------------------------------------------
101 #-------------------------------------------------------------------------------
103
102
104
103
105 class ClusterTestCase(BaseZMQTestCase):
104 class ClusterTestCase(BaseZMQTestCase):
106 timeout = 10
105 timeout = 10
107
106
108 def add_engines(self, n=1, block=True):
107 def add_engines(self, n=1, block=True):
109 """add multiple engines to our cluster"""
108 """add multiple engines to our cluster"""
110 self.engines.extend(add_engines(n))
109 self.engines.extend(add_engines(n))
111 if block:
110 if block:
112 self.wait_on_engines()
111 self.wait_on_engines()
113
112
114 def minimum_engines(self, n=1, block=True):
113 def minimum_engines(self, n=1, block=True):
115 """add engines until there are at least n connected"""
114 """add engines until there are at least n connected"""
116 self.engines.extend(add_engines(n, total=True))
115 self.engines.extend(add_engines(n, total=True))
117 if block:
116 if block:
118 self.wait_on_engines()
117 self.wait_on_engines()
119
118
120
119
121 def wait_on_engines(self, timeout=5):
120 def wait_on_engines(self, timeout=5):
122 """wait for our engines to connect."""
121 """wait for our engines to connect."""
123 n = len(self.engines)+self.base_engine_count
122 n = len(self.engines)+self.base_engine_count
124 tic = time.time()
123 tic = time.time()
125 while time.time()-tic < timeout and len(self.client.ids) < n:
124 while time.time()-tic < timeout and len(self.client.ids) < n:
126 time.sleep(0.1)
125 time.sleep(0.1)
127
126
128 assert not len(self.client.ids) < n, "waiting for engines timed out"
127 assert not len(self.client.ids) < n, "waiting for engines timed out"
129
128
130 def client_wait(self, client, jobs=None, timeout=-1):
129 def client_wait(self, client, jobs=None, timeout=-1):
131 """my wait wrapper, sets a default finite timeout to avoid hangs"""
130 """my wait wrapper, sets a default finite timeout to avoid hangs"""
132 if timeout < 0:
131 if timeout < 0:
133 timeout = self.timeout
132 timeout = self.timeout
134 return Client.wait(client, jobs, timeout)
133 return Client.wait(client, jobs, timeout)
135
134
136 def connect_client(self):
135 def connect_client(self):
137 """connect a client with my Context, and track its sockets for cleanup"""
136 """connect a client with my Context, and track its sockets for cleanup"""
138 c = Client(profile='iptest', context=self.context)
137 c = Client(profile='iptest', context=self.context)
139 c.wait = lambda *a, **kw: self.client_wait(c, *a, **kw)
138 c.wait = lambda *a, **kw: self.client_wait(c, *a, **kw)
140
139
141 for name in filter(lambda n:n.endswith('socket'), dir(c)):
140 for name in filter(lambda n:n.endswith('socket'), dir(c)):
142 s = getattr(c, name)
141 s = getattr(c, name)
143 s.setsockopt(zmq.LINGER, 0)
142 s.setsockopt(zmq.LINGER, 0)
144 self.sockets.append(s)
143 self.sockets.append(s)
145 return c
144 return c
146
145
147 def assertRaisesRemote(self, etype, f, *args, **kwargs):
146 def assertRaisesRemote(self, etype, f, *args, **kwargs):
148 try:
147 try:
149 try:
148 try:
150 f(*args, **kwargs)
149 f(*args, **kwargs)
151 except error.CompositeError as e:
150 except error.CompositeError as e:
152 e.raise_exception()
151 e.raise_exception()
153 except error.RemoteError as e:
152 except error.RemoteError as e:
154 self.assertEqual(etype.__name__, e.ename, "Should have raised %r, but raised %r"%(etype.__name__, e.ename))
153 self.assertEqual(etype.__name__, e.ename, "Should have raised %r, but raised %r"%(etype.__name__, e.ename))
155 else:
154 else:
156 self.fail("should have raised a RemoteError")
155 self.fail("should have raised a RemoteError")
157
156
158 def _wait_for(self, f, timeout=10):
157 def _wait_for(self, f, timeout=10):
159 """wait for a condition"""
158 """wait for a condition"""
160 tic = time.time()
159 tic = time.time()
161 while time.time() <= tic + timeout:
160 while time.time() <= tic + timeout:
162 if f():
161 if f():
163 return
162 return
164 time.sleep(0.1)
163 time.sleep(0.1)
165 self.client.spin()
164 self.client.spin()
166 if not f():
165 if not f():
167 print("Warning: Awaited condition never arrived")
166 print("Warning: Awaited condition never arrived")
168
167
169 def setUp(self):
168 def setUp(self):
170 BaseZMQTestCase.setUp(self)
169 BaseZMQTestCase.setUp(self)
171 self.client = self.connect_client()
170 self.client = self.connect_client()
172 # start every test with clean engine namespaces:
171 # start every test with clean engine namespaces:
173 self.client.clear(block=True)
172 self.client.clear(block=True)
174 self.base_engine_count=len(self.client.ids)
173 self.base_engine_count=len(self.client.ids)
175 self.engines=[]
174 self.engines=[]
176
175
177 def tearDown(self):
176 def tearDown(self):
178 # self.client.clear(block=True)
177 # self.client.clear(block=True)
179 # close fds:
178 # close fds:
180 for e in filter(lambda e: e.poll() is not None, launchers):
179 for e in filter(lambda e: e.poll() is not None, launchers):
181 launchers.remove(e)
180 launchers.remove(e)
182
181
183 # allow flushing of incoming messages to prevent crash on socket close
182 # allow flushing of incoming messages to prevent crash on socket close
184 self.client.wait(timeout=2)
183 self.client.wait(timeout=2)
185 # time.sleep(2)
184 # time.sleep(2)
186 self.client.spin()
185 self.client.spin()
187 self.client.close()
186 self.client.close()
188 BaseZMQTestCase.tearDown(self)
187 BaseZMQTestCase.tearDown(self)
189 # this will be redundant when pyzmq merges PR #88
188 # this will be redundant when pyzmq merges PR #88
190 # self.context.term()
189 # self.context.term()
191 # print tempfile.TemporaryFile().fileno(),
190 # print tempfile.TemporaryFile().fileno(),
192 # sys.stdout.flush()
191 # sys.stdout.flush()
193
192
@@ -1,830 +1,835 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Sphinx directive to support embedded IPython code.
2 """Sphinx directive to support embedded IPython code.
3
3
4 This directive allows pasting of entire interactive IPython sessions, prompts
4 This directive allows pasting of entire interactive IPython sessions, prompts
5 and all, and their code will actually get re-executed at doc build time, with
5 and all, and their code will actually get re-executed at doc build time, with
6 all prompts renumbered sequentially. It also allows you to input code as a pure
6 all prompts renumbered sequentially. It also allows you to input code as a pure
7 python input by giving the argument python to the directive. The output looks
7 python input by giving the argument python to the directive. The output looks
8 like an interactive ipython section.
8 like an interactive ipython section.
9
9
10 To enable this directive, simply list it in your Sphinx ``conf.py`` file
10 To enable this directive, simply list it in your Sphinx ``conf.py`` file
11 (making sure the directory where you placed it is visible to sphinx, as is
11 (making sure the directory where you placed it is visible to sphinx, as is
12 needed for all Sphinx directives).
12 needed for all Sphinx directives).
13
13
14 By default this directive assumes that your prompts are unchanged IPython ones,
14 By default this directive assumes that your prompts are unchanged IPython ones,
15 but this can be customized. The configurable options that can be placed in
15 but this can be customized. The configurable options that can be placed in
16 conf.py are
16 conf.py are
17
17
18 ipython_savefig_dir:
18 ipython_savefig_dir:
19 The directory in which to save the figures. This is relative to the
19 The directory in which to save the figures. This is relative to the
20 Sphinx source directory. The default is `html_static_path`.
20 Sphinx source directory. The default is `html_static_path`.
21 ipython_rgxin:
21 ipython_rgxin:
22 The compiled regular expression to denote the start of IPython input
22 The compiled regular expression to denote the start of IPython input
23 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
23 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
24 shouldn't need to change this.
24 shouldn't need to change this.
25 ipython_rgxout:
25 ipython_rgxout:
26 The compiled regular expression to denote the start of IPython output
26 The compiled regular expression to denote the start of IPython output
27 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
27 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
28 shouldn't need to change this.
28 shouldn't need to change this.
29 ipython_promptin:
29 ipython_promptin:
30 The string to represent the IPython input prompt in the generated ReST.
30 The string to represent the IPython input prompt in the generated ReST.
31 The default is 'In [%d]:'. This expects that the line numbers are used
31 The default is 'In [%d]:'. This expects that the line numbers are used
32 in the prompt.
32 in the prompt.
33 ipython_promptout:
33 ipython_promptout:
34
34
35 The string to represent the IPython prompt in the generated ReST. The
35 The string to represent the IPython prompt in the generated ReST. The
36 default is 'Out [%d]:'. This expects that the line numbers are used
36 default is 'Out [%d]:'. This expects that the line numbers are used
37 in the prompt.
37 in the prompt.
38
38
39 ToDo
39 ToDo
40 ----
40 ----
41
41
42 - Turn the ad-hoc test() function into a real test suite.
42 - Turn the ad-hoc test() function into a real test suite.
43 - Break up ipython-specific functionality from matplotlib stuff into better
43 - Break up ipython-specific functionality from matplotlib stuff into better
44 separated code.
44 separated code.
45
45
46 Authors
46 Authors
47 -------
47 -------
48
48
49 - John D Hunter: orignal author.
49 - John D Hunter: orignal author.
50 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
50 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
51 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
51 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
52 - Skipper Seabold, refactoring, cleanups, pure python addition
52 - Skipper Seabold, refactoring, cleanups, pure python addition
53 """
53 """
54 from __future__ import print_function
54 from __future__ import print_function
55
55
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57 # Imports
57 # Imports
58 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
59
59
60 # Stdlib
60 # Stdlib
61 import io
62 import os
61 import os
63 import re
62 import re
64 import sys
63 import sys
65 import tempfile
64 import tempfile
66 import ast
65 import ast
67
66
68 # To keep compatibility with various python versions
67 # To keep compatibility with various python versions
69 try:
68 try:
70 from hashlib import md5
69 from hashlib import md5
71 except ImportError:
70 except ImportError:
72 from md5 import md5
71 from md5 import md5
73
72
74 # Third-party
73 # Third-party
75 import matplotlib
74 import matplotlib
76 import sphinx
75 import sphinx
77 from docutils.parsers.rst import directives
76 from docutils.parsers.rst import directives
78 from docutils import nodes
77 from docutils import nodes
79 from sphinx.util.compat import Directive
78 from sphinx.util.compat import Directive
80
79
81 matplotlib.use('Agg')
80 matplotlib.use('Agg')
82
81
83 # Our own
82 # Our own
84 from IPython import Config, InteractiveShell
83 from IPython import Config, InteractiveShell
85 from IPython.core.profiledir import ProfileDir
84 from IPython.core.profiledir import ProfileDir
86 from IPython.utils import io
85 from IPython.utils import io
86 from IPython.utils.py3compat import PY3
87
88 if PY3:
89 from io import StringIO
90 else:
91 from StringIO import StringIO
87
92
88 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
89 # Globals
94 # Globals
90 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
91 # for tokenizing blocks
96 # for tokenizing blocks
92 COMMENT, INPUT, OUTPUT = range(3)
97 COMMENT, INPUT, OUTPUT = range(3)
93
98
94 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
95 # Functions and class declarations
100 # Functions and class declarations
96 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
97 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
102 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
98 """
103 """
99 part is a string of ipython text, comprised of at most one
104 part is a string of ipython text, comprised of at most one
100 input, one ouput, comments, and blank lines. The block parser
105 input, one ouput, comments, and blank lines. The block parser
101 parses the text into a list of::
106 parses the text into a list of::
102
107
103 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
108 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
104
109
105 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
110 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
106 data is, depending on the type of token::
111 data is, depending on the type of token::
107
112
108 COMMENT : the comment string
113 COMMENT : the comment string
109
114
110 INPUT: the (DECORATOR, INPUT_LINE, REST) where
115 INPUT: the (DECORATOR, INPUT_LINE, REST) where
111 DECORATOR: the input decorator (or None)
116 DECORATOR: the input decorator (or None)
112 INPUT_LINE: the input as string (possibly multi-line)
117 INPUT_LINE: the input as string (possibly multi-line)
113 REST : any stdout generated by the input line (not OUTPUT)
118 REST : any stdout generated by the input line (not OUTPUT)
114
119
115
120
116 OUTPUT: the output string, possibly multi-line
121 OUTPUT: the output string, possibly multi-line
117 """
122 """
118
123
119 block = []
124 block = []
120 lines = part.split('\n')
125 lines = part.split('\n')
121 N = len(lines)
126 N = len(lines)
122 i = 0
127 i = 0
123 decorator = None
128 decorator = None
124 while 1:
129 while 1:
125
130
126 if i==N:
131 if i==N:
127 # nothing left to parse -- the last line
132 # nothing left to parse -- the last line
128 break
133 break
129
134
130 line = lines[i]
135 line = lines[i]
131 i += 1
136 i += 1
132 line_stripped = line.strip()
137 line_stripped = line.strip()
133 if line_stripped.startswith('#'):
138 if line_stripped.startswith('#'):
134 block.append((COMMENT, line))
139 block.append((COMMENT, line))
135 continue
140 continue
136
141
137 if line_stripped.startswith('@'):
142 if line_stripped.startswith('@'):
138 # we're assuming at most one decorator -- may need to
143 # we're assuming at most one decorator -- may need to
139 # rethink
144 # rethink
140 decorator = line_stripped
145 decorator = line_stripped
141 continue
146 continue
142
147
143 # does this look like an input line?
148 # does this look like an input line?
144 matchin = rgxin.match(line)
149 matchin = rgxin.match(line)
145 if matchin:
150 if matchin:
146 lineno, inputline = int(matchin.group(1)), matchin.group(2)
151 lineno, inputline = int(matchin.group(1)), matchin.group(2)
147
152
148 # the ....: continuation string
153 # the ....: continuation string
149 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
154 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
150 Nc = len(continuation)
155 Nc = len(continuation)
151 # input lines can continue on for more than one line, if
156 # input lines can continue on for more than one line, if
152 # we have a '\' line continuation char or a function call
157 # we have a '\' line continuation char or a function call
153 # echo line 'print'. The input line can only be
158 # echo line 'print'. The input line can only be
154 # terminated by the end of the block or an output line, so
159 # terminated by the end of the block or an output line, so
155 # we parse out the rest of the input line if it is
160 # we parse out the rest of the input line if it is
156 # multiline as well as any echo text
161 # multiline as well as any echo text
157
162
158 rest = []
163 rest = []
159 while i<N:
164 while i<N:
160
165
161 # look ahead; if the next line is blank, or a comment, or
166 # look ahead; if the next line is blank, or a comment, or
162 # an output line, we're done
167 # an output line, we're done
163
168
164 nextline = lines[i]
169 nextline = lines[i]
165 matchout = rgxout.match(nextline)
170 matchout = rgxout.match(nextline)
166 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
171 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
167 if matchout or nextline.startswith('#'):
172 if matchout or nextline.startswith('#'):
168 break
173 break
169 elif nextline.startswith(continuation):
174 elif nextline.startswith(continuation):
170 inputline += '\n' + nextline[Nc:]
175 inputline += '\n' + nextline[Nc:]
171 else:
176 else:
172 rest.append(nextline)
177 rest.append(nextline)
173 i+= 1
178 i+= 1
174
179
175 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
180 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
176 continue
181 continue
177
182
178 # if it looks like an output line grab all the text to the end
183 # if it looks like an output line grab all the text to the end
179 # of the block
184 # of the block
180 matchout = rgxout.match(line)
185 matchout = rgxout.match(line)
181 if matchout:
186 if matchout:
182 lineno, output = int(matchout.group(1)), matchout.group(2)
187 lineno, output = int(matchout.group(1)), matchout.group(2)
183 if i<N-1:
188 if i<N-1:
184 output = '\n'.join([output] + lines[i:])
189 output = '\n'.join([output] + lines[i:])
185
190
186 block.append((OUTPUT, output))
191 block.append((OUTPUT, output))
187 break
192 break
188
193
189 return block
194 return block
190
195
191 class EmbeddedSphinxShell(object):
196 class EmbeddedSphinxShell(object):
192 """An embedded IPython instance to run inside Sphinx"""
197 """An embedded IPython instance to run inside Sphinx"""
193
198
194 def __init__(self):
199 def __init__(self):
195
200
196 self.cout = io.StringIO()
201 self.cout = StringIO()
197
202
198
203
199 # Create config object for IPython
204 # Create config object for IPython
200 config = Config()
205 config = Config()
201 config.Global.display_banner = False
206 config.Global.display_banner = False
202 config.Global.exec_lines = ['import numpy as np',
207 config.Global.exec_lines = ['import numpy as np',
203 'from pylab import *'
208 'from pylab import *'
204 ]
209 ]
205 config.InteractiveShell.autocall = False
210 config.InteractiveShell.autocall = False
206 config.InteractiveShell.autoindent = False
211 config.InteractiveShell.autoindent = False
207 config.InteractiveShell.colors = 'NoColor'
212 config.InteractiveShell.colors = 'NoColor'
208
213
209 # create a profile so instance history isn't saved
214 # create a profile so instance history isn't saved
210 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
215 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
211 profname = 'auto_profile_sphinx_build'
216 profname = 'auto_profile_sphinx_build'
212 pdir = os.path.join(tmp_profile_dir,profname)
217 pdir = os.path.join(tmp_profile_dir,profname)
213 profile = ProfileDir.create_profile_dir(pdir)
218 profile = ProfileDir.create_profile_dir(pdir)
214
219
215 # Create and initialize ipython, but don't start its mainloop
220 # Create and initialize ipython, but don't start its mainloop
216 IP = InteractiveShell.instance(config=config, profile_dir=profile)
221 IP = InteractiveShell.instance(config=config, profile_dir=profile)
217 # io.stdout redirect must be done *after* instantiating InteractiveShell
222 # io.stdout redirect must be done *after* instantiating InteractiveShell
218 io.stdout = self.cout
223 io.stdout = self.cout
219 io.stderr = self.cout
224 io.stderr = self.cout
220
225
221 # For debugging, so we can see normal output, use this:
226 # For debugging, so we can see normal output, use this:
222 #from IPython.utils.io import Tee
227 #from IPython.utils.io import Tee
223 #io.stdout = Tee(self.cout, channel='stdout') # dbg
228 #io.stdout = Tee(self.cout, channel='stdout') # dbg
224 #io.stderr = Tee(self.cout, channel='stderr') # dbg
229 #io.stderr = Tee(self.cout, channel='stderr') # dbg
225
230
226 # Store a few parts of IPython we'll need.
231 # Store a few parts of IPython we'll need.
227 self.IP = IP
232 self.IP = IP
228 self.user_ns = self.IP.user_ns
233 self.user_ns = self.IP.user_ns
229 self.user_global_ns = self.IP.user_global_ns
234 self.user_global_ns = self.IP.user_global_ns
230
235
231 self.input = ''
236 self.input = ''
232 self.output = ''
237 self.output = ''
233
238
234 self.is_verbatim = False
239 self.is_verbatim = False
235 self.is_doctest = False
240 self.is_doctest = False
236 self.is_suppress = False
241 self.is_suppress = False
237
242
238 # on the first call to the savefig decorator, we'll import
243 # on the first call to the savefig decorator, we'll import
239 # pyplot as plt so we can make a call to the plt.gcf().savefig
244 # pyplot as plt so we can make a call to the plt.gcf().savefig
240 self._pyplot_imported = False
245 self._pyplot_imported = False
241
246
242 def clear_cout(self):
247 def clear_cout(self):
243 self.cout.seek(0)
248 self.cout.seek(0)
244 self.cout.truncate(0)
249 self.cout.truncate(0)
245
250
246 def process_input_line(self, line, store_history=True):
251 def process_input_line(self, line, store_history=True):
247 """process the input, capturing stdout"""
252 """process the input, capturing stdout"""
248 #print "input='%s'"%self.input
253 #print "input='%s'"%self.input
249 stdout = sys.stdout
254 stdout = sys.stdout
250 splitter = self.IP.input_splitter
255 splitter = self.IP.input_splitter
251 try:
256 try:
252 sys.stdout = self.cout
257 sys.stdout = self.cout
253 splitter.push(line)
258 splitter.push(line)
254 more = splitter.push_accepts_more()
259 more = splitter.push_accepts_more()
255 if not more:
260 if not more:
256 source_raw = splitter.source_raw_reset()[1]
261 source_raw = splitter.source_raw_reset()[1]
257 self.IP.run_cell(source_raw, store_history=store_history)
262 self.IP.run_cell(source_raw, store_history=store_history)
258 finally:
263 finally:
259 sys.stdout = stdout
264 sys.stdout = stdout
260
265
261 def process_image(self, decorator):
266 def process_image(self, decorator):
262 """
267 """
263 # build out an image directive like
268 # build out an image directive like
264 # .. image:: somefile.png
269 # .. image:: somefile.png
265 # :width 4in
270 # :width 4in
266 #
271 #
267 # from an input like
272 # from an input like
268 # savefig somefile.png width=4in
273 # savefig somefile.png width=4in
269 """
274 """
270 savefig_dir = self.savefig_dir
275 savefig_dir = self.savefig_dir
271 source_dir = self.source_dir
276 source_dir = self.source_dir
272 saveargs = decorator.split(' ')
277 saveargs = decorator.split(' ')
273 filename = saveargs[1]
278 filename = saveargs[1]
274 # insert relative path to image file in source
279 # insert relative path to image file in source
275 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
280 outfile = os.path.relpath(os.path.join(savefig_dir,filename),
276 source_dir)
281 source_dir)
277
282
278 imagerows = ['.. image:: %s'%outfile]
283 imagerows = ['.. image:: %s'%outfile]
279
284
280 for kwarg in saveargs[2:]:
285 for kwarg in saveargs[2:]:
281 arg, val = kwarg.split('=')
286 arg, val = kwarg.split('=')
282 arg = arg.strip()
287 arg = arg.strip()
283 val = val.strip()
288 val = val.strip()
284 imagerows.append(' :%s: %s'%(arg, val))
289 imagerows.append(' :%s: %s'%(arg, val))
285
290
286 image_file = os.path.basename(outfile) # only return file name
291 image_file = os.path.basename(outfile) # only return file name
287 image_directive = '\n'.join(imagerows)
292 image_directive = '\n'.join(imagerows)
288 return image_file, image_directive
293 return image_file, image_directive
289
294
290
295
291 # Callbacks for each type of token
296 # Callbacks for each type of token
292 def process_input(self, data, input_prompt, lineno):
297 def process_input(self, data, input_prompt, lineno):
293 """Process data block for INPUT token."""
298 """Process data block for INPUT token."""
294 decorator, input, rest = data
299 decorator, input, rest = data
295 image_file = None
300 image_file = None
296 image_directive = None
301 image_directive = None
297 #print 'INPUT:', data # dbg
302 #print 'INPUT:', data # dbg
298 is_verbatim = decorator=='@verbatim' or self.is_verbatim
303 is_verbatim = decorator=='@verbatim' or self.is_verbatim
299 is_doctest = decorator=='@doctest' or self.is_doctest
304 is_doctest = decorator=='@doctest' or self.is_doctest
300 is_suppress = decorator=='@suppress' or self.is_suppress
305 is_suppress = decorator=='@suppress' or self.is_suppress
301 is_savefig = decorator is not None and \
306 is_savefig = decorator is not None and \
302 decorator.startswith('@savefig')
307 decorator.startswith('@savefig')
303
308
304 input_lines = input.split('\n')
309 input_lines = input.split('\n')
305 if len(input_lines) > 1:
310 if len(input_lines) > 1:
306 if input_lines[-1] != "":
311 if input_lines[-1] != "":
307 input_lines.append('') # make sure there's a blank line
312 input_lines.append('') # make sure there's a blank line
308 # so splitter buffer gets reset
313 # so splitter buffer gets reset
309
314
310 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
315 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
311 Nc = len(continuation)
316 Nc = len(continuation)
312
317
313 if is_savefig:
318 if is_savefig:
314 image_file, image_directive = self.process_image(decorator)
319 image_file, image_directive = self.process_image(decorator)
315
320
316 ret = []
321 ret = []
317 is_semicolon = False
322 is_semicolon = False
318
323
319 for i, line in enumerate(input_lines):
324 for i, line in enumerate(input_lines):
320 if line.endswith(';'):
325 if line.endswith(';'):
321 is_semicolon = True
326 is_semicolon = True
322
327
323 if i==0:
328 if i==0:
324 # process the first input line
329 # process the first input line
325 if is_verbatim:
330 if is_verbatim:
326 self.process_input_line('')
331 self.process_input_line('')
327 self.IP.execution_count += 1 # increment it anyway
332 self.IP.execution_count += 1 # increment it anyway
328 else:
333 else:
329 # only submit the line in non-verbatim mode
334 # only submit the line in non-verbatim mode
330 self.process_input_line(line, store_history=True)
335 self.process_input_line(line, store_history=True)
331 formatted_line = '%s %s'%(input_prompt, line)
336 formatted_line = '%s %s'%(input_prompt, line)
332 else:
337 else:
333 # process a continuation line
338 # process a continuation line
334 if not is_verbatim:
339 if not is_verbatim:
335 self.process_input_line(line, store_history=True)
340 self.process_input_line(line, store_history=True)
336
341
337 formatted_line = '%s %s'%(continuation, line)
342 formatted_line = '%s %s'%(continuation, line)
338
343
339 if not is_suppress:
344 if not is_suppress:
340 ret.append(formatted_line)
345 ret.append(formatted_line)
341
346
342 if not is_suppress and len(rest.strip()) and is_verbatim:
347 if not is_suppress and len(rest.strip()) and is_verbatim:
343 # the "rest" is the standard output of the
348 # the "rest" is the standard output of the
344 # input, which needs to be added in
349 # input, which needs to be added in
345 # verbatim mode
350 # verbatim mode
346 ret.append(rest)
351 ret.append(rest)
347
352
348 self.cout.seek(0)
353 self.cout.seek(0)
349 output = self.cout.read()
354 output = self.cout.read()
350 if not is_suppress and not is_semicolon:
355 if not is_suppress and not is_semicolon:
351 ret.append(output)
356 ret.append(output)
352 elif is_semicolon: # get spacing right
357 elif is_semicolon: # get spacing right
353 ret.append('')
358 ret.append('')
354
359
355 self.cout.truncate(0)
360 self.cout.truncate(0)
356 return (ret, input_lines, output, is_doctest, image_file,
361 return (ret, input_lines, output, is_doctest, image_file,
357 image_directive)
362 image_directive)
358 #print 'OUTPUT', output # dbg
363 #print 'OUTPUT', output # dbg
359
364
360 def process_output(self, data, output_prompt,
365 def process_output(self, data, output_prompt,
361 input_lines, output, is_doctest, image_file):
366 input_lines, output, is_doctest, image_file):
362 """Process data block for OUTPUT token."""
367 """Process data block for OUTPUT token."""
363 if is_doctest:
368 if is_doctest:
364 submitted = data.strip()
369 submitted = data.strip()
365 found = output
370 found = output
366 if found is not None:
371 if found is not None:
367 found = found.strip()
372 found = found.strip()
368
373
369 # XXX - fperez: in 0.11, 'output' never comes with the prompt
374 # XXX - fperez: in 0.11, 'output' never comes with the prompt
370 # in it, just the actual output text. So I think all this code
375 # in it, just the actual output text. So I think all this code
371 # can be nuked...
376 # can be nuked...
372
377
373 # the above comment does not appear to be accurate... (minrk)
378 # the above comment does not appear to be accurate... (minrk)
374
379
375 ind = found.find(output_prompt)
380 ind = found.find(output_prompt)
376 if ind<0:
381 if ind<0:
377 e='output prompt="%s" does not match out line=%s' % \
382 e='output prompt="%s" does not match out line=%s' % \
378 (output_prompt, found)
383 (output_prompt, found)
379 raise RuntimeError(e)
384 raise RuntimeError(e)
380 found = found[len(output_prompt):].strip()
385 found = found[len(output_prompt):].strip()
381
386
382 if found!=submitted:
387 if found!=submitted:
383 e = ('doctest failure for input_lines="%s" with '
388 e = ('doctest failure for input_lines="%s" with '
384 'found_output="%s" and submitted output="%s"' %
389 'found_output="%s" and submitted output="%s"' %
385 (input_lines, found, submitted) )
390 (input_lines, found, submitted) )
386 raise RuntimeError(e)
391 raise RuntimeError(e)
387 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
392 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
388
393
389 def process_comment(self, data):
394 def process_comment(self, data):
390 """Process data fPblock for COMMENT token."""
395 """Process data fPblock for COMMENT token."""
391 if not self.is_suppress:
396 if not self.is_suppress:
392 return [data]
397 return [data]
393
398
394 def save_image(self, image_file):
399 def save_image(self, image_file):
395 """
400 """
396 Saves the image file to disk.
401 Saves the image file to disk.
397 """
402 """
398 self.ensure_pyplot()
403 self.ensure_pyplot()
399 command = 'plt.gcf().savefig("%s")'%image_file
404 command = 'plt.gcf().savefig("%s")'%image_file
400 #print 'SAVEFIG', command # dbg
405 #print 'SAVEFIG', command # dbg
401 self.process_input_line('bookmark ipy_thisdir', store_history=False)
406 self.process_input_line('bookmark ipy_thisdir', store_history=False)
402 self.process_input_line('cd -b ipy_savedir', store_history=False)
407 self.process_input_line('cd -b ipy_savedir', store_history=False)
403 self.process_input_line(command, store_history=False)
408 self.process_input_line(command, store_history=False)
404 self.process_input_line('cd -b ipy_thisdir', store_history=False)
409 self.process_input_line('cd -b ipy_thisdir', store_history=False)
405 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
410 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
406 self.clear_cout()
411 self.clear_cout()
407
412
408
413
409 def process_block(self, block):
414 def process_block(self, block):
410 """
415 """
411 process block from the block_parser and return a list of processed lines
416 process block from the block_parser and return a list of processed lines
412 """
417 """
413 ret = []
418 ret = []
414 output = None
419 output = None
415 input_lines = None
420 input_lines = None
416 lineno = self.IP.execution_count
421 lineno = self.IP.execution_count
417
422
418 input_prompt = self.promptin%lineno
423 input_prompt = self.promptin%lineno
419 output_prompt = self.promptout%lineno
424 output_prompt = self.promptout%lineno
420 image_file = None
425 image_file = None
421 image_directive = None
426 image_directive = None
422
427
423 for token, data in block:
428 for token, data in block:
424 if token==COMMENT:
429 if token==COMMENT:
425 out_data = self.process_comment(data)
430 out_data = self.process_comment(data)
426 elif token==INPUT:
431 elif token==INPUT:
427 (out_data, input_lines, output, is_doctest, image_file,
432 (out_data, input_lines, output, is_doctest, image_file,
428 image_directive) = \
433 image_directive) = \
429 self.process_input(data, input_prompt, lineno)
434 self.process_input(data, input_prompt, lineno)
430 elif token==OUTPUT:
435 elif token==OUTPUT:
431 out_data = \
436 out_data = \
432 self.process_output(data, output_prompt,
437 self.process_output(data, output_prompt,
433 input_lines, output, is_doctest,
438 input_lines, output, is_doctest,
434 image_file)
439 image_file)
435 if out_data:
440 if out_data:
436 ret.extend(out_data)
441 ret.extend(out_data)
437
442
438 # save the image files
443 # save the image files
439 if image_file is not None:
444 if image_file is not None:
440 self.save_image(image_file)
445 self.save_image(image_file)
441
446
442 return ret, image_directive
447 return ret, image_directive
443
448
444 def ensure_pyplot(self):
449 def ensure_pyplot(self):
445 if self._pyplot_imported:
450 if self._pyplot_imported:
446 return
451 return
447 self.process_input_line('import matplotlib.pyplot as plt',
452 self.process_input_line('import matplotlib.pyplot as plt',
448 store_history=False)
453 store_history=False)
449
454
450 def process_pure_python(self, content):
455 def process_pure_python(self, content):
451 """
456 """
452 content is a list of strings. it is unedited directive conent
457 content is a list of strings. it is unedited directive conent
453
458
454 This runs it line by line in the InteractiveShell, prepends
459 This runs it line by line in the InteractiveShell, prepends
455 prompts as needed capturing stderr and stdout, then returns
460 prompts as needed capturing stderr and stdout, then returns
456 the content as a list as if it were ipython code
461 the content as a list as if it were ipython code
457 """
462 """
458 output = []
463 output = []
459 savefig = False # keep up with this to clear figure
464 savefig = False # keep up with this to clear figure
460 multiline = False # to handle line continuation
465 multiline = False # to handle line continuation
461 multiline_start = None
466 multiline_start = None
462 fmtin = self.promptin
467 fmtin = self.promptin
463
468
464 ct = 0
469 ct = 0
465
470
466 for lineno, line in enumerate(content):
471 for lineno, line in enumerate(content):
467
472
468 line_stripped = line.strip()
473 line_stripped = line.strip()
469 if not len(line):
474 if not len(line):
470 output.append(line)
475 output.append(line)
471 continue
476 continue
472
477
473 # handle decorators
478 # handle decorators
474 if line_stripped.startswith('@'):
479 if line_stripped.startswith('@'):
475 output.extend([line])
480 output.extend([line])
476 if 'savefig' in line:
481 if 'savefig' in line:
477 savefig = True # and need to clear figure
482 savefig = True # and need to clear figure
478 continue
483 continue
479
484
480 # handle comments
485 # handle comments
481 if line_stripped.startswith('#'):
486 if line_stripped.startswith('#'):
482 output.extend([line])
487 output.extend([line])
483 continue
488 continue
484
489
485 # deal with lines checking for multiline
490 # deal with lines checking for multiline
486 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
491 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
487 if not multiline:
492 if not multiline:
488 modified = u"%s %s" % (fmtin % ct, line_stripped)
493 modified = u"%s %s" % (fmtin % ct, line_stripped)
489 output.append(modified)
494 output.append(modified)
490 ct += 1
495 ct += 1
491 try:
496 try:
492 ast.parse(line_stripped)
497 ast.parse(line_stripped)
493 output.append(u'')
498 output.append(u'')
494 except Exception: # on a multiline
499 except Exception: # on a multiline
495 multiline = True
500 multiline = True
496 multiline_start = lineno
501 multiline_start = lineno
497 else: # still on a multiline
502 else: # still on a multiline
498 modified = u'%s %s' % (continuation, line)
503 modified = u'%s %s' % (continuation, line)
499 output.append(modified)
504 output.append(modified)
500
505
501 # if the next line is indented, it should be part of multiline
506 # if the next line is indented, it should be part of multiline
502 if len(content) > lineno + 1:
507 if len(content) > lineno + 1:
503 nextline = content[lineno + 1]
508 nextline = content[lineno + 1]
504 if len(nextline) - len(nextline.lstrip()) > 3:
509 if len(nextline) - len(nextline.lstrip()) > 3:
505 continue
510 continue
506 try:
511 try:
507 mod = ast.parse(
512 mod = ast.parse(
508 '\n'.join(content[multiline_start:lineno+1]))
513 '\n'.join(content[multiline_start:lineno+1]))
509 if isinstance(mod.body[0], ast.FunctionDef):
514 if isinstance(mod.body[0], ast.FunctionDef):
510 # check to see if we have the whole function
515 # check to see if we have the whole function
511 for element in mod.body[0].body:
516 for element in mod.body[0].body:
512 if isinstance(element, ast.Return):
517 if isinstance(element, ast.Return):
513 multiline = False
518 multiline = False
514 else:
519 else:
515 output.append(u'')
520 output.append(u'')
516 multiline = False
521 multiline = False
517 except Exception:
522 except Exception:
518 pass
523 pass
519
524
520 if savefig: # clear figure if plotted
525 if savefig: # clear figure if plotted
521 self.ensure_pyplot()
526 self.ensure_pyplot()
522 self.process_input_line('plt.clf()', store_history=False)
527 self.process_input_line('plt.clf()', store_history=False)
523 self.clear_cout()
528 self.clear_cout()
524 savefig = False
529 savefig = False
525
530
526 return output
531 return output
527
532
528 class IPythonDirective(Directive):
533 class IPythonDirective(Directive):
529
534
530 has_content = True
535 has_content = True
531 required_arguments = 0
536 required_arguments = 0
532 optional_arguments = 4 # python, suppress, verbatim, doctest
537 optional_arguments = 4 # python, suppress, verbatim, doctest
533 final_argumuent_whitespace = True
538 final_argumuent_whitespace = True
534 option_spec = { 'python': directives.unchanged,
539 option_spec = { 'python': directives.unchanged,
535 'suppress' : directives.flag,
540 'suppress' : directives.flag,
536 'verbatim' : directives.flag,
541 'verbatim' : directives.flag,
537 'doctest' : directives.flag,
542 'doctest' : directives.flag,
538 }
543 }
539
544
540 shell = None
545 shell = None
541
546
542 seen_docs = set()
547 seen_docs = set()
543
548
544 def get_config_options(self):
549 def get_config_options(self):
545 # contains sphinx configuration variables
550 # contains sphinx configuration variables
546 config = self.state.document.settings.env.config
551 config = self.state.document.settings.env.config
547
552
548 # get config variables to set figure output directory
553 # get config variables to set figure output directory
549 confdir = self.state.document.settings.env.app.confdir
554 confdir = self.state.document.settings.env.app.confdir
550 savefig_dir = config.ipython_savefig_dir
555 savefig_dir = config.ipython_savefig_dir
551 source_dir = os.path.dirname(self.state.document.current_source)
556 source_dir = os.path.dirname(self.state.document.current_source)
552 if savefig_dir is None:
557 if savefig_dir is None:
553 savefig_dir = config.html_static_path
558 savefig_dir = config.html_static_path
554 if isinstance(savefig_dir, list):
559 if isinstance(savefig_dir, list):
555 savefig_dir = savefig_dir[0] # safe to assume only one path?
560 savefig_dir = savefig_dir[0] # safe to assume only one path?
556 savefig_dir = os.path.join(confdir, savefig_dir)
561 savefig_dir = os.path.join(confdir, savefig_dir)
557
562
558 # get regex and prompt stuff
563 # get regex and prompt stuff
559 rgxin = config.ipython_rgxin
564 rgxin = config.ipython_rgxin
560 rgxout = config.ipython_rgxout
565 rgxout = config.ipython_rgxout
561 promptin = config.ipython_promptin
566 promptin = config.ipython_promptin
562 promptout = config.ipython_promptout
567 promptout = config.ipython_promptout
563
568
564 return savefig_dir, source_dir, rgxin, rgxout, promptin, promptout
569 return savefig_dir, source_dir, rgxin, rgxout, promptin, promptout
565
570
566 def setup(self):
571 def setup(self):
567 if self.shell is None:
572 if self.shell is None:
568 self.shell = EmbeddedSphinxShell()
573 self.shell = EmbeddedSphinxShell()
569 # reset the execution count if we haven't processed this doc
574 # reset the execution count if we haven't processed this doc
570 #NOTE: this may be borked if there are multiple seen_doc tmp files
575 #NOTE: this may be borked if there are multiple seen_doc tmp files
571 #check time stamp?
576 #check time stamp?
572
577
573 if not self.state.document.current_source in self.seen_docs:
578 if not self.state.document.current_source in self.seen_docs:
574 self.shell.IP.history_manager.reset()
579 self.shell.IP.history_manager.reset()
575 self.shell.IP.execution_count = 1
580 self.shell.IP.execution_count = 1
576 self.seen_docs.add(self.state.document.current_source)
581 self.seen_docs.add(self.state.document.current_source)
577
582
578
583
579
584
580 # get config values
585 # get config values
581 (savefig_dir, source_dir, rgxin,
586 (savefig_dir, source_dir, rgxin,
582 rgxout, promptin, promptout) = self.get_config_options()
587 rgxout, promptin, promptout) = self.get_config_options()
583
588
584 # and attach to shell so we don't have to pass them around
589 # and attach to shell so we don't have to pass them around
585 self.shell.rgxin = rgxin
590 self.shell.rgxin = rgxin
586 self.shell.rgxout = rgxout
591 self.shell.rgxout = rgxout
587 self.shell.promptin = promptin
592 self.shell.promptin = promptin
588 self.shell.promptout = promptout
593 self.shell.promptout = promptout
589 self.shell.savefig_dir = savefig_dir
594 self.shell.savefig_dir = savefig_dir
590 self.shell.source_dir = source_dir
595 self.shell.source_dir = source_dir
591
596
592 # setup bookmark for saving figures directory
597 # setup bookmark for saving figures directory
593
598
594 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
599 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
595 store_history=False)
600 store_history=False)
596 self.shell.clear_cout()
601 self.shell.clear_cout()
597
602
598 return rgxin, rgxout, promptin, promptout
603 return rgxin, rgxout, promptin, promptout
599
604
600
605
601 def teardown(self):
606 def teardown(self):
602 # delete last bookmark
607 # delete last bookmark
603 self.shell.process_input_line('bookmark -d ipy_savedir',
608 self.shell.process_input_line('bookmark -d ipy_savedir',
604 store_history=False)
609 store_history=False)
605 self.shell.clear_cout()
610 self.shell.clear_cout()
606
611
607 def run(self):
612 def run(self):
608 debug = False
613 debug = False
609
614
610 #TODO, any reason block_parser can't be a method of embeddable shell
615 #TODO, any reason block_parser can't be a method of embeddable shell
611 # then we wouldn't have to carry these around
616 # then we wouldn't have to carry these around
612 rgxin, rgxout, promptin, promptout = self.setup()
617 rgxin, rgxout, promptin, promptout = self.setup()
613
618
614 options = self.options
619 options = self.options
615 self.shell.is_suppress = 'suppress' in options
620 self.shell.is_suppress = 'suppress' in options
616 self.shell.is_doctest = 'doctest' in options
621 self.shell.is_doctest = 'doctest' in options
617 self.shell.is_verbatim = 'verbatim' in options
622 self.shell.is_verbatim = 'verbatim' in options
618
623
619
624
620 # handle pure python code
625 # handle pure python code
621 if 'python' in self.arguments:
626 if 'python' in self.arguments:
622 content = self.content
627 content = self.content
623 self.content = self.shell.process_pure_python(content)
628 self.content = self.shell.process_pure_python(content)
624
629
625 parts = '\n'.join(self.content).split('\n\n')
630 parts = '\n'.join(self.content).split('\n\n')
626
631
627 lines = ['.. code-block:: ipython','']
632 lines = ['.. code-block:: ipython','']
628 figures = []
633 figures = []
629
634
630 for part in parts:
635 for part in parts:
631
636
632 block = block_parser(part, rgxin, rgxout, promptin, promptout)
637 block = block_parser(part, rgxin, rgxout, promptin, promptout)
633
638
634 if len(block):
639 if len(block):
635 rows, figure = self.shell.process_block(block)
640 rows, figure = self.shell.process_block(block)
636 for row in rows:
641 for row in rows:
637 lines.extend([' %s'%line for line in row.split('\n')])
642 lines.extend([' %s'%line for line in row.split('\n')])
638
643
639 if figure is not None:
644 if figure is not None:
640 figures.append(figure)
645 figures.append(figure)
641
646
642 #text = '\n'.join(lines)
647 #text = '\n'.join(lines)
643 #figs = '\n'.join(figures)
648 #figs = '\n'.join(figures)
644
649
645 for figure in figures:
650 for figure in figures:
646 lines.append('')
651 lines.append('')
647 lines.extend(figure.split('\n'))
652 lines.extend(figure.split('\n'))
648 lines.append('')
653 lines.append('')
649
654
650 #print lines
655 #print lines
651 if len(lines)>2:
656 if len(lines)>2:
652 if debug:
657 if debug:
653 print('\n'.join(lines))
658 print('\n'.join(lines))
654 else: #NOTE: this raises some errors, what's it for?
659 else: #NOTE: this raises some errors, what's it for?
655 #print 'INSERTING %d lines'%len(lines)
660 #print 'INSERTING %d lines'%len(lines)
656 self.state_machine.insert_input(
661 self.state_machine.insert_input(
657 lines, self.state_machine.input_lines.source(0))
662 lines, self.state_machine.input_lines.source(0))
658
663
659 text = '\n'.join(lines)
664 text = '\n'.join(lines)
660 txtnode = nodes.literal_block(text, text)
665 txtnode = nodes.literal_block(text, text)
661 txtnode['language'] = 'ipython'
666 txtnode['language'] = 'ipython'
662 #imgnode = nodes.image(figs)
667 #imgnode = nodes.image(figs)
663
668
664 # cleanup
669 # cleanup
665 self.teardown()
670 self.teardown()
666
671
667 return []#, imgnode]
672 return []#, imgnode]
668
673
669 # Enable as a proper Sphinx directive
674 # Enable as a proper Sphinx directive
670 def setup(app):
675 def setup(app):
671 setup.app = app
676 setup.app = app
672
677
673 app.add_directive('ipython', IPythonDirective)
678 app.add_directive('ipython', IPythonDirective)
674 app.add_config_value('ipython_savefig_dir', None, True)
679 app.add_config_value('ipython_savefig_dir', None, True)
675 app.add_config_value('ipython_rgxin',
680 app.add_config_value('ipython_rgxin',
676 re.compile('In \[(\d+)\]:\s?(.*)\s*'), True)
681 re.compile('In \[(\d+)\]:\s?(.*)\s*'), True)
677 app.add_config_value('ipython_rgxout',
682 app.add_config_value('ipython_rgxout',
678 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), True)
683 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), True)
679 app.add_config_value('ipython_promptin', 'In [%d]:', True)
684 app.add_config_value('ipython_promptin', 'In [%d]:', True)
680 app.add_config_value('ipython_promptout', 'Out[%d]:', True)
685 app.add_config_value('ipython_promptout', 'Out[%d]:', True)
681
686
682
687
683 # Simple smoke test, needs to be converted to a proper automatic test.
688 # Simple smoke test, needs to be converted to a proper automatic test.
684 def test():
689 def test():
685
690
686 examples = [
691 examples = [
687 r"""
692 r"""
688 In [9]: pwd
693 In [9]: pwd
689 Out[9]: '/home/jdhunter/py4science/book'
694 Out[9]: '/home/jdhunter/py4science/book'
690
695
691 In [10]: cd bookdata/
696 In [10]: cd bookdata/
692 /home/jdhunter/py4science/book/bookdata
697 /home/jdhunter/py4science/book/bookdata
693
698
694 In [2]: from pylab import *
699 In [2]: from pylab import *
695
700
696 In [2]: ion()
701 In [2]: ion()
697
702
698 In [3]: im = imread('stinkbug.png')
703 In [3]: im = imread('stinkbug.png')
699
704
700 @savefig mystinkbug.png width=4in
705 @savefig mystinkbug.png width=4in
701 In [4]: imshow(im)
706 In [4]: imshow(im)
702 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
707 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
703
708
704 """,
709 """,
705 r"""
710 r"""
706
711
707 In [1]: x = 'hello world'
712 In [1]: x = 'hello world'
708
713
709 # string methods can be
714 # string methods can be
710 # used to alter the string
715 # used to alter the string
711 @doctest
716 @doctest
712 In [2]: x.upper()
717 In [2]: x.upper()
713 Out[2]: 'HELLO WORLD'
718 Out[2]: 'HELLO WORLD'
714
719
715 @verbatim
720 @verbatim
716 In [3]: x.st<TAB>
721 In [3]: x.st<TAB>
717 x.startswith x.strip
722 x.startswith x.strip
718 """,
723 """,
719 r"""
724 r"""
720
725
721 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
726 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
722 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
727 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
723
728
724 In [131]: print url.split('&')
729 In [131]: print url.split('&')
725 ['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']
730 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
726
731
727 In [60]: import urllib
732 In [60]: import urllib
728
733
729 """,
734 """,
730 r"""\
735 r"""\
731
736
732 In [133]: import numpy.random
737 In [133]: import numpy.random
733
738
734 @suppress
739 @suppress
735 In [134]: numpy.random.seed(2358)
740 In [134]: numpy.random.seed(2358)
736
741
737 @doctest
742 @doctest
738 In [135]: numpy.random.rand(10,2)
743 In [135]: numpy.random.rand(10,2)
739 Out[135]:
744 Out[135]:
740 array([[ 0.64524308, 0.59943846],
745 array([[ 0.64524308, 0.59943846],
741 [ 0.47102322, 0.8715456 ],
746 [ 0.47102322, 0.8715456 ],
742 [ 0.29370834, 0.74776844],
747 [ 0.29370834, 0.74776844],
743 [ 0.99539577, 0.1313423 ],
748 [ 0.99539577, 0.1313423 ],
744 [ 0.16250302, 0.21103583],
749 [ 0.16250302, 0.21103583],
745 [ 0.81626524, 0.1312433 ],
750 [ 0.81626524, 0.1312433 ],
746 [ 0.67338089, 0.72302393],
751 [ 0.67338089, 0.72302393],
747 [ 0.7566368 , 0.07033696],
752 [ 0.7566368 , 0.07033696],
748 [ 0.22591016, 0.77731835],
753 [ 0.22591016, 0.77731835],
749 [ 0.0072729 , 0.34273127]])
754 [ 0.0072729 , 0.34273127]])
750
755
751 """,
756 """,
752
757
753 r"""
758 r"""
754 In [106]: print x
759 In [106]: print x
755 jdh
760 jdh
756
761
757 In [109]: for i in range(10):
762 In [109]: for i in range(10):
758 .....: print i
763 .....: print i
759 .....:
764 .....:
760 .....:
765 .....:
761 0
766 0
762 1
767 1
763 2
768 2
764 3
769 3
765 4
770 4
766 5
771 5
767 6
772 6
768 7
773 7
769 8
774 8
770 9
775 9
771 """,
776 """,
772
777
773 r"""
778 r"""
774
779
775 In [144]: from pylab import *
780 In [144]: from pylab import *
776
781
777 In [145]: ion()
782 In [145]: ion()
778
783
779 # use a semicolon to suppress the output
784 # use a semicolon to suppress the output
780 @savefig test_hist.png width=4in
785 @savefig test_hist.png width=4in
781 In [151]: hist(np.random.randn(10000), 100);
786 In [151]: hist(np.random.randn(10000), 100);
782
787
783
788
784 @savefig test_plot.png width=4in
789 @savefig test_plot.png width=4in
785 In [151]: plot(np.random.randn(10000), 'o');
790 In [151]: plot(np.random.randn(10000), 'o');
786 """,
791 """,
787
792
788 r"""
793 r"""
789 # use a semicolon to suppress the output
794 # use a semicolon to suppress the output
790 In [151]: plt.clf()
795 In [151]: plt.clf()
791
796
792 @savefig plot_simple.png width=4in
797 @savefig plot_simple.png width=4in
793 In [151]: plot([1,2,3])
798 In [151]: plot([1,2,3])
794
799
795 @savefig hist_simple.png width=4in
800 @savefig hist_simple.png width=4in
796 In [151]: hist(np.random.randn(10000), 100);
801 In [151]: hist(np.random.randn(10000), 100);
797
802
798 """,
803 """,
799 r"""
804 r"""
800 # update the current fig
805 # update the current fig
801 In [151]: ylabel('number')
806 In [151]: ylabel('number')
802
807
803 In [152]: title('normal distribution')
808 In [152]: title('normal distribution')
804
809
805
810
806 @savefig hist_with_text.png
811 @savefig hist_with_text.png
807 In [153]: grid(True)
812 In [153]: grid(True)
808
813
809 """,
814 """,
810 ]
815 ]
811 # skip local-file depending first example:
816 # skip local-file depending first example:
812 examples = examples[1:]
817 examples = examples[1:]
813
818
814 #ipython_directive.DEBUG = True # dbg
819 #ipython_directive.DEBUG = True # dbg
815 #options = dict(suppress=True) # dbg
820 #options = dict(suppress=True) # dbg
816 options = dict()
821 options = dict()
817 for example in examples:
822 for example in examples:
818 content = example.split('\n')
823 content = example.split('\n')
819 IPythonDirective('debug', arguments=None, options=options,
824 IPythonDirective('debug', arguments=None, options=options,
820 content=content, lineno=0,
825 content=content, lineno=0,
821 content_offset=None, block_text=None,
826 content_offset=None, block_text=None,
822 state=None, state_machine=None,
827 state=None, state_machine=None,
823 )
828 )
824
829
825 # Run test suite as a script
830 # Run test suite as a script
826 if __name__=='__main__':
831 if __name__=='__main__':
827 if not os.path.isdir('_static'):
832 if not os.path.isdir('_static'):
828 os.mkdir('_static')
833 os.mkdir('_static')
829 test()
834 test()
830 print('All OK? Check figures in _static/')
835 print('All OK? Check figures in _static/')
@@ -1,760 +1,764 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by setting the
6 pretty-printing OFF. This can be done either by setting the
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 by interactively disabling it with %Pprint. This is required so that IPython
8 by interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Module imports
19 # Module imports
20
20
21 # From the standard library
21 # From the standard library
22 import doctest
22 import doctest
23 import inspect
23 import inspect
24 import logging
24 import logging
25 import os
25 import os
26 import re
26 import re
27 import sys
27 import sys
28 import traceback
28 import traceback
29 import unittest
29 import unittest
30
30
31 from inspect import getmodule
31 from inspect import getmodule
32 from io import StringIO
33
32
34 # We are overriding the default doctest runner, so we need to import a few
33 # We are overriding the default doctest runner, so we need to import a few
35 # things from doctest directly
34 # things from doctest directly
36 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
35 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
37 _unittest_reportflags, DocTestRunner,
36 _unittest_reportflags, DocTestRunner,
38 _extract_future_flags, pdb, _OutputRedirectingPdb,
37 _extract_future_flags, pdb, _OutputRedirectingPdb,
39 _exception_traceback,
38 _exception_traceback,
40 linecache)
39 linecache)
41
40
42 # Third-party modules
41 # Third-party modules
43 import nose.core
42 import nose.core
44
43
45 from nose.plugins import doctests, Plugin
44 from nose.plugins import doctests, Plugin
46 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
45 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
47
46
48 # Our own imports
47 # Our own imports
49 from IPython.utils.py3compat import builtin_mod
48 from IPython.utils.py3compat import builtin_mod, PY3
49
50 if PY3:
51 from io import StringIO
52 else:
53 from StringIO import StringIO
50
54
51 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
52 # Module globals and other constants
56 # Module globals and other constants
53 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
54
58
55 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
56
60
57
61
58 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
59 # Classes and functions
63 # Classes and functions
60 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
61
65
62 def is_extension_module(filename):
66 def is_extension_module(filename):
63 """Return whether the given filename is an extension module.
67 """Return whether the given filename is an extension module.
64
68
65 This simply checks that the extension is either .so or .pyd.
69 This simply checks that the extension is either .so or .pyd.
66 """
70 """
67 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
71 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
68
72
69
73
70 class DocTestSkip(object):
74 class DocTestSkip(object):
71 """Object wrapper for doctests to be skipped."""
75 """Object wrapper for doctests to be skipped."""
72
76
73 ds_skip = """Doctest to skip.
77 ds_skip = """Doctest to skip.
74 >>> 1 #doctest: +SKIP
78 >>> 1 #doctest: +SKIP
75 """
79 """
76
80
77 def __init__(self,obj):
81 def __init__(self,obj):
78 self.obj = obj
82 self.obj = obj
79
83
80 def __getattribute__(self,key):
84 def __getattribute__(self,key):
81 if key == '__doc__':
85 if key == '__doc__':
82 return DocTestSkip.ds_skip
86 return DocTestSkip.ds_skip
83 else:
87 else:
84 return getattr(object.__getattribute__(self,'obj'),key)
88 return getattr(object.__getattribute__(self,'obj'),key)
85
89
86 # Modified version of the one in the stdlib, that fixes a python bug (doctests
90 # Modified version of the one in the stdlib, that fixes a python bug (doctests
87 # not found in extension modules, http://bugs.python.org/issue3158)
91 # not found in extension modules, http://bugs.python.org/issue3158)
88 class DocTestFinder(doctest.DocTestFinder):
92 class DocTestFinder(doctest.DocTestFinder):
89
93
90 def _from_module(self, module, object):
94 def _from_module(self, module, object):
91 """
95 """
92 Return true if the given object is defined in the given
96 Return true if the given object is defined in the given
93 module.
97 module.
94 """
98 """
95 if module is None:
99 if module is None:
96 return True
100 return True
97 elif inspect.isfunction(object):
101 elif inspect.isfunction(object):
98 return module.__dict__ is object.__globals__
102 return module.__dict__ is object.__globals__
99 elif inspect.isbuiltin(object):
103 elif inspect.isbuiltin(object):
100 return module.__name__ == object.__module__
104 return module.__name__ == object.__module__
101 elif inspect.isclass(object):
105 elif inspect.isclass(object):
102 return module.__name__ == object.__module__
106 return module.__name__ == object.__module__
103 elif inspect.ismethod(object):
107 elif inspect.ismethod(object):
104 # This one may be a bug in cython that fails to correctly set the
108 # This one may be a bug in cython that fails to correctly set the
105 # __module__ attribute of methods, but since the same error is easy
109 # __module__ attribute of methods, but since the same error is easy
106 # to make by extension code writers, having this safety in place
110 # to make by extension code writers, having this safety in place
107 # isn't such a bad idea
111 # isn't such a bad idea
108 return module.__name__ == object.im_class.__module__
112 return module.__name__ == object.im_class.__module__
109 elif inspect.getmodule(object) is not None:
113 elif inspect.getmodule(object) is not None:
110 return module is inspect.getmodule(object)
114 return module is inspect.getmodule(object)
111 elif hasattr(object, '__module__'):
115 elif hasattr(object, '__module__'):
112 return module.__name__ == object.__module__
116 return module.__name__ == object.__module__
113 elif isinstance(object, property):
117 elif isinstance(object, property):
114 return True # [XX] no way not be sure.
118 return True # [XX] no way not be sure.
115 else:
119 else:
116 raise ValueError("object must be a class or function")
120 raise ValueError("object must be a class or function")
117
121
118 def _find(self, tests, obj, name, module, source_lines, globs, seen):
122 def _find(self, tests, obj, name, module, source_lines, globs, seen):
119 """
123 """
120 Find tests for the given object and any contained objects, and
124 Find tests for the given object and any contained objects, and
121 add them to `tests`.
125 add them to `tests`.
122 """
126 """
123 #print '_find for:', obj, name, module # dbg
127 #print '_find for:', obj, name, module # dbg
124 if hasattr(obj,"skip_doctest"):
128 if hasattr(obj,"skip_doctest"):
125 #print 'SKIPPING DOCTEST FOR:',obj # dbg
129 #print 'SKIPPING DOCTEST FOR:',obj # dbg
126 obj = DocTestSkip(obj)
130 obj = DocTestSkip(obj)
127
131
128 doctest.DocTestFinder._find(self,tests, obj, name, module,
132 doctest.DocTestFinder._find(self,tests, obj, name, module,
129 source_lines, globs, seen)
133 source_lines, globs, seen)
130
134
131 # Below we re-run pieces of the above method with manual modifications,
135 # Below we re-run pieces of the above method with manual modifications,
132 # because the original code is buggy and fails to correctly identify
136 # because the original code is buggy and fails to correctly identify
133 # doctests in extension modules.
137 # doctests in extension modules.
134
138
135 # Local shorthands
139 # Local shorthands
136 from inspect import isroutine, isclass, ismodule
140 from inspect import isroutine, isclass, ismodule
137
141
138 # Look for tests in a module's contained objects.
142 # Look for tests in a module's contained objects.
139 if inspect.ismodule(obj) and self._recurse:
143 if inspect.ismodule(obj) and self._recurse:
140 for valname, val in obj.__dict__.items():
144 for valname, val in obj.__dict__.items():
141 valname1 = '%s.%s' % (name, valname)
145 valname1 = '%s.%s' % (name, valname)
142 if ( (isroutine(val) or isclass(val))
146 if ( (isroutine(val) or isclass(val))
143 and self._from_module(module, val) ):
147 and self._from_module(module, val) ):
144
148
145 self._find(tests, val, valname1, module, source_lines,
149 self._find(tests, val, valname1, module, source_lines,
146 globs, seen)
150 globs, seen)
147
151
148 # Look for tests in a class's contained objects.
152 # Look for tests in a class's contained objects.
149 if inspect.isclass(obj) and self._recurse:
153 if inspect.isclass(obj) and self._recurse:
150 #print 'RECURSE into class:',obj # dbg
154 #print 'RECURSE into class:',obj # dbg
151 for valname, val in obj.__dict__.items():
155 for valname, val in obj.__dict__.items():
152 # Special handling for staticmethod/classmethod.
156 # Special handling for staticmethod/classmethod.
153 if isinstance(val, staticmethod):
157 if isinstance(val, staticmethod):
154 val = getattr(obj, valname)
158 val = getattr(obj, valname)
155 if isinstance(val, classmethod):
159 if isinstance(val, classmethod):
156 val = getattr(obj, valname).im_func
160 val = getattr(obj, valname).im_func
157
161
158 # Recurse to methods, properties, and nested classes.
162 # Recurse to methods, properties, and nested classes.
159 if ((inspect.isfunction(val) or inspect.isclass(val) or
163 if ((inspect.isfunction(val) or inspect.isclass(val) or
160 inspect.ismethod(val) or
164 inspect.ismethod(val) or
161 isinstance(val, property)) and
165 isinstance(val, property)) and
162 self._from_module(module, val)):
166 self._from_module(module, val)):
163 valname = '%s.%s' % (name, valname)
167 valname = '%s.%s' % (name, valname)
164 self._find(tests, val, valname, module, source_lines,
168 self._find(tests, val, valname, module, source_lines,
165 globs, seen)
169 globs, seen)
166
170
167
171
168 class IPDoctestOutputChecker(doctest.OutputChecker):
172 class IPDoctestOutputChecker(doctest.OutputChecker):
169 """Second-chance checker with support for random tests.
173 """Second-chance checker with support for random tests.
170
174
171 If the default comparison doesn't pass, this checker looks in the expected
175 If the default comparison doesn't pass, this checker looks in the expected
172 output string for flags that tell us to ignore the output.
176 output string for flags that tell us to ignore the output.
173 """
177 """
174
178
175 random_re = re.compile(r'#\s*random\s+')
179 random_re = re.compile(r'#\s*random\s+')
176
180
177 def check_output(self, want, got, optionflags):
181 def check_output(self, want, got, optionflags):
178 """Check output, accepting special markers embedded in the output.
182 """Check output, accepting special markers embedded in the output.
179
183
180 If the output didn't pass the default validation but the special string
184 If the output didn't pass the default validation but the special string
181 '#random' is included, we accept it."""
185 '#random' is included, we accept it."""
182
186
183 # Let the original tester verify first, in case people have valid tests
187 # Let the original tester verify first, in case people have valid tests
184 # that happen to have a comment saying '#random' embedded in.
188 # that happen to have a comment saying '#random' embedded in.
185 ret = doctest.OutputChecker.check_output(self, want, got,
189 ret = doctest.OutputChecker.check_output(self, want, got,
186 optionflags)
190 optionflags)
187 if not ret and self.random_re.search(want):
191 if not ret and self.random_re.search(want):
188 #print >> sys.stderr, 'RANDOM OK:',want # dbg
192 #print >> sys.stderr, 'RANDOM OK:',want # dbg
189 return True
193 return True
190
194
191 return ret
195 return ret
192
196
193
197
194 class DocTestCase(doctests.DocTestCase):
198 class DocTestCase(doctests.DocTestCase):
195 """Proxy for DocTestCase: provides an address() method that
199 """Proxy for DocTestCase: provides an address() method that
196 returns the correct address for the doctest case. Otherwise
200 returns the correct address for the doctest case. Otherwise
197 acts as a proxy to the test case. To provide hints for address(),
201 acts as a proxy to the test case. To provide hints for address(),
198 an obj may also be passed -- this will be used as the test object
202 an obj may also be passed -- this will be used as the test object
199 for purposes of determining the test address, if it is provided.
203 for purposes of determining the test address, if it is provided.
200 """
204 """
201
205
202 # Note: this method was taken from numpy's nosetester module.
206 # Note: this method was taken from numpy's nosetester module.
203
207
204 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
208 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
205 # its constructor that blocks non-default arguments from being passed
209 # its constructor that blocks non-default arguments from being passed
206 # down into doctest.DocTestCase
210 # down into doctest.DocTestCase
207
211
208 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
212 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
209 checker=None, obj=None, result_var='_'):
213 checker=None, obj=None, result_var='_'):
210 self._result_var = result_var
214 self._result_var = result_var
211 doctests.DocTestCase.__init__(self, test,
215 doctests.DocTestCase.__init__(self, test,
212 optionflags=optionflags,
216 optionflags=optionflags,
213 setUp=setUp, tearDown=tearDown,
217 setUp=setUp, tearDown=tearDown,
214 checker=checker)
218 checker=checker)
215 # Now we must actually copy the original constructor from the stdlib
219 # Now we must actually copy the original constructor from the stdlib
216 # doctest class, because we can't call it directly and a bug in nose
220 # doctest class, because we can't call it directly and a bug in nose
217 # means it never gets passed the right arguments.
221 # means it never gets passed the right arguments.
218
222
219 self._dt_optionflags = optionflags
223 self._dt_optionflags = optionflags
220 self._dt_checker = checker
224 self._dt_checker = checker
221 self._dt_test = test
225 self._dt_test = test
222 self._dt_test_globs_ori = test.globs
226 self._dt_test_globs_ori = test.globs
223 self._dt_setUp = setUp
227 self._dt_setUp = setUp
224 self._dt_tearDown = tearDown
228 self._dt_tearDown = tearDown
225
229
226 # XXX - store this runner once in the object!
230 # XXX - store this runner once in the object!
227 runner = IPDocTestRunner(optionflags=optionflags,
231 runner = IPDocTestRunner(optionflags=optionflags,
228 checker=checker, verbose=False)
232 checker=checker, verbose=False)
229 self._dt_runner = runner
233 self._dt_runner = runner
230
234
231
235
232 # Each doctest should remember the directory it was loaded from, so
236 # Each doctest should remember the directory it was loaded from, so
233 # things like %run work without too many contortions
237 # things like %run work without too many contortions
234 self._ori_dir = os.path.dirname(test.filename)
238 self._ori_dir = os.path.dirname(test.filename)
235
239
236 # Modified runTest from the default stdlib
240 # Modified runTest from the default stdlib
237 def runTest(self):
241 def runTest(self):
238 test = self._dt_test
242 test = self._dt_test
239 runner = self._dt_runner
243 runner = self._dt_runner
240
244
241 old = sys.stdout
245 old = sys.stdout
242 new = StringIO()
246 new = StringIO()
243 optionflags = self._dt_optionflags
247 optionflags = self._dt_optionflags
244
248
245 if not (optionflags & REPORTING_FLAGS):
249 if not (optionflags & REPORTING_FLAGS):
246 # The option flags don't include any reporting flags,
250 # The option flags don't include any reporting flags,
247 # so add the default reporting flags
251 # so add the default reporting flags
248 optionflags |= _unittest_reportflags
252 optionflags |= _unittest_reportflags
249
253
250 try:
254 try:
251 # Save our current directory and switch out to the one where the
255 # Save our current directory and switch out to the one where the
252 # test was originally created, in case another doctest did a
256 # test was originally created, in case another doctest did a
253 # directory change. We'll restore this in the finally clause.
257 # directory change. We'll restore this in the finally clause.
254 curdir = os.getcwdu()
258 curdir = os.getcwdu()
255 #print 'runTest in dir:', self._ori_dir # dbg
259 #print 'runTest in dir:', self._ori_dir # dbg
256 os.chdir(self._ori_dir)
260 os.chdir(self._ori_dir)
257
261
258 runner.DIVIDER = "-"*70
262 runner.DIVIDER = "-"*70
259 failures, tries = runner.run(test,out=new.write,
263 failures, tries = runner.run(test,out=new.write,
260 clear_globs=False)
264 clear_globs=False)
261 finally:
265 finally:
262 sys.stdout = old
266 sys.stdout = old
263 os.chdir(curdir)
267 os.chdir(curdir)
264
268
265 if failures:
269 if failures:
266 raise self.failureException(self.format_failure(new.getvalue()))
270 raise self.failureException(self.format_failure(new.getvalue()))
267
271
268 def setUp(self):
272 def setUp(self):
269 """Modified test setup that syncs with ipython namespace"""
273 """Modified test setup that syncs with ipython namespace"""
270 #print "setUp test", self._dt_test.examples # dbg
274 #print "setUp test", self._dt_test.examples # dbg
271 if isinstance(self._dt_test.examples[0], IPExample):
275 if isinstance(self._dt_test.examples[0], IPExample):
272 # for IPython examples *only*, we swap the globals with the ipython
276 # for IPython examples *only*, we swap the globals with the ipython
273 # namespace, after updating it with the globals (which doctest
277 # namespace, after updating it with the globals (which doctest
274 # fills with the necessary info from the module being tested).
278 # fills with the necessary info from the module being tested).
275 self.user_ns_orig = {}
279 self.user_ns_orig = {}
276 self.user_ns_orig.update(_ip.user_ns)
280 self.user_ns_orig.update(_ip.user_ns)
277 _ip.user_ns.update(self._dt_test.globs)
281 _ip.user_ns.update(self._dt_test.globs)
278 # We must remove the _ key in the namespace, so that Python's
282 # We must remove the _ key in the namespace, so that Python's
279 # doctest code sets it naturally
283 # doctest code sets it naturally
280 _ip.user_ns.pop('_', None)
284 _ip.user_ns.pop('_', None)
281 _ip.user_ns['__builtins__'] = builtin_mod
285 _ip.user_ns['__builtins__'] = builtin_mod
282 self._dt_test.globs = _ip.user_ns
286 self._dt_test.globs = _ip.user_ns
283
287
284 super(DocTestCase, self).setUp()
288 super(DocTestCase, self).setUp()
285
289
286 def tearDown(self):
290 def tearDown(self):
287
291
288 # Undo the test.globs reassignment we made, so that the parent class
292 # Undo the test.globs reassignment we made, so that the parent class
289 # teardown doesn't destroy the ipython namespace
293 # teardown doesn't destroy the ipython namespace
290 if isinstance(self._dt_test.examples[0], IPExample):
294 if isinstance(self._dt_test.examples[0], IPExample):
291 self._dt_test.globs = self._dt_test_globs_ori
295 self._dt_test.globs = self._dt_test_globs_ori
292 _ip.user_ns.clear()
296 _ip.user_ns.clear()
293 _ip.user_ns.update(self.user_ns_orig)
297 _ip.user_ns.update(self.user_ns_orig)
294
298
295 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
299 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
296 # it does look like one to me: its tearDown method tries to run
300 # it does look like one to me: its tearDown method tries to run
297 #
301 #
298 # delattr(builtin_mod, self._result_var)
302 # delattr(builtin_mod, self._result_var)
299 #
303 #
300 # without checking that the attribute really is there; it implicitly
304 # without checking that the attribute really is there; it implicitly
301 # assumes it should have been set via displayhook. But if the
305 # assumes it should have been set via displayhook. But if the
302 # displayhook was never called, this doesn't necessarily happen. I
306 # displayhook was never called, this doesn't necessarily happen. I
303 # haven't been able to find a little self-contained example outside of
307 # haven't been able to find a little self-contained example outside of
304 # ipython that would show the problem so I can report it to the nose
308 # ipython that would show the problem so I can report it to the nose
305 # team, but it does happen a lot in our code.
309 # team, but it does happen a lot in our code.
306 #
310 #
307 # So here, we just protect as narrowly as possible by trapping an
311 # So here, we just protect as narrowly as possible by trapping an
308 # attribute error whose message would be the name of self._result_var,
312 # attribute error whose message would be the name of self._result_var,
309 # and letting any other error propagate.
313 # and letting any other error propagate.
310 try:
314 try:
311 super(DocTestCase, self).tearDown()
315 super(DocTestCase, self).tearDown()
312 except AttributeError as exc:
316 except AttributeError as exc:
313 if exc.args[0] != self._result_var:
317 if exc.args[0] != self._result_var:
314 raise
318 raise
315
319
316
320
317 # A simple subclassing of the original with a different class name, so we can
321 # A simple subclassing of the original with a different class name, so we can
318 # distinguish and treat differently IPython examples from pure python ones.
322 # distinguish and treat differently IPython examples from pure python ones.
319 class IPExample(doctest.Example): pass
323 class IPExample(doctest.Example): pass
320
324
321
325
322 class IPExternalExample(doctest.Example):
326 class IPExternalExample(doctest.Example):
323 """Doctest examples to be run in an external process."""
327 """Doctest examples to be run in an external process."""
324
328
325 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
329 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
326 options=None):
330 options=None):
327 # Parent constructor
331 # Parent constructor
328 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
332 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
329
333
330 # An EXTRA newline is needed to prevent pexpect hangs
334 # An EXTRA newline is needed to prevent pexpect hangs
331 self.source += '\n'
335 self.source += '\n'
332
336
333
337
334 class IPDocTestParser(doctest.DocTestParser):
338 class IPDocTestParser(doctest.DocTestParser):
335 """
339 """
336 A class used to parse strings containing doctest examples.
340 A class used to parse strings containing doctest examples.
337
341
338 Note: This is a version modified to properly recognize IPython input and
342 Note: This is a version modified to properly recognize IPython input and
339 convert any IPython examples into valid Python ones.
343 convert any IPython examples into valid Python ones.
340 """
344 """
341 # This regular expression is used to find doctest examples in a
345 # This regular expression is used to find doctest examples in a
342 # string. It defines three groups: `source` is the source code
346 # string. It defines three groups: `source` is the source code
343 # (including leading indentation and prompts); `indent` is the
347 # (including leading indentation and prompts); `indent` is the
344 # indentation of the first (PS1) line of the source code; and
348 # indentation of the first (PS1) line of the source code; and
345 # `want` is the expected output (including leading indentation).
349 # `want` is the expected output (including leading indentation).
346
350
347 # Classic Python prompts or default IPython ones
351 # Classic Python prompts or default IPython ones
348 _PS1_PY = r'>>>'
352 _PS1_PY = r'>>>'
349 _PS2_PY = r'\.\.\.'
353 _PS2_PY = r'\.\.\.'
350
354
351 _PS1_IP = r'In\ \[\d+\]:'
355 _PS1_IP = r'In\ \[\d+\]:'
352 _PS2_IP = r'\ \ \ \.\.\.+:'
356 _PS2_IP = r'\ \ \ \.\.\.+:'
353
357
354 _RE_TPL = r'''
358 _RE_TPL = r'''
355 # Source consists of a PS1 line followed by zero or more PS2 lines.
359 # Source consists of a PS1 line followed by zero or more PS2 lines.
356 (?P<source>
360 (?P<source>
357 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
361 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
358 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
362 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
359 \n? # a newline
363 \n? # a newline
360 # Want consists of any non-blank lines that do not start with PS1.
364 # Want consists of any non-blank lines that do not start with PS1.
361 (?P<want> (?:(?![ ]*$) # Not a blank line
365 (?P<want> (?:(?![ ]*$) # Not a blank line
362 (?![ ]*%s) # Not a line starting with PS1
366 (?![ ]*%s) # Not a line starting with PS1
363 (?![ ]*%s) # Not a line starting with PS2
367 (?![ ]*%s) # Not a line starting with PS2
364 .*$\n? # But any other line
368 .*$\n? # But any other line
365 )*)
369 )*)
366 '''
370 '''
367
371
368 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
372 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
369 re.MULTILINE | re.VERBOSE)
373 re.MULTILINE | re.VERBOSE)
370
374
371 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
375 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
372 re.MULTILINE | re.VERBOSE)
376 re.MULTILINE | re.VERBOSE)
373
377
374 # Mark a test as being fully random. In this case, we simply append the
378 # Mark a test as being fully random. In this case, we simply append the
375 # random marker ('#random') to each individual example's output. This way
379 # random marker ('#random') to each individual example's output. This way
376 # we don't need to modify any other code.
380 # we don't need to modify any other code.
377 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
381 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
378
382
379 # Mark tests to be executed in an external process - currently unsupported.
383 # Mark tests to be executed in an external process - currently unsupported.
380 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
384 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
381
385
382 def ip2py(self,source):
386 def ip2py(self,source):
383 """Convert input IPython source into valid Python."""
387 """Convert input IPython source into valid Python."""
384 block = _ip.input_transformer_manager.transform_cell(source)
388 block = _ip.input_transformer_manager.transform_cell(source)
385 if len(block.splitlines()) == 1:
389 if len(block.splitlines()) == 1:
386 return _ip.prefilter(block)
390 return _ip.prefilter(block)
387 else:
391 else:
388 return block
392 return block
389
393
390 def parse(self, string, name='<string>'):
394 def parse(self, string, name='<string>'):
391 """
395 """
392 Divide the given string into examples and intervening text,
396 Divide the given string into examples and intervening text,
393 and return them as a list of alternating Examples and strings.
397 and return them as a list of alternating Examples and strings.
394 Line numbers for the Examples are 0-based. The optional
398 Line numbers for the Examples are 0-based. The optional
395 argument `name` is a name identifying this string, and is only
399 argument `name` is a name identifying this string, and is only
396 used for error messages.
400 used for error messages.
397 """
401 """
398
402
399 #print 'Parse string:\n',string # dbg
403 #print 'Parse string:\n',string # dbg
400
404
401 string = string.expandtabs()
405 string = string.expandtabs()
402 # If all lines begin with the same indentation, then strip it.
406 # If all lines begin with the same indentation, then strip it.
403 min_indent = self._min_indent(string)
407 min_indent = self._min_indent(string)
404 if min_indent > 0:
408 if min_indent > 0:
405 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
409 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
406
410
407 output = []
411 output = []
408 charno, lineno = 0, 0
412 charno, lineno = 0, 0
409
413
410 # We make 'all random' tests by adding the '# random' mark to every
414 # We make 'all random' tests by adding the '# random' mark to every
411 # block of output in the test.
415 # block of output in the test.
412 if self._RANDOM_TEST.search(string):
416 if self._RANDOM_TEST.search(string):
413 random_marker = '\n# random'
417 random_marker = '\n# random'
414 else:
418 else:
415 random_marker = ''
419 random_marker = ''
416
420
417 # Whether to convert the input from ipython to python syntax
421 # Whether to convert the input from ipython to python syntax
418 ip2py = False
422 ip2py = False
419 # Find all doctest examples in the string. First, try them as Python
423 # Find all doctest examples in the string. First, try them as Python
420 # examples, then as IPython ones
424 # examples, then as IPython ones
421 terms = list(self._EXAMPLE_RE_PY.finditer(string))
425 terms = list(self._EXAMPLE_RE_PY.finditer(string))
422 if terms:
426 if terms:
423 # Normal Python example
427 # Normal Python example
424 #print '-'*70 # dbg
428 #print '-'*70 # dbg
425 #print 'PyExample, Source:\n',string # dbg
429 #print 'PyExample, Source:\n',string # dbg
426 #print '-'*70 # dbg
430 #print '-'*70 # dbg
427 Example = doctest.Example
431 Example = doctest.Example
428 else:
432 else:
429 # It's an ipython example. Note that IPExamples are run
433 # It's an ipython example. Note that IPExamples are run
430 # in-process, so their syntax must be turned into valid python.
434 # in-process, so their syntax must be turned into valid python.
431 # IPExternalExamples are run out-of-process (via pexpect) so they
435 # IPExternalExamples are run out-of-process (via pexpect) so they
432 # don't need any filtering (a real ipython will be executing them).
436 # don't need any filtering (a real ipython will be executing them).
433 terms = list(self._EXAMPLE_RE_IP.finditer(string))
437 terms = list(self._EXAMPLE_RE_IP.finditer(string))
434 if self._EXTERNAL_IP.search(string):
438 if self._EXTERNAL_IP.search(string):
435 #print '-'*70 # dbg
439 #print '-'*70 # dbg
436 #print 'IPExternalExample, Source:\n',string # dbg
440 #print 'IPExternalExample, Source:\n',string # dbg
437 #print '-'*70 # dbg
441 #print '-'*70 # dbg
438 Example = IPExternalExample
442 Example = IPExternalExample
439 else:
443 else:
440 #print '-'*70 # dbg
444 #print '-'*70 # dbg
441 #print 'IPExample, Source:\n',string # dbg
445 #print 'IPExample, Source:\n',string # dbg
442 #print '-'*70 # dbg
446 #print '-'*70 # dbg
443 Example = IPExample
447 Example = IPExample
444 ip2py = True
448 ip2py = True
445
449
446 for m in terms:
450 for m in terms:
447 # Add the pre-example text to `output`.
451 # Add the pre-example text to `output`.
448 output.append(string[charno:m.start()])
452 output.append(string[charno:m.start()])
449 # Update lineno (lines before this example)
453 # Update lineno (lines before this example)
450 lineno += string.count('\n', charno, m.start())
454 lineno += string.count('\n', charno, m.start())
451 # Extract info from the regexp match.
455 # Extract info from the regexp match.
452 (source, options, want, exc_msg) = \
456 (source, options, want, exc_msg) = \
453 self._parse_example(m, name, lineno,ip2py)
457 self._parse_example(m, name, lineno,ip2py)
454
458
455 # Append the random-output marker (it defaults to empty in most
459 # Append the random-output marker (it defaults to empty in most
456 # cases, it's only non-empty for 'all-random' tests):
460 # cases, it's only non-empty for 'all-random' tests):
457 want += random_marker
461 want += random_marker
458
462
459 if Example is IPExternalExample:
463 if Example is IPExternalExample:
460 options[doctest.NORMALIZE_WHITESPACE] = True
464 options[doctest.NORMALIZE_WHITESPACE] = True
461 want += '\n'
465 want += '\n'
462
466
463 # Create an Example, and add it to the list.
467 # Create an Example, and add it to the list.
464 if not self._IS_BLANK_OR_COMMENT(source):
468 if not self._IS_BLANK_OR_COMMENT(source):
465 output.append(Example(source, want, exc_msg,
469 output.append(Example(source, want, exc_msg,
466 lineno=lineno,
470 lineno=lineno,
467 indent=min_indent+len(m.group('indent')),
471 indent=min_indent+len(m.group('indent')),
468 options=options))
472 options=options))
469 # Update lineno (lines inside this example)
473 # Update lineno (lines inside this example)
470 lineno += string.count('\n', m.start(), m.end())
474 lineno += string.count('\n', m.start(), m.end())
471 # Update charno.
475 # Update charno.
472 charno = m.end()
476 charno = m.end()
473 # Add any remaining post-example text to `output`.
477 # Add any remaining post-example text to `output`.
474 output.append(string[charno:])
478 output.append(string[charno:])
475 return output
479 return output
476
480
477 def _parse_example(self, m, name, lineno,ip2py=False):
481 def _parse_example(self, m, name, lineno,ip2py=False):
478 """
482 """
479 Given a regular expression match from `_EXAMPLE_RE` (`m`),
483 Given a regular expression match from `_EXAMPLE_RE` (`m`),
480 return a pair `(source, want)`, where `source` is the matched
484 return a pair `(source, want)`, where `source` is the matched
481 example's source code (with prompts and indentation stripped);
485 example's source code (with prompts and indentation stripped);
482 and `want` is the example's expected output (with indentation
486 and `want` is the example's expected output (with indentation
483 stripped).
487 stripped).
484
488
485 `name` is the string's name, and `lineno` is the line number
489 `name` is the string's name, and `lineno` is the line number
486 where the example starts; both are used for error messages.
490 where the example starts; both are used for error messages.
487
491
488 Optional:
492 Optional:
489 `ip2py`: if true, filter the input via IPython to convert the syntax
493 `ip2py`: if true, filter the input via IPython to convert the syntax
490 into valid python.
494 into valid python.
491 """
495 """
492
496
493 # Get the example's indentation level.
497 # Get the example's indentation level.
494 indent = len(m.group('indent'))
498 indent = len(m.group('indent'))
495
499
496 # Divide source into lines; check that they're properly
500 # Divide source into lines; check that they're properly
497 # indented; and then strip their indentation & prompts.
501 # indented; and then strip their indentation & prompts.
498 source_lines = m.group('source').split('\n')
502 source_lines = m.group('source').split('\n')
499
503
500 # We're using variable-length input prompts
504 # We're using variable-length input prompts
501 ps1 = m.group('ps1')
505 ps1 = m.group('ps1')
502 ps2 = m.group('ps2')
506 ps2 = m.group('ps2')
503 ps1_len = len(ps1)
507 ps1_len = len(ps1)
504
508
505 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
509 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
506 if ps2:
510 if ps2:
507 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
511 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
508
512
509 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
513 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
510
514
511 if ip2py:
515 if ip2py:
512 # Convert source input from IPython into valid Python syntax
516 # Convert source input from IPython into valid Python syntax
513 source = self.ip2py(source)
517 source = self.ip2py(source)
514
518
515 # Divide want into lines; check that it's properly indented; and
519 # Divide want into lines; check that it's properly indented; and
516 # then strip the indentation. Spaces before the last newline should
520 # then strip the indentation. Spaces before the last newline should
517 # be preserved, so plain rstrip() isn't good enough.
521 # be preserved, so plain rstrip() isn't good enough.
518 want = m.group('want')
522 want = m.group('want')
519 want_lines = want.split('\n')
523 want_lines = want.split('\n')
520 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
524 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
521 del want_lines[-1] # forget final newline & spaces after it
525 del want_lines[-1] # forget final newline & spaces after it
522 self._check_prefix(want_lines, ' '*indent, name,
526 self._check_prefix(want_lines, ' '*indent, name,
523 lineno + len(source_lines))
527 lineno + len(source_lines))
524
528
525 # Remove ipython output prompt that might be present in the first line
529 # Remove ipython output prompt that might be present in the first line
526 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
530 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
527
531
528 want = '\n'.join([wl[indent:] for wl in want_lines])
532 want = '\n'.join([wl[indent:] for wl in want_lines])
529
533
530 # If `want` contains a traceback message, then extract it.
534 # If `want` contains a traceback message, then extract it.
531 m = self._EXCEPTION_RE.match(want)
535 m = self._EXCEPTION_RE.match(want)
532 if m:
536 if m:
533 exc_msg = m.group('msg')
537 exc_msg = m.group('msg')
534 else:
538 else:
535 exc_msg = None
539 exc_msg = None
536
540
537 # Extract options from the source.
541 # Extract options from the source.
538 options = self._find_options(source, name, lineno)
542 options = self._find_options(source, name, lineno)
539
543
540 return source, options, want, exc_msg
544 return source, options, want, exc_msg
541
545
542 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
546 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
543 """
547 """
544 Given the lines of a source string (including prompts and
548 Given the lines of a source string (including prompts and
545 leading indentation), check to make sure that every prompt is
549 leading indentation), check to make sure that every prompt is
546 followed by a space character. If any line is not followed by
550 followed by a space character. If any line is not followed by
547 a space character, then raise ValueError.
551 a space character, then raise ValueError.
548
552
549 Note: IPython-modified version which takes the input prompt length as a
553 Note: IPython-modified version which takes the input prompt length as a
550 parameter, so that prompts of variable length can be dealt with.
554 parameter, so that prompts of variable length can be dealt with.
551 """
555 """
552 space_idx = indent+ps1_len
556 space_idx = indent+ps1_len
553 min_len = space_idx+1
557 min_len = space_idx+1
554 for i, line in enumerate(lines):
558 for i, line in enumerate(lines):
555 if len(line) >= min_len and line[space_idx] != ' ':
559 if len(line) >= min_len and line[space_idx] != ' ':
556 raise ValueError('line %r of the docstring for %s '
560 raise ValueError('line %r of the docstring for %s '
557 'lacks blank after %s: %r' %
561 'lacks blank after %s: %r' %
558 (lineno+i+1, name,
562 (lineno+i+1, name,
559 line[indent:space_idx], line))
563 line[indent:space_idx], line))
560
564
561
565
562 SKIP = doctest.register_optionflag('SKIP')
566 SKIP = doctest.register_optionflag('SKIP')
563
567
564
568
565 class IPDocTestRunner(doctest.DocTestRunner,object):
569 class IPDocTestRunner(doctest.DocTestRunner,object):
566 """Test runner that synchronizes the IPython namespace with test globals.
570 """Test runner that synchronizes the IPython namespace with test globals.
567 """
571 """
568
572
569 def run(self, test, compileflags=None, out=None, clear_globs=True):
573 def run(self, test, compileflags=None, out=None, clear_globs=True):
570
574
571 # Hack: ipython needs access to the execution context of the example,
575 # Hack: ipython needs access to the execution context of the example,
572 # so that it can propagate user variables loaded by %run into
576 # so that it can propagate user variables loaded by %run into
573 # test.globs. We put them here into our modified %run as a function
577 # test.globs. We put them here into our modified %run as a function
574 # attribute. Our new %run will then only make the namespace update
578 # attribute. Our new %run will then only make the namespace update
575 # when called (rather than unconconditionally updating test.globs here
579 # when called (rather than unconconditionally updating test.globs here
576 # for all examples, most of which won't be calling %run anyway).
580 # for all examples, most of which won't be calling %run anyway).
577 #_ip._ipdoctest_test_globs = test.globs
581 #_ip._ipdoctest_test_globs = test.globs
578 #_ip._ipdoctest_test_filename = test.filename
582 #_ip._ipdoctest_test_filename = test.filename
579
583
580 test.globs.update(_ip.user_ns)
584 test.globs.update(_ip.user_ns)
581
585
582 return super(IPDocTestRunner,self).run(test,
586 return super(IPDocTestRunner,self).run(test,
583 compileflags,out,clear_globs)
587 compileflags,out,clear_globs)
584
588
585
589
586 class DocFileCase(doctest.DocFileCase):
590 class DocFileCase(doctest.DocFileCase):
587 """Overrides to provide filename
591 """Overrides to provide filename
588 """
592 """
589 def address(self):
593 def address(self):
590 return (self._dt_test.filename, None, None)
594 return (self._dt_test.filename, None, None)
591
595
592
596
593 class ExtensionDoctest(doctests.Doctest):
597 class ExtensionDoctest(doctests.Doctest):
594 """Nose Plugin that supports doctests in extension modules.
598 """Nose Plugin that supports doctests in extension modules.
595 """
599 """
596 name = 'extdoctest' # call nosetests with --with-extdoctest
600 name = 'extdoctest' # call nosetests with --with-extdoctest
597 enabled = True
601 enabled = True
598
602
599 def options(self, parser, env=os.environ):
603 def options(self, parser, env=os.environ):
600 Plugin.options(self, parser, env)
604 Plugin.options(self, parser, env)
601 parser.add_option('--doctest-tests', action='store_true',
605 parser.add_option('--doctest-tests', action='store_true',
602 dest='doctest_tests',
606 dest='doctest_tests',
603 default=env.get('NOSE_DOCTEST_TESTS',True),
607 default=env.get('NOSE_DOCTEST_TESTS',True),
604 help="Also look for doctests in test modules. "
608 help="Also look for doctests in test modules. "
605 "Note that classes, methods and functions should "
609 "Note that classes, methods and functions should "
606 "have either doctests or non-doctest tests, "
610 "have either doctests or non-doctest tests, "
607 "not both. [NOSE_DOCTEST_TESTS]")
611 "not both. [NOSE_DOCTEST_TESTS]")
608 parser.add_option('--doctest-extension', action="append",
612 parser.add_option('--doctest-extension', action="append",
609 dest="doctestExtension",
613 dest="doctestExtension",
610 help="Also look for doctests in files with "
614 help="Also look for doctests in files with "
611 "this extension [NOSE_DOCTEST_EXTENSION]")
615 "this extension [NOSE_DOCTEST_EXTENSION]")
612 # Set the default as a list, if given in env; otherwise
616 # Set the default as a list, if given in env; otherwise
613 # an additional value set on the command line will cause
617 # an additional value set on the command line will cause
614 # an error.
618 # an error.
615 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
619 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
616 if env_setting is not None:
620 if env_setting is not None:
617 parser.set_defaults(doctestExtension=tolist(env_setting))
621 parser.set_defaults(doctestExtension=tolist(env_setting))
618
622
619
623
620 def configure(self, options, config):
624 def configure(self, options, config):
621 Plugin.configure(self, options, config)
625 Plugin.configure(self, options, config)
622 # Pull standard doctest plugin out of config; we will do doctesting
626 # Pull standard doctest plugin out of config; we will do doctesting
623 config.plugins.plugins = [p for p in config.plugins.plugins
627 config.plugins.plugins = [p for p in config.plugins.plugins
624 if p.name != 'doctest']
628 if p.name != 'doctest']
625 self.doctest_tests = options.doctest_tests
629 self.doctest_tests = options.doctest_tests
626 self.extension = tolist(options.doctestExtension)
630 self.extension = tolist(options.doctestExtension)
627
631
628 self.parser = doctest.DocTestParser()
632 self.parser = doctest.DocTestParser()
629 self.finder = DocTestFinder()
633 self.finder = DocTestFinder()
630 self.checker = IPDoctestOutputChecker()
634 self.checker = IPDoctestOutputChecker()
631 self.globs = None
635 self.globs = None
632 self.extraglobs = None
636 self.extraglobs = None
633
637
634
638
635 def loadTestsFromExtensionModule(self,filename):
639 def loadTestsFromExtensionModule(self,filename):
636 bpath,mod = os.path.split(filename)
640 bpath,mod = os.path.split(filename)
637 modname = os.path.splitext(mod)[0]
641 modname = os.path.splitext(mod)[0]
638 try:
642 try:
639 sys.path.append(bpath)
643 sys.path.append(bpath)
640 module = __import__(modname)
644 module = __import__(modname)
641 tests = list(self.loadTestsFromModule(module))
645 tests = list(self.loadTestsFromModule(module))
642 finally:
646 finally:
643 sys.path.pop()
647 sys.path.pop()
644 return tests
648 return tests
645
649
646 # NOTE: the method below is almost a copy of the original one in nose, with
650 # NOTE: the method below is almost a copy of the original one in nose, with
647 # a few modifications to control output checking.
651 # a few modifications to control output checking.
648
652
649 def loadTestsFromModule(self, module):
653 def loadTestsFromModule(self, module):
650 #print '*** ipdoctest - lTM',module # dbg
654 #print '*** ipdoctest - lTM',module # dbg
651
655
652 if not self.matches(module.__name__):
656 if not self.matches(module.__name__):
653 log.debug("Doctest doesn't want module %s", module)
657 log.debug("Doctest doesn't want module %s", module)
654 return
658 return
655
659
656 tests = self.finder.find(module,globs=self.globs,
660 tests = self.finder.find(module,globs=self.globs,
657 extraglobs=self.extraglobs)
661 extraglobs=self.extraglobs)
658 if not tests:
662 if not tests:
659 return
663 return
660
664
661 # always use whitespace and ellipsis options
665 # always use whitespace and ellipsis options
662 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
663
667
664 tests.sort()
668 tests.sort()
665 module_file = module.__file__
669 module_file = module.__file__
666 if module_file[-4:] in ('.pyc', '.pyo'):
670 if module_file[-4:] in ('.pyc', '.pyo'):
667 module_file = module_file[:-1]
671 module_file = module_file[:-1]
668 for test in tests:
672 for test in tests:
669 if not test.examples:
673 if not test.examples:
670 continue
674 continue
671 if not test.filename:
675 if not test.filename:
672 test.filename = module_file
676 test.filename = module_file
673
677
674 yield DocTestCase(test,
678 yield DocTestCase(test,
675 optionflags=optionflags,
679 optionflags=optionflags,
676 checker=self.checker)
680 checker=self.checker)
677
681
678
682
679 def loadTestsFromFile(self, filename):
683 def loadTestsFromFile(self, filename):
680 #print "ipdoctest - from file", filename # dbg
684 #print "ipdoctest - from file", filename # dbg
681 if is_extension_module(filename):
685 if is_extension_module(filename):
682 for t in self.loadTestsFromExtensionModule(filename):
686 for t in self.loadTestsFromExtensionModule(filename):
683 yield t
687 yield t
684 else:
688 else:
685 if self.extension and anyp(filename.endswith, self.extension):
689 if self.extension and anyp(filename.endswith, self.extension):
686 name = os.path.basename(filename)
690 name = os.path.basename(filename)
687 dh = open(filename)
691 dh = open(filename)
688 try:
692 try:
689 doc = dh.read()
693 doc = dh.read()
690 finally:
694 finally:
691 dh.close()
695 dh.close()
692 test = self.parser.get_doctest(
696 test = self.parser.get_doctest(
693 doc, globs={'__file__': filename}, name=name,
697 doc, globs={'__file__': filename}, name=name,
694 filename=filename, lineno=0)
698 filename=filename, lineno=0)
695 if test.examples:
699 if test.examples:
696 #print 'FileCase:',test.examples # dbg
700 #print 'FileCase:',test.examples # dbg
697 yield DocFileCase(test)
701 yield DocFileCase(test)
698 else:
702 else:
699 yield False # no tests to load
703 yield False # no tests to load
700
704
701
705
702 class IPythonDoctest(ExtensionDoctest):
706 class IPythonDoctest(ExtensionDoctest):
703 """Nose Plugin that supports doctests in extension modules.
707 """Nose Plugin that supports doctests in extension modules.
704 """
708 """
705 name = 'ipdoctest' # call nosetests with --with-ipdoctest
709 name = 'ipdoctest' # call nosetests with --with-ipdoctest
706 enabled = True
710 enabled = True
707
711
708 def makeTest(self, obj, parent):
712 def makeTest(self, obj, parent):
709 """Look for doctests in the given object, which will be a
713 """Look for doctests in the given object, which will be a
710 function, method or class.
714 function, method or class.
711 """
715 """
712 #print 'Plugin analyzing:', obj, parent # dbg
716 #print 'Plugin analyzing:', obj, parent # dbg
713 # always use whitespace and ellipsis options
717 # always use whitespace and ellipsis options
714 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
718 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
715
719
716 doctests = self.finder.find(obj, module=getmodule(parent))
720 doctests = self.finder.find(obj, module=getmodule(parent))
717 if doctests:
721 if doctests:
718 for test in doctests:
722 for test in doctests:
719 if len(test.examples) == 0:
723 if len(test.examples) == 0:
720 continue
724 continue
721
725
722 yield DocTestCase(test, obj=obj,
726 yield DocTestCase(test, obj=obj,
723 optionflags=optionflags,
727 optionflags=optionflags,
724 checker=self.checker)
728 checker=self.checker)
725
729
726 def options(self, parser, env=os.environ):
730 def options(self, parser, env=os.environ):
727 #print "Options for nose plugin:", self.name # dbg
731 #print "Options for nose plugin:", self.name # dbg
728 Plugin.options(self, parser, env)
732 Plugin.options(self, parser, env)
729 parser.add_option('--ipdoctest-tests', action='store_true',
733 parser.add_option('--ipdoctest-tests', action='store_true',
730 dest='ipdoctest_tests',
734 dest='ipdoctest_tests',
731 default=env.get('NOSE_IPDOCTEST_TESTS',True),
735 default=env.get('NOSE_IPDOCTEST_TESTS',True),
732 help="Also look for doctests in test modules. "
736 help="Also look for doctests in test modules. "
733 "Note that classes, methods and functions should "
737 "Note that classes, methods and functions should "
734 "have either doctests or non-doctest tests, "
738 "have either doctests or non-doctest tests, "
735 "not both. [NOSE_IPDOCTEST_TESTS]")
739 "not both. [NOSE_IPDOCTEST_TESTS]")
736 parser.add_option('--ipdoctest-extension', action="append",
740 parser.add_option('--ipdoctest-extension', action="append",
737 dest="ipdoctest_extension",
741 dest="ipdoctest_extension",
738 help="Also look for doctests in files with "
742 help="Also look for doctests in files with "
739 "this extension [NOSE_IPDOCTEST_EXTENSION]")
743 "this extension [NOSE_IPDOCTEST_EXTENSION]")
740 # Set the default as a list, if given in env; otherwise
744 # Set the default as a list, if given in env; otherwise
741 # an additional value set on the command line will cause
745 # an additional value set on the command line will cause
742 # an error.
746 # an error.
743 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
747 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
744 if env_setting is not None:
748 if env_setting is not None:
745 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
749 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
746
750
747 def configure(self, options, config):
751 def configure(self, options, config):
748 #print "Configuring nose plugin:", self.name # dbg
752 #print "Configuring nose plugin:", self.name # dbg
749 Plugin.configure(self, options, config)
753 Plugin.configure(self, options, config)
750 # Pull standard doctest plugin out of config; we will do doctesting
754 # Pull standard doctest plugin out of config; we will do doctesting
751 config.plugins.plugins = [p for p in config.plugins.plugins
755 config.plugins.plugins = [p for p in config.plugins.plugins
752 if p.name != 'doctest']
756 if p.name != 'doctest']
753 self.doctest_tests = options.ipdoctest_tests
757 self.doctest_tests = options.ipdoctest_tests
754 self.extension = tolist(options.ipdoctest_extension)
758 self.extension = tolist(options.ipdoctest_extension)
755
759
756 self.parser = IPDocTestParser()
760 self.parser = IPDocTestParser()
757 self.finder = DocTestFinder(parser=self.parser)
761 self.finder = DocTestFinder(parser=self.parser)
758 self.checker = IPDoctestOutputChecker()
762 self.checker = IPDoctestOutputChecker()
759 self.globs = None
763 self.globs = None
760 self.extraglobs = None
764 self.extraglobs = None
@@ -1,310 +1,315 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Class and program to colorize python source code for ANSI terminals.
3 Class and program to colorize python source code for ANSI terminals.
4
4
5 Based on an HTML code highlighter by Jurgen Hermann found at:
5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7
7
8 Modifications by Fernando Perez (fperez@colorado.edu).
8 Modifications by Fernando Perez (fperez@colorado.edu).
9
9
10 Information on the original HTML highlighter follows:
10 Information on the original HTML highlighter follows:
11
11
12 MoinMoin - Python Source Parser
12 MoinMoin - Python Source Parser
13
13
14 Title: Colorize Python source using the built-in tokenizer
14 Title: Colorize Python source using the built-in tokenizer
15
15
16 Submitter: Jurgen Hermann
16 Submitter: Jurgen Hermann
17 Last Updated:2001/04/06
17 Last Updated:2001/04/06
18
18
19 Version no:1.2
19 Version no:1.2
20
20
21 Description:
21 Description:
22
22
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 Python source code to HTML markup, rendering comments, keywords,
24 Python source code to HTML markup, rendering comments, keywords,
25 operators, numeric and string literals in different colors.
25 operators, numeric and string literals in different colors.
26
26
27 It shows how to use the built-in keyword, token and tokenize modules to
27 It shows how to use the built-in keyword, token and tokenize modules to
28 scan Python source code and re-emit it with no changes to its original
28 scan Python source code and re-emit it with no changes to its original
29 formatting (which is the hard part).
29 formatting (which is the hard part).
30 """
30 """
31 from __future__ import print_function
31 from __future__ import print_function
32 from __future__ import absolute_import
32 from __future__ import absolute_import
33 from __future__ import unicode_literals
33 from __future__ import unicode_literals
34
34
35 __all__ = ['ANSICodeColors','Parser']
35 __all__ = ['ANSICodeColors','Parser']
36
36
37 _scheme_default = 'Linux'
37 _scheme_default = 'Linux'
38
38
39
39
40 # Imports
40 # Imports
41 import io
42 import keyword
41 import keyword
43 import os
42 import os
44 import sys
43 import sys
45 import token
44 import token
46 import tokenize
45 import tokenize
47
46
48 try:
47 try:
49 generate_tokens = tokenize.generate_tokens
48 generate_tokens = tokenize.generate_tokens
50 except AttributeError:
49 except AttributeError:
51 # Python 3. Note that we use the undocumented _tokenize because it expects
50 # Python 3. Note that we use the undocumented _tokenize because it expects
52 # strings, not bytes. See also Python issue #9969.
51 # strings, not bytes. See also Python issue #9969.
53 generate_tokens = tokenize._tokenize
52 generate_tokens = tokenize._tokenize
54
53
55 from IPython.utils.coloransi import *
54 from IPython.utils.coloransi import *
55 from IPython.utils.py3compat import PY3
56
57 if PY3:
58 from io import StringIO
59 else:
60 from StringIO import StringIO
56
61
57 #############################################################################
62 #############################################################################
58 ### Python Source Parser (does Hilighting)
63 ### Python Source Parser (does Hilighting)
59 #############################################################################
64 #############################################################################
60
65
61 _KEYWORD = token.NT_OFFSET + 1
66 _KEYWORD = token.NT_OFFSET + 1
62 _TEXT = token.NT_OFFSET + 2
67 _TEXT = token.NT_OFFSET + 2
63
68
64 #****************************************************************************
69 #****************************************************************************
65 # Builtin color schemes
70 # Builtin color schemes
66
71
67 Colors = TermColors # just a shorthand
72 Colors = TermColors # just a shorthand
68
73
69 # Build a few color schemes
74 # Build a few color schemes
70 NoColor = ColorScheme(
75 NoColor = ColorScheme(
71 'NoColor',{
76 'NoColor',{
72 token.NUMBER : Colors.NoColor,
77 token.NUMBER : Colors.NoColor,
73 token.OP : Colors.NoColor,
78 token.OP : Colors.NoColor,
74 token.STRING : Colors.NoColor,
79 token.STRING : Colors.NoColor,
75 tokenize.COMMENT : Colors.NoColor,
80 tokenize.COMMENT : Colors.NoColor,
76 token.NAME : Colors.NoColor,
81 token.NAME : Colors.NoColor,
77 token.ERRORTOKEN : Colors.NoColor,
82 token.ERRORTOKEN : Colors.NoColor,
78
83
79 _KEYWORD : Colors.NoColor,
84 _KEYWORD : Colors.NoColor,
80 _TEXT : Colors.NoColor,
85 _TEXT : Colors.NoColor,
81
86
82 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
87 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
83 } )
88 } )
84
89
85 LinuxColors = ColorScheme(
90 LinuxColors = ColorScheme(
86 'Linux',{
91 'Linux',{
87 token.NUMBER : Colors.LightCyan,
92 token.NUMBER : Colors.LightCyan,
88 token.OP : Colors.Yellow,
93 token.OP : Colors.Yellow,
89 token.STRING : Colors.LightBlue,
94 token.STRING : Colors.LightBlue,
90 tokenize.COMMENT : Colors.LightRed,
95 tokenize.COMMENT : Colors.LightRed,
91 token.NAME : Colors.Normal,
96 token.NAME : Colors.Normal,
92 token.ERRORTOKEN : Colors.Red,
97 token.ERRORTOKEN : Colors.Red,
93
98
94 _KEYWORD : Colors.LightGreen,
99 _KEYWORD : Colors.LightGreen,
95 _TEXT : Colors.Yellow,
100 _TEXT : Colors.Yellow,
96
101
97 'normal' : Colors.Normal # color off (usu. Colors.Normal)
102 'normal' : Colors.Normal # color off (usu. Colors.Normal)
98 } )
103 } )
99
104
100 LightBGColors = ColorScheme(
105 LightBGColors = ColorScheme(
101 'LightBG',{
106 'LightBG',{
102 token.NUMBER : Colors.Cyan,
107 token.NUMBER : Colors.Cyan,
103 token.OP : Colors.Blue,
108 token.OP : Colors.Blue,
104 token.STRING : Colors.Blue,
109 token.STRING : Colors.Blue,
105 tokenize.COMMENT : Colors.Red,
110 tokenize.COMMENT : Colors.Red,
106 token.NAME : Colors.Normal,
111 token.NAME : Colors.Normal,
107 token.ERRORTOKEN : Colors.Red,
112 token.ERRORTOKEN : Colors.Red,
108
113
109 _KEYWORD : Colors.Green,
114 _KEYWORD : Colors.Green,
110 _TEXT : Colors.Blue,
115 _TEXT : Colors.Blue,
111
116
112 'normal' : Colors.Normal # color off (usu. Colors.Normal)
117 'normal' : Colors.Normal # color off (usu. Colors.Normal)
113 } )
118 } )
114
119
115 # Build table of color schemes (needed by the parser)
120 # Build table of color schemes (needed by the parser)
116 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
121 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
117 _scheme_default)
122 _scheme_default)
118
123
119 class Parser:
124 class Parser:
120 """ Format colored Python source.
125 """ Format colored Python source.
121 """
126 """
122
127
123 def __init__(self, color_table=None,out = sys.stdout):
128 def __init__(self, color_table=None,out = sys.stdout):
124 """ Create a parser with a specified color table and output channel.
129 """ Create a parser with a specified color table and output channel.
125
130
126 Call format() to process code.
131 Call format() to process code.
127 """
132 """
128 self.color_table = color_table and color_table or ANSICodeColors
133 self.color_table = color_table and color_table or ANSICodeColors
129 self.out = out
134 self.out = out
130
135
131 def format(self, raw, out = None, scheme = ''):
136 def format(self, raw, out = None, scheme = ''):
132 return self.format2(raw, out, scheme)[0]
137 return self.format2(raw, out, scheme)[0]
133
138
134 def format2(self, raw, out = None, scheme = ''):
139 def format2(self, raw, out = None, scheme = ''):
135 """ Parse and send the colored source.
140 """ Parse and send the colored source.
136
141
137 If out and scheme are not specified, the defaults (given to
142 If out and scheme are not specified, the defaults (given to
138 constructor) are used.
143 constructor) are used.
139
144
140 out should be a file-type object. Optionally, out can be given as the
145 out should be a file-type object. Optionally, out can be given as the
141 string 'str' and the parser will automatically return the output in a
146 string 'str' and the parser will automatically return the output in a
142 string."""
147 string."""
143
148
144 string_output = 0
149 string_output = 0
145 if out == 'str' or self.out == 'str' or \
150 if out == 'str' or self.out == 'str' or \
146 isinstance(self.out,io.StringIO):
151 isinstance(self.out,StringIO):
147 # XXX - I don't really like this state handling logic, but at this
152 # XXX - I don't really like this state handling logic, but at this
148 # point I don't want to make major changes, so adding the
153 # point I don't want to make major changes, so adding the
149 # isinstance() check is the simplest I can do to ensure correct
154 # isinstance() check is the simplest I can do to ensure correct
150 # behavior.
155 # behavior.
151 out_old = self.out
156 out_old = self.out
152 self.out = io.StringIO()
157 self.out = StringIO()
153 string_output = 1
158 string_output = 1
154 elif out is not None:
159 elif out is not None:
155 self.out = out
160 self.out = out
156
161
157 # Fast return of the unmodified input for NoColor scheme
162 # Fast return of the unmodified input for NoColor scheme
158 if scheme == 'NoColor':
163 if scheme == 'NoColor':
159 error = False
164 error = False
160 self.out.write(raw)
165 self.out.write(raw)
161 if string_output:
166 if string_output:
162 return raw,error
167 return raw,error
163 else:
168 else:
164 return None,error
169 return None,error
165
170
166 # local shorthands
171 # local shorthands
167 colors = self.color_table[scheme].colors
172 colors = self.color_table[scheme].colors
168 self.colors = colors # put in object so __call__ sees it
173 self.colors = colors # put in object so __call__ sees it
169
174
170 # Remove trailing whitespace and normalize tabs
175 # Remove trailing whitespace and normalize tabs
171 self.raw = raw.expandtabs().rstrip()
176 self.raw = raw.expandtabs().rstrip()
172
177
173 # store line offsets in self.lines
178 # store line offsets in self.lines
174 self.lines = [0, 0]
179 self.lines = [0, 0]
175 pos = 0
180 pos = 0
176 raw_find = self.raw.find
181 raw_find = self.raw.find
177 lines_append = self.lines.append
182 lines_append = self.lines.append
178 while 1:
183 while 1:
179 pos = raw_find('\n', pos) + 1
184 pos = raw_find('\n', pos) + 1
180 if not pos: break
185 if not pos: break
181 lines_append(pos)
186 lines_append(pos)
182 lines_append(len(self.raw))
187 lines_append(len(self.raw))
183
188
184 # parse the source and write it
189 # parse the source and write it
185 self.pos = 0
190 self.pos = 0
186 text = io.StringIO(self.raw)
191 text = StringIO(self.raw)
187
192
188 error = False
193 error = False
189 try:
194 try:
190 for atoken in generate_tokens(text.readline):
195 for atoken in generate_tokens(text.readline):
191 self(*atoken)
196 self(*atoken)
192 except tokenize.TokenError as ex:
197 except tokenize.TokenError as ex:
193 msg = ex.args[0]
198 msg = ex.args[0]
194 line = ex.args[1][0]
199 line = ex.args[1][0]
195 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
200 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
196 (colors[token.ERRORTOKEN],
201 (colors[token.ERRORTOKEN],
197 msg, self.raw[self.lines[line]:],
202 msg, self.raw[self.lines[line]:],
198 colors.normal)
203 colors.normal)
199 )
204 )
200 error = True
205 error = True
201 self.out.write(colors.normal+'\n')
206 self.out.write(colors.normal+'\n')
202 if string_output:
207 if string_output:
203 output = self.out.getvalue()
208 output = self.out.getvalue()
204 self.out = out_old
209 self.out = out_old
205 return (output, error)
210 return (output, error)
206 return (None, error)
211 return (None, error)
207
212
208 def __call__(self, toktype, toktext, start_pos, end_pos, line):
213 def __call__(self, toktype, toktext, start_pos, end_pos, line):
209 """ Token handler, with syntax highlighting."""
214 """ Token handler, with syntax highlighting."""
210 (srow,scol) = start_pos
215 (srow,scol) = start_pos
211 (erow,ecol) = end_pos
216 (erow,ecol) = end_pos
212 colors = self.colors
217 colors = self.colors
213 owrite = self.out.write
218 owrite = self.out.write
214
219
215 # line separator, so this works across platforms
220 # line separator, so this works across platforms
216 linesep = os.linesep
221 linesep = os.linesep
217
222
218 # calculate new positions
223 # calculate new positions
219 oldpos = self.pos
224 oldpos = self.pos
220 newpos = self.lines[srow] + scol
225 newpos = self.lines[srow] + scol
221 self.pos = newpos + len(toktext)
226 self.pos = newpos + len(toktext)
222
227
223 # send the original whitespace, if needed
228 # send the original whitespace, if needed
224 if newpos > oldpos:
229 if newpos > oldpos:
225 owrite(self.raw[oldpos:newpos])
230 owrite(self.raw[oldpos:newpos])
226
231
227 # skip indenting tokens
232 # skip indenting tokens
228 if toktype in [token.INDENT, token.DEDENT]:
233 if toktype in [token.INDENT, token.DEDENT]:
229 self.pos = newpos
234 self.pos = newpos
230 return
235 return
231
236
232 # map token type to a color group
237 # map token type to a color group
233 if token.LPAR <= toktype and toktype <= token.OP:
238 if token.LPAR <= toktype and toktype <= token.OP:
234 toktype = token.OP
239 toktype = token.OP
235 elif toktype == token.NAME and keyword.iskeyword(toktext):
240 elif toktype == token.NAME and keyword.iskeyword(toktext):
236 toktype = _KEYWORD
241 toktype = _KEYWORD
237 color = colors.get(toktype, colors[_TEXT])
242 color = colors.get(toktype, colors[_TEXT])
238
243
239 #print '<%s>' % toktext, # dbg
244 #print '<%s>' % toktext, # dbg
240
245
241 # Triple quoted strings must be handled carefully so that backtracking
246 # Triple quoted strings must be handled carefully so that backtracking
242 # in pagers works correctly. We need color terminators on _each_ line.
247 # in pagers works correctly. We need color terminators on _each_ line.
243 if linesep in toktext:
248 if linesep in toktext:
244 toktext = toktext.replace(linesep, '%s%s%s' %
249 toktext = toktext.replace(linesep, '%s%s%s' %
245 (colors.normal,linesep,color))
250 (colors.normal,linesep,color))
246
251
247 # send text
252 # send text
248 owrite('%s%s%s' % (color,toktext,colors.normal))
253 owrite('%s%s%s' % (color,toktext,colors.normal))
249
254
250 def main(argv=None):
255 def main(argv=None):
251 """Run as a command-line script: colorize a python file or stdin using ANSI
256 """Run as a command-line script: colorize a python file or stdin using ANSI
252 color escapes and print to stdout.
257 color escapes and print to stdout.
253
258
254 Inputs:
259 Inputs:
255
260
256 - argv(None): a list of strings like sys.argv[1:] giving the command-line
261 - argv(None): a list of strings like sys.argv[1:] giving the command-line
257 arguments. If None, use sys.argv[1:].
262 arguments. If None, use sys.argv[1:].
258 """
263 """
259
264
260 usage_msg = """%prog [options] [filename]
265 usage_msg = """%prog [options] [filename]
261
266
262 Colorize a python file or stdin using ANSI color escapes and print to stdout.
267 Colorize a python file or stdin using ANSI color escapes and print to stdout.
263 If no filename is given, or if filename is -, read standard input."""
268 If no filename is given, or if filename is -, read standard input."""
264
269
265 import optparse
270 import optparse
266 parser = optparse.OptionParser(usage=usage_msg)
271 parser = optparse.OptionParser(usage=usage_msg)
267 newopt = parser.add_option
272 newopt = parser.add_option
268 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
273 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
269 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
274 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
270 help="give the color scheme to use. Currently only 'Linux'\
275 help="give the color scheme to use. Currently only 'Linux'\
271 (default) and 'LightBG' and 'NoColor' are implemented (give without\
276 (default) and 'LightBG' and 'NoColor' are implemented (give without\
272 quotes)")
277 quotes)")
273
278
274 opts,args = parser.parse_args(argv)
279 opts,args = parser.parse_args(argv)
275
280
276 if len(args) > 1:
281 if len(args) > 1:
277 parser.error("you must give at most one filename.")
282 parser.error("you must give at most one filename.")
278
283
279 if len(args) == 0:
284 if len(args) == 0:
280 fname = '-' # no filename given; setup to read from stdin
285 fname = '-' # no filename given; setup to read from stdin
281 else:
286 else:
282 fname = args[0]
287 fname = args[0]
283
288
284 if fname == '-':
289 if fname == '-':
285 stream = sys.stdin
290 stream = sys.stdin
286 else:
291 else:
287 try:
292 try:
288 stream = open(fname)
293 stream = open(fname)
289 except IOError as msg:
294 except IOError as msg:
290 print(msg, file=sys.stderr)
295 print(msg, file=sys.stderr)
291 sys.exit(1)
296 sys.exit(1)
292
297
293 parser = Parser()
298 parser = Parser()
294
299
295 # we need nested try blocks because pre-2.5 python doesn't support unified
300 # we need nested try blocks because pre-2.5 python doesn't support unified
296 # try-except-finally
301 # try-except-finally
297 try:
302 try:
298 try:
303 try:
299 # write colorized version to stdout
304 # write colorized version to stdout
300 parser.format(stream.read(),scheme=opts.scheme_name)
305 parser.format(stream.read(),scheme=opts.scheme_name)
301 except IOError as msg:
306 except IOError as msg:
302 # if user reads through a pager and quits, don't print traceback
307 # if user reads through a pager and quits, don't print traceback
303 if msg.args != (32,'Broken pipe'):
308 if msg.args != (32,'Broken pipe'):
304 raise
309 raise
305 finally:
310 finally:
306 if stream is not sys.stdin:
311 if stream is not sys.stdin:
307 stream.close() # in case a non-handled exception happened above
312 stream.close() # in case a non-handled exception happened above
308
313
309 if __name__ == "__main__":
314 if __name__ == "__main__":
310 main()
315 main()
@@ -1,173 +1,179 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO capturing utilities.
3 IO capturing utilities.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2013 The IPython Development Team
7 # Copyright (C) 2013 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 from __future__ import print_function, absolute_import
12 from __future__ import print_function, absolute_import
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 import sys
18 import sys
19 from io import StringIO
19
20 from IPython.utils.py3compat import PY3
21
22 if PY3:
23 from io import StringIO
24 else:
25 from StringIO import StringIO
20
26
21 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
22 # Classes and functions
28 # Classes and functions
23 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
24
30
25
31
26 class RichOutput(object):
32 class RichOutput(object):
27 def __init__(self, source="", data=None, metadata=None):
33 def __init__(self, source="", data=None, metadata=None):
28 self.source = source
34 self.source = source
29 self.data = data or {}
35 self.data = data or {}
30 self.metadata = metadata or {}
36 self.metadata = metadata or {}
31
37
32 def display(self):
38 def display(self):
33 from IPython.display import publish_display_data
39 from IPython.display import publish_display_data
34 publish_display_data(self.source, self.data, self.metadata)
40 publish_display_data(self.source, self.data, self.metadata)
35
41
36 def _repr_mime_(self, mime):
42 def _repr_mime_(self, mime):
37 if mime not in self.data:
43 if mime not in self.data:
38 return
44 return
39 data = self.data[mime]
45 data = self.data[mime]
40 if mime in self.metadata:
46 if mime in self.metadata:
41 return data, self.metadata[mime]
47 return data, self.metadata[mime]
42 else:
48 else:
43 return data
49 return data
44
50
45 def _repr_html_(self):
51 def _repr_html_(self):
46 return self._repr_mime_("text/html")
52 return self._repr_mime_("text/html")
47
53
48 def _repr_latex_(self):
54 def _repr_latex_(self):
49 return self._repr_mime_("text/latex")
55 return self._repr_mime_("text/latex")
50
56
51 def _repr_json_(self):
57 def _repr_json_(self):
52 return self._repr_mime_("application/json")
58 return self._repr_mime_("application/json")
53
59
54 def _repr_javascript_(self):
60 def _repr_javascript_(self):
55 return self._repr_mime_("application/javascript")
61 return self._repr_mime_("application/javascript")
56
62
57 def _repr_png_(self):
63 def _repr_png_(self):
58 return self._repr_mime_("image/png")
64 return self._repr_mime_("image/png")
59
65
60 def _repr_jpeg_(self):
66 def _repr_jpeg_(self):
61 return self._repr_mime_("image/jpeg")
67 return self._repr_mime_("image/jpeg")
62
68
63 def _repr_svg_(self):
69 def _repr_svg_(self):
64 return self._repr_mime_("image/svg+xml")
70 return self._repr_mime_("image/svg+xml")
65
71
66
72
67 class CapturedIO(object):
73 class CapturedIO(object):
68 """Simple object for containing captured stdout/err and rich display StringIO objects
74 """Simple object for containing captured stdout/err and rich display StringIO objects
69
75
70 Each instance `c` has three attributes:
76 Each instance `c` has three attributes:
71
77
72 - ``c.stdout`` : standard output as a string
78 - ``c.stdout`` : standard output as a string
73 - ``c.stderr`` : standard error as a string
79 - ``c.stderr`` : standard error as a string
74 - ``c.outputs``: a list of rich display outputs
80 - ``c.outputs``: a list of rich display outputs
75
81
76 Additionally, there's a ``c.show()`` method which will print all of the
82 Additionally, there's a ``c.show()`` method which will print all of the
77 above in the same order, and can be invoked simply via ``c()``.
83 above in the same order, and can be invoked simply via ``c()``.
78 """
84 """
79
85
80 def __init__(self, stdout, stderr, outputs=None):
86 def __init__(self, stdout, stderr, outputs=None):
81 self._stdout = stdout
87 self._stdout = stdout
82 self._stderr = stderr
88 self._stderr = stderr
83 if outputs is None:
89 if outputs is None:
84 outputs = []
90 outputs = []
85 self._outputs = outputs
91 self._outputs = outputs
86
92
87 def __str__(self):
93 def __str__(self):
88 return self.stdout
94 return self.stdout
89
95
90 @property
96 @property
91 def stdout(self):
97 def stdout(self):
92 "Captured standard output"
98 "Captured standard output"
93 if not self._stdout:
99 if not self._stdout:
94 return ''
100 return ''
95 return self._stdout.getvalue()
101 return self._stdout.getvalue()
96
102
97 @property
103 @property
98 def stderr(self):
104 def stderr(self):
99 "Captured standard error"
105 "Captured standard error"
100 if not self._stderr:
106 if not self._stderr:
101 return ''
107 return ''
102 return self._stderr.getvalue()
108 return self._stderr.getvalue()
103
109
104 @property
110 @property
105 def outputs(self):
111 def outputs(self):
106 """A list of the captured rich display outputs, if any.
112 """A list of the captured rich display outputs, if any.
107
113
108 If you have a CapturedIO object ``c``, these can be displayed in IPython
114 If you have a CapturedIO object ``c``, these can be displayed in IPython
109 using::
115 using::
110
116
111 from IPython.display import display
117 from IPython.display import display
112 for o in c.outputs:
118 for o in c.outputs:
113 display(o)
119 display(o)
114 """
120 """
115 return [ RichOutput(s, d, md) for s, d, md in self._outputs ]
121 return [ RichOutput(s, d, md) for s, d, md in self._outputs ]
116
122
117 def show(self):
123 def show(self):
118 """write my output to sys.stdout/err as appropriate"""
124 """write my output to sys.stdout/err as appropriate"""
119 sys.stdout.write(self.stdout)
125 sys.stdout.write(self.stdout)
120 sys.stderr.write(self.stderr)
126 sys.stderr.write(self.stderr)
121 sys.stdout.flush()
127 sys.stdout.flush()
122 sys.stderr.flush()
128 sys.stderr.flush()
123 for source, data, metadata in self._outputs:
129 for source, data, metadata in self._outputs:
124 RichOutput(source, data, metadata).display()
130 RichOutput(source, data, metadata).display()
125
131
126 __call__ = show
132 __call__ = show
127
133
128
134
129 class capture_output(object):
135 class capture_output(object):
130 """context manager for capturing stdout/err"""
136 """context manager for capturing stdout/err"""
131 stdout = True
137 stdout = True
132 stderr = True
138 stderr = True
133 display = True
139 display = True
134
140
135 def __init__(self, stdout=True, stderr=True, display=True):
141 def __init__(self, stdout=True, stderr=True, display=True):
136 self.stdout = stdout
142 self.stdout = stdout
137 self.stderr = stderr
143 self.stderr = stderr
138 self.display = display
144 self.display = display
139 self.shell = None
145 self.shell = None
140
146
141 def __enter__(self):
147 def __enter__(self):
142 from IPython.core.getipython import get_ipython
148 from IPython.core.getipython import get_ipython
143 from IPython.core.displaypub import CapturingDisplayPublisher
149 from IPython.core.displaypub import CapturingDisplayPublisher
144
150
145 self.sys_stdout = sys.stdout
151 self.sys_stdout = sys.stdout
146 self.sys_stderr = sys.stderr
152 self.sys_stderr = sys.stderr
147
153
148 if self.display:
154 if self.display:
149 self.shell = get_ipython()
155 self.shell = get_ipython()
150 if self.shell is None:
156 if self.shell is None:
151 self.save_display_pub = None
157 self.save_display_pub = None
152 self.display = False
158 self.display = False
153
159
154 stdout = stderr = outputs = None
160 stdout = stderr = outputs = None
155 if self.stdout:
161 if self.stdout:
156 stdout = sys.stdout = StringIO()
162 stdout = sys.stdout = StringIO()
157 if self.stderr:
163 if self.stderr:
158 stderr = sys.stderr = StringIO()
164 stderr = sys.stderr = StringIO()
159 if self.display:
165 if self.display:
160 self.save_display_pub = self.shell.display_pub
166 self.save_display_pub = self.shell.display_pub
161 self.shell.display_pub = CapturingDisplayPublisher()
167 self.shell.display_pub = CapturingDisplayPublisher()
162 outputs = self.shell.display_pub.outputs
168 outputs = self.shell.display_pub.outputs
163
169
164
170
165 return CapturedIO(stdout, stderr, outputs)
171 return CapturedIO(stdout, stderr, outputs)
166
172
167 def __exit__(self, exc_type, exc_value, traceback):
173 def __exit__(self, exc_type, exc_value, traceback):
168 sys.stdout = self.sys_stdout
174 sys.stdout = self.sys_stdout
169 sys.stderr = self.sys_stderr
175 sys.stderr = self.sys_stderr
170 if self.display and self.shell:
176 if self.display and self.shell:
171 self.shell.display_pub = self.save_display_pub
177 self.shell.display_pub = self.save_display_pub
172
178
173
179
@@ -1,86 +1,90 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for io.py"""
2 """Tests for io.py"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2011 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 import sys
16 import sys
17
17
18 from io import StringIO
19 from subprocess import Popen, PIPE
18 from subprocess import Popen, PIPE
20 import unittest
19 import unittest
21
20
22 import nose.tools as nt
21 import nose.tools as nt
23
22
24 from IPython.utils.io import Tee, capture_output
23 from IPython.utils.io import Tee, capture_output
25 from IPython.utils.py3compat import doctest_refactor_print
24 from IPython.utils.py3compat import doctest_refactor_print, PY3
25
26 if PY3:
27 from io import StringIO
28 else:
29 from StringIO import StringIO
26
30
27 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
28 # Tests
32 # Tests
29 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
30
34
31
35
32 def test_tee_simple():
36 def test_tee_simple():
33 "Very simple check with stdout only"
37 "Very simple check with stdout only"
34 chan = StringIO()
38 chan = StringIO()
35 text = 'Hello'
39 text = 'Hello'
36 tee = Tee(chan, channel='stdout')
40 tee = Tee(chan, channel='stdout')
37 print(text, file=chan)
41 print(text, file=chan)
38 nt.assert_equal(chan.getvalue(), text+"\n")
42 nt.assert_equal(chan.getvalue(), text+"\n")
39
43
40
44
41 class TeeTestCase(unittest.TestCase):
45 class TeeTestCase(unittest.TestCase):
42
46
43 def tchan(self, channel, check='close'):
47 def tchan(self, channel, check='close'):
44 trap = StringIO()
48 trap = StringIO()
45 chan = StringIO()
49 chan = StringIO()
46 text = 'Hello'
50 text = 'Hello'
47
51
48 std_ori = getattr(sys, channel)
52 std_ori = getattr(sys, channel)
49 setattr(sys, channel, trap)
53 setattr(sys, channel, trap)
50
54
51 tee = Tee(chan, channel=channel)
55 tee = Tee(chan, channel=channel)
52 print(text, end='', file=chan)
56 print(text, end='', file=chan)
53 setattr(sys, channel, std_ori)
57 setattr(sys, channel, std_ori)
54 trap_val = trap.getvalue()
58 trap_val = trap.getvalue()
55 nt.assert_equal(chan.getvalue(), text)
59 nt.assert_equal(chan.getvalue(), text)
56 if check=='close':
60 if check=='close':
57 tee.close()
61 tee.close()
58 else:
62 else:
59 del tee
63 del tee
60
64
61 def test(self):
65 def test(self):
62 for chan in ['stdout', 'stderr']:
66 for chan in ['stdout', 'stderr']:
63 for check in ['close', 'del']:
67 for check in ['close', 'del']:
64 self.tchan(chan, check)
68 self.tchan(chan, check)
65
69
66 def test_io_init():
70 def test_io_init():
67 """Test that io.stdin/out/err exist at startup"""
71 """Test that io.stdin/out/err exist at startup"""
68 for name in ('stdin', 'stdout', 'stderr'):
72 for name in ('stdin', 'stdout', 'stderr'):
69 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
73 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
70 p = Popen([sys.executable, '-c', cmd],
74 p = Popen([sys.executable, '-c', cmd],
71 stdout=PIPE)
75 stdout=PIPE)
72 p.wait()
76 p.wait()
73 classname = p.stdout.read().strip().decode('ascii')
77 classname = p.stdout.read().strip().decode('ascii')
74 # __class__ is a reference to the class object in Python 3, so we can't
78 # __class__ is a reference to the class object in Python 3, so we can't
75 # just test for string equality.
79 # just test for string equality.
76 assert 'IPython.utils.io.IOStream' in classname, classname
80 assert 'IPython.utils.io.IOStream' in classname, classname
77
81
78 def test_capture_output():
82 def test_capture_output():
79 """capture_output() context works"""
83 """capture_output() context works"""
80
84
81 with capture_output() as io:
85 with capture_output() as io:
82 print('hi, stdout')
86 print('hi, stdout')
83 print('hi, stderr', file=sys.stderr)
87 print('hi, stderr', file=sys.stderr)
84
88
85 nt.assert_equal(io.stdout, 'hi, stdout\n')
89 nt.assert_equal(io.stdout, 'hi, stdout\n')
86 nt.assert_equal(io.stderr, 'hi, stderr\n')
90 nt.assert_equal(io.stderr, 'hi, stderr\n')
General Comments 0
You need to be logged in to leave comments. Login now