Unregistering connected input param in python component

hello!

I am working on a component that adaptively adds and removes input parameters depending on an initial input. When I call UnregisterInputParameter() on a connected param, even with with the isolate bool set to True, I get an object expired during solution error in a popup. The dynamic registering and unregistering of inputs is otherwise working fine. I tried using the IGH_Param.IsolateObject() method to disconnect the param before unregistering, but that didn’t work. The component takes a custom class with an input_names attribute which looks like this:

class input(object):
    def __init__(self):
        self.input_names = ["input 1", "input 2"]
    
a = input()

or

class input(object):
    def __init__(self):
        self.input_names = ["input 3", "input 4"]
    
a = input()

Here is the component script itself:

from ghpythonlib.componentbase import executingcomponent as component
from Grasshopper.Kernel.GH_RuntimeMessageLevel import Error
from Grasshopper.Kernel.GH_RuntimeMessageLevel import Warning
import Grasshopper

doc = Grasshopper.Instances.ActiveCanvas.Document

def add_GH_param(name, io, ghenv):  
    """Adds a parameter to the Grasshopper component. """
    assert io in ("Output", "Input")
    params = [param.NickName for param in getattr(ghenv.Component.Params, io)]
    if name not in params:
        param = Grasshopper.Kernel.Parameters.Param_GenericObject()
        param.NickName = name
        param.Name = name
        param.Description = name
        param.Access = Grasshopper.Kernel.GH_ParamAccess.item
        param.Optional = True
        index = getattr(ghenv.Component.Params, io).Count
        registers = dict(Input="RegisterInputParam", Output="RegisterOutputParam")
        getattr(ghenv.Component.Params, registers[io])(param, index)



def clear_GH_params(ghenv, permanent_param_count=1):
    """Clears all input parameters from the component. """
    changed = False
    while len(ghenv.Component.Params.Input) > permanent_param_count:
        ghenv.Component.Params.Input[len(ghenv.Component.Params.Input) - 1].IsolateObject()
        ghenv.Component.Params.UnregisterInputParameter(
            ghenv.Component.Params.Input[len(ghenv.Component.Params.Input) - 1],
            True
        )
        changed = True
    ghenv.Component.Params.OnParametersChanged()
    return changed


def manage_dynamic_params(input_names, ghenv, permanent_param_count=1):
    """manages component input parameters. """

    if not input_names:  # if no names are input
        return clear_GH_params(ghenv, permanent_param_count)

    else:
        register_params = False
        if len(ghenv.Component.Params.Input) == len(input_names) + permanent_param_count:           #if param count matches input_names count
            for i, name in enumerate(input_names):
                if ghenv.Component.Params.Input[i + permanent_param_count].Name != name:            #if param names don't match
                    register_params = True
                    break
        else:
            register_params = True
        if register_params:
            clear_GH_params(ghenv, permanent_param_count)       #we could consider renaming params if we don't want to disconnect GH component inputs
            for name in input_names:
                add_GH_param(name, "Input", ghenv)
            return True
        else:
            return False
            

class DirectJointRule(component):
    def RunScript(self, original_input, *args):
        names = None
        if original_input:
            names = [name for name in original_input.input_names]

        if manage_dynamic_params(names, ghenv):
            ghenv.Component.Params.OnParametersChanged()
            doc.ScheduleSolution(1)
            return
        
        return args

I tried a bunch of different things like ScheduleSolution(), ExpireSolution(), etc, but havent got this error to go away. If i click “do not show message again” then the component acts as I want it to.

Any help would be greatly appreciated!

Thanks

So there are two issues which are presumably related:

Maybe I can simplify the question:

How do I remove an input parameter on a python script component in component mode without causing Index out of range errors?

With this code:

class adaptiveComponent(component):
    def input_count(self):
        return len(ghenv.Component.Params.Input)
        

    def RunScript(self, remove, *args):
        permanent_inputs = 2
        if remove:
            print([input.Name for input in ghenv.Component.Params.Input])
            while len(ghenv.Component.Params.Input) > permanent_inputs:
                print("removing {}".format( ghenv.Component.Params.Input[self.input_count() -1].Name))
                ghenv.Component.Params.UnregisterInputParameter(
                    ghenv.Component.Params.Input[self.input_count() -1],
                    True
                )
#                ghenv.Component.Params.OnParametersChanged()
#                ghenv.Component.ExpireSolution(True)
                print([input.Name for input in ghenv.Component.Params.Input])

and this component:
image

When I press the button I get:

image

and then the expected output, including the input parameters being removed:

['x', 'y', 'z', 'u', 'v', 'w']
removing w
['x', 'y', 'z', 'u', 'v']
removing v
['x', 'y', 'z', 'u']
removing u
['x', 'y', 'z']
removing z
['x', 'y']

with the same code but an input component connected to the input parameters the error is this:
image

before also printing the expected message…

Thanks!

Hey I know this is a old thread but did you ever find a solution to this issue? I’m also having the same issue as you are describing.

hello! I did solve it, but that was a while ago. Looking at the code, I think you just have to run param.IsolateObject() before removing with UnregisterInputParameter(param, bool)

like this:

param = ghenv.Component.Params.Input[-1]          
param.IsolateObject()
ghenv.Component.Params.UnregisterInputParameter(param, True)

I hope that solves it for you!

Thank you for your response. With that added I’m still encountering the issue. Do you mind sharing your code snippet so maybe I can use it as a reference? Thanks in advance!

Hey!

The code is a bit spread out over various modules and components, and I’m not sure I can really do a code snippet per se. We made a bunch of helper functions that allow us to manipulate the params more easily. you can find those here. You can find examples of how we use them in a script component here.

I hope that helps.

hey I ended up making a post about this with the script all in one component.

you can find it here

Hey thank you for sharing these. It’s really helpful!

Just out of curiosity, have you ever tried doing something like this?

Do you think something like this doable using ghpython?