Python subprocess run() with multiple arguments on Windows

Question:

I’ve run into a problem trying to start a game with some additional parameters. Normally you enter them in the "target line" on Windows, such as:

"C:PathTogame.exe" --arg --arg2 --arg3 abc --arg4 xyz

There are both arguments that are simply the argument like –arg and –arg2, then there are other arguments that require another value, such as "–arg3 50".

I have already figured out how to run multiple arguments in a fixed manner such as below, "localconfig_data["exe"]" contains the path as "C:PathTogame.exe".

subprocess.run([localconfig_data["exe"], "--editor", "--erode 100"])

My issue is that depending on previous selections in my program, I could end up with around 10 different arguments which makes it quite impractical to make cases for all different options.

What I’ve tried that doesn’t work:

args_string = "--editor --erode 100 --hidden-hud" #args_string is made in a for loop depending on the arguments given
subprocess.run([localconfig_data["exe"], args_string])

Outcome is that nothing happens. My next best idea was to try to print it out:

args_list = ["--editor", "--erode 100", "--hidden-hud"]
subprocess.run([localconfig_data["exe"], for a in args_list: print(a)])

This gives me a syntax error: SyntaxError: did you forget parentheses around the comprehension target?, so it was a proof of concept in my mind.

Final question: how can I add all of my arguments dynamically when launching a program with subprocess.run() ?

Asked By: Wahlmat

||

Answers:

Found the solution to this after some testing. What I ended up doing was building a string for the entire command to execute at once. First part of the string was subprocess.run() with the path, followed by a for loop with all the arguments and finally the closing brackets for the subprocess. Example below.

argslist = ["--arg1", "--arg2", "--arg3"]
executeString = 'subprocess.run([localconfig_data["exe"]'

for argument in argslist:
   executeString += ', "'
   executeString += argument
   executeString += '"'

executeString += "])"
print(executeString)
>>> subprocess.run([localconfig_data["exe"], "--arg1", "--arg2", "--arg3"])

If one argument contains more than one word, such as "–argument value", you just pass this as 2 following values, as "–argument", "value".

Answered By: Wahlmat

The subprocess.run function expects the whole command as list of arguments. So assuming you’d want to execute the command

$ "C:PathTogame.exe" --arg --arg2 --arg3 abc --arg4 xyz

you need to call subprocess.run with the list ['C:PathTogame.exe', '--arg', '--arg2', '--arg3', 'abc', '--arg4', 'xyz']:

subprocess.run(['C:PathTogame.exe', '--arg', '--arg2', '--arg3', 'abc', '--arg4', 'xyz'])

The problem with the way you do it, is that you put a list inside of an other list, you need all the arguments on the same level. You can acieve this by unpacking the arguments list into the calling list.

>>> ['app.exe', args_list]
['app.exe', ['--editor', '--erode 100', '--hidden-hud']]
>>> ['app.exe', *args_list] # unpacking
['app.exe', '--editor', '--erode 100', '--hidden-hud']

So:

subprocess.run([localconfig_data["exe"], *args_string])

Your attempt with the list was right, list comprehension doesn’t work with fixed list elements because of scopal ambiguity ([a, b for b in some_list] could mean [(a, b) for b in some_list] as well as [a, (b) for b in some_list], hence the insistence on parantheses).

Answered By: Lone Lunatic