I'm creating a password manager using PySide2 and Qt Designer. The way it works is, I have a class MainWindow
. When initiated it reads a .csv
file with all my passwords (later I'm gonna switch it to a database), creates an Account
object out of each entry and adds them to a list called self.all_accounts
Here is my MainWindow
class:
class MainWindow(QMainWindow):
"""The class responsible for showing the main window"""
def __init__(self):
with open('passwords.csv', 'r') as f:
data = [i.strip('\n') for i in f.readlines()]
self.all_accounts = [] #list that holds all my accounts
for i in range(1, len(data)):
values = data[i].split(',')
a = Account(*values)
self.all_accounts.append(a)
QMainWindow.__init__(self)
self.ui = Ui_MainWindow() # class autogenerated by Qt Designer
self.ui.setupUi(self)
...
self.load_passwords()
def edit_account(self, account): #is used in self.load_passwords in editBtn QButton
"""Function responsible for editing an account. Loads a new frame replacing the main one"""
self.ui.contentContainer.setHidden(True)
editWindow = EditFrame(self, account)
editWindow.show_frame()
def show_hide_password(self, account, label, button): #see Account class
"""Function responsible for showing or hiding the password in a QLabel"""
if account.hidden:
label.setText(account.shown_password)
button.setIcon(self.hide_password_icon)
account.hidden = False
else:
label.setText(account.hidden_password)
button.setIcon(self.show_password_icon)
account.hidden = True
def load_passwords():
"""Loads all passwords from self.all_accounts to show on the main window"""
for account in self.all_accounts:
...
passwordLabel = QLabel(frame) #QLabel that shows the password
passwordLabel.setFont(font)
passwordLabel.setStyleSheet(u"border:none")
passwordLabel.setText(account.hidden_password)
horizontalLayout.addWidget(passwordLabel, 0, Qt.AlignHCenter)
copyBtn = QPushButton(frame)
copyBtn.setMinimumSize(QSize(0, 38))
copyBtn.setMaximumSize(QSize(60, 16777215))
copyBtn.setFont(font)
copyBtn.setStyleSheet(u"QPushButton{border: none;background-color: rgb(26, 156, 124)} QPushButton:hover{background-color: rgb(97, 176, 147);QPushButton:pressed{background-color: rgb(145, 218, 190)}")
copyBtn.setText('Copy')
copyBtn.clicked.connect(lambda account=account: pyCopy(account.shown_password)) #from pyperclip import copy as pyCopy
horizontalLayout.addWidget(copyBtn)
editBtn = QPushButton(frame)
editBtn.setMinimumSize(QSize(0, 38))
editBtn.setMaximumSize(QSize(70, 16777215))
editBtn.setFont(font)
editBtn.setStyleSheet(u"QPushButton{border: none; background-color: rgb(26, 156, 124)}QPushButton:hover{background-color: rgb(97, 176, 147)}QPushButton:pressed{background-color: rgb(145, 218, 190)}")
editBtn.setText('Edit')
editBtn.clicked.connect(lambda account=account: self.edit_account(account))
horizontalLayout.addWidget(editBtn)
showHideBtn = QPushButton(frame)
showHideBtn.setMinimumSize(QSize(40, 38))
showHideBtn.setMaximumSize(QSize(40, 16777215))
showHideBtn.setStyleSheet(u"QPushButton{border: none;background-color: rgb(26, 156, 124)}QPushButton:hover{background-color: rgb(97, 176, 147)}QPushButton:pressed{background-color: rgb(145, 218, 190);}")
showHideBtn.setIconSize(QSize(96, 96))
showHideBtn.setIcon(self.show_password_icon)
showHideBtn.clicked.connect(lambda account=account, label=passwordLabel, button=showHideBtn: self.show_hide_password(account, label, button))
horizontalLayout.addWidget(showHideBtn)
...
My Account
class:
class Account:
__next_id = 1
def __init__(self, name, domain, username, password, id_=None, date=None):
self.name = name
self.hidden_password = self.hide_password(password)
self.shown_password = password
self.domain = domain
self.username = username
self.logo = 'default.png'
if id_ == None:
self.id = self.__next_id
else:
self.id = id_
Account.__next_id += 1
if date == None:
self.date = datetime.strftime(datetime.now(), '%d %b, %Y; %H:%M:%S')
else:
self.date = date
self.hidden = True
def hide_password(self, password):
hidden_password = ''
for _ in password:
hidden_password += '\u25cf'
return hidden_password
Each password is stored in a QFrame
and has several QLabel
s showing the content of an account (name of the website, username, domain, etc.) and 3 buttons:
copyBtn
: copies the password to the clipboardeditBtn
: opens a new frame replacing the main one where you can edit the contents of an account. The frame is created via a class I wrote,EditFrame
(I didn't post the class because I don't think it's part of the problem, but I will post it if it's necessary)showHideBtn
: responsible for showing or "hiding" the password in passwordLabel
The problem is, that while editBtn
works fine, copyBtn
and editBtn
raises AttributeError: 'bool' object has no attribute 'shown_password'
whenever click it.
Full traceback:
277 <lambda> main.py
editBtn.clicked.connect(lambda account=account: self.edit_account(account))
102 edit_account main.py
editWindow = EditFrame(self, account)
405 __init__ main.py
self.domainEdit.setText(account.domain)
AttributeError:
'bool' object has no attribute 'domain'
and
259 <lambda> main.py
copyBtn.clicked.connect(lambda account=account: pyCopy(account.shown_password))
AttributeError:
'bool' object has no attribute 'shown_password'
If you're can't trace the errors to some classes please refer to the GitHub repository at the end of the post. I didn't post all the classes because the post will be too long.
I have no idea why. For some reason it reads my Account
object as bool
, and the weird part for me is that showHideBtn
works just fine even though I use it there too.
If you're interested, here's the link to the GitHub repository of the project https://github.com/AyazAhmadov/Password-Manager.git.
I know the code is messy, so if anything is unclear please let me know.
Edit: added traceback