Python multiprocessing.Process() not working inside Qt class - linux

I'm failing to start a multiprocessing.Process() instance inside a custom Qt Gui class. You can check the entire file (and the other files) from the project here.
However, when I create it outside of the class, in the main file, it works.
I have no idea why it behaves differently for those two ways.
(I don't know if it is relevant, but I'm running this program on a BeagleboneBlack, through "ssh -X", which shows the GUI windows on my computer. (I have to do this because one of the program's libraries can only run in the Beaglebone, because its GPIO interaction library).
Code inside the class (in the init() method) (this does not work, the GUI doesn't show up):
class MainWindow2(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow2, self).__init__()
self.setupUi(self)
self.parent, self.child = multiprocessing.Pipe()
self.listener1=Listener(self.child)
self.listening_proc=multiprocessing.Process(target=listener1)
self.listening_proc.start()
Outside the class (this works):
parent, child = multiprocessing.Pipe()
listener1=Listener(child)
listening_proc=multiprocessing.Process(target=listener1)
listening_proc.start()

Related

Do class in python need parameter when we call it?

I am new to python, actually new to programming too, and I am recently working on a simple project with Tkinter. In this project, I was trying to create a force attention window and I finally got the answer from this page. The main codes are as follows:
import tkinter as tk
class App(tk.Tk):
TITLE = 'Application'
WIDTH, HEIGHT, X, Y = 800, 600, 50, 50
def __init__(self):
tk.Tk.__init__(self)
tk.Button(self, text="open popout 1", command=self.open1).grid()
tk.Button(self, text="open popout 2", command=self.open2).grid()
def open1(self):
PopOut1(self)
def open2(self):
# .transient(self) ~
# flash PopOut if focus is attempted on main
# automatically drawn above parent
# will not appear in taskbar
PopOut2(self).transient(self)
if __name__ == '__main__':
app = App()
app.title(App.TITLE)
app.geometry(f'{App.WIDTH}x{App.HEIGHT}+{App.X}+{App.Y}')
# app.resizable(width=False, height=False)
app.mainloop()
It worked though, one thing that I am still concerning is that why he specified a parameter in a class APP:
class App(tk.Tk):
However, there is nothing pass in the class when he called it:
app = App()
Can anyone answer it, or just give me some keyword that I can go search specifically. I have read some of the tutorials about class in python, but none of them mention it.
This is called inheritance. All parameters for creating an object of the class, like you did here: app = App(), are in the __init__ method.
class App(tk.Tk):
This part is not a parameter. Instead, this indicates that the App class inherits methods from the tk.Tk class. In essence, this is what turns your App class into a Tkinter application. Without it, you wouldn't have any of the functionality that Tkinter provides. Observe how at the bottom of your code, you create the app and then call app.mainloop(). Note that your App class has no mainloop method. It actually comes from the inherited tk.Tk class.
That said, this is a major topic in most languages so I don't doubt you'll find tons of resources to learn further if you simply search for "Python inheritance".

Pyside2 trigger messagebox from button click closes whole application

i want to trigger a messagebox from a button click without closing the entire application, I managed to do this in my previous project, but this time, the behavior is really unexpected. as soon as I clicked ok or the cross sign on the messagebox, the app also closing too without any error. here's the minimal example
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.set_and_load_ui()
def set_and_load_ui(self):
self.ui = QUiLoader().load('main.ui', self)
def trigger_messagebox(self):
self.messagebox()
def messagebox(self,x=""):
msg = QMessageBox(self)
msg.setIcon(QMessageBox.Information)
msg.setText("{}".format(x))
msg.setInformativeText("test")
msg.setWindowTitle("test")
msg.exec_()
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.ui.show()
# mainWindow.trigger_messagebox() #this is fine
mainWindow.ui.mainmenuButton.clicked.connect(lambda: mainWindow.trigger_messagebox()) #this is not fine
exit_code = (app.exec_())
just to check, if the messagebox itself is causing the problem, I tried to call it directly on my code, but turns out it just fine, but not when I tried to trigger it by a button click
The problem is related to the fact that QUiLoader loads the UI using the parent given as argument, and since the UI is already a QMainWindow, you're practically loading a QMainWindow into another, which is unsupported: QMainWindows are very special types of QWidgets, and are intended to be used as top level widgets.
It's unclear to me the technical reason for the silent quit, but it's certainly related to the fact that the loaded window actually has a parent (the MainWindow instance), even if that parent is not shown (since you're showing the ui).
Unfortunately, PySide doesn't provide a way to "install" a UI file to an existing instance unlike PyQt does (through the uic.loadUi function), so if you want to keep using PySide there are only two options:
do not use a main window in Designer, but a plain widget ("Widget" in the "New Form" dialog of Designer), load it using QUiLoader and use setCentralWidget() (which is mandatory, since, as the documentation also notes, "creating a main window without a central widget is not supported"):
self.ui = QUiLoader().load('main.ui', self)
self.setCentralWidget(self.ui)
The downside of this approach is that you cannot use the main window features anymore in Designer (so, no menus, status bar, dock widgets or toolbars).
use pyside-uic to generate the python code and use the multiple inheritance method to "install" it; the following assumes that you exported the ui file as mainWindow.py:
from mainWindow import ui_mainWindow
class MainWindow(QtWidgets.QMainWindow, ui_mainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# no "set_and_load_ui"
self.mainmenuButton.clicked.connect(self.trigger_messagebox)
# ...
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
exit_code = (app.exec_())
As you can see, now you can access widgets directly (there's no ui object). The downside of this approach is that you must remember to always generate the python file everytime you modify the related ui.

Can a class own a content manager in python?

I have a class that manages some shared resources and currently provides a get_X() and put_X() method to access the resources. A better interface for this would be to use a context manager for each resource as in
with ResourceManager.X() as x:
# do stuff
But my use is a QT5 Widget class that grabs the resource then it gets configured and has to release the resource when the widget is destroyed:
class MyWidget(QtGui.Widgets.QTableWidget):
def conf(self):
self.x = ResourceManager.get_x()
def closeEvent(self, event):
ResourceManager.put_x()
super().closeEvent()
So is there a more pythonic way analog to the context manager "with" construct to keep a resource allocated for the livetime of a class?
Note: Qt5 doesn't allow multiple inheritance
Update:
The Qt5 UI file loader doesn't allow passing arguments to __init__ so I have added the conf() method to configure custom widgets after the UI files are loaded. That's why the ResourceManager.get_x() isn't in __init__.
What I would like to do is to get rid of the put_x() call. I want the resource to be automatically freed by python when the class is deleted. There are many widgets and resources and it's easy to forget a put_x() somewhere so I don't want to balance get/put calls manually.
Another concern is exceptions when multiple resources are used. If the exception happens after say the 3rd resource then only those 3 should be released. Another thing I don't want to track manually.
Never used QT before, but the first thing that comes to my mind are the __init__ and __del__ methods, called respectively when a class instance is created and destroyed.
You could try the following:
class MyWidget(QtGui.Widgets.QTableWidget):
def __init__(self):
super().__init__()
self.x = ResourceManager.get_x()
def __del__(self):
ResourceManager.put_x()
super().__del__()
My unique concern is that QT actually deletes the class if it's not used anymore.
Try it and let me know
super().closeEvent()

How to overwrite parent class init method, and use super to call grandparent init, all without editing parent? (python 3)

I've written a "child" class that inherits from the pytorch "DatasetFolder" class.
The full code for the dataset folder class is available here:
https://pytorch.org/docs/stable/_modules/torchvision/datasets/folder.html#DatasetFolder
I'd like to overwrite the init method detailed there, and replace it with my own logic.
However, I'd still like to call the grandparent init.
As the parent class (datasetfolder) code is a part of an external package, I'd like to avoid editing it.
How can I overwrite the parent class init method, and still call the grandparent init, without changing the parent?
It's kinda hacky, but the two ways to do this are to just directly call the grandparent version, or to lie to super and say you are the parent, causing it to be skipped when doing the search for the next __init__ to call. So either do:
class Child(Parent):
def __init__(self, ...args...):
GrandParent.__init__(self, ...args...)
# ... rest of __init__ ...
or:
class Child(Parent):
def __init__(self, ...args...):
super(Parent, self).__init__(...args...)
# ... rest of __init__ ...

Calling parent class function before executing every child class function in Python

Here is an idea of the code
File 1
class MyParentClass(unittest.TestCase):
def setUpClass(self):
# SuperClass is already defined in the file
obj = SuperClass()
self.exp_fn = obj.create_exp_fn()
# This doesn't work
def setUp(self):
# sets up app to open the screen on which tests run (~100 lines)
File 2
from File1 import MyParentClass
class MyChildClass(MyParentClass):
def test_func_1(self):
# Start execution of its test
self.exp_fn.run_an_attribute()
def test_func_2(self):
# Start execution of its test
self.exp_fn.run_another_attribute()
I have several functions in MyChildClass and several files containing classes like MyChildClass which inherits unittest.TestCase
I want setUp to be called before executing any function of classes like MyChildClass but I don't want to individually decorate each function of MyChildClass or use the same 100 line setUp() function of unittest in all the files of MyChildClass. It should be present in MyParentClass as shown above
To run the tests I need to setUp the app such as open a specific screen, login and open another set of windows before a test can start. Or else the test won't find the element its looking for coz the app wouldn't be on the desired screen.
And the tests start from outside the app always
Is there a way to achieve the same functionality of setUp() following the above conditions. I went through the source code of run() in unittest where they use a contextmanager to implement setUp() but didn't quite get it
Would be highly obliged if anyone can suggest a solution... Thanks!!

Resources