8000 GH-142389: Add backtick markup support in description and epilog by savannahostrowski · Pull Request #142390 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content
Merged
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)

8000 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
0