Skip to content

Instantly share code, notes, and snippets.

@evandrocoan
Last active April 24, 2022 23:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evandrocoan/916976490aeecc7b93e658084bb2834d to your computer and use it in GitHub Desktop.
Save evandrocoan/916976490aeecc7b93e658084bb2834d to your computer and use it in GitHub Desktop.
import pathlib
ROOT_DIR = pathlib.Path(__file__).parent.parent

process, output = run_process(f"python3 {ROOT_DIR / 'something.py'}", ROOT_DIR)
process = run_background(f"python3 {ROOT_DIR / 'something.py'}", ROOT_DIR)
import os
import sys
import shlex
import subprocess
import time
import signal

def run_process(command_line, directory=None, verbose=False):
    """
    Given a command line as `ls -a` runs this command on the current directory

    https://docs.python.org/3.6/library/subprocess.html#subprocess.Popen
    return (subprocess.POpen object, output_lines as list)
    """
    output_lines = []
    command = shlex.split(command_line)

    if verbose:
        print('run_process command', command, directory, file=sys.stderr)

    with subprocess.Popen(
        command,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        env=os.environ,
        cwd=directory,
    ) as process:
        # https://stackoverflow.com/questions/18421757/live-output-from-subprocess-command
        # https://stackoverflow.com/questions/1606795/catching-stdout-in-realtime-from-subprocess
        while True:
            line = process.stdout.readline()
            if not line:
                break

            line = line.decode("UTF-8", errors='replace')
            line = line.replace('\r\n', '\n').rstrip(' \n\r')
            output_lines.append(line)

            if verbose:
                print(line, file=sys.stderr)
    return process, "\n".join(output_lines)


def run_background(command_line, directory=None, verbose=False):
    command = shlex.split(command_line)
    if verbose:
        print('run_process command', command, directory, file=sys.stderr)

    process = subprocess.Popen(
            command,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            env=os.environ,
            cwd=directory,
        )

    if verbose:
        def back():
            while True:
                line = process.stdout.readline()
                if not line:
                    break
                line = line.decode("UTF-8", errors='replace')
                line = line.replace('\r\n', '\n').rstrip(' \n\r')
                print(line, file=sys.stderr)
        thread = threading.Thread(target=back, daemon=True)
        thread.start()
    return process


def gracifully_kill_process(process, timeout=1, verbose=False):
    process.send_signal(signal.SIGINT)
    time.sleep(timeout)
    if process.poll() is None:
        if verbose:
            print(f"Warning: Could not terminate the process {process.pid} with SIGINT...", file=sys.stderr)
        process.terminate()
        time.sleep(timeout)
        if process.poll() is None:
            if verbose:
                print(f"Warning: Could not terminate the process {process.pid} with SIGTERM...", file=sys.stderr)
            process.kill()
            time.sleep(timeout)
            if process.poll() is None:
                print(
                        f"Warning: Could not terminate the process {process.pid} with SIGKILL, giving up...",
                        file=sys.stderr,
                    )
                return 1
    if verbose:
        print(f"Successfully terminated the process {process.pid}={process.returncode}...", file=sys.stderr)
    return 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment