Module aerpawlib.external

Utilities allowing for aerpawlib scripts to interact with external processes running in a userspace.

Expand source code
"""
Utilities allowing for aerpawlib scripts to interact with external processes
running in a userspace.
"""

import asyncio
from typing import List
import re

class ExternalProcess:
    """
    Object allowing for interaction with a process spawned by this script and
    run asynchronously to the aerpawlib script. Allows for basic interaction
    with stdio and stdout as well as dynamic passing of arguments.
    """
    def __init__(self, executable: str, params=[], stdin: str=None, stdout: str=None):
        """
        Prepare external process for execution. Does NOT execute process, you
        must call `start()`.

        `params` should be the parameters that will be passed to the process.
        Split the list where there would be spaces in the command line version.
        """
        self._executable = executable
        self._params = params
        self._stdin = stdin
        self._stdout = stdout
        
    async def start(self):
        """
        Start the executable in an asyncronous process
        """
        executable = self._executable
        executable += " " + " ".join(self._params)
        if not self._stdin is None:
            executable += f" < {self._stdin}"
        if not self._stdout is None:
            executable += f" > {self._stdout}"
            
        self.process = await asyncio.create_subprocess_shell(
                executable,
                stdout=None if self._stdout is not None else asyncio.subprocess.PIPE,
                stdin=None if self._stdin is not None else asyncio.subprocess.PIPE)
    
    async def read_line(self) -> str:
        """
        Read one line from the stdout buffer. Returns None if process has stopped.
        """
        if not self.process.stdout:
            return None
        out = await self.process.stdout.readline()
        return out.decode('ascii').rstrip()

    async def send_input(self, data: str):
        """
        Send a string to the process's stdin
        """
        self.process.stdin.write(data.encode())
        await self.process.stdin.drain()

    async def wait_until_terminated(self):
        """
        Idles until process is complete
        """
        await self.process.wait()

    async def wait_until_output(self, output_regex) -> List[str]:
        """
        block and wait until we see the output_regex regular expression show up
        in a line of the output stream (only works w/out stdout set)
        
        Returns all lines consumes up until and including regex
        
        Use an r"string" as output_regex
        
        Will exit only if process terminates or pattern is matched
        """
        buff = []
        while True:
            out = await self.read_line()
            buff.append(out)
            if re.search(output_regex, out):
                return buff

Classes

class ExternalProcess (executable: str, params=[], stdin: str = None, stdout: str = None)

Object allowing for interaction with a process spawned by this script and run asynchronously to the aerpawlib script. Allows for basic interaction with stdio and stdout as well as dynamic passing of arguments.

Prepare external process for execution. Does NOT execute process, you must call start().

params should be the parameters that will be passed to the process. Split the list where there would be spaces in the command line version.

Expand source code
class ExternalProcess:
    """
    Object allowing for interaction with a process spawned by this script and
    run asynchronously to the aerpawlib script. Allows for basic interaction
    with stdio and stdout as well as dynamic passing of arguments.
    """
    def __init__(self, executable: str, params=[], stdin: str=None, stdout: str=None):
        """
        Prepare external process for execution. Does NOT execute process, you
        must call `start()`.

        `params` should be the parameters that will be passed to the process.
        Split the list where there would be spaces in the command line version.
        """
        self._executable = executable
        self._params = params
        self._stdin = stdin
        self._stdout = stdout
        
    async def start(self):
        """
        Start the executable in an asyncronous process
        """
        executable = self._executable
        executable += " " + " ".join(self._params)
        if not self._stdin is None:
            executable += f" < {self._stdin}"
        if not self._stdout is None:
            executable += f" > {self._stdout}"
            
        self.process = await asyncio.create_subprocess_shell(
                executable,
                stdout=None if self._stdout is not None else asyncio.subprocess.PIPE,
                stdin=None if self._stdin is not None else asyncio.subprocess.PIPE)
    
    async def read_line(self) -> str:
        """
        Read one line from the stdout buffer. Returns None if process has stopped.
        """
        if not self.process.stdout:
            return None
        out = await self.process.stdout.readline()
        return out.decode('ascii').rstrip()

    async def send_input(self, data: str):
        """
        Send a string to the process's stdin
        """
        self.process.stdin.write(data.encode())
        await self.process.stdin.drain()

    async def wait_until_terminated(self):
        """
        Idles until process is complete
        """
        await self.process.wait()

    async def wait_until_output(self, output_regex) -> List[str]:
        """
        block and wait until we see the output_regex regular expression show up
        in a line of the output stream (only works w/out stdout set)
        
        Returns all lines consumes up until and including regex
        
        Use an r"string" as output_regex
        
        Will exit only if process terminates or pattern is matched
        """
        buff = []
        while True:
            out = await self.read_line()
            buff.append(out)
            if re.search(output_regex, out):
                return buff

Methods

async def read_line(self) ‑> str

Read one line from the stdout buffer. Returns None if process has stopped.

Expand source code
async def read_line(self) -> str:
    """
    Read one line from the stdout buffer. Returns None if process has stopped.
    """
    if not self.process.stdout:
        return None
    out = await self.process.stdout.readline()
    return out.decode('ascii').rstrip()
async def send_input(self, data: str)

Send a string to the process's stdin

Expand source code
async def send_input(self, data: str):
    """
    Send a string to the process's stdin
    """
    self.process.stdin.write(data.encode())
    await self.process.stdin.drain()
async def start(self)

Start the executable in an asyncronous process

Expand source code
async def start(self):
    """
    Start the executable in an asyncronous process
    """
    executable = self._executable
    executable += " " + " ".join(self._params)
    if not self._stdin is None:
        executable += f" < {self._stdin}"
    if not self._stdout is None:
        executable += f" > {self._stdout}"
        
    self.process = await asyncio.create_subprocess_shell(
            executable,
            stdout=None if self._stdout is not None else asyncio.subprocess.PIPE,
            stdin=None if self._stdin is not None else asyncio.subprocess.PIPE)
async def wait_until_output(self, output_regex) ‑> List[str]

block and wait until we see the output_regex regular expression show up in a line of the output stream (only works w/out stdout set)

Returns all lines consumes up until and including regex

Use an r"string" as output_regex

Will exit only if process terminates or pattern is matched

Expand source code
async def wait_until_output(self, output_regex) -> List[str]:
    """
    block and wait until we see the output_regex regular expression show up
    in a line of the output stream (only works w/out stdout set)
    
    Returns all lines consumes up until and including regex
    
    Use an r"string" as output_regex
    
    Will exit only if process terminates or pattern is matched
    """
    buff = []
    while True:
        out = await self.read_line()
        buff.append(out)
        if re.search(output_regex, out):
            return buff
async def wait_until_terminated(self)

Idles until process is complete

Expand source code
async def wait_until_terminated(self):
    """
    Idles until process is complete
    """
    await self.process.wait()