[reportlab-users] pycanvas.py

Robin Becker robin at reportlab.com
Thu Nov 28 06:15:15 EST 2013


While porting reportlab to python3.3, I find one of the contributions
(pycanvas.py) is causing a problem. Are there users of this module?

It is a module that implements a reporting proxy with a canvas that records all
access calls and attribute settings etc etc. This fails under python3 because of
differences between old and new style classes.


I find that I don't understand exactly how the original works so well, but here
is a cut down version

##########################################################################
class Canvas:
def __init__(self,*args,**kwds):
self._fontname = 'Helvetica'

class PDFAction :
"""Base class to fake method calls or attributes on Canvas"""
def __init__(self, parent, action) :
"""Saves a pointer to the parent object, and the method name."""
self._parent = parent
self._action = action

def __getattr__(self, name) :
"""Probably a method call on an attribute, returns the real one."""
print('PDFAction.__getattr__(%s)' % name)
return getattr(getattr(self._parent._underlying, self._action), name)

def __call__(self, *args, **kwargs) :
"""The fake method is called, print it then call the real one."""
if not self._parent._parent._in :
self._precomment()
self._postcomment()
self._parent._parent._in += 1
meth = getattr(self._parent._underlying, self._action)
retcode = meth(*args,**kwargs)
self._parent._parent._in -= 1
return retcode

def __hash__(self) :
return hash(getattr(self._parent._underlying, self._action))

def _precomment(self) :
print('%s(__dict__=%s)._precomment()' %
(self.__class__.__name__,repr(self.__dict__)))

def _postcomment(self) :
print('%s(__dict__=%s)._postcomment()' %
(self.__class__.__name__,repr(self.__dict__)))

class PyCanvas:
_name = "c"

def __init__(self, *args, **kwargs) :
self._in = 0
self._parent = self # nice trick, isn't it ?
self._underlying = Canvas(*args,**kwargs)

def __bool__(self) :
"""This is needed by platypus' tables."""
return 1

def __str__(self) :
return 'PyCanvas.__str__()'

def __getattr__(self, name) :
return PDFAction(self, name)

if __name__=='__main__':
c = PyCanvas('filepath.pdf')
print('c._fontname=%s' % c._fontname)
print('is it a string? %r type=%s' %
(isinstance(c._fontname,str),type(c._fontname))))
##########################################################################

when run under python27 I see this

C:\code\hg-repos\reportlab>\python27\python.exe z.py
PDFAction.__getattr__(__str__)
c._fontname=Helvetica
is it a string? False type=<type 'instance'>

and under python33 I see this
C:\code\hg-repos\reportlab>\python33\python.exe z.py
c._fontname=<__main__.PDFAction object at 0x00BF8830>
is it a string? False type=<class '__main__.PDFAction'>

clearly something different is happening and this leads to failure in the real
pycanvas module testing. Is there a way to recover the old behaviour(s)?
--
Robin Becker



More information about the reportlab-users mailing list