Can anyone help me understand why my setter works sometimes, then it will stop working, then start again? For example, I can referesh my add-on, the setter will not do anything, but throws no error, then I will comment out a line of code, test, still not working, uncomment the same code so its exactly like before, and it will work.
Edit 6-30-2020
I posted the answer to this problem once I figured it out, but apparently didn't add a note to this question to direct everyone to it (making them read the whole question).
The reason this situation usually occurs is because most types of Blender properties won't exist at all in objects until they are modified from their default values for the first time. And if your code attempts to modify a property before it exists, Blender will sometimes just give up and exit the setter function without reporting a problem. In addition, if you have multiple objects, any object properties will only exist for the objects where the property was changed - it will still not exist for the other objects.
Make sure you only attempt to use or modify properties after they have been assigned by your code to something other than the default value.
Here are some notes I wrote for myself in OneNote back when I was trying to understand the chaos of this property system. These notes relate to normal properties in Blender/Python. I also have notes about "Dynamic Key" and "Dynamic Variable" properties if anyone wants to see them (both are assigned AFTER class definition). I may be able to post this in text form if anyone needs it. Just let me know.
End of edit
blocker spread
def FBXG_BlockerSpread( prev_val, new_val ):
# prepare
prefs = FBXG_Prefs()
# map to all selected?
if prefs.MapAllSelected:
# detect added and removed flags
turn_on = new_val & ~prev_val # new flags minus old flags
turn_off = prev_val & ~new_val # old flags minus new flags
# iterate all selected objects
for obj in bpy.context.selected_objects:
#if obj is not bpy.context.active_object:
obj.fbxg["Blocker"] = obj.fbxg.get("Blocker") | turn_on
obj.fbxg["Blocker"] = obj.fbxg.get("Blocker") & ~turn_off
blocker set function
def FBXG_BlockerSet(self, value):
# spread to others?
FBXG_BlockerSpread( self.get("Blocker"), value )
# set new value
self["Blocker"] = value
blocker get function
def FBXG_BlockerGet(self):
# simply return it
return self.get("Blocker")
class inclusion
# object blockers
Blocker = EnumProperty(
name="Object Blockers",
options={'ENUM_FLAG'},
items=FBXG_Mode,
description="***",
get=FBXG_BlockerGet,
set=FBXG_BlockerSet
)
Can you guys see anything wrong here?
Also, does anyone know how the getters and setters work internally? If there is an error, do we actually see it, or does it just halt execution of that task? If I comment out FBXG_BlockerSpread(...), it works. But then it still works if I remove the comment marker. So its very difficult to narrow down without an error.
One of the things I'm concerned with is that I might be calling the setter every time I spread to another variable. If that is happening, is there a way to bypass it?
Edit/Update 1:
It is not any specific code in FBXG_BlockerSpread
. I can completely remove that and add other routines and it still doesn't work.
I just tested by adding a function to print a message when the setter is called. I print hello at the start of my setter, and goodbye at the end of it, with some simple conditional branching and string formatting in the middle, the message shows only "hello". It's like the function terminates prematurely.
Is it possible there is a very limited memory footprint allowed for setters? Because that would explain why I keep getting random behavior (memory overshoot). Or maybe we are not allowed to assign other properties inside of setters (even if they are entirely different types)?
Edit/Update 2:
I tried changing my setter/getter into a simple update function, but I'm having the same exact problem with the update code. There is something very strange happening with the code inside of these functions. For example, I can write code such as "DO_NOTHING( NOTHING, DOESNTEXIST )" and get no error or message about doing something wrong. So I'm assuming I have errors in some of this code and the environment is just not telling me anything about it - it is just halting the execution of it.
Can anyone explain how these callbacks work? Is the function code copied and executed somewhere else? Is that why I don't get any errors about missing functions and such? Is there any way to get the environment to send me such feedback?
If anyone can figure this out, I will owe you one.
ob.get("prop")
which will returnNone
if not set overob.get("prop", default)
where default matches an enum item value or index,None
won't match an enum. $\endgroup$