blender/scripts/modules/bpy_extras/node_utils.py
quackarooni c0a02f4df3 Fix: Node Wrangler: Connect to Output inside node groups fails for certain socket types
When inside a group, the `Connect to Socket` operator
creates a temporary socket for viewing.

This uses `node_utils.find_base_socket_type` to determine which data
type to use for the new socket. This function is missing newer socket
types, causing errors upstream when a type couldn't be determined.

This patch updates the helper function to have a basic fallback case
that follows the most common pattern. This makes it so that the
function doesn't have to be updated for each new socket type,
provided it follows the common convention.

Pull Request: https://projects.blender.org/blender/blender/pulls/164271
2026-09-30 10:25:27 +02:00

91 lines
2.6 KiB
Python

# SPDX-FileCopyrightText: 2009-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
__all__ = (
"connect_sockets",
"find_base_socket_type",
"find_node_input",
)
def find_base_socket_type(socket):
"""
Find the base class of the socket.
Sockets can have a subtype such as NodeSocketFloatFactor,
but only the base type is allowed, e.g. NodeSocketFloat
:param socket: The socket to find the base type for.
:type socket: :class:`bpy.types.NodeSocket`
:return: The base socket type identifier.
:rtype: str
"""
if socket.type == 'CUSTOM':
# Custom socket types are used directly
return socket.bl_idname
if socket.type == 'VALUE':
return 'NodeSocketFloat'
if socket.type == 'BOOLEAN':
return 'NodeSocketBool'
if socket.type == 'RGBA':
return 'NodeSocketColor'
else:
return "NodeSocket" + socket.type.title()
def connect_sockets(input, output):
"""
Connect sockets in a node tree.
This is useful because the links created through the normal Python API are
invalid when one of the sockets is a virtual socket (grayed out sockets in
Group Input and Group Output nodes).
It replaces node_tree.links.new(input, output)
:param input: The input socket.
:type input: :class:`bpy.types.NodeSocket`
:param output: The output socket.
:type output: :class:`bpy.types.NodeSocket`
:return: The created link, or ``None`` when the sockets cannot be connected.
:rtype: :class:`bpy.types.NodeLink` | None
"""
import bpy
# Swap sockets if they are not passed in the proper order
if input.is_output and not output.is_output:
input, output = output, input
input_node = output.node
output_node = input.node
if input_node.id_data is not output_node.id_data:
print("Sockets do not belong to the same node tree")
return
if type(input) == type(output) == bpy.types.NodeSocketVirtual:
print("Cannot connect two virtual sockets together")
return
return input_node.id_data.links.new(input, output, handle_dynamic_sockets=True)
def find_node_input(node, name):
"""
Find a node input socket by name.
Note that names are not unique, returns the first match.
:param node: The node to search.
:type node: :class:`bpy.types.Node`
:param name: The name of the input socket.
:type name: str
:return: The input socket or None if not found.
:rtype: :class:`bpy.types.NodeSocket` | None
"""
for input in node.inputs:
if input.name == name:
return input
return None