Skip to content

Commit

Permalink
Rolled back undocumented changes to printing functions introduced in …
Browse files Browse the repository at this point in the history
…2.5.0.
  • Loading branch information
kmvanbrunt committed Dec 17, 2024
1 parent 20c893d commit 5b98fe6
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 128 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.5.8 (TBD)
* Bug Fixes
* Rolled back undocumented changes to printing functions introduced in 2.5.0.

## 2.5.7 (November 22, 2024)
* Bug Fixes
* Fixed issue where argument parsers for overridden commands were not being created.
Expand Down
3 changes: 0 additions & 3 deletions cmd2/ansi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1042,9 +1042,6 @@ def style(
# Default styles for printing strings of various types.
# These can be altered to suit an application's needs and only need to be a
# function with the following structure: func(str) -> str
style_output = functools.partial(style)
"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text for normal output"""

style_success = functools.partial(style, fg=Fg.GREEN)
"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text to signify success"""

Expand Down
152 changes: 32 additions & 120 deletions cmd2/cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1211,124 +1211,55 @@ def visible_prompt(self) -> str:
return ansi.strip_style(self.prompt)

def print_to(
self,
dest: Union[TextIO, IO[str]],
msg: Any,
*,
end: str = '\n',
style: Optional[Callable[[str], str]] = None,
paged: bool = False,
chop: bool = False,
self, dest: Union[TextIO, IO[str]], msg: Any, *, end: str = '\n', style: Optional[Callable[[str], str]] = None
) -> None:
final_msg = style(msg) if style is not None else msg
if paged:
self.ppaged(final_msg, end=end, chop=chop, dest=dest)
else:
try:
ansi.style_aware_write(dest, f'{final_msg}{end}')
except BrokenPipeError:
# This occurs if a command's output is being piped to another
# process and that process closes before the command is
# finished. If you would like your application to print a
# warning message, then set the broken_pipe_warning attribute
# to the message you want printed.
if self.broken_pipe_warning:
sys.stderr.write(self.broken_pipe_warning)

def poutput(
self,
msg: Any = '',
*,
end: str = '\n',
apply_style: bool = True,
paged: bool = False,
chop: bool = False,
) -> None:
try:
ansi.style_aware_write(dest, f'{final_msg}{end}')
except BrokenPipeError:
# This occurs if a command's output is being piped to another
# process and that process closes before the command is
# finished. If you would like your application to print a
# warning message, then set the broken_pipe_warning attribute
# to the message you want printed.
if self.broken_pipe_warning:
sys.stderr.write(self.broken_pipe_warning)

def poutput(self, msg: Any = '', *, end: str = '\n') -> None:
"""Print message to self.stdout and appends a newline by default
Also handles BrokenPipeError exceptions for when a command's output has
been piped to another process and that process terminates before the
cmd2 command is finished executing.
:param msg: object to print
:param end: string appended after the end of the message, default a newline
:param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
where the message text already has the desired style. Defaults to True.
:param paged: If True, pass the output through the configured pager.
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
"""
self.print_to(self.stdout, msg, end=end, style=ansi.style_output if apply_style else None, paged=paged, chop=chop)
self.print_to(self.stdout, msg, end=end)

def perror(
self,
msg: Any = '',
*,
end: str = '\n',
apply_style: bool = True,
paged: bool = False,
chop: bool = False,
) -> None:
def perror(self, msg: Any = '', *, end: str = '\n', apply_style: bool = True) -> None:
"""Print message to sys.stderr
:param msg: object to print
:param end: string appended after the end of the message, default a newline
:param apply_style: If True, then ansi.style_error will be applied to the message text. Set to False in cases
where the message text already has the desired style. Defaults to True.
:param paged: If True, pass the output through the configured pager.
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
"""
self.print_to(sys.stderr, msg, end=end, style=ansi.style_error if apply_style else None, paged=paged, chop=chop)
self.print_to(sys.stderr, msg, end=end, style=ansi.style_error if apply_style else None)

def psuccess(
self,
msg: Any = '',
*,
end: str = '\n',
paged: bool = False,
chop: bool = False,
) -> None:
"""Writes to stdout applying ansi.style_success by default
def psuccess(self, msg: Any = '', *, end: str = '\n') -> None:
"""Wraps poutput, but applies ansi.style_success by default
:param msg: object to print
:param end: string appended after the end of the message, default a newline
:param paged: If True, pass the output through the configured pager.
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
"""
self.print_to(self.stdout, msg, end=end, style=ansi.style_success, paged=paged, chop=chop)
msg = ansi.style_success(msg)
self.poutput(msg, end=end)

def pwarning(
self,
msg: Any = '',
*,
end: str = '\n',
paged: bool = False,
chop: bool = False,
) -> None:
def pwarning(self, msg: Any = '', *, end: str = '\n') -> None:
"""Wraps perror, but applies ansi.style_warning by default
:param msg: object to print
:param end: string appended after the end of the message, default a newline
:param paged: If True, pass the output through the configured pager.
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
"""
self.print_to(sys.stderr, msg, end=end, style=ansi.style_warning, paged=paged, chop=chop)

def pfailure(
self,
msg: Any = '',
*,
end: str = '\n',
paged: bool = False,
chop: bool = False,
) -> None:
"""Writes to stderr applying ansi.style_error by default
:param msg: object to print
:param end: string appended after the end of the message, default a newline
:param paged: If True, pass the output through the configured pager.
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
"""
self.print_to(sys.stderr, msg, end=end, style=ansi.style_error, paged=paged, chop=chop)
msg = ansi.style_warning(msg)
self.perror(msg, end=end, apply_style=False)

def pexcept(self, msg: Any, *, end: str = '\n', apply_style: bool = True) -> None:
"""Print Exception message to sys.stderr. If debug is true, print exception traceback if one exists.
Expand Down Expand Up @@ -1357,36 +1288,20 @@ def pexcept(self, msg: Any, *, end: str = '\n', apply_style: bool = True) -> Non

self.perror(final_msg, end=end, apply_style=False)

def pfeedback(
self,
msg: Any,
*,
end: str = '\n',
apply_style: bool = True,
paged: bool = False,
chop: bool = False,
) -> None:
def pfeedback(self, msg: Any, *, end: str = '\n') -> None:
"""For printing nonessential feedback. Can be silenced with `quiet`.
Inclusion in redirected output is controlled by `feedback_to_output`.
:param msg: object to print
:param end: string appended after the end of the message, default a newline
:param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
where the message text already has the desired style. Defaults to True.
:param paged: If True, pass the output through the configured pager.
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
"""
if not self.quiet:
self.print_to(
self.stdout if self.feedback_to_output else sys.stderr,
msg,
end=end,
style=ansi.style_output if apply_style else None,
paged=paged,
chop=chop,
)
if self.feedback_to_output:
self.poutput(msg, end=end)
else:
self.perror(msg, end=end, apply_style=False)

def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, dest: Optional[Union[TextIO, IO[str]]] = None) -> None:
def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False) -> None:
"""Print output using a pager if it would go off screen and stdout isn't currently being redirected.
Never uses a pager inside a script (Python or text) or when output is being redirected or piped or when
Expand All @@ -1399,17 +1314,14 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, dest: Optiona
- chopping is ideal for displaying wide tabular data as is done in utilities like pgcli
False -> causes lines longer than the screen width to wrap to the next line
- wrapping is ideal when you want to keep users from having to use horizontal scrolling
:param dest: Optionally specify the destination stream to write to. If unspecified, defaults to self.stdout
WARNING: On Windows, the text always wraps regardless of what the chop argument is set to
"""
dest = self.stdout if dest is None else dest

