Context is incorrect after new scene created

I’d like to make my button create a new scene and add a node in the compositor (in that new scene).

So far I could only achieve this by creating 2 buttons:

  • one to create a new scene
  • the second to add the node

because if I join the operations in a single button like this:

bpy.ops.scene.new(type='EMPTY')` 
bpy.ops.node.add_node(type="CompositorNodeTranslate", use_transform=False)

I get a “context is incorrect” error.
I guess Blender is trying to add the node in the previous scene?

How can I fix this?

(in case you’re wondering, the button is located in the Compositor’s “N” panel)

If you are trying to execute this command from the python console, the script editor or any other area than the compositor, it will fail. bpy.ops is context sensitive and a command like bpy.ops.node.add_node expect to be launched from a node editor context (panel, toolbar etc).

In my opinion, you should always avoid using bpy.ops when this is possible to be able to execute script from any area (and even in background mode).
Once your scene is created, you can execute something like this:

scene = bpy.context.scene
scene.use_nodes = True
node_tree = scene.node_tree
node_tree.nodes.new('CompositorNodeTranslate')

I’m not executing this from the console.
I’m doing this from the button which is in the side panel of the compositor.
As I said, it only works if I use 2 buttons instead of one.
I’m only looking for a way to make it work with a single button.

Are you sure you execute it from the node editor panel? I don’t think because it should work since this is the right context to call bpy.ops.node.add_node. Maybe you place the button in the properties editor, which is also on the side of the compositor but is a different context.
If you want to use it from another area, like I said, this is not a problem, look into the script I’ve posted and use it instead of bpy.ops.node.add_node.

Send your whole panel script if you want more help about the context error.

I totally understand why you wonder if I’m really clear about the interface but don’t worry, I know Blender enough to know what each area is (been using Blender for 7 years), and I guarantee you that both my buttons are in the compositor’s “N” panel.
Once again, the operator does work if the consecutive steps are separated in 2 buttons, it does not work if all steps are contained in one.
It’s really to do with the fact that the “single button” version first adds a new scene and then immediately tries to add a node in the “context” scene, and my assumption (which might be wrong) is that it assumes the context scene is still the scene I was in before creating the new one, and for some reason it doesn’t like it.

I’ll do further research and give you a narrowed down version of my code when I get back home.
Thank you for your help so far.

I don’t know what could happens with context on your side (maybe someone else has an idea?), but I suggest you to use bpy.data and bpy.scene to access and create data instead of bpy.ops.

Here is an example using one button to create a new scene, switch to it and create a node in the compositor. It does not depend on a context (except to switch to the current scene of course) and should avoid issue you have but doing the same thing.
Using bpy.data is way more convenient because it return objects you can work with directly and does not depend on your active selection, object names, etc.

import bpy

def create_scene_and_add_node():
    scene = bpy.data.scenes.new(name='new scene')
    scene.use_nodes = True
    node_tree = scene.node_tree
    node_tree.nodes.new('CompositorNodeTranslate')
    return scene


class ButtonOperator(bpy.types.Operator):
    bl_idname = 'wm.add_scene_node'
    bl_label = 'Create scene and node'
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        scene = create_scene_and_add_node()
        context.window.scene = scene
        return {'FINISHED'}


class ButtonPanel(bpy.types.Panel):
    bl_idname = 'CUSTOM_PT_ButtonPanel'
    bl_label = 'Button'
    bl_space_type = 'NODE_EDITOR'
    bl_region_type = 'UI'
    bl_category = 'Button custom'

    def draw(self, context):
        scene = context.scene
        layout = self.layout
        layout.operator('wm.add_scene_node')


def register():
    bpy.utils.register_class(ButtonOperator)
    bpy.utils.register_class(ButtonPanel)


def unregister():
    bpy.utils.unregister_class(ButtonOperator)
    bpy.utils.unregister_class(ButtonPanel)


if __name__ == '__main__':
    register()
1 Like

ok I’m trying to use this technique. However, I’d like to also add an existing node group and using the name of the group doesn’t work.
I’m not sure it’s even possible to do that with the node_tree.nodes.new command.

nvm, found it, I have to do it in 2 commands:

scene.node_tree.nodes.new('CompositorNodeGroup')
scene.node_tree.nodes["Group"].node_tree = bpy.data.node_groups['myGroupName']

Looks like the problem is solved, thank you!

Actually, some operators seem cumbersome to translate to data operations.
For example grouping the selected nodes. The operator will automatically create all the links, inputs and outputs.
To my understanding, if I were to do this with scene data, I would have to script moving the nodes in the group, adding the input/output sockets and making the links, which is Quite inefficient in comparison.

Apparently I’m not the first one to run into a similar issue but @lewis2e didn’t get a response:

Indeed, like that one :wink:

bpy.ops.mesh.primitive_monkey_add(size=2, enter_editmode=False, location=(0, 0, 0))

Be careful with this script: it could lead to some bugs because if there is already a group in the nodetree which is also named Group, the group you have created will be Group.001 and your second line will assign the wrong one.
Don’t forget that the data api returns object and you can work with:

group = scene.node_tree.nodes.new('CompositorNodeGroup')
group.node_tree = bpy.data.node_groups['myGroupName']

Thanks for the advice.

very funny ◓ ◟_◞ ◓

But for real, what I meant was that my original question is still open. Is there a way to circumvent this incorrect context issue while using an operator?

I wonder if there would not be a bug with the node editor context. I’ve tested using context in another way and the issue remains on the node editor only.

This script is working with no issue:

for area in context.screen.areas:
    if area.type == 'SEQUENCE_EDITOR':
        for region in area.regions:
            if region.type == 'WINDOW' or region.type == 'PREVIEW':
                ctx = context.copy()
                ctx['area'] = area
                ctx['region'] = region
                bpy.ops.sequencer.view_all_preview(ctx)
    if area.type == 'TIMELINE':
        for region in area.regions:
            if region.type == 'WINDOW':
                ctx = context.copy()
                ctx['area'] = area
                ctx['region'] = region
                bpy.ops.time.view_all(ctx)

But when using it for the node editor, it fails.

for area in context.screen.areas:
    if area.type == 'NODE_EDITOR':
        for region in area.regions:
            if region.type == 'WINDOW':
                ctx = context.copy()
                ctx['area'] = area
                ctx['region'] = region
                bpy.ops.node.view_all(ctx)

I can make a bug report but I’m not even sure this is a bug. Does someone have an idea of why node editor context have such problem?

Works fine here.