Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Doc/library/argparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,27 @@ are set.

.. versionadded:: 3.14

To highlight inline code in your description or epilog text, you can use
backticks::

>>> parser = argparse.ArgumentParser(
... formatter_class=argparse.RawDescriptionHelpFormatter,
... epilog='''Examples:
... `python -m myapp --verbose`
... `python -m myapp --config settings.json`
... ''')

When colors are enabled, the text inside backticks will be displayed in a
distinct color to help examples stand out. When colors are disabled, backticks
are preserved as-is, which is readable in plain text.

.. note::

Backtick markup only applies to description and epilog text. It does not
apply to individual argument ``help`` strings.

.. versionadded:: 3.15


The add_argument() method
-------------------------
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,10 @@ argparse
default to ``True``. This enables suggestions for mistyped arguments by default.
(Contributed by Jakob Schluse in :gh:`140450`.)

* Added backtick markup support in description and epilog text to highlight
inline code when color output is enabled.
(Contributed by Savannah Ostrowski in :gh:`142390`.)

calendar
--------

Expand Down
22 changes: 21 additions & 1 deletion Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,27 @@ def _format_text(self, text):
text = text % dict(prog=self._prog)
text_width = max(self._width - self._current_indent, 11)
indent = ' ' * self._current_indent
return self._fill_text(text, text_width, indent) + '\n\n'
text = self._fill_text(text, text_width, indent)
text = self._apply_text_markup(text)
return text + '\n\n'

def _apply_text_markup(self, text):
"""Apply color markup to text.

Supported markup:
`...` - inline code (rendered with prog_extra color)

When colors are disabled, backticks are preserved as-is.
"""
t = self._theme
if not t.reset:
return text
text = _re.sub(
r'`([^`]+)`',
rf'{t.prog_extra}\1{t.reset}',
text,
)
return text

def _format_action(self, action):
# determine the required width and the entry label
Expand Down
95 changes: 95 additions & 0 deletions Lib/test/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -7568,6 +7568,101 @@ def test_error_and_warning_not_colorized_when_disabled(self):
self.assertNotIn('\x1b[', warn)
self.assertIn('warning:', warn)

def test_backtick_markup_in_epilog(self):
parser = argparse.ArgumentParser(
prog='PROG',
color=True,
epilog='Example: `python -m myapp --verbose`',
)

prog_extra = self.theme.prog_extra
reset = self.theme.reset

help_text = parser.format_help()
self.assertIn(f'Example: {prog_extra}python -m myapp --verbose{reset}',
help_text)
self.assertNotIn('`', help_text)

def test_backtick_markup_in_description(self):
parser = argparse.ArgumentParser(
prog='PROG',
color=True,
description='Run `python -m myapp` to start.',
)

prog_extra = self.theme.prog_extra
reset = self.theme.reset

help_text = parser.format_help()
self.assertIn(f'Run {prog_extra}python -m myapp{reset} to start.',
help_text)

def test_backtick_markup_multiple(self):
parser = argparse.ArgumentParser(
prog='PROG',
color=True,
epilog='Try `app run` or `app test`.',
)

prog_extra = self.theme.prog_extra
reset = self.theme.reset

help_text = parser.format_help()
self.assertIn(f'{prog_extra}app run{reset}', help_text)
self.assertIn(f'{prog_extra}app test{reset}', help_text)

def test_backtick_markup_not_applied_when_color_disabled(self):
# When color is disabled, backticks are preserved as-is
parser = argparse.ArgumentParser(
prog='PROG',
color=False,
epilog='Example: `python -m myapp`',
)

help_text = parser.format_help()
self.assertIn('`python -m myapp`', help_text)
self.assertNotIn('\x1b[', help_text)

def test_backtick_markup_with_format_string(self):
parser = argparse.ArgumentParser(
prog='myapp',
color=True,
epilog='Run `%(prog)s --help` for more info.',
)

prog_extra = self.theme.prog_extra
reset = self.theme.reset

help_text = parser.format_help()
self.assertIn(f'{prog_extra}myapp --help{reset}', help_text)

def test_backtick_markup_in_subparser(self):
parser = argparse.ArgumentParser(prog='PROG', color=True)
subparsers = parser.add_subparsers()
sub = subparsers.add_parser(
'sub',
description='Run `PROG sub --foo` to start.',
)

prog_extra = self.theme.prog_extra
reset = self.theme.reset

help_text = sub.format_help()
self.assertIn(f'{prog_extra}PROG sub --foo{reset}', help_text)

def test_backtick_markup_special_regex_chars(self):
parser = argparse.ArgumentParser(
prog='PROG',
color=True,
epilog='`grep "foo.*bar" | sort`',
)

prog_extra = self.theme.prog_extra
reset = self.theme.reset

help_text = parser.format_help()
self.assertIn(f'{prog_extra}grep "foo.*bar" | sort{reset}', help_text)

def test_print_help_uses_target_file_for_color_decision(self):
parser = argparse.ArgumentParser(prog='PROG', color=True)
parser.add_argument('--opt')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add backtick markup support in :mod:`argparse` description and epilog text to highlight inline code when color output is enabled.
Loading