sympy/printing/printer.py
author Ondrej Certik <ondrej@certik.cz>
Wed Mar 12 12:15:16 2008 +0100 (8 months ago)
changeset 1880 ab549e392e27
parent 15825636b9da4297
permissions -rw-r--r--
Fixes pretty_symbology.py to work if sys.stdout.encoding doesn't exist (#737).
     1 """Printing subsystem driver"""
     2 
     3 class Printer(object):
     4     """Generic printer driver
     5 
     6     This is a generic printer driver.
     7     It's job is to provide infrastructure for implementing new printers easily.
     8 
     9     Basically, if you want to implement a printer, all you have to do is:
    10 
    11     1. Subclass Printer.
    12     2. In your subclass, define _print_<CLASS> methods
    13 
    14        For each class you want to provide printing to, define an appropriate
    15        method how to do it. For example if you want a class FOO to be printed in
    16        it's own way, define _print_FOO:
    17 
    18        def _print_FOO(self, e):
    19            ...
    20 
    21        this should return how FOO instance e is printed
    22 
    23        Also, if BAR is a subclass of FOO, _print_FOO(bar) will be called for
    24        instance of BAR, if no _print_BAR is provided.  Thus, usually, we don't
    25        need to provide prining routines for every class we want to support --
    26        only generic routine has to be provided for a set of classes. 
    27 
    28        A good example for this are functions - for example PrettyPrinter only
    29        defines _print_Function, and there is no _print_sin, _print_tan, etc...
    30 
    31        On the other hand, a good printer will probably have to define separate
    32        routines for Symbol, Atom, Number, Integral, Limit, etc...
    33 
    34     3. If convenient, override self.emptyPrinter
    35 
    36        This callable will be called to obtain printing result as a last resort,
    37        that is when no appropriate _print_<CLASS> was found for an expression.
    38 
    39     """
    40     def __init__(self):
    41         self._depth = -1
    42         self._str = str
    43         self.emptyPrinter = str
    44 
    45     def doprint(self, expr):
    46         """Returns printer's representation for expr (as a string)"""
    47         return self._str(self._print(expr))
    48 
    49     def _print(self, expr, *args):
    50         """internal dispatcher
    51 
    52            It's job is to loop through expr classes (class + it's bases), and
    53            try to dispatch the work to _print_<EXPR_CLASS>
    54 
    55            e.g., suppose we have the following class hierarcy::
    56 
    57                  Basic
    58                    |
    59                  Atom
    60                    |
    61                  Number
    62                    |
    63                 Rational
    64 
    65            then, for expr=Rational(...), in order to dispatch, we will try
    66            calling printer methods as shown in the figure below:
    67 
    68                p._print(expr)
    69                |
    70                |-- p._print_Rational(expr)
    71                |
    72                |-- p._print_Number(expr)
    73                |
    74                |-- p._print_Atom(expr)
    75                |
    76                `-- p._print_Basic(expr)
    77 
    78            if ._print_Rational method exists in the printer, then it is called,
    79            and the result is returned back.
    80 
    81            otherwise, we proceed with trying Rational bases in the inheritance
    82            order.
    83 
    84            if nothing exists, we just return:
    85 
    86                p.emptyPrinter(expr)
    87         """
    88         self._depth += 1
    89 
    90         # See if the class of expr is known, or if one of its super
    91         # classes is known, and use that print function
    92         res = None
    93         for cls in expr.__class__.__mro__:
    94             if hasattr(self, '_print_'+cls.__name__):
    95                 res = getattr(self, '_print_'+cls.__name__)(expr, *args)
    96                 break
    97 
    98         # Unknown object, just use its string representation
    99         if res is None:
   100             res = self.emptyPrinter(expr)
   101 
   102         self._depth -= 1
   103         return res
   104