text:
Can anyone Fix this Little Error in My Script
I Just Have a Test Script Which Has Some Errors, As I Am Noob To Scripting I don’t Know How to Fix these errors
This script creates a Test Material and a Panel in Physics Panel and a Button is Created according to me when this Button is Pressed a Material Should be created but this is created when script is run I don’t wan’t that.
This Script Creates a Node Group but I am Unable to Connect that Node -group to Material Output Node.
My script is -
import bpy

#Context for Test Material
def T_M(context):
    bpy.context.scene.use_nodes = True
    tree = bpy.context.scene.node_tree

    #removes unwanted nodes
    for node in tree.nodes:
        tree.nodes.remove(node)

Testshader_mat = bpy.data.materials.new("TestMat")
mesh = bpy.context.object.data
mesh.materials.clear()
mesh.materials.append(Testshader_mat)
bpy.context.object.active_material.use_nodes = True
mat_name = "TestMat"
for mat in bpy.data.materials:
    if "TestMat" in mat.name:
        nodes = mat.node_tree.nodes
        for node in nodes:
            if node.type != 'OUTPUT_MATERIAL': # skip the material output node as we'll need it later
                nodes.remove(node)

#Creating Node Group Test_Material

group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")

#Creating Group Input
group.inputs.new("NodeSocketColor", "Diffuse Color")
group.inputs.new("NodeSocketColor", "Glossy Color")
group.inputs.new("NodeSocketFloat", "Mix Factor")
group.inputs.new("NodeSocketFloat", "Glossyness")
input_node = group.nodes.new("NodeGroupInput")
input_node.location = (-800, 0)

# Creating Group Output Node
group.outputs.new("NodeSocketShader", "Diffuse Color")
group.outputs.new("NodeSocketShader", "Glossy Color")
group.outputs.new("NodeSocketShader", "Mix Output")

output_node = group.nodes.new("NodeGroupOutput")
output_node.location = (1500, 0)

#Creating Diffuse Node
Diffuse_node = group.nodes.new(type = 'ShaderNodeBsdfDiffuse')
Diffuse_node.location = (150, 100)

#Creating Glossy Node
Glossy_node = group.nodes.new(type = 'ShaderNodeBsdfGlossy')
Glossy_node.location = (300, 250)

#Creating Mix Shader Node
Mix_Shader_node = group.nodes.new(type = 'ShaderNodeMixShader')
Mix_Shader_node.location = (450,100)

# Creating Links Between Nodes
group.links.new(Diffuse_node.outputs["BSDF"], Mix_Shader_node.inputs[1])
group.links.new(Glossy_node.outputs["BSDF"], Mix_Shader_node.inputs[2])
group.links.new(input_node.outputs["Diffuse Color"], Diffuse_node.inputs[0])
group.links.new(input_node.outputs["Glossy Color"], Glossy_node.inputs[0])
group.links.new(input_node.outputs["Mix Factor"], Mix_Shader_node.inputs[0])
group.links.new(input_node.outputs["Glossyness"], Glossy_node.inputs[1])
group.links.new(output_node.inputs["Diffuse Color"],
Diffuse_node.outputs[0])
group.links.new(output_node.inputs["Glossy Color"], Glossy_node.outputs[0])
group.links.new(output_node.inputs["Mix Output"], Mix_Shader_node.outputs[0])

# Putting Node Group to the node editor
tree = bpy.context.object.active_material.node_tree
group_node = tree.nodes.new("ShaderNodeGroup")
group_node.node_tree = group
group_node.location = (-40,300)
group_node.use_custom_color = True
group_node.color = (1,0.341,0.034)
group_node.width = (250)

ShaderNodeOutputMaterial_node = tree.nodes["Material Output"]
links = tree.links
link = links.new(group_node.outputs[0], ShaderNodeOutputMaterial_node.inputs[1])

#operation to add Test Material Node
class T_M(bpy.types.Operator):
    """Click this Button to Add Test Material."""
    bl_idname = "t_m.addnodes"
    bl_label = " Test Material"

    def execute(self, context):
        T_M(context)
        return {'FINISHED'}

    #operation for Panel
class LayoutPanel(bpy.types.Panel):
    bl_label = "Test Material Node"
    bl_idname = "SCENE_PT_layout"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "physics"

    def draw(self, context):
        layout = self.layout

        scene = context.scene

        layout.label(text="_______________________________________________")

        #Welcome text

        row = layout.row()
        layout.label(text=" Click on Test Material Button,")
        layout.label(text=" and the required nodes will be added to the")
        layout.label(text=" Node Editor in the form of Test Material")
        layout.label(text=" Node Group.")
        row = layout.row()
        row = layout.row()
        layout.label(text="_____________________________________________")

        #Test Material Add UI

        row = layout.row()
        row = layout.row()
        row = layout.row()

        layout.label(text=" Test Material", icon= 'MATERIAL_DATA')
        row = layout.row()
        row = layout.row()
        row = layout.row()
        layout.label(text=" This Button will Add a Material")
        layout.label(text=" For Your Object.")
        row = layout.row()
        row = layout.row()
        row = layout.row()
        row.operator("t_m.addnodes", icon= 'IMPORT')
        row = layout.row()
        layout.label(text="_______________________________________________")

    #register and unregister
def register():
    bpy.utils.register_class(T_M)
    bpy.utils.register_class(LayoutPanel)

def unregister():

    bpy.utils.unregister_class(T_M)
    bpy.utils.unregister_class(LayoutPanel)

if __name__ == "__main__":
    register()

I want that this Test_MaterialOP should Add this Material which is written above to the node editor using this -

    row = layout.row()
    row = layout.row()
    row.operator("t_m.addnodes", icon= 'IMPORT')
    row = layout.row()
And I got This
But when I click Test Material Button In Layout Panel A New Material Should Be Created with this But It is Not Happening It is Only Added When Script is Run,and not on clicking button

Hello. This is more of a learning site than a "fix-it-forme" style personal help desk. Could you rephrase your question so that it shows what the script looks like and what specific errors it throws, rather than requiring users to download and run it themselves?

That's a complicated script for a 'noob' - presumably it was pieced together from something else or provided as-is and not working...? It would be useful to have some history of where this has come from. An initial thought is that Python is very dependent of indentations (how much space there is to the left of lines of text). The first 'def T_M(context):' is at the same indent level as the following lines - indicating that the indentation is wrong and this would likely fail at that point, regardless of the rest. Please check the indentation with what you presumably have running.

In this script I am having error in   these lines as i am not able to all the process above(creation of material etc.) -     "  #operation to add Test Material Node
class Test_MaterialOP(bpy.types.Operator):
"""Click this Button to Add Test Material."""
bl_idname = "t_m.addnodes"
bl_label = " Test Material"
def execute(self, context):
Test_MaterialOP(context)
return {'FINISHED'}     "   **I have fixed Indentation errors

Please keep comments short or invite to chatroom.  @Rakeshchoudhary please edit your question rather than adding code in comments.  There are formatting buttons for code.

There are multiple issues with your script:

The indentation is incorrect. Code that belongs into your T_M function isn't indented by four spaces, which results in the code being executed even though the functions wasn't called. Similarly the functions that should be part of the class aren't indented, e.g. the execute function for Test_MaterialOP.
The Test_MaterialOP calls Test_MaterialOP(context) in execute. I believe you intend to call T_M here. Creating another operator object is certainly not what you want.
The Material creation in T_M is incomplete, the code wouldn't create a connection to the Material Output node.
The layout code could be improved. Use layout.separator() to draw horizontal lines. Don't create empty rows that you aren't using.

These are the most obvious errors that I could spot.

The updated script still has issues. I've fixed the following problems in the script below:

The entire function body has to be indented by at least four spaces (more for loops and conditionals)
The operator name and the function to add the material should have different names. The operator is your button and the execute function what happens when the button is pressed. Therefore you need to call the function that creates the material in the execute function. The operator needs to be registered.
The node group was connected to the volume socket for the material output. It's now connected to the shader output.
Fixed for compliance with Blender's naming convention
Moved the panel to the 3D View sidebar in the "Test Material" tab (open with N)
Added bl_info so you can install as add-on.
Moved explanatory text to the add-on's description and the operator's description. The latter will appear when you hover over the button.

bl_info = {
    "name": "Add Test Material",
    "author": "Rakesh Choudhary",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D > Sidebar > Test Material Node",
    "description": "Click on the 'Test Material' button to add a material to your object.",
    "warning": "",
    "wiki_url": "",
    "category": "3D View"
}

import bpy

class TEST_MATERIAL_OT_add_material(bpy.types.Operator):
    bl_idname = "test_material.add_material"
    bl_label = "Add Test Material"
    bl_description = "This button will add a material to your object"

    def execute(self, context):
        self.create_material()
        return {'FINISHED'}

    def create_material(self):
        bpy.context.scene.use_nodes = True
        tree = bpy.context.scene.node_tree

        # removes unwanted nodes
        for node in tree.nodes:
            tree.nodes.remove(node)

        test_shader_mat = bpy.data.materials.new("TestMat")
        mesh = bpy.context.object.data
        mesh.materials.clear()
        mesh.materials.append(test_shader_mat)
        bpy.context.object.active_material.use_nodes = True

        for mat in bpy.data.materials:
            if "TestMat" in mat.name:
                nodes = mat.node_tree.nodes
                for node in nodes:
                    if node.type != 'OUTPUT_MATERIAL':  # skip the material output node as we'll need it later
                        nodes.remove(node)

        # Creating Node Group Test_Material
        group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")

        # Creating Group Input
        group.inputs.new("NodeSocketColor", "Diffuse Color")
        group.inputs.new("NodeSocketColor", "Glossy Color")
        group.inputs.new("NodeSocketFloat", "Mix Factor")
        group.inputs.new("NodeSocketFloat", "Glossyness")
        input_node = group.nodes.new("NodeGroupInput")
        input_node.location = (-800, 0)

        # Creating Group Output Node
        group.outputs.new("NodeSocketShader", "Diffuse Color")
        group.outputs.new("NodeSocketShader", "Glossy Color")
        group.outputs.new("NodeSocketShader", "Mix Output")

        output_node = group.nodes.new("NodeGroupOutput")
        output_node.location = (1500, 0)

        # Creating Diffuse Node
        diffuse_node = group.nodes.new(type='ShaderNodeBsdfDiffuse')
        diffuse_node.location = (150, 100)

        # Creating Glossy Node
        glossy_node = group.nodes.new(type='ShaderNodeBsdfGlossy')
        glossy_node.location = (300, 250)

        # Creating Mix Shader Node
        mix_shader_node = group.nodes.new(type='ShaderNodeMixShader')
        mix_shader_node.location = (450, 100)

        # Creating Links Between Nodes
        group.links.new(diffuse_node.outputs["BSDF"], mix_shader_node.inputs[1])
        group.links.new(glossy_node.outputs["BSDF"], mix_shader_node.inputs[2])
        group.links.new(input_node.outputs["Diffuse Color"], diffuse_node.inputs[0])
        group.links.new(input_node.outputs["Glossy Color"], glossy_node.inputs[0])
        group.links.new(input_node.outputs["Mix Factor"], mix_shader_node.inputs[0])
        group.links.new(input_node.outputs["Glossyness"], glossy_node.inputs[1])
        group.links.new(output_node.inputs["Diffuse Color"], diffuse_node.outputs[0])
        group.links.new(output_node.inputs["Glossy Color"], glossy_node.outputs[0])
        group.links.new(output_node.inputs["Mix Output"], mix_shader_node.outputs[0])

        # Putting Node Group to the node editor
        tree = bpy.context.object.active_material.node_tree
        group_node = tree.nodes.new("ShaderNodeGroup")
        group_node.node_tree = group
        group_node.location = (-40, 300)
        group_node.use_custom_color = True
        group_node.color = (1, 0.341, 0.034)
        group_node.width = 250

        shader_node_output_material_node = tree.nodes["Material Output"]
        links = tree.links
        links.new(group_node.outputs[0], shader_node_output_material_node.inputs[0])

class TEST_MATERIAL_PT_layout_panel(bpy.types.Panel):
    bl_label = "Test Material Node"
    bl_category = "Test Material"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout
        layout.operator("test_material.add_material", icon='IMPORT')

classes = (TEST_MATERIAL_OT_add_material, TEST_MATERIAL_PT_layout_panel)

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

def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)

if __name__ == "__main__":
    register()

I have Fixed All The Indentation Errors and also now material creation is complete it is connected to Material output node. as in your answer i have completed point no - 1, 3, 4(Leave layout.separator for now because it is not creating any kind of error and i will improve it further) I think my problem is at point no 2 of your answer Please Explain it to me.

@Rakeshchoudhary If you want to call the T_M function you need to write T_M(context) instead of Test_MaterialOP(context).

I have done as You Said You can see I have edited the question + also added screenshot I got this Material in Node editor when this script is run, I wan't that the Button "Test Material" Should be Useful and this Material should be created as Many times as I press this Button

@Rakeshchoudhary you shouldn't change the name of the operator, just add the function call. I've updated my answer.


text:
How to append a Geometry nodes node group using Python
I wanted to append a Geometry nodes node group from a blend file named "test", and the node group name is also 'test' and I used the following code, but I am getting an error of the wrong path("test does not exist").
I am trying to install it as an addon, and a blend file with the same name and node group with the same name is present in the same folder where the __init__.py is
What am I doing wrong?
import os
import bpy

from bpy.types import (
    Operator,
    Panel
)
from bpy.props import (
    StringProperty
)

bl_info = {
    "name": "Geonode tree",
    "description": "Imports Geometry Node tree",
    "author": "Rakesh",
    "version": (1, 0),
    "blender": (3, 0, 0),
    "location": "Node Editor > Properties Panel",
    "warning": "",  # used for warning icon and text in addons panel
    "tracker_url": "",
    "category": "Node"
}

# ------------------------------------------------------------------------
#    Append Operator
# ------------------------------------------------------------------------

class NG_OT_Append(Operator):
    bl_idname = "ng.append_node_tree"
    bl_label = "Append NG"
    bl_options = {'REGISTER'}

    blend : StringProperty(name="Library Blend File")
    ng_name : StringProperty(name="Node group Name")

    @classmethod
    def poll(cls, context):
        ob = context.active_object

        return ob is not None and ob.type == 'MESH'

    def execute(self, context):

        ob = context.active_object

        if ob is None:
            self.report({'ERROR'}, "No active object")
            return{"CANCELLED"}

        if ob.type != 'MESH':
            self.report({'ERROR'}, "Active object is not a mesh")
            return {"CANCELLED"}

        # os.path.abspath(__file__) returns path to the addon
        filepath = os.path.join(os.path.dirname(
            os.path.abspath(__file__)), self.blend)

        # -> Test whether the file exist
        if not os.path.isfile(filepath):
            self.report({'WARNING'}, "{} does not exist".format(self.blend))
            return {'CANCELLED'}

        with bpy.data.libraries.load(filepath, link=False) as (data_from, data_to):
            data_to.node_groups = [
                name for name in data_from.node_groups if name.startswith("test")]

        # -> Test whether the object exist
        if not data_to.node_groups:
            self.report({'WARNING'}, "{} not found in {}".format(
                self.ng_name, self.blend))
            return {'CANCELLED'}

        self.report({'INFO'}, "Test Node tree added")
        return {'FINISHED'}

# ------------------------------------------------------------------------
#    Panel in Object Mode
# ------------------------------------------------------------------------

class NG_PT_mainPanel(Panel):
    '''Adds nodetree to active object'''
    bl_label = "NG"
    bl_idname = "NG_PT_mainPanel"
    bl_space_type = 'NODE_EDITOR'
    bl_region_type = "UI"
    bl_category = "NG"

    def draw(self, context):
        layout = self.layout

        file_name = "test"
        ng_name = "test"

        row = layout.row()
        row = layout.row()
        row.scale_y = 1.5
        props = row.operator(NG_OT_Append.bl_idname,
                             text="Add Node tree", icon='IMPORT')
        props.blend = file_name
        props.ng_name = ng_name

        layout.separator()

# ------------------------------------------------------------------------
#    Registration
# ------------------------------------------------------------------------

classes = (
    NG_OT_Append,
    NG_PT_mainPanel,
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)

if __name__ == "__main__":
    register()

If I understand well the context you're describing,
you just need to replace:
filepath = os.path.join(os.path.dirname(
    os.path.abspath(__file__)), self.blend)

by:
filepath = os.path.join(os.path.dirname(
    os.path.abspath(__file__)), self.blend + ".blend")

The reason is the os.path.isfile won't recognize a file path if it does not includes the file extension.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
How to Update NodeSocketString Value inside a node group in a attribute node using python
I have an Attribute node inside a node group, and for the node group inputs, I have created a NodeSocketString, Using group.inputs.new("NodeSocketString", "Factor") and I want that whenever I enter any String value in that NodeSocket, it should also be updated in the attribute node immediately
I tried attribute_node.attribute_name = group.inputs[3].default_value
but it is not working as expected this gives the default value set for node socket in the attribute node but what is want is that this should change whenever I change the value there so I also tried to do this using a for loop -
for default_value in group.inputs["Factor"]:
    attribute_node.attribute_name = group.inputs[3].default_value

but this is also not working, this produces an error - TypeError: 'NodeSocketInterfaceString' object is not iterable
I want that if I insert any string value in the Factor input shown in screenshot 1 that value should also be updated in the attribute node (that is present inside this node group) shown in the screenshot 2
Screenshot 1 -

I want this value(in the attribute node) to be updated every time when any value is inserted in the group node shown in screenshot-1
Screenshot 2 -

So is this Possible? and do I have to declare separately a string variable?
Can anyone help me with this problem?
This is the Updated Script -
bl_info = {
"name": "Add Test Material",
"author": "Rakesh Choudhary",
"version": (1, 0),
"blender": (2, 83, 0),
"location": "View3D > Sidebar > Test Material Node",
"description": "Click on the 'Test Material' button to add a material to your object.",
"warning": "",
"wiki_url": "",
"category": "3D View"
}

