Ross McKerchar wrote: > 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. > > 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.
This is exactly the problem I have with things like active_directory and WMI. In the case of the latter you're slightly better off because the thing allows for a certain amount of introspection. With the former, I've just bitten the bullet and explictly wrapped the most popular classes (User, Group, OU etc.) But I agree: it's something of a pain. > ... it also introduced a significant performance overhead > (about 15% runtime overhead from some rough tests). Yes, this doesn't bother me directly, but I was contacted by someone who wanted to do real-time monitoring with WMI where it starts to matter, so I did some work with him to speed things up. > 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__) This -- just in case you haven't come across the expression -- is called monkey-patching. It's a slightly general-purpose example of it, but it's something which is usefully easy to do in Python. (Consequently, it's easy to abuse but...) Frankly, I never even thought of doing it. You may already have covered this, but it does have one or corner-cases you might want to consider. If one of your methods needs to completely cover one of the original ones *and* to call the original one as well (say to get the data you're going to wrap) then you have to do something a bit smarter than the straight __dict__.update you're doing there. Not very much harder, but you'd have to do it. > 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. Presumably, then, if the original COM class exposed, say, a .GetGroups method which returned a list of groups, each of which you wanted to wrap, in this implementation, you'd add a .MyGetGroups method which called the original and wrapped the result? This is the sort of thing I was averting to above. You *could* rename (on the fly) .GetGroups to ._GetGroups and add your own .GetGroups which called ._GetGroups under the covers etc. This is obviously only important if you're trying to present an API faithful to a documented original. If you're simply rolling your own, then you can do what you like. I think what you've done is fine, and I'll certainly look into it for my own stuff, not least because, as you point out, it gives a speed advantage. Others may point out hidden flaws which I've missed, and I'll be glad to hear them, but if it works for you... :) TJG _______________________________________________ Python-win32 mailing list Python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32