3
$\begingroup$

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?

$\endgroup$
  • $\begingroup$ Are you running this script from the command line? $\endgroup$ – TLousky Nov 8 '15 at 7:32
  • 1
    $\begingroup$ Your problem is that you are trying to access during register. wiki.blender.org/index.php/Extensions:2.6/Py/… when there is "restriced context". Run the code outside and it will be fine. $\endgroup$ – batFINGER Nov 8 '15 at 8:14
  • $\begingroup$ @ TLousky : no, I was trying to activate a 3-module script installed from zip. It installed fine, but wouldn't activate. $\endgroup$ – RobinsSea Nov 8 '15 at 10:07
  • 1
    $\begingroup$ Cool. @RobinsSea, since you found a solution to this issue, consider moving your update from question to an answer and accepting it. $\endgroup$ – TLousky Nov 8 '15 at 10:08
  • $\begingroup$ Sounds good - will do, TLousky. $\endgroup$ – RobinsSea Nov 8 '15 at 10:18
2
$\begingroup$

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.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.