[python-win32] wrapping objects from a COM server

Mark Hammond mhammond at skippinet.com.au
Wed Jan 24 03:04:02 CET 2007


> Mark Hammond wrote:
>
> >> Is there a way that I can automatically have this happen for me, so
> >> that `win32com.server.util.wrap` will automatically be
> called on the
> >> way out of a method?
> >
> > It should be possible to have your _dynamic_ method do this for you?
> > Instead of returning the result item, introspect what is returned
> > and if it
> > is an instance with _public_methods_ etc, just explicitly
> do the wrap
> > yourself.
> >
> > Or I'm missing something... :)
>
> Well, thats basically what I am doing now, but these object structures
> that are returned can be arbitrarily complex, with lists of objects
> that contain other kinds of objects, which have lists of even more
> objects.  Having to walk through arbitrary object structures and look
> for lists/tuples of other objects, etc. is a bit of a pain, and I am
> not sure if I can really do this reliably.

You don't need to recurse deeply though.  If all your objects use the same
policy, the sub-objects will work automatically

>
> Here is a simple example:
>
>      class Person:
>          _public_methods_ = []
>          _public_attrs_ = [
>              'firstName',
>              'lastName',
>              'titles'
>          ]
>
>      class Title:
>          _public_methods_ = []
>          _public_attrs_ = [
>              'name',
>              'description'
>          ]
>
>      p1 = Person()
>      p1.firstName = 'Jonathan'
>      p1.lastName = 'LaCour'
>
>      t1 = Title()
>      t1.name = 'Some Title'
>      t1.description = 'Some Description'
>
>      p1.titles.append(t1)
>
> In order to return arbitrary objects from my _dynamic_ method, I have
> to check and see if any of the public attributes are lists or have
> their own public attributes, and then replace them with "wrapped"
> versions.

In the above example, your hack would be called with a Person object, which
you wrap.  When this person object references the 'titles' attribute, you
will then have see the list of instances that you wrap.  There is no need to
deal with the 'titles' when wrapping the Person object - just wait for the
person object to return the other instances.

>      from win32com.server.util import wrap, register_wrapper
>
>      register_wrapper(Title, wrap)
>      register_wrapper(Person, wrap)

That makes sense - but such a facility doesn't exist.  It would work - but
I'd be leaning towards the more explicit:

class Title:
  _com_wrap_ = wrap
  _public_methods_ = [...]

(although the name _com_wrap_ sucks :)  This would be backwards compatible.
The C code in pythoncom would check for that special attribute and call it
to perform a conversion into a COM object.

It might get a little complicated though with respect to object identity.

Consider the Python COM objects:

class Child:
  _com_wrap_ = wrap
  ...

class Foo:
  _com_wrap_ = wrap
  _public_attrs_ = 'child'
  def __init__(self):
    self.child = Child() # just an instance

In the above example, self.child is a standard Python instance.  Each time
the .child attribute is fetched, COM would do the auto-wrap thing and return
an instance.  However - this implies it would be a *different* COM object
each time the attribute was referenced.  Anyone doing equality tests etc of
the object itself would always fail.  In the pyxpcom world, we solved that
by having the wrapper store a weak-reference to the COM object.  It is
something we need to consider.

But in general, this is something that I've always felt should be
implemented in one way or another.  I don't have much time at the moment
though, but would be happy to help if you wanted to investigate.

Cheers,

Mark



More information about the Python-win32 mailing list