From: R (Chandra) Chandrasekhar on
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

One other question I forgot to ask is this why is there a terminal
backslash in

> subprocess.call("""\

Removing the backslash makes the function fail.

I wonder why, because """ is supposed to allow multi-line strings. I am
sorry if this sounds obtuse but that backslash baffles me.
From: Steve Holden on
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
>
> One other question I forgot to ask is this why is there a terminal
> backslash in
>
>> subprocess.call("""\
>
> Removing the backslash makes the function fail.
>
> I wonder why, because """ is supposed to allow multi-line strings. I am
> sorry if this sounds obtuse but that backslash baffles me.

It does, but a leading newline would cause the splitlines() result to
start with an empty word - the backslash just causes the interpreter to
ignore the newline immediately following, rather than including it in
the string literal's value.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
PyCon is coming! Atlanta, Feb 2010 http://us.pycon.org/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/

From: R (Chandra) Chandrasekhar on
Alf P. Steinbach wrote:
> * R (Chandra) Chandrasekhar:
>>
>> width = 5
>> height = 30
>> colors = ['#abcdef]', '#456789']
>> filename = "/tmp/image.png"
>>
>> # I want to get the equivalent of variable interpolation in Perl
>> # so that the command
>> #
>> # convert -size 5x30 gradient:#abcdef-#456789 /tmp/image.png
>> #
>> # is derived from the variables above
>
> Assuming that the extra right square bracket in 'colors' is a typo,
> here's one way:
>
> s = "convert -size {w}x{h} gradient:{g1}-{g2} {f}".format(
> w = width, h = height, g1 = colors[0], g2 = colors[1], f = filename
> )
>
>
> Cheers & hth.,
>
> - ALf

Thanks, Alf. It works if I use it so:

subprocess.call(s, shell=True)

and I think that is because s is a single string assembled in almost the
variable interpolation fashion of Perl. It does not work with the
default shell=False argument, presumably because the arguments are not
split into separate strings (something that was horrible to do by hand
using the %s and %() syntax that I had tried out previously).

I think that you and Peter have, between you, shown me two ways of using
subprocess.call(): one with shell=True and the other with shell = False.

Thanks.

Chandra
From: Peter Otten on
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
From: Nobody on
On Tue, 16 Feb 2010 00:11:36 +0800, R (Chandra) Chandrasekhar wrote:

> One other question I forgot to ask is this why is there a terminal
> backslash in
>
>> subprocess.call("""\
>
> Removing the backslash makes the function fail.
>
> I wonder why, because """ is supposed to allow multi-line strings. I am
> sorry if this sounds obtuse but that backslash baffles me.

The backslash causes the following newline to be skipped, so the "c" at
the beginning of "convert" is the first character in the string. Without
it, the newline would be the first character, and the .splitlines() would
result in an empty string as the first element in the list.

Example:

> """
= hello
= world
= """.splitlines()
['', 'hello', 'world']
> """\
= hello
= world
= """.splitlines()
['hello', 'world']