Custom NodeTree and NodeCustomGroup and bpy.ops.node.tree_path_parent() I've done a fair amount of custom PyNode tree scripting for Sverchok, but one thing remains a bit nebulous and i'm hoping someone can shed some light.

The Material node trees have this Group feature which turns the background green and enables an operator on the header to call bpy.ops.node.tree_path_parent() to go to the parent node tree.



The poll / execute code for bpy.ops.node.tree_path_parent() is (...full code link)

@classmethod
def poll(cls, context):
    space = context.space_data
    # needs active node editor and a tree
    return (space.type == 'NODE_EDITOR' and len(space.path) &gt; 1)

def execute(self, context):
    space = context.space_data
    space.path.pop()
    return {'FINISHED'}


For a NodeGroup of ShaderNodeTree space.path becomes a collection of 2 paths.

&lt;bpy_collection[2], SpaceNodeEditorPath&gt;
--- &lt;bpy_struct, ShaderNodeTree("Shader Nodetree")&gt;
--- &lt;bpy_struct, ShaderNodeTree("NodeGroup")&gt;


My simple attempt at declaring a NodeCustomGroup has some superficial success. 
My question is how / where can I set the space.path so there's something to .pop(), -- somewhere in the init of the custom node?

excerpt full code here:

class SvGroupNodeExp(bpy.types.NodeCustomGroup, SverchCustomTreeNode):
    bl_idname = 'SvGroupNodeExp'
    bl_label = 'Group Exp'
    bl_icon = 'OUTLINER_OB_EMPTY'

    group_name = StringProperty()

    def init(self, context):

        self.node_tree = bpy.data.node_groups.new('nooobgroup', 'SverchCustomTreeType')
        self.group_name = self.node_tree.name
        # self.node_tree.parent = self
        # space = context.space_data
        nodes = self.node_tree.nodes

        inputnode = nodes.new('SvGroupInputsNode')
        outputnode = nodes.new('SvGroupOutputsNode')
        inputnode.location = (-300, 0)
        outputnode.location = (300, 0)
I'm not sure how useful this is to people (see a sverchok branch which implements this). I'll provide this as answer to my question, because that's what it does -- whether or not this allows for a functional custom node_tree group implementation is still up in the air.



It seems the way to get the node.tree_path_parent to poll True is to repopulate the context.space_data.path with the parent tree at index 0 and the new group node (a tree under the hood) at index 1.

def group_make(self, new_group_name):
    self.node_tree = bpy.data.node_groups.new(new_group_name, 'SverchCustomTreeType')
    self.group_name = self.node_tree.name

    nodes = self.node_tree.nodes
    inputnode = nodes.new('SvGroupInputsNode')
    outputnode = nodes.new('SvGroupOutputsNode')
    inputnode.location = (-300, 0)
    outputnode.location = (300, 0)
    return self.node_tree

class SvGroupEdit(bpy.types.Operator):
    bl_idname = "node.sv_group_edit"
    bl_label = "edits an sv group"

    group_name = StringProperty()

    def execute(self, context):
        node = context.node
        ng = bpy.data.node_groups

        group_node = ng.get(self.group_name)
        if not group_node:
            group_node = group_make(node, new_group_name=self.group_name)

        bpy.ops.node.sv_switch_layout(layout_name=self.group_name)
        # context.space_data.node_tree = ng[self.group_name]  # does the same

        # by switching, space_data is now different
        parent_tree_name = node.id_data.name
        path = context.space_data.path
        path.clear()
        path.append(ng[parent_tree_name]) # below the green opacity layer
        path.append(ng[self.group_name])  # top level

        return {"FINISHED"}


However, when hitting the back button (tree_path_parent) the active node_tree isn't set. Why? I suspect it's due to using .clear() instead of .pop() and some loss of information. This means we need to roll our own version of tree_path_parent, to switch the node_tree and then set the context.space_data.node_tree to the desired parent tree.

Something like:

class SvTreePathParent(bpy.types.Operator):
    '''Go to parent node tree'''
    bl_idname = "node.sv_tree_path_parent"
    bl_label = "Parent Sv Node Tree"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        space = context.space_data
        return space.type == 'NODE_EDITOR' and len(space.path) &gt; 1

    def execute(self, context):
        space = context.space_data
        space.path.pop()
        context.space_data.node_tree = space.path[0].node_tree
        return {'FINISHED'}


Bottom left in the screenshot i prepended the operator button for node.sv_tree_path_parent.