6

I need to run multiple programs one after the other and they each run in a console window. I want the console window to be visible, but a new window is created for each program. This is annoying because each window is opened in a new position from where the other is closed and steals focus when working in Eclipse.

This is the initial code I was using:

def runCommand( self, cmd, instream=None, outstream=None, errstream=None ):
    proc = subprocess.Popen( cmd, stdin=instream, stdout=outstream, stderr=errstream )

    while True:
        retcode = proc.poll()
        if retcode == None:
            if mAbortBuild:
                proc.terminate()
                return False
            else:
                time.sleep(1)
        else:
            if retcode == 0:
                return True
            else:
                return False

I switched to opening a command prompt using 'cmd' when calling subprocess.Popen and then calling proc.stdin.write( b'program.exe\r\n' ). This seems to solve the one command window problem but now I can't tell when the first program is done and I can start the second. I want to stop and interrogate the log file from the first program before running the second program.

Any tips on how I can achieve this? Is there another option for running the programs in one window I haven't found yet?

2 Answers 2

6

Since you're using Windows, you could just create a batch file listing each program you want to run which will all execute in a single console window. Since it's a batch script you can do things like put conditional statements in it as shown in the example.

import os
import subprocess
import textwrap

# create a batch file with some commands in it
batch_filename = 'commands.bat'
with open(batch_filename, "wt") as batchfile:
    batchfile.write(textwrap.dedent("""
        python hello.py
        if errorlevel 1 (
            @echo non-zero exit code: %errorlevel% - terminating
            exit
        )
        time /t
        date /t
    """))

# execute the batch file as a separate process and echo its output
kwargs = dict(stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
              universal_newlines=True)
with subprocess.Popen(batch_filename, **kwargs).stdout as output:
    for line in output:
        print line,

try: os.remove(batch_filename)  # clean up
except os.error: pass
Sign up to request clarification or add additional context in comments.

9 Comments

That would almost work. I've essentially done the same thing by writing to a command prompt that I have opened myself. But the problem there is that I cannot stop after the first command is done, inspect a log file, and then move on to the next command.
@Sean: Seems like you could intersperse invocations of your commands with one that allowed you inspect the log file and determine an exit code which the batch file can then inspect and use to determine whether to exit or continue on. Batch programs support if [not] errorlevel ... conditional processing. If you're interested I could update my answer to show how that might be done.
Thanks martineau. I did a quick search on errorlevels and batch files and found it. Thanks for the help!
@Sean: Well, I went ahead and updated my answer anyway, for others who may be interested.
Have you observed the behavior described in the question - opening new console by each process when using Popen? I don't and this would be in line with the following statement subprocess.CREATE_NEW_CONSOLE - The new process has a new console, instead of inheriting its parent’s console (the default).
|
0

In section 17.5.3.1. Constants in the subprocess module documentation there's description of subprocess.CREATE_NEW_CONSOLE constant:

The new process has a new console, instead of inheriting its parent’s console (the default).

As we see, by default, new process inherits its parent's console. The reason you observe multiple consoles being opened is the fact that you call your scripts from within Eclipse, which itself does not have console so each subprocess creates its own console as there's no console it could inherit. If someone would like to simulate this behavior it's enough to run Python script which creates subprocesses using pythonw.exe instead of python.exe. The difference between the two is that the former does not open a console whereas the latter does.

The solution is to have helper script — let's call it launcher — which, by default, creates console and runs your programs in subprocesses. This way each program inherits one and the same console from its parent — the launcher. To run programs sequentially we use Popen.wait() method.

--- script_run_from_eclipse.py ---

import subprocess
import sys

subprocess.Popen([sys.executable, 'helper.py'])

--- helper.py ---

import subprocess

programs = ['first_program.exe', 'second_program.exe']
for program in programs:
    subprocess.Popen([program]).wait()
    if input('Do you want to continue? (y/n): ').upper() == 'N':
        break

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.