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()
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.
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:
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']
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?