Compiled .ghpy input tree access error

compiled a component and it gives me this error
it works ok before compilation
input at index 0 is this

image

any help please?

UPDATE: I changed Param_Geometry() to Param_GenericObject() and it seemed ok but the second input now is erroneous.

So does the GH_ParamAccess.tree not work with any other type than Param_GenericObject()???

When you compile advanced components, you will sometimes need to copy and paste the code to a file and analyze what “code generation” created for you. In general it should work, though. DataTrees might need to have some additional treatment, because there is no support for the DataTree type in pure GH SDK, but GH uses the GH_Structure type internally.

Could you post your code here so I can have a look?
You can skip the ‘RunScript’ method except for a sample of the expected and returned objects.

Thanks,

Giulio


Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

Sorry about the indent. You can assume I got them right.

from ghpythonlib.componentbase import dotnetcompiledcomponent as component
import Grasshopper, GhPython
import System
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
import ghpythonlib.treehelpers as tree

class Load(component):
    def __new__(cls):
        instance = Grasshopper.Kernel.GH_Component.__new__(cls,
            "Load", "Load", """analyze objects""", "Params", "Util")
        return instance

def get_ComponentGuid(self):
    return System.Guid("3b7be4ce-e0ec-4f87-bf95-879ec3a98757")

def SetUpParam(self, p, name, nickname, description):
    p.Name = name
    p.NickName = nickname
    p.Description = description
    p.Optional = True

def RegisterInputParams(self, pManager):
    p = Grasshopper.Kernel.Parameters.Param_Geometry()
    self.SetUpParam(p, "O", "O", "all objects")
    p.Access = Grasshopper.Kernel.GH_ParamAccess.tree
    self.Params.Input.Add(p)
    
    p = Grasshopper.Kernel.Parameters.Param_String()
    self.SetUpParam(p, "T", "T", """option tag""")
    p.Access = Grasshopper.Kernel.GH_ParamAccess.tree
    self.Params.Input.Add(p)
    
    p = Grasshopper.Kernel.Parameters.Param_Boolean()
    self.SetUpParam(p, "b", "b", "boolean")
    p.Access = Grasshopper.Kernel.GH_ParamAccess.item
    self.Params.Input.Add(p)
    

def RegisterOutputParams(self, pManager):
    pass    
def SolveInstance(self, DA):
    p0 = self.marshal.GetInput(DA, 0)
    p1 = self.marshal.GetInput(DA, 1)
    p2 = self.marshal.GetInput(DA, 2)
    result = self.RunScript(p0, p1, p2)

    
def get_Internal_Icon_24x24(self):
    o = ""
    return System.Drawing.Bitmap(System.IO.MemoryStream(System.Convert.FromBase64String(o)))

def RunScript(self, O, T, b):
    
    
    # return outputs if you have them; here I try it for you:
    return None

Thanks to your report, I just discovered a bug, or maybe a missing feature, that would allow to directly handle GH_Structure<specializedtype> from GhPython compiled components (GHPYs).

To be able to immediately consume this type of object (as you noticed, the only working one is the GH_Goo type, which handles the most generic no-hint case), I wrote an additional static method that you can add to your class: structure_to_list. Here is a fully sample that works with GH_Structure (the equivalent of DataTree outside of scripting components. This converts the structure to a list of lists, much easier to use in Python.

from ghpythonlib.componentbase import dotnetcompiledcomponent as component
import Grasshopper, GhPython
import System
import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
import ghpythonlib.treehelpers as tree

class Load(component):
    def __new__(cls):
        instance = Grasshopper.Kernel.GH_Component.__new__(cls,
            "Load2", "Load2", """analyze objects""", "Params", "Util")
        return instance
    
    def get_ComponentGuid(self):
        return System.Guid("7b7be4ce-e0ec-4f87-bf95-879ec3a98757")
    
    def SetUpParam(self, p, name, nickname, description):
        p.Name = name
        p.NickName = nickname
        p.Description = description
        p.Optional = True
    
    def RegisterInputParams(self, pManager):
        p = Grasshopper.Kernel.Parameters.Param_Geometry()
        self.SetUpParam(p, "O", "O", "all objects")
        p.Access = Grasshopper.Kernel.GH_ParamAccess.tree
        self.Params.Input.Add(p)
        
        p = Grasshopper.Kernel.Parameters.Param_String()
        self.SetUpParam(p, "T", "T", """option tag""")
        p.Access = Grasshopper.Kernel.GH_ParamAccess.item
        self.Params.Input.Add(p)
        
        p = Grasshopper.Kernel.Parameters.Param_Boolean()
        self.SetUpParam(p, "b", "b", "boolean")
        p.Access = Grasshopper.Kernel.GH_ParamAccess.item
        self.Params.Input.Add(p)
        
    
    def RegisterOutputParams(self, pManager):
        p = Grasshopper.Kernel.Parameters.Param_GenericObject()
        self.SetUpParam(p, "a", "a", "Script output a.")
        self.Params.Output.Add(p)
        
    def SolveInstance(self, DA):
        val, p0 = DA.GetDataTree[Grasshopper.Kernel.Types.IGH_GeometricGoo](0) #change to GH_String, GH_Brep,...
        if p0: p0 = Load.structure_to_list(p0)
        p1 = self.marshal.GetInput(DA, 1)
        p2 = self.marshal.GetInput(DA, 2)
        result = self.RunScript(p0, p1, p2)
        if result is not None:
            self.marshal.SetOutput(result, DA, 0, True)
    
    # written by Giulio Piacentino, giulio@mcneel.com
    @staticmethod
    def structure_to_list(input, retrieve_base = lambda x: x[0]):
        """Returns a list representation of a Grasshopper DataTree"""
        def extend_at(path, index, simple_input, rest_list):
            target = path[index]
            if len(rest_list) <= target: rest_list.extend([None]*(target-len(rest_list)+1))
            if index == path.Length - 1:
                rest_list[target] = list(simple_input)
            else:
                if rest_list[target] is None: rest_list[target] = []
                extend_at(path, index+1, simple_input, rest_list[target])
        all = []
        for i in range(input.PathCount):
            path = input.Path[i]
            extend_at(path, 0, input.Branch[path], all)
        return retrieve_base(all)
    
    def RunScript(self, O, T, b):
        
        
        # return outputs if you have them; here I try it for you:
        return O

import GhPython
import System

class AssemblyInfo(GhPython.Assemblies.PythonAssemblyInfo):
    def get_AssemblyName(self):
        return "PyN"
    
    def get_AssemblyDescription(self):
        return """"""

    def get_AssemblyVersion(self):
        return "0.1"

    def get_AuthorName(self):
        return ""
    
    def get_Id(self):
        return System.Guid("d0adc7c0-d053-4da6-8cdf-f002c013a959")

Additionally, I am adding a bugfix that will permit to directly consume GH_Structures as datatrees from GHPYs in a new Service Release of Rhino 6.

You can track it here: RH-48754.

Thanks,

Giulio


Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

is that equivalent to ghpythonlib.treehelpers.tree_to_list()?

Yes, that will translate from GH_Structure to lists of lists, like tree_to_list() will translate from DataTree to lists of lists.

RH-48754 is fixed in the latest Service Release Candidate