SOLVED Storing node data in a Tag plugin

I try to save an object (using IsolateObjects()) using the Tag plugins Write() function.

Here the code:

class EDITABLECLEANTAG(plugins.TagData):

    myData = None

    def Write(self, node, HFfile):
        print "WRITE myData: ", self.myData
        # Store the size
        # Store the data itself
        if HFfile.WriteMemory(self.myData[0]) is False:
            raise ValueError("can't write the file")
        return True
    def Message(self, tag, type, data):

        doc = tag.GetDocument()
        id = GetMessageID(data)
        if id == CLICK_EDITABLECLEAN:  # If this Gizmo is activated

            # using a MemoryFileStructure to store a document
            mfs =

            IsolateObject = tag.GetObject()
            print "IsolateObject: ", IsolateObject
            newdoc = c4d.documents.IsolateObjects(doc , [IsolateObject])
            # Save the document to the MemoryFileStructure
            c4d.documents.SaveDocument(newdoc, mfs, c4d.SAVEDOCUMENTFLAGS_NONE, c4d.FORMAT_C4DEXPORT)

            #Retrieve the data and store it somewhere, here in self.myData
            self.myData = mfs.GetData()
            print "Data saved: ", self.myData

When a button is clicked in the tag UI, I do an IsolateObjects(), and then store the resulting newdoc in myData.
Later on, when the scene file is saved, the Write() function is called automatically and the data is saved.

However, it looks to me that c4d.documents.SaveDocument() also calls Write().
If so, myData is not filled yet, and an error occurs.


What am I doing wrong?


well, you answered your question yourself. You are trying to index myData with the bracket syntax (i.e. invoke __getitem__) which causes an excpetion when myData is None. You have to test first, if the class dictionary of myData contains __getitem__, or more straight forward - if it is not of type None.



as @zipit said, you have to check your data before trying to write them on the HF.

Another thing, in your code you are trying to isolate the object, don't forget it will isolate your tag also.
You should use a command data that will

  • isolate the hierarchy,
  • retrieve a polygon object from it and insert it in your document.
  • add the tag to your object that will store the old hierarchy

Even if i still think a generator should work better.


@zipit, The strange thing is the sequence of things / of messages in the console.

In the code I do:

  • print "IsolateObject: ", IsolateObject
  • c4d.documents.SaveDocument(newdoc, mfs, c4d.SAVEDOCUMENTFLAGS_NONE, c4d.FORMAT_C4DEXPORT)
  • self.myData = mfs.GetData() and print "Data saved: ", self.myData

So, in the console I would expect:

  • "IsolateObject: ", IsolateObject
  • "Data saved: ", self.myData

But what I get in the console is:

  • "IsolateObject: ", IsolateObject
  • "WRITE myData: ", self.myData !!! This tells me that the Write function is called?
    And because the write function is called before the statement self.myData = mfs.GetData(), self.myData is None!
  • "Data saved: ", self.myData

So the question is, why is the Write function called?
I guess it is called by c4d.documents.SaveDocument()?


As i said, when you are isolating the object you are also isolating your tag with it.
you save the new document where your object is isolated (with a copy of your tag).
So, this "second" tag is calling the write function.

if your print out the "self" you should see two different instances of your tag.

That's why you should use a CommandData to store the hierarchy in your tag.
And the tag to "restore" the hierarchy.


@m_magalhaes, Aha, clear.
I will convert it to a Command plugin.
However, I find an issue with Isolate().
I will open another thread for that one.
Basically it is that when I isolate a Cloner, the effector is not 'copied'.

For now let's close this thread.
Thanks for all the information and your patience.



@m_magalhaes already explained the reason for your problem, I would just like to point out a more general misconception which does not only apply to this specific problem.

You assumption is that NodeData.Write() is being called once you are "ready", i.e. the user has clicked the button in the interface (I assume that message ID is a button), i.e. after a call to NodeData.Message(). You cannot make this assumption in general with SDKs that let you interface with complex objects. Things might get called not in an order you would consider consecutive, multiple times for no apparent reason, or in the oddest situations you do not really anticipate at all. So you have to check all your inputs and outputs every time.


@zipit, thanks for this extra information!
Indeed my assumption is / was that Write is only called, when you save the scene file.