Skip to content

Commit 9290ccf

Browse files
committed
Merge branch 'master' into 3.0.0
2 parents 4616b09 + 69aa9af commit 9290ccf

File tree

10 files changed

+111
-186
lines changed

10 files changed

+111
-186
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
* Added `RawDescriptionCmd2HelpFormatter`, `RawTextCmd2HelpFormatter`, `ArgumentDefaultsCmd2HelpFormatter`,
1111
and `MetavarTypeCmd2HelpFormatter` and they all use `rich-argparse`.
1212

13+
## 2.5.8 (December 17, 2024)
14+
* Bug Fixes
15+
* Rolled back undocumented changes to printing functions introduced in 2.5.0.
16+
1317
## 2.5.7 (November 22, 2024)
1418
* Bug Fixes
1519
* Fixed issue where argument parsers for overridden commands were not being created.

README.md

Lines changed: 60 additions & 59 deletions
Large diffs are not rendered by default.

cmd2.png

-101 KB
Loading

cmd2/ansi.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,9 +1041,6 @@ def style(
10411041
# Default styles for printing strings of various types.
10421042
# These can be altered to suit an application's needs and only need to be a
10431043
# function with the following structure: func(str) -> str
1044-
style_output = functools.partial(style)
1045-
"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text for normal output"""
1046-
10471044
style_success = functools.partial(style, fg=Fg.GREEN)
10481045
"""Partial function supplying arguments to :meth:`cmd2.ansi.style()` which colors text to signify success"""
10491046

cmd2/cmd2.py

Lines changed: 40 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,123 +1194,67 @@ def visible_prompt(self) -> str:
11941194

11951195
def print_to(
11961196
self,
1197-
dest: Union[TextIO, IO[str]],
1197+
dest: IO[str],
11981198
msg: Any,
11991199
*,
12001200
end: str = '\n',
12011201
style: Optional[Callable[[str], str]] = None,
1202-
paged: bool = False,
1203-
chop: bool = False,
12041202
) -> None:
1205-
final_msg = style(msg) if style is not None else msg
1206-
if paged:
1207-
self.ppaged(final_msg, end=end, chop=chop, dest=dest)
1208-
else:
1209-
try:
1210-
ansi.style_aware_write(dest, f'{final_msg}{end}')
1211-
except BrokenPipeError:
1212-
# This occurs if a command's output is being piped to another
1213-
# process and that process closes before the command is
1214-
# finished. If you would like your application to print a
1215-
# warning message, then set the broken_pipe_warning attribute
1216-
# to the message you want printed.
1217-
if self.broken_pipe_warning:
1218-
sys.stderr.write(self.broken_pipe_warning)
1203+
"""
1204+
Print message to a given file object.
12191205
1220-
def poutput(
1221-
self,
1222-
msg: Any = '',
1223-
*,
1224-
end: str = '\n',
1225-
apply_style: bool = True,
1226-
paged: bool = False,
1227-
chop: bool = False,
1228-
) -> None:
1206+
:param dest: the file object being written to
1207+
:param msg: object to print
1208+
:param end: string appended after the end of the message, default a newline
1209+
:param style: optional style function to format msg with (e.g. ansi.style_success)
1210+
"""
1211+
final_msg = style(msg) if style is not None else msg
1212+
try:
1213+
ansi.style_aware_write(dest, f'{final_msg}{end}')
1214+
except BrokenPipeError:
1215+
# This occurs if a command's output is being piped to another
1216+
# process and that process closes before the command is
1217+
# finished. If you would like your application to print a
1218+
# warning message, then set the broken_pipe_warning attribute
1219+
# to the message you want printed.
1220+
if self.broken_pipe_warning:
1221+
sys.stderr.write(self.broken_pipe_warning)
1222+
1223+
def poutput(self, msg: Any = '', *, end: str = '\n') -> None:
12291224
"""Print message to self.stdout and appends a newline by default
12301225
1231-
Also handles BrokenPipeError exceptions for when a command's output has
1232-
been piped to another process and that process terminates before the
1233-
cmd2 command is finished executing.
1234-
12351226
:param msg: object to print
12361227
:param end: string appended after the end of the message, default a newline
1237-
:param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
1238-
where the message text already has the desired style. Defaults to True.
1239-
:param paged: If True, pass the output through the configured pager.
1240-
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
12411228
"""
1242-
self.print_to(self.stdout, msg, end=end, style=ansi.style_output if apply_style else None, paged=paged, chop=chop)
1229+
self.print_to(self.stdout, msg, end=end)
12431230

1244-
def perror(
1245-
self,
1246-
msg: Any = '',
1247-
*,
1248-
end: str = '\n',
1249-
apply_style: bool = True,
1250-
paged: bool = False,
1251-
chop: bool = False,
1252-
) -> None:
1231+
def perror(self, msg: Any = '', *, end: str = '\n', apply_style: bool = True) -> None:
12531232
"""Print message to sys.stderr
12541233
12551234
:param msg: object to print
12561235
:param end: string appended after the end of the message, default a newline
12571236
:param apply_style: If True, then ansi.style_error will be applied to the message text. Set to False in cases
12581237
where the message text already has the desired style. Defaults to True.
1259-
:param paged: If True, pass the output through the configured pager.
1260-
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
12611238
"""
1262-
self.print_to(sys.stderr, msg, end=end, style=ansi.style_error if apply_style else None, paged=paged, chop=chop)
1239+
self.print_to(sys.stderr, msg, end=end, style=ansi.style_error if apply_style else None)
12631240

1264-
def psuccess(
1265-
self,
1266-
msg: Any = '',
1267-
*,
1268-
end: str = '\n',
1269-
paged: bool = False,
1270-
chop: bool = False,
1271-
) -> None:
1272-
"""Writes to stdout applying ansi.style_success by default
1241+
def psuccess(self, msg: Any = '', *, end: str = '\n') -> None:
1242+
"""Wraps poutput, but applies ansi.style_success by default
12731243
12741244
:param msg: object to print
12751245
:param end: string appended after the end of the message, default a newline
1276-
:param paged: If True, pass the output through the configured pager.
1277-
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
12781246
"""
1279-
self.print_to(self.stdout, msg, end=end, style=ansi.style_success, paged=paged, chop=chop)
1247+
msg = ansi.style_success(msg)
1248+
self.poutput(msg, end=end)
12801249

1281-
def pwarning(
1282-
self,
1283-
msg: Any = '',
1284-
*,
1285-
end: str = '\n',
1286-
paged: bool = False,
1287-
chop: bool = False,
1288-
) -> None:
1250+
def pwarning(self, msg: Any = '', *, end: str = '\n') -> None:
12891251
"""Wraps perror, but applies ansi.style_warning by default
12901252
12911253
:param msg: object to print
12921254
:param end: string appended after the end of the message, default a newline
1293-
:param paged: If True, pass the output through the configured pager.
1294-
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
1295-
"""
1296-
self.print_to(sys.stderr, msg, end=end, style=ansi.style_warning, paged=paged, chop=chop)
1297-
1298-
def pfailure(
1299-
self,
1300-
msg: Any = '',
1301-
*,
1302-
end: str = '\n',
1303-
paged: bool = False,
1304-
chop: bool = False,
1305-
) -> None:
1306-
"""Writes to stderr applying ansi.style_error by default
1307-
1308-
:param msg: object to print
1309-
:param end: string appended after the end of the message, default a newline
1310-
:param paged: If True, pass the output through the configured pager.
1311-
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
13121255
"""
1313-
self.print_to(sys.stderr, msg, end=end, style=ansi.style_error, paged=paged, chop=chop)
1256+
msg = ansi.style_warning(msg)
1257+
self.perror(msg, end=end, apply_style=False)
13141258

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

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

1342-
def pfeedback(
1343-
self,
1344-
msg: Any,
1345-
*,
1346-
end: str = '\n',
1347-
apply_style: bool = True,
1348-
paged: bool = False,
1349-
chop: bool = False,
1350-
) -> None:
1286+
def pfeedback(self, msg: Any, *, end: str = '\n') -> None:
13511287
"""For printing nonessential feedback. Can be silenced with `quiet`.
13521288
Inclusion in redirected output is controlled by `feedback_to_output`.
13531289
13541290
:param msg: object to print
13551291
:param end: string appended after the end of the message, default a newline
1356-
:param apply_style: If True, then ansi.style_output will be applied to the message text. Set to False in cases
1357-
where the message text already has the desired style. Defaults to True.
1358-
:param paged: If True, pass the output through the configured pager.
1359-
:param chop: If paged is True, True to truncate long lines or False to wrap long lines.
13601292
"""
13611293
if not self.quiet:
1362-
self.print_to(
1363-
self.stdout if self.feedback_to_output else sys.stderr,
1364-
msg,
1365-
end=end,
1366-
style=ansi.style_output if apply_style else None,
1367-
paged=paged,
1368-
chop=chop,
1369-
)
1294+
if self.feedback_to_output:
1295+
self.poutput(msg, end=end)
1296+
else:
1297+
self.perror(msg, end=end, apply_style=False)
13701298

1371-
def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, dest: Optional[Union[TextIO, IO[str]]] = None) -> None:
1299+
def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False) -> None:
13721300
"""Print output using a pager if it would go off screen and stdout isn't currently being redirected.
13731301
13741302
Never uses a pager inside a script (Python or text) or when output is being redirected or piped or when
@@ -1381,17 +1309,14 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, dest: Optiona
13811309
- chopping is ideal for displaying wide tabular data as is done in utilities like pgcli
13821310
False -> causes lines longer than the screen width to wrap to the next line
13831311
- wrapping is ideal when you want to keep users from having to use horizontal scrolling
1384-
:param dest: Optionally specify the destination stream to write to. If unspecified, defaults to self.stdout
13851312
13861313
WARNING: On Windows, the text always wraps regardless of what the chop argument is set to
13871314
"""
1388-
dest = self.stdout if dest is None else dest
1389-
13901315
# Attempt to detect if we are not running within a fully functional terminal.
13911316
# Don't try to use the pager when being run by a continuous integration system like Jenkins + pexpect.
13921317
functional_terminal = False
13931318

1394-
if self.stdin.isatty() and dest.isatty():
1319+
if self.stdin.isatty() and self.stdout.isatty():
13951320
if sys.platform.startswith('win') or os.environ.get('TERM') is not None:
13961321
functional_terminal = True
13971322

@@ -1412,7 +1337,7 @@ def ppaged(self, msg: Any, *, end: str = '\n', chop: bool = False, dest: Optiona
14121337
with self.sigint_protection:
14131338
import subprocess
14141339

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

14261351
# ----- Methods related to tab completion -----
14271352

examples/colors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def do_speak(self, args):
7777

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

8282
def do_timetravel(self, _):
8383
"""A command which always generates an error message, to demonstrate custom error colors"""

examples/initialization.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def do_intro(self, _):
6565
def do_echo(self, arg):
6666
"""Example of a multiline command"""
6767
fg_color = Fg[self.foreground_color.upper()]
68-
self.poutput(style(arg, fg=fg_color), apply_style=False)
68+
self.poutput(style(arg, fg=fg_color))
6969

7070

7171
if __name__ == '__main__':

examples/pirate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def do_quit(self, arg):
7575

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

8080
yo_parser = cmd2.Cmd2ArgumentParser()
8181
yo_parser.add_argument('--ho', type=int, default=2, help="How often to chant 'ho'")

examples/python_scripting.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@
2424
import os
2525

2626
import cmd2
27-
from cmd2 import (
28-
ansi,
29-
)
27+
from cmd2 import ansi
3028

3129

3230
class CmdLineApp(cmd2.Cmd):
@@ -41,7 +39,7 @@ def __init__(self):
4139
def _set_prompt(self):
4240
"""Set prompt so it displays the current working directory."""
4341
self.cwd = os.getcwd()
44-
self.prompt = ansi.style(f'{self.cwd} $ ', fg='cyan')
42+
self.prompt = ansi.style(f'{self.cwd} $ ', fg=ansi.Fg.CYAN)
4543

4644
def postcmd(self, stop: bool, line: str) -> bool:
4745
"""Hook method executed just after a command dispatch is finished.

tests/test_cmd2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,7 +1993,7 @@ def test_poutput_none(outsim_app):
19931993
def test_poutput_ansi_always(outsim_app):
19941994
msg = 'Hello World'
19951995
colored_msg = ansi.style(msg, fg=ansi.Fg.CYAN)
1996-
outsim_app.poutput(colored_msg, apply_style=False)
1996+
outsim_app.poutput(colored_msg)
19971997
out = outsim_app.stdout.getvalue()
19981998
expected = colored_msg + '\n'
19991999
assert colored_msg != msg
@@ -2004,7 +2004,7 @@ def test_poutput_ansi_always(outsim_app):
20042004
def test_poutput_ansi_never(outsim_app):
20052005
msg = 'Hello World'
20062006
colored_msg = ansi.style(msg, fg=ansi.Fg.CYAN)
2007-
outsim_app.poutput(colored_msg, apply_style=False)
2007+
outsim_app.poutput(colored_msg)
20082008
out = outsim_app.stdout.getvalue()
20092009
expected = msg + '\n'
20102010
assert colored_msg != msg

0 commit comments

Comments
 (0)