Home > Back-end >  Passing multiple lists to subprocess
Passing multiple lists to subprocess

Time:07-27

I have the following python code:

var_b='en'
var_c='cs'
var_d='false'
var_e=str(Path.home())

IDS='TEST_123'

L1 = [1, 2 , 3, 4]
L2 = ['env', L1, f'a={var_b}']
CMD = ['COMMAND']
L3 = [IDS]
L4 = [f'--b {var_b}', f'--c {var_c}']
L5 = [f'--d {var_d}', f'--e {var_e}.xml', L4]

I would like to execute a terminal command using subprocess to make the end command entry on the terminal looks in the combination L2 CMD L3 L5 i.e.

**L2 CMD L3 L5**
env 1 2 3 4 a=en COMMAND TEST_123 --d false --e /path/to/home.xml --b en --c cs

Here is what i have tried:

subprocess.run([*L2, *CMD, *L3, *L5])

But i'm getting this error:

TypeError: expected str, bytes or os.PathLike object, not list

Could someone please suggest how to implement this.

CodePudding user response:

For the case if L2 contains some L6 as and so on, there must be recursion:

var_b='en'
var_c='cs'
var_d='false'
var_e=str("Path.home()")

IDS='TEST_123'

L1 = [1, 2 , 3, 4]
L2 = ['env', L1, f'a={var_b}']
CMD = ['COMMAND']
L3 = [IDS]
L4 = [f'--b {var_b}', f'--c {var_c}']
L5 = [f'--d {var_d}', f'--e {var_e}.xml', L4]

def build_string_recursively(command_list):
    ret = []
    for command in command_list:
        if isinstance(command,list):
            ret =build_string_recursively(command)
        else:
            ret.append(command)
    return ret

print(build_string_recursively(L2 CMD L3 L5))

This also gives desired:

['env', 1, 2, 3, 4, 'a=en', 'COMMAND', 'TEST_123', '--d false', '--e Path.home().xml', '--b en', '--c cs']

CodePudding user response:

The problem is that this unpacking * goes only one level deep. But you want to unpack every level in order to get a flat list. You should do something like this:

import itertools
from pathlib import Path

def flatten_to_strings(l):
    """Flatten a list or tuple, turning the remaining components into strings."""
    if not isinstance(l, (list, tuple)):
        return [str(l)]
    flat = (flatten_to_strings(i) for i in l)
    return list(itertools.chain.from_iterable(flat))

With this and your code, you can do

print(flatten_to_strings([*L2, *CMD, *L3, *L5]))

and it prints

['env', '1', '2', '3', '4', 'a=en', 'COMMAND', 'TEST_123', '--d false', '--e /home/glglgl.xml', '--b en', '--c cs']

Alternatively, you could assemble your lists as you need them to be:

L1 = [str(i) for i in [1, 2, 3, 4]] # so that they are strings
L2 = ['env', *L1, f'a={var_b}']     # unpack L1 early
CMD = ['COMMAND']
L3 = [IDS]
L4 = [f'--b {var_b}', f'--c {var_c}']
L5 = [f'--d {var_d}', f'--e {var_e}.xml', *L4] # unpack L4 early

This way,

print([*L2, *CMD, *L3, *L5])

gives

['env', '1', '2', '3', '4', 'a=en', 'COMMAND', 'TEST_123', '--d false', '--e /home/glglgl.xml', '--b en', '--c cs']

as well.

  • Related