import bpy
from bpy.types import (
    Operator,
    Panel,
)

class TEST_MATERIAL_OT_add_material(Operator):
    bl_idname = "test_material.add_material"
    bl_label = "Add Test Material"
    bl_description = "This button will add a material to your object"

    def execute(self, context):
        self.create_material(context)
        return {'FINISHED'}

    def create_material(self, context):
        test_shader_mat = bpy.data.materials.new("TestMat")
        mesh = context.object.data
        mesh.materials.clear()
        mesh.materials.append(test_shader_mat)
        context.object.active_material.use_nodes = True

        for mat in bpy.data.materials:
            if "TestMat" in mat.name:
                nodes = mat.node_tree.nodes
                for node in nodes:
                    if node.type != 'OUTPUT_MATERIAL':  # skip the material output node as we'll need it later
                        nodes.remove(node)

        # Creating Node Group Test_Material
        group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")

        # Creating Group Input
        group.inputs.new("NodeSocketColor", "Diffuse Color")
        group.inputs.new("NodeSocketColor", "Glossy Color")
        group.inputs.new("NodeSocketFloat", "Glossyness")
        group.inputs.new("NodeSocketString", "Factor")
        input_node = group.nodes.new("NodeGroupInput")
        input_node.location = (-800, 0)

        group.inputs[0].default_value = (1, 1, 1, 1)
        group.inputs[1].default_value = (1, 1, 1, 1)
        group.inputs[2].default_value = (0.500)
        group.inputs[3].default_value = "foam"

        # Creating Group Output Node
        group.outputs.new("NodeSocketShader", "Diffuse Color")
        group.outputs.new("NodeSocketShader", "Glossy Color")
        group.outputs.new("NodeSocketShader", "Mix Output")

        output_node = group.nodes.new("NodeGroupOutput")
        output_node.location = (1500, 0)

        # Creating Diffuse Node
        diffuse_node = group.nodes.new(type='ShaderNodeBsdfDiffuse')
        diffuse_node.location = (150, 100)

        # Creating Glossy Node
        glossy_node = group.nodes.new(type='ShaderNodeBsdfGlossy')
        glossy_node.location = (300, 250)

        # Creating Mix Shader Node
        mix_shader_node = group.nodes.new(type='ShaderNodeMixShader')
        mix_shader_node.location = (450, 100)

        #Attribute Node
        attribute_node = group.nodes.new(type='ShaderNodeAttribute')
        attribute_node.location  = (100, 400)
        attribute_node.attribute_name = group.inputs[3].default_value

        # Creating Links Between Nodes----------------------------------------------
        group.links.new(diffuse_node.outputs["BSDF"], mix_shader_node.inputs[1])
        group.links.new(glossy_node.outputs["BSDF"], mix_shader_node.inputs[2])
        group.links.new(input_node.outputs["Diffuse Color"], diffuse_node.inputs[0])
        group.links.new(input_node.outputs["Glossy Color"], glossy_node.inputs[0])
        group.links.new(input_node.outputs["Glossyness"], glossy_node.inputs[1])
        group.links.new(output_node.inputs["Diffuse Color"], diffuse_node.outputs[0])
        group.links.new(output_node.inputs["Glossy Color"], glossy_node.outputs[0])
        group.links.new(output_node.inputs["Mix Output"], mix_shader_node.outputs[0])
        group.links.new(attribute_node.outputs["Fac"], mix_shader_node.inputs[0])

        # Putting Node Group to the node editor
        tree = bpy.context.object.active_material.node_tree
        group_node = tree.nodes.new("ShaderNodeGroup")
        group_node.node_tree = group
        group_node.location = (-40, 300)
        group_node.use_custom_color = True
        group_node.color = (1, 0.341, 0.034)
        group_node.width = 250

        shader_node_output_material_node = tree.nodes["Material Output"]
        links = tree.links
        links.new(group_node.outputs[0], shader_node_output_material_node.inputs[0])

        #Material ends here------------------------------

class TEST_MATERIAL_PT_layout_panel(Panel):
    bl_label = "Test Material Node"
    bl_category = "Test Material"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout
        layout.operator("test_material.add_material", icon='IMPORT')

    def get_group_nodes(material):
            if material.use_nodes:
                return [n for n in material.node_tree.nodes if isinstance(n, bpy.types.ShaderNodeGroup)]
            return []

    def set_value(self, value):
        print(self, self.id_data, value)
        if not 'Factor' in self.inputs.keys():
           return None
           self.inputs['Factor'].default_value = value
        name = self.node_tree.name
        bpy.data.node_groups[name].nodes['Attribute'].attribute_name = value

    def get_value(self):
        if not 'Factor' in self.inputs.keys():
            return ""
        return self.inputs["Factor"].default_value

    bpy.types.ShaderNodeGroup.factor = bpy.props.StringProperty(
             get=get_value,
             set=set_value)

    def draw_prop(self, context):
        mat = context.material
        nodes = get_group_nodes(mat)
        for n in nodes:
            self.layout.prop(n, "factor")

    bpy.types.NODE_HT_header.prepend(draw_prop)

classes = (TEST_MATERIAL_OT_add_material, TEST_MATERIAL_PT_layout_panel)

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

def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)

if __name__ == "__main__":
    register()

Follow up -
I tried from the answer I just put that code into the panel class, but that is not working and the error I am getting is -
NameError: name 'get_group_nodes' is not defined

what I did wrong?
Follow up -
If I split the script and use init.py to import file,  this method does not work I get this error -

Traceback (most recent call last):
File "C:\Users\ADMIN\AppData\Roaming\Blender Foundation\Blender\2.83\scripts\addons\Test for init\panel.py", line 19, in draw
for n in get_group_nodes(mat):
NameError: name 'get_group_nodes' is not defined
location: :-1
location: :-1 Traceback (most recent call last):
File "C:\Users\ADMIN\AppData\Roaming\Blender
Foundation\Blender\2.83\scripts\addons\Test for init\panel.py", line
19, in draw
for n in get_group_nodes(mat): NameError: name 'get_group_nodes' is not defined
location: :-1

I split this script into 3 files first is init.py, second is material_operator.py and third is panel.py
_ init _.py
bl_info = {
"name": "Add Test Material",
"author": "Rakesh Choudhary",
"version": (1, 0),
"blender": (2, 83, 0),
"location": "View3D > Sidebar > Test Material Node",
"description": "Click on the 'Test Material' button to add a material to your object.",
"warning": "",
"wiki_url": "",
"category": "3D View"
}

import bpy
from bpy.types import (
    Operator,
    Panel,
)
from . import material_operator
from . import panel

def register():
    material_operator.register()
    panel.register()

def unregister():
    material_operator.unregister()
    panel.unregister()

if __name__ == "__main__":
    register()

material operator.py -
import bpy
from bpy.types import (
    Operator,
    Panel,
)
def get_group_nodes(material):
    if material.use_nodes:
        return [n for n in material.node_tree.nodes if isinstance(n, bpy.types.ShaderNodeGroup)]
    return []

def set_value(self, value):
    print(self, self.id_data, value)
    if not 'Factor' in self.inputs.keys():
        return None
    self.inputs['Factor'].default_value = value
    name = self.node_tree.name
    bpy.data.node_groups[name].nodes['Attribute'].attribute_name = value

def get_value(self):
    if not 'Factor' in self.inputs.keys():
        return ""
    return self.inputs["Factor"].default_value

