Execute script WITH GUI 'Context' object has no attribute 'active_object' I'm trying to create some automated test that will launch blender open a specific file and call an operator from an addon.

The operator is using bpy.context.active_object and it works perfectly when calling this operator from blender window. 

The test are launched with GUI to respect the user environement as much as possible. Unfortunately this is not enough, i got the error:


  'Context' object has no attribute 'active_object'


This problem doesn't occur if I don't open a file before calling the operator in the script. 

If I call the operator manually (in the exact same blender instance opened automatically for the test) everythings works fine.

What can I do to call this operator from an automated script without making any modification to the initial addon? 

A generic solution would be usefull since I have a lot of operator to test and most of them are using bpy.context.active_object or bpy.context.selected_object

Here is a minimal example: (Tested on Blender 2.73)

The addon: (CANNOT BE CHANGED)

bl_info = {
    "name": "test addon",
    "description": "test addon",
    "author": "Pyros",
    "version": (1, 0, 0),
    "blender": (2, 73, 0),
    "location": "3D View",
    "warning": "development",
    "category": "3D View"
}
import bpy

class OBJECT_OT_addon_operator_to_test(bpy.types.Operator):
    bl_idname =  "mesh.operator_to_test"
    bl_label = bl_description = "Operator to test"
    bl_options = {'REGISTER', 'UNDO'}
    def execute(self, context):
        ob = bpy.context.active_object
        print(ob.name)#do stuff with object
        return {'FINISHED'}   
def register():
    bpy.utils.register_module(__name__)
def unregister():
    bpy.utils.unregister_module(__name__)


The script:

import os
import sys
import bpy

base = sys.argv.index("--")
blendFile = sys.argv[base+1]
bpy.ops.wm.open_mainfile(filepath=blendFile)#without this line everything looks to work fine
bpy.ops.mesh.operator_to_test()
exit()


And a little python file to launch the test 

import os
testfolder = os.path.split(os.path.realpath(__file__))[0]
scriptPath = testfolder+"\\script.py"
blendFile = testfolder+"\\base.blend"
os.system("blender -P \""+scriptPath+"\" -- \""+blendFile+"\"")


EDIT:
A solution would be to launch blender with a file to open instead of opening it in the script:

os.system("blender \""+blendFile+"\" -P \""+scriptPath)


This solution would be acceptable but I'd prefer to open the file in the script to have more control. More than that I want to understand why this errors occurs.
When calling blender from the CLI or script with arguments, it will "perform" each argument in the order it is presented, this can be important with many tasks.

What that means, is that blender -P script.py file.blend will run the given script and then open the blend file, while blender file.blend -P script.py will open the blend file and then run the script. In the second example you don't need to run bpy.ops.wm.open_mainfile and won't have the issue you are trying to solve.

That also means, your addon test example can be reduced to a single line and passed to blender without using a script.

blender file.blend --python-expr 'import bpy; bpy.ops.mesh.operator_to_test()'


Rather than combining a string to pass to os.system() I would suggest using subprocess.call() which uses a list for the arguments, preventing the need to quote and escape... effectively the list becomes sys.argv

As you are doing an automated addon test, consider using --factory-startup and --addon to control what addons are enabled. You could do one run with your normal startup file and another with factory and your addon or simply ensure your addon is enabled without having to change your startup file.

To test an addon with multiple files -

from glob import glob
from subprocess import call

for blendFile in glob('*.blend'):
    arglist = [
    'blender',
    '--factory-startup',
    '--addons',
    'addon_test',
    blendFile,
    '--python-expr',
    'import bpy; bpy.ops.mesh.operator_to_test()'
    ]
    call(arglist)


Or you can loop through multiple addons and test one at a time -

from subprocess import call

for addon in ['addon_test1', 'addon_test2']:
    arglist = [
    'blender',
    '--factory-startup',
    '--addons',
    addon,
    'test.blend',
    '--python',
    addon + '_test.py'
    ]
    call(arglist)