# Attempt to detect if we are not running within a fully functional terminal.
# Don't try to use the pager when being run by a continuous integration system like Jenkins + pexpect.
functional_terminal = False

if self.stdin.isatty() and dest.isatty():
if self.stdin.isatty() and self.stdout.isatty():
if sys.platform.startswith('win') or os.environ.get('TERM') is not None:
functional_terminal = True

Expand All @@ -1430,7 +1342,7 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, dest: Optiona
with self.sigint_protection:
import subprocess

pipe_proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE, stdout=dest)
pipe_proc = subprocess.Popen(pager, shell=True, stdin=subprocess.PIPE, stdout=self.stdout)
pipe_proc.communicate(final_msg.encode('utf-8', 'replace'))
except BrokenPipeError:
# This occurs if a command's output is being piped to another process and that process closes before the
Expand All @@ -1439,7 +1351,7 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, dest: Optiona
if self.broken_pipe_warning:
sys.stderr.write(self.broken_pipe_warning)
else:
self.print_to(dest, msg, end=end, paged=False)
self.poutput(msg, end=end)

# ----- Methods related to tab completion -----

Expand Down
2 changes: 1 addition & 1 deletion examples/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def do_speak(self, args):

for _ in range(min(repetitions, self.maxrepeats)):
# .poutput handles newlines, and accommodates output redirection too
self.poutput(output_str, apply_style=False)
self.poutput(output_str)

def do_timetravel(self, _):
"""A command which always generates an error message, to demonstrate custom error colors"""
Expand Down
2 changes: 1 addition & 1 deletion examples/initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def do_intro(self, _):
def do_echo(self, arg):
"""Example of a multiline command"""
fg_color = Fg[self.foreground_color.upper()]
self.poutput(style(arg, fg=fg_color), apply_style=False)
self.poutput(style(arg, fg=fg_color))


if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion examples/pirate.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def do_quit(self, arg):

def do_sing(self, arg):
"""Sing a colorful song."""
self.poutput(cmd2.ansi.style(arg, fg=Fg[self.songcolor.upper()]), apply_style=False)
self.poutput(cmd2.ansi.style(arg, fg=Fg[self.songcolor.upper()]))

yo_parser = cmd2.Cmd2ArgumentParser()
yo_parser.add_argument('--ho', type=int, default=2, help="How often to chant 'ho'")
Expand Down
4 changes: 2 additions & 2 deletions tests/test_cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1992,7 +1992,7 @@ def test_poutput_none(outsim_app):
def test_poutput_ansi_always(outsim_app):
msg = 'Hello World'
colored_msg = ansi.style(msg, fg=ansi.Fg.CYAN)
outsim_app.poutput(colored_msg, apply_style=False)
outsim_app.poutput(colored_msg)
out = outsim_app.stdout.getvalue()
expected = colored_msg + '\n'
assert colored_msg != msg
Expand All @@ -2003,7 +2003,7 @@ def test_poutput_ansi_always(outsim_app):
def test_poutput_ansi_never(outsim_app):
msg = 'Hello World'
colored_msg = ansi.style(msg, fg=ansi.Fg.CYAN)
outsim_app.poutput(colored_msg, apply_style=False)
outsim_app.poutput(colored_msg)
out = outsim_app.stdout.getvalue()
expected = msg + '\n'
assert colored_msg != msg
Expand Down

0 comments on commit 5b98fe6

Please sign in to comment.