7
7
parser that inherits from it. This will give a consistent look-and-feel between
8
8
the help/error output of built-in cmd2 commands and the app-specific commands.
9
9
If you wish to override the parser used by cmd2's built-in commands, see
10
- override_parser .py example.
10
+ custom_parser .py example.
11
11
12
12
Since the new capabilities are added by patching at the argparse API level,
13
13
they are available whether or not Cmd2ArgumentParser is used. However, the help
@@ -265,6 +265,18 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens)
265
265
runtime_checkable ,
266
266
)
267
267
268
+ from rich .console import (
269
+ Group ,
270
+ RenderableType ,
271
+ )
272
+ from rich_argparse import (
273
+ ArgumentDefaultsRichHelpFormatter ,
274
+ MetavarTypeRichHelpFormatter ,
275
+ RawDescriptionRichHelpFormatter ,
276
+ RawTextRichHelpFormatter ,
277
+ RichHelpFormatter ,
278
+ )
279
+
268
280
from . import (
269
281
ansi ,
270
282
constants ,
@@ -1042,9 +1054,14 @@ def _SubParsersAction_remove_parser(self: argparse._SubParsersAction, name: str)
1042
1054
############################################################################################################
1043
1055
1044
1056
1045
- class Cmd2HelpFormatter (argparse . RawTextHelpFormatter ):
1057
+ class Cmd2HelpFormatter (RichHelpFormatter ):
1046
1058
"""Custom help formatter to configure ordering of help text"""
1047
1059
1060
+ # Render usage, argument help, description, and epilog as markup.
1061
+ RichHelpFormatter .usage_markup = True
1062
+ RichHelpFormatter .help_markup = True
1063
+ RichHelpFormatter .text_markup = True
1064
+
1048
1065
def _format_usage (
1049
1066
self ,
1050
1067
usage : Optional [str ],
@@ -1249,17 +1266,95 @@ def _format_args(self, action: argparse.Action, default_metavar: Union[str, Tupl
1249
1266
return super ()._format_args (action , default_metavar ) # type: ignore[arg-type]
1250
1267
1251
1268
1269
+ class RawDescriptionCmd2HelpFormatter (
1270
+ RawDescriptionRichHelpFormatter ,
1271
+ Cmd2HelpFormatter ,
1272
+ ):
1273
+ """Cmd2 help message formatter which retains any formatting in descriptions and epilogs."""
1274
+
1275
+
1276
+ class RawTextCmd2HelpFormatter (
1277
+ RawTextRichHelpFormatter ,
1278
+ Cmd2HelpFormatter ,
1279
+ ):
1280
+ """Cmd2 help message formatter which retains formatting of all help text."""
1281
+
1282
+
1283
+ class ArgumentDefaultsCmd2HelpFormatter (
1284
+ ArgumentDefaultsRichHelpFormatter ,
1285
+ Cmd2HelpFormatter ,
1286
+ ):
1287
+ """Cmd2 help message formatter which adds default values to argument help."""
1288
+
1289
+
1290
+ class MetavarTypeCmd2HelpFormatter (
1291
+ MetavarTypeRichHelpFormatter ,
1292
+ Cmd2HelpFormatter ,
1293
+ ):
1294
+ """
1295
+ Cmd2 help message formatter which uses the argument 'type' as the default
1296
+ metavar value (instead of the argument 'dest').
1297
+ """
1298
+
1299
+
1300
+ class TextGroup :
1301
+ """
1302
+ A block of text which is formatted like an argparse argument group, including a title.
1303
+
1304
+ Title:
1305
+ Here is the first row of text.
1306
+ Here is yet another row of text.
1307
+ """
1308
+
1309
+ def __init__ (
1310
+ self ,
1311
+ title : str ,
1312
+ text : RenderableType ,
1313
+ formatter_creator : Callable [[], Cmd2HelpFormatter ],
1314
+ ) -> None :
1315
+ """
1316
+ :param title: the group's title
1317
+ :param text: the group's text (string or object that may be rendered by Rich)
1318
+ :param formatter_creator: callable which returns a Cmd2HelpFormatter instance
1319
+ """
1320
+ self .title = title
1321
+ self .text = text
1322
+ self .formatter_creator = formatter_creator
1323
+
1324
+ def __rich__ (self ) -> Group :
1325
+ """Custom rendering logic."""
1326
+ import rich
1327
+
1328
+ formatter = self .formatter_creator ()
1329
+
1330
+ styled_title = rich .text .Text (
1331
+ type (formatter ).group_name_formatter (f"{ self .title } :" ),
1332
+ style = formatter .styles ["argparse.groups" ],
1333
+ )
1334
+
1335
+ # Left pad the text like an argparse argument group does
1336
+ left_padding = formatter ._indent_increment
1337
+
1338
+ text_table = rich .table .Table (
1339
+ box = None ,
1340
+ show_header = False ,
1341
+ padding = (0 , 0 , 0 , left_padding ),
1342
+ )
1343
+ text_table .add_row (self .text )
1344
+ return Group (styled_title , text_table )
1345
+
1346
+
1252
1347
class Cmd2ArgumentParser (argparse .ArgumentParser ):
1253
1348
"""Custom ArgumentParser class that improves error and help output"""
1254
1349
1255
1350
def __init__ (
1256
1351
self ,
1257
1352
prog : Optional [str ] = None ,
1258
1353
usage : Optional [str ] = None ,
1259
- description : Optional [str ] = None ,
1260
- epilog : Optional [str ] = None ,
1354
+ description : Optional [RenderableType ] = None ,
1355
+ epilog : Optional [RenderableType ] = None ,
1261
1356
parents : Sequence [argparse .ArgumentParser ] = (),
1262
- formatter_class : Type [argparse . HelpFormatter ] = Cmd2HelpFormatter ,
1357
+ formatter_class : Type [Cmd2HelpFormatter ] = Cmd2HelpFormatter ,
1263
1358
prefix_chars : str = '-' ,
1264
1359
fromfile_prefix_chars : Optional [str ] = None ,
1265
1360
argument_default : Optional [str ] = None ,
@@ -1279,10 +1374,10 @@ def __init__(
1279
1374
super (Cmd2ArgumentParser , self ).__init__ (
1280
1375
prog = prog ,
1281
1376
usage = usage ,
1282
- description = description ,
1283
- epilog = epilog ,
1377
+ description = description , # type: ignore[arg-type]
1378
+ epilog = epilog , # type: ignore[arg-type]
1284
1379
parents = parents if parents else [],
1285
- formatter_class = formatter_class , # type: ignore[arg-type]
1380
+ formatter_class = formatter_class ,
1286
1381
prefix_chars = prefix_chars ,
1287
1382
fromfile_prefix_chars = fromfile_prefix_chars ,
1288
1383
argument_default = argument_default ,
@@ -1291,6 +1386,10 @@ def __init__(
1291
1386
allow_abbrev = allow_abbrev ,
1292
1387
)
1293
1388
1389
+ # Recast to assist type checkers since in a Cmd2HelpFormatter, these can be Rich renderables.
1390
+ self .description : Optional [RenderableType ] = self .description # type: ignore[assignment]
1391
+ self .epilog : Optional [RenderableType ] = self .epilog # type: ignore[assignment]
1392
+
1294
1393
self .set_ap_completer_type (ap_completer_type ) # type: ignore[attr-defined]
1295
1394
1296
1395
def add_subparsers (self , ** kwargs : Any ) -> argparse ._SubParsersAction : # type: ignore
@@ -1321,6 +1420,10 @@ def error(self, message: str) -> NoReturn:
1321
1420
formatted_message = ansi .style_error (formatted_message )
1322
1421
self .exit (2 , f'{ formatted_message } \n \n ' )
1323
1422
1423
+ def _get_formatter (self ) -> Cmd2HelpFormatter :
1424
+ """Copy of _get_formatter() with a different return type to assist type checkers."""
1425
+ return cast (Cmd2HelpFormatter , super ()._get_formatter ())
1426
+
1324
1427
def format_help (self ) -> str :
1325
1428
"""Copy of format_help() from argparse.ArgumentParser with tweaks to separately display required parameters"""
1326
1429
formatter = self ._get_formatter ()
@@ -1329,7 +1432,7 @@ def format_help(self) -> str:
1329
1432
formatter .add_usage (self .usage , self ._actions , self ._mutually_exclusive_groups ) # type: ignore[arg-type]
1330
1433
1331
1434
# description
1332
- formatter .add_text (self .description )
1435
+ formatter .add_text (self .description ) # type: ignore[arg-type]
1333
1436
1334
1437
# Begin cmd2 customization (separate required and optional arguments)
1335
1438
@@ -1370,7 +1473,7 @@ def format_help(self) -> str:
1370
1473
# End cmd2 customization
1371
1474
1372
1475
# epilog
1373
- formatter .add_text (self .epilog )
1476
+ formatter .add_text (self .epilog ) # type: ignore[arg-type]
1374
1477
1375
1478
# determine help from format above
1376
1479
return formatter .format_help () + '\n '
@@ -1382,6 +1485,10 @@ def _print_message(self, message: str, file: Optional[IO[str]] = None) -> None:
1382
1485
file = sys .stderr
1383
1486
ansi .style_aware_write (file , message )
1384
1487
1488
+ def create_text_group (self , title : str , text : RenderableType ) -> TextGroup :
1489
+ """Create a TextGroup using this parser's formatter creator."""
1490
+ return TextGroup (title , text , self ._get_formatter )
1491
+
1385
1492
1386
1493
class Cmd2AttributeWrapper :
1387
1494
"""
0 commit comments