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
66 changes: 64 additions & 2 deletions cmd2/cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1198,22 +1198,39 @@ def print_to(
end: str = "\n",
style: StyleType | None = None,
soft_wrap: bool = True,
emoji: bool = False,
markup: bool = False,
highlight: bool = False,
rich_print_kwargs: RichPrintKwargs | None = None,
**kwargs: Any, # noqa: ARG002
) -> None:
"""Print objects to a given file stream.

This method is configured for general-purpose printing. By default, it enables
soft wrap and disables Rich's automatic detection for markup, emoji, and highlighting.
These defaults can be overridden by passing explicit keyword arguments.

:param file: file stream being written to
:param objects: objects to print
:param sep: string to write between printed text. Defaults to " ".
:param end: string to write at end of printed text. Defaults to a newline.
:param style: optional style to apply to output
:param soft_wrap: Enable soft wrap mode. If True, lines of text will not be word-wrapped or cropped to
fit the terminal width. Defaults to True.
:param soft_wrap: Enable soft wrap mode. If True, lines of text will not be
word-wrapped or cropped to fit the terminal width. Defaults to True.
:param emoji: If True, Rich will replace emoji codes (e.g., :smiley:) with their
corresponding Unicode characters. Defaults to False.
:param markup: If True, Rich will interpret strings with tags (e.g., [bold]hello[/bold])
as styled output. Defaults to False.
:param highlight: If True, Rich will automatically apply highlighting to elements within
strings, such as common Python data types like numbers, booleans, or None.
This is particularly useful when pretty printing objects like lists and
dictionaries to display them in color. Defaults to False.
:param rich_print_kwargs: optional additional keyword arguments to pass to Rich's Console.print().
:param kwargs: Arbitrary keyword arguments. This allows subclasses to extend the signature of this
method and still call `super()` without encountering unexpected keyword argument errors.
These arguments are not passed to Rich's Console.print().

See the Rich documentation for more details on emoji codes, markup tags, and highlighting.
"""
prepared_objects = ru.prepare_objects_for_rendering(*objects)

Expand All @@ -1224,6 +1241,9 @@ def print_to(
end=end,
style=style,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
**(rich_print_kwargs if rich_print_kwargs is not None else {}),
)
except BrokenPipeError:
Expand All @@ -1242,6 +1262,9 @@ def poutput(
end: str = "\n",
style: StyleType | None = None,
soft_wrap: bool = True,
emoji: bool = False,
markup: bool = False,
highlight: bool = False,
rich_print_kwargs: RichPrintKwargs | None = None,
**kwargs: Any, # noqa: ARG002
) -> None:
Expand All @@ -1256,6 +1279,9 @@ def poutput(
end=end,
style=style,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
rich_print_kwargs=rich_print_kwargs,
)

Expand All @@ -1266,6 +1292,9 @@ def perror(
end: str = "\n",
style: StyleType | None = Cmd2Style.ERROR,
soft_wrap: bool = True,
emoji: bool = False,
markup: bool = False,
highlight: bool = False,
rich_print_kwargs: RichPrintKwargs | None = None,
**kwargs: Any, # noqa: ARG002
) -> None:
Expand All @@ -1282,6 +1311,9 @@ def perror(
end=end,
style=style,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
rich_print_kwargs=rich_print_kwargs,
)

Expand All @@ -1291,6 +1323,9 @@ def psuccess(
sep: str = " ",
end: str = "\n",
soft_wrap: bool = True,
emoji: bool = False,
markup: bool = False,
highlight: bool = False,
rich_print_kwargs: RichPrintKwargs | None = None,
**kwargs: Any, # noqa: ARG002
) -> None:
Expand All @@ -1304,6 +1339,9 @@ def psuccess(
end=end,
style=Cmd2Style.SUCCESS,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
rich_print_kwargs=rich_print_kwargs,
)

Expand All @@ -1313,6 +1351,9 @@ def pwarning(
sep: str = " ",
end: str = "\n",
soft_wrap: bool = True,
emoji: bool = False,
markup: bool = False,
highlight: bool = False,
rich_print_kwargs: RichPrintKwargs | None = None,
**kwargs: Any, # noqa: ARG002
) -> None:
Expand All @@ -1326,6 +1367,9 @@ def pwarning(
end=end,
style=Cmd2Style.WARNING,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
rich_print_kwargs=rich_print_kwargs,
)

Expand Down Expand Up @@ -1390,6 +1434,9 @@ def pfeedback(
end: str = "\n",
style: StyleType | None = None,
soft_wrap: bool = True,
emoji: bool = False,
markup: bool = False,
highlight: bool = False,
rich_print_kwargs: RichPrintKwargs | None = None,
**kwargs: Any, # noqa: ARG002
) -> None:
Expand All @@ -1408,6 +1455,9 @@ def pfeedback(
end=end,
style=style,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
rich_print_kwargs=rich_print_kwargs,
)
else:
Expand All @@ -1417,6 +1467,9 @@ def pfeedback(
end=end,
style=style,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
rich_print_kwargs=rich_print_kwargs,
)

