0

I have a getFile function which will get the address of the csv file and print the filename in the command console. When I run the function in the main window, I keep getting "'bool' object has no attribute 'filename'". Why is this happening?

ttreadfile.py

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def getFile(self):
    """this function will get the address of the sdv file location"""
    self.filename = QFileDialog.getOpenFileName(filter = "csv (*.csv)")[0]
    print("File:",self.filename)

ttool.py

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from Module.ttreadfile import *

class ApplicationWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        """set layout of window"""
        self.main_widget = QWidget(self)

        l = QGridLayout(self.main_widget)
        open_button =QPushButton('Open')
        open_button.clicked.connect(getFile)

        l.addWidget(open_button, 0,0)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    aw = ApplicationWindow()
    aw.setWindowTitle("PyQt5 Matplot Example")
    aw.show()
    #sys.exit(qApp.exec_())
    app.exec_()

1 Answers1

0

The QPushButton widget inherits the clicked signal from QAbstractButton which is the parent class of QCheckBox as well. As such when the clicked signal is emitted it is sent with a default checked Boolean argument that indicates the button's check state. For QPushButton this argument is always False and is often ignored or omitted in slots connected to the signal.

What is happening in your situation is that the self parameter of your getFile function is being filled with the value of the checked argument which is a boolean and therefore does not have a filename attribute.

Also since getFile is not a method of the ApplicationWindow class it doesn't receive self as it's default first argument like it would if you were calling self.getFile.

A work around is to simply assign the clicked signal to and intermediate method that can trigger the getFile function with the appropriate argument.

For example

class ApplicationWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        ...
        open_button.clicked.connect(self.get_file)

    def get_file(self):
        getFile(self)

Or as suggested in the comments you can simply use a lambda to trigger the function:

open_button.clicked.connect(lambda : getFile(self))

I also suggest changing the signature of your getFile function for the sake of clarity and readability.

For example:

def getFile(instance):
    """this function will get the address of the sdv file location"""
    instance.filename = QFileDialog.getOpenFileName(filter = "csv (*.csv)")[0]
    print("File:",instance.filename)
Alexander
  • 16,091
  • 5
  • 13
  • 29
  • @HoneyWeGOTissues if it is just a simple function like readData then all you need to is call `readData(self)` from the getFile function.... or if you made changes I suggested it would be `readData(instance)`. The `self` keyword is best reserved for instance methods. – Alexander Sep 26 '22 at 21:18
  • Both ways work splendidly! Thank you! I am now trying to call another function (def readData(self)) from the getFile function and I am getting the error "ApplicationWindow object has no attribute 'readData'"...do you know why this occurs? I added self.readData() to the getFile function, thinking that it will call the function, but it is not :( Is this occurring because I didn't create a class? – HoneyWeGOTissues Sep 26 '22 at 21:21
  • @HoneyWeGOTissues I suggest giving a careful read to [python docs intro to classes](https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes) it should hopefully clarify your confusion. – Alexander Sep 26 '22 at 21:46
  • This solution is a quite dubious. There's no need to pass in an instance at all. Just return `filename` from `getFile`, and then do e.g. `def get_file(self): filename = getFile()`. Let the caller decide what to do with the return value. Generally speaking, it's bad practice to create utility functions that modify their agurments or that have indirect side-effects. In this particular case, I doubt whether it's even necessary to create an attribute, since `filename` will probably only be used within the `get_file` slot itself (e.g. to open the csv file). – ekhumoro Sep 27 '22 at 17:12
  • @ekhumoro Of course, or they could simply make the slot an instance method and then the OPs original question would work as expected. This solution seemed to take the least amount of refactoring. – Alexander Sep 27 '22 at 18:51