Executing a command from within python using the subprocess module

Peter Otten __peter__ at web.de
Mon Feb 15 17:44:25 CET 2010


R (Chandra) Chandrasekhar wrote:

> Peter Otten wrote:
> 
>> import subprocess
>> 
>> def convert(width=5, height=30, colors=['#abcdef', '#456789'],
>>             filename="tmp/image with space in its name.png"):
>>     lookup = locals()
>>     assert all("\n" not in str(s) for s in lookup.values())
>>     subprocess.call("""\
>> convert
>> -size
>> {width}x{height}
>> gradient:{colors[0]}-{colors[1]}
>> {filename}""".format(**lookup).splitlines())
>> 
>> convert()
>> 
>> Peter
> 
> Thank you. It works. Now I need to understand why and am able to follow
> what you are doing part of the way:
> 
> 1. Assign default values in the function definition.
> 
> 2. Store the variables existing in the local namespace in the list lookup.
> 
> 3. Assert that there are no newlines in the values in lookup converted
> to strings. (Why? Is this because of splitlines() later on?)

Yes. 

> 4. Assemble a string (array?) for the subprocess.call argument using the
>   format string syntax (section 8.1.3 et seq. of the Python
> documentation for 2.6.4). Your example works with  default option of
> shell=False for subprocess.call().

I wanted to pass the executable and its arguments as a list (a python "list" 
is called array in other languages) to avoid bothering with shell escapes. 
 
> 5. I am unable to decipher how you got to format(**lookup).splitlines())
> especially the **prefix part, although I guess that splitlines() is
> dishing out the arguments one by one from each line in the
> subprocess.call argument.

Given some_dict = {key1: value1, key2: value2,...}

f(**some_dict) 

is a shortcut for

f(key1=value1, key2=value2, ...)

with the additional twist that you do not have to know the key/value pairs 
in advance.

I introduced splitlines to avoid calling the format method on every argument 
to "convert", i. e.

def convert2(width=5, height=30, colors=['#abcdef', '#456789'],
            filename="tmp/image with space in its name.png"):
    subprocess.call([
            "convert",
            "-size",
            "{width}x{height}".format(width=width, height=height),
            "gradient:{0}-{1}".format(*colors),
            filename])

I supected that it would look cleaner than the above, but now that I tried 
it I think convert2() is the better alternative.

Peter



More information about the Python-list mailing list