How can I connect nodes in a node group to the input or output sockets?

This connection here:

enter image description here

I can't figure out how to access the group node_tree, and the Group node as well as the Group input/output nodes seem to be different than normal nodes.

My script so far:

import bpy

for area in bpy.context.screen.areas:
    if area.type == "NODE_EDITOR":
        override = {'screen': bpy.context.screen, 'area': area}
bpy.ops.node.select_all(override, action='DESELECT')

tree = bpy.context.object.active_material.node_tree
nodes = tree.nodes
links = tree.links

node = nodes.new(type='ShaderNodeMath')
node.operation = "ADD"
node.location = (100,0)
node_add = node

node = nodes.new(type='ShaderNodeMath')
node.operation = "GREATER_THAN"
node.name = "greater"
node.location = (-100,100)
links.new(node.outputs["Value"], node_add.inputs[0])

node = nodes.new(type='ShaderNodeMath')
node.operation = "LESS_THAN"
node.name = "less"
node.location = (-100,-100)
links.new(node.outputs["Value"], node_add.inputs[1])

bpy.ops.node.tree_socket_add(override, in_out='IN')
bpy.ops.node.tree_socket_add(override, in_out='IN')
bpy.ops.node.tree_socket_add(override, in_out='OUT')

2 Answers 2


As a rule of thumb, you should try to avoid operator calls in scripts and use api functions directly as much as possible (if you do this, no need to override). So the snippet below is not needed.

for area in bpy.context.screen.areas:
    if area.type == "NODE_EDITOR":
        override = {'screen': bpy.context.screen, 'area': area}
bpy.ops.node.select_all(override, action='DESELECT')

Through some experimenting, I found it's easier to not use group_make as the default GroupInput and GroupOutput nodes it creates can be a bit unwieldy and adding a Socket to a tree creates a template rather than an actual socket (the lists displayed in Interface panel).

Rather, it's easier to create a new node group with bpy.data.node_groups.new and work with that.

import bpy

group = bpy.data.node_groups.new(type="ShaderNodeTree", name="testgroup")
group.inputs.new("NodeSocketFloat", "Input One")
group.inputs.new("NodeSocketFloat", "Input Two")
input_node = group.nodes.new("NodeGroupInput")
input_node.location = (0, 0)

group.outputs.new("NodeSocketFloat", "Out")
output_node = group.nodes.new("NodeGroupOutput")
output_node.location = (600, 0)

gtr_math_node = group.nodes.new(type='ShaderNodeMath')
gtr_math_node.operation = "GREATER_THAN"
gtr_math_node.name = "greater"
gtr_math_node.location = (200, 100)
group.links.new(input_node.outputs["Input One"], gtr_math_node.inputs[0])

lss_math_node = group.nodes.new(type='ShaderNodeMath')
lss_math_node.operation = "LESS_THAN"
lss_math_node.name = "less"
lss_math_node.location = (200,-100)
group.links.new(input_node.outputs["Input Two"], lss_math_node.inputs[1])

add_math_node = group.nodes.new(type='ShaderNodeMath')
add_math_node.operation = "ADD"
add_math_node.name = "add"
add_math_node.location = (400, 0)

group.links.new(gtr_math_node.outputs["Value"], add_math_node.inputs[0])
group.links.new(lss_math_node.outputs["Value"], add_math_node.inputs[1])

group.links.new(add_math_node.outputs["Value"], output_node.inputs["Out"])

tree = bpy.context.object.active_material.node_tree
group_node = tree.nodes.new("ShaderNodeGroup")
group_node.node_tree = group

The above gives you

enter image description here

  • 1
    $\begingroup$ Thanks NodeSocketFloat is the key that I was missing. $\endgroup$
    – sambler
    Commented Dec 11, 2013 at 10:40

I figured a way to get this to work. It still uses the override as we add the group to the material and put the group into edit mode to use the tree_socket_add operator. Ideally we should be able to do this without using operators to visually edit the group. I'm using the operator usage to separate this from your other group question. As mentioned in that question the api change in 2.67 means this won't work in blender <=2.66

It should be improved by testing that we have an active material or even an object to add a material to.

Note that tree_socket_add adds the sockets to test_group.inputs where we can name them but to make connections we need to use group_inputs.outputs

import bpy

for area in bpy.context.screen.areas:
    if area.type == "NODE_EDITOR":
        override = {'screen': bpy.context.screen, 'area': area}

# create a group
test_group = bpy.data.node_groups.new('testGroup', 'ShaderNodeTree')

# create group inputs
group_inputs = test_group.nodes.new('NodeGroupInput')
group_inputs.location = (-350,0)

# create group outputs
group_outputs = test_group.nodes.new('NodeGroupOutput')
group_outputs.location = (300,0)

# add group to active material
bpy.ops.node.add_node(override,settings=[{"name":"node_tree", "value":"bpy.data.node_groups['"+test_group.name+"']"}], type="ShaderNodeGroup")
# put group into edit mode

# create group input/output sockets
bpy.ops.node.tree_socket_add(override, in_out='IN')
test_group.inputs[0].name = 'in_to_greater'
bpy.ops.node.tree_socket_add(override, in_out='IN')
test_group.inputs[1].name = 'in_to_less'
bpy.ops.node.tree_socket_add(override, in_out='OUT')
test_group.outputs[0].name = 'out_result'

# create three math nodes in a group
node_add = test_group.nodes.new('ShaderNodeMath')
node_add.operation = 'ADD'
node_add.location = (100,0)

node_greater = test_group.nodes.new('ShaderNodeMath')
node_greater.operation = 'GREATER_THAN'
node_greater.label = 'greater'
node_greater.location = (-100,100)

node_less = test_group.nodes.new('ShaderNodeMath')
node_less.operation = 'LESS_THAN'
node_less.label = 'less'
node_less.location = (-100,-100)

# link nodes together
test_group.links.new(node_add.inputs[0], node_greater.outputs[0])
test_group.links.new(node_add.inputs[1], node_less.outputs[0])
test_group.links.new(group_inputs.outputs[0], node_greater.inputs[0])
test_group.links.new(group_inputs.outputs[1], node_less.inputs[0])
test_group.links.new(node_add.outputs[0], group_outputs.inputs[0])

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .