How to Run Python Shell ( or any other shell ) with QProcess
-
Hi All,
I want make an QWidget application on Windows with Qt6. My main goal is to open a python shell and then send some python scripts line by line.
Here is my code:
When i run the code, I can see from my task manager that python.exe is invoked under my application but, no valid output is returned.
I suspect that either i can not write to python shell or i cannot read from it.
What am i missing in here?
-
@MK97w Please post code as text not pictures.
After writing to the process you should wait for output instead of directly trying to read stdout (https://doc.qt.io/qt-6/qiodevice.html#waitForReadyRead). -
@jsulm Thank you for the advice.
void MainWindow::on_pushButton_clicked()
{
QProcess *childProcess1 = new QProcess(this);
QString program = "python.exe";
QStringList arguments{};
childProcess1->setCreateProcessArgumentsModifier(
[](QProcess::CreateProcessArguments *args) {
//args->flags |= CREATE_NEW_CONSOLE;
args->startupInfo->dwFlags &=~ STARTF_USESTDHANDLES;
});
childProcess1->setInputChannelMode( QProcess::ForwardedInputChannel );
childProcess1->setProcessChannelMode( QProcess::ForwardedChannels );
childProcess1->start( program, arguments , QIODevice::ReadWrite | QIODevice::Text );
childProcess1->waitForStarted();
childProcess1->write("2+2\n");
//childProcess1->waitForBytesWritten();
childProcess1->waitForReadyRead();
qDebug()<<"output:"<<childProcess1->readAll()<<"\n";
}i added waitForReadyRead and also waitForBytesWritten. They all got timeout. With this method i couldn't read the result of 2+2 either.
-
@MK97w
There are so many possibilities as to what might be needed or what might ot might not work here. In principle I would expect you can get this working.I would start by building tests up slowly. For example: let's start without sending it any input and just see if can get output? Invoke as
python \path\to\script.py
, where that file contains, say, someprint()
statements. (I think you can also invoke aspython -c "print('Hello world')"
) Does it run? Do you get the output back to your calling Qt program? Does it finish and exit properly? Don't forget to put error handling in, certainly while you are trying to develop. -
Thanks @JonB !
I have added two test cases
QStringList arguments = QStringList()<<"-c"<<"print('Hello World!')"; //test 1
QStringList arguments = QStringList()<<"python"<<"mert.py"; //test 2 (mert.py has only one print statement)
With both cases, i was able to see expected output.
-
@MK97w said in How to Run Python Shell ( or any other shell ) with QProcess:
childProcess1->setInputChannelMode( QProcess::ForwardedInputChannel );
childProcess1->setProcessChannelMode( QProcess::ForwardedChannels );
BTW, I'm not at all sure about these. Especially the second one. It would make any output received from the child appear on parent's stdout, which isn't attached anywhere. Not sure you'd see it, and not sure how these interact with your
write()
andreadAll()
. I would comment them both out/try with & without for your tests. AFAIR, your "exchange" should work without them in your code. -
@MK97w
My latest post crossed with your latest one.OK, so in
"python"<<"mert.py"
case try something like this in the script:print("Hello world") # try with and without a terminating `\n`, and/or does Python have a `flush()` statement? sleep(30) # whatever for this in Python
Now the question is: when do you receive the `Hello world"? Before or after the 30 seconds?
-
For your previous post;
Indeed, i got output by removing these two modifiers
childProcess1->setInputChannelMode( QProcess::ForwardedInputChannel );
childProcess1->setProcessChannelMode( QProcess::ForwardedChannels );For your latest post:
Test Case :
import time
print('test output1')
time.sleep(30)Result: "test output\n" printed after 30 seconds
(But i had to change the timeout value of waitForReadyRead()) -
Works for me.
#include <QCoreApplication> #include <QProcess> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QString prg = "C:/Users/posktomten/AppData/Local/Programs/Python/Python310/python.exe"; QStringList ARG; ARG << "-c" << "print(int(2)+int(2))"; QProcess *process = new QProcess(nullptr); process->setProcessChannelMode(QProcess::MergedChannels); process->start(prg, ARG); QObject::connect(process, &QProcess::readyReadStandardOutput, [process]() { QString result(process->readAllStandardOutput()); QTextStream(stdout) << result; }); return a.exec(); }
Clean up
#include <QCoreApplication> #include <QProcess> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QString prg = "C:/Users/posktomten/AppData/Local/Programs/Python/Python310/python.exe"; QStringList ARG; ARG << "-c" << "print(int(2)+int(2))" << "exit()"; QProcess *process = new QProcess(nullptr); process->setProcessChannelMode(QProcess::MergedChannels); process->start(prg, ARG); QObject::connect(process, &QProcess::readyReadStandardOutput, [process]() { QString result(process->readAllStandardOutput()); QTextStream(stdout) << result; QObject::connect(process, &QProcess::finished, [process]() { delete process; }); }); return a.exec(); }
Or run a script
// ARG << "-c" << "print(int(2)+int(2))" << "exit()"; ARG << "test.py";