Python Nodes

Registration

Subclasses

Blender has a dynamic registration feature for certain RNA classes, like Operators, Panels, etc. This feature is now also available for node types, as well as socket types and even entire tree types.

The easiest way to register such types is by using Python scripts (although any RNA language binding could do this). In Python it works the same way as with existing registerable types, by defining a subclass of the bpy.types.Node base class:

class MyCustomTree(bpy.types.NodeTree):
# Description string'''A custom node tree type that will show up in the node editor header'''# Optional identifier string. If not explicitly defined, the python class name is used.
bl_idname = 'CustomTreeType'# Label for nice name display
bl_label = 'Custom Node Tree'# Icon identifier# Note: If no icon is defined, the node tree will not show up in the editor header!# This can be used to make additional tree types for groups and similar nodes
bl_icon = 'NODETREE'

Polling

Poll functions are a widely used concept in Blender for determining availability of features based on the context. For example:

Operator poll is used to test if an operator can be executed in a given context

Panel/Menu poll determines the visibility

Poll functions are used in different roles throughout Python Nodes as well.

node.poll

Many node types only work in one type of node system, for example:

Shader nodes only make sense in a Cycles node tree

Blur nodes only work in compositor nodes

The node.poll function in Node subclasses is a way of checking compatibility and/or limiting nodes to certain types of trees. Only if this function returns True can a new node of this type be created in the given tree.

class MyCustomNode(bpy.types.Node):
@classmethoddef poll(cls, tree):
# this node is only available in trees of the 'CustomTreeType'return tree.bl_idname == 'CustomTreeType'

Note that the poll function is a classmethod, so it can be called before an actual instance of this node type is created.

Node Types indepedent from Tree Types

In the current C implementation node types are stored as lists in tree types. This means that node types can not be shared between different tree types, which is a desirable feature (e.g. math nodes are common in many trees and could share the UI implementation).
By storing node types completely separate from tree types this limitation is removed. A node is not registered as part of a specific tree type. This limitation must be implemented by the poll function instead.

node.poll_instance

There is a secondary poll function called 'poll_instance', which is optional and not required for most node types. Unlike the poll function this is a full member function:

poll_instance is used by certain operators which insert nodes into a different tree, such as the node clipboard paste operator or the node group insert operator. One example use case is group nodes, which need to be prevented from being inserted into themselves to avoid infinite recursion. In general the 'poll_instance' function allows you to check the node's settings before allowing it to be inserted.

node_tree.poll

Node tree poll functions can restrict general access to a tree type based on context. If this function is defined and returns False, the tree type will not show up in the node editor.

copy

Called when a copy of some node is made instead of creating a new instance on its own.

free

def free(self, context):
print("Removing node: ", self.name)

Called when a node is deleted.

update

def update(self):
print("Updating node: ", self.name)

Called whenever the node relations in the editor change, i.e. a connection from/to this node is added or removed. Some advanced nodes may use this e.g. to change their socket layout based on connections.

Custom Properties

Almost all nodes will need to store some additional data for parameters. For this purpose nodes now have the ability to store custom properties (see this page for in-depth info about custom properties in general). With the bpy.props module node properties can be registered in the RNA:

Node Sockets

Node sockets can be added to and removed from nodes at any time. Most nodes will just need to add a static list of sockets when they are created, but in principle it is possible to change the interface to a node whenever needed.

Basic API functions

Node socket layout can be changed directly using one the following functions:

Adds an input/output socket respectively. The optional identifier can be used to resolve ambiguity when nodes have several equivalent sockets with the same name. If no identifier string is given explicitly the name string will be used. If a socket with the same identifier already exists, it will be replaced by the new socket.

Node.inputs.remove(socket)
Node.outputs.remove(socket)

Remove the input/output socket.

Sockets can be looked up by strings, which will use the socket identifier (defaulting to the socket name).

Socket Input Values

Sockets typically describe some sort of numeric input value of a node. Standard socket types of this kind in Blender include

Floating point numbers

RGB/RGBA colors

3D Vectors

Integer numbers

Boolean options (true/false)

Strings

These types of sockets conveniently can display a constant input value, which will be used when the socket is not connected to another node's output.

When created with the API functions described above, however, a new socket will not display a constant input value by default. In order to enable this the socket must be pointed to a property of the node, using the value_property string:

Instead of the low-level add/remove functions sockets can also be generated using a static list of templates. This is a simpler method for nodes that don't need to change their interface. These would be defined similar to bpy.props on the class level and generate appropriate input properties.

Draw functions

To actually display the custom properties of a node there is a draw function which can be implemented in Python. It works the same way as drawing in panels:

There is a second variant of the draw function which is used for the sidebar panel. This way extended information can be displayed separately if drawing on the node would take too much space or cause unwanted visual noise. The secondary draw function is optional, if undefined the standard draw function will be used in the sidebar.

Implementation Notes

Identifying Nodes

Main way of identifying node is bNodeType->idname string, not bNodeType->type integer. The type id stays for compatibility reasons and to keep old systems working until it can be replaced at later date.

Custom nodes use the NODE_CUSTOM type (value -1) to distinguish them and make functions use idname instead. For static node types (type != NODE_CUSTOM) the NOD_static_types.h header file (previously rna_nodetree_types.h) is used to generate usable idnames.

Registering Custom Node Types

Custom node types can be created using the RNA API functions. Node struct has register/unregister functions defined, which allocate a bNodeType struct and initialize from validation function.

Tree and node types use global hashes now for storing registered types. Node types are not directly stored in tree types any more, to have more flexibility: a node type can be used for multiple different tree types, if necessary.