I am in the process of porting reportlab to python3.3, one of the contributions 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

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to