1#!./runmodule.sh

2

3 import subprocess

4 import typing

5 from collections.abc import Sequence, Mapping

6

7 PIPE = '|'

8

9 T = typing.TypeVar('T')

10 CompletedProcess = subprocess.CompletedProcess

11

12 def run_and_pipe(cmds: 'Sequence[str]', *, get_output: bool = False, env: 'Mapping[str, str]|None' = None) -> 'subprocess.CompletedProcess[bytes]':

13 '''

14 Run an external program and return when the program is finished.

15

16 :param cmds: One or several commands to be executed. If several commands are passed they are seperated by a '|' and stdout of the former command is piped to stdin of the following command.

17 :param env: The environment variables to be passed to the subprocess. If env is None :py:data:`os.environ` is used.

18 :param get_output: Make stdout and stderr available in the returned completed process object.

19 :return: The completed process

20 :raises OSError: e.g. if the program was not found

21 :raises CalledProcessError: if the called program failed

22

23 https://docs.python.org/3/library/subprocess.html#exceptions

24 '''

25 # I am not using shell=True because that is platform dependend

26 # and shlex is for UNIX like shells only, so it may not work on Windows

27 if get_output:

28 def run(cmd: 'Sequence[str]', input: 'bytes|None' = None) -> 'subprocess.CompletedProcess[bytes]':

29 return subprocess.run(cmd, env=env, input=input, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

30 else:

31 def run(cmd: 'Sequence[str]', input: 'bytes|None' = None) -> 'subprocess.CompletedProcess[bytes]':

32 return subprocess.run(cmd, env=env, input=input)

33

34 cmd_list = split_list(cmds, PIPE)

35 n = len(cmd_list)

36 if n == 1:

37 return run(cmd_list[0])

38

39 p = subprocess.run(cmd_list[0], env=env, stdout=subprocess.PIPE)

40 for cmd in cmd_list[1:-1]:

41 p = subprocess.run(cmd, env=env, input=p.stdout, stdout=subprocess.PIPE)

42 return run(cmd_list[-1], input=p.stdout)

43

44 def split_list(l: 'Sequence[T]', sep: T) -> 'Sequence[Sequence[T]]':

45 '''

46 Like str.split but for lists/tuples.

47 Splits a sequence into several sequences.

48 '''

49 out: 'list[Sequence[T]]' = []

50 i0 = 0

51 while True:

52 try:

53 i1 = l.index(sep, i0)

54 except ValueError:

55 break

56 out.append(l[i0:i1])

57 i0 = i1 + 1

58 out.append(l[i0:])

59 return out