How to properly subclass the pretty printer

9 views
Skip to first unread message

Luke

unread,
Jun 25, 2009, 2:50:54 PM6/25/09
to sympy
I'm trying to subclass the StrPrinter and PrettyPrinter so that I can
customize the display of some classes I have created for PyDy. I have
had success with getting StrPrinter, but I found it to have some weird
unicode issues, so I am using plain old strings for my sublcass of
StrPrinter, and would like to reserve all unicode stuff for the
PrettyPrinter.

The way I am subclassing StrPrinter is as follows:
1) My PyDy classes are subclassed from Basic. I override the __str__()
method of each of my PyDy classes to look like:
def __str__(self):
return pydy_str(self)

where pydy_str(self) looks like:
def pydy_str(e):
p = PyDyStrPrinter()
return p.doprint(e)

2) I subclass StrPrinter, and add methods entitled
_print_<MyPyDyClass>, as follows:
def _print_UnitVector(self, e):
....

These _print_*** methods return a string of how I want each class to
be displayed.

Nowhere in any of my classes, or in my subclassing of StrPrinter, do I
have printmethod defined. Everything above works just fine.

The problem is when I try the same approach with subclassing
PrettyPrinter. I created class methods entitled _sympypretty_() for
each of my classes, then define a pydy_pretty() function, and then
subclass PrettyPrinter, analogously to my approach above. It doesn't
work. Specifically, I get infinite recursion runtime errors. I tried
adding the printmethod class attribute to my PyDyPrettyPrinter, but it
didn't make any difference, I still get infinite recursion errors.

I have spent many hours on this and I am sure it is probably a very
simple fix and that I am just not using things correctly. Does
anybody have any recommendations on how this should be done properly?
Ideally, some example code would be the best that way there would be
no confusion as to how this should be done.

It seems to me that the approach that should be taken to subclassing
either StrPrinter or PrettyPrinter should be conceptually the same,
but perhaps this isn't the case?

Also, is the approach I am using above for customizing the StrPrinter
the recommended way to do it?

Thanks,
~Luke

Ondrej Certik

unread,
Jun 25, 2009, 2:58:20 PM6/25/09
to sy...@googlegroups.com

Please create a new branch in your repository with the above problem
and show here how to reproduce it, so that people can have a look.

Ondrej

Luke

unread,
Jun 25, 2009, 3:13:55 PM6/25/09
to sympy
This code will replicate the problem when run using the latest sympy
pull:

from sympy import Basic
from sympy.printing.str import StrPrinter
from sympy.printing.pretty.pretty import PrettyPrinter, xsym, pprint

class GreenEggsAndHam(Basic):
def __init__(self, string):
self.s = string

def _pretty_(self):
return print_GreenEggsAndHam(self)

class HamPrinter(PrettyPrinter):
printmethod = '_pretty_'
def _print_GreenEggsAndHam(self, e):
return e.s.lower() + xsym('*') + "\xC2\xB7"

def print_GreenEggsAndHam(e):
pp = HamPrinter()
return pp.doprint(e)


MyBreakfast = GreenEggsAndHam('I LOVE SYMPY')
print_GreenEggsAndHam(MyBreakfast)
pprint(MyBreakfast)



~Luke


On Jun 25, 11:58 am, Ondrej Certik <ond...@certik.cz> wrote:

Ondrej Certik

unread,
Jun 25, 2009, 4:02:43 PM6/25/09
to sy...@googlegroups.com
On Thu, Jun 25, 2009 at 1:13 PM, Luke<hazel...@gmail.com> wrote:
>
> This code will replicate the problem when run using the latest sympy
> pull:
>
> from sympy import Basic
> from sympy.printing.str import StrPrinter
> from sympy.printing.pretty.pretty import PrettyPrinter, xsym, pprint
>
> class GreenEggsAndHam(Basic):
>    def __init__(self, string):
>        self.s = string
>
>    def _pretty_(self):
>        return print_GreenEggsAndHam(self)
>
> class HamPrinter(PrettyPrinter):
>    printmethod = '_pretty_'
>    def _print_GreenEggsAndHam(self, e):
>        return e.s.lower() + xsym('*') + "\xC2\xB7"
>
> def print_GreenEggsAndHam(e):
>    pp = HamPrinter()
>    return pp.doprint(e)
>
>
> MyBreakfast = GreenEggsAndHam('I LOVE SYMPY')
> print_GreenEggsAndHam(MyBreakfast)
> pprint(MyBreakfast)

it's because you have overridden *both* _pretty_ and
_print_GreenEggsAndHam(). You only should override one of those, then
it will work.

It's true we should improve the Printer code to handle such case too,
patches welcome.

Another problem is that if you use unicode, you have to change
"\xC2\xB7" to u"\xC2\xB7"

Yet another problem with the above code is that PrettyPrinter expects
StringPict() instance, so you can fake it by your own class that
implements render.

Another problem is that print_GreenEggsAndHam returns the result, but
you want to print it. Anyways, with all the above things fixed, it now
prints:

i love sympy⋅·
GreenEggsAndHam(I LOVE SYMPY)

Is this what you want?

The fixed script is below.

Ondrej

--------------------

from sympy import Basic
from sympy.printing.str import StrPrinter
from sympy.printing.pretty.pretty import PrettyPrinter, xsym, pprint

class GreenEggsAndHam(Basic):
def __init__(self, string):
self.s = string

#def _pretty_(self):
# return print_GreenEggsAndHam(self)

class HamPrinter(PrettyPrinter):
printmethod = '_pretty_'
def _print_GreenEggsAndHam(self, e):

class Fake(object):
def render(self, *args, **kwargs):
return e.s.lower() + xsym('*') + u"\xC2\xB7"
return Fake()

def print_GreenEggsAndHam(e):
pp = HamPrinter()
return pp.doprint(e)


MyBreakfast = GreenEggsAndHam('I LOVE SYMPY')

print print_GreenEggsAndHam(MyBreakfast)
pprint(MyBreakfast)

Reply all
Reply to author
Forward
0 new messages