'Attribute error when using Kivy Screen Manager and self.ids

from kivymd.app import MDApp
from kivy.config import Config
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
from kivy.core.window import Window
Window.minimum_width, Window.minimum_height = (1200, 700)
Window.maximize()
from kivy.lang import Builder
import requests
from geopy.geocoders import Nominatim
import geopy
from kivy.uix.widget import Widget
from kivymd.uix.menu import MDDropdownMenu
from datetime import datetime
import pytz
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty

class WindowManager(ScreenManager):
    pass

class Weather(Screen):  
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Clock.schedule_interval(self.update_time, 60)
        city = 'Tokyo'
        self.get_weather(city)
    def search_weather(self):
        self.get_weather(self.ids.city_name.text)
    def get_weather(self, city_name):
        self.ids.location.text = 'City : '+city_name
    def update_time(self, *args):
        print(datetime.now())

class Login(Screen):
    username = ObjectProperty(None)
    password = ObjectProperty(None)
    message = StringProperty()
    def action(self):
        print(f'logged in as {username}')


class App(MDApp):
    def build(self):
        return kv = Builder.load_file('destest.kv')

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

This is the python code

And the following is the code in the destest.kv file

#: import utils kivy.utils
WindowManager: 
    Login:
    Weather: 
    

<Login>
    username: username
    password: password
    name: 'logsin'
    GridLayout:
        cols:2
        padding: 0, 20, 0 , 0
        spacing: 5
        TextInput:
            id : username
            multiline: False
            write_tab : False
            background_color: utils.get_color_from_hex('#B8F9EE')
            size_hint_x: None
            width : (root.width/3)*1.5
            foreground_color: utils.get_color_from_hex('#1b3446') # changes colour of text
            font_size: 32
            hint_text : 'Username'
        TextInput:
            id : password
            multiline: False
            write_tab : False
            background_color: utils.get_color_from_hex('#B8F9EE')
            size_hint_x: None
            width : (root.width/3)*1.5
            foreground_color: utils.get_color_from_hex('#1b3446') # changes colour of text
            font_size: 25
            hint_text: 'Password'

        Button:
            text : 'Login'
            font_size : 40
            on_press: root.action()
            size_hint_y : None
            height : 60
            size_hint_x : None
            width : 180
            background_normal : ''
            background_color: 0, 0, 0, 0
            canvas.before:
                Color:
                    rgba: utils.get_color_from_hex('#0CD408')
                RoundedRectangle:
                    radius : [5]
                    size: self.size
                    pos: self.pos
        Button:
            text : 'Go to weather'
            font_size : 40
            on_release: app.root.current = 'weathers'
            size_hint_y : None
            height : 60
            size_hint_x : None
            width : 180
            background_normal : ''
            background_color: 0, 0, 0, 0
            canvas.before:
                Color:
                    rgba: utils.get_color_from_hex('#0CD408')
                RoundedRectangle:
                    radius : [5]
                    size: self.size
                    pos: self.pos


<Weather>:
    name: 'weathers'
    MDFloatLayout:
        spacing : 30, 10
        md_bg_color : 1,1,1,1
        size: root.size
        pos_hint: {'x': 0, 'y': 0}
        MDLabel:
            id : location
            text: "City"
            pos_hint: {"center_x": .5,"center_y": .89}
            halign : "center"
            font_size: 60
            
        MDFloatLayout:
            size_hint_y : .3
            canvas:
                Color:
                    rgb: rgba(148, 117, 255, 255)
                RoundedRectangle:
                    size: self.size
                    pos: self.pos
                    radius : [10, 10, 0, 0]
            MDFloatLayout:
                pos_hint: {"center_x": 0.5,"center_y": .71}
                size_hint: .9, .32
                canvas:
                    Color:
                        rgb: rgba(131, 69, 255, 255)
                    RoundedRectangle:
                        size: self.size
                        pos: self.pos
                        radius : [6]
                TextInput:
                    id: city_name
                    hint_text : "Enter City Name"
                    size_hint: 1, None
                    height: self.minimum_height
                    pos_hint: {"center_x": 0.5,"center_y": .5}
                    multiline: False
                    font_name : "fonts/Exo/Exo2-RegularCondensed.otf"
                    font_size : 30
                    hint_text_color : 1, 1, 1, 1
                    foreground_color: 1, 1, 1, 1
                    background_color: 1, 1, 1, 0
                    padding : 15
                    cursor_color : 1, 1, 1, 1
                    cursor_width : 3
            Button:
                id: button
                text : "Get Weather"
                font_name : "fonts/Exo/Exo2-SemiBoldCondensed.otf"
                font_size : 30
                size_hint : .9, .32
                pos_hint :{"center_x": 0.5,"center_y": .29}
                background_color : 1, 1, 1, 0
                color: rgba(148, 117, 255, 255)
                on_release: root.search_weather()
                on_press: root.change_bg()
                canvas.before:
                    Color:
                        rgba: 1, 1, 1, 1
                    RoundedRectangle:
                        size: self.size
                        pos: self.pos
                        radius : [6]
        Button:
            text : 'switch to login'
            pos_hint : {"center_x": 0.85,"center_y": .9}
            font_size : 10
            on_press: app.root.current = 'logsin'
            size_hint_y : None
            height : 20
            size_hint_x : None
            width : 60
            background_normal : ''
            background_color: 0, 0, 0, 0
            canvas.before:
                Color:
                    rgba: utils.get_color_from_hex('#0CD408')
                RoundedRectangle:
                    radius : [5]
                    size: self.size
                    pos: self.pos

However when I run the code I get the following error:

 Traceback (most recent call last):
   File "kivy\properties.pyx", line 861, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'location'

 During handling of the above exception, another exception occurred:

 Traceback (most recent call last):
   File "C:\Users\KERAI\Documents\Darsh_work\Python stuff\imagine_cup\altlog.py", line 42, in <module>
     kv = Builder.load_file('destest.kv')
   File "C:\Users\KERAI\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 306, in load_file
     return self.load_string(data, **kwargs)
   File "C:\Users\KERAI\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 408, in load_string
   File "C:\Users\KERAI\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 659, in _apply_rule
     child = cls(__no_builder=True)
   File "C:\Users\KERAI\Documents\Darsh_work\Python stuff\imagine_cup\altlog.py", line 27, in __init__
     self.get_weather(city)
   File "C:\Users\KERAI\Documents\Darsh_work\Python stuff\imagine_cup\altlog.py", line 31, in get_weather
     self.ids.location.text = 'City : '+city_name
   File "kivy\properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'

I am aware that the error is because using screen manager the value of self.ids changes and that you have to access the ids another way, I would really appreciate if someone could help me with this program and I made it as simple as I could since the original file was much to long.



Solution 1:[1]

I found a fix:

from kivy.app import App

plus

class Weather(Screen):  
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Clock.schedule_interval(self.update_time, 60)
        Clock.schedule_once(after_init)
    def after_init(self, *largs):
        app = App.get_running_app()
        self.ids = app.root.get_screen('weathers').ids
        city = 'Tokyo'
        self.get_weather(city)
    def search_weather(self):
        self.get_weather(self.ids.city_name.text)
    def get_weather(self, city_name):
        self.ids.location.text = 'City : '+city_name
    def update_time(self, *args):
        print(datetime.now())

plus

class AnotherName(MDApp):
    def build(self):
        self.root = Builder.load_file('destest.kv')
if __name__ == '__main__':        
    AnotherName().run()

Do let me know if there is another simpler method.

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 DrHakeshi