2
$\begingroup$

following Blenders documentation from the following link:

https://docs.blender.org/api/current/bpy.msgbus.html

I am trying to adapt the example to add a subscription to a custom property as follow:

import bpy
    
    
def notification_handler(*args):
    # This will print:
    # Something changed! (1, 2, 3)
    print("Something changed!", args)
    
if __name__ == "__main__":
    
    subscription_owner = bpy.types.Collection
    subscribe_to = bpy.context.scene['myproperty']
    
    print(subscribe_to)
    bpy.msgbus.subscribe_rna(
        key=subscribe_to,
        owner=subscription_owner,
        args=("example argument",),
        notify=notification_handler,
        options=set(["PERSISTENT"])
    )

Then, in the python console, I execute the following command:

bpy.context.scene['myproperty'] = "new value"

And I see that the value changes in the UI but there is nothing printed in the console (I launch Blender from the CLI).

I suspect that the values of subcription_owner and subscribe_to are not totally correct, but I don't know how to continue.

Anyone knows how to do it?

$\endgroup$
3
  • $\begingroup$ I tried with the object and a few of more options, but the problem is that I don't even see the point of that owner parameter. What is that for? I have the feeling that there are much more behind subscribe_rna that is not well documented. $\endgroup$ – Héctor Valverde Pareja May 28 at 22:02
  • $\begingroup$ after testing a bit i would say: maybe a bug in Blender. With objects everything is fine, but the scene properties change won't call the handler. So as workaround - just save it in an object rather than in scene. $\endgroup$ – Chris May 29 at 9:45
  • $\begingroup$ Thanks for testing, Chris. I am trying different approaches also, like storing the data in an instance of bpy.props.CollectionProperty $\endgroup$ – Héctor Valverde Pareja May 29 at 9:59
4
+100
$\begingroup$

From the documentation :

Some properties are converted to Python objects when you retrieve them. This needs to be avoided in order to create the subscription, by using datablock.path_resolve("property_name", False):

subscribe_to = bpy.context.object.path_resolve("name", False)

The callback doesn't work because in subscribe_to = bpy.context.scene['myproperty'], the right part of the statement evaluates to a python object (eg float if your property is a FloatProperty), and from this point there is no tie to the Blender API to get value updates to the msgbus.

enter image description here

With path_resolve you're actually pointing to the API property, which has an available callback .

enter image description here

It seems you do have to register my_property as a global bpy.types.Scene property if you want the callback to fire. I didn't find a way to make it work for regular custom props.

Your code then becomes :

import bpy
    
    
def notification_handler(*args):
    # This will print:
    # Something changed! (1, 2, 3)
    print("Something changed!", args)
    
if __name__ == "__main__":        
    subscription_owner = bpy.types.Collection

    bpy.types.Scene.my_property = bpy.props.FloatProperty()
    subscribe_to = bpy.context.scene.path_resolve("my_property", False)
    
    print(subscribe_to)
    bpy.msgbus.subscribe_rna(
        key=subscribe_to,
        owner=subscription_owner,
        args=("example argument",),
        notify=notification_handler,
        options=set(["PERSISTENT"])
    )
$\endgroup$
7
  • $\begingroup$ Thanks for your answer. I followed your recommendation and I made it work. However, it only triggers the event from the UI, not from the Python console. I am not sure if I will encounter problems later because of that. The whole intention of that is to subscribe a property to a system socket and be able to trigger them from a different process ... wish me luck :D $\endgroup$ – Héctor Valverde Pareja May 31 at 9:20
  • $\begingroup$ It should be triggered with the Python API, but I don't know if it will work with an entirely different process :) good luck $\endgroup$ – Gorgious May 31 at 9:48
  • $\begingroup$ I don't want to extend the question, but as you may now more about the bpy.props library. Is there any way to instantiate a different class (ie. defined in an imported module)? $\endgroup$ – Héctor Valverde Pareja May 31 at 11:39
  • 2
    $\begingroup$ If having to define via bpy.props probably leads to question, why not then use a property update callback, or getter / setter? The owner is arbitrary and often see owner = object() See no advantage in using a member bpy.types $\endgroup$ – batFINGER May 31 at 12:35
  • 2
    $\begingroup$ @batFINGER Agreed, it seems way more straightforward to use props get/set/update methods for this. Héctor Valverde Pareja : Might be worth digging around docs.blender.org/api/current/bpy.props.html or try to define more the end goal $\endgroup$ – Gorgious May 31 at 12:42

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.