Python Forum
AttributeError: '_tkinter.tkapp' object has no attribute 'username' - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: AttributeError: '_tkinter.tkapp' object has no attribute 'username' (/thread-40476.html)



AttributeError: '_tkinter.tkapp' object has no attribute 'username' - Konstantin23 - Aug-03-2023

I was following up with multiple tutorials online for designing a tkinter gui app for a password manager program I made recently, and so I split up the app into a package of multiple python scripts, with the __innit__.py file of the package containg the parent root class and then multiple other scripts containing tk.frame classes, all inheriting from the parent class.

from .home import *
from .register import *
from .login import *
from .menu import *
from .store import *
from .retrieve import *
from PIL import Image, ImageTk
import tkinter as tk


class App(tk.Tk):
    
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        
        self.configure(bg="black")
        self.geometry("500x500+500+100")
        self.minsize(500, 500)
        self.maxsize(500, 500)
        self.title("The Vault v1.0")
        
        self.home = ImageTk.PhotoImage(
            Image.open('./interface/Home.png').resize((35, 30), Image.ANTIALIAS))
        
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        #container.configure(bg="black", highlightbackground="white", highlightthickness=2)
        
        self.frames = {}
        for F in (home, register, login, menu, store, retrieve):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("home")  
        self.bind('<Escape>', lambda x: self.destroy())
        global username
    
    def exit(self):
        self.destroy()
        
    def show_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()
        frame.focus_set()
        self.unbinder()
        frame.binds()

    def unbinder(self):
        self.unbind('<Return>')
        self.unbind('1')
        self.unbind('2')
        self.unbind('3')
        self.unbind('4')
        self.unbind('5')
        
    def exitButton(self, frame):
        note = tk.Label(self, bg= "black", fg="white", text="(esc)", font=("Terminal", 10))
        exitBut = tk.Button(frame, bg= "black", fg="white",
                            text='EXIT', font=("Terminal", 20),
                            command=exit,
                            activebackground="black",
                            relief=tk.SOLID,
                            borderwidth=0,
                            padx=0, pady=0,
                            cursor="hand2")
        exitBut.place(relx=0.9, rely=0.9, y=-10,anchor=tk.CENTER)
        note.place(relx=0.9, rely=0.9, x=-8, y=10, anchor=tk.CENTER)
        
    def homeButton(self, frame):
        def home_clear(self):
            self.show_frame('home')
            self.username = ""
        buttn = tk.Button(frame, image=self.home,
                        bg="black", command=lambda: home_clear(self),
                        activebackground="black",
                        relief=tk.SOLID,
                        borderwidth=0,
                        padx=0, pady=0, cursor="hand2")
        buttn.place(relx=0.05, rely=0.05)
        
def start():
    app = App()
    app.mainloop()
In the above __innit__.py file, there is a global variable username which needs to be passed on to and modified by other classes so that they may call various backend function using 'username' as a parameter.
Now the problem persists in the code below where it is calling the username variable in the class' innit function:

import tkinter as tk
from customtkinter import CTkComboBox, CTkTextbox
from .backend import *


class retrieve(tk.Frame):
    def __init__(self, parent, controller):
        self.controller = controller
        tk.Frame.__init__(self, parent, bg="black", highlightthickness=5, highlightcolor='white')
        self.controller = controller
        head = tk.Label(self, bg="black", fg="white", text="STORED DATA",
                        font=("Terminal", 32))    
        # retrieve _passwords: returns a list of tuples split in two lists with same number of elements.
        services, data = retrieve_passwords(self.controller.username) # THIS THROWS ERROR
        service_list.configure(values=services)
        
        def combobox_callback(choice):
            data_out = data[services.index(choice)]
            data_disp.insert("0.0", data_out)
            print("combobox dropdown clicked:", choice)    
        service_list = CTkComboBox(self, fg_color="black", text_color="white", font=("Terminal", 20, "bold"), justify="left",
                              corner_radius=0, width=450, height=36, border_width=0, border_color="white", 
                              command=combobox_callback, dropdown_fg_color="black", dropdown_text_color="white", 
                              dropdown_font=("Terminal", 20, "bold"),hover=False, button_color="black", 
                              button_hover_color="white", dropdown_hover_color="black")
        
        service_list.set(">SERVICE NAME")
        data_disp = CTkTextbox(self, fg_color="black", text_color="white", font=("Terminal", 22, "bold"),
                          scrollbar_button_color="white", scrollbar_button_hover_color="white",wrap=tk.WORD,
                            corner_radius=0, width=450, height=250, border_width=0)
        
        data_disp.configure(state=tk.DISABLED)
        back = tk.Button(self,
                          bg="black", fg="white",
                          text='BACK', font=("Terminal", 18, "bold"),
                          command=lambda: controller.show_frame("menu"),
                          activebackground="black",
                          relief=tk.SOLID,
                          borderwidth=0,
                          padx=16, pady=0, cursor="hand2")
        entNote = tk.Label(self,bg="black", fg="white", text="(enter)",
                           font=("Terminal", 10))

        head.place(relx=0.5, rely=0.1, anchor=tk.CENTER)
        service_list.place(relx=0.1, rely=0.3, y=-10,x=-35,anchor=tk.W)
        data_disp.place(relx=0.1, rely=0.45, x=-30, y=65,anchor=tk.W)
        back.place(relx=0.5, rely=0.9, anchor=tk.CENTER)
        entNote.place(relx=0.5, rely=0.9, y=20, anchor=tk.CENTER)
        controller.exitButton(self)
        controller.homeButton(self) 
        
    def binds(self):
        self.focus_set()
        self.controller.bind('<Return>', lambda x: self.controller.show_frame("menu"))
