Using ANSI escape colors

Specific escape codes are of the form: \033[0m
This one clears the previous color/font style.

ESC = lambda n: f'\033[{n}m'
ENDC = ESC(0)
BOLD = ESC(1), 
DIM = ESC(2)
OBLIQUE = ESC(2)
UNDER = ESC(4)
RED = ESC(91)
GREEN = ESC(92)
BLUE = ESC(94)
YELLOW = ESC(93)
MAGENTA = ESC(95)
CYAN = ESC(96)

Using subprocess to make Bash calls

Executing bash commands with subprocess

import subprocess
def run_shell(cmdl):
    try:
        output = subprocess.check_output(cmdl,
            stderr=subprocess.STDOUT,
            shell=True, text=True)
        return output
    except subprocess.CalledProcessError as e:
        print("ERROR -", e.output); exit(1)

Accepting from both stdin and argv

Reads from stdin if piped, else argv. Supports globs.

def maplines(type):
    import sys
    args = (map(str.strip, sys.stdin)
    if sys.stdin.isatty() else sys.argv[1:])
    yield from map(type, args)

Using argparse to define CLT API

The docstring can serve as ArgumentParser description to avoid repetition.


from argparse import ArgumentParser
p = ArgumentParser(description=__doc__)

Unary functions can be exposed directly in the add argument step.


p.add_argument("-print", type=lambda _: print(_))

It has two issues.
  1. It does not work with arities other than one
  2. Errors are raised as parsing errors without trace

Nullary actions can be exposed directly in the add argument step as well, but require a work-around.

from argparse import _StoreTrueAction
p.add_argument("-action", action=type('',
    (_StoreTrueAction,), {"__call__":
    lambda *_: print(...)} ))
Likely not worth the confusing syntax

Subclassing the argparse Action

This enables defining inline the API for a CLT where args expose calls to callables of any arity.
from argparse import Action
class Cmd(Action):
    def __init__(self, **_):
        self._cmd = _.pop("cmd")
        optstr = _.pop("option_strings")
        dest = _.pop("dest")
        super().__init__(optstr, dest, **_)
    def __call__(self, _1, _2, vals, *_3):
        self._cmd(*vals)

p = ArgumentParser()
p.register("action", "cmd", Cmd)
This setup can be used like:
p.add_argument("-help", nargs=0, action="cmd",
               cmd=lambda: print(__doc__))
p.add_argument("-echo", nargs=1, action="cmd",
               cmd=lambda x: print(x))
p.add_argument("-catw", nargs=2, action="cmd",
               cmd=lambda x, y: print(x, y))
p.add_argument("-lines", nargs="*", action="cmd",
               cmd=lambda *xs: print(*xs, sep='\n'))
p.parse_args()

Post-Processing Exception Stack Traces

import io, traceback
def get_trace(exc: Exception, lines=False) -> str:
    # https://stackoverflow.com/a/76584117/
    BUFFER = dict(file=(file := io.StringIO()))
    traceback.print_exception(exc, **BUFFER)
    tr = file.getvalue().rstrip()
    return tr if not lines else tr.splitlines()