0
$\begingroup$

I'm trying to run this command, I crash after print 1, which I guess has something to do with setting another context but no idea how to bite it to get it to work... Any hints?

        print("Update graph")
        bpy.context.evaluated_depsgraph_get()
        for window in bpy.context.window_manager.windows:
            screen = window.screen
            for area in screen.areas:
                if area.type == 'VIEW_3D':
                    #set context to 3dview
                    cont = bpy.context.copy()
                    cont['area'] = area
                    cont['region'] = area.regions[-1]
                    bpy.ops.view3d.view_selected(cont)
                    break

        if len(objects) > 0 and cont is not None:
            # Deselect all
            for obj in objects:
                if obj.type == 'MESH':
                    obj.select_set(state=False)

            #Select 1 by 1, and apply the uv system.
            for obj in objects:
                if obj.type == "MESH":
                    obj.select_set(state=True)
                    print("1",cont)
                    bpy.ops.object.editmode_toggle(cont)
                    print("2",cont)
                    bpy.ops.mesh.select_all(action='SELECT')
                    print("3",cont)
                    bpy.ops.uv.smart_project(cont)
                    print("4",cont)
                    bpy.ops.object.editmode_toggle(cont)
                    obj.select_set(state=False)

TIA

I have missed some explanations.

This function is called by a persistent handler

@persistent
def load_handler(dummy):
    bpy.app.timers.register(actionQueue.runInternalFastTimer)

def register()
      bpy.app.handlers.load_post.append(load_handler)

Its done this way as I'm sending command to it from a threadX that is not blender thread. So the idea is to push job function ptr to a queue that then gets called/executed by blender in its own correct thread. However at that stage I have wrong context and I get this error >

RuntimeError: Operator bpy.ops.object.editmode_toggle.poll() failed, context is incorrect

EDIT A more comprehensive example of the issue can be found here (second post) > https://devtalk.blender.org/t/creating-a-valid-context-for-uv-editing/15670

$\endgroup$
8
  • $\begingroup$ What is in the error log? Code is not full. What is objects? If this is bpy.data.objects and some objects are not in the context viewlayer, select_set will raise Error. cont is defined only in if statement, so if there's no 'VIEW_3D' area Error is also will be raised. $\endgroup$ Sep 28, 2020 at 12:56
  • 1
    $\begingroup$ Hey, apology objects its bpy.context.view_layer.objects.selected, The function gets called by a bpy.app.timers.register(actionQueue.runInternalFastTimer) Which gets send there from another thread. Esentially I'm pushing a job from threadX to blender thread via timers. When the timmer run the function it has wrong context. $\endgroup$
    – Dariusz
    Sep 28, 2020 at 20:08
  • 1
    $\begingroup$ @AndreySokolov I've updated original question with more info. I'm sorry for lack of it from the start. $\endgroup$
    – Dariusz
    Sep 28, 2020 at 20:11
  • $\begingroup$ This is why it is generally recommended to avoid using bpy.ops as far as this is possible: Blender operators are very context-dependent, and it's pretty hard here to find out what is the exact problem with the context for bpy.ops.object.editmode_toggle(). I'd suggest trying to write the full context override instead of bpy.context.copy(), including exact "window", "screen", "area", "region" and "scene". But the problem also may be anywhere else: current mode, no active object, hidden objects... really too many cases to guess. $\endgroup$ Sep 28, 2020 at 21:42
  • $\begingroup$ @AndreySokolov yes I try to avoid them. But I'm not sure how else can I perform this action. I just want to batch apply UV mapping to all selected objects. Any ideas? I tried doing full copy, but that seem to not work either :- ( $\endgroup$
    – Dariusz
    Sep 29, 2020 at 11:18

1 Answer 1

1
$\begingroup$

Running this script from the cli, I can unwrap an object in the background (no gui window).

I think the key point is setting the active object not just selecting it. I also create a uvmap layer if one doesn't exist and use mode_set rather that editmode_toggle.

import bpy

# Deselect all
bpy.ops.object.select_all(action='DESELECT')

for obj in bpy.context.scene.objects:
    if obj.type == 'MESH':
        obj.select_set(state=True)
        bpy.context.view_layer.objects.active = obj
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.mesh.select_all(action='SELECT')
        if len(obj.data.uv_layers) == 0:
            obj.data.uv_layers.new()
        bpy.ops.uv.smart_project()
        bpy.ops.object.mode_set(mode='OBJECT')
        bpy.ops.wm.save_mainfile()

I saved it as uvproject.py and used the cli command

blender -b test.blend -P uvproject.py
$\endgroup$
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .