python multithreading login pyqt4 pickle

python - No se pueden cargar archivos usando pickle y múltiples módulos



multithreading login (3)

El problema es que está encurtiendo objetos definidos en Configuración ejecutando realmente el módulo ''Configuración'' , luego está tratando de desempaquetar los objetos del módulo GUI .

Recuerde que pickle en realidad no almacena información sobre cómo se construye una clase / objeto, y necesita acceso a la clase cuando se desactiva. Ver wiki sobre el uso de Pickle para más detalles.

En los datos de pkl, verá que el objeto al que se hace referencia es __main__.Manager , ya que el módulo ''Configuración'' era principal cuando creó el archivo pickle (es decir, ejecutó el módulo ''Configuración'' como script principal para invocar la función addUser ) .

Luego, intente desbloquear en ''Gui'', de modo que ese módulo tenga el nombre __main__ , y esté importando Configuración dentro de ese módulo. Entonces, por supuesto, la clase Manager será realmente Settings.Manager . Pero el archivo pkl no lo sabe, y busca la clase Manager dentro de __main__ , y lanza un AttributeError porque no existe ( Settings.Manager sí, pero __main__.Manager no).

Aquí hay un conjunto mínimo de códigos para demostrar.

El módulo class_def.py :

import pickle class Foo(object): def __init__(self, name): self.name = name def main(): foo = Foo(''a'') with open(''test_data.pkl'', ''wb'') as f: pickle.dump([foo], f, -1) if __name__==''__main__'': main()

Ejecutas lo anterior para generar los datos de pickle. El módulo main_module.py :

import pickle import class_def if __name__==''__main__'': with open(''test_data.pkl'', ''rb'') as f: users = pickle.load(f)

Ejecutas lo anterior para intentar abrir el archivo pickle, y esto arroja aproximadamente el mismo error que estabas viendo. (Ligeramente diferente, pero supongo que es porque estoy en Python 2.7)

La solución es:

  1. Hace que la clase esté disponible dentro del espacio de nombres del módulo de nivel superior (es decir, GUI o main_module) a través de una importación explícita, o
  2. Usted crea el archivo pickle desde el mismo módulo de nivel superior en el que lo abrirá (es decir, llame a Settings.addUser desde la GUI o class_def.main desde main_module). Esto significa que el archivo pkl guardará los objetos como Settings.Manager o class_def.Foo , que luego se pueden encontrar en el espacio de nombres GUI `main_module`.

Opción 1 ejemplo:

import pickle import class_def from class_def import Foo # Import Foo into main_module''s namespace explicitly if __name__==''__main__'': with open(''test_data.pkl'', ''rb'') as f: users = pickle.load(f)

Opción 2 ejemplo:

import pickle import class_def if __name__==''__main__'': class_def.main() # Objects are being pickled with main_module as the top-level with open(''test_data.pkl'', ''rb'') as f: users = pickle.load(f)

Estoy tratando de crear un sistema de usuario, que usa una configuración y un módulo Gui, y cuando el módulo GUI solicita que el archivo se cargue usando pickle, sigo recibiendo un error de atributo. esto es del módulo de configuración:

import pickle import hashlib class User(object): def __init__(self, fname, lname, dob, gender): self.firstname = fname self.lastname = lname self._dob = dob self.gender = gender self.type = ''General'' self._username = '''' self._hashkey = '''' def Report(self): print("Full Name: {0} {1}/nDate of Birth: {2}/nGender: {3}/nAccess Level: {4}".format(self.firstname,self.lastname, self._dob, self.gender, self.type)) print(self._username) def Genusername(self): self._username = str(str(self._dob)[:2] + self.firstname[:2] + self.lastname[:2]) saveUsers(users) def Genhashkey(self, password): encoded = password.encode(''utf-8'',''strict'') return hashlib.sha256(encoded).hexdigest() def Verifypassword(self, password): if self._hashkey == self.Genhashkey(password): return True else: return False class SAdmin(User): def __init__(self, fname, lname, dob, gender): super().__init__(fname, lname, dob, gender) self.type = ''Stock Admin'' class Manager(User): def __init__(self, fname, lname, dob, gender): super().__init__(fname, lname, dob, gender) self.type = ''Manager'' def saveUsers(users): with open(''user_data.pkl'', ''wb'') as file: pickle.dump(users, file, -1) # PICKLE HIGHEST LEVEL PROTOCOL def loadUsers(users): try: with open(''user_data.pkl'', ''rb'') as file: temp = pickle.load(file) for item in temp: users.append(item) except IOError: saveUsers([]) def userReport(users): for user in users: print(user.firstname, user.lastname) def addUser(users): fname = input(''What is your First Name?/n > '') lname = input(''What is your Last Name?/n > '') dob = int(input(''Please enter your date of birth in the following format, example 12211996/n> '')) gender = input("What is your gender? ''M'' or ''F''/n >") level = input("Enter the access level given to this user ''G'', ''A'', ''M''/n > ") password = input("Enter a password:/n > ") if level == ''G'': usertype = User if level == ''A'': usertype = SAdmin if level == ''M'': usertype = Manager users.append(usertype(fname, lname, dob, gender)) user = users[len(users)-1] user.Genusername() user._hashkey = user.Genhashkey(password) saveUsers(users) def deleteUser(users): userReport(users) delete = input(''Please type in the First Name of the user do you wish to delete:/n > '') for user in users: if user.firstname == delete: users.remove(user) saveUsers(users) def changePass(users): userReport(users) change = input(''Please type in the First Name of the user you wish to change the password for :/n > '') for user in users: if user.firstname == change: oldpass = input(''Please type in your old password:/n > '') newpass = input(''Please type in your new password:/n > '') if user.Verifypassword(oldpass): user._hashkey = user.Genhashkey(newpass) saveUsers(users) else: print(''Your old password does not match!'') def verifyUser(username, password): for user in users: if user._username == username and user.Verifypassword(password): return True else: return False if __name__ == ''__main__'': users = [] loadUsers(users)

y este es el módulo GUI:

from PyQt4 import QtGui, QtCore import Settings class loginWindow(QtGui.QDialog): def __init__(self): super().__init__() self.initUI() def initUI(self): self.lbl1 = QtGui.QLabel(''Username'') self.lbl2 = QtGui.QLabel(''Password'') self.username = QtGui.QLineEdit() self.password = QtGui.QLineEdit() self.okButton = QtGui.QPushButton("OK") self.okButton.clicked.connect(self.tryLogin) self.cancelButton = QtGui.QPushButton("Cancel") grid = QtGui.QGridLayout() grid.setSpacing(10) grid.addWidget(self.lbl1, 1, 0) grid.addWidget(self.username, 1, 1) grid.addWidget(self.lbl2, 2, 0) grid.addWidget(self.password, 2, 1) grid.addWidget(self.okButton, 3, 1) grid.addWidget(self.cancelButton, 3, 0) self.setLayout(grid) self.setGeometry(300, 300, 2950, 150) self.setWindowTitle(''Login'') self.show() def tryLogin(self): print(self.username.text(), self.password.text()) if Settings.verifyUser(self.username.text(),self.password.text()): print(''it Woks'') else: QtGui.QMessageBox.warning( self, ''Error'', ''Incorrect Username or Password'') class Window(QtGui.QMainWindow): def __init__(self): super().__init__() if __name__ == ''__main__'': app = QtGui.QApplication(sys.argv) users = [] Settings.loadUsers(users) if loginWindow().exec_() == QtGui.QDialog.Accepted: window = Window() window.show() sys.exit(app.exec_())

cada usuario es una clase y se coloca en una lista y luego la lista se guarda usando pickle cuando cargo solo el archivo de configuración y verifico el inicio de sesión, todo funciona bien, pero cuando abro el módulo GUI e intento verificar que no déjame, el error que estoy recibiendo:

Traceback (most recent call last): File "C:/Users`Program/LoginGUI.py", line 53, in <module> Settings.loadUsers(users) File "C:/Users/Program/Settings.py", line 51, in loadUsers temp = pickle.load(file) AttributeError: Can''t get attribute ''Manager'' on <module ''__main__'' (built-in)>


Lea primero la respuesta mencionada por zehnpaard para conocer el motivo del error de atributo. Además de la solución que ya proporcionó, en python3 puede usar la clase pickle.Unpickler y anular el método find_class como se menciona a continuación:

import pickle class CustomUnpickler(pickle.Unpickler): def find_class(self, module, name): if name == ''Manager'': from settings import Manager return Manager return super().find_class(module, name) pickle_data = CustomUnpickler(open(''file_path.pkl'', ''rb'')).load()


Si tiene una clase definida fuera del módulo, cuyo objeto está en los datos de pickle, debe importar la clase

from outside_module import DefinedClass1, DefinedClass2, DefinedClass3 with open(''pickle_file.pkl'', ''rb'') as f: pickle_data = pickle.load(f)