'Kivy : AttributeError: 'Mylayout' object has no attribute 'hint'

I'm new to python and I am developing a US states flashcard with Kivy. The flashcard will shuffle the US states letter, the user will need to input the answer. When the user is not sure, he may click the Get Hint button, the flashcard will display a letter, the user may click for another letter until all letters are shown.

us_state_flaskcard_3.py file

        from kivy.app import App
        from kivy.lang import Builder
        from kivy.uix.widget import Widget
        from kivy.core.window import Window
        from kivy.uix.button import Button
        
        from random import choice
        from random import shuffle
        
        Builder.load_file('us_state_flashcard.kv')
        
        Window.size = (350, 600)
        
        class MainApp(App):
            title='US State Flashcard'
            def build(self):
                Window.clearcolor = (255/255, 255/255, 0, 1) 
                return Mylayout()  
        
            def shuffler(self):
              
                self.root.ids.entry_answer.text = ''
                self.root.ids.answer_label.text = ''
                self.root.ids.hint_label.text = ''
        
                global hint_count
                hint_count = 0
        
                states= ['Washington', 'Oregon','California','Ohio','Nebraska',
                    'Wisconsin', 'Daleware','Arkansas','Louisiana','California',
                    'Michigan','Florida', 'Taxes','Kectucky','Alabama','Alaska',
                    'Arizona','Colorado','Connecticut',' Georgia','Hawaii', 
                    'Illinois','Indiana', 'Iowa','Maryland','Massachusetts', 
                    'Rhode Island','New York']
        
                global word
                self.word = choice(states)
                self.root.ids.my_label.text = self.word
                break_apart_word = list(self.word)
                shuffle(break_apart_word)
          
                global shuffled_word
                shuffled_word = ''
                for letter in break_apart_word:
                    shuffled_word += letter
        
                self.root.ids.my_label.text = shuffled_word
        
            def answer(self):
                if self.word == self.root.ids.entry_answer.text :
                    self.root.ids.answer_label.text= "Correct!!"
                else:
                    self.root.ids.answer_label.text = "Incorrect!!"
            global hint_count
            hint_count = 0
        
            def hint(self, count):
                global hint_count
                hint_count = count
        
                word_length = len(self.word)
         
                if count < word_length:
                    self.root.ids.hint_label.text = f'{self.hint_label["text"]} {self.word[count]}'
                    hint_count +=1
        
            def on_start(self, **kwargs): 
                self.shuffler()
        
        class Mylayout(Widget):    
          def __init__(self, **kwargs):
                super(Mylayout, self).__init__(**kwargs)
          
                self.btn1 = Button(
                    text ='hint_button', 
                    font_size ="20sp",
                    background_color =(1, 1, 1, 1), 
                    color =(1, 1, 1, 1), 
                    size =(200, 50), 
                    pos =(80, 130)
                    )
        
                buttoncallback = lambda x : self.hint(hint_count) 
                self.btn1.bind(on_press=buttoncallback)
                self.add_widget(self.btn1)
        
                
        if __name__ == '__main__':
            MainApp().run()

us_state_flaskcard_3.kv file

        <MyLayout>
                    
          FloatLayout:
                Label:
                    id: my_label
                    font_size: 25
                    text: 'abc'
                    pos_hint: {'x': 1.3, 'y':5}
                    size_hint: (1, 1)
                    color: 'black'
        
                TextInput:
                    id: entry_answer
                    multiline: False
                    font_size: 24
                    pos_hint: {'x': .8, 'y':4.5}
                    size_hint: (2, .4)
                    halign: "center"
        
                Button: 
                    font_size: 20
                    text: "Answer"
                    on_press: app.answer()
                    pos_hint: {'x': .8, 'y':3.5 }
                    size_hint: (2, .5)
        
                Label:
                    id: answer_label
                    font_size: 25
                    text: ''
                    pos_hint: {'x': 0.8, 'y':2.8}
                    size_hint: (2, .5)
                    color: 'black'
                    
                Button: 
                    font_size: 20
                    text: "Pick Another Word"
                    on_press: app.shuffler()
                    pos_hint: {'x': .8, 'y':2 }
                    size_hint: (2, .5)    
                    
                Label:
                    id: hint_label
                    font_size: 20
                    text: 'Hint Label'
                    pos_hint: {'x': .8, 'y':1.5}
                    size_hint: (2, .5)
                    color: 'black'

When I click the Get Hint Button, the error shown:

     File "C:\Users\Kelvin Loh\Documents\kivyMD\kivy_venv\lib\site-packages\kivy\base.py", line 342, in dispatch_input
         post_dispatch_input(*pop(0))
       File "C:\Users\Kelvin Loh\Documents\kivyMD\kivy_venv\lib\site-packages\kivy\base.py", line 248, in post_dispatch_input
         listener.dispatch('on_motion', etype, me)
       File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
       File "C:\Users\Kelvin Loh\Documents\kivyMD\kivy_venv\lib\site-packages\kivy\core\window\__init__.py", line 1412, in on_motion        
         self.dispatch('on_touch_down', me)
       File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
       File "C:\Users\Kelvin Loh\Documents\kivyMD\kivy_venv\lib\site-packages\kivy\core\window\__init__.py", line 1428, in on_touch_down    
         if w.dispatch('on_touch_down', touch):
       File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
       File "C:\Users\Kelvin Loh\Documents\kivyMD\kivy_venv\lib\site-packages\kivy\uix\widget.py", line 545, in on_touch_down
         if child.dispatch('on_touch_down', touch):
       File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
       File "C:\Users\Kelvin Loh\Documents\kivyMD\kivy_venv\lib\site-packages\kivy\uix\behaviors\button.py", line 151, in on_touch_down     
         self.dispatch('on_press')
       File "kivy\_event.pyx", line 705, in kivy._event.EventDispatcher.dispatch
       File "kivy\_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
       File "kivy\_event.pyx", line 1172, in kivy._event.EventObservers._dispatch
       File "c:\Users\Kelvin Loh\Documents\kivyMD\us_state_flaskcard_3.py", line 115, in <lambda>
         buttoncallback = lambda x : self.hint(hint_count)
     AttributeError: 'Mylayout' object has no attribute 'hint'


Solution 1:[1]

The reason behind this error lies in buttoncallback where you are triggering hint method. But you defined that method in the App's subclass namely, MainApp. So if you want to access that method from the Mylayout class, you have to first access the running app instance which you might do as follows,

        app = App.get_running_app()
        buttoncallback = lambda x : app.hint(hint_count)
        self.btn1.bind(on_press=buttoncallback)

Also, perhaps you may need some change in method hint,

    def hint(self, count):
        global hint_count
        hint_count = count

        word_length = len(self.word)

        if count < word_length:
            self.root.ids.hint_label.text = f'{self.word[count]}'
            hint_count +=1

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ApuCoder