0
$\begingroup$

Essentially what I am trying to do is create a script that can make nodes into groups or shader node trees (unsure exactly what the difference is) based on which nodes are told to be selected at the time. Imagine someone has their current object with it's material, ideally this would take the respectable nodes needed to make that material/shader and turn it into a custom node group so that it can be called in later. Much like Ctrl-G does to the selected nodes except "bpy.ops.node.group_make()" gives me an error claiming I don't have the right context/operator poll error. Is there a more appropriate way to call operator node.group_make to assure it has the right context? I do want this to be able to happen whether or not the operations are happening in the 3D viewport or the Node editor but not limited to only if there is a node editor open.

$\endgroup$
3
  • $\begingroup$ Hello, if you are just trying to call an existing operator in code but it throws an invalid context error, you should look into "context override" blender.stackexchange.com/search?q=context+override $\endgroup$
    – Gorgious
    Commented Sep 30, 2020 at 14:23
  • $\begingroup$ I will check into this. It seems from what I've found that some operators may only be designed to work in certain windows. Maybe this will work though still. I did find that test_group = bpy.data.node_groups.new('testGroup', 'ShaderNodeTree') will create a custom node group no matter what view you're in but it doesn't create it from the selected nodes or anything just a generic group. This would work fine except I need to then append or insert the existing nodes of the active material into newly created group in order to have a group made from the active material's nodes. $\endgroup$ Commented Sep 30, 2020 at 23:42
  • $\begingroup$ If anyone knows of bpy.data.node_group commands that can append other nodes to existing node groups that might help as well. $\endgroup$ Commented Sep 30, 2020 at 23:45

1 Answer 1

2
$\begingroup$

When you run a script from the Text Editor you use its bpy.context. The Text Editor does not have a node tree related API.

To run your script in a right context you can:

  1. Pass a context to an API function as an argument.
  2. Run an operator with your script in the editor using search menu.

enter image description here

To be able to find the operator in the search menu Developer Extras should be enabled.

enter image description here

  1. Create a button in that editor to run your script.

enter image description here

Your code should be in the execute() function.

import bpy

class TEST_OT_poll():
    @classmethod
    def poll(cls, context):
        if context.space_data.type == 'NODE_EDITOR' and context.space_data.tree_type == 'ShaderNodeTree':
            return True
        else:
            return False

class TEST_OT_make_group(bpy.types.Operator, TEST_OT_poll):
    bl_idname = "node.test_make_group"
    bl_label = "Make Group"
    bl_description = ""
    bl_options = {'REGISTER', 'UNDO'}
    

    def execute(self, context):
        
        bpy.ops.node.group_make()
        bpy.ops.node.group_edit(exit=True)
        
        return {'FINISHED'}
  
    
class TEST_PT_panel(bpy.types.Panel):
    bl_idname = "TEST_PT_panel"
    bl_label = "Make group"
    bl_space_type = 'NODE_EDITOR'
    bl_region_type = "UI"
    bl_category = "Tool"

    @classmethod
    def poll(cls, context):
        if context.space_data.tree_type == 'ShaderNodeTree':
            return True
        else:
            return False

    def draw(self, context):
        
        layout = self.layout
        column = layout.column()
        column.operator("node.test_make_group", text = "Make Group")
    

classes = (
    TEST_PT_panel,
    TEST_OT_make_group,
)

def register():
    for c in classes:
        bpy.utils.register_class(c)

def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)
        
        
if __name__ == "__main__":
    register()
  1. Change the editor in the script with changing it back at the end.

But in this case, it may not update the UI correctly, and you have to use an unrecommended force update.

import bpy

try:
    initial_area_type = bpy.context.area.type
    bpy.context.area.type = 'NODE_EDITOR'
    bpy.context.area.ui_type = 'ShaderNodeTree'
    bpy.ops.wm.redraw_timer(type='DRAW_WIN', iterations=1)
    
    bpy.ops.node.group_make()
    bpy.ops.node.group_edit(exit=True)
    
except Exception as e:
    print(e)
finally:
    bpy.context.area.type = initial_area_type
$\endgroup$

You must log in to answer this question.

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