Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Login

    TypeError: GeListNode_ass_subscript when creating a new object

    Cinema 4D SDK
    python 2024
    2
    7
    768
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • John_DoJ
      John_Do
      last edited by

      Hello,

      I have the following error message in one of my script ( which is iteraring over shaders) when I perfom these steps :

      1. running the script over the materials
      2. performing an undo
      3. running the script again > error
      TypeError: GeListNode_ass_subscript expected Description identifier, not None
      
      The above exception was the direct cause of the following exception:
      
      Traceback (most recent call last):
        File "scriptmanager", line 198, in <module>
        File "scriptmanager", line 171, in main
        File "scriptmanager", line 84, in convert_c4d_bitmap
        File "scriptmanager", line 116, in create_cr_bitmap_shader
      SystemError: <class 'c4d.BaseShader'> returned a result with an exception set
      

      I've seen another topic where the same error was reported, but in this case the error is happening on the line responsible for creating a new BaseShader object ( first line of the function below ). Undo / Redo commands are working perfectly fine, so I really don't see how I could fix this one.

      def create_cr_bitmap_shader(filepath, colorspc, basename, exposure, shader):
          cr_bitmap = c4d.BaseShader(1036473)
          cr_bitmap_bc = cr_bitmap.GetDataInstance()
          cr_bitmap_bc.SetFilename(c4d.CORONA_BITMAP_FILENAME, filepath)
          cr_bitmap_bc.SetInt32(c4d.CORONA_BITMAP_COLORPROFILE, colorspc)
          cr_bitmap_bc.SetString(c4d.ID_BASELIST_NAME, basename)
          cr_bitmap_bc.SetFloat(c4d.CORONA_BITMAP_EXPOSURE, exposure)
          return cr_bitmap  # Return the bitmap shader object for further material insertion
      

      The result of the error is a messed up shader tree, with some shaders missing file path, others completely removed from the scene.

      Thank you

      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by

        Hi, please post a reproducible example, because with the information you posted we can't help you much since the code you posted does not contain any use of GeListNode_ass_subscript

        Cheers,
        Maxime.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        John_DoJ 1 Reply Last reply Reply Quote 0
        • John_DoJ
          John_Do @m_adam
          last edited by

          Hi Maxime,

          It's a script for Corona for Cinema 4D so I don't know if it'll be of any use to you. But from what I've understood materials and shaders structure are identical to the Standard C4D Material, so I've reduced the script to its essentials by removing few parameters, code below.

          import c4d
          import time
          
          
          
          def iter_shaders(node):
              """Credits go to @ferdinand and @HerrMay over 
              at https://developers.maxon.net/ for the tree-traversal method
          
              Yields all descendants of ``node`` in a truly iterative fashion.
          
              The passed node itself is yielded as the first node and the node graph is
              being traversed in depth first fashion.
          
              This will not fail even on the most complex scenes due to truly
              hierarchical iteration. The lookup table to do this, is here solved with
              a dictionary which yields favorable look-up times in especially larger
              scenes but results in a more convoluted code. The look-up could
              also be solved with a list and then searching in the form ``if node in
              lookupTable`` in it, resulting in cleaner code but worse runtime metrics
              due to the difference in lookup times between list and dict collections.
              """
              if not node:
                  return
          
              # The lookup dictionary and a terminal node which is required due to the
              # fact that this is truly iterative, and we otherwise would leak into the
              # ancestors and siblings of the input node. The terminal node could be
              # set to a different node, for example ``node.GetUp()`` to also include
              # siblings of the passed in node.
              visited = {}
              terminator = node
          
              while node:
          
                  if isinstance(node, c4d.BaseMaterial) and not node.GetFirstShader():
                      break
          
                  if isinstance(node, c4d.BaseMaterial) and node.GetFirstShader():
                      node = node.GetFirstShader()
          
                  # C4DAtom is not natively hashable, i.e., cannot be stored as a key
                  # in a dict, so we have to hash them by their unique id.
                  node_uuid = node.FindUniqueID(c4d.MAXON_CREATOR_ID)
                  if not node_uuid:
                      raise RuntimeError("Could not retrieve UUID for {}.".format(node))
          
                  # Yield the node when it has not been encountered before.
                  if not visited.get(bytes(node_uuid)):
                      yield node
                      visited[bytes(node_uuid)] = True
          
                  # Attempt to get the first child of the node and hash it.
                  child = node.GetDown()
          
                  if child:
                      child_uuid = child.FindUniqueID(c4d.MAXON_CREATOR_ID)
                      if not child_uuid:
                          raise RuntimeError(
                              "Could not retrieve UUID for {}.".format(child))
          
                  # Walk the graph in a depth first fashion.
                  if child and not visited.get(bytes(child_uuid)):
                      node = child
          
                  elif node == terminator:
                      break
          
                  elif node.GetNext():
                      node = node.GetNext()
          
                  else:
                      node = node.GetUp()
          
          
          def convert_c4d_bitmap(doc, c4d_bitmap, remove=True):
              # Create the bitmap object in memory
              cr_bitmap = create_cr_bitmap_shader(
                  c4d_bitmap[c4d.BITMAPSHADER_FILENAME])
              if isinstance(c4d_bitmap.GetUp(), c4d.BaseShader):
                  parent = c4d_bitmap.GetUp()
                  # Looking for the slot in the parent base
                  # container where the shader is inserted
                  parent_shader_slot = get_bc_id(parent.GetDataInstance(), c4d_bitmap)
                  cr_bitmap.InsertUnder(parent)  # Insert the bitmap in the shader
                  doc.AddUndo(c4d.UNDOTYPE_NEW, cr_bitmap)
                  doc.AddUndo(c4d.UNDOTYPE_CHANGE, parent)
                  # Linking the bitmap in the right slot
                  parent[parent_shader_slot] = cr_bitmap
              elif isinstance(c4d_bitmap.GetMain(), c4d.BaseMaterial):
                  parent = c4d_bitmap.GetMain()
                  parent_shader_slot = get_bc_id(parent.GetDataInstance(), c4d_bitmap)
                  parent.InsertShader(cr_bitmap)
                  doc.AddUndo(c4d.UNDOTYPE_NEW, cr_bitmap)
                  doc.AddUndo(c4d.UNDOTYPE_CHANGE, parent)
                  parent[parent_shader_slot] = cr_bitmap
              # Removing the old bitmap
              if remove:
                  doc.AddUndo(c4d.UNDOTYPE_DELETEOBJ, c4d_bitmap)
                  c4d_bitmap.Remove()
              return cr_bitmap
          
          
          def create_cr_bitmap_shader(filepath):
              cr_bitmap = c4d.BaseShader(1036473)
              cr_bitmap_bc = cr_bitmap.GetDataInstance()
              cr_bitmap_bc.SetFilename(c4d.CORONA_BITMAP_FILENAME, filepath)
              return cr_bitmap  # Return the bitmap shader object for further material insertion
          
          
          def get_bc_id(target_bc, target_value):
              for index, value in target_bc:
                  if value == target_value:
                      return index
          
          
          def main():
          
              doc = c4d.documents.GetActiveDocument()
          
              materials = doc.GetActiveMaterials()
          
              doc.StartUndo()
          
              # Performance measurements
              tic = time.perf_counter()
              c = 0
          
              # Main loop
              for material in materials:
          
                  mtl_shaders = []
          
                  # Step over non Corona Physical materials or Corona Legacy materials.
                  if material.GetType() not in (1056306, 1032100):
                      continue
          
                  print(f"{material = }")
          
                  for shader in iter_shaders(material):
                      if shader.GetRealType() == c4d.Xbitmap:
                          mtl_shaders.append(shader)
          
                  if mtl_shaders:
                      for i in mtl_shaders:
                          c += 1
                          convert_c4d_bitmap(doc, i)
          
                  print(end="\n")
          
              # Performance measurements
              toc = time.perf_counter()
              print(
                  f"Bitmap conversion successful: {c} shaders converted in {toc - tic:0.4f} seconds ")
          
              doc.EndUndo()
          
              c4d.EventAdd()
          
          
          if __name__ == '__main__':
              main()
          

          One thing worth mentionning : with this version, I've got the also a TypeError but the Traceback is different, now the AddUndo method raises an exception.

          Traceback (most recent call last):
            File "scriptmanager", line 162, in <module>
            File "scriptmanager", line 147, in main
            File "scriptmanager", line 99, in convert_c4d_bitmap
          SystemError: <method 'AddUndo' of 'c4d.documents.BaseDocument' objects> returned a result with an exception set
          

          Thank you

          1 Reply Last reply Reply Quote 0
          • M
            m_adam
            last edited by

            Hey, sadly I can't reproduce your issue, can you provide a test scene?

            MAXON SDK Specialist

            Development Blog, MAXON Registered Developer

            1 Reply Last reply Reply Quote 0
            • John_DoJ
              John_Do
              last edited by

              Hi Maxime,

              Thank for looking into this, I'll send you my test scene by DM since it contains some 3rd party textures.

              1 Reply Last reply Reply Quote 0
              • M
                m_adam
                last edited by

                Hi the issue is that there some shaders that are shared between multiple instances. So meaning when you change one you also change the others.
                So you have to take into account that in your convert_c4d_bitmap method, since you are deleting the original things in any case.

                So with that's said in order to not have this exception you need to adapt your code to not to try to delete a node that have been already deleted:

                def convert_c4d_bitmap(doc, c4d_bitmap, remove=True):
                    # Create the bitmap object in memory
                    cr_bitmap = create_cr_bitmap_shader(c4d_bitmap[c4d.BITMAPSHADER_FILENAME])
                    cr_bitmap_added = True
                    if isinstance(c4d_bitmap.GetUp(), c4d.BaseShader):
                        parent = c4d_bitmap.GetUp()
                        # Looking for the slot in the parent base
                        # container where the shader is inserted
                        parent_shader_slot = get_bc_id(parent.GetDataInstance(), c4d_bitmap)
                        cr_bitmap.InsertUnder(parent)  # Insert the bitmap in the shader
                        doc.AddUndo(c4d.UNDOTYPE_NEW, cr_bitmap)
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, parent)
                        # Linking the bitmap in the right slot
                        parent[parent_shader_slot] = cr_bitmap
                    
                    elif isinstance(c4d_bitmap.GetMain(), c4d.BaseMaterial):
                        parent = c4d_bitmap.GetMain()
                        parent_shader_slot = get_bc_id(parent.GetDataInstance(), c4d_bitmap)
                        parent.InsertShader(cr_bitmap)
                        doc.AddUndo(c4d.UNDOTYPE_NEW, cr_bitmap)
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, parent)
                        parent[parent_shader_slot] = cr_bitmap
                
                    else:
                        cr_bitmap_added = False
                
                    # Removing the old bitmap
                    if remove and cr_bitmap_added:
                        doc.AddUndo(c4d.UNDOTYPE_DELETEOBJ, c4d_bitmap)
                        c4d_bitmap.Remove()
                
                    return cr_bitmap
                

                Cheers,
                Maxime.

                MAXON SDK Specialist

                Development Blog, MAXON Registered Developer

                1 Reply Last reply Reply Quote 0
                • John_DoJ
                  John_Do
                  last edited by

                  Hi Maxime,

                  Thank you very much for looking at my issue.
                  Did you try the new function ? I've added it in my code and unfortunately I get the same result as before.

                  Cinema_4D_3JwcCopDUD.gif

                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post