Tips

Kivy get_property_observers: Unable to Get method_name in Callback With arguments

This article can be read in about 8 minutes.

Mentions a problem with Kivy’s get_property_observers() where method_name cannot be retrieved when a callback function with arguments is bound.

get_property_observers()

The get_property_observers() is a method that returns a list of callback functions bound to a property or event, allowing the bound callback functions to be examined.

See below for details and sample code of the get_property_observers() method.

Specifying args = True as a parameter to this method returns a list similar to the following.

[<WeakMethod proxy=<__main__.RootWidget object at 0x00000164BC361240> method=None method_name=on_callback>]

The method_name contains the callback function name. This is the list of callback functions when bound with no arguments. I am making a note of this because I have encountered a phenomenon where method_name is None or the element does not exist in the case of a callback function with arguments.

Phenomenon that method_name cannot be obtained

In the case of a callback function with arguments, method_name could not be obtained. I don’t know if it is related to weak references, a bug, or my fault, but I couldn’t solve this problem. I would appreciate comments from anyone who can help me understand this phenomenon.

When using bind()

# For bind With argument
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from functools import partial
from kivy.lang import Builder

kv_code = Builder.load_string('''
<RootWidget>:
    orientation: 'vertical'       
    Button:
        id: button2
        text: "Unbind Callback"
        font_size: 30
        on_press: root.unbind_callback()
''')

class RootWidget(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.register_event_type('on_custom_event')
        self.bind(on_custom_event=partial(self.on_callback,'args1','args2',kwargs='kwargs'))
        

    # Custon Event1
    def on_custom_event(self,*args):
        print('on_custom_event was called')

    # Callback
    def on_callback(self, *args, **kwargs):
        print('on_callback has been called')


    # Unbind callback functions.
    def unbind_callback(self):
        print(self.get_property_observers('on_custom_event', args = True))
        #self.funbind('on_custom_event',self.on_callback,'args1','args2',kwargs='kwargs')

class KivyEventsCustomEvent3(App):
    def build(self):
        return RootWidget()

if __name__ == '__main__':
    KivyEventsCustomEvent3().run()

If I specify arguments to the callback function in bind(), method_name=None. And the argument is not in the element where it should fit. It should be correct that args should be in index 2 and kwargs in index 3.

# For bind With argument.
[(<WeakMethod proxy=None method=functools.partial(<bound method RootWidget.on_callback of <__main__.RootWidget object at 0x00000264A5C87D90>>, 'args1', 'args2', kwargs='kwargs') method_name=None>, (), {}, 1, None)]

Using fbind()

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder

kv_code = Builder.load_string('''
<RootWidget>:
    orientation: 'vertical'       
    Button:
        id: button2
        text: "Unbind Callback"
        font_size: 30
        on_press: root.unbind_callback()
''')

class RootWidget(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.register_event_type('on_custom_event')
        self.fbind('on_custom_event',self.on_callback,'args1','args2',kwargs='kwargs')     

    # Custon Event1
    def on_custom_event(self,*args):
        print('on_custom_event was called')

    # Callback
    def on_callback(self, *args, **kwargs):
        print('on_callback has been called')


    # Unbind callback functions.
    def unbind_callback(self):
        print(self.get_property_observers('on_custom_event', args = True))
        #self.funbind('on_custom_event',self.on_callback,'args1','args2',kwargs='kwargs')

class KivyEventsCustomEvent3(App):
    def build(self):
        return RootWidget()

if __name__ == '__main__':
    KivyEventsCustomEvent3().run()

If we use fbind(), method_name has disappeared. However, the arguments are in elements that should fit. It is correct that args is in index 2 and kwargs is in index 3.

# For fbind With argument.
[(<bound method RootWidget.on_callback of <__main__.RootWidget object at 0x00000262DA867D90>>, ('args1', 'args2'), {'kwargs': 'kwargs'}, 0, 1)]

Comment

Copied title and URL