How to access a value (global) from another file?
-
Hello, I would like to have a program that is split into three files: 1. Main file with the entire layout and connections; 2. Worker file; 3. File where the output of the Worker file is called (and later plotted).
How can I access the output of the worker file if my program is structured like this?
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QPlainTextEdit,QVBoxLayout, QWidget, QProgressBar, QFileDialog) from PyQt5.QtCore import QProcess import sys import re progress_re = re.compile("Total complete: (\d+)%") def simple_percent_parser(output): m = progress_re.search(output) if m: pc_complete = m.group(1) return int(pc_complete) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.p = None self.btn = QPushButton("Execute") self.btn.pressed.connect(self.start_process) self.btn1 = QPushButton("Stop") self.btn1.pressed.connect(self.stop_process) self.dButton = QPushButton("Select a File") self.dButton.clicked.connect(self.getfile) self.text = QPlainTextEdit() self.text.setReadOnly(True) self.progress = QProgressBar() self.progress.setRange(0, 100) l = QVBoxLayout() l.addWidget(self.btn) l.addWidget(self.btn1) l.addWidget(self.dButton) l.addWidget(self.text) w = QWidget() w.setLayout(l) self.setCentralWidget(w) def message(self, s): self.text.appendPlainText(s) def start_process(self): if self.p is None: self.message("Executing process") self.p = QProcess() self.p.readyReadStandardOutput.connect(self.handle_stdout) self.p.readyReadStandardError.connect(self.handle_stderr) self.p.finished.connect(self.process_finished) params = ['dummy_script2.py', 'PATH_TO_THE_FILE'] self.p.start("python", params) def handle_stderr(self): data = self.p.readAllStandardError() stderr = bytes(data).decode("utf8") progress = simple_percent_parser(stderr) if progress: self.progress.setValue(progress) self.message(stderr) def handle_stdout(self): data = self.p.readAllStandardOutput() stdout = bytes(data).decode("utf8") self.message(stdout) def process_finished(self): self.message("Process finished.") self.p = None def stop_process(self): self.message("Process finished.") self.p = None def getfile(self): # global fileName filename = QFileDialog.getOpenFileName() fileName = filename[0] return fileName app = QApplication(sys.argv) w = MainWindow() w.show() app.exec_()
dummy_script2.py:
import time import sys def run(filePath): global x count =0 while True: count = count + 1 x = 2*count return x time.sleep(1) run(sys.argv[1])
call_output.py:
from dummy_script2.py import * print(x)
I would be happy to receive any tips and help!
-
@Dara1
What is " the output of the worker file"? You talk about "How to access a value (global) from another file?". If you mean theglobal x
you have indummy_script2.py
then given that you execute that script as a separate process (QtQProcess
, would be same if you used Python calls to run it) there is no chance of actually accessing any variables in the script.- Either bring your Python script's code directly into your PyQt project so you can access things from there;
- Or if you run a subprocess let it output whatever you want back and you can read and parse that via the connections you already have to subprocess's stdout/stderr. Or you could do some other kind of IPC, like sockets, but stdout/err seems fine here.
-
@JonB "If you mean the
global x
you have indummy_script2.py
" - I meant exactly this (global x)- Either bring your Python script's code directly into your PyQt project so you can access things from there; - this script is quite long and I want to avoid mixing everything together...
- Or if you run a subprocess let it output whatever you want back and you can read and parse that via the connections you already have to subprocess's stdout/stderr. Or you could do some other kind of IPC, like sockets, but stdout/err seems fine here. - I actually print an output (to check if everything is working correctly) and I didn't even think about using it this way. I just tested it and it works as expected.
Thank you very much for the help :)
-
@Dara1
Of course.Assuming you mean the stdout from your
QProcess
see void QProcess::setStandardOutputFile(const QString &fileName, QIODeviceBase::OpenMode mode = Truncate). Then the subprocess's stdout goes to file instead of to yourreadyReadStandardOutput
.If you instead mean the redirecting the stdout of your host [not
dummy_script2.py
] Qt program (e.g. where its Pythonprint()
statements go) then that's different, so say if that is what you meant. -
@JonB Indeed, I mean if it is possible to redirect the output to call_output.py.
Actually, I have a pyqtgraph which is also quite messy and I want to have it in a separate file. I don't know if that's a good idea as I already see how it slows down the speed of my app...
-
@Dara1
I don't even know if/how/where you callcall_output.py:
. Atm yourQProcess
runsdummy_script2.py
directly. If you change that to runcall_output.py
(is that what you intend?) then it's being run viaQProcess
and you can usesetStandardOutputFile()
(orreadAllStandardOutput()
) on that to grab theprint(x)
it executes. -
-
@Dara1
Your picture is pretty :), but I'm afraid I have no clear idea of what you are really trying to do.And just for example, I note you have a script,
dummy_script2.py
, which defines a method namedrun
. That uses aglobal x
, for no discernible reason much. It has awhile True
loop. Yet that has an unconditionalreturn
statement in it (notyield
). So (a) it only runs through once, (b) thetime.sleep(1)
is never executed and (c) it simply always returns the value2
. That's it. And if you invokecall_output.py
that will simplyprint(2)
. Andcall_output.py
only executesrun()
once. Anddummy_script2.py
also takes a parameter of a file path which it does not use.You will need to await someone else who understands what you are saying/trying to achieve.
All I will say is if the idea of (some combination of)
dummy_script2.py
andcall_output.py
is to produce a stream of points to plot, run aQProcess
(with one or the other of them) which spits out the desired points to stdout and your main Qt program can read that output as it arrives and plot some points. [Maybe what you intend is thatcall_output.py
repeatedly getsdummy_script2.py
to generate some data returned from a function andcall_output.py
justprint()
s that to stdout? In which case you wantQProcess
to runcall_output.py
notdummy_script.py
?] I don't know about either your file path or yourglobal x
. And if you rundummy_script2.py
as a sub-process you cannot also somehow docall_output.py
separately and have it access anything (likeglobal x
) fromdummy_script.py
. -
@JonB thank you very much :)
These are the parts of my real code...
main fileclass MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() <-- GUI loaded from another file self.ui.setupUi(self) def start_process(self): if self.p is None: self.p = QProcess() self.p.readyReadStandardOutput.connect(self.handle_stdout) params = ['file.py', arg1, arg2, arg3] self.p.start("python", params) def handle_stdout(self): data = self.p.readAllStandardOutput() stdout = bytes(data).decode("utf8") self.message(stdout)
and in plot_routine file I have:
class CustomWidget(pg.GraphicsLayoutWidget): this is a pyqtgraph class for plotting def __init__(self): pg.GraphicsLayoutWidget.__init__(self, **kargs) self.setParent(parent) self.setWindowTitle('pyqtgraph example: Scrolling Plots') def plot_plot(self): plot(stdout) if __name__ == '__main__': w = CustomWidget() w.show() QtWidgets.QApplication.instance().exec_()
The question is how can I pass stdout value from main file to the plot_routine?
-
@Dara1
Maybe I'm missing the point, butstdout
is just a string (Pythonstr
) variable, right? So either directly call a method inCustomWidget
passing it as a parameter or maybe emit a signal with it as a parameter where there is a slot attaching that to a method inCustomWidget
?