0

If I have a list of subprocess.Popen objects, is there any way to tell what command was initially used when generating them?

Python 2.7

Context: I have a list of various commands that fire off tests. If one of the tests fails, a script cleans up the environment. I would like to then retry those failed commands only.

Note: Commands below are for demonstration purposes only; those called in my prod code are more complex, but that is beside the point. If I can this to work, it will work with my prod cmds.

commands = [['nosetests', '-V'],
        ['nosetests', '--collect-only'],
        ['nosetests', '--with-id']
        ]

def cleanup_env():
    ...do things...

def run_in_parallel(cmds, retry):
    retry_tasks = []

    if not cmds:
        return

    def done(p):
        return p.poll() is not None

    def success(p):
        return p.returncode == 0

    def fail(p):
        if not retry:
            retry_tasks.append(p)
            print("{} failed, will need to retry.".format(retry_tasks))
        else:
            pass # if this is already a retry, we don't care, not going to retry again

    MAX_PARALLEL = 4
    processes = []

    while True:
        while cmds and len(processes) < MAX_PARALLEL:
            task = cmds.pop() # pop last cmd off the stack
            processes.append(subprocess.Popen(task))

        for p in processes:
            if done(p):
                if success(p):
                    processes.remove(p)
                else:
                    fail(p)
                    processes.remove(p)

        if not processes and not cmds:
            break

        else:
            time.sleep(0.05)

    return retry_tasks

Calling the above:

retry_list=run_in_parallel(commands, False)

if retry_list:
    cleanup_env()
    run_in_parallel(retry_list, True)

The first part works, but calling the retry doesn't because I'm passing a list of subprocess.Popen objects, rather than their initial input.

Hence the question, how do I get at the input of a subprocess.Popoen object?

dbJones
  • 762
  • 1
  • 10
  • 31
  • unrelated: your `run_in_parallel()` is incorrect (don't remove items from a sequence during iteration; [use `break` instead](http://stackoverflow.com/a/12102040/4279)). [A simple way to keep the same number of parallel process is to use a thread pool](http://stackoverflow.com/a/14533902/4279) – jfs Sep 22 '15 at 00:13
  • Thanks, I'll check it out. – dbJones Sep 22 '15 at 15:14

1 Answers1

1

There is no Popen.args in Python 2.7. You could use a dictionary instead of a list for processes where keys are Popen instances and values are corressponding Popen parameters.

jfs
  • 399,953
  • 195
  • 994
  • 1,670