It throws this error everytime I try run the application:

Error:
Traceback (most recent call last): File "a:/python projects/password generator/main.py", line 3, in <module> interface.start() File "a:\python projects\password generator\interface\__init__.py", line 86, in start app = App() File "a:\python projects\password generator\interface\__init__.py", line 34, in __init__ frame = F(parent=container, controller=self) File "a:\python projects\password generator\interface\retrieve.py", line 14, in __init__ services, data = retrieve_passwords(self.controller.username) File "C:\Users\konstantin\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 2345, in __getattr__ return getattr(self.tk, attr) AttributeError: '_tkinter.tkapp' object has no attribute 'username'
PS: I am fairly new to python classes and tkinter so I might have made some mistakes with the inheritances, just cant figure which ones exactly so any help at all is very much appreciated, thanks


RE: AttributeError: '_tkinter.tkapp' object has no attribute 'username' - deanhystad - Aug-03-2023

The error is correct. Class App does not have an attribute named "username" until after homeButton() is called. You should initialize self.username to something in the __init__() method.


RE: AttributeError: '_tkinter.tkapp' object has no attribute 'username' - Konstantin23 - Aug-04-2023

(Aug-03-2023, 10:33 PM)deanhystad Wrote: The error is correct. Class App does not have an attribute named "username" until after homeButton() is called. You should initialize self.username to something in the __init__() method.

I also tried initialising self.username to an empty string inside the __init__() method of the class App like so:
class App(tk.Tk):
    
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        
        self.configure(bg="black")
        self.geometry("500x500+500+100")
        self.minsize(500, 500)
        self.maxsize(500, 500)
        self.title("The Vault v1.0")
        
        self.home = ImageTk.PhotoImage(
            Image.open('./interface/Home.png').resize((35, 30), Image.ANTIALIAS))
        
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        #container.configure(bg="black", highlightbackground="white", highlightthickness=2)
        
        self.frames = {}
        for F in (home, register, login, menu, store, retrieve):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("home")  
        self.bind('<Escape>', lambda x: self.destroy())
        global username
        self.username = ""
but it still returns the same attribute error, or perhaps I am doing it wrong. Again, thanks alot for the help


RE: AttributeError: '_tkinter.tkapp' object has no attribute 'username' - deanhystad - Aug-04-2023

Still too late, You must assign username before making all the frames.
        self.frames = {}
        for F in (home, register, login, menu, store, retrieve):
            page_name = F.__name__
            frame = F(parent=container, controller=self)    # <-- Error happens here
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, sticky="nsew")
 
        self.show_frame("home")  
        self.bind('<Escape>', lambda x: self.destroy())
        global username       # <-- This does nothing
        self.username = ""    # <-- You don't assign value to username until here
Thinking is required when programming. You get an error saying that the object does not have an attributed named "username", but obviously the class assigns an instance variable of that name. How is this possible? What sequence of events can result in getting this error? Sit down and look carefully at your code, focusing on where the error is reported and where you are assigning a value to "username". You are doing this:
x = username
username = "a name"
Here the problem is clear. Through careful analysis you can make the problem in your program just as clear. It just requires some thought.


RE: AttributeError: '_tkinter.tkapp' object has no attribute 'username' - Konstantin23 - Aug-04-2023

(Aug-04-2023, 11:54 AM)deanhystad Wrote: Still too late, You must assign username before making all the frames.
        self.frames = {}
        for F in (home, register, login, menu, store, retrieve):
            page_name = F.__name__
            frame = F(parent=container, controller=self)    # <-- Error happens here
            self.frames[page_name] = frame
            frame.grid(row=0, column=0, sticky="nsew")
 
        self.show_frame("home")  
        self.bind('<Escape>', lambda x: self.destroy())
        global username       # <-- This does nothing
        self.username = ""    # <-- You don't assign value to username until here
Thinking is required when programming. You get an error saying that the object does not have an attributed named "username", but obviously the class assigns an instance variable of that name. How is this possible? What sequence of events can result in getting this error? Sit down and look carefully at your code, focusing on where the error is reported and where you are assigning a value to "username". You are doing this:
x = username
username = "a name"
Here the problem is clear. Through careful analysis you can make the problem in your program just as clear. It just requires some thought.
Wow! that was super helpful, assigned the variable before the frame stack and it worked like a charm :)
also thanks alot for the advice as well, as I am still just a beginner so yes, patience is indeed required specially when working with python oop XD