SOLVED Is ObjectIterator() parsing depreciated under R23 and higher?

Hello folks,

I trying to update a plugin which has been developed for C4D R21.x and Python 2 to C4D R23 and higher which is running Python 3. I got almost everything working now except a redundant issue I'm getting with ObjectIterator() parsing. So, I wondering if the use I made of it is wrong, or if this lib is depreciated?

Here the code running under Python 2 without any issues on C4D R21,

def RetreiveTags(self):
        self.tagList = []
        obj = self.cacheDoc.GetFirstObject()
        scene = ObjectIterator(obj)
        for obj in scene:
            tags = TagIterator(obj)
            for tag in tags:
                self.tagList.append(tag)

But while I'm running the same code under C4D R23 with Python 3 I'm getting this error:

Traceback (most recent call last):
  File "TestIterator.pyp", line 204, in CoreMessage
    self.RetreiveTags()
  File "TestIterator.pyp", line 160, in RetreiveTags
    for obj in scene:
TypeError: iter() returned non-iterator of type 'ObjectIterator'

The line in error, is the one with the for tag in tags:

After some readings, especially this one http://cgrebel.com/2015/03/c4d-python-scene-iterator/ , I assume that the error comes from the raise StopIteration

Is there a way to get this library works normally as it was under R21 or should I update the code like I already did with my own iterator for object list?

Any advises are as usual more than welcome!
Thanks a lot,

Christophe

Hello @mocoloco,

thank you for reaching out to us. We did reactivate this topic because we do think it contains a problem that might be relevant to other users.

First of all, we would like to point out that this question is formally out of scope of support, since it is about third-party code and why it is not working. Please refer to the Forum Guidelines for details on what is eligible for support and what not. We cannot debug third party code for users.

In this case however, one can see the reason immediately, due to the code being quite short and you providing a link. The code for the class ObjectIterator has been written in 2015 for Python 2 and is still using the old object interface of Python. With R23 Cinema did move to Python 3 and therefor also to the new object interface. You list R21 and R23 as versions in your tags. I would expect this code to work in R21 (which has a CPython 2 interpreter), but not in R23 (which has a CPython 3 interpreter).

Cinema is throwingTypeError: iter() returned non-iterator of type 'ObjectIterator' when you try to run for obj in ObjectIterator(obj):. What is happening is that in will invoke the __iter__ implementation of ObjectIterator which just returns a reference to the object itself. The interpreter then looks for __next__() in your object and cannot find it, then throwing this error. Python 2.x's next has changed to __next__ with Python 3.x. But there are also other changes, which will make that code not work if you do just change the name of the method ObjectIterator.next to ObjectIterator.__next__. We cannot provide here support on learning Python, I would suggest reading content on the difference of the object interface between 2.x and 3.x. However, a minimal solution for your case could look like this:

class Iterator():
    """A minimal Python 3.x conformant iterator implementation.
    """

    def __init__(self, data):
        self._data = data

    def __iter__(self):
        for item in self._data:
            yield item

for item in Iterator([1, 2, 3, 4, 5]):
    print (item)

Cheers,
Ferdinand

I went a but further in this old code and discover that the plugin was based on the class I linked in my previous post.
There is now better ways to get the same result with BaseObject.GetTags(). I simply got rid of this class and change the code to parse everything.
Done.

Cheers.

Hello @mocoloco,

thank you for reaching out to us. We did reactivate this topic because we do think it contains a problem that might be relevant to other users.

First of all, we would like to point out that this question is formally out of scope of support, since it is about third-party code and why it is not working. Please refer to the Forum Guidelines for details on what is eligible for support and what not. We cannot debug third party code for users.

In this case however, one can see the reason immediately, due to the code being quite short and you providing a link. The code for the class ObjectIterator has been written in 2015 for Python 2 and is still using the old object interface of Python. With R23 Cinema did move to Python 3 and therefor also to the new object interface. You list R21 and R23 as versions in your tags. I would expect this code to work in R21 (which has a CPython 2 interpreter), but not in R23 (which has a CPython 3 interpreter).

Cinema is throwingTypeError: iter() returned non-iterator of type 'ObjectIterator' when you try to run for obj in ObjectIterator(obj):. What is happening is that in will invoke the __iter__ implementation of ObjectIterator which just returns a reference to the object itself. The interpreter then looks for __next__() in your object and cannot find it, then throwing this error. Python 2.x's next has changed to __next__ with Python 3.x. But there are also other changes, which will make that code not work if you do just change the name of the method ObjectIterator.next to ObjectIterator.__next__. We cannot provide here support on learning Python, I would suggest reading content on the difference of the object interface between 2.x and 3.x. However, a minimal solution for your case could look like this:

class Iterator():
    """A minimal Python 3.x conformant iterator implementation.
    """

    def __init__(self, data):
        self._data = data

    def __iter__(self):
        for item in self._data:
            yield item

for item in Iterator([1, 2, 3, 4, 5]):
    print (item)

Cheers,
Ferdinand

Hello @ferdinand, thanks a lot for your time and reply.
I indeed discovered that the code was for Python 2 when I went I bit further in the code analysis.
I thought it was a c4d library, and that's was my mistake and indeed it was totally out of the scope to place it here; sorry.
In the meantime, I got rid of that class and made my own iterator method - not a class itself like you did to update the old one (but that's also a good idea).

It was quite easy to iterate all the tags by simply use GetTags() which gives the following,

          tags = obj.GetTags()
                if tags is not None:
                    for tag in tags:
                        print (tag.GetTypeName() + " found") 
                        self.tagList.append(tag)

Thanks for your time!
Christophe

Hello @mocoloco,

without any further replies or questions, we will consider this thread as solved by Thursday and flag it accordingly.

Thank you for your understanding,
Ferdinand