Expand All @@ -1428,6 +1481,9 @@ def ppaged(
style: StyleType | None = None,
chop: bool = False,
soft_wrap: bool = True,
emoji: bool = False,
markup: bool = False,
highlight: bool = False,
rich_print_kwargs: RichPrintKwargs | None = None,
**kwargs: Any, # noqa: ARG002
) -> None:
Expand Down Expand Up @@ -1479,6 +1535,9 @@ def ppaged(
end=end,
style=style,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
**(rich_print_kwargs if rich_print_kwargs is not None else {}),
)
output_bytes = capture.get().encode('utf-8', 'replace')
Expand All @@ -1503,6 +1562,9 @@ def ppaged(
end=end,
style=style,
soft_wrap=soft_wrap,
emoji=emoji,
markup=markup,
highlight=highlight,
rich_print_kwargs=rich_print_kwargs,
)

Expand Down
13 changes: 6 additions & 7 deletions cmd2/rich_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,6 @@ class RichPrintKwargs(TypedDict, total=False):
justify: JustifyMethod | None
overflow: OverflowMethod | None
no_wrap: bool | None
markup: bool | None
emoji: bool | None
highlight: bool | None
width: int | None
height: int | None
crop: bool
Expand Down Expand Up @@ -216,9 +213,11 @@ def __init__(self, file: IO[str] | None = None) -> None:
:param file: optional file object where the console should write to.
Defaults to sys.stdout.
"""
# Disable Rich's automatic detection for markup, emoji, and highlighting.
# rich-argparse does markup and highlighting without involving the console
# so these won't affect its internal functionality.
# Since this console is used to print error messages which may not have
# been pre-formatted by rich-argparse, disable Rich's automatic detection
# for markup, emoji, and highlighting. rich-argparse does markup and
# highlighting without involving the console so these won't affect its
# internal functionality.
super().__init__(
file=file,
markup=False,
Expand All @@ -236,7 +235,7 @@ class Cmd2ExceptionConsole(Cmd2BaseConsole):

def console_width() -> int:
"""Return the width of the console."""
return Cmd2BaseConsole().width
return Console().width


def rich_text_to_string(text: Text) -> str:
Expand Down
27 changes: 4 additions & 23 deletions tests/test_cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2136,33 +2136,21 @@ def test_poutput_ansi_terminal(outsim_app) -> None:

@with_ansi_style(ru.AllowStyle.ALWAYS)
def test_poutput_highlight(outsim_app):
rich_print_kwargs = RichPrintKwargs(highlight=True)
outsim_app.poutput(
"My IP Address is 192.168.1.100.",
rich_print_kwargs=rich_print_kwargs,
)
outsim_app.poutput("My IP Address is 192.168.1.100.", highlight=True)
out = outsim_app.stdout.getvalue()
assert out == "My IP Address is \x1b[1;92m192.168.1.100\x1b[0m.\n"


@with_ansi_style(ru.AllowStyle.ALWAYS)
def test_poutput_markup(outsim_app):
rich_print_kwargs = RichPrintKwargs(markup=True)
outsim_app.poutput(
"The leaves are [green]green[/green].",
rich_print_kwargs=rich_print_kwargs,
)
outsim_app.poutput("The leaves are [green]green[/green].", markup=True)
out = outsim_app.stdout.getvalue()
assert out == "The leaves are \x1b[32mgreen\x1b[0m.\n"


@with_ansi_style(ru.AllowStyle.ALWAYS)
def test_poutput_emoji(outsim_app):
rich_print_kwargs = RichPrintKwargs(emoji=True)
outsim_app.poutput(
"Look at the emoji :1234:.",
rich_print_kwargs=rich_print_kwargs,
)
outsim_app.poutput("Look at the emoji :1234:.", emoji=True)
out = outsim_app.stdout.getvalue()
assert out == "Look at the emoji 🔢.\n"

Expand Down Expand Up @@ -2196,13 +2184,9 @@ def test_poutput_no_wrap_and_overflow(outsim_app):
@with_ansi_style(ru.AllowStyle.ALWAYS)
def test_poutput_pretty_print(outsim_app):
"""Test that cmd2 passes objects through so they can be pretty-printed when highlighting is enabled."""
rich_print_kwargs = RichPrintKwargs(highlight=True)
dictionary = {1: 'hello', 2: 'person', 3: 'who', 4: 'codes'}

outsim_app.poutput(
dictionary,
rich_print_kwargs=rich_print_kwargs,
)
outsim_app.poutput(dictionary, highlight=True)
out = outsim_app.stdout.getvalue()
assert out.startswith("\x1b[1m{\x1b[0m\x1b[1;36m1\x1b[0m: \x1b[32m'hello'\x1b[0m")

Expand All @@ -2214,9 +2198,6 @@ def test_poutput_all_keyword_args(outsim_app):
justify="center",
overflow="ellipsis",
no_wrap=True,
markup=True,
emoji=True,
highlight=True,
width=40,
height=50,
crop=False,
Expand Down
5 changes: 2 additions & 3 deletions tests/test_rich_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ def test_cmd2_base_console() -> None:


def test_indented_text() -> None:
console = ru.Cmd2GeneralConsole()
console = Console(width=20)

# With an indention of 10, text will be evenly split across two lines.
console.width = 20
text = "A" * 20
level = 10
indented_text = ru.indent(text, level)
Expand All @@ -50,7 +49,7 @@ def test_indented_text() -> None:


def test_indented_table() -> None:
console = ru.Cmd2GeneralConsole()
console = Console()

level = 2
table = Table("Column", box=rich.box.ASCII)
Expand Down
Loading