def expose_input(
        self, name, val=None, attribute=None, dtype=None, use_namednode=False
    ):
        """
        Expose an input to the nodegroups interface, making it able to be specified externally

        If this nodegroup is
        """

        if attribute is not None:
            if self.modifier is None and val is None:
                raise ValueError(
                    "Attempted to use expose_input(attribute=...) on NodeWrangler constructed from "
                    "node_tree.\n"
                    "Please construct by passing in the modifier instead, or specify expose_input(val=..., "
                    "attribute=...) to provide a fallback"
                )

        if use_namednode:
            assert dtype is not None
            return self.new_node(
                Nodes.NamedAttribute, [name], attrs={"data_type": dtype}
            )

        group_input = self.new_node(Nodes.GroupInput)  # will reuse singleton

        if name in ng_inputs(self.node_group):
            assert len([o for o in group_input.outputs if o.name == name]) == 1
            return group_input.outputs[name]

        # Infer from args what type of node input to make (NodeSocketFloat / NodeSocketVector / etc)
        nodeclass = self._infer_nodeclass_from_args(dtype, val)
        inp = self.node_group.interface.new_socket(
            name, in_out="INPUT", socket_type=nodeclass
        )

        def prepare_cast(to_type, val):
            # cast val only when necessary, and only when type(val) wont crash
            if to_type not in [bpy.types.bpy_prop_array, bpy.types.bpy_prop]:
                val = to_type(val)
            return val

        if val is not None:
            if not hasattr(inp, "default_value") or inp.default_value is None:
                raise ValueError(
                    f"expose_input() recieved {val=} but inp {inp} does not expect a default_value"
                )
            inp.default_value = prepare_cast(type(inp.default_value), val)

        if self.modifier is not None:
            id = inp.identifier
            if val is not None:
                curr_mod_inp_val = self.modifier[id]
                if hasattr(curr_mod_inp_val, "real"):
                    self.modifier[id] = prepare_cast(type(curr_mod_inp_val.real), val)
            if attribute is not None:
                self.modifier[f"{id}_attribute_name"] = attribute
                self.modifier[f"{id}_use_attribute"] = 1

        assert len([o for o in group_input.outputs if o.name == name]) == 1
        return group_input.outputs[name]

        Expose an input to the nodegroups interface, making it able to be specified externally

        If this nodegroup is
        
infinigen/core/nodes/node_wrangler.py