test_formatters.py
523 lines
| 14.7 KiB
| text/x-python
|
PythonLexer
MinRK
|
r13977 | """Tests for the Formatters.""" | ||
Robert Kern
|
r3209 | |||
Min RK
|
r19557 | import warnings | ||
MinRK
|
r3350 | from math import pi | ||
try: | ||||
import numpy | ||||
except: | ||||
numpy = None | ||||
Robert Kern
|
r3209 | import nose.tools as nt | ||
Min RK
|
r19557 | from IPython import get_ipython | ||
Min RK
|
r21253 | from traitlets.config import Config | ||
Brian E. Granger
|
r15121 | from IPython.core.formatters import ( | ||
Min RK
|
r19384 | PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key, | ||
Min RK
|
r19557 | DisplayFormatter, JSONFormatter, | ||
Brian E. Granger
|
r15121 | ) | ||
MinRK
|
r13977 | from IPython.utils.io import capture_output | ||
Robert Kern
|
r3209 | |||
class A(object): | ||||
def __repr__(self): | ||||
return 'A()' | ||||
class B(A): | ||||
def __repr__(self): | ||||
return 'B()' | ||||
MinRK
|
r13781 | class C: | ||
pass | ||||
MinRK
|
r18025 | class BadRepr(object): | ||
def __repr__(self): | ||||
raise ValueError("bad repr") | ||||
Robert Kern
|
r6268 | class BadPretty(object): | ||
_repr_pretty_ = None | ||||
class GoodPretty(object): | ||||
def _repr_pretty_(self, pp, cycle): | ||||
pp.text('foo') | ||||
def __repr__(self): | ||||
return 'GoodPretty()' | ||||
Robert Kern
|
r3209 | def foo_printer(obj, pp, cycle): | ||
pp.text('foo') | ||||
def test_pretty(): | ||||
MinRK
|
r3350 | f = PlainTextFormatter() | ||
Robert Kern
|
r3209 | f.for_type(A, foo_printer) | ||
Bradley M. Froehle
|
r7875 | nt.assert_equal(f(A()), 'foo') | ||
nt.assert_equal(f(B()), 'foo') | ||||
nt.assert_equal(f(GoodPretty()), 'foo') | ||||
Robert Kern
|
r6268 | # Just don't raise an exception for the following: | ||
f(BadPretty()) | ||||
Robert Kern
|
r3209 | f.pprint = False | ||
Bradley M. Froehle
|
r7875 | nt.assert_equal(f(A()), 'A()') | ||
nt.assert_equal(f(B()), 'B()') | ||||
nt.assert_equal(f(GoodPretty()), 'GoodPretty()') | ||||
Robert Kern
|
r6268 | |||
Robert Kern
|
r3209 | |||
def test_deferred(): | ||||
MinRK
|
r3350 | f = PlainTextFormatter() | ||
def test_precision(): | ||||
"""test various values for float_precision.""" | ||||
f = PlainTextFormatter() | ||||
Bradley M. Froehle
|
r7875 | nt.assert_equal(f(pi), repr(pi)) | ||
MinRK
|
r3350 | f.float_precision = 0 | ||
if numpy: | ||||
po = numpy.get_printoptions() | ||||
Bradley M. Froehle
|
r7875 | nt.assert_equal(po['precision'], 0) | ||
nt.assert_equal(f(pi), '3') | ||||
MinRK
|
r3350 | f.float_precision = 2 | ||
if numpy: | ||||
po = numpy.get_printoptions() | ||||
Bradley M. Froehle
|
r7875 | nt.assert_equal(po['precision'], 2) | ||
nt.assert_equal(f(pi), '3.14') | ||||
MinRK
|
r3350 | f.float_precision = '%g' | ||
if numpy: | ||||
po = numpy.get_printoptions() | ||||
Bradley M. Froehle
|
r7875 | nt.assert_equal(po['precision'], 2) | ||
nt.assert_equal(f(pi), '3.14159') | ||||
MinRK
|
r3350 | f.float_precision = '%e' | ||
Bradley M. Froehle
|
r7875 | nt.assert_equal(f(pi), '3.141593e+00') | ||
MinRK
|
r3350 | f.float_precision = '' | ||
if numpy: | ||||
po = numpy.get_printoptions() | ||||
Bradley M. Froehle
|
r7875 | nt.assert_equal(po['precision'], 8) | ||
nt.assert_equal(f(pi), repr(pi)) | ||||
MinRK
|
r3350 | |||
def test_bad_precision(): | ||||
"""test various invalid values for float_precision.""" | ||||
f = PlainTextFormatter() | ||||
def set_fp(p): | ||||
f.float_precision=p | ||||
nt.assert_raises(ValueError, set_fp, '%') | ||||
nt.assert_raises(ValueError, set_fp, '%.3f%i') | ||||
nt.assert_raises(ValueError, set_fp, 'foo') | ||||
nt.assert_raises(ValueError, set_fp, -1) | ||||
MinRK
|
r13655 | def test_for_type(): | ||
f = PlainTextFormatter() | ||||
MinRK
|
r13783 | # initial return, None | ||
nt.assert_is(f.for_type(C, foo_printer), None) | ||||
MinRK
|
r13655 | # no func queries | ||
MinRK
|
r13783 | nt.assert_is(f.for_type(C), foo_printer) | ||
MinRK
|
r13655 | # shouldn't change anything | ||
MinRK
|
r13783 | nt.assert_is(f.for_type(C), foo_printer) | ||
MinRK
|
r13781 | # None should do the same | ||
MinRK
|
r13783 | nt.assert_is(f.for_type(C, None), foo_printer) | ||
nt.assert_is(f.for_type(C, None), foo_printer) | ||||
MinRK
|
r13655 | |||
MinRK
|
r13781 | def test_for_type_string(): | ||
MinRK
|
r13655 | f = PlainTextFormatter() | ||
MinRK
|
r13781 | type_str = '%s.%s' % (C.__module__, 'C') | ||
MinRK
|
r13783 | # initial return, None | ||
nt.assert_is(f.for_type(type_str, foo_printer), None) | ||||
MinRK
|
r13781 | # no func queries | ||
MinRK
|
r13783 | nt.assert_is(f.for_type(type_str), foo_printer) | ||
nt.assert_in(_mod_name_key(C), f.deferred_printers) | ||||
nt.assert_is(f.for_type(C), foo_printer) | ||||
nt.assert_not_in(_mod_name_key(C), f.deferred_printers) | ||||
nt.assert_in(C, f.type_printers) | ||||
MinRK
|
r13781 | |||
def test_for_type_by_name(): | ||||
f = PlainTextFormatter() | ||||
mod = C.__module__ | ||||
MinRK
|
r13655 | |||
MinRK
|
r13783 | # initial return, None | ||
nt.assert_is(f.for_type_by_name(mod, 'C', foo_printer), None) | ||||
MinRK
|
r13655 | # no func queries | ||
MinRK
|
r13783 | nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer) | ||
MinRK
|
r13655 | # shouldn't change anything | ||
MinRK
|
r13783 | nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer) | ||
MinRK
|
r13781 | # None should do the same | ||
MinRK
|
r13783 | nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer) | ||
nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer) | ||||
MinRK
|
r13655 | |||
MinRK
|
r13781 | def test_lookup(): | ||
f = PlainTextFormatter() | ||||
MinRK
|
r13783 | f.for_type(C, foo_printer) | ||
nt.assert_is(f.lookup(C()), foo_printer) | ||||
with nt.assert_raises(KeyError): | ||||
f.lookup(A()) | ||||
def test_lookup_string(): | ||||
f = PlainTextFormatter() | ||||
type_str = '%s.%s' % (C.__module__, 'C') | ||||
f.for_type(type_str, foo_printer) | ||||
nt.assert_is(f.lookup(C()), foo_printer) | ||||
# should move from deferred to imported dict | ||||
nt.assert_not_in(_mod_name_key(C), f.deferred_printers) | ||||
nt.assert_in(C, f.type_printers) | ||||
def test_lookup_by_type(): | ||||
f = PlainTextFormatter() | ||||
f.for_type(C, foo_printer) | ||||
nt.assert_is(f.lookup_by_type(C), foo_printer) | ||||
with nt.assert_raises(KeyError): | ||||
f.lookup_by_type(A) | ||||
def test_lookup_by_type_string(): | ||||
f = PlainTextFormatter() | ||||
type_str = '%s.%s' % (C.__module__, 'C') | ||||
f.for_type(type_str, foo_printer) | ||||
# verify insertion | ||||
nt.assert_in(_mod_name_key(C), f.deferred_printers) | ||||
nt.assert_not_in(C, f.type_printers) | ||||
MinRK
|
r13781 | |||
MinRK
|
r13788 | nt.assert_is(f.lookup_by_type(type_str), foo_printer) | ||
# lookup by string doesn't cause import | ||||
nt.assert_in(_mod_name_key(C), f.deferred_printers) | ||||
nt.assert_not_in(C, f.type_printers) | ||||
MinRK
|
r13783 | nt.assert_is(f.lookup_by_type(C), foo_printer) | ||
# should move from deferred to imported dict | ||||
nt.assert_not_in(_mod_name_key(C), f.deferred_printers) | ||||
nt.assert_in(C, f.type_printers) | ||||
MinRK
|
r13788 | def test_in_formatter(): | ||
f = PlainTextFormatter() | ||||
f.for_type(C, foo_printer) | ||||
type_str = '%s.%s' % (C.__module__, 'C') | ||||
nt.assert_in(C, f) | ||||
nt.assert_in(type_str, f) | ||||
def test_string_in_formatter(): | ||||
f = PlainTextFormatter() | ||||
type_str = '%s.%s' % (C.__module__, 'C') | ||||
f.for_type(type_str, foo_printer) | ||||
nt.assert_in(type_str, f) | ||||
nt.assert_in(C, f) | ||||
MinRK
|
r13783 | def test_pop(): | ||
f = PlainTextFormatter() | ||||
f.for_type(C, foo_printer) | ||||
nt.assert_is(f.lookup_by_type(C), foo_printer) | ||||
MinRK
|
r13788 | nt.assert_is(f.pop(C, None), foo_printer) | ||
f.for_type(C, foo_printer) | ||||
nt.assert_is(f.pop(C), foo_printer) | ||||
MinRK
|
r13783 | with nt.assert_raises(KeyError): | ||
f.lookup_by_type(C) | ||||
with nt.assert_raises(KeyError): | ||||
f.pop(C) | ||||
with nt.assert_raises(KeyError): | ||||
f.pop(A) | ||||
MinRK
|
r13788 | nt.assert_is(f.pop(A, None), None) | ||
MinRK
|
r13783 | |||
def test_pop_string(): | ||||
f = PlainTextFormatter() | ||||
MinRK
|
r13781 | type_str = '%s.%s' % (C.__module__, 'C') | ||
MinRK
|
r13783 | with nt.assert_raises(KeyError): | ||
f.pop(type_str) | ||||
f.for_type(type_str, foo_printer) | ||||
f.pop(type_str) | ||||
with nt.assert_raises(KeyError): | ||||
f.lookup_by_type(C) | ||||
with nt.assert_raises(KeyError): | ||||
f.pop(type_str) | ||||
f.for_type(C, foo_printer) | ||||
MinRK
|
r13788 | nt.assert_is(f.pop(type_str, None), foo_printer) | ||
MinRK
|
r13783 | with nt.assert_raises(KeyError): | ||
f.lookup_by_type(C) | ||||
with nt.assert_raises(KeyError): | ||||
f.pop(type_str) | ||||
MinRK
|
r13788 | nt.assert_is(f.pop(type_str, None), None) | ||
MinRK
|
r13783 | |||
MinRK
|
r18025 | def test_error_method(): | ||
MinRK
|
r13977 | f = HTMLFormatter() | ||
class BadHTML(object): | ||||
def _repr_html_(self): | ||||
MinRK
|
r18025 | raise ValueError("Bad HTML") | ||
MinRK
|
r13977 | bad = BadHTML() | ||
with capture_output() as captured: | ||||
result = f(bad) | ||||
nt.assert_is(result, None) | ||||
MinRK
|
r18025 | nt.assert_in("Traceback", captured.stdout) | ||
nt.assert_in("Bad HTML", captured.stdout) | ||||
nt.assert_in("_repr_html_", captured.stdout) | ||||
MinRK
|
r13977 | |||
MinRK
|
r14636 | def test_nowarn_notimplemented(): | ||
f = HTMLFormatter() | ||||
class HTMLNotImplemented(object): | ||||
def _repr_html_(self): | ||||
raise NotImplementedError | ||||
h = HTMLNotImplemented() | ||||
with capture_output() as captured: | ||||
result = f(h) | ||||
nt.assert_is(result, None) | ||||
MinRK
|
r18025 | nt.assert_equal("", captured.stderr) | ||
nt.assert_equal("", captured.stdout) | ||||
MinRK
|
r14636 | |||
MinRK
|
r13977 | def test_warn_error_for_type(): | ||
f = HTMLFormatter() | ||||
f.for_type(int, lambda i: name_error) | ||||
with capture_output() as captured: | ||||
result = f(5) | ||||
nt.assert_is(result, None) | ||||
MinRK
|
r18025 | nt.assert_in("Traceback", captured.stdout) | ||
nt.assert_in("NameError", captured.stdout) | ||||
nt.assert_in("name_error", captured.stdout) | ||||
MinRK
|
r13977 | |||
MinRK
|
r18025 | def test_error_pretty_method(): | ||
MinRK
|
r13977 | f = PlainTextFormatter() | ||
class BadPretty(object): | ||||
def _repr_pretty_(self): | ||||
return "hello" | ||||
bad = BadPretty() | ||||
with capture_output() as captured: | ||||
result = f(bad) | ||||
nt.assert_is(result, None) | ||||
MinRK
|
r18025 | nt.assert_in("Traceback", captured.stdout) | ||
nt.assert_in("_repr_pretty_", captured.stdout) | ||||
nt.assert_in("given", captured.stdout) | ||||
nt.assert_in("argument", captured.stdout) | ||||
def test_bad_repr_traceback(): | ||||
f = PlainTextFormatter() | ||||
bad = BadRepr() | ||||
with capture_output() as captured: | ||||
result = f(bad) | ||||
# catches error, returns None | ||||
nt.assert_is(result, None) | ||||
nt.assert_in("Traceback", captured.stdout) | ||||
nt.assert_in("__repr__", captured.stdout) | ||||
nt.assert_in("ValueError", captured.stdout) | ||||
MinRK
|
r13977 | |||
Brian E. Granger
|
r15121 | class MakePDF(object): | ||
def _repr_pdf_(self): | ||||
return 'PDF' | ||||
MinRK
|
r13655 | |||
Brian E. Granger
|
r15121 | def test_pdf_formatter(): | ||
pdf = MakePDF() | ||||
f = PDFFormatter() | ||||
nt.assert_equal(f(pdf), 'PDF') | ||||
MinRK
|
r15216 | |||
def test_print_method_bound(): | ||||
f = HTMLFormatter() | ||||
class MyHTML(object): | ||||
def _repr_html_(self): | ||||
return "hello" | ||||
with capture_output() as captured: | ||||
result = f(MyHTML) | ||||
nt.assert_is(result, None) | ||||
nt.assert_not_in("FormatterWarning", captured.stderr) | ||||
with capture_output() as captured: | ||||
result = f(MyHTML()) | ||||
nt.assert_equal(result, "hello") | ||||
nt.assert_equal(captured.stderr, "") | ||||
Min RK
|
r19026 | def test_print_method_weird(): | ||
class TextMagicHat(object): | ||||
def __getattr__(self, key): | ||||
return key | ||||
f = HTMLFormatter() | ||||
text_hat = TextMagicHat() | ||||
nt.assert_equal(text_hat._repr_html_, '_repr_html_') | ||||
with capture_output() as captured: | ||||
result = f(text_hat) | ||||
nt.assert_is(result, None) | ||||
nt.assert_not_in("FormatterWarning", captured.stderr) | ||||
class CallableMagicHat(object): | ||||
def __getattr__(self, key): | ||||
return lambda : key | ||||
call_hat = CallableMagicHat() | ||||
with capture_output() as captured: | ||||
result = f(call_hat) | ||||
Min RK
|
r19128 | nt.assert_equal(result, None) | ||
Min RK
|
r19026 | |||
class BadReprArgs(object): | ||||
def _repr_html_(self, extra, args): | ||||
return "html" | ||||
bad = BadReprArgs() | ||||
with capture_output() as captured: | ||||
result = f(bad) | ||||
nt.assert_is(result, None) | ||||
nt.assert_not_in("FormatterWarning", captured.stderr) | ||||
MinRK
|
r15216 | def test_format_config(): | ||
"""config objects don't pretend to support fancy reprs with lazy attrs""" | ||||
f = HTMLFormatter() | ||||
cfg = Config() | ||||
with capture_output() as captured: | ||||
result = f(cfg) | ||||
nt.assert_is(result, None) | ||||
nt.assert_equal(captured.stderr, "") | ||||
with capture_output() as captured: | ||||
result = f(Config) | ||||
nt.assert_is(result, None) | ||||
nt.assert_equal(captured.stderr, "") | ||||
Min RK
|
r18518 | |||
def test_pretty_max_seq_length(): | ||||
f = PlainTextFormatter(max_seq_length=1) | ||||
lis = list(range(3)) | ||||
text = f(lis) | ||||
nt.assert_equal(text, '[0, ...]') | ||||
f.max_seq_length = 0 | ||||
text = f(lis) | ||||
nt.assert_equal(text, '[0, 1, 2]') | ||||
text = f(list(range(1024))) | ||||
lines = text.splitlines() | ||||
nt.assert_equal(len(lines), 1024) | ||||
Min RK
|
r19384 | |||
def test_ipython_display_formatter(): | ||||
"""Objects with _ipython_display_ defined bypass other formatters""" | ||||
f = get_ipython().display_formatter | ||||
catcher = [] | ||||
class SelfDisplaying(object): | ||||
def _ipython_display_(self): | ||||
catcher.append(self) | ||||
class NotSelfDisplaying(object): | ||||
def __repr__(self): | ||||
return "NotSelfDisplaying" | ||||
def _ipython_display_(self): | ||||
raise NotImplementedError | ||||
Min RK
|
r23310 | save_enabled = f.ipython_display_formatter.enabled | ||
f.ipython_display_formatter.enabled = True | ||||
Min RK
|
r19384 | yes = SelfDisplaying() | ||
no = NotSelfDisplaying() | ||||
d, md = f.format(no) | ||||
nt.assert_equal(d, {'text/plain': repr(no)}) | ||||
nt.assert_equal(md, {}) | ||||
nt.assert_equal(catcher, []) | ||||
d, md = f.format(yes) | ||||
nt.assert_equal(d, {}) | ||||
nt.assert_equal(md, {}) | ||||
nt.assert_equal(catcher, [yes]) | ||||
Min RK
|
r23310 | f.ipython_display_formatter.enabled = save_enabled | ||
Min RK
|
r19557 | def test_json_as_string_deprecated(): | ||
class JSONString(object): | ||||
def _repr_json_(self): | ||||
return '{}' | ||||
f = JSONFormatter() | ||||
with warnings.catch_warnings(record=True) as w: | ||||
d = f(JSONString()) | ||||
nt.assert_equal(d, {}) | ||||
nt.assert_equal(len(w), 1) | ||||
Min RK
|
r23578 | |||
def test_repr_mime(): | ||||
class HasReprMime(object): | ||||
Matthias Bussonnier
|
r23618 | def _repr_mimebundle_(self, include=None, exclude=None): | ||
Min RK
|
r23578 | return { | ||
'application/json+test.v2': { | ||||
'x': 'y' | ||||
Matthias Bussonnier
|
r23612 | }, | ||
'plain/text' : '<HasReprMime>', | ||||
'image/png' : 'i-overwrite' | ||||
Min RK
|
r23578 | } | ||
Matthias Bussonnier
|
r23612 | |||
def _repr_png_(self): | ||||
return 'should-be-overwritten' | ||||
Min RK
|
r23578 | def _repr_html_(self): | ||
return '<b>hi!</b>' | ||||
f = get_ipython().display_formatter | ||||
html_f = f.formatters['text/html'] | ||||
save_enabled = html_f.enabled | ||||
html_f.enabled = True | ||||
obj = HasReprMime() | ||||
d, md = f.format(obj) | ||||
html_f.enabled = save_enabled | ||||
Matthias Bussonnier
|
r23612 | nt.assert_equal(sorted(d), ['application/json+test.v2', | ||
'image/png', | ||||
'plain/text', | ||||
'text/html', | ||||
'text/plain']) | ||||
Min RK
|
r23578 | nt.assert_equal(md, {}) | ||
Matthias Bussonnier
|
r23612 | d, md = f.format(obj, include={'image/png'}) | ||
nt.assert_equal(list(d.keys()), ['image/png'], | ||||
'Include should filter out even things from repr_mimebundle') | ||||
nt.assert_equal(d['image/png'], 'i-overwrite', '_repr_mimebundle_ take precedence') | ||||
Min RK
|
r23578 | |||
Matthias Bussonnier
|
r23674 | |||
def test_pass_correct_include_exclude(): | ||||
class Tester(object): | ||||
def __init__(self, include=None, exclude=None): | ||||
self.include = include | ||||
self.exclude = exclude | ||||
def _repr_mimebundle_(self, include, exclude, **kwargs): | ||||
if include and (include != self.include): | ||||
raise ValueError('include got modified: display() may be broken.') | ||||
if exclude and (exclude != self.exclude): | ||||
raise ValueError('exclude got modified: display() may be broken.') | ||||
return None | ||||
include = {'a', 'b', 'c'} | ||||
exclude = {'c', 'e' , 'f'} | ||||
f = get_ipython().display_formatter | ||||
f.format(Tester(include=include, exclude=exclude), include=include, exclude=exclude) | ||||
f.format(Tester(exclude=exclude), exclude=exclude) | ||||
f.format(Tester(include=include), include=include) | ||||
Min RK
|
r23578 | def test_repr_mime_meta(): | ||
class HasReprMimeMeta(object): | ||||
Matthias Bussonnier
|
r23618 | def _repr_mimebundle_(self, include=None, exclude=None): | ||
Min RK
|
r23578 | data = { | ||
'image/png': 'base64-image-data', | ||||
} | ||||
metadata = { | ||||
'image/png': { | ||||
'width': 5, | ||||
'height': 10, | ||||
} | ||||
} | ||||
return (data, metadata) | ||||
f = get_ipython().display_formatter | ||||
obj = HasReprMimeMeta() | ||||
d, md = f.format(obj) | ||||
nt.assert_equal(sorted(d), ['image/png', 'text/plain']) | ||||
nt.assert_equal(md, { | ||||
'image/png': { | ||||
'width': 5, | ||||
'height': 10, | ||||
} | ||||
}) | ||||