Callum
Callum

Reputation: 31

Unsure of how to fix this error

So I'm creating my first ever program in Python and I've got it all made up into tiny parts and I'm having trouble putting it all together.

The code that I've extracted for this post is basically logging in, using a premade .txt called "yournamehere profile.txt" where the first 2 lines have your username and password which is checked and lets you log in.

Then I have it so you can go and enter in your details, however I'm getting an error: TypeError: descriptor 'write' requires a 'file' object but received a 'str', which after looking up I'm assuming is caused by the file not being open in the correct part of code.

I'm sorry if my code is messy or badly done, it's my first ever program so if you have any tips or ways to make it nicer I'll appreciate those too :P

from Tkinter import *

root = Tk()
root.configure(bg="#CCFFCC")

#========--------------PERSONAL DETAILS START-------------==========#
def Personal():
    Personal=Toplevel(root)
    Personal.title("Personal Details")
    Personal.configure(bg="#CCFFCC")
    #----COMMANDS W/ WIDGETS----#
    #First Name
    def WriteFName():
        file.write("\n")
        file.write("First Name: ")
        file.write(str(entryFName.get()))
        file.write("\n")
        labelSaveFName.configure(text="Saved")
    labelFName = Label(Personal, text="First name: ", bg="#ccffcc")
    entryFName = Entry(Personal)
    buttonFName = Button(Personal, text="Save", command=WriteFName, bg="#93FF00")
    labelSaveFName = Label(Personal, text="...", bg="#ccffcc")
    #Last Name
    def WriteLName():
        file.write("Last Name: ")
        file.write(str(entryLName.get()))
        file.write("\n")
        labelSaveLName.configure(text="Saved")
    labelLName = Label(Personal, text="Last name: ", bg="#ccffcc")
    entryLName = Entry(Personal)
    buttonLName = Button(Personal, text="Save", command=WriteLName, bg="#93FF00")
    labelSaveLName = Label(Personal, text="...", bg="#ccffcc")
    #Age
    def WriteAge():
        file.write("Age: ")
        file.write(str(entryAge.get()))
        file.write("\n")
        labelSaveAge.configure(text="Saved")
    labelAge = Label(Personal, text="Age: ", bg="#ccffcc")
    entryAge = Entry(Personal)
    buttonAge = Button(Personal, text="Save", command=WriteAge, bg="#93FF00")
    labelSaveAge = Label(Personal, text="...", bg="#ccffcc")
    #----GRID----#
    labelFName.grid(row=0, column=0)
    entryFName.grid(row=0, column=1)
    buttonFName.grid(row=0, column=2)
    labelSaveFName.grid(row=0,column=3)
    labelLName.grid(row=1, column=0)
    entryLName.grid(row=1, column=1)
    buttonLName.grid(row=1, column=2)
    labelSaveLName.grid(row=1, column=3)
    labelAge.grid(row=2, column=0)
    entryAge.grid(row=2, column=1)
    buttonAge.grid(row=2, column=2)
    labelSaveAge.grid(row=2, column=3)

#=================--------PERSONAL DETAILS END-------================#

#=====----CHOOSING WHAT TO INPUT START----=====#
def details():
    detailswindow=Toplevel(root)
    detailswindow.configure(bg="#CCFFCC")
    detailswindow.title("Choose")
    def end():
        detailswindow.destroy()
    #---WIDGETS---#
    PersonalButton = Button(detailswindow, text="Personal Details", command=Personal, bg="#93ff00")
    CloseButton = Button(detailswindow, text="Close Window", command=end, bg="#93ff00")
    #---GRID---#
    PersonalButton.grid(row=0, column=0)
    CloseButton.grid(row=1, column=1)
#=====----CHOOSING WHAT TO INPUT END----=====#

