Quick way to force context area in test script

Is there a quick way to force a script to run in a specific area while pushing the “Run script” button, without having to put the following and do an F3 > “operator name”?

class SimpleOperator(bpy.types.Operator):
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"

    def execute(self, context):
        do this
        do that
        return {'FINISHED'}

def register():
    bpy.utils.register_class(SimpleOperator)

def unregister():
    bpy.utils.unregister_class(SimpleOperator)


if __name__ == "__main__":
    register()

For example, could I just loop through the areas in the current screen and when its type matches the one I’m looking for (e.g. 'VIEW3D'), run the script in that area instead of the text editor?

for a in bpy.context.screen.areas:
    if a.type=='VIEW_3D':
        myViewport = some area property
        break

[something to run the following in myViewport]:
    my code

or something different but as short as possible.

More or less, yes, you should be able to – IFF the operator has been coded correctly.

It’s explained in some detail here: https://docs.blender.org/api/blender2.8/bpy.ops.html in the “Execution Context” section.

For example, here I loop over every single VIEW3D across my workspace tabs and execute one of my operators against it:

    for screen in bpy.data.screens:
        for area in (a for a in screen.areas if a.type == 'VIEW_3D'):
            region = next((region for region in area.regions if region.type == 'WINDOW'), None)
            if region is not None:
                override = {'area': area, 'region': region}  # !!the first important bit!!
                bpy.ops.dconfig.viewport_defaults(override)

As for the actual operator – It MUST be coded to use the proper context. This context is passed into your execute method already etc. There are many operators that are coded incorrectly and rather than using the passed in context variable, they instead use bpy.context , which may not be correct:

class DCONFIG_OT_viewport_defaults(bpy.types.Operator):
    bl_idname = "dconfig.viewport_defaults"
    bl_label = "DC Viewport Defaults"
    bl_description = "Set common viewport parameters"
    bl_options = {'REGISTER'}

    def execute(self, context):
        dc.trace_enter(self)

        # Use the passed in context, not bpy.context in your operators folks!
        context.space_data.show_region_tool_header = False

        context.space_data.clip_end = 100
        context.space_data.clip_start = 0.02

        # etc. etc. etc.

Thanks. My goal is mostly to make test code less cluttered and quicker to set up and run. If I understand your reply correctly, I can’t avoid using all the code to generate and register a class and overriding the context would actually require more code compared to leaving it to be run with F3 while the cursor is in the proper area. Nonetheless your answer is quite informative.

Hey I’m using the following utility context manager to run test code in other contexts:

import bpy
from contextlib import contextmanager

@contextmanager
def context(area_type: str):
    area = bpy.context.area
    former_area_type = area.type
    area.type = area_type
    try:
        yield area
    finally:
        area.type = former_area_type

And then to use:

with context('NLA_EDITOR'):
    print(bpy.context.selected_nla_strips)
3 Likes

This is handy ! Thank you for sharing.