pycanvas.py

Robin Becker <[email protected]>
Newsgroups gmane.comp.python.reportlab.user
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.