Skip to content

Commit a8a4293

Browse files
committed
Removed most overrided functions for custom argparse help formatting due to incompatibilities with newer versions.
1 parent 95f3fd8 commit a8a4293

File tree

2 files changed

+12
-183
lines changed

2 files changed

+12
-183
lines changed

cmd2/argparse_custom.py

Lines changed: 8 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,9 @@ def get_items(self) -> list[CompletionItems]:
261261
from argparse import ArgumentError
262262
from collections.abc import (
263263
Callable,
264-
Iterable,
265264
Iterator,
266265
Sequence,
267266
)
268-
from gettext import gettext
269267
from typing import (
270268
TYPE_CHECKING,
271269
Any,
@@ -1131,173 +1129,6 @@ def __init__(
11311129

11321130
super().__init__(prog, indent_increment, max_help_position, width, console=console, **kwargs)
11331131

1134-
def _format_usage(
1135-
self,
1136-
usage: str | None,
1137-
actions: Iterable[argparse.Action],
1138-
groups: Iterable[argparse._ArgumentGroup],
1139-
prefix: str | None = None,
1140-
) -> str:
1141-
if prefix is None:
1142-
prefix = gettext('Usage: ')
1143-
1144-
# if usage is specified, use that
1145-
if usage is not None:
1146-
usage %= {"prog": self._prog}
1147-
1148-
# if no optionals or positionals are available, usage is just prog
1149-
elif not actions:
1150-
usage = f'{self._prog}'
1151-
1152-
# if optionals and positionals are available, calculate usage
1153-
else:
1154-
prog = f'{self._prog}'
1155-
1156-
# split optionals from positionals
1157-
optionals = []
1158-
positionals = []
1159-
# Begin cmd2 customization (separates required and optional, applies to all changes in this function)
1160-
required_options = []
1161-
for action in actions:
1162-
if action.option_strings:
1163-
if action.required:
1164-
required_options.append(action)
1165-
else:
1166-
optionals.append(action)
1167-
else:
1168-
positionals.append(action)
1169-
# End cmd2 customization
1170-
1171-
# build full usage string
1172-
format_actions = self._format_actions_usage
1173-
action_usage = format_actions(required_options + optionals + positionals, groups) # type: ignore[arg-type]
1174-
usage = ' '.join([s for s in [prog, action_usage] if s])
1175-
1176-
# wrap the usage parts if it's too long
1177-
text_width = self._width - self._current_indent
1178-
if len(prefix) + len(usage) > text_width:
1179-
# Begin cmd2 customization
1180-
1181-
# break usage into wrappable parts
1182-
part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
1183-
req_usage = format_actions(required_options, groups) # type: ignore[arg-type]
1184-
opt_usage = format_actions(optionals, groups) # type: ignore[arg-type]
1185-
pos_usage = format_actions(positionals, groups) # type: ignore[arg-type]
1186-
req_parts = re.findall(part_regexp, req_usage)
1187-
opt_parts = re.findall(part_regexp, opt_usage)
1188-
pos_parts = re.findall(part_regexp, pos_usage)
1189-
1190-
# End cmd2 customization
1191-
1192-
# helper for wrapping lines
1193-
def get_lines(parts: list[str], indent: str, prefix: str | None = None) -> list[str]:
1194-
lines: list[str] = []
1195-
line: list[str] = []
1196-
line_len = len(prefix) - 1 if prefix is not None else len(indent) - 1
1197-
for part in parts:
1198-
if line_len + 1 + len(part) > text_width and line:
1199-
lines.append(indent + ' '.join(line))
1200-
line = []
1201-
line_len = len(indent) - 1
1202-
line.append(part)
1203-
line_len += len(part) + 1
1204-
if line:
1205-
lines.append(indent + ' '.join(line))
1206-
if prefix is not None:
1207-
lines[0] = lines[0][len(indent) :]
1208-
return lines
1209-
1210-
# if prog is short, follow it with optionals or positionals
1211-
if len(prefix) + len(prog) <= 0.75 * text_width:
1212-
indent = ' ' * (len(prefix) + len(prog) + 1)
1213-
# Begin cmd2 customization
1214-
if req_parts:
1215-
lines = get_lines([prog, *req_parts], indent, prefix)
1216-
lines.extend(get_lines(opt_parts, indent))
1217-
lines.extend(get_lines(pos_parts, indent))
1218-
elif opt_parts:
1219-
lines = get_lines([prog, *opt_parts], indent, prefix)
1220-
lines.extend(get_lines(pos_parts, indent))
1221-
elif pos_parts:
1222-
lines = get_lines([prog, *pos_parts], indent, prefix)
1223-
else:
1224-
lines = [prog]
1225-
# End cmd2 customization
1226-
1227-
# if prog is long, put it on its own line
1228-
else:
1229-
indent = ' ' * len(prefix)
1230-
# Begin cmd2 customization
1231-
parts = req_parts + opt_parts + pos_parts
1232-
lines = get_lines(parts, indent)
1233-
if len(lines) > 1:
1234-
lines = []
1235-
lines.extend(get_lines(req_parts, indent))
1236-
lines.extend(get_lines(opt_parts, indent))
1237-
lines.extend(get_lines(pos_parts, indent))
1238-
# End cmd2 customization
1239-
lines = [prog, *lines]
1240-
1241-
# join lines into usage
1242-
usage = '\n'.join(lines)
1243-
1244-
# prefix with 'Usage:'
1245-
return f'{prefix}{usage}\n\n'
1246-
1247-
def _format_action_invocation(self, action: argparse.Action) -> str:
1248-
if not action.option_strings:
1249-
default = self._get_default_metavar_for_positional(action)
1250-
(metavar,) = self._metavar_formatter(action, default)(1)
1251-
return metavar
1252-
1253-
parts: list[str] = []
1254-
1255-
# if the Optional doesn't take a value, format is:
1256-
# -s, --long
1257-
if action.nargs == 0:
1258-
parts.extend(action.option_strings)
1259-
return ', '.join(parts)
1260-
1261-
# Begin cmd2 customization (less verbose)
1262-
# if the Optional takes a value, format is:
1263-
# -s, --long ARGS
1264-
default = self._get_default_metavar_for_optional(action)
1265-
args_string = self._format_args(action, default)
1266-
1267-
return ', '.join(action.option_strings) + ' ' + args_string
1268-
# End cmd2 customization
1269-
1270-
def _determine_metavar(
1271-
self,
1272-
action: argparse.Action,
1273-
default_metavar: str,
1274-
) -> str | tuple[str, ...]:
1275-
"""Determine what to use as the metavar value of an action."""
1276-
if action.metavar is not None:
1277-
result = action.metavar
1278-
elif action.choices is not None:
1279-
choice_strs = [str(choice) for choice in action.choices]
1280-
# Begin cmd2 customization (added space after comma)
1281-
result = f'{", ".join(choice_strs)}'
1282-
# End cmd2 customization
1283-
else:
1284-
result = default_metavar
1285-
return result
1286-
1287-
def _metavar_formatter(
1288-
self,
1289-
action: argparse.Action,
1290-
default_metavar: str,
1291-
) -> Callable[[int], tuple[str, ...]]:
1292-
metavar = self._determine_metavar(action, default_metavar)
1293-
1294-
def format_tuple(tuple_size: int) -> tuple[str, ...]:
1295-
if isinstance(metavar, tuple):
1296-
return metavar
1297-
return (metavar,) * tuple_size
1298-
1299-
return format_tuple
1300-
13011132
def _build_nargs_range_str(self, nargs_range: tuple[int, int | float]) -> str:
13021133
"""Generate nargs range string for help text."""
13031134
if nargs_range[1] == constants.INFINITY:
@@ -1314,13 +1145,12 @@ def _format_args(self, action: argparse.Action, default_metavar: str) -> str:
13141145
13151146
All formats in this function need to be handled by _rich_metavar_parts().
13161147
"""
1317-
metavar = self._determine_metavar(action, default_metavar)
1318-
metavar_formatter = self._metavar_formatter(action, default_metavar)
1148+
get_metavar = self._metavar_formatter(action, default_metavar)
13191149

13201150
# Handle nargs specified as a range
13211151
nargs_range = action.get_nargs_range() # type: ignore[attr-defined]
13221152
if nargs_range is not None:
1323-
arg_str = '%s' % metavar_formatter(1) # noqa: UP031
1153+
arg_str = '%s' % get_metavar(1) # noqa: UP031
13241154
range_str = self._build_nargs_range_str(nargs_range)
13251155
return f"{arg_str}{range_str}"
13261156

@@ -1329,8 +1159,8 @@ def _format_args(self, action: argparse.Action, default_metavar: str) -> str:
13291159
# To make this less verbose, format it like: 'command arg{5}'.
13301160
# Do not customize the output when metavar is a tuple of strings. Allow argparse's
13311161
# formatter to handle that instead.
1332-
if isinstance(metavar, str) and isinstance(action.nargs, int) and action.nargs > 1:
1333-
arg_str = '%s' % metavar_formatter(1) # noqa: UP031
1162+
if not isinstance(action.metavar, tuple) and isinstance(action.nargs, int) and action.nargs > 1:
1163+
arg_str = '%s' % get_metavar(1) # noqa: UP031
13341164
return f"{arg_str}{{{action.nargs}}}"
13351165

13361166
# Fallback to parent for all other cases
@@ -1342,19 +1172,18 @@ def _rich_metavar_parts(
13421172
default_metavar: str,
13431173
) -> Iterator[tuple[str, bool]]:
13441174
"""Override to handle all cmd2-specific formatting in _format_args()."""
1345-
metavar = self._determine_metavar(action, default_metavar)
1346-
metavar_formatter = self._metavar_formatter(action, default_metavar)
1175+
get_metavar = self._metavar_formatter(action, default_metavar)
13471176

13481177
# Handle nargs specified as a range
13491178
nargs_range = action.get_nargs_range() # type: ignore[attr-defined]
13501179
if nargs_range is not None:
1351-
yield "%s" % metavar_formatter(1), True # noqa: UP031
1180+
yield "%s" % get_metavar(1), True # noqa: UP031
13521181
yield self._build_nargs_range_str(nargs_range), False
13531182
return
13541183

13551184
# Handle specific integer nargs (e.g., nargs=5 -> arg{5})
1356-
if isinstance(metavar, str) and isinstance(action.nargs, int) and action.nargs > 1:
1357-
yield "%s" % metavar_formatter(1), True # noqa: UP031
1185+
if not isinstance(action.metavar, tuple) and isinstance(action.nargs, int) and action.nargs > 1:
1186+
yield "%s" % get_metavar(1), True # noqa: UP031
13581187
yield f"{{{action.nargs}}}", False
13591188
return
13601189

tests/transcripts/from_cmdloop.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ Usage: speak [-h] [-p] [-s] [-r REPEAT]/ */
77
Repeats what you tell me to./ */
88

99
Optional Arguments:/ */
10-
-h, --help show this help message and exit/ */
11-
-p, --piglatin atinLay/ */
12-
-s, --shout N00B EMULATION MODE/ */
13-
-r, --repeat REPEAT output [n] times/ */
10+
-h, --help/ */show this help message and exit/ */
11+
-p, --piglatin/ */atinLay/ */
12+
-s, --shout/ */N00B EMULATION MODE/ */
13+
-r, --repeat REPEAT/ */output [n] times/ */
1414

1515
(Cmd) say goodnight, Gracie
1616
goodnight, Gracie

0 commit comments

Comments
 (0)