How to call from python function that require View3D context

Scripting in Blender with Python, and working on the API

Moderators: jesterKing, stiv

Post Reply
dvochin
Posts: 46
Joined: Mon Aug 20, 2012 9:39 pm

How to call from python function that require View3D context

Post by dvochin » Mon Jul 22, 2013 7:31 pm

Hi all,

I need to call the bpy.ops.mesh.knife_project() function from within python code.

My code works perfectly if I create a GUI button (similar to technique at http://en.wikibooks.org/wiki/Blender_3D ... able_Addon) and click on the GUI button that appears in the toolshelf.

Unfortunately, if I attempt to launch the same code in the same mesh edit mode from python the call to knife_project will fail with an error stating that the context is incorrect. Looking at the C code for this function, this particular call needs to be made from a View3D.

I had hoped that wrapping that call within a GUI function that services GUI buttons would call knife_project() from the View3D context but it does not.

Is it possible for python call to call functions from the context of View3D?

Many thanks!!

Dan,

dvochin
Posts: 46
Joined: Mon Aug 20, 2012 9:39 pm

Post by dvochin » Mon Jul 22, 2013 7:57 pm


dvochin
Posts: 46
Joined: Mon Aug 20, 2012 9:39 pm

Post by dvochin » Wed Jul 24, 2013 1:58 am

Well after a grueling couple of days absorbing stuff I really didn't want I figured it out!

To call bpy.ops operators that require to be run from the 'VIEW_3D' space (i.e. most of the visual stuff like bpy.ops.mesh.knife_project(), obtain an override context like the code below and you should be good to go! :)

Code: Select all

def AssembleOverrideContextForView3dOps():
    #=== Iterates through the blender GUI's windows, screens, areas, regions to find the View3D space and its associated window.  Populate an 'oContextOverride context' that can be used with bpy.ops that require to be used from within a View3D (like most addon code that runs of View3D panels)
    # Tip: If your operator fails the log will show an "PyContext: 'xyz' not found".  To fix stuff 'xyz' into the override context and try again!
    for oWindow in bpy.context.window_manager.windows:          ###IMPROVE: Find way to avoid doing four levels of traversals at every request!!
        oScreen = oWindow.screen
        for oArea in oScreen.areas:
            if oArea.type == 'VIEW_3D':                         ###LEARN: Frequently, bpy.ops operators are called from View3d's toolbox or property panel.  By finding that window/screen/area we can fool operators in thinking they were called from the View3D!
                for oRegion in oArea.regions:
                    if oRegion.type == 'WINDOW':                ###LEARN: View3D has several 'windows' like 'HEADER' and 'WINDOW'.  Most bpy.ops require 'WINDOW'
                        #=== Now that we've (finally!) found the damn View3D stuff all that into a dictionary bpy.ops operators can accept to specify their context.  I stuffed extra info in there like selected objects, active objects, etc as most operators require them.  (If anything is missing operator will fail and log a 'PyContext: error on the log with what is missing in context override) ===
                        oContextOverride = {'window': oWindow, 'screen': oScreen, 'area': oArea, 'region': oRegion, 'scene': bpy.context.scene, 'edit_object': bpy.context.edit_object, 'active_object': bpy.context.active_object, 'selected_objects': bpy.context.selected_objects}   # Stuff the override context with very common requests by operators.  MORE COULD BE NEEDED!
                        print("-AssembleOverrideContextForView3dOps() created override context: ", oContextOverride)
                        return oContextOverride
    raise Exception("ERROR: AssembleOverrideContextForView3dOps() could not find a VIEW_3D with WINDOW region to create override context to enable View3D operators.  Operator cannot function.")

def TestView3dOperatorFromPythonScript():       # Run this from a python script and operators that would normally fail because they were not called from a View3D context will work!
    oContextOverride = AssembleOverrideContextForView3dOps()    # Get an override context suitable for bpy.ops operators that require View3D
    bpy.ops.mesh.knife_project(oContextOverride)                # An operator like this normally requires to run off the View3D context.  By overriding it with what it needs it will run from any context (like Python script, Python shell, etc)
    #bpy.ops.screen.screen_full_area(oContextOverride)
    print("TestView3dOperatorFromPythonScript() completed succesfully.")


dvochin
Posts: 46
Joined: Mon Aug 20, 2012 9:39 pm

Post by dvochin » Wed Jul 24, 2013 2:34 am

Note that additional info & discussion on this issue can be found at http://www.blender.org/forum/viewtopic. ... 787#105787

rabbi_joe
Posts: 2
Joined: Thu Aug 08, 2013 2:25 pm

Post by rabbi_joe » Thu Aug 08, 2013 2:40 pm

hi dvochin,

i used your code with
bpy.ops.transform.create_orientation(oContextOverride, name="CTO", use=True, overwrite=True)
because "use=True" normaly works only in 3dView.
And it worked.

But now i want to transform my Objekt with "Align to Transform Orientation". I tried to do this:
bpy.ops.transform.transform(mode = 'ALIGN')

It says: FINISHED, but in fact nothing happened.

can you, or somebody help me please.

P.S. what i originaly wanted to do is to transform the lokal orientation in the CTO

Post Reply

Who is online

Users browsing this forum: Yahoo [Bot] and 1 guest