Skip to content

Instantly share code, notes, and snippets.

@chapmanjacobd
Last active May 8, 2024 22:56
Show Gist options
  • Save chapmanjacobd/d6fca950b0ce2f7d0fa8ecf098b47a01 to your computer and use it in GitHub Desktop.
Save chapmanjacobd/d6fca950b0ce2f7d0fa8ecf098b47a01 to your computer and use it in GitHub Desktop.
import argparse
import shutil
import textwrap
from itertools import zip_longest
TERMINAL_SIZE = shutil.get_terminal_size(fallback=(80, 60))
def format_two_columns(text1, text2, width1=30, width2=70, left_gutter=2, middle_gutter=2, right_gutter=3):
terminal_width = min(TERMINAL_SIZE.columns, 100) - (left_gutter + middle_gutter + right_gutter)
if text2:
width1 = int(terminal_width * (width1 / (width1 + width2)))
width2 = int(terminal_width * (width2 / (width1 + width2)))
else:
width1 = terminal_width
wrapped_text1 = textwrap.wrap(text1, width=width1)
wrapped_text2 = textwrap.wrap(text2, width=width2)
formatted_lines = [
f"{' ' * left_gutter}{line1:<{width1}}{' ' * middle_gutter}{line2:<{width2}}{' ' * right_gutter}".rstrip()
for line1, line2 in zip_longest(wrapped_text1, wrapped_text2, fillvalue="")
]
return "\n".join(formatted_lines) + "\n"
class CustomHelpFormatter(argparse.HelpFormatter):
def _format_action(self, action):
help_text = self._expand_help(action) if action.help else ""
if help_text == "show this help message and exit":
return "" # not very useful self-referential humor
subactions = []
for subaction in self._iter_indented_subactions(action):
subactions.append(self._format_action(subaction))
opts = action.option_strings
if not opts and not help_text:
return ""
elif not opts: # positional with help text
opts = [action.dest.upper()]
if len(opts) == 1:
left = opts[0]
elif opts[1].startswith("--no-"): # argparse.BooleanOptionalAction
left = f"{opts[0]} / {opts[1]}"
elif opts[-1].startswith("--"):
left = opts[0]
else:
left = f"{opts[0]} ({opts[-1]})"
left += " " + self._format_args(action, "VALUE") + "\n"
return "".join(subactions) + format_two_columns(left, help_text)
class ArgumentParser(argparse.ArgumentParser):
def __init__(self, *args, **kwargs):
kwargs["formatter_class"] = lambda prog: CustomHelpFormatter(prog, max_help_position=40)
super().__init__(*args, **kwargs)
parser = ArgumentParser()
parser.add_argument('--name', help='help help')
parser.add_argument('--parameter', help='help help')
parser.add_argument('--parameter-name', help='help help')
parser.add_argument('--this-parameter-name', help='help help')
parser.add_argument('--this-is-parameter-name', help='help help')
parser.add_argument('--this-is-a-parameter-name', help='help help')
parser.add_argument('--this-is-a-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-very-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-very-very-long-parameter-name', help='help help')
parser.parse_args()
@chapmanjacobd
Copy link
Author

using width1=40, width2=60 (essentially 40% left column, 60% right):

python test.py -h
usage: test.py [-h] [--name NAME] [--parameter PARAMETER] [--parameter-name PARAMETER_NAME] [--this-parameter-name THIS_PARAMETER_NAME] [--this-is-parameter-name THIS_IS_PARAMETER_NAME]
               [--this-is-a-parameter-name THIS_IS_A_PARAMETER_NAME] [--this-is-a-long-parameter-name THIS_IS_A_LONG_PARAMETER_NAME] [--this-is-a-very-long-parameter-name THIS_IS_A_VERY_LONG_PARAMETER_NAME]
               [--this-is-a-very-very-long-parameter-name THIS_IS_A_VERY_VERY_LONG_PARAMETER_NAME] [--this-is-a-very-very-very-long-parameter-name THIS_IS_A_VERY_VERY_VERY_LONG_PARAMETER_NAME]

options:
  --name VALUE                           help help
  --parameter VALUE                      help help
  --parameter-name VALUE                 help help
  --this-parameter-name VALUE            help help
  --this-is-parameter-name VALUE         help help
  --this-is-a-parameter-name VALUE       help help
  --this-is-a-long-parameter-name VALUE  help help
  --this-is-a-very-long-parameter-name   help help
  VALUE
  --this-is-a-very-very-long-parameter-  help help
  name VALUE
  --this-is-a-very-very-very-long-       help help
  parameter-name VALUE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment