##// END OF EJS Templates
warn on failed formatter calls
MinRK -
Show More
@@ -28,12 +28,15 b' import abc'
28 import sys
28 import sys
29 import warnings
29 import warnings
30
30
31 from IPython.external.decorator import decorator
32
31 # Our own imports
33 # Our own imports
32 from IPython.config.configurable import Configurable
34 from IPython.config.configurable import Configurable
33 from IPython.lib import pretty
35 from IPython.lib import pretty
34 from IPython.utils.traitlets import (
36 from IPython.utils.traitlets import (
35 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
37 Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List,
36 )
38 )
39 from IPython.utils.warn import warn
37 from IPython.utils.py3compat import (
40 from IPython.utils.py3compat import (
38 unicode_to_str, with_metaclass, PY3, string_types,
41 unicode_to_str, with_metaclass, PY3, string_types,
39 )
42 )
@@ -180,6 +183,16 b' class DisplayFormatter(Configurable):'
180 #-----------------------------------------------------------------------------
183 #-----------------------------------------------------------------------------
181
184
182
185
186 @decorator
187 def warn_format_error(method, self, *args, **kwargs):
188 """decorator for warning on failed format call"""
189 try:
190 return method(self, *args, **kwargs)
191 except Exception as e:
192 warn("Exception in %s formatter: %s" % (self.format_type, e))
193 return None
194
195
183 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
196 class FormatterABC(with_metaclass(abc.ABCMeta, object)):
184 """ Abstract base class for Formatters.
197 """ Abstract base class for Formatters.
185
198
@@ -194,17 +207,16 b' class FormatterABC(with_metaclass(abc.ABCMeta, object)):'
194
207
195 # Is the formatter enabled...
208 # Is the formatter enabled...
196 enabled = True
209 enabled = True
197
210
198 @abc.abstractmethod
211 @abc.abstractmethod
212 @warn_format_error
199 def __call__(self, obj):
213 def __call__(self, obj):
200 """Return a JSON'able representation of the object.
214 """Return a JSON'able representation of the object.
201
215
202 If the object cannot be formatted by this formatter, then return None
216 If the object cannot be formatted by this formatter,
217 warn and return None.
203 """
218 """
204 try:
219 return repr(obj)
205 return repr(obj)
206 except Exception:
207 return None
208
220
209
221
210 def _mod_name_key(typ):
222 def _mod_name_key(typ):
@@ -223,6 +235,7 b' def _get_type(obj):'
223
235
224 _raise_key_error = object()
236 _raise_key_error = object()
225
237
238
226 class BaseFormatter(Configurable):
239 class BaseFormatter(Configurable):
227 """A base formatter class that is configurable.
240 """A base formatter class that is configurable.
228
241
@@ -266,24 +279,22 b' class BaseFormatter(Configurable):'
266 # Map (modulename, classname) pairs to the format functions.
279 # Map (modulename, classname) pairs to the format functions.
267 deferred_printers = Dict(config=True)
280 deferred_printers = Dict(config=True)
268
281
282 @warn_format_error
269 def __call__(self, obj):
283 def __call__(self, obj):
270 """Compute the format for an object."""
284 """Compute the format for an object."""
271 if self.enabled:
285 if self.enabled:
286 # lookup registered printer
272 try:
287 try:
273 # lookup registered printer
288 printer = self.lookup(obj)
274 try:
289 except KeyError:
275 printer = self.lookup(obj)
276 except KeyError:
277 pass
278 else:
279 return printer(obj)
280 # Finally look for special method names
281 method = pretty._safe_getattr(obj, self.print_method, None)
282 if method is not None:
283 return method()
284 return None
285 except Exception:
286 pass
290 pass
291 else:
292 return printer(obj)
293 # Finally look for special method names
294 method = pretty._safe_getattr(obj, self.print_method, None)
295 if method is not None:
296 return method()
297 return None
287 else:
298 else:
288 return None
299 return None
289
300
@@ -599,6 +610,7 b' class PlainTextFormatter(BaseFormatter):'
599
610
600 #### FormatterABC interface ####
611 #### FormatterABC interface ####
601
612
613 @warn_format_error
602 def __call__(self, obj):
614 def __call__(self, obj):
603 """Compute the pretty representation of the object."""
615 """Compute the pretty representation of the object."""
604 if not self.pprint:
616 if not self.pprint:
@@ -1,5 +1,4 b''
1 """Tests for the Formatters.
1 """Tests for the Formatters."""
2 """
3
2
4 from math import pi
3 from math import pi
5
4
@@ -9,7 +8,8 b' except:'
9 numpy = None
8 numpy = None
10 import nose.tools as nt
9 import nose.tools as nt
11
10
12 from IPython.core.formatters import PlainTextFormatter, _mod_name_key
11 from IPython.core.formatters import PlainTextFormatter, HTMLFormatter, _mod_name_key
12 from IPython.utils.io import capture_output
13
13
14 class A(object):
14 class A(object):
15 def __repr__(self):
15 def __repr__(self):
@@ -231,4 +231,40 b' def test_pop_string():'
231 nt.assert_is(f.pop(type_str, None), None)
231 nt.assert_is(f.pop(type_str, None), None)
232
232
233
233
234 def test_warn_error_method():
235 f = HTMLFormatter()
236 class BadHTML(object):
237 def _repr_html_(self):
238 return 1/0
239 bad = BadHTML()
240 with capture_output() as captured:
241 result = f(bad)
242 nt.assert_is(result, None)
243 nt.assert_in("WARNING", captured.stderr)
244 nt.assert_in("text/html", captured.stderr)
245 nt.assert_in("zero", captured.stderr)
246
247 def test_warn_error_for_type():
248 f = HTMLFormatter()
249 f.for_type(int, lambda i: name_error)
250 with capture_output() as captured:
251 result = f(5)
252 nt.assert_is(result, None)
253 nt.assert_in("WARNING", captured.stderr)
254 nt.assert_in("text/html", captured.stderr)
255 nt.assert_in("name_error", captured.stderr)
256
257 def test_warn_error_pretty_method():
258 f = PlainTextFormatter()
259 class BadPretty(object):
260 def _repr_pretty_(self):
261 return "hello"
262 bad = BadPretty()
263 with capture_output() as captured:
264 result = f(bad)
265 nt.assert_is(result, None)
266 nt.assert_in("WARNING", captured.stderr)
267 nt.assert_in("text/plain", captured.stderr)
268 nt.assert_in("argument", captured.stderr)
269
234
270
General Comments 0
You need to be logged in to leave comments. Login now