class TEST_MATERIAL_OT_add_material(Operator):
    bl_idname = "test_material.add_material"
    bl_label = "Add Test Material"
    bl_description = "This button will add a material to your object"

    def execute(self, context):
        self.create_material()
        return {'FINISHED'}

    def create_material(self):
        test_shader_mat = bpy.data.materials.new("TestMat")
        mesh = bpy.context.object.data
        mesh.materials.clear()
        mesh.materials.append(test_shader_mat)
        bpy.context.object.active_material.use_nodes = True

        for mat in bpy.data.materials:
            if "TestMat" in mat.name:
                nodes = mat.node_tree.nodes
                for node in nodes:
                    if node.type != 'OUTPUT_MATERIAL':  # skip the material output node as we'll need it later
                        nodes.remove(node)

        # Creating Node Group Test_Material
        group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")

        # Creating Group Input
        group.inputs.new("NodeSocketColor", "Diffuse Color")
        group.inputs.new("NodeSocketColor", "Glossy Color")
        group.inputs.new("NodeSocketFloat", "Glossyness")
        group.inputs.new("NodeSocketString", "Factor")
        input_node = group.nodes.new("NodeGroupInput")
        input_node.location = (-800, 0)

        # Creating Group Output Node
        group.outputs.new("NodeSocketShader", "Diffuse Color")
        group.outputs.new("NodeSocketShader", "Glossy Color")
        group.outputs.new("NodeSocketShader", "Mix Output")

        output_node = group.nodes.new("NodeGroupOutput")
        output_node.location = (1500, 0)

        # Creating Diffuse Node
        diffuse_node = group.nodes.new(type='ShaderNodeBsdfDiffuse')
        diffuse_node.location = (150, 100)

        # Creating Glossy Node
        glossy_node = group.nodes.new(type='ShaderNodeBsdfGlossy')
        glossy_node.location = (300, 250)

        # Creating Mix Shader Node
        mix_shader_node = group.nodes.new(type='ShaderNodeMixShader')
        mix_shader_node.location = (450, 100)

        # Creating Attribute Node
        attribute_node = group.nodes.new(type="ShaderNodeAttribute")
        attribute_node.location = (400, -300)
        attribute_node.attribute_name = group.inputs[3].default_value

        # Creating Links Between Nodes----------------------------------------------
        group.links.new(diffuse_node.outputs["BSDF"], mix_shader_node.inputs[1])
        group.links.new(glossy_node.outputs["BSDF"], mix_shader_node.inputs[2])
        group.links.new(input_node.outputs["Diffuse Color"], diffuse_node.inputs[0])
        group.links.new(input_node.outputs["Glossy Color"], glossy_node.inputs[0])
        group.links.new(input_node.outputs["Glossyness"], glossy_node.inputs[1])
        group.links.new(output_node.inputs["Diffuse Color"], diffuse_node.outputs[0])
        group.links.new(output_node.inputs["Glossy Color"], glossy_node.outputs[0])
        group.links.new(output_node.inputs["Mix Output"], mix_shader_node.outputs[0])

        # Putting Node Group to the node editor
        tree = bpy.context.object.active_material.node_tree
        group_node = tree.nodes.new("ShaderNodeGroup")
        group_node.node_tree = group
        group_node.location = (-40, 300)
        group_node.use_custom_color = True
        group_node.color = (1, 0.341, 0.034)
        group_node.width = 250

        shader_node_output_material_node = tree.nodes["Material Output"]
        links = tree.links
        links.new(group_node.outputs[0], shader_node_output_material_node.inputs[0])

        #Material ends here------------------------------

def register():
    bpy.utils.register_class(TEST_MATERIAL_OT_add_material)

def unregister():
    bpy.utils.unregister_class(TEST_MATERIAL_OT_add_material)

if __name__ == "__main__":
    register()

panel.py -
import bpy
from bpy.types import (
    Operator,
    Panel,
)

from material_operator import get_group_nodes

class TEST_MATERIAL_PT_layout_panel(Panel):
    bl_label = "Test Material Node"
    bl_category = "Test Material"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout
        layout.operator("test_material.add_material", icon='IMPORT')
        mat = context.object.active_material
        if mat:
            for n in get_group_nodes(mat):
                layout.prop(n, "factor")

def register():
    bpy.utils.register_class(TEST_MATERIAL_PT_layout_panel)
    bpy.types.ShaderNodeGroup.factor = bpy.props.StringProperty(
         get=get_value,
         set=set_value)

def unregister():
    bpy.utils.unregister_class(TEST_MATERIAL_PT_layout_panel)

if __name__ == "__main__":
    register()

Can you show me where I am doing wrong?

I'd suggest you upload a minimal working example of your addon. The creation of all those nodes does not seem relevant to your problem.

Agree with Leander. Also, can't see any StringProperty declared... Where and how the user can enter a new string?

@brockmann I updated my question so that it is easy to understand, I want that whatever string value I feed in the Factor Socket in the group node that value should automatically be updated inside the attribute node present inside the node group. Is it possible?

AFAIK there is no way to call a function for NodeGroupInputs on update: https://docs.blender.org/api/current/bpy.types.NodeInputs.html#bpy.types.NodeInputs Not entirely sure though... Too bad that the attribute node doesn't provide any input string socket by default, might be a nice feature request IMHO. You can try msgbus per node: https://blender.stackexchange.com/questions/150809/how-to-get-an-event-when-an-object-is-selected/150881#150881 or just add a button to force an update.

@brockmann thanks for the update, as you said I can add a button to force an Update can you show me how to do that.

Re edit re answer see https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules  The error suggests that wherever you've put the code it does not see the method get_group_nodes

Updating a user defined property

Similarly to Get all materials inside an object for controlling mapping nodes with single var
In the proof of concept (ie needs checks and balances to test for particular group nodes) code below:

Defines  a custom property on a shader node group.  As with all properties defined this way, all shadernode groups will have this value.

When the custom property is updated it sets the group node input and attribute nodes attribute name to value.

Have instead of an update method on the property used a getter and setter by way of example.. An update, as demonstrated in linked, could be used instead.

Use an enum property to only be able to choose from a particular set.  Gif above uses "froth" by way of example, with no idea if it is a viable option.

Example uses shader editor header where context.material is defined.  To put the property in panel in 3D view UI would require getting material from, for example context objects active material

Test code:
import bpy

def get_group_nodes(material):
    if material.use_nodes:
        return [n for n in material.node_tree.nodes if isinstance(n, bpy.types.ShaderNodeGroup)]
    return []

def set_value(self, value):
    print(self, self.id_data, value)
    if not 'Factor' in self.inputs.keys():
        return None
    self.inputs['Factor'].default_value = value
    name = self.node_tree.name
    bpy.data.node_groups[name].nodes['Attribute'].attribute_name = value

def get_value(self):
    if not 'Factor' in self.inputs.keys():
        return ""
    return self.inputs["Factor"].default_value

bpy.types.ShaderNodeGroup.factor = bpy.props.StringProperty(
         get=get_value,
         set=set_value)

def draw_prop(self, context):
    mat = context.material
    nodes = get_group_nodes(mat)
    for n in nodes:
        self.layout.prop(n, "factor")

bpy.types.NODE_HT_header.prepend(draw_prop)

Re edit, quicker to do than explain, here is question code with above added.  Recommend you read https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules re the scope of variables / methods in python.
bl_info = {
"name": "Add Test Material",
"author": "Rakesh Choudhary",
"version": (1, 0),
"blender": (2, 83, 0),
"location": "View3D > Sidebar > Test Material Node",
"description": "Click on the 'Test Material' button to add a material to your object.",
"warning": "",
"wiki_url": "",
"category": "3D View"
}

import bpy
from bpy.types import (
    Operator,
    Panel,
)

def get_group_nodes(material):
    if material.use_nodes:
        return [n for n in material.node_tree.nodes if isinstance(n, bpy.types.ShaderNodeGroup)]
    return []

def set_value(self, value):
    print(self, self.id_data, value)
    if not 'Factor' in self.inputs.keys():
        return None
    self.inputs['Factor'].default_value = value
    name = self.node_tree.name
    bpy.data.node_groups[name].nodes['Attribute'].attribute_name = value

def get_value(self):
    if not 'Factor' in self.inputs.keys():
        return ""
    return self.inputs["Factor"].default_value

class TEST_MATERIAL_OT_add_material(Operator):
    bl_idname = "test_material.add_material"
    bl_label = "Add Test Material"
    bl_description = "This button will add a material to your object"

    def execute(self, context):
        self.create_material(context)
        return {'FINISHED'}

    def create_material(self, context):
        test_shader_mat = bpy.data.materials.new("TestMat")
        mesh = context.object.data
        mesh.materials.clear()
        mesh.materials.append(test_shader_mat)
        context.object.active_material.use_nodes = True

        for mat in bpy.data.materials:
            if "TestMat" in mat.name:
                nodes = mat.node_tree.nodes
                for node in nodes:
                    if node.type != 'OUTPUT_MATERIAL':  # skip the material output node as we'll need it later
                        nodes.remove(node)

        # Creating Node Group Test_Material
        group = bpy.data.node_groups.new(type="ShaderNodeTree", name="Test_Material")

        # Creating Group Input
        group.inputs.new("NodeSocketColor", "Diffuse Color")
        group.inputs.new("NodeSocketColor", "Glossy Color")
        group.inputs.new("NodeSocketFloat", "Glossyness")
        group.inputs.new("NodeSocketString", "Factor")
        input_node = group.nodes.new("NodeGroupInput")
        input_node.location = (-800, 0)

        group.inputs[0].default_value = (1, 1, 1, 1)
        group.inputs[1].default_value = (1, 1, 1, 1)
        group.inputs[2].default_value = (0.500)
        group.inputs[3].default_value = "foam"

        # Creating Group Output Node
        group.outputs.new("NodeSocketShader", "Diffuse Color")
        group.outputs.new("NodeSocketShader", "Glossy Color")
        group.outputs.new("NodeSocketShader", "Mix Output")

        output_node = group.nodes.new("NodeGroupOutput")
        output_node.location = (1500, 0)

        # Creating Diffuse Node
        diffuse_node = group.nodes.new(type='ShaderNodeBsdfDiffuse')
        diffuse_node.location = (150, 100)

        # Creating Glossy Node
        glossy_node = group.nodes.new(type='ShaderNodeBsdfGlossy')
        glossy_node.location = (300, 250)

        # Creating Mix Shader Node
        mix_shader_node = group.nodes.new(type='ShaderNodeMixShader')
        mix_shader_node.location = (450, 100)

        #Attribute Node
        attribute_node = group.nodes.new(type='ShaderNodeAttribute')
        attribute_node.location  = (100, 400)
        attribute_node.attribute_name = group.inputs[3].default_value

        # Creating Links Between Nodes----------------------------------------------
        group.links.new(diffuse_node.outputs["BSDF"], mix_shader_node.inputs[1])
        group.links.new(glossy_node.outputs["BSDF"], mix_shader_node.inputs[2])
        group.links.new(input_node.outputs["Diffuse Color"], diffuse_node.inputs[0])
        group.links.new(input_node.outputs["Glossy Color"], glossy_node.inputs[0])
        group.links.new(input_node.outputs["Glossyness"], glossy_node.inputs[1])
        group.links.new(output_node.inputs["Diffuse Color"], diffuse_node.outputs[0])
        group.links.new(output_node.inputs["Glossy Color"], glossy_node.outputs[0])
        group.links.new(output_node.inputs["Mix Output"], mix_shader_node.outputs[0])
        group.links.new(attribute_node.outputs["Fac"], mix_shader_node.inputs[0])

        # Putting Node Group to the node editor
        tree = bpy.context.object.active_material.node_tree
        group_node = tree.nodes.new("ShaderNodeGroup")
        group_node.node_tree = group
        group_node.location = (-40, 300)
        group_node.use_custom_color = True
        group_node.color = (1, 0.341, 0.034)
        group_node.width = 250

        shader_node_output_material_node = tree.nodes["Material Output"]
        links = tree.links
        links.new(group_node.outputs[0], shader_node_output_material_node.inputs[0])

        #Material ends here------------------------------

