[python-win32] extending com objects
Ross McKerchar
it at crummock.com
Thu May 24 11:32:05 CEST 2007
A few months ago I posted asking for some advice on ways to extend
classes provided by com objects.
Primarily I was keen to make a com library that I work with a lot
(Notes/Domino if anyone's interested) nicer and more pythonic to use.
I've spent a good few hours bashing away and have found two ways which
appear to work with my simplistic test suite. However I'm not
particularly comfortable with either of them (the black magic I'm using
is all a bit new to me). Consequently if anyone has time to have a look
at my solutions I'd be very grateful.
Attempt #1 (code at http://www2.crummock.com/comwrapper.py):
Based on what Tim Golden called a "Delegation model", involved holding
an internal copy of my com class and by implementing getattr/setattr
calling the com object when necessary. This turned out a fair bit more
complicated than I originally expected as lots of the com objects
methods returned other com objects from the same library. I wanted these
returned com objects to also be automatically wrapped in my extension
classes to save having to constantly wrap in my client code. To do this
I ended up with some very convoluted code that intercepted all my com
method calls to see if they returned a com object for which I had a
corresponding wrapper class and if so, wrap it. Of course I then had to
check all tuples returned to see if they also contained candidates for
wrapping.
I got this working (well enough that it passed my far-from-comprehensive
test-suite) but I wasn't convinced by it: the complexity of my wrapping
system is bound to contain some subtle bugs and it also introduced a
significant performance overhead (about 15% runtime overhead from some
rough tests).
Attempt #2:
This very simple, alternative method then occured to me:
#My custom classes
class IDocument: ...
class IDatabase: ...
class IDocumentCollection: ...
from win32com.client.gencache import GetModuleForProgID
module = GetModuleForProgID('Lotus.NotesSession')
implementedChildClasses = (IDocument,IDatabase,IDocumentCollection)
for klass in implementedChildClasses:
#find parent class of same name
parentclass = getattr(module,klass.__name__)
parentclass.__dict__.update(klass.__dict__)
I just put this code at the bottom of my module and it automagically
adds all my methods & attributes from classes listed in
"implementedChildClasses" to the com class (at the expense of needing to
run makepy on the com library, of course). The beauty of this is that I
dont have to worry about wrapping the results of any functions as I'm
always dealing with the real com class, just with some extra methods
added. It is also a more efficient - a small overhead when loading the
module but a lot quicker when using it. Unfortunately, it does feel like
a big hack and I'm not convinced it's a sensible thing to do?
So, I dont actually have any real problems as such I'm just looking for
advice/comments from anyone who is more familiar with all these magical
techniques.
-ross
More information about the Python-win32
mailing list