-
-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Input socket types for nodes #341
Comments
I would love having this feature. I think you could do the following to implement this feature.
Something like this could work for 3. class A:
@overload
def __getitem__(self, key: Literal[1]) -> Literal["a"]: ...
@overload
def __getitem__(self, key: Literal["a"]) -> Literal["a"]: ...
@overload
def __getitem__(self, key: Literal[2]) -> Literal["b"]: ...
@overload
def __getitem__(self, key: Literal["b"]) -> Literal["b"]: ...
def __getitem__(self, key: int | str) -> Any: ... What is describe above do not require a change to the Blender documentation. You may need to make a PR to Blender to surface the node type information @nutti, may have more to say on this. |
Iterating over the node inputs does return the class of the socket at runtime, will try writing something that should be able to dump that type information into a definition file. Thanks for the tips! |
Incredibly embarrassed to have come up with this, but this seems to work? import bpy
for node in bpy.types.ShaderNode.__subclasses__():
obj = bpy.context.selected_objects[0].material_slots[0].material.node_tree
m = obj.nodes.new(node.__name__)
print("--------------")
print(m.__class__.__name__)
print("--------------")
for i, input in enumerate(m.inputs):
print(f"[{i}]: {input.__class__.__name__}: {input.name}") |
I agree with your idea. @Surasia |
Hi! I've just ran into this and decided to look into fixing it. Based on the POC by @Surasia , I've written a simple generator script which adds a "private" Here's a small output example for class ShaderNodeBsdfDiffuse(ShaderNode, NodeInternal, Node, bpy_struct):
# insert after the existing type hints
class _NodeInputs(NodeInputs):
@typing.overload
def __getitem__(self, key: typing.Literal[0] | typing.Literal["Color"]) -> NodeSocketColor: ...
@typing.overload
def __getitem__(self, key: typing.Literal[1] | typing.Literal["Roughness"]) -> NodeSocketFloatFactor: ...
@typing.overload
def __getitem__(self, key: typing.Literal[2] | typing.Literal["Normal"]) -> NodeSocketVector: ...
@typing.overload
def __getitem__(self, key: typing.Literal[3] | typing.Literal["Weight"]) -> NodeSocketFloat: ...
inputs: _NodeInputs
class _NodeOutputs(NodeOutputs):
@typing.overload
def __getitem__(self, key: typing.Literal["BSDF"] | typing.Literal[0]) -> NodeSocketShader: ...
outputs: _NodeOutputs And here's the generator code: from pathlib import Path
import bpy
OUTPUT_PATH = Path(__file__).parent / "node_typing_out.pyi"
with OUTPUT_PATH.open("w", encoding="utf-8") as output_file:
for node_base_class in bpy.types.NodeInternal.__subclasses__():
print(node_base_class)
node_baseclass_name = node_base_class.__name__
nodetree_id = f"{node_baseclass_name}Tree"
nodetree_class = getattr(bpy.types, nodetree_id)
node_group = bpy.data.node_groups.new(nodetree_id, nodetree_id)
for node_class_name in dir(bpy.types):
if not node_class_name.startswith(node_baseclass_name):
continue
try:
node = node_group.nodes.new(node_class_name)
except RuntimeError:
continue
output_file.write(
f"class {node_class_name}({node_baseclass_name}, NodeInternal, Node, bpy_struct):\n"
f" # insert after the existing type hints\n\n"
)
if node.inputs:
output_file.write(" class _NodeInputs(NodeInputs):\n")
for i, input in enumerate(node.inputs):
output_file.write(
f" @typing.overload\n"
f" def __getitem__(self, key: typing.Literal[{i}]"
f' | typing.Literal["{input.name}"]) -> {input.__class__.__name__}: ...\n'
)
output_file.write("\n inputs: _NodeInputs\n\n")
if node.outputs:
output_file.write(" class _NodeOutputs(NodeOutputs):\n")
for i, output in enumerate(node.outputs):
output_file.write(
f" @typing.overload\n"
f' def __getitem__(self, key: typing.Literal["{output.name}"]'
f" | typing.Literal[{i}]) -> {output.__class__.__name__}: ...\n"
)
output_file.write("\n outputs: _NodeOutputs\n\n") @nutti I'd be happy to submit this as a pull request, but I'm not sure how/where this would be integrated into the existing generator code. Could you give me any pointers? |
Thank you for challenging this issue. I think this should not output to mod files which requires lots of computing resources. Is it possible to create a custom transformer? |
I've read through Generate Modules now to try to understand how this project functions and I'm not sure about that. The script I came up with requires information which is not present in the docs, so it has to be run from within Blender. Looking at Also, out of curiosity, what's the performance problem with "mod files"? |
OK, I misunderstood about it. |
Description about the feature
When creating nodes, it doesn't seem possible to use the "default_value" attribute for a
NodeSocket
, as those are defined for subclasses ofNodeSocket
such asNodeSocketFloat
.For instance, this code accesses the second input of a math node:
This however throws a type error as .default_value may is not defined in the
NodeSocket
class. It's possible to work around this by overriding the type of the input:Unfortunately, the documentation does not seem to specify the types for each input in a node socket, so I'm not sure if an implementation is possible.
Are you willing to contribute about this feature.
Yes, contributing to blender docs to specify input types.
The text was updated successfully, but these errors were encountered: