API change - simple script help

Hey guys,

like many others the API changes have broken my scripts

I have a simple script that I used to display a UI for a character
(based on the Sintel rig)

It has a few features like:
1.bone layers visibility
2.it displays certain properties with sliders
3.and there is a few buttons to turn parts of the mesh off

I have managed to update 1 and 2 but I can’t figure out the 3 bit.

The button should invoke an operator that turns the modifier on/off in the viewport
I have tested the code in the console and it works so it is obviously something wrong with the way I am trying to invoke it

I get a error:

AttributeError: ‘NoneType’ object has no attribute ‘data’
RNA_struct_free ‘vsb_Body’ freed while holding a python reference

here is the script


import bpy
import re

class DougieProperties(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Rig Properties"

    @classmethod
    def poll(self, context):
        try:
           ob = context.active_object
           return (ob.name == "Dougie_Rig")
        except AttributeError:
           return 0

    def draw(self, context):
        pose_bones = context.active_object.pose.bones

        layout = self.layout        
        col = layout.column()

        col.label(text="Body:")
        #Body Rotation
        col.prop(pose_bones["Body"],'rotation_euler', index=0,text="Rot X", slider=False)
        col.prop(pose_bones["Body"],'rotation_euler', index=1,text="Rot Y", slider=False)
        col.prop(pose_bones["Body"],'rotation_euler', index=2,text="Rot Z", slider=False)
        # Body Squash
        col.prop(pose_bones["Body"],'scale', index=0,text="Body Squash", slider=False)
        col.label(text="Tail:")
        # Tail Rotaion
        col.prop(pose_bones["Tail.1"], '["rot"]', text="Tail Hinge", slider=True)
        # Tail Stretch
        col.prop(pose_bones["Tail.1"],'scale', index=1,text="Tail Stretch", slider=False)
        # Tail Auto IK
        col.prop(pose_bones["Tail.5"].constraints["AutoIK"], 'mute',text="Auto IK Tail")


class DougieLayers(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Rig Layers"

    @classmethod
    def poll(self, context):
        try:
           ob = context.active_object
           return (ob.name == "Dougie_Rig")
        except AttributeError:
           return 0

    def draw(self, context):
        layout = self.layout
        col = layout.column()

        # Layers
        root = col.row()
        root.label(text="Root:")
        root.prop(context.active_object.data, "layers", index=16, toggle=True, text="Root")
        body = col.row()
        body.label(text="Body:")
        body.prop(context.active_object.data, "layers", index=0, toggle=True, text="Body")

        tail = col.row()
        tail.label(text="Tail:")
        tail.prop(context.active_object.data, "layers", index=2, toggle=True, text="Tail")

        squash = col.row()
        squash.label(text="Squash:")
        squash.prop(context.active_object.data, "layers", index=1, toggle=True, text="Squash")

       
        
        
class DougieVisib(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Visibility"

    @classmethod
    def poll(self, context):
        try:
           ob = context.active_object
           return (ob.name == "Dougie_Rig")
        except AttributeError:
           return 0

    def draw(self, context):
        layout = self.layout
        col = layout.column()
        row = col.row(align=True)
        
        row.operator("vsb_Body", text="Body")
        row.operator("vsb_Tail", text="Tail")        


def is_selected(context, names):
    try:
        for name in names:
            if context.active_pose_bone.name == name:
                return True
        for bone in context.selected_pose_bones:
            for name in names:
                if bone.name == name:
                    return True
    except AttributeError:
        pass
    return False



class OBJECT_OT_Visib_Body(bpy.types.Operator):
    bl_label = "Body"
    bl_idname = "vsb_Body"

    def invoke(self, context, event):
        for mesh in ['Dougie']:
            bpy.data.objects['Dougie'].modifiers['BodyVIS'].show_viewport = not(bpy.data.objects['Dougie'].modifiers['BodyVIS'].show_viewport)
        return{'FINISHED'}

class OBJECT_OT_Visib_Tail(bpy.types.Operator):
    bl_label = "Tail"
    bl_idname = "vsb_Tail"

    def invoke(self, context, event):
        for mesh in ['Dougie']:
            bpy.data.objects['Dougie'].modifiers['TailVIS'].show_viewport = not(bpy.data.objects['Dougie'].modifiers['TailVIS'].show_viewport)
        return{'FINISHED'}



#bpy.types.register(OBJECT_OT_Visib_Body)
#bpy.types.register(OBJECT_OT_Visib_Tail)
#bpy.types.register(DougieLayers)
#bpy.types.register(DougieVisib)
#bpy.types.register(DougieProperties)


anybody know what I’m doing wrong?

if you need the blend let me know

cheers

for mesh in ['Dougie']:

looks suspicious…

Hi Uncle

Yes that is the exact bit that I am having trouble with
‘Dougie’ is the name of the mesh

here is an example of the same thing that works in 2.53
(only ‘ManCandy’ is the name of the mesh here and the .realtime is different now)


class OBJECT_OT_Visib_Head(bpy.types.Operator):
    bl_label = "Head"
    bl_idname = "vsb_Head"

    def invoke(self, context, event):
        for mesh in ['ManCandy']:
           bpy.data.objects[mesh].modifiers['HeadVIS'].realtime = not(bpy.data.objects[mesh].modifiers['HeadVIS'].realtime)
        return{'FINISHED'}

and then it would be registered at the end of the script

do you know how to replicate this with the new API?

Hi Wayne,

It has a few features like:
1.bone layers visibility
2.it displays certain properties with sliders
3.and there is a few buttons to turn parts of the mesh off

I have managed to update 1 and 2 but I can’t figure out the 3 bit.

Sorry I can’t help you to figure out the 3 bit.
How did you do de update 1 and 2 ? we only have to add the line ‘@classmethod’ ?

Thanks.

1 - yep just add @classmethod before the poll
(and they also self register now - so you can remove the bottom register statement)

2- and the “layer” property is now called “layers”

3 - and if you are not doing any mesh visibility you should be good to go as this won’t effect your script

1- can we test this on doogie rig
and where can we get it ?

also can you descibe the Poll function what does it do and when is it executed?

2 -

i ran another script and got an error on link?

anyidea if there was any cahnges for this link command?

3 - The hold vars thing

i saw that several times as error in 2.53
looks like blender is holding a variable
this seems to happen when you try to re execute a script in text editor

the only way i found was to re load teh file and then execute it
and it would work again

strange error ?

4- and do you know if tehre are other variables that have change name of change to other command in 2.54?

happy 2.54

1- I will link the rig very shortly - I’m just having a few FTP issues (and we can’t attach in this forum) - but you can get the 2.53 version from the link in my signature then replace the dougie.py text with the version above for now
the UI will display in the side panel but the Visibility buttons don’t work (Head/Tail)

poll is a way of checking if an object is active
in plain english - “is this object select?- if yes - display this”
and that is all I know about it

2 - don’t know the link command

3- I’m not sure what causes this error but I think it is saying that that operator was freed because at the end of the script it didn’t do anything (because the code is wrong)

  1. a Lot of the things have changed names - if there is something you need to check I usually have been right clicking > Copy data path > then paste it to the text editor and see what it called now

example - to turn off a constraint it was “enable” but now it is “mute”

ok here’s the link to the file with the updated script
(everything works except the visibility buttons)

http://www.waynedixon.com.au/Dougie/Dougie.2.5.4.WIP.blend

i don’t understand what you mean by copy paste path ?

and do you paste this in text editor or the python console
then return to see if it’s ok or not ?

and is there any list somewhere to show which names have changed?

i know another trick for buttons in panel ect…
it may work but not all the time i think
put the cursor over the button and the tool tip should show the correct python call for it!

for this poll thing
is this only available in panel class

or can you define this for any other method too?
like if you make your own method can you add a poll to it may be !

Thanks and happy 2.5

ignore that - just download the complete file

you can test a line of code in the console by typing it in - if it works you know that line is correct
by that, I mean the line of code that switches the modifier on/off is working, it’s the way the script doesn’t invoke this code that is broken

I do know that trick but it sometimes doesn’t give you the exact name
but it does come in handy for some things

ahh - just found that if you open the file fresh it all works

but if you run the script while it is open - it breaks and the buttons no longer work

weird

it’s one of the thing i said before

sometimes when re running script it will hang on some var and cannot redefine it
and not certain if this is not really a bug ?

only way is to re load the file and then run it !

sent it as a bug may be it can be fixed!

salutations

Something like this maybe;


class DougieVisib(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Visibility"
    bl_idname = "Dougie_PT_visibility"

    @classmethod
    def poll(cls, context):
        if context.mode != 'POSE':
            return False
        try:
            return (bpy.context.active_object.name == "Dougie_Rig")
        except (AttributeError, KeyError, TypeError):
            return False

    def draw(self, context):
        layout = self.layout
        col = layout.column()

        body = col.row()
        body.label(text="Body:")
        body.prop(context.active_object.modifiers['BodyVIS'], "show_viewport", toggle=True, text="Show Body")

        tail = col.row()
        tail.label(text="Tail:")
        tail.prop(context.active_object.modifiers['TailVIS'], "show_viewport", toggle=True, text="Show Tail")

The ‘context.active_object.modifiers[ ]’ bit might not work straight out of the box though.

–edit–
context.active_object probably needs to be bpy.data.objects[‘Dougie’]

I just read in the Python docs that the @classmethod is irrelevant and not needed.

What is it supposed to do?

@Atom: I don’t know exactly - but there are at least 2 methods I know of ‘staticmethod’ and ‘classmethod’
when to use what - I have no idea

I do know that it is now needed as this was added to the API about a month ago

@Uncle - I having a bit of trouble trying to edit your code
at present the visibility is an operator not a property - and I have been unsuccessful in trying to get an operator to act like a toggle button (so it looks just like a normal button)

but the first part of the script tells it to put the operator “button” in the side panel
then the actual operator is down further

PS - the linked file won’t work at the moment because my rigs were featured on Blender nation and my site has now exceeded the bandwidth, so if anyone need the dougie file PM me and I will email it

If you replace context.active_object with bpy.data.objects[‘Dougie’] it should Just Work™. I tested it on one of my models (using subsurf.show_viewport) and it did what you’d expect.

Well, assuming your goal is to simply toggle on and off the ‘show_viewport’ parameter in the modifiers.

No clue how to do this with an operator but you really don’t need to.

yeah I would prefer not to have to do it with an operator
a toggle is better because you can instantly see if it’s on or off

I’m still struggling to get the code working

I have stripped back the rest of the script to focus on just this bit
here is the code


import bpy
import re

class DougieVisib(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Visibility"
    bl_idname = "Dougie_PT_visibility"

    @classmethod
    def poll(cls, context):
        try:
           ob = context.active_object
           return (ob.name == "Dougie_Rig")
        except AttributeError:
           return 0

    def draw(self, context):
        layout = self.layout
        col = layout.column()

        body = col.row()
        body.label(text="Body:")
        body.prop(bpy.data.objects['Dougie'].modifiers['BodyVIS'], "show_viewport", toggle=True ,text="Body")




it shows the label but not the button (usually means there is something wrong with the next line)
If I test the code in the console it works

Just tested this;


import bpy
import re

class DougieVisib(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Visibility"
    bl_idname = "Dougie_PT_visibility"

    @classmethod
    def poll(cls, context):
        try:
           ob = context.active_object
           return (ob.name == "Cube")
        except AttributeError:
           return 0

    def draw(self, context):
        layout = self.layout
        col = layout.column()

        body = col.row()
        body.label(text="Subsurf:")
        body.prop(bpy.data.objects['Cube'].modifiers['Subsurf'], "show_viewport", toggle=True ,text="Subsurf")

Just add subsurf to the default cube to try it.

bpy.data.objects[‘Dougie’].modifiers[‘BodyVIS’].show_viewport = False <-- that works for you from the console?

hey Uncle,

I tried this and it is not working

but yes both of these lines work in the console


bpy.data.objects['Dougie'].modifiers['BodyVIS'].show_viewport = False 

and


bpy.data.objects['Cube'].modifiers['Subsurf'].show_viewport" =True

but the script only displays the label and not the button

does this really work for you?
if it is working for you perhaps this is a bug
I’m running the Mac version
(tried both SVN and official 2.54)

Yep, works just fine;
http://www.********.org/pic/show.php?id=5822

There aren’t any errors in the console when you try to run it?

–edit–

Oops, forgot about the paste all prohibition…

–edit 2–

Had someone test on the IRC and apparently this is a bug.