class TEST_MATERIAL_PT_layout_panel(Panel):
    bl_label = "Test Material Node"
    bl_category = "Test Material"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout
        layout.operator("test_material.add_material", icon='IMPORT')
        mat = context.object.active_material
        if mat:
            for n in get_group_nodes(mat):
                layout.prop(n, "factor")

classes = (TEST_MATERIAL_OT_add_material, TEST_MATERIAL_PT_layout_panel)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.ShaderNodeGroup.factor = bpy.props.StringProperty(
         get=get_value,
         set=set_value)

def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)

if __name__ == "__main__":
    register()

thanks for answering but still I have one problem, maybe I made some mistake in the code because it is not working for me I updated in the question whatever I did after your answer

Ok! I understood now, Thank you very much for the help

NP.  note made a small change making material in panel draw  objects active material.

if I split the script into material_operator.py and panel.py and init.py and after splitting this stopped working and I am getting error - get_group_nodes is not defined I have updated in my question.  can you please show me what I am doing wrong

If its elsewhere import it eg  from test_addon.operators import get_nodes

Re multi file I would ask myself whats the logical way to split up the files.  Why not have the operator that creates the material  and the panel that displays it all in the one module.   On the errors and assoc edits to question.  These are, strictly speaking,  basic python errors, not associated with the use of blender.   Strongly recommend googling eg  "python nameerror"  the causes and fixes are well documented.  Stackoverflow is good in this regard.

I have tried importing - from material_operator import get_group_nodes but it is showing material operator not found, I don't know why? I am keeping panel and operator in different files because I am making multiple materials and each material is an operator and in a different file and each operator is called from the panel, keeping all in one file will make the file huge and also it is not a good practise.

One operator could make multiple materials. Anyway please review my previous comment re import.  Don't mind helping, but this is getting way past the original question or related to usage of python in blender.  Is basic relative importing.   I'm not here to teach you python, nor am I inclined to argue your point on what is or isn't good practice.

Thank you very much finally I did it.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
How to get Geometry nodes modifier inputs and its type using python
Is there any way to get the input value and type of Geometry Nodes modifier
I want to use these values in an addon, but these are not consistent, so I can't call it by using this command as sometimes it can be Input_3 despite its second input only
bpy.ops.object.geometry_nodes_input_attribute_toggle(prop_path="[\"Input_2_use_attribute\"]", modifier_name="GeometryNodes")

and I can't feed the values using this -
bpy.data.objects["Cube"].modifiers["GeometryNodes"]["Input_2_attribute_name"] = "UVMap"

as this will only work if the inputs are toggled to attribute only.
so is there any way to get the status of the input? and can we get all the inputs of a modifier and the input name and use Input name to make sure, we are feeding values for the right input, Like in the below example image second input's name is UVMap and I want to feed some value to the input of the modifier which has this particular name only and not by the name like Input_2
or is there any other better way of handling this situation?

Edit:
I have some doubts, like we need to use this command to toggle to attribute mode, and is there any other way of toggling? or is it the only way? bpy.ops.object.geometry_nodes_input_attribute_toggle(prop_path="[\"Input_2_use_attribute\"]", modifier_name="GeometryNodes") as this method use "Inputs_2_use attribute" as string and we can't assign this value to variable and use it dynamically.

FWIW the operator can be overriden with the object key if you don't want to use the context : bpy.ops.object.geometry_nodes_input_attribute_toggle({"object": bpy.data.objects["Cube"]}, prop_path="[\"Input_2_use_attribute\"]", modifier_name="my_mod_name")

Be aware that there is current a bug in Geometry Nodes and the assignment will not always work correctly.
That said, the way to get to the individual input fields is to go through the object's Geometry Node Modifier's node_group to get the relationship between the display name of the input field and the numeric position of the input field.  Here's an example that assumes that modifier has already been set to the object's Geometry Nodes Modifier:
for input in modifier.node_group.inputs:
    print(f"Input {input.identifier} is named {input.name}")

Thus, if you know the name, you would search node_group.inputs for that name.  That input would be the one you wanted.
Also note that the modifier's own name "GeometryNodes" can change and that an object can have more than one GeometryNodes modifier.  Here's code that finds all of the GeometryNode modifiers of the active object and selects the first one in the list:
object = bpy.context.active_object

modifiers = []
for modifier in object.modifiers:
    if modifier.type == 'NODES':
        modifiers.append(modifier)
        print(f"Found Geometry Node modifier {modifier.name}")

modifier = modifiers[0]

Hi, thanks for your answer, and it helped me pretty much, but still I have some doubts, like we need to use this command to toggle to attribute mode, and is there any other way of toggling? or is it the only way? bpy.ops.object.geometry_nodes_input_attribute_toggle(prop_path="[\"Input_2_use_attribute\"]", modifier_name="GeometryNodes") as this method use "Inputs_2_use attribute" as string and we can assign this value to variable and use it dynamically. I hope you understood though this may be a little bit of unclear explanation

We do have to use the toggle and as far as I know there is no other way.

The syntax has changed since version 4.0. I suggest monkey-patching bpy.types.GeometryNodeTree so you can use previous scripts as is.
from bpy.types import GeometryNodeTree

def register():
    @property
    def inputs(tree):
        return [
            s
            for s in tree.interface.items_tree
            if getattr(s, "in_out", "Panel") == "INPUT"
        ]

    @property
    def outputs(tree):
        return [
            s
            for s in tree.interface.items_tree
            if getattr(s, "in_out", "Panel") == "OUTPUT"
        ]

    GeometryNodeTree.inputs = inputs
    GeometryNodeTree.outputs = outputs

if __name__ == "__main__":
    register()

Otherwise the syntax is
for item in mod.node_group.interface.items_tree:
     if item.item_type == "PANEL":
        print("I am a Panel")
        print(f"{item.name=}")
    elif item.in_out == "INPUT":  # item.item_type = "SOCKET"
        print("I am an input")
        print(f"{item.identifier=}")
        print(f"{item.socket_type=}")
        print(f"{item.name=}")
    elif item.in_out == "OUTPUT":  # item.item_type = "SOCKET"
        print("I am an output")
        print(f"{item.identifier=}")
        print(f"{item.socket_type=}")
        print(f"{item.name=}")

Relevant links
https://docs.blender.org/api/current/bpy.types.NodeTree.html#bpy.types.NodeTree.interface
https://docs.blender.org/api/current/bpy.types.NodeTreeInterface.html#bpy.types.NodeTreeInterface
https://docs.blender.org/api/current/bpy.types.NodeTreeInterfaceItem.html#bpy.types.NodeTreeInterfaceItem
Other relevant attributes of bpy.types.NodeTreeInterfaceItem that are not documented are :
bl_socket_idname  # Only for sockets
default_attribute_name  # Only for sockets
default_value  # Only for sockets
default_closed  # Only for panels
description
force_non_field  # Only for sockets
from_socket  # Only for sockets
hide_in_modifier  # Only for sockets
hide_value  # Only for sockets
identifier  # Only for sockets
in_out  # Only for sockets
index
init_socket  # Only for sockets
interface_items  # Only for panels
item_type
name
parent
position
rna_type
socket_type  # Only for sockets

Thank you. I was going insane as to why my script for changing inputs suddenly stopped working and the blender documentation was no help!

Thank you, however I still have not figured out how to print the current value of a socket. What am I missing?

@CobyRandal what I have done is taking the item.identifier and use it as mod[item.identifier] (where mod is NodesModifier). Maybe there is more direct way but it works


