##// END OF EJS Templates
Merge pull request #4561 from minrk/for_type_clear...
Min RK -
r13976:3db536e9 merge
parent child Browse files
Show More
@@ -0,0 +1,20 b''
1 DisplayFormatter changes
2 ========================
3
4 There was no official way to query or remove callbacks in the Formatter API.
5 To remedy this, the following methods are added to :class:`BaseFormatter`:
6
7 - ``lookup(instance)`` - return appropriate callback or a given object
8 - ``lookup_by_type(type_or_str)`` - return appropriate callback for a given type or ``'mod.name'`` type string
9 - ``pop(type_or_str)`` - remove a type (by type or string).
10 Pass a second argument to avoid KeyError (like dict).
11
12 All of the above methods raise a KeyError if no match is found.
13
14 And the following methods are changed:
15
16 - ``for_type(type_or_str)`` - behaves the same as before, only adding support for ``'mod.name'``
17 type strings in addition to plain types. This removes the need for ``for_type_by_name()``,
18 but it remains for backward compatibility.
19
20
@@ -1,654 +1,791 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
30
31 # Our own imports
31 # Our own imports
32 from IPython.config.configurable import Configurable
32 from IPython.config.configurable import Configurable
33 from IPython.lib import pretty
33 from IPython.lib import pretty
34 from IPython.utils.traitlets import (
34 from IPython.utils.traitlets import (
35 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
35 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
36 )
36 )
37 from IPython.utils.py3compat import unicode_to_str, with_metaclass, PY3
37 from IPython.utils.py3compat import (
38 unicode_to_str, with_metaclass, PY3, string_types,
39 )
38
40
39 if PY3:
41 if PY3:
40 from io import StringIO
42 from io import StringIO
41 else:
43 else:
42 from StringIO import StringIO
44 from StringIO import StringIO
43
45
44
46
45 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
46 # The main DisplayFormatter class
48 # The main DisplayFormatter class
47 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
48
50
49
50 class DisplayFormatter(Configurable):
51 class DisplayFormatter(Configurable):
51
52
52 # When set to true only the default plain text formatter will be used.
53 # When set to true only the default plain text formatter will be used.
53 plain_text_only = Bool(False, config=True)
54 plain_text_only = Bool(False, config=True)
54 def _plain_text_only_changed(self, name, old, new):
55 def _plain_text_only_changed(self, name, old, new):
55 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
56 warnings.warn("""DisplayFormatter.plain_text_only is deprecated.
56
57
57 Use DisplayFormatter.active_types = ['text/plain']
58 Use DisplayFormatter.active_types = ['text/plain']
58 for the same effect.
59 for the same effect.
59 """, DeprecationWarning)
60 """, DeprecationWarning)
60 if new:
61 if new:
61 self.active_types = ['text/plain']
62 self.active_types = ['text/plain']
62 else:
63 else:
63 self.active_types = self.format_types
64 self.active_types = self.format_types
64
65
65 active_types = List(Unicode, config=True,
66 active_types = List(Unicode, config=True,
66 help="""List of currently active mime-types to display.
67 help="""List of currently active mime-types to display.
67 You can use this to set a white-list for formats to display.
68 You can use this to set a white-list for formats to display.
68
69
69 Most users will not need to change this value.
70 Most users will not need to change this value.
70 """)
71 """)
71 def _active_types_default(self):
72 def _active_types_default(self):
72 return self.format_types
73 return self.format_types
73
74
74 def _active_types_changed(self, name, old, new):
75 def _active_types_changed(self, name, old, new):
75 for key, formatter in self.formatters.items():
76 for key, formatter in self.formatters.items():
76 if key in new:
77 if key in new:
77 formatter.enabled = True
78 formatter.enabled = True
78 else:
79 else:
79 formatter.enabled = False
80 formatter.enabled = False
80
81
81 # A dict of formatter whose keys are format types (MIME types) and whose
82 # A dict of formatter whose keys are format types (MIME types) and whose
82 # values are subclasses of BaseFormatter.
83 # values are subclasses of BaseFormatter.
83 formatters = Dict()
84 formatters = Dict()
84 def _formatters_default(self):
85 def _formatters_default(self):
85 """Activate the default formatters."""
86 """Activate the default formatters."""
86 formatter_classes = [
87 formatter_classes = [
87 PlainTextFormatter,
88 PlainTextFormatter,
88 HTMLFormatter,
89 HTMLFormatter,
89 SVGFormatter,
90 SVGFormatter,
90 PNGFormatter,
91 PNGFormatter,
91 JPEGFormatter,
92 JPEGFormatter,
92 LatexFormatter,
93 LatexFormatter,
93 JSONFormatter,
94 JSONFormatter,
94 JavascriptFormatter
95 JavascriptFormatter
95 ]
96 ]
96 d = {}
97 d = {}
97 for cls in formatter_classes:
98 for cls in formatter_classes:
98 f = cls(parent=self)
99 f = cls(parent=self)
99 d[f.format_type] = f
100 d[f.format_type] = f
100 return d
101 return d
101
102
102 def format(self, obj, include=None, exclude=None):
103 def format(self, obj, include=None, exclude=None):
103 """Return a format data dict for an object.
104 """Return a format data dict for an object.
104
105
105 By default all format types will be computed.
106 By default all format types will be computed.
106
107
107 The following MIME types are currently implemented:
108 The following MIME types are currently implemented:
108
109
109 * text/plain
110 * text/plain
110 * text/html
111 * text/html
111 * text/latex
112 * text/latex
112 * application/json
113 * application/json
113 * application/javascript
114 * application/javascript
114 * image/png
115 * image/png
115 * image/jpeg
116 * image/jpeg
116 * image/svg+xml
117 * image/svg+xml
117
118
118 Parameters
119 Parameters
119 ----------
120 ----------
120 obj : object
121 obj : object
121 The Python object whose format data will be computed.
122 The Python object whose format data will be computed.
122 include : list or tuple, optional
123 include : list or tuple, optional
123 A list of format type strings (MIME types) to include in the
124 A list of format type strings (MIME types) to include in the
124 format data dict. If this is set *only* the format types included
125 format data dict. If this is set *only* the format types included
125 in this list will be computed.
126 in this list will be computed.
126 exclude : list or tuple, optional
127 exclude : list or tuple, optional
127 A list of format type string (MIME types) to exclude in the format
128 A list of format type string (MIME types) to exclude in the format
128 data dict. If this is set all format types will be computed,
129 data dict. If this is set all format types will be computed,
129 except for those included in this argument.
130 except for those included in this argument.
130
131
131 Returns
132 Returns
132 -------
133 -------
133 (format_dict, metadata_dict) : tuple of two dicts
134 (format_dict, metadata_dict) : tuple of two dicts
134
135
135 format_dict is a dictionary of key/value pairs, one of each format that was
136 format_dict is a dictionary of key/value pairs, one of each format that was
136 generated for the object. The keys are the format types, which
137 generated for the object. The keys are the format types, which
137 will usually be MIME type strings and the values and JSON'able
138 will usually be MIME type strings and the values and JSON'able
138 data structure containing the raw data for the representation in
139 data structure containing the raw data for the representation in
139 that format.
140 that format.
140
141
141 metadata_dict is a dictionary of metadata about each mime-type output.
142 metadata_dict is a dictionary of metadata about each mime-type output.
142 Its keys will be a strict subset of the keys in format_dict.
143 Its keys will be a strict subset of the keys in format_dict.
143 """
144 """
144 format_dict = {}
145 format_dict = {}
145 md_dict = {}
146 md_dict = {}
146
147
147 for format_type, formatter in self.formatters.items():
148 for format_type, formatter in self.formatters.items():
148 if include and format_type not in include:
149 if include and format_type not in include:
149 continue
150 continue
150 if exclude and format_type in exclude:
151 if exclude and format_type in exclude:
151 continue
152 continue
152
153
153 md = None
154 md = None
154 try:
155 try:
155 data = formatter(obj)
156 data = formatter(obj)
156 except:
157 except:
157 # FIXME: log the exception
158 # FIXME: log the exception
158 raise
159 raise
159
160
160 # formatters can return raw data or (data, metadata)
161 # formatters can return raw data or (data, metadata)
161 if isinstance(data, tuple) and len(data) == 2:
162 if isinstance(data, tuple) and len(data) == 2:
162 data, md = data
163 data, md = data
163
164
164 if data is not None:
165 if data is not None:
165 format_dict[format_type] = data
166 format_dict[format_type] = data
166 if md is not None:
167 if md is not None:
167 md_dict[format_type] = md
168 md_dict[format_type] = md
168
169
169 return format_dict, md_dict
170 return format_dict, md_dict
170
171
171 @property
172 @property
172 def format_types(self):
173 def format_types(self):
173 """Return the format types (MIME types) of the active formatters."""
174 """Return the format types (MIME types) of the active formatters."""
174 return list(self.formatters.keys())
175 return list(self.formatters.keys())
175
176
176
177
177 #-----------------------------------------------------------------------------
178 #-----------------------------------------------------------------------------
178 # Formatters for specific format types (text, html, svg, etc.)
179 # Formatters for specific format types (text, html, svg, etc.)
179 #-----------------------------------------------------------------------------
180 #-----------------------------------------------------------------------------
180
181
181
182
182 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
183 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
183 """ Abstract base class for Formatters.
184 """ Abstract base class for Formatters.
184
185
185 A formatter is a callable class that is responsible for computing the
186 A formatter is a callable class that is responsible for computing the
186 raw format data for a particular format type (MIME type). For example,
187 raw format data for a particular format type (MIME type). For example,
187 an HTML formatter would have a format type of `text/html` and would return
188 an HTML formatter would have a format type of `text/html` and would return
188 the HTML representation of the object when called.
189 the HTML representation of the object when called.
189 """
190 """
190
191
191 # The format type of the data returned, usually a MIME type.
192 # The format type of the data returned, usually a MIME type.
192 format_type = 'text/plain'
193 format_type = 'text/plain'
193
194
194 # Is the formatter enabled...
195 # Is the formatter enabled...
195 enabled = True
196 enabled = True
196
197
197 @abc.abstractmethod
198 @abc.abstractmethod
198 def __call__(self, obj):
199 def __call__(self, obj):
199 """Return a JSON'able representation of the object.
200 """Return a JSON'able representation of the object.
200
201
201 If the object cannot be formatted by this formatter, then return None
202 If the object cannot be formatted by this formatter, then return None
202 """
203 """
203 try:
204 try:
204 return repr(obj)
205 return repr(obj)
205 except Exception:
206 except Exception:
206 return None
207 return None
207
208
208
209
210 def _mod_name_key(typ):
211 """Return a (__module__, __name__) tuple for a type.
212
213 Used as key in Formatter.deferred_printers.
214 """
215 module = getattr(typ, '__module__', None)
216 name = getattr(typ, '__name__', None)
217 return (module, name)
218
219
220 def _get_type(obj):
221 """Return the type of an instance (old and new-style)"""
222 return getattr(obj, '__class__', None) or type(obj)
223
224 _raise_key_error = object()
225
209 class BaseFormatter(Configurable):
226 class BaseFormatter(Configurable):
210 """A base formatter class that is configurable.
227 """A base formatter class that is configurable.
211
228
212 This formatter should usually be used as the base class of all formatters.
229 This formatter should usually be used as the base class of all formatters.
213 It is a traited :class:`Configurable` class and includes an extensible
230 It is a traited :class:`Configurable` class and includes an extensible
214 API for users to determine how their objects are formatted. The following
231 API for users to determine how their objects are formatted. The following
215 logic is used to find a function to format an given object.
232 logic is used to find a function to format an given object.
216
233
217 1. The object is introspected to see if it has a method with the name
234 1. The object is introspected to see if it has a method with the name
218 :attr:`print_method`. If is does, that object is passed to that method
235 :attr:`print_method`. If is does, that object is passed to that method
219 for formatting.
236 for formatting.
220 2. If no print method is found, three internal dictionaries are consulted
237 2. If no print method is found, three internal dictionaries are consulted
221 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
238 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
222 and :attr:`deferred_printers`.
239 and :attr:`deferred_printers`.
223
240
224 Users should use these dictionaries to register functions that will be
241 Users should use these dictionaries to register functions that will be
225 used to compute the format data for their objects (if those objects don't
242 used to compute the format data for their objects (if those objects don't
226 have the special print methods). The easiest way of using these
243 have the special print methods). The easiest way of using these
227 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
244 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
228 methods.
245 methods.
229
246
230 If no function/callable is found to compute the format data, ``None`` is
247 If no function/callable is found to compute the format data, ``None`` is
231 returned and this format type is not used.
248 returned and this format type is not used.
232 """
249 """
233
250
234 format_type = Unicode('text/plain')
251 format_type = Unicode('text/plain')
235
252
236 enabled = Bool(True, config=True)
253 enabled = Bool(True, config=True)
237
254
238 print_method = ObjectName('__repr__')
255 print_method = ObjectName('__repr__')
239
256
240 # The singleton printers.
257 # The singleton printers.
241 # Maps the IDs of the builtin singleton objects to the format functions.
258 # Maps the IDs of the builtin singleton objects to the format functions.
242 singleton_printers = Dict(config=True)
259 singleton_printers = Dict(config=True)
243 def _singleton_printers_default(self):
244 return {}
245
260
246 # The type-specific printers.
261 # The type-specific printers.
247 # Map type objects to the format functions.
262 # Map type objects to the format functions.
248 type_printers = Dict(config=True)
263 type_printers = Dict(config=True)
249 def _type_printers_default(self):
250 return {}
251
264
252 # The deferred-import type-specific printers.
265 # The deferred-import type-specific printers.
253 # Map (modulename, classname) pairs to the format functions.
266 # Map (modulename, classname) pairs to the format functions.
254 deferred_printers = Dict(config=True)
267 deferred_printers = Dict(config=True)
255 def _deferred_printers_default(self):
256 return {}
257
268
258 def __call__(self, obj):
269 def __call__(self, obj):
259 """Compute the format for an object."""
270 """Compute the format for an object."""
260 if self.enabled:
271 if self.enabled:
261 obj_id = id(obj)
262 try:
272 try:
263 obj_class = getattr(obj, '__class__', None) or type(obj)
273 # lookup registered printer
264 # First try to find registered singleton printers for the type.
265 try:
274 try:
266 printer = self.singleton_printers[obj_id]
275 printer = self.lookup(obj)
267 except (TypeError, KeyError):
276 except KeyError:
268 pass
277 pass
269 else:
278 else:
270 return printer(obj)
279 return printer(obj)
271 # Next look for type_printers.
280 # Finally look for special method names
272 for cls in pretty._get_mro(obj_class):
281 method = pretty._safe_getattr(obj, self.print_method, None)
273 if cls in self.type_printers:
282 if method is not None:
274 return self.type_printers[cls](obj)
283 return method()
275 else:
276 printer = self._in_deferred_types(cls)
277 if printer is not None:
278 return printer(obj)
279 # Finally look for special method names.
280 if hasattr(obj_class, self.print_method):
281 printer = getattr(obj_class, self.print_method)
282 return printer(obj)
283 return None
284 return None
284 except Exception:
285 except Exception:
285 pass
286 pass
286 else:
287 else:
287 return None
288 return None
289
290 def __contains__(self, typ):
291 """map in to lookup_by_type"""
292 try:
293 self.lookup_by_type(typ)
294 except KeyError:
295 return False
296 else:
297 return True
298
299 def lookup(self, obj):
300 """Look up the formatter for a given instance.
301
302 Parameters
303 ----------
304 obj : object instance
288
305
289 def for_type(self, typ, func):
306 Returns
290 """Add a format function for a given type.
307 -------
308 f : callable
309 The registered formatting callable for the type.
310
311 Raises
312 ------
313 KeyError if the type has not been registered.
314 """
315 # look for singleton first
316 obj_id = id(obj)
317 if obj_id in self.singleton_printers:
318 return self.singleton_printers[obj_id]
319 # then lookup by type
320 return self.lookup_by_type(_get_type(obj))
321
322 def lookup_by_type(self, typ):
323 """Look up the registered formatter for a type.
324
325 Parameters
326 ----------
327 typ : type or '__module__.__name__' string for a type
328
329 Returns
330 -------
331 f : callable
332 The registered formatting callable for the type.
333
334 Raises
335 ------
336 KeyError if the type has not been registered.
337 """
338 if isinstance(typ, string_types):
339 typ_key = tuple(typ.rsplit('.',1))
340 if typ_key not in self.deferred_printers:
341 # We may have it cached in the type map. We will have to
342 # iterate over all of the types to check.
343 for cls in self.type_printers:
344 if _mod_name_key(cls) == typ_key:
345 return self.type_printers[cls]
346 else:
347 return self.deferred_printers[typ_key]
348 else:
349 for cls in pretty._get_mro(typ):
350 if cls in self.type_printers or self._in_deferred_types(cls):
351 return self.type_printers[cls]
352
353 # If we have reached here, the lookup failed.
354 raise KeyError("No registered printer for {0!r}".format(typ))
291
355
356 def for_type(self, typ, func=None):
357 """Add a format function for a given type.
358
292 Parameters
359 Parameters
293 -----------
360 -----------
294 typ : class
361 typ : type or '__module__.__name__' string for a type
295 The class of the object that will be formatted using `func`.
362 The class of the object that will be formatted using `func`.
296 func : callable
363 func : callable
297 The callable that will be called to compute the format data. The
364 A callable for computing the format data.
298 call signature of this function is simple, it must take the
365 `func` will be called with the object to be formatted,
299 object to be formatted and return the raw data for the given
366 and will return the raw data in this formatter's format.
300 format. Subclasses may use a different call signature for the
367 Subclasses may use a different call signature for the
301 `func` argument.
368 `func` argument.
369
370 If `func` is None or not specified, there will be no change,
371 only returning the current value.
372
373 Returns
374 -------
375 oldfunc : callable
376 The currently registered callable.
377 If you are registering a new formatter,
378 this will be the previous value (to enable restoring later).
302 """
379 """
303 oldfunc = self.type_printers.get(typ, None)
380 # if string given, interpret as 'pkg.module.class_name'
381 if isinstance(typ, string_types):
382 type_module, type_name = typ.rsplit('.', 1)
383 return self.for_type_by_name(type_module, type_name, func)
384
385 try:
386 oldfunc = self.lookup_by_type(typ)
387 except KeyError:
388 oldfunc = None
389
304 if func is not None:
390 if func is not None:
305 # To support easy restoration of old printers, we need to ignore
306 # Nones.
307 self.type_printers[typ] = func
391 self.type_printers[typ] = func
392
308 return oldfunc
393 return oldfunc
309
394
310 def for_type_by_name(self, type_module, type_name, func):
395 def for_type_by_name(self, type_module, type_name, func=None):
311 """Add a format function for a type specified by the full dotted
396 """Add a format function for a type specified by the full dotted
312 module and name of the type, rather than the type of the object.
397 module and name of the type, rather than the type of the object.
313
398
314 Parameters
399 Parameters
315 ----------
400 ----------
316 type_module : str
401 type_module : str
317 The full dotted name of the module the type is defined in, like
402 The full dotted name of the module the type is defined in, like
318 ``numpy``.
403 ``numpy``.
319 type_name : str
404 type_name : str
320 The name of the type (the class name), like ``dtype``
405 The name of the type (the class name), like ``dtype``
321 func : callable
406 func : callable
322 The callable that will be called to compute the format data. The
407 A callable for computing the format data.
323 call signature of this function is simple, it must take the
408 `func` will be called with the object to be formatted,
324 object to be formatted and return the raw data for the given
409 and will return the raw data in this formatter's format.
325 format. Subclasses may use a different call signature for the
410 Subclasses may use a different call signature for the
326 `func` argument.
411 `func` argument.
412
413 If `func` is None or unspecified, there will be no change,
414 only returning the current value.
415
416 Returns
417 -------
418 oldfunc : callable
419 The currently registered callable.
420 If you are registering a new formatter,
421 this will be the previous value (to enable restoring later).
327 """
422 """
328 key = (type_module, type_name)
423 key = (type_module, type_name)
329 oldfunc = self.deferred_printers.get(key, None)
424
425 try:
426 oldfunc = self.lookup_by_type("%s.%s" % key)
427 except KeyError:
428 oldfunc = None
429
330 if func is not None:
430 if func is not None:
331 # To support easy restoration of old printers, we need to ignore
332 # Nones.
333 self.deferred_printers[key] = func
431 self.deferred_printers[key] = func
334 return oldfunc
432 return oldfunc
433
434 def pop(self, typ, default=_raise_key_error):
435 """Pop a formatter for the given type.
436
437 Parameters
438 ----------
439 typ : type or '__module__.__name__' string for a type
440 default : object
441 value to be returned if no formatter is registered for typ.
442
443 Returns
444 -------
445 obj : object
446 The last registered object for the type.
447
448 Raises
449 ------
450 KeyError if the type is not registered and default is not specified.
451 """
452
453 if isinstance(typ, string_types):
454 typ_key = tuple(typ.rsplit('.',1))
455 if typ_key not in self.deferred_printers:
456 # We may have it cached in the type map. We will have to
457 # iterate over all of the types to check.
458 for cls in self.type_printers:
459 if _mod_name_key(cls) == typ_key:
460 old = self.type_printers.pop(cls)
461 break
462 else:
463 old = default
464 else:
465 old = self.deferred_printers.pop(typ_key)
466 else:
467 if typ in self.type_printers:
468 old = self.type_printers.pop(typ)
469 else:
470 old = self.deferred_printers.pop(_mod_name_key(typ), default)
471 if old is _raise_key_error:
472 raise KeyError("No registered value for {0!r}".format(typ))
473 return old
335
474
336 def _in_deferred_types(self, cls):
475 def _in_deferred_types(self, cls):
337 """
476 """
338 Check if the given class is specified in the deferred type registry.
477 Check if the given class is specified in the deferred type registry.
339
478
340 Returns the printer from the registry if it exists, and None if the
479 Successful matches will be moved to the regular type registry for future use.
341 class is not in the registry. Successful matches will be moved to the
342 regular type registry for future use.
343 """
480 """
344 mod = getattr(cls, '__module__', None)
481 mod = getattr(cls, '__module__', None)
345 name = getattr(cls, '__name__', None)
482 name = getattr(cls, '__name__', None)
346 key = (mod, name)
483 key = (mod, name)
347 printer = None
348 if key in self.deferred_printers:
484 if key in self.deferred_printers:
349 # Move the printer over to the regular registry.
485 # Move the printer over to the regular registry.
350 printer = self.deferred_printers.pop(key)
486 printer = self.deferred_printers.pop(key)
351 self.type_printers[cls] = printer
487 self.type_printers[cls] = printer
352 return printer
488 return True
489 return False
353
490
354
491
355 class PlainTextFormatter(BaseFormatter):
492 class PlainTextFormatter(BaseFormatter):
356 """The default pretty-printer.
493 """The default pretty-printer.
357
494
358 This uses :mod:`IPython.lib.pretty` to compute the format data of
495 This uses :mod:`IPython.lib.pretty` to compute the format data of
359 the object. If the object cannot be pretty printed, :func:`repr` is used.
496 the object. If the object cannot be pretty printed, :func:`repr` is used.
360 See the documentation of :mod:`IPython.lib.pretty` for details on
497 See the documentation of :mod:`IPython.lib.pretty` for details on
361 how to write pretty printers. Here is a simple example::
498 how to write pretty printers. Here is a simple example::
362
499
363 def dtype_pprinter(obj, p, cycle):
500 def dtype_pprinter(obj, p, cycle):
364 if cycle:
501 if cycle:
365 return p.text('dtype(...)')
502 return p.text('dtype(...)')
366 if hasattr(obj, 'fields'):
503 if hasattr(obj, 'fields'):
367 if obj.fields is None:
504 if obj.fields is None:
368 p.text(repr(obj))
505 p.text(repr(obj))
369 else:
506 else:
370 p.begin_group(7, 'dtype([')
507 p.begin_group(7, 'dtype([')
371 for i, field in enumerate(obj.descr):
508 for i, field in enumerate(obj.descr):
372 if i > 0:
509 if i > 0:
373 p.text(',')
510 p.text(',')
374 p.breakable()
511 p.breakable()
375 p.pretty(field)
512 p.pretty(field)
376 p.end_group(7, '])')
513 p.end_group(7, '])')
377 """
514 """
378
515
379 # The format type of data returned.
516 # The format type of data returned.
380 format_type = Unicode('text/plain')
517 format_type = Unicode('text/plain')
381
518
382 # This subclass ignores this attribute as it always need to return
519 # This subclass ignores this attribute as it always need to return
383 # something.
520 # something.
384 enabled = Bool(True, config=False)
521 enabled = Bool(True, config=False)
385
522
386 # Look for a _repr_pretty_ methods to use for pretty printing.
523 # Look for a _repr_pretty_ methods to use for pretty printing.
387 print_method = ObjectName('_repr_pretty_')
524 print_method = ObjectName('_repr_pretty_')
388
525
389 # Whether to pretty-print or not.
526 # Whether to pretty-print or not.
390 pprint = Bool(True, config=True)
527 pprint = Bool(True, config=True)
391
528
392 # Whether to be verbose or not.
529 # Whether to be verbose or not.
393 verbose = Bool(False, config=True)
530 verbose = Bool(False, config=True)
394
531
395 # The maximum width.
532 # The maximum width.
396 max_width = Integer(79, config=True)
533 max_width = Integer(79, config=True)
397
534
398 # The newline character.
535 # The newline character.
399 newline = Unicode('\n', config=True)
536 newline = Unicode('\n', config=True)
400
537
401 # format-string for pprinting floats
538 # format-string for pprinting floats
402 float_format = Unicode('%r')
539 float_format = Unicode('%r')
403 # setter for float precision, either int or direct format-string
540 # setter for float precision, either int or direct format-string
404 float_precision = CUnicode('', config=True)
541 float_precision = CUnicode('', config=True)
405
542
406 def _float_precision_changed(self, name, old, new):
543 def _float_precision_changed(self, name, old, new):
407 """float_precision changed, set float_format accordingly.
544 """float_precision changed, set float_format accordingly.
408
545
409 float_precision can be set by int or str.
546 float_precision can be set by int or str.
410 This will set float_format, after interpreting input.
547 This will set float_format, after interpreting input.
411 If numpy has been imported, numpy print precision will also be set.
548 If numpy has been imported, numpy print precision will also be set.
412
549
413 integer `n` sets format to '%.nf', otherwise, format set directly.
550 integer `n` sets format to '%.nf', otherwise, format set directly.
414
551
415 An empty string returns to defaults (repr for float, 8 for numpy).
552 An empty string returns to defaults (repr for float, 8 for numpy).
416
553
417 This parameter can be set via the '%precision' magic.
554 This parameter can be set via the '%precision' magic.
418 """
555 """
419
556
420 if '%' in new:
557 if '%' in new:
421 # got explicit format string
558 # got explicit format string
422 fmt = new
559 fmt = new
423 try:
560 try:
424 fmt%3.14159
561 fmt%3.14159
425 except Exception:
562 except Exception:
426 raise ValueError("Precision must be int or format string, not %r"%new)
563 raise ValueError("Precision must be int or format string, not %r"%new)
427 elif new:
564 elif new:
428 # otherwise, should be an int
565 # otherwise, should be an int
429 try:
566 try:
430 i = int(new)
567 i = int(new)
431 assert i >= 0
568 assert i >= 0
432 except ValueError:
569 except ValueError:
433 raise ValueError("Precision must be int or format string, not %r"%new)
570 raise ValueError("Precision must be int or format string, not %r"%new)
434 except AssertionError:
571 except AssertionError:
435 raise ValueError("int precision must be non-negative, not %r"%i)
572 raise ValueError("int precision must be non-negative, not %r"%i)
436
573
437 fmt = '%%.%if'%i
574 fmt = '%%.%if'%i
438 if 'numpy' in sys.modules:
575 if 'numpy' in sys.modules:
439 # set numpy precision if it has been imported
576 # set numpy precision if it has been imported
440 import numpy
577 import numpy
441 numpy.set_printoptions(precision=i)
578 numpy.set_printoptions(precision=i)
442 else:
579 else:
443 # default back to repr
580 # default back to repr
444 fmt = '%r'
581 fmt = '%r'
445 if 'numpy' in sys.modules:
582 if 'numpy' in sys.modules:
446 import numpy
583 import numpy
447 # numpy default is 8
584 # numpy default is 8
448 numpy.set_printoptions(precision=8)
585 numpy.set_printoptions(precision=8)
449 self.float_format = fmt
586 self.float_format = fmt
450
587
451 # Use the default pretty printers from IPython.lib.pretty.
588 # Use the default pretty printers from IPython.lib.pretty.
452 def _singleton_printers_default(self):
589 def _singleton_printers_default(self):
453 return pretty._singleton_pprinters.copy()
590 return pretty._singleton_pprinters.copy()
454
591
455 def _type_printers_default(self):
592 def _type_printers_default(self):
456 d = pretty._type_pprinters.copy()
593 d = pretty._type_pprinters.copy()
457 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
594 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
458 return d
595 return d
459
596
460 def _deferred_printers_default(self):
597 def _deferred_printers_default(self):
461 return pretty._deferred_type_pprinters.copy()
598 return pretty._deferred_type_pprinters.copy()
462
599
463 #### FormatterABC interface ####
600 #### FormatterABC interface ####
464
601
465 def __call__(self, obj):
602 def __call__(self, obj):
466 """Compute the pretty representation of the object."""
603 """Compute the pretty representation of the object."""
467 if not self.pprint:
604 if not self.pprint:
468 return pretty._safe_repr(obj)
605 return pretty._safe_repr(obj)
469 else:
606 else:
470 # This uses use StringIO, as cStringIO doesn't handle unicode.
607 # This uses use StringIO, as cStringIO doesn't handle unicode.
471 stream = StringIO()
608 stream = StringIO()
472 # self.newline.encode() is a quick fix for issue gh-597. We need to
609 # 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,
610 # ensure that stream does not get a mix of unicode and bytestrings,
474 # or it will cause trouble.
611 # or it will cause trouble.
475 printer = pretty.RepresentationPrinter(stream, self.verbose,
612 printer = pretty.RepresentationPrinter(stream, self.verbose,
476 self.max_width, unicode_to_str(self.newline),
613 self.max_width, unicode_to_str(self.newline),
477 singleton_pprinters=self.singleton_printers,
614 singleton_pprinters=self.singleton_printers,
478 type_pprinters=self.type_printers,
615 type_pprinters=self.type_printers,
479 deferred_pprinters=self.deferred_printers)
616 deferred_pprinters=self.deferred_printers)
480 printer.pretty(obj)
617 printer.pretty(obj)
481 printer.flush()
618 printer.flush()
482 return stream.getvalue()
619 return stream.getvalue()
483
620
484
621
485 class HTMLFormatter(BaseFormatter):
622 class HTMLFormatter(BaseFormatter):
486 """An HTML formatter.
623 """An HTML formatter.
487
624
488 To define the callables that compute the HTML representation of your
625 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`
626 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
627 or :meth:`for_type_by_name` methods to register functions that handle
491 this.
628 this.
492
629
493 The return value of this formatter should be a valid HTML snippet that
630 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
631 could be injected into an existing DOM. It should *not* include the
495 ```<html>`` or ```<body>`` tags.
632 ```<html>`` or ```<body>`` tags.
496 """
633 """
497 format_type = Unicode('text/html')
634 format_type = Unicode('text/html')
498
635
499 print_method = ObjectName('_repr_html_')
636 print_method = ObjectName('_repr_html_')
500
637
501
638
502 class SVGFormatter(BaseFormatter):
639 class SVGFormatter(BaseFormatter):
503 """An SVG formatter.
640 """An SVG formatter.
504
641
505 To define the callables that compute the SVG representation of your
642 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`
643 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
644 or :meth:`for_type_by_name` methods to register functions that handle
508 this.
645 this.
509
646
510 The return value of this formatter should be valid SVG enclosed in
647 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
648 ```<svg>``` tags, that could be injected into an existing DOM. It should
512 *not* include the ```<html>`` or ```<body>`` tags.
649 *not* include the ```<html>`` or ```<body>`` tags.
513 """
650 """
514 format_type = Unicode('image/svg+xml')
651 format_type = Unicode('image/svg+xml')
515
652
516 print_method = ObjectName('_repr_svg_')
653 print_method = ObjectName('_repr_svg_')
517
654
518
655
519 class PNGFormatter(BaseFormatter):
656 class PNGFormatter(BaseFormatter):
520 """A PNG formatter.
657 """A PNG formatter.
521
658
522 To define the callables that compute the PNG representation of your
659 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`
660 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
661 or :meth:`for_type_by_name` methods to register functions that handle
525 this.
662 this.
526
663
527 The return value of this formatter should be raw PNG data, *not*
664 The return value of this formatter should be raw PNG data, *not*
528 base64 encoded.
665 base64 encoded.
529 """
666 """
530 format_type = Unicode('image/png')
667 format_type = Unicode('image/png')
531
668
532 print_method = ObjectName('_repr_png_')
669 print_method = ObjectName('_repr_png_')
533
670
534
671
535 class JPEGFormatter(BaseFormatter):
672 class JPEGFormatter(BaseFormatter):
536 """A JPEG formatter.
673 """A JPEG formatter.
537
674
538 To define the callables that compute the JPEG representation of your
675 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`
676 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
677 or :meth:`for_type_by_name` methods to register functions that handle
541 this.
678 this.
542
679
543 The return value of this formatter should be raw JPEG data, *not*
680 The return value of this formatter should be raw JPEG data, *not*
544 base64 encoded.
681 base64 encoded.
545 """
682 """
546 format_type = Unicode('image/jpeg')
683 format_type = Unicode('image/jpeg')
547
684
548 print_method = ObjectName('_repr_jpeg_')
685 print_method = ObjectName('_repr_jpeg_')
549
686
550
687
551 class LatexFormatter(BaseFormatter):
688 class LatexFormatter(BaseFormatter):
552 """A LaTeX formatter.
689 """A LaTeX formatter.
553
690
554 To define the callables that compute the LaTeX representation of your
691 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`
692 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
693 or :meth:`for_type_by_name` methods to register functions that handle
557 this.
694 this.
558
695
559 The return value of this formatter should be a valid LaTeX equation,
696 The return value of this formatter should be a valid LaTeX equation,
560 enclosed in either ```$```, ```$$``` or another LaTeX equation
697 enclosed in either ```$```, ```$$``` or another LaTeX equation
561 environment.
698 environment.
562 """
699 """
563 format_type = Unicode('text/latex')
700 format_type = Unicode('text/latex')
564
701
565 print_method = ObjectName('_repr_latex_')
702 print_method = ObjectName('_repr_latex_')
566
703
567
704
568 class JSONFormatter(BaseFormatter):
705 class JSONFormatter(BaseFormatter):
569 """A JSON string formatter.
706 """A JSON string formatter.
570
707
571 To define the callables that compute the JSON string representation of
708 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`
709 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
710 or :meth:`for_type_by_name` methods to register functions that handle
574 this.
711 this.
575
712
576 The return value of this formatter should be a valid JSON string.
713 The return value of this formatter should be a valid JSON string.
577 """
714 """
578 format_type = Unicode('application/json')
715 format_type = Unicode('application/json')
579
716
580 print_method = ObjectName('_repr_json_')
717 print_method = ObjectName('_repr_json_')
581
718
582
719
583 class JavascriptFormatter(BaseFormatter):
720 class JavascriptFormatter(BaseFormatter):
584 """A Javascript formatter.
721 """A Javascript formatter.
585
722
586 To define the callables that compute the Javascript representation of
723 To define the callables that compute the Javascript representation of
587 your objects, define a :meth:`_repr_javascript_` method or use the
724 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
725 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
589 that handle this.
726 that handle this.
590
727
591 The return value of this formatter should be valid Javascript code and
728 The return value of this formatter should be valid Javascript code and
592 should *not* be enclosed in ```<script>``` tags.
729 should *not* be enclosed in ```<script>``` tags.
593 """
730 """
594 format_type = Unicode('application/javascript')
731 format_type = Unicode('application/javascript')
595
732
596 print_method = ObjectName('_repr_javascript_')
733 print_method = ObjectName('_repr_javascript_')
597
734
598 FormatterABC.register(BaseFormatter)
735 FormatterABC.register(BaseFormatter)
599 FormatterABC.register(PlainTextFormatter)
736 FormatterABC.register(PlainTextFormatter)
600 FormatterABC.register(HTMLFormatter)
737 FormatterABC.register(HTMLFormatter)
601 FormatterABC.register(SVGFormatter)
738 FormatterABC.register(SVGFormatter)
602 FormatterABC.register(PNGFormatter)
739 FormatterABC.register(PNGFormatter)
603 FormatterABC.register(JPEGFormatter)
740 FormatterABC.register(JPEGFormatter)
604 FormatterABC.register(LatexFormatter)
741 FormatterABC.register(LatexFormatter)
605 FormatterABC.register(JSONFormatter)
742 FormatterABC.register(JSONFormatter)
606 FormatterABC.register(JavascriptFormatter)
743 FormatterABC.register(JavascriptFormatter)
607
744
608
745
609 def format_display_data(obj, include=None, exclude=None):
746 def format_display_data(obj, include=None, exclude=None):
610 """Return a format data dict for an object.
747 """Return a format data dict for an object.
611
748
612 By default all format types will be computed.
749 By default all format types will be computed.
613
750
614 The following MIME types are currently implemented:
751 The following MIME types are currently implemented:
615
752
616 * text/plain
753 * text/plain
617 * text/html
754 * text/html
618 * text/latex
755 * text/latex
619 * application/json
756 * application/json
620 * application/javascript
757 * application/javascript
621 * image/png
758 * image/png
622 * image/jpeg
759 * image/jpeg
623 * image/svg+xml
760 * image/svg+xml
624
761
625 Parameters
762 Parameters
626 ----------
763 ----------
627 obj : object
764 obj : object
628 The Python object whose format data will be computed.
765 The Python object whose format data will be computed.
629
766
630 Returns
767 Returns
631 -------
768 -------
632 format_dict : dict
769 format_dict : dict
633 A dictionary of key/value pairs, one or each format that was
770 A dictionary of key/value pairs, one or each format that was
634 generated for the object. The keys are the format types, which
771 generated for the object. The keys are the format types, which
635 will usually be MIME type strings and the values and JSON'able
772 will usually be MIME type strings and the values and JSON'able
636 data structure containing the raw data for the representation in
773 data structure containing the raw data for the representation in
637 that format.
774 that format.
638 include : list or tuple, optional
775 include : list or tuple, optional
639 A list of format type strings (MIME types) to include in the
776 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
777 format data dict. If this is set *only* the format types included
641 in this list will be computed.
778 in this list will be computed.
642 exclude : list or tuple, optional
779 exclude : list or tuple, optional
643 A list of format type string (MIME types) to exclue in the format
780 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,
781 data dict. If this is set all format types will be computed,
645 except for those included in this argument.
782 except for those included in this argument.
646 """
783 """
647 from IPython.core.interactiveshell import InteractiveShell
784 from IPython.core.interactiveshell import InteractiveShell
648
785
649 InteractiveShell.instance().display_formatter.format(
786 InteractiveShell.instance().display_formatter.format(
650 obj,
787 obj,
651 include,
788 include,
652 exclude
789 exclude
653 )
790 )
654
791
@@ -1,342 +1,342 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities.
2 """Pylab (matplotlib) support utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Fernando Perez.
7 * Fernando Perez.
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2009 The IPython Development Team
13 # Copyright (C) 2009 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
22
23 import sys
23 import sys
24 from io import BytesIO
24 from io import BytesIO
25
25
26 from IPython.core.display import _pngxy
26 from IPython.core.display import _pngxy
27 from IPython.utils.decorators import flag_calls
27 from IPython.utils.decorators import flag_calls
28
28
29 # If user specifies a GUI, that dictates the backend, otherwise we read the
29 # If user specifies a GUI, that dictates the backend, otherwise we read the
30 # user's mpl default from the mpl rc structure
30 # user's mpl default from the mpl rc structure
31 backends = {'tk': 'TkAgg',
31 backends = {'tk': 'TkAgg',
32 'gtk': 'GTKAgg',
32 'gtk': 'GTKAgg',
33 'gtk3': 'GTK3Agg',
33 'gtk3': 'GTK3Agg',
34 'wx': 'WXAgg',
34 'wx': 'WXAgg',
35 'qt': 'Qt4Agg', # qt3 not supported
35 'qt': 'Qt4Agg', # qt3 not supported
36 'qt4': 'Qt4Agg',
36 'qt4': 'Qt4Agg',
37 'osx': 'MacOSX',
37 'osx': 'MacOSX',
38 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
38 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
39
39
40 # We also need a reverse backends2guis mapping that will properly choose which
40 # We also need a reverse backends2guis mapping that will properly choose which
41 # GUI support to activate based on the desired matplotlib backend. For the
41 # GUI support to activate based on the desired matplotlib backend. For the
42 # most part it's just a reverse of the above dict, but we also need to add a
42 # most part it's just a reverse of the above dict, but we also need to add a
43 # few others that map to the same GUI manually:
43 # few others that map to the same GUI manually:
44 backend2gui = dict(zip(backends.values(), backends.keys()))
44 backend2gui = dict(zip(backends.values(), backends.keys()))
45 # Our tests expect backend2gui to just return 'qt'
45 # Our tests expect backend2gui to just return 'qt'
46 backend2gui['Qt4Agg'] = 'qt'
46 backend2gui['Qt4Agg'] = 'qt'
47 # In the reverse mapping, there are a few extra valid matplotlib backends that
47 # In the reverse mapping, there are a few extra valid matplotlib backends that
48 # map to the same GUI support
48 # map to the same GUI support
49 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
49 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
50 backend2gui['GTK3Cairo'] = 'gtk3'
50 backend2gui['GTK3Cairo'] = 'gtk3'
51 backend2gui['WX'] = 'wx'
51 backend2gui['WX'] = 'wx'
52 backend2gui['CocoaAgg'] = 'osx'
52 backend2gui['CocoaAgg'] = 'osx'
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Matplotlib utilities
55 # Matplotlib utilities
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58
58
59 def getfigs(*fig_nums):
59 def getfigs(*fig_nums):
60 """Get a list of matplotlib figures by figure numbers.
60 """Get a list of matplotlib figures by figure numbers.
61
61
62 If no arguments are given, all available figures are returned. If the
62 If no arguments are given, all available figures are returned. If the
63 argument list contains references to invalid figures, a warning is printed
63 argument list contains references to invalid figures, a warning is printed
64 but the function continues pasting further figures.
64 but the function continues pasting further figures.
65
65
66 Parameters
66 Parameters
67 ----------
67 ----------
68 figs : tuple
68 figs : tuple
69 A tuple of ints giving the figure numbers of the figures to return.
69 A tuple of ints giving the figure numbers of the figures to return.
70 """
70 """
71 from matplotlib._pylab_helpers import Gcf
71 from matplotlib._pylab_helpers import Gcf
72 if not fig_nums:
72 if not fig_nums:
73 fig_managers = Gcf.get_all_fig_managers()
73 fig_managers = Gcf.get_all_fig_managers()
74 return [fm.canvas.figure for fm in fig_managers]
74 return [fm.canvas.figure for fm in fig_managers]
75 else:
75 else:
76 figs = []
76 figs = []
77 for num in fig_nums:
77 for num in fig_nums:
78 f = Gcf.figs.get(num)
78 f = Gcf.figs.get(num)
79 if f is None:
79 if f is None:
80 print('Warning: figure %s not available.' % num)
80 print('Warning: figure %s not available.' % num)
81 else:
81 else:
82 figs.append(f.canvas.figure)
82 figs.append(f.canvas.figure)
83 return figs
83 return figs
84
84
85
85
86 def figsize(sizex, sizey):
86 def figsize(sizex, sizey):
87 """Set the default figure size to be [sizex, sizey].
87 """Set the default figure size to be [sizex, sizey].
88
88
89 This is just an easy to remember, convenience wrapper that sets::
89 This is just an easy to remember, convenience wrapper that sets::
90
90
91 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
91 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
92 """
92 """
93 import matplotlib
93 import matplotlib
94 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
94 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
95
95
96
96
97 def print_figure(fig, fmt='png'):
97 def print_figure(fig, fmt='png'):
98 """Convert a figure to svg or png for inline display."""
98 """Convert a figure to svg or png for inline display."""
99 from matplotlib import rcParams
99 from matplotlib import rcParams
100 # When there's an empty figure, we shouldn't return anything, otherwise we
100 # When there's an empty figure, we shouldn't return anything, otherwise we
101 # get big blank areas in the qt console.
101 # get big blank areas in the qt console.
102 if not fig.axes and not fig.lines:
102 if not fig.axes and not fig.lines:
103 return
103 return
104
104
105 fc = fig.get_facecolor()
105 fc = fig.get_facecolor()
106 ec = fig.get_edgecolor()
106 ec = fig.get_edgecolor()
107 bytes_io = BytesIO()
107 bytes_io = BytesIO()
108 dpi = rcParams['savefig.dpi']
108 dpi = rcParams['savefig.dpi']
109 if fmt == 'retina':
109 if fmt == 'retina':
110 dpi = dpi * 2
110 dpi = dpi * 2
111 fmt = 'png'
111 fmt = 'png'
112 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
112 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
113 facecolor=fc, edgecolor=ec, dpi=dpi)
113 facecolor=fc, edgecolor=ec, dpi=dpi)
114 data = bytes_io.getvalue()
114 data = bytes_io.getvalue()
115 return data
115 return data
116
116
117 def retina_figure(fig):
117 def retina_figure(fig):
118 """format a figure as a pixel-doubled (retina) PNG"""
118 """format a figure as a pixel-doubled (retina) PNG"""
119 pngdata = print_figure(fig, fmt='retina')
119 pngdata = print_figure(fig, fmt='retina')
120 w, h = _pngxy(pngdata)
120 w, h = _pngxy(pngdata)
121 metadata = dict(width=w//2, height=h//2)
121 metadata = dict(width=w//2, height=h//2)
122 return pngdata, metadata
122 return pngdata, metadata
123
123
124 # We need a little factory function here to create the closure where
124 # We need a little factory function here to create the closure where
125 # safe_execfile can live.
125 # safe_execfile can live.
126 def mpl_runner(safe_execfile):
126 def mpl_runner(safe_execfile):
127 """Factory to return a matplotlib-enabled runner for %run.
127 """Factory to return a matplotlib-enabled runner for %run.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 safe_execfile : function
131 safe_execfile : function
132 This must be a function with the same interface as the
132 This must be a function with the same interface as the
133 :meth:`safe_execfile` method of IPython.
133 :meth:`safe_execfile` method of IPython.
134
134
135 Returns
135 Returns
136 -------
136 -------
137 A function suitable for use as the ``runner`` argument of the %run magic
137 A function suitable for use as the ``runner`` argument of the %run magic
138 function.
138 function.
139 """
139 """
140
140
141 def mpl_execfile(fname,*where,**kw):
141 def mpl_execfile(fname,*where,**kw):
142 """matplotlib-aware wrapper around safe_execfile.
142 """matplotlib-aware wrapper around safe_execfile.
143
143
144 Its interface is identical to that of the :func:`execfile` builtin.
144 Its interface is identical to that of the :func:`execfile` builtin.
145
145
146 This is ultimately a call to execfile(), but wrapped in safeties to
146 This is ultimately a call to execfile(), but wrapped in safeties to
147 properly handle interactive rendering."""
147 properly handle interactive rendering."""
148
148
149 import matplotlib
149 import matplotlib
150 import matplotlib.pylab as pylab
150 import matplotlib.pylab as pylab
151
151
152 #print '*** Matplotlib runner ***' # dbg
152 #print '*** Matplotlib runner ***' # dbg
153 # turn off rendering until end of script
153 # turn off rendering until end of script
154 is_interactive = matplotlib.rcParams['interactive']
154 is_interactive = matplotlib.rcParams['interactive']
155 matplotlib.interactive(False)
155 matplotlib.interactive(False)
156 safe_execfile(fname,*where,**kw)
156 safe_execfile(fname,*where,**kw)
157 matplotlib.interactive(is_interactive)
157 matplotlib.interactive(is_interactive)
158 # make rendering call now, if the user tried to do it
158 # make rendering call now, if the user tried to do it
159 if pylab.draw_if_interactive.called:
159 if pylab.draw_if_interactive.called:
160 pylab.draw()
160 pylab.draw()
161 pylab.draw_if_interactive.called = False
161 pylab.draw_if_interactive.called = False
162
162
163 return mpl_execfile
163 return mpl_execfile
164
164
165
165
166 def select_figure_format(shell, fmt):
166 def select_figure_format(shell, fmt):
167 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
167 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
168
168
169 Using this method ensures only one figure format is active at a time.
169 Using this method ensures only one figure format is active at a time.
170 """
170 """
171 from matplotlib.figure import Figure
171 from matplotlib.figure import Figure
172 from IPython.kernel.zmq.pylab import backend_inline
172 from IPython.kernel.zmq.pylab import backend_inline
173
173
174 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
174 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
175 png_formatter = shell.display_formatter.formatters['image/png']
175 png_formatter = shell.display_formatter.formatters['image/png']
176
176
177 if fmt == 'png':
177 if fmt == 'png':
178 svg_formatter.type_printers.pop(Figure, None)
178 svg_formatter.pop(Figure, None)
179 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
179 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
180 elif fmt in ('png2x', 'retina'):
180 elif fmt in ('png2x', 'retina'):
181 svg_formatter.type_printers.pop(Figure, None)
181 svg_formatter.pop(Figure, None)
182 png_formatter.for_type(Figure, retina_figure)
182 png_formatter.for_type(Figure, retina_figure)
183 elif fmt == 'svg':
183 elif fmt == 'svg':
184 png_formatter.type_printers.pop(Figure, None)
184 png_formatter.pop(Figure, None)
185 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
185 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
186 else:
186 else:
187 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
187 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
188
188
189 # set the format to be used in the backend()
189 # set the format to be used in the backend()
190 backend_inline._figure_format = fmt
190 backend_inline._figure_format = fmt
191
191
192 #-----------------------------------------------------------------------------
192 #-----------------------------------------------------------------------------
193 # Code for initializing matplotlib and importing pylab
193 # Code for initializing matplotlib and importing pylab
194 #-----------------------------------------------------------------------------
194 #-----------------------------------------------------------------------------
195
195
196
196
197 def find_gui_and_backend(gui=None, gui_select=None):
197 def find_gui_and_backend(gui=None, gui_select=None):
198 """Given a gui string return the gui and mpl backend.
198 """Given a gui string return the gui and mpl backend.
199
199
200 Parameters
200 Parameters
201 ----------
201 ----------
202 gui : str
202 gui : str
203 Can be one of ('tk','gtk','wx','qt','qt4','inline').
203 Can be one of ('tk','gtk','wx','qt','qt4','inline').
204 gui_select : str
204 gui_select : str
205 Can be one of ('tk','gtk','wx','qt','qt4','inline').
205 Can be one of ('tk','gtk','wx','qt','qt4','inline').
206 This is any gui already selected by the shell.
206 This is any gui already selected by the shell.
207
207
208 Returns
208 Returns
209 -------
209 -------
210 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
210 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
211 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
211 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
212 """
212 """
213
213
214 import matplotlib
214 import matplotlib
215
215
216 if gui and gui != 'auto':
216 if gui and gui != 'auto':
217 # select backend based on requested gui
217 # select backend based on requested gui
218 backend = backends[gui]
218 backend = backends[gui]
219 else:
219 else:
220 # We need to read the backend from the original data structure, *not*
220 # We need to read the backend from the original data structure, *not*
221 # from mpl.rcParams, since a prior invocation of %matplotlib may have
221 # from mpl.rcParams, since a prior invocation of %matplotlib may have
222 # overwritten that.
222 # overwritten that.
223 # WARNING: this assumes matplotlib 1.1 or newer!!
223 # WARNING: this assumes matplotlib 1.1 or newer!!
224 backend = matplotlib.rcParamsOrig['backend']
224 backend = matplotlib.rcParamsOrig['backend']
225 # In this case, we need to find what the appropriate gui selection call
225 # In this case, we need to find what the appropriate gui selection call
226 # should be for IPython, so we can activate inputhook accordingly
226 # should be for IPython, so we can activate inputhook accordingly
227 gui = backend2gui.get(backend, None)
227 gui = backend2gui.get(backend, None)
228
228
229 # If we have already had a gui active, we need it and inline are the
229 # If we have already had a gui active, we need it and inline are the
230 # ones allowed.
230 # ones allowed.
231 if gui_select and gui != gui_select:
231 if gui_select and gui != gui_select:
232 gui = gui_select
232 gui = gui_select
233 backend = backends[gui]
233 backend = backends[gui]
234
234
235 return gui, backend
235 return gui, backend
236
236
237
237
238 def activate_matplotlib(backend):
238 def activate_matplotlib(backend):
239 """Activate the given backend and set interactive to True."""
239 """Activate the given backend and set interactive to True."""
240
240
241 import matplotlib
241 import matplotlib
242 matplotlib.interactive(True)
242 matplotlib.interactive(True)
243
243
244 # Matplotlib had a bug where even switch_backend could not force
244 # Matplotlib had a bug where even switch_backend could not force
245 # the rcParam to update. This needs to be set *before* the module
245 # the rcParam to update. This needs to be set *before* the module
246 # magic of switch_backend().
246 # magic of switch_backend().
247 matplotlib.rcParams['backend'] = backend
247 matplotlib.rcParams['backend'] = backend
248
248
249 import matplotlib.pyplot
249 import matplotlib.pyplot
250 matplotlib.pyplot.switch_backend(backend)
250 matplotlib.pyplot.switch_backend(backend)
251
251
252 # This must be imported last in the matplotlib series, after
252 # This must be imported last in the matplotlib series, after
253 # backend/interactivity choices have been made
253 # backend/interactivity choices have been made
254 import matplotlib.pylab as pylab
254 import matplotlib.pylab as pylab
255
255
256 pylab.show._needmain = False
256 pylab.show._needmain = False
257 # We need to detect at runtime whether show() is called by the user.
257 # We need to detect at runtime whether show() is called by the user.
258 # For this, we wrap it into a decorator which adds a 'called' flag.
258 # For this, we wrap it into a decorator which adds a 'called' flag.
259 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
259 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
260
260
261
261
262 def import_pylab(user_ns, import_all=True):
262 def import_pylab(user_ns, import_all=True):
263 """Populate the namespace with pylab-related values.
263 """Populate the namespace with pylab-related values.
264
264
265 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
265 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
266
266
267 Also imports a few names from IPython (figsize, display, getfigs)
267 Also imports a few names from IPython (figsize, display, getfigs)
268
268
269 """
269 """
270
270
271 # Import numpy as np/pyplot as plt are conventions we're trying to
271 # Import numpy as np/pyplot as plt are conventions we're trying to
272 # somewhat standardize on. Making them available to users by default
272 # somewhat standardize on. Making them available to users by default
273 # will greatly help this.
273 # will greatly help this.
274 s = ("import numpy\n"
274 s = ("import numpy\n"
275 "import matplotlib\n"
275 "import matplotlib\n"
276 "from matplotlib import pylab, mlab, pyplot\n"
276 "from matplotlib import pylab, mlab, pyplot\n"
277 "np = numpy\n"
277 "np = numpy\n"
278 "plt = pyplot\n"
278 "plt = pyplot\n"
279 )
279 )
280 exec(s, user_ns)
280 exec(s, user_ns)
281
281
282 if import_all:
282 if import_all:
283 s = ("from matplotlib.pylab import *\n"
283 s = ("from matplotlib.pylab import *\n"
284 "from numpy import *\n")
284 "from numpy import *\n")
285 exec(s, user_ns)
285 exec(s, user_ns)
286
286
287 # IPython symbols to add
287 # IPython symbols to add
288 user_ns['figsize'] = figsize
288 user_ns['figsize'] = figsize
289 from IPython.core.display import display
289 from IPython.core.display import display
290 # Add display and getfigs to the user's namespace
290 # Add display and getfigs to the user's namespace
291 user_ns['display'] = display
291 user_ns['display'] = display
292 user_ns['getfigs'] = getfigs
292 user_ns['getfigs'] = getfigs
293
293
294
294
295 def configure_inline_support(shell, backend):
295 def configure_inline_support(shell, backend):
296 """Configure an IPython shell object for matplotlib use.
296 """Configure an IPython shell object for matplotlib use.
297
297
298 Parameters
298 Parameters
299 ----------
299 ----------
300 shell : InteractiveShell instance
300 shell : InteractiveShell instance
301
301
302 backend : matplotlib backend
302 backend : matplotlib backend
303 """
303 """
304 # If using our svg payload backend, register the post-execution
304 # If using our svg payload backend, register the post-execution
305 # function that will pick up the results for display. This can only be
305 # function that will pick up the results for display. This can only be
306 # done with access to the real shell object.
306 # done with access to the real shell object.
307
307
308 # Note: if we can't load the inline backend, then there's no point
308 # Note: if we can't load the inline backend, then there's no point
309 # continuing (such as in terminal-only shells in environments without
309 # continuing (such as in terminal-only shells in environments without
310 # zeromq available).
310 # zeromq available).
311 try:
311 try:
312 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
312 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
313 except ImportError:
313 except ImportError:
314 return
314 return
315 from matplotlib import pyplot
315 from matplotlib import pyplot
316
316
317 cfg = InlineBackend.instance(parent=shell)
317 cfg = InlineBackend.instance(parent=shell)
318 cfg.shell = shell
318 cfg.shell = shell
319 if cfg not in shell.configurables:
319 if cfg not in shell.configurables:
320 shell.configurables.append(cfg)
320 shell.configurables.append(cfg)
321
321
322 if backend == backends['inline']:
322 if backend == backends['inline']:
323 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
323 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
324 shell.register_post_execute(flush_figures)
324 shell.register_post_execute(flush_figures)
325
325
326 # Save rcParams that will be overwrittern
326 # Save rcParams that will be overwrittern
327 shell._saved_rcParams = dict()
327 shell._saved_rcParams = dict()
328 for k in cfg.rc:
328 for k in cfg.rc:
329 shell._saved_rcParams[k] = pyplot.rcParams[k]
329 shell._saved_rcParams[k] = pyplot.rcParams[k]
330 # load inline_rc
330 # load inline_rc
331 pyplot.rcParams.update(cfg.rc)
331 pyplot.rcParams.update(cfg.rc)
332 else:
332 else:
333 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
333 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
334 if flush_figures in shell._post_execute:
334 if flush_figures in shell._post_execute:
335 shell._post_execute.pop(flush_figures)
335 shell._post_execute.pop(flush_figures)
336 if hasattr(shell, '_saved_rcParams'):
336 if hasattr(shell, '_saved_rcParams'):
337 pyplot.rcParams.update(shell._saved_rcParams)
337 pyplot.rcParams.update(shell._saved_rcParams)
338 del shell._saved_rcParams
338 del shell._saved_rcParams
339
339
340 # Setup the default figure format
340 # Setup the default figure format
341 select_figure_format(shell, cfg.figure_format)
341 select_figure_format(shell, cfg.figure_format)
342
342
@@ -1,90 +1,234 b''
1 """Tests for the Formatters.
1 """Tests for the Formatters.
2 """
2 """
3
3
4 from math import pi
4 from math import pi
5
5
6 try:
6 try:
7 import numpy
7 import numpy
8 except:
8 except:
9 numpy = None
9 numpy = None
10 import nose.tools as nt
10 import nose.tools as nt
11
11
12 from IPython.core.formatters import PlainTextFormatter
12 from IPython.core.formatters import PlainTextFormatter, _mod_name_key
13
13
14 class A(object):
14 class A(object):
15 def __repr__(self):
15 def __repr__(self):
16 return 'A()'
16 return 'A()'
17
17
18 class B(A):
18 class B(A):
19 def __repr__(self):
19 def __repr__(self):
20 return 'B()'
20 return 'B()'
21
21
22 class C:
23 pass
24
22 class BadPretty(object):
25 class BadPretty(object):
23 _repr_pretty_ = None
26 _repr_pretty_ = None
24
27
25 class GoodPretty(object):
28 class GoodPretty(object):
26 def _repr_pretty_(self, pp, cycle):
29 def _repr_pretty_(self, pp, cycle):
27 pp.text('foo')
30 pp.text('foo')
28
31
29 def __repr__(self):
32 def __repr__(self):
30 return 'GoodPretty()'
33 return 'GoodPretty()'
31
34
32 def foo_printer(obj, pp, cycle):
35 def foo_printer(obj, pp, cycle):
33 pp.text('foo')
36 pp.text('foo')
34
37
35 def test_pretty():
38 def test_pretty():
36 f = PlainTextFormatter()
39 f = PlainTextFormatter()
37 f.for_type(A, foo_printer)
40 f.for_type(A, foo_printer)
38 nt.assert_equal(f(A()), 'foo')
41 nt.assert_equal(f(A()), 'foo')
39 nt.assert_equal(f(B()), 'foo')
42 nt.assert_equal(f(B()), 'foo')
40 nt.assert_equal(f(GoodPretty()), 'foo')
43 nt.assert_equal(f(GoodPretty()), 'foo')
41 # Just don't raise an exception for the following:
44 # Just don't raise an exception for the following:
42 f(BadPretty())
45 f(BadPretty())
43
46
44 f.pprint = False
47 f.pprint = False
45 nt.assert_equal(f(A()), 'A()')
48 nt.assert_equal(f(A()), 'A()')
46 nt.assert_equal(f(B()), 'B()')
49 nt.assert_equal(f(B()), 'B()')
47 nt.assert_equal(f(GoodPretty()), 'GoodPretty()')
50 nt.assert_equal(f(GoodPretty()), 'GoodPretty()')
48
51
49
52
50 def test_deferred():
53 def test_deferred():
51 f = PlainTextFormatter()
54 f = PlainTextFormatter()
52
55
53 def test_precision():
56 def test_precision():
54 """test various values for float_precision."""
57 """test various values for float_precision."""
55 f = PlainTextFormatter()
58 f = PlainTextFormatter()
56 nt.assert_equal(f(pi), repr(pi))
59 nt.assert_equal(f(pi), repr(pi))
57 f.float_precision = 0
60 f.float_precision = 0
58 if numpy:
61 if numpy:
59 po = numpy.get_printoptions()
62 po = numpy.get_printoptions()
60 nt.assert_equal(po['precision'], 0)
63 nt.assert_equal(po['precision'], 0)
61 nt.assert_equal(f(pi), '3')
64 nt.assert_equal(f(pi), '3')
62 f.float_precision = 2
65 f.float_precision = 2
63 if numpy:
66 if numpy:
64 po = numpy.get_printoptions()
67 po = numpy.get_printoptions()
65 nt.assert_equal(po['precision'], 2)
68 nt.assert_equal(po['precision'], 2)
66 nt.assert_equal(f(pi), '3.14')
69 nt.assert_equal(f(pi), '3.14')
67 f.float_precision = '%g'
70 f.float_precision = '%g'
68 if numpy:
71 if numpy:
69 po = numpy.get_printoptions()
72 po = numpy.get_printoptions()
70 nt.assert_equal(po['precision'], 2)
73 nt.assert_equal(po['precision'], 2)
71 nt.assert_equal(f(pi), '3.14159')
74 nt.assert_equal(f(pi), '3.14159')
72 f.float_precision = '%e'
75 f.float_precision = '%e'
73 nt.assert_equal(f(pi), '3.141593e+00')
76 nt.assert_equal(f(pi), '3.141593e+00')
74 f.float_precision = ''
77 f.float_precision = ''
75 if numpy:
78 if numpy:
76 po = numpy.get_printoptions()
79 po = numpy.get_printoptions()
77 nt.assert_equal(po['precision'], 8)
80 nt.assert_equal(po['precision'], 8)
78 nt.assert_equal(f(pi), repr(pi))
81 nt.assert_equal(f(pi), repr(pi))
79
82
80 def test_bad_precision():
83 def test_bad_precision():
81 """test various invalid values for float_precision."""
84 """test various invalid values for float_precision."""
82 f = PlainTextFormatter()
85 f = PlainTextFormatter()
83 def set_fp(p):
86 def set_fp(p):
84 f.float_precision=p
87 f.float_precision=p
85 nt.assert_raises(ValueError, set_fp, '%')
88 nt.assert_raises(ValueError, set_fp, '%')
86 nt.assert_raises(ValueError, set_fp, '%.3f%i')
89 nt.assert_raises(ValueError, set_fp, '%.3f%i')
87 nt.assert_raises(ValueError, set_fp, 'foo')
90 nt.assert_raises(ValueError, set_fp, 'foo')
88 nt.assert_raises(ValueError, set_fp, -1)
91 nt.assert_raises(ValueError, set_fp, -1)
89
92
93 def test_for_type():
94 f = PlainTextFormatter()
95
96 # initial return, None
97 nt.assert_is(f.for_type(C, foo_printer), None)
98 # no func queries
99 nt.assert_is(f.for_type(C), foo_printer)
100 # shouldn't change anything
101 nt.assert_is(f.for_type(C), foo_printer)
102 # None should do the same
103 nt.assert_is(f.for_type(C, None), foo_printer)
104 nt.assert_is(f.for_type(C, None), foo_printer)
105
106 def test_for_type_string():
107 f = PlainTextFormatter()
108
109 mod = C.__module__
110
111 type_str = '%s.%s' % (C.__module__, 'C')
112
113 # initial return, None
114 nt.assert_is(f.for_type(type_str, foo_printer), None)
115 # no func queries
116 nt.assert_is(f.for_type(type_str), foo_printer)
117 nt.assert_in(_mod_name_key(C), f.deferred_printers)
118 nt.assert_is(f.for_type(C), foo_printer)
119 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
120 nt.assert_in(C, f.type_printers)
121
122 def test_for_type_by_name():
123 f = PlainTextFormatter()
124
125 mod = C.__module__
126
127 # initial return, None
128 nt.assert_is(f.for_type_by_name(mod, 'C', foo_printer), None)
129 # no func queries
130 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
131 # shouldn't change anything
132 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
133 # None should do the same
134 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
135 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
136
137 def test_lookup():
138 f = PlainTextFormatter()
139
140 f.for_type(C, foo_printer)
141 nt.assert_is(f.lookup(C()), foo_printer)
142 with nt.assert_raises(KeyError):
143 f.lookup(A())
144
145 def test_lookup_string():
146 f = PlainTextFormatter()
147 type_str = '%s.%s' % (C.__module__, 'C')
148
149 f.for_type(type_str, foo_printer)
150 nt.assert_is(f.lookup(C()), foo_printer)
151 # should move from deferred to imported dict
152 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
153 nt.assert_in(C, f.type_printers)
154
155 def test_lookup_by_type():
156 f = PlainTextFormatter()
157 f.for_type(C, foo_printer)
158 nt.assert_is(f.lookup_by_type(C), foo_printer)
159 type_str = '%s.%s' % (C.__module__, 'C')
160 with nt.assert_raises(KeyError):
161 f.lookup_by_type(A)
162
163 def test_lookup_by_type_string():
164 f = PlainTextFormatter()
165 type_str = '%s.%s' % (C.__module__, 'C')
166 f.for_type(type_str, foo_printer)
167
168 # verify insertion
169 nt.assert_in(_mod_name_key(C), f.deferred_printers)
170 nt.assert_not_in(C, f.type_printers)
171
172 nt.assert_is(f.lookup_by_type(type_str), foo_printer)
173 # lookup by string doesn't cause import
174 nt.assert_in(_mod_name_key(C), f.deferred_printers)
175 nt.assert_not_in(C, f.type_printers)
176
177 nt.assert_is(f.lookup_by_type(C), foo_printer)
178 # should move from deferred to imported dict
179 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
180 nt.assert_in(C, f.type_printers)
181
182 def test_in_formatter():
183 f = PlainTextFormatter()
184 f.for_type(C, foo_printer)
185 type_str = '%s.%s' % (C.__module__, 'C')
186 nt.assert_in(C, f)
187 nt.assert_in(type_str, f)
188
189 def test_string_in_formatter():
190 f = PlainTextFormatter()
191 type_str = '%s.%s' % (C.__module__, 'C')
192 f.for_type(type_str, foo_printer)
193 nt.assert_in(type_str, f)
194 nt.assert_in(C, f)
195
196 def test_pop():
197 f = PlainTextFormatter()
198 f.for_type(C, foo_printer)
199 nt.assert_is(f.lookup_by_type(C), foo_printer)
200 nt.assert_is(f.pop(C, None), foo_printer)
201 f.for_type(C, foo_printer)
202 nt.assert_is(f.pop(C), foo_printer)
203 with nt.assert_raises(KeyError):
204 f.lookup_by_type(C)
205 with nt.assert_raises(KeyError):
206 f.pop(C)
207 with nt.assert_raises(KeyError):
208 f.pop(A)
209 nt.assert_is(f.pop(A, None), None)
210
211 def test_pop_string():
212 f = PlainTextFormatter()
213 type_str = '%s.%s' % (C.__module__, 'C')
214
215 with nt.assert_raises(KeyError):
216 f.pop(type_str)
217
218 f.for_type(type_str, foo_printer)
219 f.pop(type_str)
220 with nt.assert_raises(KeyError):
221 f.lookup_by_type(C)
222 with nt.assert_raises(KeyError):
223 f.pop(type_str)
224
225 f.for_type(C, foo_printer)
226 nt.assert_is(f.pop(type_str, None), foo_printer)
227 with nt.assert_raises(KeyError):
228 f.lookup_by_type(C)
229 with nt.assert_raises(KeyError):
230 f.pop(type_str)
231 nt.assert_is(f.pop(type_str, None), None)
232
233
90
234
General Comments 0
You need to be logged in to leave comments. Login now