Switching render engine in a script without using .context.scene All the suggestions on switching or setting a render engine that I have found here and elsewhere involve using bpy.context.scene.etc except for this one, which doesn't provide a solution to the problem that the API is now designed to throw an error if your script uses that approach.

For example, I have an __init__.py acting as a panel: it imports the script that actually does the work. The package (3 files: __init__.py, test_Shaders.py and figure_Def.py) installs fine. When I try to initialise this, Blender Python throws an error:


  Traceback (most recent call last):
    File "/home/robyn/blender276/2.76/scripts/modules/addon_utils.py", line 324, in enable
      mod = __import__(module_name)
    File "/home/robyn/.config/blender/2.76/scripts/addons/make_Shaders/__init__.py", line 42, in 
      from . import test_Shaders
    File "/home/robyn/.config/blender/2.76/scripts/addons/make_Shaders/test_Shaders.py", line 68, in 
      for scene in bpy.data.scenes:
  AttributeError: '_RestrictData' object has no attribute 'scenes'


The offending code looks like this - this is the __init__.py:

# GPL LICENCE BLOCK
bl_info = {
    "name": "Shaders-Poser Figures",
    "author": "Robyn Hahn",
    "version": (0, 3, 5),
    "blender": (2, 76, 0),
    "category": "Pynode"}

# allows the [F8] to reload changed scripts, seems that it's within this 'if' statement that the add-on activation fails
if "bpy" in locals():
    import imp
    imp.reload(test_Shaders)
    print("Reloaded test_Shaders.py")
else:
    from . import test_Shaders
    print("Imported test_Shaders.py")

import sys
import os
import bpy

class MatShaderPanel(bpy.types.Panel):
    """Create shaders for your Poser figure: Panel"""
    bl_label = "Figure Files Util"
    bl_idname = "MATERIALS_PT_shaders"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'

    def draw(self, context):
        layout = self.layout
        obj = context.object
        row = layout.row()
        row.label(text='Figure Name')
        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")
        row = layout.row()
        row.prop(context.scene, 'conf_path')
        row = layout.row()
        row.operator("object.run_script", text = 'Apply Shaders')

class runScript(bpy.types.Operator):
    """Runs the script"""
    bl_idname = "object.run_script"
    bl_label = "Invokes Shader Script"
    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        filename = 'test_Shaders.py'
        exec(compile(open(filename).read(), filename, 'exec'))
        return {'FINISHED'}

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.conf_path = bpy.props.StringProperty \
      (
      name = "Images Path",
      default = "",
      description = "Define the path to your images",
      subtype = 'DIR_PATH'
      )

def unregister():
    del bpy.types.Scene.conf_path
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()


and test_Shader.py:

import sys
import os
import bpy
tPath = os.path.dirname(__file__)
sys.path.append(tPath)
from figure_Defs import *
""" 
Will need to change this to not-hard-coded path.
"""
tPath = '/home/robyn/Documents/Blender/Projects/AllTextures/AllSkin/PS_Syri/'
sys.path.append(tPath)
from imageList import *

#print(tPath)

# sets renderer to Cycles - here's where the error happens
for scene in bpy.data.scenes:
    scene.render.engine = 'CYCLES'


Are there alternative methods to bpy.context.scene?
Update:

I was actually reading that very page you suggested while you were suggesting it, batFINGER - and thank you for validating my suspicions - and used the sample code they offered as a sort of template. Lo and behold: it loads. There is still a long way to go to make it a workable script, but I can see the validity of isolating context-specific behaviour and keeping it from the general code base that doesn't know what context it is going to wake up in (so to speak). So, for the curious:

import sys
import os
import bpy
from bpy.types import Operator
from bpy.props import IntProperty, StringProperty

class MatShaderPanel(bpy.types.Panel):
    """Create shaders for your Poser figure: Panel"""
    bl_label = "Figure Files Util"
    bl_idname = "MATERIALS_PT_shaders"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'

    def draw(self, context):
        layout = self.layout
        obj = context.object
        row = layout.row()
        row.label(text='Figure Name')
        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")
        row = layout.row()
        row.prop(context.scene, 'conf_path')
        row = layout.row()
        row.operator("object.run_script", text='Apply Shaders')

class runScript(bpy.types.Operator):
    """Will run script"""
    # was bl_idname = "object.run_script" - is now:
    bl_idname = "object.run_script"
    bl_label = "Invokes Shader Script"

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        filename = 'test_Shaders.py'
        exec(compile(open(filename).read(), filename, 'exec'))

        return {'FINISHED'}

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.conf_path = bpy.props.StringProperty( \
      name="Images Path",
      default="",
      description="Defines the path to your images",
      subtype='DIR_PATH')
    bpy.types.Scene.conf_figure = bpy.props.StringProperty( \
      name="Figure Type",
      default="",
      description="Defines the base mesh name of your figure")

def unregister():
    del bpy.types.Scene.conf_path
    del bpy.types.Scene.conf_figure
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()


Not finished yet, but at least I have this question sorted.