text:
Blender version(s) useable on Linux PCs with CPUs without SSE2?
Several computer science students in developing countries, who only have access to old PCs with non-SSE2 CPUs (mostly AthlonXP processors with SSE1), would like to know the version number of the last Blender before this great application began to be compiled to take advantage of SSE2. The machines use the Ubuntu based Linux Mint version of the Linux operating system.
If anybody could advise the best and most stable edition that can run on such machine I would be sincerely grateful.
Thank you in advance for your help.

Here is a list of previous releases.  You may need to use some trial and error with this to find out what works.  http://download.blender.org/release/

While there are 32bit versions available to download, you should be able to use the newest version of blender but maybe you need to compile it yourself. If you have one faster machine and want to use it to compile for the other machines you can specify -march=athlon-xp in the CFLAGS and CXXFLAGS to be sure the compiled app will run on the older cpu's. I have seen issues compiling using gcc4.2 so you may want to install gcc4.6 or clang to compile with. See this wiki page

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
How To Append a Node group from another Blend file Using Python Script
How To Append a Node group from another Blend file that is Present in my D drive on my windows computer.
I wan't to Append a Material and path to my material is -
- D:\2.8\Test01.blend\Material\Test_Material
using a python script.
Can Anyone Help me Out ?

https://blender.stackexchange.com/a/92676/442

This Script which you suggested is not loading my file path it is showing error - (Traceback (most recent call last):
File "C:\Users\Rakesh\Desktop\Script.blend\Text", line 16, in
OSError: load: C:\Users\Rakesh\Desktop\Fire Shader Advanced.blend\Material failed to open blend file
Error: Python script failed, check the message in the system console)

Also see https://blender.stackexchange.com/questions/139322

I finally got the answer of this problem
this scipt worked for me
 -
import bpy
path = "/Users/Rakesh\Desktop/wallpapers/FIRE SHADER/Fire Shader Advanced.blend\\Material\\"
material_name = "domain"
bpy.ops.wm.append( filename = material_name, directory = path)

Could you please post your code?

I just Made a New Material and Imported it using this script - import bpy
path = "/Users/Rakesh\Desktop/wallpapers/FIRE SHADER/Fire Shader Advanced.blend\Material\"
material_name = "domain"
bpy.ops.wm.append(filename=material_name,directory=path)


text:
How to draw a node group in a layout panel using python
I just made that node group and i just wanted that this node group should appear in Properties panel in 3d view which appears when 'N' Key is Pressed
this should look like this in materials tab

can any one tell me how to do that?

This sounds confusing. Like this??

From you edit, I see that you have added  a custom panel in the 3D view. That information is important I think. You should add it back again.

Already gave you a answer to this here https://blenderartists.org/t/how-to-access-and-draw-the-node-group-input-slider-in-layout-panel/1185331/12
You had a material named "TestMat" and a group named "Group". It draws the group properties if there is a material and group with those names.


text:
How to draw Inputs from Geometry nodes modifier in a panel
I am trying to draw the inputs of the Geometry Nodes modifier to a panel, and I tried doing this
import bpy
from bpy.types import (Panel)

class DRAW_PT_ModInputs(Panel):
    bl_label = "Draw Modifier Inputs"
    bl_idname = "DRAW_PT_ModInputs"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"

    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.label(text = "Geometry Node inputs here")
        row = layout.row()
        GeoNodesModifier = context.active_object.modifiers.get("GeometryNodes")
        if GeoNodesModifier:
            row.prop(GeoNodesModifier.Input_5, "Density Max", text="Density")

classes = [DRAW_PT_ModInputs]

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

def unregister():
    for cls in classes:
        bpy.utils.register_class(cls)

if __name__ == "__main__":
    register()

and that gave me error AttributeError: 'NodesModifier', object has no attribute 'Input_5' and in another attempt I tried this row.prop(GeoNodesModifier['Input_5'], "Density Max", text="Density") but this is also not working and it gives error -
TypeError: UILayout.prop(): error with argument 1, "data" -  Function.data expected a AnyType type, not float

and this is how my Geometry Nodes Modifier looks like -

and this is my Geometry Node tree -

I needed help regarding drawing the inputs from the Geometry Nodes modifier in my customized panel.
Thanks in advance!

Check out the style guide  under which the modifier instance variable would be named akin to geom_modifier  (I  like using gm to reduce the verbosity)  Camel case is used for class names. A variable named  GeoNodesModifier  will consistently be a type in any official blender UI code.

The modifier input value is treated like a custom property.
If you right click over the data field in the modifier and select "copy datapath", pasting will reveal
modifiers["GeometryNodes"]["Input_5"]

Indicating it is a custom propoerty of the modifier named "Input_5".  A custom property named "prop" on object ob is shown in UI as
UILayout.prop(ob, '["prop"]')

Hence in this case.
    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.label(text = "Geometry Node inputs here")
        row = layout.row()
        gm = context.active_object.modifiers.get("GeometryNodes")
        if gm:
            row.prop(gm, '["Input_5"]',  text="Density")

Note
Check out the style guide under which the modifier instance variable would be named akin to geom_modifier (I like using gm to reduce the verbosity) Camel case is used for class names. A variable named GeoNodesModifier will consistently be a type in any official blender UI code

That was fast :) Oh right, add commas around the list ! Clever. I don't know about the use of custom properties though. It would seem better to me if they were categorised in an inputs container and accessed like in node groups for instance. Using custom properties might clash with addons and so on. Idk

Agreed, fuddles the py console too.  Teething problem perhaps?

Yeah, I'm not too worried, it's still a very young tool and they have time to improve the API and UI :) But unfortunately that will render this kind of answers outdated at every breaking update...

Also agreed. Will notice that like UI defined custom properties the _RNA_UIdata is set. Changing the input / output node default_value sets the default of custom prop. C.object.modifiers["GeometryNodes"]['_RNA_UI'].to_dict()

@batFINGER aside from losing panel formatting can you think of any other reason not to do something like for ip in gm.node_group.inputs: layout.prop(gm, f'["{ip.identifier}"]', text=ip.name)

Very helpful, would have never thought of trying it like this.

From what I understood from the GeoNodes modifier API, you access the node group (or tree, since every node tree is a group and every node group is a tree there) with modifier.node_group. This will give you access to the inputs and outputs, very much like all other node groups in Blender (Shader, Compositor, etc.)
You can then access the input by its Name, or its integer position in the inputs hierarchy. The former will break if you change the input name, while the latter will break if you reorder your inputs.
Replace your row.prop line with
row.prop(geom_modifier.node_group.inputs["Density Max"], "default_value", text="Density")

OR
row.prop(geom_modifier.node_group.inputs[1], "default_value", text="Density")

Result :

If you want more information from the API, check Python tooltips and developer extras in the preferences, and hover over fields to get more information about their relative path.

Hi, this is working fine with the default value of the input node, but it is not updating in the inputs of the modifier

Right, my mistake ! See the other answer :)

This does not answer how to change the value of the modifier (Geometry node) input, but how to change a "default_value" value of the group node contained in the modifier. This will have no effect on the value displayed in the Geometry Node

@NoobCat yes, as stated in the comment above I didn't understand the question. See the other answer


text:
Align the corner and make the walls symmetrical in edit mode
Is there any way to even out the wall thickness in edit mode? It is important to repeat the distance between the edges so that the angle is symmetrical.

hello, how does the whole mesh look like? maybe try extrude along normals?

Perhaps this would work, but the walls given in the example already initially have different thicknesses. Extrude along normals will initially turn out to be asymmetric.

