""" Use pretty.py for configurable pretty-printing.

Register pretty-printers for types using ipy_pretty.for_type() or
ipy_pretty.for_type_by_name(). For example, to use the example pretty-printer
for numpy dtype objects, add the following to your ipy_user_conf.py::

    from IPython.Extensions import ipy_pretty

    ipy_pretty.activate()

    # If you want to have numpy always imported anyways:
    import numpy
    ipy_pretty.for_type(numpy.dtype, ipy_pretty.dtype_pprinter)

    # If you don't want to have numpy imported until it needs to be:
    ipy_pretty.for_type_by_name('numpy', 'dtype', ipy_pretty.dtype_pprinter)
"""

import IPython.ipapi
from IPython.genutils import Term

from IPython.external import pretty

ip = IPython.ipapi.get()


#### Implementation ############################################################

def pretty_result_display(self, arg):
    """ Uber-pretty-printing display hook.

    Called for displaying the result to the user.
    """
    
    if ip.options.pprint:
        verbose = getattr(ip.options, 'pretty_verbose', False)
        out = pretty.pretty(arg, verbose=verbose)
        if '\n' in out:
            # So that multi-line strings line up with the left column of
            # the screen, instead of having the output prompt mess up
            # their first line.                
            Term.cout.write('\n')
        print >>Term.cout, out
    else:
        raise IPython.ipapi.TryNext


#### API #######################################################################

# Expose the for_type and for_type_by_name functions for easier use.
for_type = pretty.for_type
for_type_by_name = pretty.for_type_by_name


# FIXME: write deactivate(). We need a way to remove a hook.
def activate():
    """ Activate this extension.
    """
    ip.set_hook('result_display', pretty_result_display, priority=99)


#### Example pretty-printers ###################################################

def dtype_pprinter(obj, p, cycle):
    """ A pretty-printer for numpy dtype objects.
    """
    if cycle:
        return p.text('dtype(...)')
    if obj.fields is None:
        p.text(repr(obj))
    else:
        p.begin_group(7, 'dtype([')
        for i, field in enumerate(obj.descr):
            if i > 0:
                p.text(',')
                p.breakable()
            p.pretty(field)
        p.end_group(7, '])')


#### Tests #####################################################################

def test_pretty():
    """
    In [1]: from IPython.Extensions import ipy_pretty

    In [2]: ipy_pretty.activate()

    In [3]: class A(object):
       ...:     def __repr__(self):
       ...:         return 'A()'
       ...:     
       ...:     

    In [4]: a = A()

    In [5]: a
    Out[5]: A()

    In [6]: def a_pretty_printer(obj, p, cycle):
       ...:     p.text('<A>')
       ...:     
       ...:     

    In [7]: ipy_pretty.for_type(A, a_pretty_printer)

    In [8]: a
    Out[8]: <A>

    In [9]: class B(object):
       ...:     def __repr__(self):
       ...:         return 'B()'
       ...:     
       ...:     

    In [10]: B.__module__, B.__name__
    Out[10]: ('__main__', 'B')

    In [11]: def b_pretty_printer(obj, p, cycle):
       ....:     p.text('<B>')
       ....:     
       ....:     

    In [12]: ipy_pretty.for_type_by_name('__main__', 'B', b_pretty_printer)

    In [13]: b = B()

    In [14]: b
    Out[14]: <B>
    """
    assert False, "This should only be doctested, not run."

