pythonkivyattributeerrorkivymdgetattr

AttributeError: 'super' object has no attribute '__getattr__' KivyMD


I'm learning KivyMD and I'm trying to add a dropdown menu but I get this error. It's probably because of my wrong usage of ids but I still cant figure it out. Here is my main py code:

from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.screenmanager import ScreenManager
from kivymd.uix.screen import Screen
from kivymd.uix.menu import MDDropdownMenu

from kivy.metrics import dp
from kivy.core.window import Window

Window.size = (500, 800)

class HomePage(Screen):
    pass

class SecondPage(Screen):
    pass

class App(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.screen = Builder.load_file("kivy.kv")
        items_d = ['Settings', 'Profile', 'Log Out', 'Exit']
        menu_items = [
            {
                "text": f"{i}",
                "viewclass": "OneLineListItem",
                "height": dp(40),
                "on_release": lambda x=f"{i}": self.menu_callback(x),
            } for i in items_d
        ]
        self.menu = MDDropdownMenu(
            caller = self.screen.ids.tool1,
            items = menu_items,
            width_mult =2
        )

    def menu_callback(self, text_item):
        print(text_item)
        self.menu.dismiss()

    def build(self):
        self.theme_cls.primary_palette = 'Red'
        self.theme_cls.primary_hue = '500'
        self.theme_cls.theme_style = 'Dark'

        sm = ScreenManager()
        sm.add_widget(HomePage(name='first'))
        sm.add_widget(SecondPage(name='second'))

        return self.screen
    

App().run()

and here is the kv file:

#:kivy 2.1.0

ScreenManager:
    HomePage:
    SecondPage:

<HomePage>
    name: 'first'

    MDNavigationLayout:
        ScreenManager:
            Screen:
                BoxLayout:
                    orientation:'vertical'

                    MDTopAppBar:
                        id:tool1
                        title: 'Home Page'
                        left_action_items: [['menu', lambda x: nav_drawer.set_state('toggle')]]
                        right_action_items: [['dots-vertical'], lambda x: app.menu.open()]
                        elevation: 3

                    MDLabel:
                        text: "."

                    MDBottomAppBar:
                        MDTopAppBar:
                            icon: 'apps'
                            mode: 'center'
                            type: 'bottom'
                            

        MDNavigationDrawer:
            id: nav_drawer

            ScrollView:
                MDList:
                    OneLineIconListItem:
                        text: 'Home Page'
                        on_press: nav_drawer.set_state('close')
                        on_press: root.manager.current = 'first'

                        IconLeftWidgetWithoutTouch:
                            icon:'bluetooth'

                    OneLineIconListItem:
                        text: 'Content Page'
                        on_press: root.manager.current = 'second'
                        on_press: nav_drawer.set_state('close')
                                
                        IconLeftWidgetWithoutTouch:
                            icon:'content-copy'


<SecondPage>
    name: 'second'

    MDNavigationLayout:
        ScreenManager:
            Screen:
                BoxLayout:
                    orientation:'vertical'

                    MDTopAppBar:
                        id:tool1
                        title: 'Content Page'
                        left_action_items: [['menu', lambda x: nav_drawer.set_state('toggle')]]
                        right_action_items: [['dots-vertical'], lambda x: app.menu.open()]
                        elevation: 3

                    MDLabel:
                        text: "."

                    MDBottomAppBar:
                        MDTopAppBar:
                            type: 'bottom'
                            icon: 'apps'
                            mode: 'center'
                            left_action_items: [['information']]

        MDNavigationDrawer:
            id: nav_drawer

            ScrollView:
                MDList:
                    OneLineIconListItem:
                        text: 'Home Page'
                        on_press: nav_drawer.set_state('close')
                        on_press: root.manager.current = 'first'

                        IconLeftWidgetWithoutTouch:
                            icon:'bluetooth'

                    OneLineIconListItem:
                        text: 'Second Page'
                        on_press: nav_drawer.set_state('close')
                        on_press: root.manager.current = 'second'

                        IconLeftWidgetWithoutTouch:
                            icon:'wifi'

I don't know why exactly but maybe because of self.screen doesn't really contain the ids? And please tell me what to use instead if I'm using wrong methods.


Solution

  • You are incorrectly trying to access the tool1 id. First, note that the ids defined in the kv file become part of the ids dictionary of the root of the rule where that id is defined. So the tool1 id (which is defined twice) ends up in the ids of the HomePage and also in the ids of the SecondPage. So you must reference that id through the containing object. Assuming you want to reference the tool1 defined in HomePage, just change:

    caller = self.screen.ids.tool1,
    

    to:

    caller = self.screen.get_screen('first').ids.tool1,
    

    Unrelated, but you can eliminate the lines:

        sm = ScreenManager()
        sm.add_widget(HomePage(name='first'))
        sm.add_widget(SecondPage(name='second'))
    

    since their result is unused.