#======----LOG-IN WINDOW START----======#
def newwindow():
    login=Toplevel(root)
    login.configure(bg="#CCFFCC")
    name=raw_input("Please enter your name: ")
    file = open(name.lower() + " profile.txt", "a+")
    #---Commands---#
    def end():
        login.destroy()
    def callback():
        line = file.readlines()
        username = user.get()
        password = passw.get()
        if username == line[0].strip() and password == line[1].strip():
            Message.configure(text = "Logged in.")
            proceed.configure(text="Proceed", command=details)
        else:
            Message.configure(text = "Username and password don't match the account \n under the name;\n \'" + name + "\'. \nPlease try again.")
        return f
    #---LOG-IN WIDGETS---#
    #labels
    LogInTitle = Label(login, text="Please log in.", bg="#CCFFCC").grid(row=0, column=1)
    UserTitle = Label(login, text="Username:", bg="#CCFFCC").grid(row=1, column=0)
    PassTitle = Label(login, text="Password:", bg="#CCFFCC").grid(row=2, column=0)
    Message = Label(login, bg="#CCFFCC")

    #text entry windows
    user = Entry(login)
    passw = Entry(login, show='*')

    #buttons
    go = Button(login, text="Log in!", command = callback, bg="#93ff00").grid(row=3, column=1)
    proceed = Button(login, text="...", bg="#93ff00")
    close = Button(login, text="Close window", command=end, bg="#93FF00")
    #===--LOG-IN GRID===--#
    user.grid(row=1, column=1)
    passw.grid(row=2, column=1)
    Message.grid(row=4, column=1)
    proceed.grid(row=5, column=1)
    close.grid(row=5, column=0)
#=====----LOG-IN WINDOW END----=====#

#====----OPENING PAGE----=====#
def destroyroot():
    root.destroy()
LogInButton = Button(root, text="Log In", bg="#93ff00", command=newwindow).grid(row=1, column=0)
CloseRoot = Button(root, text="Close window", bg="#93ff00", command=destroyroot).grid(row=3, column=0)

root.mainloop()
#===--OPENING PAGE END---====#

#======================-------------END------------------======================#

Upvotes: 0

Views: 583

Answers (2)

Fred S
Fred S

Reputation: 995

Some Python basics for you:

1) "from Tkinter import *" is bad form. It gets real messy when you "import *" from several modules. Try "import Tkinter" instead. Reference methods as "Tkinter.xxxx". Like for example "personal = Tkinter.Toplevel(root)".

2) "file" is a type in Python, so you should never ever use it as a variable name. Using "str" and "len" as variable names are other common gotchas for new Python users.

Moving on, your code seems really complex with all the nested functions.

You might do better with classes if you have groups of variables shared across a different functions. Here is a very simple example class that also shows the correct way to write to a file:

class MyClass(object):

    def __init__(self, file_name = r'c:\myfile.txt'):
        self.file_name = file_name

    def write_to_file(self, stuff_to_write):
        with open(self.file_name, 'a') as f:
            f.write(stuff_to_write)

    def WriteLName(self, name):
        text = "Last Name: %s\n"%name
        self.write_to_file(text)

output = MyClass(r'c:\output_file.txt')
output.WriteLName('Jones')

Makes a file called c:\output_file.txt with the text "Last Name: Jones" in it.

When you define a variable within a function, it is not automatically "global", so other functions do not see it:

def open_file():
    fout = open(r'c:\myfile.txt', 'w') 
def write_file():
    fout.write('some text\n')

open_file()
write_file()

Gives this error when you hit the "fout.write" line:

NameError: global name 'fout' is not defined

If you add global declarations, it works as you expect. Many would say that this is "bad form" but as a quick fix for your existing code, it might be something to try.

def open_file():
    global fout
    fout = open(r'c:\myfile.txt', 'w') 
def write_file():
    global fout
    fout.write('some text\n')
open_file()
write_file()

Upvotes: 0

spalac24
spalac24

Reputation: 1116

You are not setting correctly the file variable. You define it in a function, newwindow, however that variable is not being set in other functions. Also, file is a type in python (such as int, list, etc...). So you should NOT be using it as a name, it is where the error comes from. You are doing file.write so it's getting the write from the type, not the variable, and you are getting extraneous errors.

Upvotes: 2

Related Questions