Are they aligned with the X and Y axes? Then I would for example select the edges in Y direction, hit G, X to move them along X and snap them to the outer edge. Press Enter to confirm their position. Now with them still selected (will be tricky to select them afterwards when they're overlapping), hit G, X again and enter a value like .1 (or -.1 depending to go to the other side) to move it an exact distance. Do this accordingly for the other edges in X direction by moving them with G, Y.

I got it, thanks for the hint, now everything has worked out.


text:
Is there a way to increase the shader node limit?
I'm curently working on a reasonably bigger shader node tree. The problem I have is that I keep hitting the shader node limit in EEVEE, so I switched to Cycles.
However after adding a few nodes even Cycles hit the node limit.
It is absolutely impossible to toss out any nodes, or "find a more elegant way to solve my underlying problem" as every node serves it's own purpose and has been optimized as much as possible, so finding a way to increase the node limit would be the only solution.
The thing is that the node tree isn't even computationally that expensive (it takes about 10 seconds to render 100 samples on a flat plane) so I absoluetly see no reason why Blender would stop me from using more nodes.
Is there a way to increase the shader node limit or remove it entirely?
And how is it calculated in the first place?

You need a lot of nodes to hit the limit (>400) - at some point over this, blender encounters a SVM (Support Vector Machine) stack error and shows nothing but black. As far as I know this is a hard-coded limitation, and there is no way to increase it.

I use multiple uber shaders which can do lots of things simulatenously but consequently also have to be complicated. Is there not even a python way or something to increase the limit? @ChristopherBennett

This sounds like the XY Problem there is probably a more elegant way to solve your underlying objective

@DuarteFarrajotaRamos I edited the question to make the question clearer. It doesn't seem like teh XY Problem to me though.

@ChristopherBennett If possible, could you please tell us a little more about the SVM (Support Vector Machine) (even if it isn't directly related to the question)?

SVM stands for Shader Virtual Machine as far as I know

My bad - I assumed it was doing lots of vector math. It seems Shader Virtual Machine is correct as Duarte mentioned. It's just a small virtual machine that runs shader code - but it does have a buffer limit - I assume you are reaching it somehow.


text:
Can I render simultaneously both with EEVEE and Cycles on the same GPU without perfomance loss?
Recently while rendering in EEVEE and Cycles I had a look on my GPU usage in task manager.
Unsurprisingly when I looked at CUDA usage when using Cycles it was near 100%, while another tab called "3D" was near 0%. But when I then rendered using EEVEE CUDA was at near 0% while "3D" was near 100%.
It appears to me as though EEVEE and Cycles use two completely different areas of the GPU.
Does that mean that I should be able to simultaneously render a scene in Cycles and in EEVEE without experiencing a slowdown in either render?

Cycles & EEVEE use different sections of the GPU because they are separate. Cycles uses ray-tracing, while EEVEE uses approximate rendering.

My initial thought is no - the card operates within an input power envelope and probably is throwing all available wattage at the job.  Anything else you give it will divide the available power.

When rendering, you are doing many things other than strictly calculating the color of each pixel, some of these things require the same parts of the GPU, some of thing things go through the same gate which can't allow any load size nor rate of passage, the list goes on. And even the simple heating of the device by one task does change the performance.

While I do not have measurements at the moment to back this up, the answer is most likely that you will experience slower rendering. Cycles has to move significant amounts of data to the GPU (e.g. textures and geometry) for the rendering. The possible data rate (bandwidth) creates a bottleneck that determines how fast the rendering can happen. Plenty of resources are shared on the GPU regardless whether OpenGL or CUDA are used. Considering caches, shared local memory, the GPU heating up, the render time per job will most likely degrade.

However, you might still save time as long as running the jobs in parallel does not cause a slow down longer than running them in sequence. Determining the utilization and performance will require actual measurments on real hardware though and also depend on the particular hardware architecture of the GPU as well as scene complexity.

Think of it like flatmates: they each have their dedicated rooms but still need to share the same doorway, bills and kitchen.


text:
How to get the actual light reflectance vector?
The texture coordinate node has an output called "reflection". But this "reflection" output only gives us the reflection of a perfectly sharp mirror. So if I have e.g. a diffuse shader or a glossy shader with the roughness set toany value other than 0 the vector the texture coordinate node gives as "reflection" is not really the vector that the actual light ray got reflected.
How do I get the actual light reflectance vector?
Edit:
Here I have included a sample .blend file:

I may be wrong, but isn't that exactly the behavior of a ray? Angle of incidence == angle of reflection? And a light beam/ray has always only exactly one reflection. Diffusity only comes about when many rays are reflected differently at different coordinates due to the surface property, right?

Angle of incidence == angle of reflection? Yes and No. Yes because in microfacet theory this happens on a microscopic scale, but here's the problem: When you set e.g. a glossy shader roughness to anything other than 0 it randomizes the shading normal about which the reflection occurs. The Texture coordinate reflection output can't do that and therefore always calculates the reflection vector using the unmodified shading normal.

But then I would rather guess that even in microscopic scales there is always only one ray, and that the diffusivity is rather a trick of the shader, because never so many rays can be generated as it is the case in reality, right?

What I want is the reflection vector that was calcuated using the modified shading normal.

But then I would rather guess that even in microscopic scales there is always only one ray, and that the diffusivity is rather a trick of the shader, because never so many rays can be generated as it is the case in reality, right? Yes and I want the vector representing that ray.

Yes, but that's what I meant ;-): this vector always stays the same, no matter how the shader then tricks around with it and builds diffusivity around it ....or am I completely wrong here?

No this vector is different for every sample. If it were the same you would just get a scewed sharp reflection.

So you would like to have the vector of a single sample (Which again depend on renderer)?

Cycles. EEVEE doesn't do path tracing.

As far as I'm aware this is not possible with shader nodes. It would also be highly dependent on the particular ray and sample that is being evaluated. A particular pixel / coordinate would possibly have many different vectors. I don't think OSL would help here either. Perhaps you could explain what you are trying to use this for, so we could suggest an alternative approach?

I have a 3D procedural shape which I can only visualize using a volume shader. For this I use the Principled volume shader. You can imagine that I have an inside of the shape and an outside of the shape. To make the shape look like a solid instead of a volume I use a very high density value (about 1000000). The problem I now face is that Principled volume scatters the light diffusely, so I can't get sharp reflections. If I can somehow drive the behaviour of the shader depending on the real reflection vector I could maybe achieve sharp relfections.

I will now try to upload a sample .blend file.

I might be missing some context information, but wouldn't a Volume to Mesh node or modifier work?


text:
Any blender GUI toolkit for use with Game engine?
Is there any blender GUI toolkit/library (popup window + eventual window control, button, radio button, checklists, slider, enter text...) to use with blender game engine.
The purpose is to evoke, for example, a button, place it at a given coordinates, then add the appropriate sensor, controller and actuator.

There is a library called bgui that makes creating GUI for the bge much easier.
There are two locations for the documentation, the old (but better) google project wiki and the read the docs page.
In a nutshell, add the bgui script to your project with a python controller in the logic editor. Use a always sensor to trigger the script to always run.
Next you add widgets or components to bgui with a line such as this (this will add a button).
# A FrameButton widget
self.btn = bgui.FrameButton(self.frame, 'button', text='Click Me!', size=[0.3, 0.1], pos=[0, 0.4], options=bgui.BGUI_DEFAULT | bgui.BGUI_CENTERX)

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
How to smooth second derivative of selected mesh?
I have a mesh that I want to smooth by minimizing the second derivative of it, while taking into account non-selected vertices (for the edge condition of this derivative).
For example, let the following be a 1-Dimensional line of connected vertices (connected left to right):

      .       .
  .       .

Where the last two are NOT selected. They determine the slope
at the end though. So, after smoothing 100% (only changing the vertical coordinate here) the result should look like:

              .
          .
      .
  .

where the second derivative has been reduced to zero.
Of course, for a 2D mesh the mathematics are a lot more complex and you need an edge condition on all sides; but hopefully you get the picture.


text:
What do the different types of musgrave texture do?
The musgrave texture properties let's one choose between 5 types of perlin noise. While FBM is just the Fractal Brownian Motion we all know and love it also offers other types like Hetero terrain or Multifractal which I have never heard of.
What I want to know is how those types of perlin noise are generated mathematically, as there are already enough tutorials on Youtube, which vaguely describe how these noise types look.
You can assume that I know how Perlin noise is generated.
Edit: Quellenform found the source code in question: https://github.com/blender/blender/blob/dfb8c90324c018068f12ca41543c3c311dff6d21/source/blender/blenlib/intern/noise.cc#L747
Thanks!


text:
How does the noise texture keep it's values between a 0 to 1 range
When using both the fac output and the color output (which is the same as three different fac outputs in RGB) the values somehow are always between a 0 to 1 value range. If we use a reguralar perlin noise like the musgrave texture in Blender we see that for high detail values the output values quickly go above 1 and below 0. So the noise texture, which like the musgrave texture also evaluates a perlin noise, obviously remaps the perlin noise so that it always stays in the 0 to 1 range.
Could somebody please explain how the noise texture does that and link the source code, which controls this remapping?

Looks like it just divides it by the maximum possible amplitude. src

Wait how did you figure that out?

Cause I just found that out simultaneously XD

But do you know why Blender seems to have the same code in multiple locations? Because I found it in a completely different folder

There are at least two implementations of nodes; Eevee, that uses OpenGL and is written in GLSL, and Cycles that uses OSL. For simple nodes I generally I find Cycles easier to understand. They differ for things like Principled (Eevee uses an approximation IIUC).

In the source code you linked it uses a "noise" function, which is not declared in that file do you know where it is?

No. (more characters so this passes the character limit)

The difference is actually only that for example Musgrave Texture initializes perlin noise as signed integer, and the Noise Texture as unsigned integer.
Therefore only the range from $-1$ to $1$ or $0$ - $1$ changes at the base.
The following example illustrates this a bit better:

On the left, the values have simply been mapped to a new range using the Map Range node, and on the right is the normal Noise Texture (the contrast here is just to make the result stand out more).
You can find the corresponding places in the source code here:
Musgrave Texture:

class MusgraveFunction
float musgrave_multi_fractal

Noise Texture:

class NoiseFunction
float perlin_fractal_template

Wow, this again is in a completely different location than what scurest and I found.

Small correction: musgrave node also doesn't divide by maximal amplitude

@tempdevnova Yes, in further consequence these function differently, you are absolutely right, but the decisive factor is primarily the basis with which the calculation is started.

@quellenform Sorry. Am I correct for saying this: The actual range of Perlin Noise is [-1,1], but in Blender, the range is remapped to [0,1] (for whatever reason) by using a Map Range (aka Linear Interpolation) function?

Scurest found the corresponding source code, linked in his comment.
Apart from that I also found the source code in question in a different folder:
https://github.com/blender/blender/blob/dfb8c90324c018068f12ca41543c3c311dff6d21/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl#L29
So, yeah basically it just divides by the maximal possible amplitude.

Sorry. Am I correct for saying this: The actual range of Perlin Noise is [-1,1], but in Blender, the range is remapped to [0,1] (for whatever reason) by using a Map Range function? The highest upvotes answer mentioned Map Range (aka Linear Interpolation).


text:
Blender progress bar not updating while downloading file
I wrote a function and an operator to download files, but whenever I am downloading the files, Blender freezes. and progress bar is not updating, while downloading, it is only updated after the download finished.
I Imported threading, for this, download is working fine, the only issue is with freezing blender and updating progress bar realtime.
# Global variable to store download progress
download_progress = 0.0
is_downloading = False

# Lock for thread-safe progress updates
progress_lock = threading.Lock()

# Function to download a file in a background thread
def download_file(url, save_path):
    global download_progress, is_downloading

    with progress_lock:
        is_downloading = True

    try:
        response = requests.get(url, stream=True)
        total_size = int(response.headers.get('content-length', 0))

        if response.status_code == 200 and total_size > 0:
            downloaded = 0

            # Open a file to write the download stream
            with open(save_path, 'wb') as file:
                for data in response.iter_content(chunk_size=4096):
                    file.write(data)
                    downloaded += len(data)

                    # Update progress inside the download loop
                    with progress_lock:
                        download_progress = downloaded / total_size
                        bpy.context.scene.download_progress = download_progress  # Update scene progress
        else:
            raise Exception(f"Error downloading asset: {response.status_code}")

    except Exception as e:
        print(f"Error during download: {e}")

    finally:
        with progress_lock:
            download_progress = 1.0  # Mark the download as complete
            bpy.context.scene.download_progress = 1.0
            is_downloading = False  # Reset downloading flag

I wrote this operator to download files and save them in a directory
class DownloadAssetOperator(bpy.types.Operator):
    bl_idname = "asset_browser.download_asset"
    bl_label = "Download Asset"

    file_name: bpy.props.StringProperty()
    _timer = None
    _thread = None

    def execute(self, context):

        try:
            prefs = bpy.context.preferences.addons[__package__].preferences
            id_token = prefs.id_token  # Fetch the id_token stored during login

            # Check if the user is logged in (if id_token exists)
            if not id_token:
                self.report({'ERROR'}, "Please log in first.")
                return {'CANCELLED'}

            # Get the asset directory from preferences
            asset_directory = prefs.asset_directory

            # Ensure the directory exists
            if not os.path.exists(asset_directory):
                os.makedirs(asset_directory)

            # print(f"ID Token: {id_token}")

            # Step 1: Get assetId using file_name
            asset_id = get_asset_id(self.file_name, id_token)

            # Step 2: Get presigned URL using assetId
            presigned_url = get_presigned_url(asset_id, self.file_name, id_token)

            # Step 3: Download asset with progress bar
            save_path = os.path.join(asset_directory, self.file_name)

            # Start the download and update the progress bar
            self._thread = threading.Thread(target=download_file, args=(presigned_url, save_path))
            self._thread.start()

            # Start a modal timer to update the progress in the UI
            self._timer = context.window_manager.event_timer_add(0.1, window=context.window)
            context.window_manager.modal_handler_add(self)

        except Exception as e:
            self.report({'ERROR'}, str(e))

        return {'RUNNING_MODAL'}

    def modal(self, context, event):
        global download_progress, is_downloading

        if event.type == 'TIMER':
            with progress_lock:
                # If download is in progress, update progress bar in 3D view header
                if is_downloading:
                    # Redraw the 3D View header
                    for area in context.window.screen.areas:
                        if area.type == 'VIEW_3D':
                            area.tag_redraw()
                            # Force a redraw of the header
                            for region in area.regions:
                                if region.type == 'HEADER':
                                    region.tag_redraw()
                else:
                    self.finish(context)
                    return {'FINISHED'}

        return {'RUNNING_MODAL'}

    def finish(self, context):
        # Remove the timer and stop modal operator
        context.window_manager.event_timer_remove(self._timer)
        self.report({'INFO'}, "Download Complete")
        print("Operator finished")  # Debug: print when operator finishes

    def invoke(self, context, event):
        # Start the modal operator
        return self.execute(context)

and also a panel to view progress bar
class LayoutDemoPanel(bpy.types.Panel):
    """Creates a Panel in the scene context of the properties editor"""
    bl_label = "Layout Demo"
    bl_idname = "SCENE_PT_layout"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"

    def draw(self, context):
        global download_progress, is_downloading
        layout = self.layout
        layout.label(text="Progress here:")
        layout.prop(bpy.context.scene, "download_progress", slider=True)

Progress bar FloatProperty is registered, in the register function in the bottom of the code
bpy.types.Scene.download_progress = bpy.props.FloatProperty(name="Progress", default=0.0, min=0.0, max=1.0)

What could be the issue, where am I wrong?
Update:
# Global variables to store download progress
download_progress = 0.0
is_downloading = False
download_complete = False

# Lock for thread-safe progress updates
progress_lock = threading.Lock()

def download_in_background(url, save_path):
    global download_progress, is_downloading, download_complete
    is_downloading = True
    download_complete = False
    download_progress = 0.0

    try:
        # Start the download request
        response = requests.get(url, stream=True)

        if response.status_code == 200:
            total_size = int(response.headers.get('content-length', 0))
            chunk_size = 1024  # 1 KB
            downloaded_size = 0

            with open(save_path, 'wb') as f:
                for chunk in response.iter_content(chunk_size=chunk_size):
                    if chunk:
                        f.write(chunk)
                        downloaded_size += len(chunk)

                        # Update progress safely with the lock
                        with progress_lock:
                            download_progress = (downloaded_size / total_size) * 100

            # Mark the download as complete
            with progress_lock:
                download_complete = True
                download_progress = 100.0
        else:
            print(f"Failed to download the file. HTTP Status: {response.status_code}")
            with progress_lock:
                download_complete = True  # Mark as finished even if failed

    except Exception as e:
        print(f"Error during download: {e}")
        with progress_lock:
            download_complete = True  # Mark as finished even if failed

class DownloadAssetOperator(bpy.types.Operator):
    bl_idname = "asset_browser.download_asset"
    bl_label = "Download Asset"

    file_name: bpy.props.StringProperty()
    _timer = None
    _thread = None

    def execute(self, context):
        prefs = bpy.context.preferences.addons[__package__].preferences
        id_token = prefs.id_token

        if not id_token:
            self.report({'ERROR'}, "Please log in first.")
            return {'CANCELLED'}

        asset_directory = prefs.asset_directory
        if not os.path.exists(asset_directory):
            os.makedirs(asset_directory)

        asset_id = get_asset_id(self.file_name, id_token)
        presigned_url = get_presigned_url(asset_id, self.file_name, id_token)

        save_path = os.path.join(asset_directory, self.file_name)

        # Start download in a separate thread
        self._thread = threading.Thread(target=download_in_background, args=(presigned_url, save_path))
        self._thread.start()

        # Start the progress timer to update Blender's UI without freezing
        bpy.app.timers.register(self.update_progress)

        return {'RUNNING_MODAL'}

    def update_progress(self):
        global download_progress, download_complete

        with progress_lock:
            # Update progress in Blender's progress bar
            bpy.context.window_manager.download_progress(download_progress / 100.0)

            if download_complete:
                self.finish()
                return None  # Stop the timer, download is complete

        # Return a time interval to re-call this function (to update regularly)
        return 0.1  # Update every 0.1 second

    def finish(self):
        bpy.context.window_manager.progress_end()  # End the progress bar
        self.report({'INFO'}, "Download Complete")
        bpy.context.scene.download_progress = 1.0  # Ensure the progress is set to 100% when done

    def invoke(self, context, event):
        bpy.context.window_manager.progress_begin(0, 100)  # Start progress bar
        return self.execute(context)

Now Blender is not freezing, and also the file is downloading, but, Progress bar is still not updating with the download?

Might be related: https://docs.blender.org/api/current/info_gotcha.html#strange-errors-when-using-the-threading-module See other stuff on the page as well.

Not sure global variables just work like that in Blender add-ons. Try storing stuff some other way. Search for a good way to do this with Blender API here on BSE. Maybe this: https://blender.stackexchange.com/questions/160451/how-to-declare-global-variables-for-use-in-an-addon-that-arent-stored-in-the-bl ?..

The problem is the entire download process happens within one iteration of the modal operator, after the with open file as .... You want to find another way to do it, store the result of the request somewhere and throttle the download in every modal execution

"I wrote[...]" - you or chat GPT?