Python COM iterator

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Larry Bates

    #1

    Python COM iterator

    Does anyone know if there is a way to make a Python COM object
    act like a proper iterator in VB/Delphi?

    Example:

    Python COM object

    class foo:
    _public_methods _=['next']

    def __init__(self):
    self.numbers=[1,2,3,4,5,6,7,8]

    def next(self):
    try: return self.numbers.po p(0)
    except IndexError:
    #
    # Normally in Python I would do this, but that raises a
    # COMexception when used in a COM object.
    #
    raise StopIteration

    def __iter__(self):
    return self


    I want to be able to write something like (VB):

    oFOO=foo()
    for each n in oFOO
    '
    ' Do something with n
    '
    next

    Seems like there should be a way. Hope explanation is clear enough.

    Regards, Larry

  • Carsten Haese

    #2
    Re: Python COM iterator

    On Tue, 2007-04-17 at 16:54 -0500, Larry Bates wrote:
    Does anyone know if there is a way to make a Python COM object
    act like a proper iterator in VB/Delphi?
    I don't use COM, VB, or Delphi, but Google turned up these two
    references:
    http://msdn.microsoft.com/library/de...ingForEach.asp http://17slon.com/blogs/gabr/2007/03...rs-part-1.html

    Judging from those links, an object is iterable in VB and Delphi (or as
    they call it, it is enumerable) if it exposes a GetEnumerator method
    that returns an enumerator. The enumerator in turn needs to expose a
    MoveNext method and a Current property.

    Assuming that the Enumerable and the Enumerator are allowed to be the
    same object, you'll probably need code that looks something like this:

    class foo:
    _public_methods _=['GetEnumerator' ,'MoveNext']
    # You'll need to figure out how to expose "self.Curre nt"

    def __init__(self):
    self.numbers=[1,2,3,4,5,6,7,8]
    self.Current = None

    def MoveNext(self):
    try:
    self.Current = self.numbers.po p(0)
    return True
    except IndexError:
    return False

    def GetEnumerator(s elf):
    return self

    Good luck,

    Carsten.


    Comment

    • Larry Bates

      #3
      Re: Python COM iterator

      Carsten Haese wrote:
      On Tue, 2007-04-17 at 16:54 -0500, Larry Bates wrote:
      >Does anyone know if there is a way to make a Python COM object
      >act like a proper iterator in VB/Delphi?
      >
      I don't use COM, VB, or Delphi, but Google turned up these two
      references:
      http://msdn.microsoft.com/library/de...ingForEach.asp http://17slon.com/blogs/gabr/2007/03...rs-part-1.html
      >
      Judging from those links, an object is iterable in VB and Delphi (or as
      they call it, it is enumerable) if it exposes a GetEnumerator method
      that returns an enumerator. The enumerator in turn needs to expose a
      MoveNext method and a Current property.
      >
      Assuming that the Enumerable and the Enumerator are allowed to be the
      same object, you'll probably need code that looks something like this:
      >
      class foo:
      _public_methods _=['GetEnumerator' ,'MoveNext']
      # You'll need to figure out how to expose "self.Curre nt"
      >
      def __init__(self):
      self.numbers=[1,2,3,4,5,6,7,8]
      self.Current = None
      >
      def MoveNext(self):
      try:
      self.Current = self.numbers.po p(0)
      return True
      except IndexError:
      return False
      >
      def GetEnumerator(s elf):
      return self
      >
      Good luck,
      >
      Carsten.
      >
      >
      I looked over the links and what you have proposed seems to make sense, but
      I can't make it work. I have the following class defined and registered.

      class foo:

      _public_methods _=['GetEnumerator' ,'MoveNext']
      _public_attrs_=['Current']
      _reg_clsid_='{F C2A0E7B-E428-4414-B1C4-60373BB12102}'
      _reg_progid_="S yscon.foo"

      def __init__(self):
      self.numbers=[1,2,3,4,5,6,7,8]
      self.Current = None

      def MoveNext(self):
      try:
      self.Current = self.numbers.po p(0)
      rtnval=True

      except IndexError:
      self.Current=No ne
      rtnval=False

      def GetEnumerator(s elf):
      return self


      Then I do:
      >>import win32com.client
      >>typelib='Sysc on.foo'
      >>F=win32com.cl ient.Dispatch(t ypelib)
      >>for x in F:
      .... print x
      ....
      Traceback (most recent call last):
      File "<interacti ve input>", line 1, in <module>
      File "C:\Python25\li b\site-packages\win32c om\client\dynam ic.py", line 228, in
      __getitem__
      raise TypeError, "This object does not support enumeration"
      TypeError: This object does not support enumeration
      >>>
      but this works fine:
      >>F.MoveNext( )
      >>F.Current
      1
      >>F.MoveNext( )
      >>F.Current
      2
      >>>

      I'm stumped.

      -Larry

      Comment

      • Carsten Haese

        #4
        Re: Python COM iterator

        >[...]
        On Tue, 2007-04-17 at 16:54 -0500, Larry Bates wrote:
        Does anyone know if there is a way to make a Python COM object
        act like a proper iterator in VB/Delphi?
        >[...]
        After more googling, staring at win32com's code, and a fair bit of trial
        and error, I've come up with the following working example:

        # server.py
        import pythoncom

        class HelloWorld:
        _reg_clsid_ = "{CAB8BED1-9174-4AAD-ABC5-F377951CB71B}"
        _reg_desc_ = "Python Test COM Server"
        _reg_progid_ = "Python.TestSer ver"
        _public_methods _ = ['Next']
        _com_interfaces _ = [pythoncom.IID_I EnumVARIANT]

        def __init__(self):
        self.numbers=[1,2,3,4,5,6,7,8]

        def Next(self, count):
        assert count==1
        try:
        return (self.numbers.p op(0),)
        except IndexError:
        return ()

        def _NewEnum(self):
        import win32com.server .util
        return win32com.server .util.wrap(self )

        if __name__=='__ma in__':
        import win32com.server .register
        win32com.server .register.UseCo mmandLine(Hello World)

        # client.py
        import win32com.client
        comobj = win32com.client .Dispatch("Pyth on.TestServer")
        for x in comobj:
        print x

        This works for me on Python 2.5 and pywin32 Build 210, but I don't know
        whether clients in VB or Delphi are able to use this iterator.

        -Carsten


        Comment

        • Larry Bates

          #5
          Re: Python COM iterator

          Carsten Haese wrote:
          >[...]
          >>On Tue, 2007-04-17 at 16:54 -0500, Larry Bates wrote:
          >>>Does anyone know if there is a way to make a Python COM object
          >>>act like a proper iterator in VB/Delphi?
          >[...]
          >
          After more googling, staring at win32com's code, and a fair bit of trial
          and error, I've come up with the following working example:
          >
          # server.py
          import pythoncom
          >
          class HelloWorld:
          _reg_clsid_ = "{CAB8BED1-9174-4AAD-ABC5-F377951CB71B}"
          _reg_desc_ = "Python Test COM Server"
          _reg_progid_ = "Python.TestSer ver"
          _public_methods _ = ['Next']
          _com_interfaces _ = [pythoncom.IID_I EnumVARIANT]
          >
          def __init__(self):
          self.numbers=[1,2,3,4,5,6,7,8]
          >
          def Next(self, count):
          assert count==1
          try:
          return (self.numbers.p op(0),)
          except IndexError:
          return ()
          >
          def _NewEnum(self):
          import win32com.server .util
          return win32com.server .util.wrap(self )
          >
          if __name__=='__ma in__':
          import win32com.server .register
          win32com.server .register.UseCo mmandLine(Hello World)
          >
          # client.py
          import win32com.client
          comobj = win32com.client .Dispatch("Pyth on.TestServer")
          for x in comobj:
          print x
          >
          This works for me on Python 2.5 and pywin32 Build 210, but I don't know
          whether clients in VB or Delphi are able to use this iterator.
          >
          -Carsten
          >
          >
          I tested in VB and by golly it works! What is odd is that this looks
          NOTHING like what we got from the docs earlier. No GetEnumerator
          method, no MoveNext method. I'm glad it works, but I'm a little
          puzzled as to why it works.

          Thanks loads.

          -Larry

          Comment

          • Larry Bates

            #6
            Re: Python COM iterator

            Carsten Haese wrote:
            >[...]
            >>On Tue, 2007-04-17 at 16:54 -0500, Larry Bates wrote:
            >>>Does anyone know if there is a way to make a Python COM object
            >>>act like a proper iterator in VB/Delphi?
            >[...]
            >
            After more googling, staring at win32com's code, and a fair bit of trial
            and error, I've come up with the following working example:
            >
            # server.py
            import pythoncom
            >
            class HelloWorld:
            _reg_clsid_ = "{CAB8BED1-9174-4AAD-ABC5-F377951CB71B}"
            _reg_desc_ = "Python Test COM Server"
            _reg_progid_ = "Python.TestSer ver"
            _public_methods _ = ['Next']
            _com_interfaces _ = [pythoncom.IID_I EnumVARIANT]
            >
            def __init__(self):
            self.numbers=[1,2,3,4,5,6,7,8]
            >
            def Next(self, count):
            assert count==1
            try:
            return (self.numbers.p op(0),)
            except IndexError:
            return ()
            >
            def _NewEnum(self):
            import win32com.server .util
            return win32com.server .util.wrap(self )
            >
            if __name__=='__ma in__':
            import win32com.server .register
            win32com.server .register.UseCo mmandLine(Hello World)
            >
            # client.py
            import win32com.client
            comobj = win32com.client .Dispatch("Pyth on.TestServer")
            for x in comobj:
            print x
            >
            This works for me on Python 2.5 and pywin32 Build 210, but I don't know
            whether clients in VB or Delphi are able to use this iterator.
            >
            -Carsten
            >
            >
            I tested in VB and by golly it works! What is odd is that this looks
            NOTHING like what we got from the docs earlier. No GetEnumerator
            method, no MoveNext method. I'm glad it works, but I'm a little
            puzzled as to why it works.

            Thanks loads.

            -Larry

            Comment

            • Steve Holden

              #7
              Re: Python COM iterator

              Larry Bates wrote:
              Carsten Haese wrote:
              [iterative acess to COM objects]
              I tested in VB and by golly it works! What is odd is that this looks
              NOTHING like what we got from the docs earlier. No GetEnumerator
              method, no MoveNext method. I'm glad it works, but I'm a little
              puzzled as to why it works.
              >
              Presumably the magic of mark Hammond's wrapper classes providing
              adaptation between Python iteration and COM enumerable collection
              objects. win32all is *very* Pythonic.

              Jim Hugunin, the author of IronPython (and of J[P]ython before that) has
              commented that Microsoft users are frequently surprised by the small
              amount of code required in IronPython to manipulate .NET objects.

              regards
              Steve
              --
              Steve Holden +44 150 684 7255 +1 800 494 3119
              Holden Web LLC/Ltd http://www.holdenweb.com
              Skype: holdenweb http://del.icio.us/steve.holden
              Recent Ramblings http://holdenweb.blogspot.com

              Comment

              • Carsten Haese

                #8
                Re: Python COM iterator

                On Thu, 2007-04-19 at 12:49 -0400, Steve Holden wrote:
                Larry Bates wrote:
                Carsten Haese wrote:
                [iterative acess to COM objects]
                I tested in VB and by golly it works! What is odd is that this looks
                NOTHING like what we got from the docs earlier. No GetEnumerator
                method, no MoveNext method. I'm glad it works, but I'm a little
                puzzled as to why it works.
                I'm glad, too.
                Presumably the magic of mark Hammond's wrapper classes providing
                adaptation between Python iteration and COM enumerable collection
                objects. win32all is *very* Pythonic.
                There is some magic, but it appears to be on the client side only. This
                magic is what allows you to stick the win32com.client .Dispatcher object
                into a for-loop.

                If there were magic on the server side, it shouldn't be necessary to
                declare that IID_IEnumVARIAN T is exposed, and it shouldn't be necessary
                to implement the _NewEnum and Next methods; it should be enough to have
                __iter__ present and let the magic take care of the rest.

                It appears that the reason why my first completely uninformed guess
                didn't work and my second somewhat less uninformed guess did work is
                that there are two different enumeration protocols in the wonderfully
                confusing world of Win32. I'm guessing that GetEnumerator/MoveNext is
                the .NET enumeration protocol and IID_IEnumVARIAN T/Next is the COM
                enumeration protocol.

                -Carsten


                Comment

                • Ross Ridge

                  #9
                  Re: Python COM iterator

                  Larry Bates wrote:
                  I tested in VB and by golly it works! What is odd is that this looks
                  NOTHING like what we got from the docs earlier. No GetEnumerator
                  method, no MoveNext method. I'm glad it works, but I'm a little
                  puzzled as to why it works.
                  The documention Carsten Haese referenced earlier was for the .NET version
                  of VisualBasic, and shows how to use .NET's IEnumerate and IEnumerable
                  interfaces.

                  Steve Holden <steve@holdenwe b.comwrote:
                  >Presumably the magic of mark Hammond's wrapper classes providing
                  >adaptation between Python iteration and COM enumerable collection
                  >objects. win32all is *very* Pythonic.
                  Maybe Mark Hammond's win32all provides such a magic wrapper, but Cartsen
                  Haese's example didn't use it. Instead it provided it own implementation
                  of the COM IEnumVARIANT interface, the OLE Automation (ie. VisualBasic
                  6 compatable) way implementing iteratable objects.

                  Ross Ridge

                  --
                  l/ // Ross Ridge -- The Great HTMU
                  [oo][oo] rridge@csclub.u waterloo.ca
                  -()-/()/ http://www.csclub.uwaterloo.ca/~rridge/
                  db //

                  Comment

                  • Steve Holden

                    #10
                    Re: Python COM iterator

                    Ross Ridge wrote:
                    Larry Bates wrote:
                    >I tested in VB and by golly it works! What is odd is that this looks
                    >NOTHING like what we got from the docs earlier. No GetEnumerator
                    >method, no MoveNext method. I'm glad it works, but I'm a little
                    >puzzled as to why it works.
                    >
                    The documention Carsten Haese referenced earlier was for the .NET version
                    of VisualBasic, and shows how to use .NET's IEnumerate and IEnumerable
                    interfaces.
                    >
                    Steve Holden <steve@holdenwe b.comwrote:
                    >Presumably the magic of mark Hammond's wrapper classes providing
                    >adaptation between Python iteration and COM enumerable collection
                    >objects. win32all is *very* Pythonic.
                    >
                    Maybe Mark Hammond's win32all provides such a magic wrapper, but Cartsen
                    Haese's example didn't use it. Instead it provided it own implementation
                    of the COM IEnumVARIANT interface, the OLE Automation (ie. VisualBasic
                    6 compatable) way implementing iteratable objects.
                    >
                    Ross Ridge
                    >
                    So I saw when I read Carsten's reply to my post. Thanks. It's the
                    difference between COM and .NET (something I am currently having to come
                    to terms with myself, but strangely in C# rather than Python).

                    regards
                    Steve
                    --
                    Steve Holden +44 150 684 7255 +1 800 494 3119
                    Holden Web LLC/Ltd http://www.holdenweb.com
                    Skype: holdenweb http://del.icio.us/steve.holden
                    Recent Ramblings http://holdenweb.blogspot.com

                    Comment

                    Working...