Module trappedbot.tasks.task

Expand source code
import os
import re
import subprocess
import typing

from trappedbot.applogger import LOGGER
from trappedbot.mxutil import MessageFormat


# TODO: Rethink TaskMessageContext name ?
class TaskMessageContext(typing.NamedTuple):
    """A container for message context that can be passed to a TaskFunction"""

    sender: str
    room: str


class TaskResult(typing.NamedTuple):
    """The result of a TaskFunction"""

    output: str
    format: MessageFormat
    split: typing.Optional[str] = None


# A function that we can use to run code for our task
# TaskFunction callables take a list of arguments, and a set of message context
# The list of arguments comes from the chat command;
# e.g. if you send the bot a command like 'echo 1 2 3' the list of arguments
# is ['1', '2', '3'].
# The message context contains the sender, room, and possibly other metadata,
# and can be used to write tasks that take these values into account,
# for instance replying to users by name.
TaskFunction = typing.Callable[[typing.List[str], TaskMessageContext], TaskResult]


def systemcmd2taskfunc(cmd: str) -> TaskFunction:
    """Return a TaskFunction that runs an external program"""

    def _run_systemcmd(
        arguments: typing.List[str], context: TaskMessageContext
    ) -> TaskResult:
        """Run an external program"""

        fullcmd = [cmd] + arguments
        LOGGER.debug(f"Running system command {fullcmd}")

        env = os.environ.copy()
        env["MATRIX_SENDER"] = context.sender
        env["MATRIX_ROOM"] = context.room

        proc = subprocess.Popen(
            fullcmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            env=env,
        )
        stdout, stderr = proc.communicate()
        stdout = stdout.strip()
        stderr = stderr.strip()

        if proc.returncode != 0:
            raise subprocess.CalledProcessError(
                proc.returncode, fullcmd, stdout, stderr
            )

        return TaskResult(stdout, MessageFormat.CODE)

    return _run_systemcmd


def constant2taskfunc(
    value: str, format: MessageFormat = MessageFormat.NATURAL
) -> TaskFunction:
    """Given a constant, return a TaskFunction"""

    def _result_func(
        arguments: typing.List[str], context: TaskMessageContext
    ) -> TaskResult:
        return TaskResult(value, format)

    return _result_func


class Task(typing.NamedTuple):
    """A task that our bot can perform
    Arguments:
        name:                   The name of the task.
        taskfunc:               A TaskFunction callable.
        split:                  If set, split response into multiple messages
                                whenever this string occurs in the taskfunc output.
    """

    name: str
    taskfunc: TaskFunction
    split: typing.Optional[str] = None

Functions

def constant2taskfunc(value: str, format: MessageFormat = MessageFormat.NATURAL) ‑> Callable[[List[str], TaskMessageContext], TaskResult]

Given a constant, return a TaskFunction

Expand source code
def constant2taskfunc(
    value: str, format: MessageFormat = MessageFormat.NATURAL
) -> TaskFunction:
    """Given a constant, return a TaskFunction"""

    def _result_func(
        arguments: typing.List[str], context: TaskMessageContext
    ) -> TaskResult:
        return TaskResult(value, format)

    return _result_func
def systemcmd2taskfunc(cmd: str) ‑> Callable[[List[str], TaskMessageContext], TaskResult]

Return a TaskFunction that runs an external program

Expand source code
def systemcmd2taskfunc(cmd: str) -> TaskFunction:
    """Return a TaskFunction that runs an external program"""

    def _run_systemcmd(
        arguments: typing.List[str], context: TaskMessageContext
    ) -> TaskResult:
        """Run an external program"""

        fullcmd = [cmd] + arguments
        LOGGER.debug(f"Running system command {fullcmd}")

        env = os.environ.copy()
        env["MATRIX_SENDER"] = context.sender
        env["MATRIX_ROOM"] = context.room

        proc = subprocess.Popen(
            fullcmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            env=env,
        )
        stdout, stderr = proc.communicate()
        stdout = stdout.strip()
        stderr = stderr.strip()

        if proc.returncode != 0:
            raise subprocess.CalledProcessError(
                proc.returncode, fullcmd, stdout, stderr
            )

        return TaskResult(stdout, MessageFormat.CODE)

    return _run_systemcmd

Classes

class Task (name: str, taskfunc: Callable[[List[str], TaskMessageContext], TaskResult], split: Optional[str] = None)

A task that our bot can perform

Arguments

name: The name of the task. taskfunc: A TaskFunction callable. split: If set, split response into multiple messages whenever this string occurs in the taskfunc output.

Expand source code
class Task(typing.NamedTuple):
    """A task that our bot can perform
    Arguments:
        name:                   The name of the task.
        taskfunc:               A TaskFunction callable.
        split:                  If set, split response into multiple messages
                                whenever this string occurs in the taskfunc output.
    """

    name: str
    taskfunc: TaskFunction
    split: typing.Optional[str] = None

Ancestors

  • builtins.tuple

Instance variables

var name : str

Alias for field number 0

var split : Optional[str]

Alias for field number 2

var taskfunc : Callable[[List[str], TaskMessageContext], TaskResult]

Alias for field number 1

class TaskMessageContext (sender: str, room: str)

A container for message context that can be passed to a TaskFunction

Expand source code
class TaskMessageContext(typing.NamedTuple):
    """A container for message context that can be passed to a TaskFunction"""

    sender: str
    room: str

Ancestors

  • builtins.tuple

Instance variables

var room : str

Alias for field number 1

var sender : str

Alias for field number 0

class TaskResult (output: str, format: MessageFormat, split: Optional[str] = None)

The result of a TaskFunction

Expand source code
class TaskResult(typing.NamedTuple):
    """The result of a TaskFunction"""

    output: str
    format: MessageFormat
    split: typing.Optional[str] = None

Ancestors

  • builtins.tuple

Instance variables

var formatMessageFormat

Alias for field number 1

var output : str

Alias for field number 0

var split : Optional[str]

Alias for field number 2