A canceled file dialog returns an empty string as first parameter; since open() expects a valid file path or object, it will raise a FileNotFoundError exception, since '' is obviously not a valid file path.
In the exception you used a string as argument for the QDialog() constructor, which is wrong since, like most widgets, it can only accept a QWidget as first positional argument (only strictly text based widgets accept a string).
The proper way to handle a canceled file dialog static method is to check if the path argument is empty. Then, if the file does exist but you want to show an error message if anything wrong happens in the open block, you should use a QMessageBox instead, as a basic QDialog is practically an empty widget.
def open_file(self):
filename, _ = QFileDialog.getOpenFileName(self, 'Open File', expanduser("~"))
if not filename:
return
try:
with open(filename, 'r') as f:
text = f.read()
self.path = filename
self.textEdit.setPlainText(text)
self.setWindowTitle(f'{filename} - QtNotepad')
except Exception as e:
QMessageBox.warning(self, 'Error',
f'The following error occurred:\n{type(e)}: {e}')
return
Whenever you get a crash, you must try to run your script in a terminal or prompt (using an IDE is not always enough) so that you can get the full traceback of the error which will probably explain why the program crashed.
Also, adding print statements of the exception right at the beginning of their handlers will help you understand the reason for those exceptions.