Skip to content

Commit 8b669d5

Browse files
GH-142389: Add backtick markup support in description and epilog (#142390)
1 parent fa1ac90 commit 8b669d5

File tree

5 files changed

+142
-1
lines changed

5 files changed

+142
-1
lines changed

Doc/library/argparse.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,27 @@ are set.
645645

646646
.. versionadded:: 3.14
647647

648+
To highlight inline code in your description or epilog text, you can use
649+
backticks::
650+
651+
>>> parser = argparse.ArgumentParser(
652+
... formatter_class=argparse.RawDescriptionHelpFormatter,
653+
... epilog='''Examples:
654+
... `python -m myapp --verbose`
655+
... `python -m myapp --config settings.json`
656+
... ''')
657+
658+
When colors are enabled, the text inside backticks will be displayed in a
659+
distinct color to help examples stand out. When colors are disabled, backticks
660+
are preserved as-is, which is readable in plain text.
661+
662+
.. note::
663+
664+
Backtick markup only applies to description and epilog text. It does not
665+
apply to individual argument ``help`` strings.
666+
667+
.. versionadded:: 3.15
668+
648669

649670
The add_argument() method
650671
-------------------------

Doc/whatsnew/3.15.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@ argparse
423423
default to ``True``. This enables suggestions for mistyped arguments by default.
424424
(Contributed by Jakob Schluse in :gh:`140450`.)
425425

426+
* Added backtick markup support in description and epilog text to highlight
427+
inline code when color output is enabled.
428+
(Contributed by Savannah Ostrowski in :gh:`142390`.)
429+
426430
calendar
427431
--------
428432

Lib/argparse.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,27 @@ def _format_text(self, text):
517517
text = text % dict(prog=self._prog)
518518
text_width = max(self._width - self._current_indent, 11)
519519
indent = ' ' * self._current_indent
520-
return self._fill_text(text, text_width, indent) + '\n\n'
520+
text = self._fill_text(text, text_width, indent)
521+
text = self._apply_text_markup(text)
522+
return text + '\n\n'
523+
524+
def _apply_text_markup(self, text):
525+
"""Apply color markup to text.
526+
527+
Supported markup:
528+
`...` - inline code (rendered with prog_extra color)
529+
530+
When colors are disabled, backticks are preserved as-is.
531+
"""
532+
t = self._theme
533+
if not t.reset:
534+
return text
535+
text = _re.sub(
536+
r'`([^`]+)`',
537+
rf'{t.prog_extra}\1{t.reset}',
538+
text,
539+
)
540+
return text
521541

522542
def _format_action(self, action):
523543
# determine the required width and the entry label

Lib/test/test_argparse.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7568,6 +7568,101 @@ def test_error_and_warning_not_colorized_when_disabled(self):
75687568
self.assertNotIn('\x1b[', warn)
75697569
self.assertIn('warning:', warn)
75707570

7571+
def test_backtick_markup_in_epilog(self):
7572+
parser = argparse.ArgumentParser(
7573+
prog='PROG',
7574+
color=True,
7575+
epilog='Example: `python -m myapp --verbose`',
7576+
)
7577+
7578+
prog_extra = self.theme.prog_extra
7579+
reset = self.theme.reset
7580+
7581+
help_text = parser.format_help()
7582+
self.assertIn(f'Example: {prog_extra}python -m myapp --verbose{reset}',
7583+
help_text)
7584+
self.assertNotIn('`', help_text)
7585+
7586+
def test_backtick_markup_in_description(self):
7587+
parser = argparse.ArgumentParser(
7588+
prog='PROG',
7589+
color=True,
7590+
description='Run `python -m myapp` to start.',
7591+
)
7592+
7593+
prog_extra = self.theme.prog_extra
7594+
reset = self.theme.reset
7595+
7596+
help_text = parser.format_help()
7597+
self.assertIn(f'Run {prog_extra}python -m myapp{reset} to start.',
7598+
help_text)
7599+
7600+
def test_backtick_markup_multiple(self):
7601+
parser = argparse.ArgumentParser(
7602+
prog='PROG',
7603+
color=True,
7604+
epilog='Try `app run` or `app test`.',
7605+
)
7606+
7607+
prog_extra = self.theme.prog_extra
7608+
reset = self.theme.reset
7609+
7610+
help_text = parser.format_help()
7611+
self.assertIn(f'{prog_extra}app run{reset}', help_text)
7612+
self.assertIn(f'{prog_extra}app test{reset}', help_text)
7613+
7614+
def test_backtick_markup_not_applied_when_color_disabled(self):
7615+
# When color is disabled, backticks are preserved as-is
7616+
parser = argparse.ArgumentParser(
7617+
prog='PROG',
7618+
color=False,
7619+
epilog='Example: `python -m myapp`',
7620+
)
7621+
7622+
help_text = parser.format_help()
7623+
self.assertIn('`python -m myapp`', help_text)
7624+
self.assertNotIn('\x1b[', help_text)
7625+
7626+
def test_backtick_markup_with_format_string(self):
7627+
parser = argparse.ArgumentParser(
7628+
prog='myapp',
7629+
color=True,
7630+
epilog='Run `%(prog)s --help` for more info.',
7631+
)
7632+
7633+
prog_extra = self.theme.prog_extra
7634+
reset = self.theme.reset
7635+
7636+
help_text = parser.format_help()
7637+
self.assertIn(f'{prog_extra}myapp --help{reset}', help_text)
7638+
7639+
def test_backtick_markup_in_subparser(self):
7640+
parser = argparse.ArgumentParser(prog='PROG', color=True)
7641+
subparsers = parser.add_subparsers()
7642+
sub = subparsers.add_parser(
7643+
'sub',
7644+
description='Run `PROG sub --foo` to start.',
7645+
)
7646+
7647+
prog_extra = self.theme.prog_extra
7648+
reset = self.theme.reset
7649+
7650+
help_text = sub.format_help()
7651+
self.assertIn(f'{prog_extra}PROG sub --foo{reset}', help_text)
7652+
7653+
def test_backtick_markup_special_regex_chars(self):
7654+
parser = argparse.ArgumentParser(
7655+
prog='PROG',
7656+
color=True,
7657+
epilog='`grep "foo.*bar" | sort`',
7658+
)
7659+
7660+
prog_extra = self.theme.prog_extra
7661+
reset = self.theme.reset
7662+
7663+
help_text = parser.format_help()
7664+
self.assertIn(f'{prog_extra}grep "foo.*bar" | sort{reset}', help_text)
7665+
75717666
def test_print_help_uses_target_file_for_color_decision(self):
75727667
parser = argparse.ArgumentParser(prog='PROG', color=True)
75737668
parser.add_argument('--opt')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add backtick markup support in :mod:`argparse` description and epilog text to highlight inline code when color output is enabled.

0 commit comments

Comments
 (0)