2
$\begingroup$

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.

Blender Property Notes

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.

$\endgroup$
1
  • $\begingroup$ Couple of things, post text as text, not an image of text editor. IMO at issue here is not that an ID prop isn't created until a non-default value is set, rather the use of ob.get("prop") which will return None if not set over ob.get("prop", default) where default matches an enum item value or index, None won't match an enum. $\endgroup$
    – batFINGER
    Commented Jul 1, 2020 at 18:16

1 Answer 1

1
$\begingroup$

The reason my setters would not work depended on several circumstances, but here are the primary reasons:

  • The environment will not always throw errors when a setter has invalid code, so it helps to call the setter from standard code to work out any possible errors.
  • Custom properties added to objects don't actually exist until the system generates them, which it does not do until the UI changes them from their default value. So if code tries to modify such an attribute in a setter before it exists, Blender will just give up. This one was my biggest problem. This made me think it was random, but it was actually because I used the same mechanism twice and the attribute existed the second time.
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .