From c3ae14ad7107fe84255c7e316b9c7c7587ca15ec Mon Sep 17 00:00:00 2001 From: BrendanParmer <51296046+BrendanParmer@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:57:05 -0600 Subject: [PATCH 1/7] feat: lights only set use_nodes prior to 5.1 --- NodeToPython/export/shader/exporter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NodeToPython/export/shader/exporter.py b/NodeToPython/export/shader/exporter.py index 70060be..16d2ab2 100644 --- a/NodeToPython/export/shader/exporter.py +++ b/NodeToPython/export/shader/exporter.py @@ -160,7 +160,8 @@ def _create_light(self): f"type = {enum_to_py_str(light_type)})", indent_level ) - self._write(f"{self._obj_var}.use_nodes = True\n\n", indent_level) + if bpy.app.version < (5, 1, 0): + self._write(f"{self._obj_var}.use_nodes = True\n\n", indent_level) self._write( f"{LIGHT_OBJ} = bpy.data.objects.new(" f"name = {str_to_py_str(light.name)}, " From 034f3f08a3c23af0881e2149ccc5e524ba1d3126 Mon Sep 17 00:00:00 2001 From: BrendanParmer <51296046+BrendanParmer@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:58:44 -0600 Subject: [PATCH 2/7] feat: parser script version bump --- tools/node_settings_generator/parse_nodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/node_settings_generator/parse_nodes.py b/tools/node_settings_generator/parse_nodes.py index 34a368c..562d547 100644 --- a/tools/node_settings_generator/parse_nodes.py +++ b/tools/node_settings_generator/parse_nodes.py @@ -39,7 +39,7 @@ class NodeInfo(NamedTuple): BLENDER_3_MAX_VERSION = 6 BLENDER_4_MAX_VERSION = 5 -BLENDER_5_MAX_VERSION = 0 +BLENDER_5_MAX_VERSION = 1 NTP_MIN_VERSION = Version(4, 2) From 7fd8cd922f82d3df8e799334743a365704d4df5a Mon Sep 17 00:00:00 2001 From: BrendanParmer <51296046+BrendanParmer@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:59:00 -0600 Subject: [PATCH 3/7] feat: auto-update node_settings.py --- NodeToPython/export/node_settings.py | 128 ++++++++++++++++++++++++--- 1 file changed, 118 insertions(+), 10 deletions(-) diff --git a/NodeToPython/export/node_settings.py b/NodeToPython/export/node_settings.py index 1e2eaaf..ec510f9 100644 --- a/NodeToPython/export/node_settings.py +++ b/NodeToPython/export/node_settings.py @@ -64,12 +64,12 @@ class NTPNodeSetting(NamedTuple): name_: str st_: ST min_version_: tuple = (4, 2, 0) - max_version_: tuple = (5, 1, 0) + max_version_: tuple = (5, 2, 0) class NodeInfo(NamedTuple): attributes_: list[NTPNodeSetting] min_version_: tuple = (4, 2, 0) - max_version_: tuple = (5, 1, 0) + max_version_: tuple = (5, 2, 0) node_settings : dict[str, NodeInfo] = { 'CompositorNodeAlphaOver' : NodeInfo( @@ -647,6 +647,11 @@ class NodeInfo(NamedTuple): ] ), + 'CompositorNodeMaskToSDF' : NodeInfo( + [], + min_version_ = (5, 1, 0) + ), + 'CompositorNodeMath' : NodeInfo( [ NTPNodeSetting("operation", ST.ENUM), @@ -804,6 +809,11 @@ class NodeInfo(NamedTuple): max_version_ = (5, 0, 0) ), + 'CompositorNodeSequencerStripInfo' : NodeInfo( + [], + min_version_ = (5, 1, 0) + ), + 'CompositorNodeSetAlpha' : NodeInfo( [ NTPNodeSetting("mode", ST.ENUM, max_version_=(5, 0, 0)), @@ -1093,6 +1103,11 @@ class NodeInfo(NamedTuple): [] ), + 'FunctionNodeMatrixSVD' : NodeInfo( + [], + min_version_ = (5, 1, 0) + ), + 'FunctionNodeProjectPoint' : NodeInfo( [] ), @@ -1220,6 +1235,13 @@ class NodeInfo(NamedTuple): ] ), + 'GeometryNodeBoneInfo' : NodeInfo( + [ + NTPNodeSetting("transform_space", ST.ENUM), + ], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeBoundBox' : NodeInfo( [] ), @@ -1282,6 +1304,11 @@ class NodeInfo(NamedTuple): [] ), + 'GeometryNodeCubeGridTopology' : NodeInfo( + [], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeCurveArc' : NodeInfo( [ NTPNodeSetting("mode", ST.ENUM), @@ -1495,6 +1522,13 @@ class NodeInfo(NamedTuple): min_version_ = (5, 0, 0) ), + 'GeometryNodeFieldToList' : NodeInfo( + [ + NTPNodeSetting("active_index", ST.INT), + ], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeFieldVariance' : NodeInfo( [ NTPNodeSetting("data_type", ST.ENUM), @@ -1542,6 +1576,11 @@ class NodeInfo(NamedTuple): [] ), + 'GeometryNodeGetGeometryBundle' : NodeInfo( + [], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeGetNamedGrid' : NodeInfo( [ NTPNodeSetting("data_type", ST.ENUM), @@ -1590,11 +1629,25 @@ class NodeInfo(NamedTuple): min_version_ = (5, 0, 0) ), + 'GeometryNodeGridClip' : NodeInfo( + [ + NTPNodeSetting("data_type", ST.ENUM), + ], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeGridCurl' : NodeInfo( [], min_version_ = (5, 0, 0) ), + 'GeometryNodeGridDilateAndErode' : NodeInfo( + [ + NTPNodeSetting("data_type", ST.ENUM), + ], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeGridDivergence' : NodeInfo( [], min_version_ = (5, 0, 0) @@ -1617,6 +1670,20 @@ class NodeInfo(NamedTuple): min_version_ = (5, 0, 0) ), + 'GeometryNodeGridMean' : NodeInfo( + [ + NTPNodeSetting("data_type", ST.ENUM), + ], + min_version_ = (5, 1, 0) + ), + + 'GeometryNodeGridMedian' : NodeInfo( + [ + NTPNodeSetting("data_type", ST.ENUM), + ], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeGridPrune' : NodeInfo( [ NTPNodeSetting("data_type", ST.ENUM), @@ -1628,6 +1695,13 @@ class NodeInfo(NamedTuple): [] ), + 'GeometryNodeGridToPoints' : NodeInfo( + [ + NTPNodeSetting("data_type", ST.ENUM), + ], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeGridVoxelize' : NodeInfo( [ NTPNodeSetting("data_type", ST.ENUM), @@ -1873,12 +1947,15 @@ class NodeInfo(NamedTuple): [ NTPNodeSetting("data_type", ST.ENUM), ], - min_version_ = (5, 0, 0) + min_version_ = (5, 0, 0), + max_version_ = (5, 1, 0) ), 'GeometryNodeListGetItem' : NodeInfo( [ - NTPNodeSetting("data_type", ST.ENUM), + NTPNodeSetting("data_type", ST.ENUM, max_version_=(5, 1, 0)), + NTPNodeSetting("socket_type", ST.ENUM, min_version_=(5, 1, 0)), + NTPNodeSetting("structure_type", ST.ENUM, min_version_=(5, 1, 0)), ], min_version_ = (5, 0, 0) ), @@ -2048,7 +2125,9 @@ class NodeInfo(NamedTuple): ), 'GeometryNodeRealizeInstances' : NodeInfo( - [] + [ + NTPNodeSetting("realize_to_point_domain", ST.BOOL, min_version_=(5, 1, 0)), + ] ), 'GeometryNodeRemoveAttribute' : NodeInfo( @@ -2224,6 +2303,11 @@ class NodeInfo(NamedTuple): [] ), + 'GeometryNodeSetGeometryBundle' : NodeInfo( + [], + min_version_ = (5, 1, 0) + ), + 'GeometryNodeSetGeometryName' : NodeInfo( [], min_version_ = (4, 3, 0) @@ -2362,11 +2446,11 @@ class NodeInfo(NamedTuple): 'GeometryNodeStringToCurves' : NodeInfo( [ - NTPNodeSetting("align_x", ST.ENUM), - NTPNodeSetting("align_y", ST.ENUM), - NTPNodeSetting("font", ST.FONT), - NTPNodeSetting("overflow", ST.ENUM), - NTPNodeSetting("pivot_mode", ST.ENUM), + NTPNodeSetting("align_x", ST.ENUM, max_version_=(5, 1, 0)), + NTPNodeSetting("align_y", ST.ENUM, max_version_=(5, 1, 0)), + NTPNodeSetting("font", ST.FONT, max_version_=(5, 1, 0)), + NTPNodeSetting("overflow", ST.ENUM, max_version_=(5, 1, 0)), + NTPNodeSetting("pivot_mode", ST.ENUM, max_version_=(5, 1, 0)), ] ), @@ -2548,6 +2632,14 @@ class NodeInfo(NamedTuple): ] ), + 'NodeGetBundleItem' : NodeInfo( + [ + NTPNodeSetting("socket_type", ST.ENUM), + NTPNodeSetting("structure_type", ST.ENUM), + ], + min_version_ = (5, 1, 0) + ), + 'NodeGroup' : NodeInfo( [ NTPNodeSetting("node_tree", ST.NODE_TREE), @@ -2584,6 +2676,14 @@ class NodeInfo(NamedTuple): min_version_ = (5, 0, 0) ), + 'NodeStoreBundleItem' : NodeInfo( + [ + NTPNodeSetting("socket_type", ST.ENUM), + NTPNodeSetting("structure_type", ST.ENUM), + ], + min_version_ = (5, 1, 0) + ), + 'ShaderNodeAddShader' : NodeInfo( [] ), @@ -2852,6 +2952,7 @@ class NodeInfo(NamedTuple): 'ShaderNodeNormalMap' : NodeInfo( [ + NTPNodeSetting("convention", ST.ENUM, min_version_=(5, 1, 0)), NTPNodeSetting("space", ST.ENUM), NTPNodeSetting("uv_map", ST.STRING), ] @@ -2927,6 +3028,13 @@ class NodeInfo(NamedTuple): min_version_ = (5, 0, 0) ), + 'ShaderNodeRaycast' : NodeInfo( + [ + NTPNodeSetting("only_local", ST.BOOL), + ], + min_version_ = (5, 1, 0) + ), + 'ShaderNodeScript' : NodeInfo( [ NTPNodeSetting("bytecode", ST.STRING), From 84a6407a1b499c47a7f73016910724cb8ef3e989 Mon Sep 17 00:00:00 2001 From: BrendanParmer <51296046+BrendanParmer@users.noreply.github.com> Date: Sun, 22 Feb 2026 10:59:47 -0600 Subject: [PATCH 4/7] feat: support font sockets --- NodeToPython/export/node_tree_exporter.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/NodeToPython/export/node_tree_exporter.py b/NodeToPython/export/node_tree_exporter.py index 4fda0b5..cf3fcd4 100644 --- a/NodeToPython/export/node_tree_exporter.py +++ b/NodeToPython/export/node_tree_exporter.py @@ -46,13 +46,16 @@ bpy.types.NodeTreeInterfaceSocketMatrix, bpy.types.NodeTreeInterfaceSocketObject, bpy.types.NodeTreeInterfaceSocketShader, - bpy.types.NodeTreeInterfaceSocketTexture + bpy.types.NodeTreeInterfaceSocketTexture, } if bpy.app.version >= (5, 0, 0): NO_DEFAULT_SOCKETS.add(bpy.types.NodeTreeInterfaceSocketBundle) NO_DEFAULT_SOCKETS.add(bpy.types.NodeTreeInterfaceSocketClosure) +if bpy.app.version >= (5, 1, 0): + NO_DEFAULT_SOCKETS.add(bpy.types.NodeTreeInterfaceSocketFont) + #node input sockets that are messy to set default values for DONT_SET_DEFAULTS = { 'NodeSocketGeometry', @@ -1509,6 +1512,10 @@ def _set_input_defaults(self, node: bpy.types.Node) -> None: self._in_file_inputs(input, socket_var, "textures") default_val = None + elif input.bl_idname == 'NodeSocketFont': + self._in_file_inputs(input, socket_var, "fonts") + default_val = None + else: default_val = getattr(input, "default_value") From 426d62b033444f0fce92dc713f800da11dc51952 Mon Sep 17 00:00:00 2001 From: BrendanParmer <51296046+BrendanParmer@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:00:14 -0600 Subject: [PATCH 5/7] feat: max blender version bump --- NodeToPython/export/ntp_operator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NodeToPython/export/ntp_operator.py b/NodeToPython/export/ntp_operator.py index 707457b..3c3ebf4 100644 --- a/NodeToPython/export/ntp_operator.py +++ b/NodeToPython/export/ntp_operator.py @@ -27,7 +27,7 @@ } MIN_BLENDER_VERSION = (4, 2, 0) -MAX_BLENDER_VERSION = (5, 1, 0) +MAX_BLENDER_VERSION = (5, 2, 0) class NodeTreeInfo(): def __init__(self): From f1acf116b5f1c9892f36c50daf905fffc2c94274 Mon Sep 17 00:00:00 2001 From: BrendanParmer <51296046+BrendanParmer@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:02:36 -0600 Subject: [PATCH 6/7] feat: better warning message for outdated node groups --- NodeToPython/export/ntp_operator.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/NodeToPython/export/ntp_operator.py b/NodeToPython/export/ntp_operator.py index 3c3ebf4..cf180e2 100644 --- a/NodeToPython/export/ntp_operator.py +++ b/NodeToPython/export/ntp_operator.py @@ -414,7 +414,22 @@ def dfs(nt: bpy.types.NodeTree) -> None: node_info._lib_dependencies[relative_path].append(nt) return else: - print(f"Library {lib_path} didn't seem essential, copying node groups") + # Try to link to current Blender version + # TODO: this fails when the tree interface changes + #for parent in lib_path.parents: + # if parent.name == "datafiles": + # relative_path = lib_path.relative_to(parent) + # if relative_path not in node_info._lib_dependencies: + # node_info._lib_dependencies[relative_path] = [] + # node_info._lib_dependencies[relative_path].append(nt) + # return + self.report( + {'WARNING'}, + f"Performing deep copy of node group \"{nt.name}\". " + f"Library {lib_path} was not included with current " + f"Blender version. If this node group came with Blender, " + f"please upgrade your node group to the current version" + ) if nt not in self._visited: self._visited.add(nt) From 1f0061c915bd8b6e4724eab88bd3703c3b1ab5b2 Mon Sep 17 00:00:00 2001 From: BrendanParmer <51296046+BrendanParmer@users.noreply.github.com> Date: Sun, 22 Feb 2026 11:03:18 -0600 Subject: [PATCH 7/7] fix: better handling of vector dimension/default value mismatches --- NodeToPython/export/node_tree_exporter.py | 37 ++++++++++++++++++----- NodeToPython/export/utils.py | 21 +++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/NodeToPython/export/node_tree_exporter.py b/NodeToPython/export/node_tree_exporter.py index cf3fcd4..206622c 100644 --- a/NodeToPython/export/node_tree_exporter.py +++ b/NodeToPython/export/node_tree_exporter.py @@ -576,16 +576,39 @@ def _set_tree_socket_defaults( elif type(dv) == mathutils.Euler: dv = vec3_to_py_str(dv) elif type(dv) == bpy_prop_array: - dv = array_to_py_str(dv) + dimensions = getattr(socket_interface, "dimensions") + if dimensions != len(dv): + self._operator.report( + {'WARNING'}, + f"Mismatched dimensions ({dimensions}) and " + f"default value ({len(dv)}) for socket {socket_var}" + ) + if dimensions < len(dv): + dv = vec_to_py_str(dv, dimensions) + else: + return + else: + dv = array_to_py_str(dv) elif type(dv) == str: dv = str_to_py_str(dv) elif type(dv) == mathutils.Vector: - if len(dv) == 2: - dv = vec2_to_py_str(dv) - elif len(dv) == 3: - dv = vec3_to_py_str(dv) - elif len(dv) == 4: - dv = vec4_to_py_str(dv) + dimensions = getattr(socket_interface, "dimensions") + if dimensions != len(dv): + self._operator.report( + {'WARNING'}, + f"Mismatched dimensions ({dimensions}) and " + f"default value ({len(dv)}) for socket {socket_var}" + ) + return + if dimensions in {2, 3, 4}: + dv = vec_to_py_str(dv, dimensions) + else: + self._operator.report( + {'WARNING'}, + f"Incorrect number of dimensions {dimensions} " + f"found for socket {socket_var}" + ) + return self._write(f"{socket_var}.default_value = {dv}") # min value diff --git a/NodeToPython/export/utils.py b/NodeToPython/export/utils.py index 0de8d54..2536572 100644 --- a/NodeToPython/export/utils.py +++ b/NodeToPython/export/utils.py @@ -111,6 +111,27 @@ def vec4_to_py_str(vec4) -> str: """ return f"({vec4[0]}, {vec4[1]}, {vec4[2]}, {vec4[3]})" +def vec_to_py_str(vec, dimensions: int) -> str: + """ + Converts a {dimensions}-D vector to a string usable aby the add-on + + Parameters: + vec: a {dimensions}-D vector + dimensions: number of dimensions + + Returns: + (str): string version + """ + if dimensions == 1: + return vec1_to_py_str(vec) + elif dimensions == 2: + return vec2_to_py_str(vec) + elif dimensions == 3: + return vec3_to_py_str(vec) + elif dimensions == 4: + return vec4_to_py_str(vec) + return "" + def array_to_py_str(array: bpy_prop_array) -> str: """ Converts a bpy_prop_array into a string