Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to Run Python Shell ( or any other shell ) with QProcess
Forum Updated to NodeBB v4.3 + New Features

How to Run Python Shell ( or any other shell ) with QProcess

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 4 Posters 1.7k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    MK97w
    wrote on last edited by
    #1

    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:
    45a922b8-c9ba-44ab-836a-433e92dd8c44-image.png

    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.
    Screenshot 2023-06-16 163950.png

    I suspect that either i can not write to python shell or i cannot read from it.

    What am i missing in here?

    jsulmJ 1 Reply Last reply
    0
    • M MK97w

      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:
      45a922b8-c9ba-44ab-836a-433e92dd8c44-image.png

      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.
      Screenshot 2023-06-16 163950.png

      I suspect that either i can not write to python shell or i cannot read from it.

      What am i missing in here?

      jsulmJ Online
      jsulmJ Online
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @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).

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      M 1 Reply Last reply
      2
      • jsulmJ jsulm

        @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).

        M Offline
        M Offline
        MK97w
        wrote on last edited by
        #3

        @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.

        JonBJ 2 Replies Last reply
        0
        • M MK97w

          @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.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #4

          @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, some print() statements. (I think you can also invoke as python -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.

          M 1 Reply Last reply
          0
          • JonBJ JonB

            @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, some print() statements. (I think you can also invoke as python -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.

            M Offline
            M Offline
            MK97w
            wrote on last edited by
            #5

            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.

            JonBJ 1 Reply Last reply
            0
            • M MK97w

              @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.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #6

              @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() and readAll(). I would comment them both out/try with & without for your tests. AFAIR, your "exchange" should work without them in your code.

              1 Reply Last reply
              0
              • M MK97w

                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.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @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?

                M 1 Reply Last reply
                0
                • JonBJ JonB

                  @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?

                  M Offline
                  M Offline
                  MK97w
                  wrote on last edited by
                  #8

                  @JonB

                  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())

                  JonBJ 1 Reply Last reply
                  0
                  • M MK97w

                    @JonB

                    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())

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by
                    #9

                    @MK97w
                    So not quite with you, but (a) you are better off without those channel modes and (b) it appears output from the subprocess may be "buffered" at the Python side, so you don't receive it immediately?

                    1 Reply Last reply
                    0
                    • posktomtenP Offline
                      posktomtenP Offline
                      posktomten
                      wrote on last edited by posktomten
                      #10

                      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";
                      

                      posktomten

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved