Reference error: weakly-referenced object no longer exists (Kivy)
Сделал приложение на python 3.6 с помощью kivy. В PyCharm и в линуксе запускается и работает, но выводит предупреждение:
[WARNING] Deprecated property "<StringProperty name=id>" of object "<kivy.uix.boxlayout.BoxLayout object at 0x00000288E8284DD8>" was accessed, it will be removed in a future version.
На андройде при нажатии кнопки добавить запись в БД, закрывается и в логе ошибка
Reference error: weakly-referenced object no longer exists
но при этом запись добавляется в базу данных.
Ошибка возникает на строке
self.task.add_widget(TaskLabel(id=str(self.i[0])))
main.py
from kivy.app import App
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.uix.anchorlayout import AnchorLayout
from kivy.utils import get_color_from_hex
from kivy.core.window import Window
import sqlite3 #База данных
import hashlib #Хеширование пароля
from kivy.uix.boxlayout import BoxLayout
import speech_recognition as sr #Голосовой ввод
from gtts import gTTS
import playsound
import uuid #Генерация соли
from re import * #Проверка на email
################################################################################
Window.clearcolor = get_color_from_hex("#16203B")
################################################################################
class Register(Screen):
def disconnect(self):
self.app = App.get_running_app()
self.app.on_change_screen(self.manager.current, 'login', 'right')
self.manager.get_screen('login').resetForm()
def do_register(self, loginText, passwordText, email, password2):
self.app = App.get_running_app()
if(len(loginText) < 5):
#print('Имя пользователя должно содержать больше 4 символов')
self.app.on_error("Ошибка: Имя пользователя должно содержать больше 4 символов", self.manager.current)
else:
if(len(passwordText) < 6):
#print('Пароль должен содержать больше 5 символов')
self.app.on_error("Ошибка: Пароль должен содержать больше 5 символов", self.manager.current)
else:
if(passwordText != password2):
#print('Пароли не совпадают!')
self.app.on_error("Ошибка: Пароли не совпадают", self.manager.current)
else:
self.pattern = compile('(^|\s)[-a-z0-9_.]+@([-a-z0-9]+\.)+[a-z]{2,6}(\s|$)')
self.email_valid = self.pattern.match(email)
if not self.email_valid:
#print('Email не поддерживается, введите другой')
self.app.on_error("Ошибка: Email не поддерживается, введите другой", self.manager.current)
else:
self.conn = sqlite3.connect("users.db")
self.cursor = self.conn.cursor()
self.rows = self.cursor.execute("SELECT COUNT(*) FROM users WHERE login=?", (loginText,)).fetchone()[0]
if(self.rows == 0):
def hash_password(password):
self.salt = uuid.uuid4().hex
return hashlib.sha256(self.salt.encode() + password.encode()).hexdigest() + ':' + self.salt
try:
self.cursor.execute("INSERT INTO users VALUES (NULL, ?, ?, ?)", (loginText, hash_password(passwordText), email))
except sqlite3.DatabaseError as error:
#print ("Ошибка: ", error)
self.app.on_error("Ошибка: " + error, self.manager.current)
else:
self.conn.commit()
self.cursor.close()
self.conn.close()
self.app.on_change_screen(self.manager.current, 'login', 'right')
self.manager.get_screen('login').resetForm()
else:
#print('Имя пользователя уже используется')
self.app.on_error("Ошибка: Имя пользователя уже используется", self.manager.current)
################################################################################
class Connected(Screen):
task = ObjectProperty(None)
def __init__(self, *args, **kwargs):
super(Connected, self).__init__(*args, **kwargs)
def get_tasks_from_db(self):
self.app = App.get_running_app()
self.task.clear_widgets()
self.conn = sqlite3.connect("users.db")
self.cursor = self.conn.cursor()
try:
self.cursor.execute("SELECT id, task_text FROM tasks WHERE task_screen=? AND user_login =? ORDER BY id DESC", (self.manager.current, self.app.username))
except sqlite3.DatabaseError as error:
self.app.on_error("Ошибка: " + str(error), self.manager.current)
else:
self.rows = self.cursor.fetchall()
for self.i in self.rows:
self.app.TaskId = str(self.i[0])
self.app.TaskText = str(self.i[1])
self.task.add_widget(TaskLabel(id=str(self.i[0])))
self.cursor.close()
self.conn.close()
def talk(self, file_name):
playsound.playsound(file_name, True)
def get_voice_text(self):
self.is_speaking = True
self.r = sr.Recognizer()
self.talk("1.mp3")
with sr.Microphone() as source:
self.r.pause_threshold = 1
#r.adjust_for_ambient_noise(source, duration=1)
self.audio = self.r.listen(source)
try:
self.command = self.r.recognize_google(self.audio, language="ru-RU").lower()
self.talk("2.mp3")
self.add_task(self.command)
except sr.UnknownValueError:
self.talk("3.mp3")
self.is_speaking = False
def add_task(self, task_text):
self.app = App.get_running_app()
self.conn = sqlite3.connect("users.db")
self.cursor = self.conn.cursor()
if(len(task_text) > 0):
if(len(task_text) < 56):
try:
self.cursor.execute("INSERT INTO tasks VALUES (NULL, ?, ?, ?)", (task_text, self.manager.current, self.app.username))
except sqlite3.DatabaseError as error:
self.app.on_error("Ошибка: " + error, self.manager.current)
else:
self.conn.commit()
self.cursor.close()
self.conn.close()
self.get_tasks_from_db()
else:
self.app.on_error("Ошибка: Текст заметки не может быть длиннее 55 символов", self.manager.current)
else:
self.app.on_error("Ошибка: Текст заметки не задан", self.manager.current)
def disconnect(self):
self.app = App.get_running_app()
self.app.on_change_screen(self.manager.current, 'login', 'right')
self.manager.get_screen('login').resetForm()
#################################################################################
class TaskLabel(BoxLayout):
def __init__(self, *args, **kwargs):
super(TaskLabel, self).__init__(*args, **kwargs)
def remove_task(self, id):
self.app = App.get_running_app()
self.conn = sqlite3.connect("users.db")
self.cursor = self.conn.cursor()
try:
self.cursor.execute("DELETE FROM tasks WHERE id=?", (id,))
except sqlite3.DatabaseError as error:
self.app.on_error("Ошибка: " + (error), self.manager.current)
else:
self.conn.commit()
self.cursor.close()
self.conn.close()
################################################################################
class Login(Screen):
def __init__(self, *args, **kwargs):
super(Login, self).__init__(*args, **kwargs)
def do_login(self, loginText, passwordText):
self.app = App.get_running_app()
self.app.username = loginText
self.app.password = passwordText
self.conn = sqlite3.connect("users.db")
self.cursor = self.conn.cursor()
self.cursor_row = self.conn.cursor()
self.cursor.execute("SELECT password FROM users WHERE login=?", (loginText,))
self.rows = self.cursor_row.execute("SELECT COUNT(*) FROM users WHERE login=?", (loginText,)).fetchone()[0]
if(self.rows > 0):
self.hashed_password = "".join(self.cursor.fetchone())
self.pass_without_salt, self.salt = self.hashed_password.split(':')
self.salt = "".join(self.salt)
self.pass_without_salt = "".join(self.pass_without_salt)
def hash_password(password, salt):
return hashlib.sha256(salt.encode() + password.encode()).hexdigest()
def checkPassword(password):
if hash_password(password, self.salt) == self.pass_without_salt:
return True
if((self.rows > 0) and checkPassword(passwordText)):
self.app.on_change_screen(self.manager.current, 'connected', 'left')
else:
self.app.on_error("Ошибка: Неверный логин или пароль", self.manager.current)
self.cursor_row.close()
self.cursor.close()
self.conn.close()
def resetForm(self):
self.ids['login'].text = ""
self.ids['password'].text = ""
def do_register(self):
self.app = App.get_running_app()
self.app.on_change_screen(self.manager.current, 'register', 'left')
################################################################################
class ErrorMessageWidget(AnchorLayout):
pass
################################################################################
class LoginApp(App):
username = StringProperty(None)
password = StringProperty(None)
def __init__(self, *args, **kwargs):
super(LoginApp, self).__init__(*args, **kwargs)
def on_change_screen(self, screen, target_screen, transition):
self.root.transition = SlideTransition(direction=transition)
self.root.current = target_screen
for child in self.root.get_screen(screen).children[:]:
if child.id == 'error':
self.root.get_screen(screen).remove_widget(child)
def on_error(self, error, screen):
self.ErrorMessage = error
self.root.get_screen(screen).add_widget(ErrorMessageWidget(id='error'))
def build(self):
manager = ScreenManager()
manager.add_widget(Login(name='login'))
manager.add_widget(Connected(name='connected'))
manager.add_widget(Register(name='register'))
return manager
################################################################################
if __name__ == '__main__':
LoginApp().run()
login.kv
<Register>:
BoxLayout
id: register_layout
orientation: 'vertical'
padding: [10,50,10,50]
spacing: 30
Label:
text: '\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F'
#Регистрация
font_size: 32
color: 0, 0, 0, 1
size_hint_y: .1
AnchorLayout:
size_hint_y: .8
BoxLayout:
orientation: 'vertical'
size_hint_y: None
spacing: 10
TextInput:
id: login
multiline:False
font_size: 20
hint_text: '\u041B\u043E\u0433\u0438\u043D'
size_hint_y: None
size_hint_x: .5
pos_hint: {'x': .25}
height: 40
padding: [5, 8]
TextInput:
id: email
multiline:False
font_size: 20
hint_text: '\u042D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430\u044F\u0020\u043F\u043E\u0447\u0442\u0430'
size_hint_y: None
size_hint_x: .5
pos_hint: {'x': .25}
height: 40
padding: [5, 8]
TextInput:
id: password
multiline:False
password:True
hint_text: '\u041F\u0430\u0440\u043E\u043B\u044C'
font_size: 20
size_hint_y: None
size_hint_x: .5
pos_hint: {'x': .25}
height: 40
TextInput:
id: password_verify
multiline:False
password:True
hint_text: '\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435\u0020\u043F\u0430\u0440\u043E\u043B\u044C'
font_size: 20
size_hint_y: None
size_hint_x: .5
pos_hint: {'x': .25}
height: 40
BoxLayout:
orientation: 'horizontal'
spacing: 10
size_hint_y: .1
Button:
text: '\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C\u0441\u044F'
#Зарегистрироваться
font_size: 24
color: 0, 0, 0, 1
background_color: 1, 1, 1, .5
on_press: root.do_register(login.text, password.text, email.text, password_verify.text)
Button:
text: "\u041D\u0430\u0437\u0430\u0434"
#Назад
font_size: 24
color: 0, 0, 0, 1
background_color: 1, 1, 1, .5
on_press: root.disconnect()
################################################################################
<Connected>:
on_enter: root.get_tasks_from_db()
task: task.__self__
BoxLayout:
orientation: 'vertical'
spacing: 20
padding: [10,50,10,50]
Label:
text: u"\u0412\u0432\u0435\u0434\u0438\u0442\u0435\u0020\u0442\u0435\u043A\u0441\u0442\u0020\u0437\u0430\u043C\u0435\u0442\u043A\u0438"
#Введите текст заметки
font_size: 24
color: 0, 0, 0, 1
size_hint_y: .1
pos_hint: {'center_x': .5}
BoxLayout:
orientation: 'horizontal'
size_hint_y: .2
TextInput:
id: task_input
multiline:True
font_size: 20
padding: [5, 0]
Button:
text: 'Voice'
on_press: root.get_voice_text()
size_hint_x: .1
color: 0, 0, 0, 1
background_color: 1, 1, 1, .5
BoxLayout:
orientation: 'horizontal'
size_hint_y: .1
spacing: 20
Button:
text: u"\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C\u0020\u0437\u0430\u043C\u0435\u0442\u043A\u0443"
#Добавить заметку
font_size: 24
color: 0, 0, 0, 1
background_color: 1, 1, 1, .5
on_press: root.add_task(task_input.text); task_input.text = ""
Button:
text: u"\u0421\u043C\u0435\u043D\u0438\u0442\u044C\u0020\u0430\u043A\u043A\u0430\u0443\u043D\u0442"
#Сменить аккаунт
font_size: 24
color: 0, 0, 0, 1
background_color: 1, 1, 1, .5
on_press: root.disconnect()
ScrollView:
bar_width: 4
scroll_type: ['bars']
bar_inactive_color: 5, 20, 10, .5
bar_color: 5, 10, 15, .8
size_hint_y: .6
BoxLayout:
orientation: 'vertical'
id: task
size_hint_y: None
height: self.minimum_height
################################################################################
<TaskLabel>:
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: 0, 0, 0, 1
Line:
width: 1
rectangle: self.x, self.y, self.width, self.height
orientation: 'horizontal'
Label:
text_size: (self.width-20, self.height)
halign: 'left'
valign: 'middle'
text: str(app.TaskText)
font_size: 24
color: 0, 0, 0, 1
Button:
text: "X"
font_size: 24
color: 0, 0, 0, 1
size_hint: (.1, 1)
background_color: 1, 1, 1, 0
on_press: root.remove_task(root.id); root.parent.remove_widget(root);
################################################################################
<Login>:
BoxLayout
id: login_layout
orientation: 'vertical'
padding: [10,50,10,50]
spacing: 30
Label:
text: u'\u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F'
#Авторизация
font_size: 32
color: 0, 0, 0, 1
size_hint_y: .1
AnchorLayout:
size_hint_y: .8
BoxLayout:
orientation: 'vertical'
size_hint_y: None
spacing: 10
TextInput:
id: login
multiline:False
font_size: 20
hint_text: '\u041B\u043E\u0433\u0438\u043D'
size_hint_y: None
size_hint_x: .5
pos_hint: {'x': .25}
height: 40
padding: [5, 8]
TextInput:
id: password
multiline:False
password:True
hint_text: '\u041F\u0430\u0440\u043E\u043B\u044C'
font_size: 20
size_hint_y: None
size_hint_x: .5
pos_hint: {'x': .25}
height: 40
BoxLayout:
orientation: 'horizontal'
spacing: 10
size_hint_y: .1
Button:
text: '\u0412\u043E\u0439\u0442\u0438'
#Войти
font_size: 24
color: 0, 0, 0, 1
background_color: 1, 1, 1, .5
on_press: root.do_login(login.text, password.text)
Button:
text: '\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F'
#Регистрация
font_size: 24
color: 0, 0, 0, 1
background_color: 1, 1, 1, .5
on_press: root.do_register()
<ErrorMessageWidget>:
anchor_x: "center"
anchor_y: "top"
Button:
text: app.ErrorMessage
background_color: 1, 0, 0, 1
size_hint_y: .05
on_press: root.parent.remove_widget(root)
Ответы (1 шт):
Автор решения: Skullage
→ Ссылка
Переустановил linux, поставил xubuntu, убрал некоторые зависимости в buildozer.spec и проблема решилась