Jolin
Jolin

Reputation: 27

Kivy: AttributeError: 'str' object has no attribute 'text'

'''I am relatively new to kivy so I would really appreciate any help given. I have been stuck with this problem: if self.name.text != "" and self.username.text != "" and self.password.text != "": AttributeError: 'str' object has no attribute 'text . This problem is faced in the python code's SignupScreen. I have tried placing a "text" argument into: def submit(self, text) However, it returns me with another error: TypeError: submit() missing 1 required positional argument: 'text'. Would appreciate any advice/ help given. '''

class SignupScreen(Screen):
    name = ObjectProperty(None)
    username = ObjectProperty(None)
    password = ObjectProperty(None)

    def submit(self):
        if self.name.text != "" and self.username.text != "" and self.password.text != "": 
            added = db.add_user(self.username.text, self.password.text, self.name.text)
            if added == 1:
                self.reset()
                wm.current = "login"
            elif added == 2:
                PassTooShort()
            else:
                AccAlreadyExists()
        else:
            invalidForm()

     def login(self):
        self.reset()
        wm.current = "login"

    def reset(self):
        self.username.text = ""
        self.password.text = ""
        self.name.text = ""


# Invalid input handling functions
def invalidLogin():
    pop = Popup(title='Invalid Login',
              content=Label(text='Invalid username\nor password.'),
              size_hint=(None, None), size=(400, 400))
    pop.open()

def invalidForm():
    pop = Popup(title='Invalid Form',
              content=Label(text='Invalid fields. Try again.'),
              size_hint=(None, None), size=(400, 400))

    pop.open()

def AccAlreadyExists():
    pop = Popup(title='Invalid Form (User Exists)',
              content=Label(text='Enter a unique\nUsername.'),
              size_hint=(None, None), size=(400, 400))

    pop.open()

def PassTooShort():
    pop = Popup(title='Invalid Form (Password Too Short)', content=Label(text='Password is too short. Try again.'), size_hint=(None, None), size=(400, 400))

    pop.open()


wm = WindowManager()
db = DataBase("users.db")

wm.current = "welcome"

class MyMainApp(MDApp):
    def build(self):
        self.kv = Builder.load_file("main.kv")
        return self.kv

if __name__ == "__main__":
    MyMainApp().run()

'''The below is my Kivy code:'''

<SignupScreen>:
    name: "signup"
    n: name
    username: username
    password: passw

    MDFloatLayout:
        md_bg_color: 1,1,1,1
        MDIconButton:
            icon: "arrow-left"
            pos_hint: {"center_y": .95}
            user_font_size: "30sp"
            theme_text_color: "Custom"
            text_color: rgba(26, 24, 58, 255)
            on_release:
                app.root.transition.direction = "right"
                app.root.current = "welcome"    
    
        MDLabel: 
            text: "H i !"
            font_name: "BPoppins"
            font_size: "30sp"
            pos_hint: {"center_x": .5, "center_y": .85}
            halign: "center"
            color: rgba(0, 0, 59, 255)

        MDLabel:
            text: "Create a new account"
            font_name: "MPoppins"
            font_size: "18sp"
            pos_hint: {"center_x": .5, "center_y": .79}
            halign: "center"
            color: rgba(135, 135, 193, 255)

        MDFloatLayout:   #Creating name
            size_hint: .45, .07
            pos_hint: {"center_x": .5, "center_y": .68}
            TextInput:
                id: name
                hint_text: "Name"
                font_name: "MPoppins"
                pos_hint: {"center_x": .445, "center_y": .5}
                background_color: 1,1,1,0          
                foreground_color: rgba(0,0,59,255)
                cursor_color: rgba(0,0,59,255)
                font_size: "14sp"
                cursor_width: "2sp"
                multiline: False
            MDFloatLayout:
                pos_hint: {"center_x": .45, "center_y": 0}
                size_hint_y: .03
                md_bg_color: rgba(178, 178, 178, 255)
    

        MDFloatLayout:   #Creating username
            size_hint: .45, .07
            pos_hint: {"center_x": .5, "center_y": .56}
            TextInput:
                id: username  
                hint_text: "Username"
                font_name: "MPoppins"
                pos_hint: {"center_x": .445, "center_y": .5}
                background_color: 1,1,1,0
                foreground_color: rgba(0,0,59,255)
                cursor_color: rgba(0,0,59,255)
                font_size: "14sp"
                cursor_width: "2sp"
                multiline: False
            MDFloatLayout:
                pos_hint: {"center_x": .45, "center_y": 0}
                size_hint_y: .03
                md_bg_color: rgba(178, 178, 178, 255)
    

        MDFloatLayout:   #Creating password
            size_hint: .45, .07
            pos_hint: {"center_x": .5, "center_y": .44}
            TextInput:
                id: passw
                hint_text: "Password"
                font_name: "MPoppins"
                pos_hint: {"center_x": .445, "center_y": .5}
                background_color: 1,1,1,0
                foreground_color: rgba(0,0,59,255)
                cursor_color: rgba(0,0,59,255)
                font_size: "14sp"
                cursor_width: "2sp"
                multiline: False
                password: True
            MDFloatLayout:
                pos_hint: {"center_x": .45, "center_y": 0}
                size_hint_y: .03
                md_bg_color: rgba(178, 178, 178, 255)

        Button:   #Creating log in button
            text: "SIGN UP"
            size_hint: .35, .065
            pos_hint: {"center_x": .5, "center_y": .3}
            background_color: 0,0,0,0
            font_name: "BPoppins"
            canvas.before:
                Color:
                    rgb: rgba(52, 0, 231, 255)
                RoundedRectangle:
                    size: self.size
                    pos: self.pos
                    radius: [5]
            on_release:            
                app.root.transition.direction = "right"
                root.submit()
                     

        MDLabel:
            text: "or"
            color: rgba(52, 0, 231, 255)
            pos_hint: {"center_y": 0.2}
            font_size: "13sp"
            font_name: "BPoppins"
            halign: "center"
        MDFloatLayout:   
            md_bg_color: rgba(178, 178, 178, 255)
            size_hint: .162, .002
            pos_hint: {"center_x": .405, "center_y": .196}
        MDFloatLayout:   
            md_bg_color: rgba(178, 178, 178, 255)
            size_hint: .162, .002
            pos_hint: {"center_x": .595, "center_y": .196}

        MDTextButton:
            text: "Already have an account?"
            pos_hint: {"center_x": 0.47, "center_y": 0.15}
            color: rgba(68, 78, 132, 255)
            font_size: "12sp"
            font_name: "BPoppins"
    
        MDTextButton:
            text: "Sign in"
            font_name: "BPoppins"
            font_size: "12sp"
            pos_hint: {"center_x": 0.58, "center_y": 0.15}
            color: rgba(52, 0, 213, 255)
            on_release:
                app.root.transition.direction = "left"
                app.root.current = "login"   
        

