"""
Implements a displayhook for Sage. The main improvement over the default
displayhook is a new facility for displaying lists of matrices in an easier to
read format.
AUTHORS:
- Bill Cauchois (2009): initial version
"""
import IPython, sys, __builtin__
from sage.matrix.matrix import is_Matrix
from sage.modular.arithgroup.arithgroup_element import ArithmeticSubgroupElement
MAX_COLUMN = 70
def _check_tall_list_and_print(out_stream, the_list):
"""
First check whether a list is "tall" -- whether the reprs of the elements of
the list will span multiple lines and cause the list to be printed awkwardly.
If not, this function returns False and does nothing; you should revert back
to the normal method for printing an object (its repr). If so, return True and
print the list in the special format. Note that the special format isn't just
for matrices. Any object with a multiline repr will be formatted.
INPUT:
- ``out_stream`` - The output stream to use.
- ``the_list`` - The list (or a tuple).
TESTS::
sage: import sage.misc.displayhook, sys
We test _check_tall_list_and_print() indirectly by calling print_obj() on
a list of matrices::
sage: sage.misc.displayhook.print_obj(sys.stdout, \
[matrix([[1, 2, 3, 4], [5, 6, 7, 8]]) for i in xrange(7)])
[
[1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4] [1 2 3 4]
[5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8], [5 6 7 8],
<BLANKLINE>
[1 2 3 4]
[5 6 7 8]
]
"""
split_reprs = []
tall = False
for elem in the_list:
split_reprs.append(`elem`.split('\n'))
if len(split_reprs[-1]) > 1:
tall = True
if not tall:
return False
if isinstance(the_list, tuple):
parens = '()'
elif isinstance(the_list, list):
parens = '[]'
else:
raise TypeError, 'expected list or tuple'
running_lines = [[]]
current_column = 0
print >>out_stream, parens[0]
for split_repr in split_reprs:
width = max(len(x) for x in split_repr)
if current_column + width > MAX_COLUMN and not (width > MAX_COLUMN):
_print_tall_list_row(out_stream, running_lines)
running_lines = [[]]
current_column = 0
current_column += width + 2
for i in xrange(len(running_lines), len(split_repr)):
running_lines.insert(0, [' ' * len(x) for x in running_lines[-1]])
line_diff = len(running_lines) - len(split_repr)
for i, x in enumerate(split_repr):
running_lines[i + line_diff].append(x.ljust(width))
for i in xrange(line_diff):
running_lines[i].append(' ' * width)
if len(running_lines[0]) > 0:
_print_tall_list_row(out_stream, running_lines, True)
print >>out_stream, parens[1]
return True
def _print_tall_list_row(out_stream, running_lines, last_row=False):
for i, line in enumerate(running_lines):
if i + 1 != len(running_lines):
sep, tail = ' ', ''
else:
sep, tail = ', ', '' if last_row else ','
print >>out_stream, sep.join(line) + tail
if not last_row:
print >>out_stream
def print_obj(out_stream, obj):
"""
Print an object. This function is used internally by the displayhook.
EXAMPLES::
sage: import sage.misc.displayhook, sys
For most objects, printing is done simply using their repr::
sage: sage.misc.displayhook.print_obj(sys.stdout, 'Hello, world!')
'Hello, world!'
sage: sage.misc.displayhook.print_obj(sys.stdout, (1, 2, 3, 4))
(1, 2, 3, 4)
We demonstrate the special format for lists of matrices::
sage: sage.misc.displayhook.print_obj(sys.stdout, \
[matrix([[1], [2]]), matrix([[3], [4]])])
[
[1] [3]
[2], [4]
]
"""
if isinstance(obj, (tuple, list)):
if len(obj) > 0 and (is_Matrix(obj[0]) or isinstance(obj[0], ArithmeticSubgroupElement)):
if _check_tall_list_and_print(out_stream, obj):
return
print >>out_stream, `obj`
def result_display(ip_self, obj):
"""
This function implements the ``result_display`` hook for IPython.
"""
print_obj(IPython.genutils.Term.cout, obj)
def displayhook(obj):
"""
This function adheres to the displayhook protocol described in `PEP 217`_.
In order to mimic the behavior of the default displayhook, we update the
variable ``__builtin__._`` every time an object is printed.
.. _`PEP 217`: http://www.python.org/dev/peps/pep-0217/
TESTS::
sage: import sage.misc.displayhook, sys
sage: sage.misc.displayhook.displayhook(1)
1
sage: print _
1
sage: sage.misc.displayhook.displayhook(None)
sage: print _
1
"""
if obj is None:
return
__builtin__._ = None
print_obj(sys.stdout, obj)
__builtin__._ = obj
def install():
"""
Install the new displayhook, so that subsequent output from the interpreter
will be preprocessed by the mechanisms in this module.
"""
ipapi = IPython.ipapi.get()
if ipapi:
ipapi.set_hook('result_display', result_display)
else:
sys.displayhook = displayhook