Upvotes: 1

Views: 755

Answers (3)

Jolin
Jolin

Reputation: 27

''' database.py (The database code that I use for the above) '''
import datetime import sqlite3 import hashlib import os

class DataBase:
    def __init__(self, conn):
        self.conn = sqlite3.connect(conn)
        self.users = None
        self.load()

    def load(self):
        self.conn.execute("CREATE TABLE IF NOT EXISTS users (username VARCHAR(20) UNIQUE, name VARCHAR(50), passw BLOB, salt BLOB, createdOn DATE); ")
        self.conn.commit()

    def get_user(self, username):
        try:
            self.conn.execute("SELECT username FROM users WHERE (username = ?);", (username,))
            self.conn.commit()
            return 1
        except sqlite3.Error:
            return -1

def add_user(self, username, password, name):
    if len(list(password)) <= 3:
        return 2
    else:
        salt = os.urandom(32)
        hash = hashlib.sha512()
        hash.update(('%s%s' % (salt, password)).encode('utf-8'))
        hashPass = hash.hexdigest()

        try:
            self.conn.execute("INSERT INTO users (username, name, passw, salt, createdOn) VALUES (?, ?, ?, ?, ?)",
                              (username, name, hashPass, salt, self.get_date()))
            self.conn.commit()
            return 1
        except sqlite3.Error:
            print("error")
            return -1
        


def validate(self, username, password):
    user = self.conn.execute("SELECT * FROM users WHERE (username = ?);", (username,)).fetchall()
    if user:
        salt = user[0][3]
        hash = hashlib.sha512()
        hash.update(('%s%s' % (salt, password)).encode('utf-8'))
        hashPass = hash.hexdigest()
        if hashPass == str(user[0][2]):
            return True
        else:
            return False
    else:
        return False


@staticmethod
def get_date():
    return str(datetime.datetime.now()).split(" ")[0]

Upvotes: 0

John Anderson
John Anderson

Reputation: 38937

The root of your problem is a confusion of the name property of SignupScreen. After examining your code more closely, I see:

    MDFloatLayout:   #Creating name
        size_hint: .45, .07
        pos_hint: {"center_x": .5, "center_y": .68}
        TextInput:
            id: name

and:

<SignupScreen>:
    name: "signup"
    n: name
    username: username
    password: passw

Any Screen has a name property that identifies the Screen to its ScreenManager. I believe your code is confusing this name property with the name of that the user is expected to enter in the TextInput with the id of name. I suggest you use a different id and ObjectProperty to keep these properties clear. For example, you cold change the first bit of code to:

    MDFloatLayout:   #Creating name
        size_hint: .45, .07
        pos_hint: {"center_x": .5, "center_y": .68}
        TextInput:
            id: personname  # different id to clear up confusion

and in the SignupScreen rule:

<SignupScreen>:
    name: "signup"
    personname: personname
    username: username
    password: passw

and, of course, this requires corresponding changes in the SignupScreen code:

class SignupScreen(Screen):
    personname = ObjectProperty(None)
    username = ObjectProperty(None)
    password = ObjectProperty(None)

    def submit(self):
        if self.personname.text != "" and self.username.text != "" and self.password.text != "":
            added = db.add_user(self.username.text, self.password.text, self.personname.text)
            if added == 1:
                self.reset()
                wm.current = "login"
            elif added == 2:
                PassTooShort()
            else:
                AccAlreadyExists()
        else:
            invalidForm()

    def login(self):
        self.reset()
        wm.current = "login"

    def reset(self):
        self.username.text = ""
        self.password.text = ""
        self.personname.text = ""

Upvotes: 1

John Anderson
John Anderson

Reputation: 38937

self.name is a string:

<SignupScreen>:
    name: "signup"

to trying to access self.name.text will throw that exception. Just use self.name without the .text.

Upvotes: 0

Related Questions